diff --git a/.env b/.env deleted file mode 100644 index 976b6b1..0000000 --- a/.env +++ /dev/null @@ -1,14 +0,0 @@ -DATABASE_URL="postgresql://postgres:postgres@localhost:5432/vash" - -ORIGIN="http://localhost:5173" - -# Better Auth -# For production use 32 characters and generated with high entropy -# https://www.better-auth.com/docs/installation -BETTER_AUTH_SECRET="***REMOVED***" - -OSU_CLIENT_ID="30152" -OSU_CLIENT_SECRET="***REMOVED***" - -OSU_IRC_USERNAME="jollyWudchip" -OSU_IRC_PASSWORD="***REMOVED***" diff --git a/.svelte-kit/adapter-node/.vite/manifest.json b/.svelte-kit/adapter-node/.vite/manifest.json deleted file mode 100644 index 36de7fb..0000000 --- a/.svelte-kit/adapter-node/.vite/manifest.json +++ /dev/null @@ -1,661 +0,0 @@ -{ - ".svelte-kit/generated/server/internal.js": { - "file": "internal.js", - "name": "internal", - "src": ".svelte-kit/generated/server/internal.js", - "isEntry": true, - "imports": [ - "_root.js", - "_environment.js", - "_server.js", - "_internal.js", - "_shared-server.js" - ] - }, - "_api.js": { - "file": "chunks/api.js", - "name": "api", - "imports": [ - "_shared-server.js", - "_index2.js" - ] - }, - "_auth.js": { - "file": "chunks/auth.js", - "name": "auth", - "imports": [ - "_shared-server.js", - "_url.js", - "_root.js", - "_utils.js", - "_query.js", - "_index2.js" - ], - "dynamicImports": [ - "node_modules/better-auth/dist/adapters/memory-adapter/index.mjs", - "node_modules/better-auth/dist/adapters/kysely-adapter/index.mjs", - "node_modules/better-auth/dist/adapters/kysely-adapter/index.mjs", - "node_modules/better-auth/dist/adapters/kysely-adapter/bun-sqlite-dialect.mjs", - "node_modules/better-auth/dist/adapters/kysely-adapter/node-sqlite-dialect.mjs" - ] - }, - "_engine.js": { - "file": "chunks/engine.js", - "name": "engine", - "imports": [ - "_index2.js" - ] - }, - "_environment.js": { - "file": "chunks/environment.js", - "name": "environment" - }, - "_exports.js": { - "file": "chunks/exports.js", - "name": "exports" - }, - "_false.js": { - "file": "chunks/false.js", - "name": "false" - }, - "_index.js": { - "file": "chunks/index.js", - "name": "index", - "imports": [ - "_index3.js", - "_root.js" - ] - }, - "_index2.js": { - "file": "chunks/index2.js", - "name": "index", - "imports": [ - "_shared-server.js" - ] - }, - "_index3.js": { - "file": "chunks/index3.js", - "name": "index" - }, - "_index4.js": { - "file": "chunks/index4.js", - "name": "index", - "imports": [ - "_state.svelte.js", - "_url.js", - "_utils.js", - "_index.js", - "_root.js", - "_exports.js", - "_index3.js" - ] - }, - "_internal.js": { - "file": "chunks/internal.js", - "name": "internal", - "imports": [ - "_root.js", - "_environment.js", - "_server.js", - "_shared-server.js" - ], - "dynamicImports": [ - "src/hooks.server.ts" - ] - }, - "_orchestrator.js": { - "file": "chunks/orchestrator.js", - "name": "orchestrator", - "imports": [ - "_index2.js", - "_engine.js", - "_shared-server.js" - ] - }, - "_query.js": { - "file": "chunks/query.js", - "name": "query", - "imports": [ - "_shared.js", - "_environment.js" - ] - }, - "_root.js": { - "file": "chunks/root.js", - "name": "root", - "imports": [ - "_index3.js", - "_false.js" - ] - }, - "_routing.js": { - "file": "chunks/routing.js", - "name": "routing", - "imports": [ - "_url.js" - ] - }, - "_server.js": { - "file": "chunks/server.js", - "name": "server" - }, - "_shared-server.js": { - "file": "chunks/shared-server.js", - "name": "shared-server" - }, - "_shared.js": { - "file": "chunks/shared.js", - "name": "shared", - "imports": [ - "_utils.js" - ] - }, - "_state.svelte.js": { - "file": "chunks/state.svelte.js", - "name": "state.svelte", - "imports": [ - "_index3.js", - "_url.js", - "_root.js" - ] - }, - "_url.js": { - "file": "chunks/url.js", - "name": "url" - }, - "_utils.js": { - "file": "chunks/utils.js", - "name": "utils" - }, - "node_modules/@sveltejs/kit/src/runtime/app/server/remote/index.js": { - "file": "remote-entry.js", - "name": "remote-entry", - "src": "node_modules/@sveltejs/kit/src/runtime/app/server/remote/index.js", - "isEntry": true, - "imports": [ - "_query.js", - "_shared.js", - "_false.js", - "_server.js" - ] - }, - "node_modules/@sveltejs/kit/src/runtime/components/svelte-5/layout.svelte": { - "file": "entries/fallbacks/layout.svelte.js", - "name": "entries/fallbacks/layout.svelte", - "src": "node_modules/@sveltejs/kit/src/runtime/components/svelte-5/layout.svelte", - "isEntry": true - }, - "node_modules/@sveltejs/kit/src/runtime/server/index.js": { - "file": "index.js", - "name": "index", - "src": "node_modules/@sveltejs/kit/src/runtime/server/index.js", - "isEntry": true, - "imports": [ - "_false.js", - "_server.js", - "_shared.js", - "_url.js", - "_utils.js", - "_index.js", - "_shared-server.js", - "_routing.js", - "_exports.js", - "_internal.js" - ] - }, - "node_modules/better-auth/dist/adapters/kysely-adapter/bun-sqlite-dialect.mjs": { - "file": "chunks/bun-sqlite-dialect.js", - "name": "bun-sqlite-dialect", - "src": "node_modules/better-auth/dist/adapters/kysely-adapter/bun-sqlite-dialect.mjs", - "isDynamicEntry": true - }, - "node_modules/better-auth/dist/adapters/kysely-adapter/index.mjs": { - "file": "chunks/index6.js", - "name": "index", - "src": "node_modules/better-auth/dist/adapters/kysely-adapter/index.mjs", - "isDynamicEntry": true, - "imports": [ - "_auth.js" - ] - }, - "node_modules/better-auth/dist/adapters/kysely-adapter/node-sqlite-dialect.mjs": { - "file": "chunks/node-sqlite-dialect.js", - "name": "node-sqlite-dialect", - "src": "node_modules/better-auth/dist/adapters/kysely-adapter/node-sqlite-dialect.mjs", - "isDynamicEntry": true - }, - "node_modules/better-auth/dist/adapters/memory-adapter/index.mjs": { - "file": "chunks/index5.js", - "name": "index", - "src": "node_modules/better-auth/dist/adapters/memory-adapter/index.mjs", - "isDynamicEntry": true - }, - "src/hooks.server.ts": { - "file": "entries/hooks.server.js", - "name": "entries/hooks.server", - "src": "src/hooks.server.ts", - "isEntry": true, - "isDynamicEntry": true, - "imports": [ - "_environment.js", - "_auth.js", - "_index2.js" - ] - }, - "src/routes/(app)/+layout.server.ts": { - "file": "entries/pages/(app)/_layout.server.ts.js", - "name": "entries/pages/(app)/_layout.server.ts", - "src": "src/routes/(app)/+layout.server.ts", - "isEntry": true - }, - "src/routes/(app)/+layout.svelte": { - "file": "entries/pages/(app)/_layout.svelte.js", - "name": "entries/pages/(app)/_layout.svelte", - "src": "src/routes/(app)/+layout.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_index4.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ], - "css": [ - "_app/immutable/assets/_layout.Dv2no-8m.css" - ] - }, - "src/routes/(app)/+page.server.ts": { - "file": "entries/pages/(app)/_page.server.ts.js", - "name": "entries/pages/(app)/_page.server.ts", - "src": "src/routes/(app)/+page.server.ts", - "isEntry": true, - "imports": [ - "_index2.js" - ] - }, - "src/routes/(app)/+page.svelte": { - "file": "entries/pages/(app)/_page.svelte.js", - "name": "entries/pages/(app)/_page.svelte", - "src": "src/routes/(app)/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js" - ] - }, - "src/routes/(app)/admin/+page.server.ts": { - "file": "entries/pages/(app)/admin/_page.server.ts.js", - "name": "entries/pages/(app)/admin/_page.server.ts", - "src": "src/routes/(app)/admin/+page.server.ts", - "isEntry": true, - "imports": [ - "_index2.js" - ] - }, - "src/routes/(app)/admin/+page.svelte": { - "file": "entries/pages/(app)/admin/_page.svelte.js", - "name": "entries/pages/(app)/admin/_page.svelte", - "src": "src/routes/(app)/admin/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ] - }, - "src/routes/(app)/mappools/+page.server.ts": { - "file": "entries/pages/(app)/mappools/_page.server.ts.js", - "name": "entries/pages/(app)/mappools/_page.server.ts", - "src": "src/routes/(app)/mappools/+page.server.ts", - "isEntry": true, - "imports": [ - "_index2.js" - ] - }, - "src/routes/(app)/mappools/+page.svelte": { - "file": "entries/pages/(app)/mappools/_page.svelte.js", - "name": "entries/pages/(app)/mappools/_page.svelte", - "src": "src/routes/(app)/mappools/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ] - }, - "src/routes/(app)/mappools/[id]/+page.server.ts": { - "file": "entries/pages/(app)/mappools/_id_/_page.server.ts.js", - "name": "entries/pages/(app)/mappools/_id_/_page.server.ts", - "src": "src/routes/(app)/mappools/[id]/+page.server.ts", - "isEntry": true, - "imports": [ - "_index2.js", - "_api.js" - ] - }, - "src/routes/(app)/mappools/[id]/+page.svelte": { - "file": "entries/pages/(app)/mappools/_id_/_page.svelte.js", - "name": "entries/pages/(app)/mappools/_id_/_page.svelte", - "src": "src/routes/(app)/mappools/[id]/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ] - }, - "src/routes/(app)/matches/+page.server.ts": { - "file": "entries/pages/(app)/matches/_page.server.ts.js", - "name": "entries/pages/(app)/matches/_page.server.ts", - "src": "src/routes/(app)/matches/+page.server.ts", - "isEntry": true, - "imports": [ - "_index2.js", - "_engine.js", - "_orchestrator.js" - ] - }, - "src/routes/(app)/matches/+page.svelte": { - "file": "entries/pages/(app)/matches/_page.svelte.js", - "name": "entries/pages/(app)/matches/_page.svelte", - "src": "src/routes/(app)/matches/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ] - }, - "src/routes/(app)/matches/[id]/+page.server.ts": { - "file": "entries/pages/(app)/matches/_id_/_page.server.ts.js", - "name": "entries/pages/(app)/matches/_id_/_page.server.ts", - "src": "src/routes/(app)/matches/[id]/+page.server.ts", - "isEntry": true, - "imports": [ - "_index2.js", - "_engine.js", - "_orchestrator.js", - "_api.js" - ] - }, - "src/routes/(app)/matches/[id]/+page.svelte": { - "file": "entries/pages/(app)/matches/_id_/_page.svelte.js", - "name": "entries/pages/(app)/matches/_id_/_page.svelte", - "src": "src/routes/(app)/matches/[id]/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ] - }, - "src/routes/(app)/settings/+page.server.ts": { - "file": "entries/pages/(app)/settings/_page.server.ts.js", - "name": "entries/pages/(app)/settings/_page.server.ts", - "src": "src/routes/(app)/settings/+page.server.ts", - "isEntry": true, - "imports": [ - "_auth.js", - "_index2.js" - ] - }, - "src/routes/(app)/settings/+page.svelte": { - "file": "entries/pages/(app)/settings/_page.svelte.js", - "name": "entries/pages/(app)/settings/_page.svelte", - "src": "src/routes/(app)/settings/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ] - }, - "src/routes/(app)/teams/+page.server.ts": { - "file": "entries/pages/(app)/teams/_page.server.ts.js", - "name": "entries/pages/(app)/teams/_page.server.ts", - "src": "src/routes/(app)/teams/+page.server.ts", - "isEntry": true, - "imports": [ - "_index2.js" - ] - }, - "src/routes/(app)/teams/+page.svelte": { - "file": "entries/pages/(app)/teams/_page.svelte.js", - "name": "entries/pages/(app)/teams/_page.svelte", - "src": "src/routes/(app)/teams/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ] - }, - "src/routes/+error.svelte": { - "file": "entries/pages/_error.svelte.js", - "name": "entries/pages/_error.svelte", - "src": "src/routes/+error.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_index4.js" - ] - }, - "src/routes/api/health/+server.ts": { - "file": "entries/endpoints/api/health/_server.ts.js", - "name": "entries/endpoints/api/health/_server.ts", - "src": "src/routes/api/health/+server.ts", - "isEntry": true, - "imports": [ - "_index2.js" - ] - }, - "src/routes/api/mappools/+server.ts": { - "file": "entries/endpoints/api/mappools/_server.ts.js", - "name": "entries/endpoints/api/mappools/_server.ts", - "src": "src/routes/api/mappools/+server.ts", - "isEntry": true, - "imports": [ - "_index2.js" - ] - }, - "src/routes/api/mappools/[id]/+server.ts": { - "file": "entries/endpoints/api/mappools/_id_/_server.ts.js", - "name": "entries/endpoints/api/mappools/_id_/_server.ts", - "src": "src/routes/api/mappools/[id]/+server.ts", - "isEntry": true, - "imports": [ - "_index2.js" - ] - }, - "src/routes/api/mappools/[id]/slots/+server.ts": { - "file": "entries/endpoints/api/mappools/_id_/slots/_server.ts.js", - "name": "entries/endpoints/api/mappools/_id_/slots/_server.ts", - "src": "src/routes/api/mappools/[id]/slots/+server.ts", - "isEntry": true, - "imports": [ - "_index2.js" - ] - }, - "src/routes/api/mappools/[id]/slots/[slotId]/+server.ts": { - "file": "entries/endpoints/api/mappools/_id_/slots/_slotId_/_server.ts.js", - "name": "entries/endpoints/api/mappools/_id_/slots/_slotId_/_server.ts", - "src": "src/routes/api/mappools/[id]/slots/[slotId]/+server.ts", - "isEntry": true, - "imports": [ - "_index2.js" - ] - }, - "src/routes/api/matches/+server.ts": { - "file": "entries/endpoints/api/matches/_server.ts.js", - "name": "entries/endpoints/api/matches/_server.ts", - "src": "src/routes/api/matches/+server.ts", - "isEntry": true, - "imports": [ - "_index2.js", - "_engine.js" - ] - }, - "src/routes/api/matches/[id]/+server.ts": { - "file": "entries/endpoints/api/matches/_id_/_server.ts.js", - "name": "entries/endpoints/api/matches/_id_/_server.ts", - "src": "src/routes/api/matches/[id]/+server.ts", - "isEntry": true, - "imports": [ - "_engine.js" - ] - }, - "src/routes/api/matches/[id]/lobby/+server.ts": { - "file": "entries/endpoints/api/matches/_id_/lobby/_server.ts.js", - "name": "entries/endpoints/api/matches/_id_/lobby/_server.ts", - "src": "src/routes/api/matches/[id]/lobby/+server.ts", - "isEntry": true, - "imports": [ - "_engine.js" - ] - }, - "src/routes/api/matches/[id]/pick/+server.ts": { - "file": "entries/endpoints/api/matches/_id_/pick/_server.ts.js", - "name": "entries/endpoints/api/matches/_id_/pick/_server.ts", - "src": "src/routes/api/matches/[id]/pick/+server.ts", - "isEntry": true, - "imports": [ - "_engine.js" - ] - }, - "src/routes/api/matches/[id]/roll/+server.ts": { - "file": "entries/endpoints/api/matches/_id_/roll/_server.ts.js", - "name": "entries/endpoints/api/matches/_id_/roll/_server.ts", - "src": "src/routes/api/matches/[id]/roll/+server.ts", - "isEntry": true, - "imports": [ - "_engine.js" - ] - }, - "src/routes/api/matches/[id]/rolling/+server.ts": { - "file": "entries/endpoints/api/matches/_id_/rolling/_server.ts.js", - "name": "entries/endpoints/api/matches/_id_/rolling/_server.ts", - "src": "src/routes/api/matches/[id]/rolling/+server.ts", - "isEntry": true, - "imports": [ - "_engine.js" - ] - }, - "src/routes/api/matches/[id]/score/+server.ts": { - "file": "entries/endpoints/api/matches/_id_/score/_server.ts.js", - "name": "entries/endpoints/api/matches/_id_/score/_server.ts", - "src": "src/routes/api/matches/[id]/score/+server.ts", - "isEntry": true, - "imports": [ - "_engine.js" - ] - }, - "src/routes/api/osu/beatmap/[id]/+server.ts": { - "file": "entries/endpoints/api/osu/beatmap/_id_/_server.ts.js", - "name": "entries/endpoints/api/osu/beatmap/_id_/_server.ts", - "src": "src/routes/api/osu/beatmap/[id]/+server.ts", - "isEntry": true, - "imports": [ - "_api.js" - ] - }, - "src/routes/api/queue/+server.ts": { - "file": "entries/endpoints/api/queue/_server.ts.js", - "name": "entries/endpoints/api/queue/_server.ts", - "src": "src/routes/api/queue/+server.ts", - "isEntry": true, - "imports": [ - "_engine.js", - "_index2.js" - ] - }, - "src/routes/demo/+page.svelte": { - "file": "entries/pages/demo/_page.svelte.js", - "name": "entries/pages/demo/_page.svelte", - "src": "src/routes/demo/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_server.js", - "_routing.js", - "_url.js", - "_root.js" - ] - }, - "src/routes/demo/better-auth/+page.server.ts": { - "file": "entries/pages/demo/better-auth/_page.server.ts.js", - "name": "entries/pages/demo/better-auth/_page.server.ts", - "src": "src/routes/demo/better-auth/+page.server.ts", - "isEntry": true, - "imports": [ - "_auth.js" - ] - }, - "src/routes/demo/better-auth/+page.svelte": { - "file": "entries/pages/demo/better-auth/_page.svelte.js", - "name": "entries/pages/demo/better-auth/_page.svelte", - "src": "src/routes/demo/better-auth/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ] - }, - "src/routes/demo/better-auth/login/+page.server.ts": { - "file": "entries/pages/demo/better-auth/login/_page.server.ts.js", - "name": "entries/pages/demo/better-auth/login/_page.server.ts", - "src": "src/routes/demo/better-auth/login/+page.server.ts", - "isEntry": true, - "imports": [ - "_auth.js" - ] - }, - "src/routes/demo/better-auth/login/+page.svelte": { - "file": "entries/pages/demo/better-auth/login/_page.svelte.js", - "name": "entries/pages/demo/better-auth/login/_page.svelte", - "src": "src/routes/demo/better-auth/login/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ] - }, - "src/routes/login/+page.server.ts": { - "file": "entries/pages/login/_page.server.ts.js", - "name": "entries/pages/login/_page.server.ts", - "src": "src/routes/login/+page.server.ts", - "isEntry": true, - "imports": [ - "_auth.js" - ] - } -} \ No newline at end of file diff --git a/.svelte-kit/adapter-node/_app/immutable/assets/_layout.Dv2no-8m.css b/.svelte-kit/adapter-node/_app/immutable/assets/_layout.Dv2no-8m.css deleted file mode 100644 index d32e9ae..0000000 --- a/.svelte-kit/adapter-node/_app/immutable/assets/_layout.Dv2no-8m.css +++ /dev/null @@ -1 +0,0 @@ -@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:"Geist Mono", ui-monospace, monospace;--color-red-400:oklch(70.4% .191 22.216);--color-red-500:oklch(63.7% .237 25.331);--color-yellow-400:oklch(85.2% .199 91.936);--color-yellow-500:oklch(79.5% .184 86.047);--color-green-400:oklch(79.2% .209 151.711);--color-green-500:oklch(72.3% .219 149.579);--color-blue-400:oklch(70.7% .165 254.624);--color-blue-500:oklch(62.3% .214 259.815);--color-blue-600:oklch(54.6% .245 262.881);--color-blue-700:oklch(48.8% .243 264.376);--color-purple-400:oklch(71.4% .203 305.504);--color-purple-500:oklch(62.7% .265 303.9);--color-pink-400:oklch(71.8% .202 349.761);--color-pink-500:oklch(65.6% .241 354.308);--color-gray-300:oklch(87.2% .01 258.338);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-md:28rem;--container-2xl:42rem;--container-3xl:48rem;--container-4xl:56rem;--container-5xl:64rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height: 1.5 ;--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height: 1.2 ;--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--text-6xl:3.75rem;--text-6xl--line-height:1;--tracking-tight:-.025em;--tracking-wider:.05em;--tracking-widest:.1em;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--animate-ping:ping 1s cubic-bezier(0, 0, .2, 1) infinite;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--blur-sm:8px;--blur-md:12px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-surface-900:#0a0a0f;--color-surface-800:#12121a;--color-surface-700:#1a1a25;--color-surface-600:#24243a;--color-accent:#ff66ab;--color-accent-hover:#ff85be;--color-accent-dim:#ff66ab33;--color-text-primary:#eeeef0;--color-text-secondary:#8888a0;--color-border:#2a2a3d;--font-body:"Geist", system-ui, sans-serif}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing) * 0)}.start{inset-inline-start:var(--spacing)}.top-0{top:calc(var(--spacing) * 0)}.left-0{left:calc(var(--spacing) * 0)}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.col-span-2{grid-column:span 2/span 2}.mx-auto{margin-inline:auto}.my-4{margin-block:calc(var(--spacing) * 4)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.ml-56{margin-left:calc(var(--spacing) * 56)}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline-block{display:inline-block}.table{display:table}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-2{height:calc(var(--spacing) * 2)}.h-3{height:calc(var(--spacing) * 3)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-10{height:calc(var(--spacing) * 10)}.h-12{height:calc(var(--spacing) * 12)}.h-14{height:calc(var(--spacing) * 14)}.h-16{height:calc(var(--spacing) * 16)}.h-full{height:100%}.max-h-\[80vh\]{max-height:80vh}.min-h-\[70vh\]{min-height:70vh}.min-h-dvh{min-height:100dvh}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-2{width:calc(var(--spacing) * 2)}.w-3{width:calc(var(--spacing) * 3)}.w-6{width:calc(var(--spacing) * 6)}.w-7{width:calc(var(--spacing) * 7)}.w-8{width:calc(var(--spacing) * 8)}.w-10{width:calc(var(--spacing) * 10)}.w-16{width:calc(var(--spacing) * 16)}.w-20{width:calc(var(--spacing) * 20)}.w-24{width:calc(var(--spacing) * 24)}.w-56{width:calc(var(--spacing) * 56)}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-3xl{max-width:var(--container-3xl)}.max-w-4xl{max-width:var(--container-4xl)}.max-w-5xl{max-width:var(--container-5xl)}.max-w-md{max-width:var(--container-md)}.min-w-0{min-width:calc(var(--spacing) * 0)}.flex-1{flex:1}.rotate-90{rotate:90deg}.animate-ping{animation:var(--animate-ping)}.animate-pulse{animation:var(--animate-pulse)}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-\[auto_1fr_auto_auto_auto\]{grid-template-columns:auto 1fr auto auto auto}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-6{gap:calc(var(--spacing) * 6)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-accent\/20{border-color:#ff66ab33}@supports (color:color-mix(in lab,red,red)){.border-accent\/20{border-color:color-mix(in oklab,var(--color-accent) 20%,transparent)}}.border-accent\/30{border-color:#ff66ab4d}@supports (color:color-mix(in lab,red,red)){.border-accent\/30{border-color:color-mix(in oklab,var(--color-accent) 30%,transparent)}}.border-blue-500\/30{border-color:#3080ff4d}@supports (color:color-mix(in lab,red,red)){.border-blue-500\/30{border-color:color-mix(in oklab,var(--color-blue-500) 30%,transparent)}}.border-border{border-color:var(--color-border)}.border-border\/50{border-color:#2a2a3d80}@supports (color:color-mix(in lab,red,red)){.border-border\/50{border-color:color-mix(in oklab,var(--color-border) 50%,transparent)}}.border-gray-300{border-color:var(--color-gray-300)}.border-green-500\/20{border-color:#00c75833}@supports (color:color-mix(in lab,red,red)){.border-green-500\/20{border-color:color-mix(in oklab,var(--color-green-500) 20%,transparent)}}.border-green-500\/30{border-color:#00c7584d}@supports (color:color-mix(in lab,red,red)){.border-green-500\/30{border-color:color-mix(in oklab,var(--color-green-500) 30%,transparent)}}.border-green-500\/40{border-color:#00c75866}@supports (color:color-mix(in lab,red,red)){.border-green-500\/40{border-color:color-mix(in oklab,var(--color-green-500) 40%,transparent)}}.border-pink-500\/30{border-color:#f6339a4d}@supports (color:color-mix(in lab,red,red)){.border-pink-500\/30{border-color:color-mix(in oklab,var(--color-pink-500) 30%,transparent)}}.border-purple-500\/30{border-color:#ac4bff4d}@supports (color:color-mix(in lab,red,red)){.border-purple-500\/30{border-color:color-mix(in oklab,var(--color-purple-500) 30%,transparent)}}.border-red-500\/30{border-color:#fb2c364d}@supports (color:color-mix(in lab,red,red)){.border-red-500\/30{border-color:color-mix(in oklab,var(--color-red-500) 30%,transparent)}}.border-yellow-500\/30{border-color:#edb2004d}@supports (color:color-mix(in lab,red,red)){.border-yellow-500\/30{border-color:color-mix(in oklab,var(--color-yellow-500) 30%,transparent)}}.bg-accent{background-color:var(--color-accent)}.bg-accent-dim{background-color:var(--color-accent-dim)}.bg-accent\/10{background-color:#ff66ab1a}@supports (color:color-mix(in lab,red,red)){.bg-accent\/10{background-color:color-mix(in oklab,var(--color-accent) 10%,transparent)}}.bg-black\/70{background-color:#000000b3}@supports (color:color-mix(in lab,red,red)){.bg-black\/70{background-color:color-mix(in oklab,var(--color-black) 70%,transparent)}}.bg-blue-400{background-color:var(--color-blue-400)}.bg-blue-500\/10{background-color:#3080ff1a}@supports (color:color-mix(in lab,red,red)){.bg-blue-500\/10{background-color:color-mix(in oklab,var(--color-blue-500) 10%,transparent)}}.bg-blue-500\/20{background-color:#3080ff33}@supports (color:color-mix(in lab,red,red)){.bg-blue-500\/20{background-color:color-mix(in oklab,var(--color-blue-500) 20%,transparent)}}.bg-blue-600{background-color:var(--color-blue-600)}.bg-green-400{background-color:var(--color-green-400)}.bg-green-500\/5{background-color:#00c7580d}@supports (color:color-mix(in lab,red,red)){.bg-green-500\/5{background-color:color-mix(in oklab,var(--color-green-500) 5%,transparent)}}.bg-green-500\/20{background-color:#00c75833}@supports (color:color-mix(in lab,red,red)){.bg-green-500\/20{background-color:color-mix(in oklab,var(--color-green-500) 20%,transparent)}}.bg-pink-500\/20{background-color:#f6339a33}@supports (color:color-mix(in lab,red,red)){.bg-pink-500\/20{background-color:color-mix(in oklab,var(--color-pink-500) 20%,transparent)}}.bg-purple-500\/10{background-color:#ac4bff1a}@supports (color:color-mix(in lab,red,red)){.bg-purple-500\/10{background-color:color-mix(in oklab,var(--color-purple-500) 10%,transparent)}}.bg-purple-500\/20{background-color:#ac4bff33}@supports (color:color-mix(in lab,red,red)){.bg-purple-500\/20{background-color:color-mix(in oklab,var(--color-purple-500) 20%,transparent)}}.bg-red-500\/5{background-color:#fb2c360d}@supports (color:color-mix(in lab,red,red)){.bg-red-500\/5{background-color:color-mix(in oklab,var(--color-red-500) 5%,transparent)}}.bg-red-500\/10{background-color:#fb2c361a}@supports (color:color-mix(in lab,red,red)){.bg-red-500\/10{background-color:color-mix(in oklab,var(--color-red-500) 10%,transparent)}}.bg-red-500\/20{background-color:#fb2c3633}@supports (color:color-mix(in lab,red,red)){.bg-red-500\/20{background-color:color-mix(in oklab,var(--color-red-500) 20%,transparent)}}.bg-surface-600{background-color:var(--color-surface-600)}.bg-surface-700{background-color:var(--color-surface-700)}.bg-surface-800{background-color:var(--color-surface-800)}.bg-surface-900{background-color:var(--color-surface-900)}.bg-surface-900\/80{background-color:#0a0a0fcc}@supports (color:color-mix(in lab,red,red)){.bg-surface-900\/80{background-color:color-mix(in oklab,var(--color-surface-900) 80%,transparent)}}.bg-transparent{background-color:#0000}.bg-white{background-color:var(--color-white)}.bg-yellow-400{background-color:var(--color-yellow-400)}.bg-yellow-500\/5{background-color:#edb2000d}@supports (color:color-mix(in lab,red,red)){.bg-yellow-500\/5{background-color:color-mix(in oklab,var(--color-yellow-500) 5%,transparent)}}.bg-yellow-500\/20{background-color:#edb20033}@supports (color:color-mix(in lab,red,red)){.bg-yellow-500\/20{background-color:color-mix(in oklab,var(--color-yellow-500) 20%,transparent)}}.object-cover{object-fit:cover}.p-1{padding:calc(var(--spacing) * 1)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-3\.5{padding-inline:calc(var(--spacing) * 3.5)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.px-8{padding-inline:calc(var(--spacing) * 8)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-5{padding-block:calc(var(--spacing) * 5)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-12{padding-block:calc(var(--spacing) * 12)}.pt-3{padding-top:calc(var(--spacing) * 3)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.text-accent{color:var(--color-accent)}.text-blue-400{color:var(--color-blue-400)}.text-green-400{color:var(--color-green-400)}.text-pink-400{color:var(--color-pink-400)}.text-purple-400{color:var(--color-purple-400)}.text-red-400{color:var(--color-red-400)}.text-red-500{color:var(--color-red-500)}.text-surface-900{color:var(--color-surface-900)}.text-text-primary{color:var(--color-text-primary)}.text-text-secondary{color:var(--color-text-secondary)}.text-text-secondary\/30{color:#8888a04d}@supports (color:color-mix(in lab,red,red)){.text-text-secondary\/30{color:color-mix(in oklab,var(--color-text-secondary) 30%,transparent)}}.text-white{color:var(--color-white)}.text-yellow-400{color:var(--color-yellow-400)}.uppercase{text-transform:uppercase}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.opacity-0{opacity:0}.opacity-30{opacity:.3}.opacity-50{opacity:.5}.opacity-75{opacity:.75}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.backdrop-blur-md{--tw-backdrop-blur:blur(var(--blur-md));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-blur-sm{--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media(hover:hover){.group-hover\:text-accent:is(:where(.group):hover *){color:var(--color-accent)}.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}.placeholder\:text-text-secondary\/50::placeholder{color:#8888a080}@supports (color:color-mix(in lab,red,red)){.placeholder\:text-text-secondary\/50::placeholder{color:color-mix(in oklab,var(--color-text-secondary) 50%,transparent)}}.last\:border-b-0:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}@media(hover:hover){.hover\:border-accent:hover{border-color:var(--color-accent)}.hover\:border-accent\/30:hover{border-color:#ff66ab4d}@supports (color:color-mix(in lab,red,red)){.hover\:border-accent\/30:hover{border-color:color-mix(in oklab,var(--color-accent) 30%,transparent)}}.hover\:border-accent\/40:hover{border-color:#ff66ab66}@supports (color:color-mix(in lab,red,red)){.hover\:border-accent\/40:hover{border-color:color-mix(in oklab,var(--color-accent) 40%,transparent)}}.hover\:border-green-500\/40:hover{border-color:#00c75866}@supports (color:color-mix(in lab,red,red)){.hover\:border-green-500\/40:hover{border-color:color-mix(in oklab,var(--color-green-500) 40%,transparent)}}.hover\:border-red-500\/30:hover{border-color:#fb2c364d}@supports (color:color-mix(in lab,red,red)){.hover\:border-red-500\/30:hover{border-color:color-mix(in oklab,var(--color-red-500) 30%,transparent)}}.hover\:bg-accent-hover:hover{background-color:var(--color-accent-hover)}.hover\:bg-blue-700:hover{background-color:var(--color-blue-700)}.hover\:bg-red-500\/10:hover{background-color:#fb2c361a}@supports (color:color-mix(in lab,red,red)){.hover\:bg-red-500\/10:hover{background-color:color-mix(in oklab,var(--color-red-500) 10%,transparent)}}.hover\:bg-surface-600:hover{background-color:var(--color-surface-600)}.hover\:bg-surface-700:hover{background-color:var(--color-surface-700)}.hover\:bg-yellow-500\/10:hover{background-color:#edb2001a}@supports (color:color-mix(in lab,red,red)){.hover\:bg-yellow-500\/10:hover{background-color:color-mix(in oklab,var(--color-yellow-500) 10%,transparent)}}.hover\:text-accent:hover{color:var(--color-accent)}.hover\:text-red-400:hover{color:var(--color-red-400)}.hover\:text-text-primary:hover{color:var(--color-text-primary)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}}.focus\:border-accent:focus{border-color:var(--color-accent)}.focus\:border-blue-500:focus{border-color:var(--color-blue-500)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-blue-500:focus{--tw-ring-color:var(--color-blue-500)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.disabled\:opacity-50:disabled{opacity:.5}@media(min-width:40rem){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}@media(min-width:64rem){.lg\:col-span-1{grid-column:span 1/span 1}.lg\:col-span-2{grid-column:span 2/span 2}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}}html{background-color:var(--color-surface-900);color:var(--color-text-primary);font-family:var(--font-body)}body{min-height:100dvh}::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:var(--color-surface-900)}::-webkit-scrollbar-thumb{background:var(--color-surface-600);border-radius:3px}::-webkit-scrollbar-thumb:hover{background:var(--color-accent)}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@keyframes ping{75%,to{opacity:0;transform:scale(2)}}@keyframes pulse{50%{opacity:.5}} diff --git a/.svelte-kit/adapter-node/chunks/api.js b/.svelte-kit/adapter-node/chunks/api.js deleted file mode 100644 index 5e6cc8c..0000000 --- a/.svelte-kit/adapter-node/chunks/api.js +++ /dev/null @@ -1,69 +0,0 @@ -import { b as private_env } from "./shared-server.js"; -import "./index2.js"; -const CACHE_TTL = 10 * 60 * 1e3; -const MAX_ENTRIES = 500; -const cache = /* @__PURE__ */ new Map(); -function getCached(key) { - const entry = cache.get(key); - if (!entry) return null; - if (Date.now() > entry.expiresAt) { - cache.delete(key); - return null; - } - return entry.data; -} -function setCache(key, data, ttl = CACHE_TTL) { - if (cache.size >= MAX_ENTRIES) { - const firstKey = cache.keys().next().value; - if (firstKey) cache.delete(firstKey); - } - cache.set(key, { data, expiresAt: Date.now() + ttl }); -} -let clientToken = null; -let clientTokenExpiresAt = 0; -async function getClientToken() { - if (clientToken && Date.now() < clientTokenExpiresAt - 6e4) { - return clientToken; - } - const res = await fetch("https://osu.ppy.sh/oauth/token", { - method: "POST", - headers: { - Accept: "application/json", - "Content-Type": "application/x-www-form-urlencoded" - }, - body: new URLSearchParams({ - client_id: private_env.OSU_CLIENT_ID, - client_secret: private_env.OSU_CLIENT_SECRET, - grant_type: "client_credentials", - scope: "identify public" - }) - }); - if (!res.ok) { - throw new Error(`Failed to get osu! client token: ${res.status} ${res.statusText}`); - } - const data = await res.json(); - clientToken = data.access_token; - clientTokenExpiresAt = Date.now() + data.expires_in * 1e3; - return clientToken; -} -async function osuFetch(path, token) { - const t = await getClientToken(); - const res = await fetch(`https://osu.ppy.sh/api/v2${path}`, { - headers: { Authorization: `Bearer ${t}` } - }); - if (!res.ok) { - throw new Error(`osu! API ${path}: ${res.status} ${res.statusText}`); - } - return res.json(); -} -async function getBeatmap(beatmapId) { - const cacheKey = `beatmap:${beatmapId}`; - const cached = getCached(cacheKey); - if (cached) return cached; - const data = await osuFetch(`/beatmaps/${beatmapId}`); - setCache(cacheKey, data); - return data; -} -export { - getBeatmap as g -}; diff --git a/.svelte-kit/adapter-node/chunks/auth.js b/.svelte-kit/adapter-node/chunks/auth.js deleted file mode 100644 index 588593c..0000000 --- a/.svelte-kit/adapter-node/chunks/auth.js +++ /dev/null @@ -1,7983 +0,0 @@ -import { env, isTest, isDevelopment, logger, createLogger, isProduction, shouldPublishLog } from "@better-auth/core/env"; -import { BetterAuthError, BASE_ERROR_CODES } from "@better-auth/core/error"; -import { isValidIP, normalizeIP, deprecate, normalizePathname, createRateLimitKey, safeJSONParse, generateId, filterOutputFields, defineErrorCodes } from "@better-auth/core/utils"; -import { defineRequestState, getCurrentAuthContext, getCurrentAdapter, runWithTransaction, hasRequestState, runWithRequestState, runWithEndpointContext, runWithAdapter, getBetterAuthVersion } from "@better-auth/core/context"; -import { APIError, toResponse, createRouter } from "better-call"; -import { createAuthMiddleware, createAuthEndpoint } from "@better-auth/core/api"; -import * as import___better_auth_core_db from "@better-auth/core/db"; -import { getAuthTables } from "@better-auth/core/db"; -import * as z from "zod"; -import { Kysely, SqliteDialect, MysqlDialect, PostgresDialect, MssqlDialect, sql } from "kysely"; -import { initGetModelName, initGetFieldName, createAdapterFactory } from "@better-auth/core/db/adapter"; -import { hkdf } from "@noble/hashes/hkdf.js"; -import { sha256 } from "@noble/hashes/sha2.js"; -import { jwtDecrypt, calculateJwkThumbprint, base64url, jwtVerify, EncryptJWT, SignJWT, decodeJwt } from "jose"; -import { hex } from "@better-auth/utils/hex"; -import { createRandomStringGenerator } from "@better-auth/utils/random"; -import "@better-auth/utils"; -import { createHash } from "@better-auth/utils/hash"; -import { base64Url } from "@better-auth/utils/base64"; -import { binary } from "@better-auth/utils/binary"; -import { createHMAC } from "@better-auth/utils/hmac"; -import { xchacha20poly1305 } from "@noble/ciphers/chacha.js"; -import { hexToBytes as hexToBytes$1, managedNonce, utf8ToBytes, bytesToHex } from "@noble/ciphers/utils.js"; -import { SocialProviderListEnum, socialProviders } from "@better-auth/core/social-providers"; -import { JWTExpired } from "jose/errors"; -import defu$1, { createDefu, defu } from "defu"; -import { scryptAsync } from "@noble/hashes/scrypt.js"; -import { hexToBytes } from "@noble/hashes/utils.js"; -import { createTelemetry } from "@better-auth/telemetry"; -import { count, desc, asc, inArray, notInArray, like, lt, lte, ne, gt, gte, eq, and, or, sql as sql$1 } from "drizzle-orm"; -import { b as private_env } from "./shared-server.js"; -import "./url.js"; -import { getRequestEvent } from "@sveltejs/kit/internal/server"; -import "./root.js"; -import "./utils.js"; -import "@sveltejs/kit"; -import "@sveltejs/kit/internal"; -import "./query.js"; -import { d as db, c as team, t as teamMember } from "./index2.js"; -import { betterFetch } from "@better-fetch/fetch"; -import { createAuthorizationURL, validateAuthorizationCode, refreshAccessToken } from "@better-auth/core/oauth2"; -import "@better-auth/utils/otp"; -function checkHasPath(url) { - try { - return (new URL(url).pathname.replace(/\/+$/, "") || "/") !== "/"; - } catch { - throw new BetterAuthError(`Invalid base URL: ${url}. Please provide a valid base URL.`); - } -} -function assertHasProtocol(url) { - try { - const parsedUrl = new URL(url); - if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") throw new BetterAuthError(`Invalid base URL: ${url}. URL must include 'http://' or 'https://'`); - } catch (error2) { - if (error2 instanceof BetterAuthError) throw error2; - throw new BetterAuthError(`Invalid base URL: ${url}. Please provide a valid base URL.`, { cause: error2 }); - } -} -function withPath(url, path = "/api/auth") { - assertHasProtocol(url); - if (checkHasPath(url)) return url; - const trimmedUrl = url.replace(/\/+$/, ""); - if (!path || path === "/") return trimmedUrl; - path = path.startsWith("/") ? path : `/${path}`; - return `${trimmedUrl}${path}`; -} -function validateProxyHeader(header, type) { - if (!header || header.trim() === "") return false; - if (type === "proto") return header === "http" || header === "https"; - if (type === "host") { - if ([ - /\.\./, - /\0/, - /[\s]/, - /^[.]/, - /[<>'"]/, - /javascript:/i, - /file:/i, - /data:/i - ].some((pattern) => pattern.test(header))) return false; - return /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*(:[0-9]{1,5})?$/.test(header) || /^(\d{1,3}\.){3}\d{1,3}(:[0-9]{1,5})?$/.test(header) || /^\[[0-9a-fA-F:]+\](:[0-9]{1,5})?$/.test(header) || /^localhost(:[0-9]{1,5})?$/i.test(header); - } - return false; -} -function getBaseURL(url, path, request, loadEnv, trustedProxyHeaders) { - if (url) return withPath(url, path); - { - const fromEnv = env.BETTER_AUTH_URL || env.NEXT_PUBLIC_BETTER_AUTH_URL || env.PUBLIC_BETTER_AUTH_URL || env.NUXT_PUBLIC_BETTER_AUTH_URL || env.NUXT_PUBLIC_AUTH_URL || (env.BASE_URL !== "/" ? env.BASE_URL : void 0); - if (fromEnv) return withPath(fromEnv, path); - } - const fromRequest = request?.headers.get("x-forwarded-host"); - const fromRequestProto = request?.headers.get("x-forwarded-proto"); - if (fromRequest && fromRequestProto && trustedProxyHeaders) { - if (validateProxyHeader(fromRequestProto, "proto") && validateProxyHeader(fromRequest, "host")) try { - return withPath(`${fromRequestProto}://${fromRequest}`, path); - } catch (_error) { - } - } - if (request) { - const url$1 = getOrigin(request.url); - if (!url$1) throw new BetterAuthError("Could not get origin from request. Please provide a valid base URL."); - return withPath(url$1, path); - } - if (typeof window !== "undefined" && window.location) return withPath(window.location.origin, path); -} -function getOrigin(url) { - try { - const parsedUrl = new URL(url); - return parsedUrl.origin === "null" ? null : parsedUrl.origin; - } catch { - return null; - } -} -function getProtocol(url) { - try { - return new URL(url).protocol; - } catch { - return null; - } -} -function getHost(url) { - try { - return new URL(url).host; - } catch { - return null; - } -} -const LOCALHOST_IP = "127.0.0.1"; -function getIp(req, options) { - if (options.advanced?.ipAddress?.disableIpTracking) return null; - const headers = "headers" in req ? req.headers : req; - const ipHeaders = options.advanced?.ipAddress?.ipAddressHeaders || ["x-forwarded-for"]; - for (const key of ipHeaders) { - const value = "get" in headers ? headers.get(key) : headers[key]; - if (typeof value === "string") { - const ip = value.split(",")[0].trim(); - if (isValidIP(ip)) return normalizeIP(ip, { ipv6Subnet: options.advanced?.ipAddress?.ipv6Subnet }); - } - } - if (isTest() || isDevelopment()) return LOCALHOST_IP; - return null; -} -const { get: getOAuthState, set: setOAuthState } = defineRequestState(() => null); -function escapeRegExpChar(char) { - if (char === "-" || char === "^" || char === "$" || char === "+" || char === "." || char === "(" || char === ")" || char === "|" || char === "[" || char === "]" || char === "{" || char === "}" || char === "*" || char === "?" || char === "\\") return `\\${char}`; - else return char; -} -function escapeRegExpString(str) { - let result = ""; - for (let i = 0; i < str.length; i++) result += escapeRegExpChar(str[i]); - return result; -} -function transform(pattern, separator = true) { - if (Array.isArray(pattern)) return `(?:${pattern.map((p) => `^${transform(p, separator)}$`).join("|")})`; - let separatorSplitter = ""; - let separatorMatcher = ""; - let wildcard = "."; - if (separator === true) { - separatorSplitter = "/"; - separatorMatcher = "[/\\\\]"; - wildcard = "[^/\\\\]"; - } else if (separator) { - separatorSplitter = separator; - separatorMatcher = escapeRegExpString(separatorSplitter); - if (separatorMatcher.length > 1) { - separatorMatcher = `(?:${separatorMatcher})`; - wildcard = `((?!${separatorMatcher}).)`; - } else wildcard = `[^${separatorMatcher}]`; - } - const requiredSeparator = separator ? `${separatorMatcher}+?` : ""; - const optionalSeparator = separator ? `${separatorMatcher}*?` : ""; - const segments = separator ? pattern.split(separatorSplitter) : [pattern]; - let result = ""; - for (let s = 0; s < segments.length; s++) { - const segment = segments[s]; - const nextSegment = segments[s + 1]; - let currentSeparator = ""; - if (!segment && s > 0) continue; - if (separator) if (s === segments.length - 1) currentSeparator = optionalSeparator; - else if (nextSegment !== "**") currentSeparator = requiredSeparator; - else currentSeparator = ""; - if (separator && segment === "**") { - if (currentSeparator) { - result += s === 0 ? "" : currentSeparator; - result += `(?:${wildcard}*?${currentSeparator})*?`; - } - continue; - } - for (let c = 0; c < segment.length; c++) { - const char = segment[c]; - if (char === "\\") { - if (c < segment.length - 1) { - result += escapeRegExpChar(segment[c + 1]); - c++; - } - } else if (char === "?") result += wildcard; - else if (char === "*") result += `${wildcard}*?`; - else result += escapeRegExpChar(char); - } - result += currentSeparator; - } - return result; -} -function isMatch(regexp, sample) { - if (typeof sample !== "string") throw new TypeError(`Sample must be a string, but ${typeof sample} given`); - return regexp.test(sample); -} -function wildcardMatch(pattern, options) { - if (typeof pattern !== "string" && !Array.isArray(pattern)) throw new TypeError(`The first argument must be a single pattern string or an array of patterns, but ${typeof pattern} given`); - if (typeof options === "string" || typeof options === "boolean") options = { separator: options }; - if (arguments.length === 2 && !(typeof options === "undefined" || typeof options === "object" && options !== null && !Array.isArray(options))) throw new TypeError(`The second argument must be an options object or a string/boolean separator, but ${typeof options} given`); - options = options || {}; - if (options.separator === "\\") throw new Error("\\ is not a valid separator because it is used for escaping. Try setting the separator to `true` instead"); - const regexpPattern = transform(pattern, options.separator); - const regexp = new RegExp(`^${regexpPattern}$`, options.flags); - const fn = isMatch.bind(null, regexp); - fn.options = options; - fn.pattern = pattern; - fn.regexp = regexp; - return fn; -} -const matchesOriginPattern = (url, pattern, settings) => { - if (url.startsWith("/")) { - if (settings?.allowRelativePaths) return url.startsWith("/") && /^\/(?!\/|\\|%2f|%5c)[\w\-.\+/@]*(?:\?[\w\-.\+/=&%@]*)?$/.test(url); - return false; - } - if (pattern.includes("*") || pattern.includes("?")) { - if (pattern.includes("://")) return wildcardMatch(pattern)(getOrigin(url) || url); - const host = getHost(url); - if (!host) return false; - return wildcardMatch(pattern)(host); - } - const protocol = getProtocol(url); - return protocol === "http:" || protocol === "https:" || !protocol ? pattern === getOrigin(url) : url.startsWith(pattern); -}; -function shouldSkipCSRFForBackwardCompat(ctx) { - return ctx.context.skipOriginCheck === true && ctx.context.options.advanced?.disableCSRFCheck === void 0; -} -const logBackwardCompatWarning = deprecate(function logBackwardCompatWarning$1() { -}, "disableOriginCheck: true currently also disables CSRF checks. In a future version, disableOriginCheck will ONLY disable URL validation. To keep CSRF disabled, add disableCSRFCheck: true to your config."); -const originCheckMiddleware = createAuthMiddleware(async (ctx) => { - if (ctx.request?.method === "GET" || ctx.request?.method === "OPTIONS" || ctx.request?.method === "HEAD" || !ctx.request) return; - await validateOrigin(ctx); - if (ctx.context.skipOriginCheck) return; - const { body, query } = ctx; - const callbackURL = body?.callbackURL || query?.callbackURL; - const redirectURL = body?.redirectTo; - const errorCallbackURL = body?.errorCallbackURL; - const newUserCallbackURL = body?.newUserCallbackURL; - const validateURL = (url, label) => { - if (!url) return; - if (!ctx.context.isTrustedOrigin(url, { allowRelativePaths: label !== "origin" })) { - ctx.context.logger.error(`Invalid ${label}: ${url}`); - ctx.context.logger.info(`If it's a valid URL, please add ${url} to trustedOrigins in your auth config -`, `Current list of trustedOrigins: ${ctx.context.trustedOrigins}`); - throw new APIError("FORBIDDEN", { message: `Invalid ${label}` }); - } - }; - callbackURL && validateURL(callbackURL, "callbackURL"); - redirectURL && validateURL(redirectURL, "redirectURL"); - errorCallbackURL && validateURL(errorCallbackURL, "errorCallbackURL"); - newUserCallbackURL && validateURL(newUserCallbackURL, "newUserCallbackURL"); -}); -const originCheck = (getValue) => createAuthMiddleware(async (ctx) => { - if (!ctx.request) return; - if (ctx.context.skipOriginCheck) return; - const callbackURL = getValue(ctx); - const validateURL = (url, label) => { - if (!url) return; - if (!ctx.context.isTrustedOrigin(url, { allowRelativePaths: label !== "origin" })) { - ctx.context.logger.error(`Invalid ${label}: ${url}`); - ctx.context.logger.info(`If it's a valid URL, please add ${url} to trustedOrigins in your auth config -`, `Current list of trustedOrigins: ${ctx.context.trustedOrigins}`); - throw new APIError("FORBIDDEN", { message: `Invalid ${label}` }); - } - }; - const callbacks = Array.isArray(callbackURL) ? callbackURL : [callbackURL]; - for (const url of callbacks) validateURL(url, "callbackURL"); -}); -async function validateOrigin(ctx, forceValidate = false) { - const headers = ctx.request?.headers; - if (!headers || !ctx.request) return; - const originHeader = headers.get("origin") || headers.get("referer") || ""; - const useCookies = headers.has("cookie"); - if (ctx.context.skipCSRFCheck) return; - if (shouldSkipCSRFForBackwardCompat(ctx)) { - ctx.context.options.advanced?.disableOriginCheck === true && logBackwardCompatWarning(); - return; - } - const skipOriginCheck = ctx.context.skipOriginCheck; - if (Array.isArray(skipOriginCheck)) try { - const basePath = new URL(ctx.context.baseURL).pathname; - const currentPath = normalizePathname(ctx.request.url, basePath); - if (skipOriginCheck.some((skipPath) => currentPath.startsWith(skipPath))) return; - } catch { - } - if (!(forceValidate || useCookies)) return; - if (!originHeader || originHeader === "null") throw new APIError("FORBIDDEN", { message: BASE_ERROR_CODES.MISSING_OR_NULL_ORIGIN }); - const trustedOrigins = Array.isArray(ctx.context.options.trustedOrigins) ? ctx.context.trustedOrigins : [...ctx.context.trustedOrigins, ...(await ctx.context.options.trustedOrigins?.(ctx.request))?.filter((v) => Boolean(v)) || []]; - if (!trustedOrigins.some((origin) => matchesOriginPattern(originHeader, origin))) { - ctx.context.logger.error(`Invalid origin: ${originHeader}`); - ctx.context.logger.info(`If it's a valid URL, please add ${originHeader} to trustedOrigins in your auth config -`, `Current list of trustedOrigins: ${trustedOrigins}`); - throw new APIError("FORBIDDEN", { message: "Invalid origin" }); - } -} -const formCsrfMiddleware = createAuthMiddleware(async (ctx) => { - if (!ctx.request) return; - await validateFormCsrf(ctx); -}); -async function validateFormCsrf(ctx) { - const req = ctx.request; - if (!req) return; - if (ctx.context.skipCSRFCheck) return; - if (shouldSkipCSRFForBackwardCompat(ctx)) return; - const headers = req.headers; - if (headers.has("cookie")) return await validateOrigin(ctx); - const site = headers.get("Sec-Fetch-Site"); - const mode = headers.get("Sec-Fetch-Mode"); - const dest = headers.get("Sec-Fetch-Dest"); - if (Boolean(site && site.trim() || mode && mode.trim() || dest && dest.trim())) { - if (site === "cross-site" && mode === "navigate") { - ctx.context.logger.error("Blocked cross-site navigation login attempt (CSRF protection)", { - secFetchSite: site, - secFetchMode: mode, - secFetchDest: dest - }); - throw new APIError("FORBIDDEN", { message: BASE_ERROR_CODES.CROSS_SITE_NAVIGATION_LOGIN_BLOCKED }); - } - return await validateOrigin(ctx, true); - } -} -const memory = /* @__PURE__ */ new Map(); -function shouldRateLimit(max, window2, rateLimitData) { - const now2 = Date.now(); - const windowInMs = window2 * 1e3; - return now2 - rateLimitData.lastRequest < windowInMs && rateLimitData.count >= max; -} -function rateLimitResponse(retryAfter) { - return new Response(JSON.stringify({ message: "Too many requests. Please try again later." }), { - status: 429, - statusText: "Too Many Requests", - headers: { "X-Retry-After": retryAfter.toString() } - }); -} -function getRetryAfter(lastRequest, window2) { - const now2 = Date.now(); - const windowInMs = window2 * 1e3; - return Math.ceil((lastRequest + windowInMs - now2) / 1e3); -} -function createDatabaseStorageWrapper(ctx) { - const model = "rateLimit"; - const db2 = ctx.adapter; - return { - get: async (key) => { - const data = (await db2.findMany({ - model, - where: [{ - field: "key", - value: key - }] - }))[0]; - if (typeof data?.lastRequest === "bigint") data.lastRequest = Number(data.lastRequest); - return data; - }, - set: async (key, value, _update) => { - try { - if (_update) await db2.updateMany({ - model, - where: [{ - field: "key", - value: key - }], - update: { - count: value.count, - lastRequest: value.lastRequest - } - }); - else await db2.create({ - model, - data: { - key, - count: value.count, - lastRequest: value.lastRequest - } - }); - } catch (e) { - ctx.logger.error("Error setting rate limit", e); - } - } - }; -} -function getRateLimitStorage(ctx, rateLimitSettings) { - if (ctx.options.rateLimit?.customStorage) return ctx.options.rateLimit.customStorage; - const storage = ctx.rateLimit.storage; - if (storage === "secondary-storage") return { - get: async (key) => { - const data = await ctx.options.secondaryStorage?.get(key); - return data ? safeJSONParse(data) : null; - }, - set: async (key, value, _update) => { - const ttl = rateLimitSettings?.window ?? ctx.options.rateLimit?.window ?? 10; - await ctx.options.secondaryStorage?.set?.(key, JSON.stringify(value), ttl); - } - }; - else if (storage === "memory") return { - async get(key) { - const entry = memory.get(key); - if (!entry) return null; - if (Date.now() >= entry.expiresAt) { - memory.delete(key); - return null; - } - return entry.data; - }, - async set(key, value, _update) { - const ttl = rateLimitSettings?.window ?? ctx.options.rateLimit?.window ?? 10; - const expiresAt = Date.now() + ttl * 1e3; - memory.set(key, { - data: value, - expiresAt - }); - } - }; - return createDatabaseStorageWrapper(ctx); -} -async function onRequestRateLimit(req, ctx) { - if (!ctx.rateLimit.enabled) return; - const basePath = new URL(ctx.baseURL).pathname; - const path = normalizePathname(req.url, basePath); - let currentWindow = ctx.rateLimit.window; - let currentMax = ctx.rateLimit.max; - const ip = getIp(req, ctx.options); - if (!ip) return; - const key = createRateLimitKey(ip, path); - const specialRule = getDefaultSpecialRules().find((rule) => rule.pathMatcher(path)); - if (specialRule) { - currentWindow = specialRule.window; - currentMax = specialRule.max; - } - for (const plugin of ctx.options.plugins || []) if (plugin.rateLimit) { - const matchedRule = plugin.rateLimit.find((rule) => rule.pathMatcher(path)); - if (matchedRule) { - currentWindow = matchedRule.window; - currentMax = matchedRule.max; - break; - } - } - if (ctx.rateLimit.customRules) { - const _path = Object.keys(ctx.rateLimit.customRules).find((p) => { - if (p.includes("*")) return wildcardMatch(p)(path); - return p === path; - }); - if (_path) { - const customRule = ctx.rateLimit.customRules[_path]; - const resolved = typeof customRule === "function" ? await customRule(req, { - window: currentWindow, - max: currentMax - }) : customRule; - if (resolved) { - currentWindow = resolved.window; - currentMax = resolved.max; - } - if (resolved === false) return; - } - } - const storage = getRateLimitStorage(ctx, { window: currentWindow }); - const data = await storage.get(key); - const now2 = Date.now(); - if (!data) await storage.set(key, { - key, - count: 1, - lastRequest: now2 - }); - else { - const timeSinceLastRequest = now2 - data.lastRequest; - if (shouldRateLimit(currentMax, currentWindow, data)) return rateLimitResponse(getRetryAfter(data.lastRequest, currentWindow)); - else if (timeSinceLastRequest > currentWindow * 1e3) await storage.set(key, { - ...data, - count: 1, - lastRequest: now2 - }, true); - else await storage.set(key, { - ...data, - count: data.count + 1, - lastRequest: now2 - }, true); - } -} -function getDefaultSpecialRules() { - return [{ - pathMatcher(path) { - return path.startsWith("/sign-in") || path.startsWith("/sign-up") || path.startsWith("/change-password") || path.startsWith("/change-email"); - }, - window: 10, - max: 3 - }]; -} -const getDate = (span, unit = "ms") => { - return new Date(Date.now() + (unit === "sec" ? span * 1e3 : span)); -}; -const cache = /* @__PURE__ */ new WeakMap(); -function parseOutputData(data, schema2) { - const fields = schema2.fields; - const parsedData = {}; - for (const key in data) { - const field = fields[key]; - if (!field) { - parsedData[key] = data[key]; - continue; - } - if (field.returned === false && key !== "id") continue; - parsedData[key] = data[key]; - } - return parsedData; -} -function getFields(options, table, mode) { - const cacheKey = `${table}:${mode}`; - if (!cache.has(options)) cache.set(options, /* @__PURE__ */ new Map()); - const tableCache = cache.get(options); - if (tableCache.has(cacheKey)) return tableCache.get(cacheKey); - const coreSchema = mode === "output" ? getAuthTables(options)[table]?.fields ?? {} : {}; - const additionalFields = table === "user" || table === "session" || table === "account" ? options[table]?.additionalFields : void 0; - let schema2 = { - ...coreSchema, - ...additionalFields ?? {} - }; - for (const plugin of options.plugins || []) if (plugin.schema && plugin.schema[table]) schema2 = { - ...schema2, - ...plugin.schema[table].fields - }; - tableCache.set(cacheKey, schema2); - return schema2; -} -function parseUserOutput(options, user) { - return parseOutputData(user, { fields: getFields(options, "user", "output") }); -} -function parseSessionOutput(options, session) { - return parseOutputData(session, { fields: getFields(options, "session", "output") }); -} -function parseAccountOutput(options, account) { - const { accessToken: _accessToken, refreshToken: _refreshToken, idToken: _idToken, accessTokenExpiresAt: _accessTokenExpiresAt, refreshTokenExpiresAt: _refreshTokenExpiresAt, password: _password, ...rest } = parseOutputData(account, { fields: getFields(options, "account", "output") }); - return rest; -} -function parseInputData(data, schema2) { - const action = schema2.action || "create"; - const fields = schema2.fields; - const parsedData = Object.assign(/* @__PURE__ */ Object.create(null), null); - for (const key in fields) { - if (key in data) { - if (fields[key].input === false) { - if (fields[key].defaultValue !== void 0) { - if (action !== "update") { - parsedData[key] = fields[key].defaultValue; - continue; - } - } - if (data[key]) throw new APIError("BAD_REQUEST", { message: `${key} is not allowed to be set` }); - continue; - } - if (fields[key].validator?.input && data[key] !== void 0) { - const result = fields[key].validator.input["~standard"].validate(data[key]); - if (result instanceof Promise) throw new APIError("INTERNAL_SERVER_ERROR", { message: "Async validation is not supported for additional fields" }); - if ("issues" in result && result.issues) throw new APIError("BAD_REQUEST", { message: result.issues[0]?.message || "Validation Error" }); - parsedData[key] = result.value; - continue; - } - if (fields[key].transform?.input && data[key] !== void 0) { - parsedData[key] = fields[key].transform?.input(data[key]); - continue; - } - parsedData[key] = data[key]; - continue; - } - if (fields[key].defaultValue !== void 0 && action === "create") { - if (typeof fields[key].defaultValue === "function") { - parsedData[key] = fields[key].defaultValue(); - continue; - } - parsedData[key] = fields[key].defaultValue; - continue; - } - if (fields[key].required && action === "create") throw new APIError("BAD_REQUEST", { message: `${key} is required` }); - } - return parsedData; -} -function parseUserInput(options, user = {}, action) { - return parseInputData(user, { - fields: getFields(options, "user", "input"), - action - }); -} -function parseAdditionalUserInput(options, user) { - const schema2 = getFields(options, "user", "input"); - return parseInputData(user || {}, { fields: schema2 }); -} -function parseAccountInput(options, account) { - return parseInputData(account, { fields: getFields(options, "account", "input") }); -} -function parseSessionInput(options, session) { - return parseInputData(session, { fields: getFields(options, "session", "input") }); -} -function mergeSchema(schema2, newSchema) { - if (!newSchema) return schema2; - for (const table in newSchema) { - const newModelName = newSchema[table]?.modelName; - if (newModelName) schema2[table].modelName = newModelName; - for (const field in schema2[table].fields) { - const newField = newSchema[table]?.fields?.[field]; - if (!newField) continue; - schema2[table].fields[field].fieldName = newField; - } - } - return schema2; -} -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (all, symbols) => { - let target = {}; - for (var name in all) { - __defProp(target, name, { - get: all[name], - enumerable: true - }); - } - return target; -}; -var __copyProps = (to, from, except, desc2) => { - if (from && typeof from === "object" || typeof from === "function") { - for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) { - key = keys[i]; - if (!__hasOwnProp.call(to, key) && key !== except) { - __defProp(to, key, { - get: ((k) => from[k]).bind(null, key), - enumerable: !(desc2 = __getOwnPropDesc(from, key)) || desc2.enumerable - }); - } - } - } - return to; -}; -var __reExport = (target, mod, secondTarget, symbols) => { - __copyProps(target, mod, "default"); -}; -async function getBaseAdapter(options, handleDirectDatabase) { - let adapter; - if (!options.database) { - const tables = getAuthTables(options); - const memoryDB = Object.keys(tables).reduce((acc, key) => { - acc[key] = []; - return acc; - }, {}); - const { memoryAdapter } = await import("./index5.js"); - adapter = memoryAdapter(memoryDB)(options); - } else if (typeof options.database === "function") adapter = options.database(options); - else adapter = await handleDirectDatabase(options); - if (!adapter.transaction) { - logger.warn("Adapter does not correctly implement transaction function, patching it automatically. Please update your adapter implementation."); - adapter.transaction = async (cb) => { - return cb(adapter); - }; - } - return adapter; -} -async function getAdapter(options) { - return getBaseAdapter(options, async (opts) => { - const { createKyselyAdapter: createKyselyAdapter2 } = await import("./index6.js"); - const { kysely, databaseType, transaction } = await createKyselyAdapter2(opts); - if (!kysely) throw new BetterAuthError("Failed to initialize database adapter"); - const { kyselyAdapter } = await import("./index6.js"); - return kyselyAdapter(kysely, { - type: databaseType || "sqlite", - debugLogs: opts.database && "debugLogs" in opts.database ? opts.database.debugLogs : false, - transaction - })(opts); - }); -} -const createFieldAttribute = (type, config2) => { - return { - type, - ...config2 - }; -}; -function convertToDB(fields, values) { - const result = values.id ? { id: values.id } : {}; - for (const key in fields) { - const field = fields[key]; - const value = values[key]; - if (value === void 0) continue; - result[field.fieldName || key] = value; - } - return result; -} -function convertFromDB(fields, values) { - if (!values) return null; - const result = { id: values.id }; - for (const [key, value] of Object.entries(fields)) result[key] = values[value.fieldName || key]; - return result; -} -function getWithHooks(adapter, ctx) { - const hooks = ctx.hooks; - async function createWithHooks(data, model, customCreateFn) { - const context = await getCurrentAuthContext().catch(() => null); - let actualData = data; - for (const hook of hooks || []) { - const toRun = hook[model]?.create?.before; - if (toRun) { - const result = await toRun(actualData, context); - if (result === false) return null; - if (typeof result === "object" && "data" in result) actualData = { - ...actualData, - ...result.data - }; - } - } - const customCreated = customCreateFn ? await customCreateFn.fn(actualData) : null; - const created = !customCreateFn || customCreateFn.executeMainFn ? await (await getCurrentAdapter(adapter)).create({ - model, - data: actualData, - forceAllowId: true - }) : customCreated; - for (const hook of hooks || []) { - const toRun = hook[model]?.create?.after; - if (toRun) await toRun(created, context); - } - return created; - } - async function updateWithHooks(data, where, model, customUpdateFn) { - const context = await getCurrentAuthContext().catch(() => null); - let actualData = data; - for (const hook of hooks || []) { - const toRun = hook[model]?.update?.before; - if (toRun) { - const result = await toRun(data, context); - if (result === false) return null; - if (typeof result === "object" && "data" in result) actualData = { - ...actualData, - ...result.data - }; - } - } - const customUpdated = customUpdateFn ? await customUpdateFn.fn(actualData) : null; - const updated = !customUpdateFn || customUpdateFn.executeMainFn ? await (await getCurrentAdapter(adapter)).update({ - model, - update: actualData, - where - }) : customUpdated; - for (const hook of hooks || []) { - const toRun = hook[model]?.update?.after; - if (toRun) await toRun(updated, context); - } - return updated; - } - async function updateManyWithHooks(data, where, model, customUpdateFn) { - const context = await getCurrentAuthContext().catch(() => null); - let actualData = data; - for (const hook of hooks || []) { - const toRun = hook[model]?.update?.before; - if (toRun) { - const result = await toRun(data, context); - if (result === false) return null; - if (typeof result === "object" && "data" in result) actualData = { - ...actualData, - ...result.data - }; - } - } - const customUpdated = customUpdateFn ? await customUpdateFn.fn(actualData) : null; - const updated = !customUpdateFn || customUpdateFn.executeMainFn ? await (await getCurrentAdapter(adapter)).updateMany({ - model, - update: actualData, - where - }) : customUpdated; - for (const hook of hooks || []) { - const toRun = hook[model]?.update?.after; - if (toRun) await toRun(updated, context); - } - return updated; - } - async function deleteWithHooks(where, model, customDeleteFn) { - const context = await getCurrentAuthContext().catch(() => null); - let entityToDelete = null; - try { - entityToDelete = (await (await getCurrentAdapter(adapter)).findMany({ - model, - where, - limit: 1 - }))[0] || null; - } catch { - } - if (entityToDelete) for (const hook of hooks || []) { - const toRun = hook[model]?.delete?.before; - if (toRun) { - if (await toRun(entityToDelete, context) === false) return null; - } - } - const customDeleted = customDeleteFn ? await customDeleteFn.fn(where) : null; - const deleted = !customDeleteFn || customDeleteFn.executeMainFn ? await (await getCurrentAdapter(adapter)).delete({ - model, - where - }) : customDeleted; - if (entityToDelete) for (const hook of hooks || []) { - const toRun = hook[model]?.delete?.after; - if (toRun) await toRun(entityToDelete, context); - } - return deleted; - } - async function deleteManyWithHooks(where, model, customDeleteFn) { - const context = await getCurrentAuthContext().catch(() => null); - let entitiesToDelete = []; - try { - entitiesToDelete = await (await getCurrentAdapter(adapter)).findMany({ - model, - where - }); - } catch { - } - for (const entity of entitiesToDelete) for (const hook of hooks || []) { - const toRun = hook[model]?.delete?.before; - if (toRun) { - if (await toRun(entity, context) === false) return null; - } - } - const customDeleted = customDeleteFn ? await customDeleteFn.fn(where) : null; - const deleted = !customDeleteFn || customDeleteFn.executeMainFn ? await (await getCurrentAdapter(adapter)).deleteMany({ - model, - where - }) : customDeleted; - for (const entity of entitiesToDelete) for (const hook of hooks || []) { - const toRun = hook[model]?.delete?.after; - if (toRun) await toRun(entity, context); - } - return deleted; - } - return { - createWithHooks, - updateWithHooks, - updateManyWithHooks, - deleteWithHooks, - deleteManyWithHooks - }; -} -const createInternalAdapter = (adapter, ctx) => { - const logger2 = ctx.logger; - const options = ctx.options; - const secondaryStorage = options.secondaryStorage; - const sessionExpiration = options.session?.expiresIn || 3600 * 24 * 7; - const { createWithHooks, updateWithHooks, updateManyWithHooks, deleteWithHooks, deleteManyWithHooks } = getWithHooks(adapter, ctx); - async function refreshUserSessions(user) { - if (!secondaryStorage) return; - const listRaw = await secondaryStorage.get(`active-sessions-${user.id}`); - if (!listRaw) return; - const now2 = Date.now(); - const validSessions = (safeJSONParse(listRaw) || []).filter((s) => s.expiresAt > now2); - await Promise.all(validSessions.map(async ({ token }) => { - const cached = await secondaryStorage.get(token); - if (!cached) return; - const parsed = safeJSONParse(cached); - if (!parsed) return; - const sessionTTL = Math.max(Math.floor(new Date(parsed.session.expiresAt).getTime() - now2) / 1e3, 0); - await secondaryStorage.set(token, JSON.stringify({ - session: parsed.session, - user - }), Math.floor(sessionTTL)); - })); - } - return { - createOAuthUser: async (user, account) => { - return runWithTransaction(adapter, async () => { - const createdUser = await createWithHooks({ - createdAt: /* @__PURE__ */ new Date(), - updatedAt: /* @__PURE__ */ new Date(), - ...user - }, "user", void 0); - return { - user: createdUser, - account: await createWithHooks({ - ...account, - userId: createdUser.id, - createdAt: /* @__PURE__ */ new Date(), - updatedAt: /* @__PURE__ */ new Date() - }, "account", void 0) - }; - }); - }, - createUser: async (user) => { - return await createWithHooks({ - createdAt: /* @__PURE__ */ new Date(), - updatedAt: /* @__PURE__ */ new Date(), - ...user, - email: user.email?.toLowerCase() - }, "user", void 0); - }, - createAccount: async (account) => { - return await createWithHooks({ - createdAt: /* @__PURE__ */ new Date(), - updatedAt: /* @__PURE__ */ new Date(), - ...account - }, "account", void 0); - }, - listSessions: async (userId) => { - if (secondaryStorage) { - const currentList = await secondaryStorage.get(`active-sessions-${userId}`); - if (!currentList) return []; - const list = safeJSONParse(currentList) || []; - const now2 = Date.now(); - const seenTokens = /* @__PURE__ */ new Set(); - const sessions = []; - for (const { token, expiresAt } of list) { - if (expiresAt <= now2 || seenTokens.has(token)) continue; - seenTokens.add(token); - const data = await secondaryStorage.get(token); - if (!data) continue; - try { - const parsed = typeof data === "string" ? JSON.parse(data) : data; - if (!parsed?.session) continue; - sessions.push(parseSessionOutput(ctx.options, { - ...parsed.session, - expiresAt: new Date(parsed.session.expiresAt) - })); - } catch { - continue; - } - } - return sessions; - } - return await (await getCurrentAdapter(adapter)).findMany({ - model: "session", - where: [{ - field: "userId", - value: userId - }] - }); - }, - listUsers: async (limit, offset, sortBy, where) => { - return await (await getCurrentAdapter(adapter)).findMany({ - model: "user", - limit, - offset, - sortBy, - where - }); - }, - countTotalUsers: async (where) => { - const total = await (await getCurrentAdapter(adapter)).count({ - model: "user", - where - }); - if (typeof total === "string") return parseInt(total); - return total; - }, - deleteUser: async (userId) => { - if (!secondaryStorage || options.session?.storeSessionInDatabase) await deleteManyWithHooks([{ - field: "userId", - value: userId - }], "session", void 0); - await deleteManyWithHooks([{ - field: "userId", - value: userId - }], "account", void 0); - await deleteWithHooks([{ - field: "id", - value: userId - }], "user", void 0); - }, - createSession: async (userId, dontRememberMe, override, overrideAll) => { - const ctx$1 = await getCurrentAuthContext().catch(() => null); - const headers = ctx$1?.headers || ctx$1?.request?.headers; - const { id: _, ...rest } = override || {}; - const defaultAdditionalFields = parseSessionInput(ctx$1?.context.options ?? options, {}); - const data = { - ipAddress: ctx$1?.request || ctx$1?.headers ? getIp(ctx$1?.request || ctx$1?.headers, ctx$1?.context.options) || "" : "", - userAgent: headers?.get("user-agent") || "", - ...rest, - expiresAt: dontRememberMe ? getDate(3600 * 24, "sec") : getDate(sessionExpiration, "sec"), - userId, - token: generateId(32), - createdAt: /* @__PURE__ */ new Date(), - updatedAt: /* @__PURE__ */ new Date(), - ...defaultAdditionalFields, - ...overrideAll ? rest : {} - }; - return await createWithHooks(data, "session", secondaryStorage ? { - fn: async (sessionData) => { - const currentList = await secondaryStorage.get(`active-sessions-${userId}`); - let list = []; - const now2 = Date.now(); - if (currentList) { - list = safeJSONParse(currentList) || []; - list = list.filter((session) => session.expiresAt > now2 && session.token !== data.token); - } - const sorted = [...list, { - token: data.token, - expiresAt: data.expiresAt.getTime() - }].sort((a, b) => a.expiresAt - b.expiresAt); - const furthestSessionExp = sorted.at(-1)?.expiresAt ?? data.expiresAt.getTime(); - const furthestSessionTTL = Math.max(Math.floor((furthestSessionExp - now2) / 1e3), 0); - if (furthestSessionTTL > 0) await secondaryStorage.set(`active-sessions-${userId}`, JSON.stringify(sorted), furthestSessionTTL); - const user = await (await getCurrentAdapter(adapter)).findOne({ - model: "user", - where: [{ - field: "id", - value: userId - }] - }); - const sessionTTL = Math.max(Math.floor((data.expiresAt.getTime() - now2) / 1e3), 0); - if (sessionTTL > 0) await secondaryStorage.set(data.token, JSON.stringify({ - session: sessionData, - user - }), sessionTTL); - return sessionData; - }, - executeMainFn: options.session?.storeSessionInDatabase - } : void 0); - }, - findSession: async (token) => { - if (secondaryStorage) { - const sessionStringified = await secondaryStorage.get(token); - if (!sessionStringified && !options.session?.storeSessionInDatabase) return null; - if (sessionStringified) { - const s = safeJSONParse(sessionStringified); - if (!s) return null; - return { - session: parseSessionOutput(ctx.options, { - ...s.session, - expiresAt: new Date(s.session.expiresAt), - createdAt: new Date(s.session.createdAt), - updatedAt: new Date(s.session.updatedAt) - }), - user: parseUserOutput(ctx.options, { - ...s.user, - createdAt: new Date(s.user.createdAt), - updatedAt: new Date(s.user.updatedAt) - }) - }; - } - } - const result = await (await getCurrentAdapter(adapter)).findOne({ - model: "session", - where: [{ - value: token, - field: "token" - }], - join: { user: true } - }); - if (!result) return null; - const { user, ...session } = result; - if (!user) return null; - return { - session: parseSessionOutput(ctx.options, session), - user: parseUserOutput(ctx.options, user) - }; - }, - findSessions: async (sessionTokens) => { - if (secondaryStorage) { - const sessions$1 = []; - for (const sessionToken of sessionTokens) { - const sessionStringified = await secondaryStorage.get(sessionToken); - if (sessionStringified) try { - const s = typeof sessionStringified === "string" ? JSON.parse(sessionStringified) : sessionStringified; - if (!s?.session) continue; - const session = { - session: { - ...s.session, - expiresAt: new Date(s.session.expiresAt) - }, - user: { - ...s.user, - createdAt: new Date(s.user.createdAt), - updatedAt: new Date(s.user.updatedAt) - } - }; - sessions$1.push(session); - } catch { - continue; - } - } - return sessions$1; - } - const sessions = await (await getCurrentAdapter(adapter)).findMany({ - model: "session", - where: [{ - field: "token", - value: sessionTokens, - operator: "in" - }], - join: { user: true } - }); - if (!sessions.length) return []; - if (sessions.some((session) => !session.user)) return []; - return sessions.map((_session) => { - const { user, ...session } = _session; - return { - session, - user - }; - }); - }, - updateSession: async (sessionToken, session) => { - return await updateWithHooks(session, [{ - field: "token", - value: sessionToken - }], "session", secondaryStorage ? { - async fn(data) { - const currentSession = await secondaryStorage.get(sessionToken); - if (!currentSession) return null; - const parsedSession = safeJSONParse(currentSession); - if (!parsedSession) return null; - const mergedSession = { - ...parsedSession.session, - ...data, - expiresAt: new Date(data.expiresAt ?? parsedSession.session.expiresAt), - createdAt: new Date(parsedSession.session.createdAt), - updatedAt: new Date(data.updatedAt ?? parsedSession.session.updatedAt) - }; - const updatedSession = parseSessionOutput(ctx.options, mergedSession); - const now2 = Date.now(); - const expiresMs = new Date(updatedSession.expiresAt).getTime(); - const sessionTTL = Math.max(Math.floor((expiresMs - now2) / 1e3), 0); - if (sessionTTL > 0) { - await secondaryStorage.set(sessionToken, JSON.stringify({ - session: updatedSession, - user: parsedSession.user - }), sessionTTL); - const listKey = `active-sessions-${updatedSession.userId}`; - const listRaw = await secondaryStorage.get(listKey); - const sorted = (listRaw ? safeJSONParse(listRaw) || [] : []).filter((s) => s.token !== sessionToken && s.expiresAt > now2).concat([{ - token: sessionToken, - expiresAt: expiresMs - }]).sort((a, b) => a.expiresAt - b.expiresAt); - const furthestSessionExp = sorted.at(-1)?.expiresAt; - if (furthestSessionExp && furthestSessionExp > now2) await secondaryStorage.set(listKey, JSON.stringify(sorted), Math.floor((furthestSessionExp - now2) / 1e3)); - else await secondaryStorage.delete(listKey); - } - return updatedSession; - }, - executeMainFn: options.session?.storeSessionInDatabase - } : void 0); - }, - deleteSession: async (token) => { - if (secondaryStorage) { - const data = await secondaryStorage.get(token); - if (data) { - const { session } = safeJSONParse(data) ?? {}; - if (!session) { - logger2.error("Session not found in secondary storage"); - return; - } - const userId = session.userId; - const currentList = await secondaryStorage.get(`active-sessions-${userId}`); - if (currentList) { - const list = safeJSONParse(currentList) || []; - const now2 = Date.now(); - const filtered = list.filter((session$1) => session$1.expiresAt > now2 && session$1.token !== token); - const furthestSessionExp = filtered.sort((a, b) => a.expiresAt - b.expiresAt).at(-1)?.expiresAt; - if (filtered.length > 0 && furthestSessionExp && furthestSessionExp > Date.now()) await secondaryStorage.set(`active-sessions-${userId}`, JSON.stringify(filtered), Math.floor((furthestSessionExp - now2) / 1e3)); - else await secondaryStorage.delete(`active-sessions-${userId}`); - } else logger2.error("Active sessions list not found in secondary storage"); - } - await secondaryStorage.delete(token); - if (!options.session?.storeSessionInDatabase || ctx.options.session?.preserveSessionInDatabase) return; - } - await deleteWithHooks([{ - field: "token", - value: token - }], "session", void 0); - }, - deleteAccounts: async (userId) => { - await deleteManyWithHooks([{ - field: "userId", - value: userId - }], "account", void 0); - }, - deleteAccount: async (accountId) => { - await deleteWithHooks([{ - field: "id", - value: accountId - }], "account", void 0); - }, - deleteSessions: async (userIdOrSessionTokens) => { - if (secondaryStorage) { - if (typeof userIdOrSessionTokens === "string") { - const activeSession = await secondaryStorage.get(`active-sessions-${userIdOrSessionTokens}`); - const sessions = activeSession ? safeJSONParse(activeSession) : []; - if (!sessions) return; - for (const session of sessions) await secondaryStorage.delete(session.token); - await secondaryStorage.delete(`active-sessions-${userIdOrSessionTokens}`); - } else for (const sessionToken of userIdOrSessionTokens) if (await secondaryStorage.get(sessionToken)) await secondaryStorage.delete(sessionToken); - if (!options.session?.storeSessionInDatabase || ctx.options.session?.preserveSessionInDatabase) return; - } - await deleteManyWithHooks([{ - field: Array.isArray(userIdOrSessionTokens) ? "token" : "userId", - value: userIdOrSessionTokens, - operator: Array.isArray(userIdOrSessionTokens) ? "in" : void 0 - }], "session", void 0); - }, - findOAuthUser: async (email, accountId, providerId) => { - const account = await (await getCurrentAdapter(adapter)).findOne({ - model: "account", - where: [{ - value: accountId, - field: "accountId" - }, { - value: providerId, - field: "providerId" - }], - join: { user: true } - }); - if (account) if (account.user) return { - user: account.user, - linkedAccount: account, - accounts: [account] - }; - else { - const user = await (await getCurrentAdapter(adapter)).findOne({ - model: "user", - where: [{ - value: email.toLowerCase(), - field: "email" - }] - }); - if (user) return { - user, - linkedAccount: account, - accounts: [account] - }; - return null; - } - else { - const user = await (await getCurrentAdapter(adapter)).findOne({ - model: "user", - where: [{ - value: email.toLowerCase(), - field: "email" - }] - }); - if (user) return { - user, - linkedAccount: null, - accounts: await (await getCurrentAdapter(adapter)).findMany({ - model: "account", - where: [{ - value: user.id, - field: "userId" - }] - }) || [] - }; - else return null; - } - }, - findUserByEmail: async (email, options$1) => { - const result = await (await getCurrentAdapter(adapter)).findOne({ - model: "user", - where: [{ - value: email.toLowerCase(), - field: "email" - }], - join: { ...options$1?.includeAccounts ? { account: true } : {} } - }); - if (!result) return null; - const { account: accounts, ...user } = result; - return { - user, - accounts: accounts ?? [] - }; - }, - findUserById: async (userId) => { - if (!userId) return null; - return await (await getCurrentAdapter(adapter)).findOne({ - model: "user", - where: [{ - field: "id", - value: userId - }] - }); - }, - linkAccount: async (account) => { - return await createWithHooks({ - createdAt: /* @__PURE__ */ new Date(), - updatedAt: /* @__PURE__ */ new Date(), - ...account - }, "account", void 0); - }, - updateUser: async (userId, data) => { - const user = await updateWithHooks(data, [{ - field: "id", - value: userId - }], "user", void 0); - await refreshUserSessions(user); - return user; - }, - updateUserByEmail: async (email, data) => { - const user = await updateWithHooks(data, [{ - field: "email", - value: email.toLowerCase() - }], "user", void 0); - await refreshUserSessions(user); - return user; - }, - updatePassword: async (userId, password) => { - await updateManyWithHooks({ password }, [{ - field: "userId", - value: userId - }, { - field: "providerId", - value: "credential" - }], "account", void 0); - }, - findAccounts: async (userId) => { - return await (await getCurrentAdapter(adapter)).findMany({ - model: "account", - where: [{ - field: "userId", - value: userId - }] - }); - }, - findAccount: async (accountId) => { - return await (await getCurrentAdapter(adapter)).findOne({ - model: "account", - where: [{ - field: "accountId", - value: accountId - }] - }); - }, - findAccountByProviderId: async (accountId, providerId) => { - return await (await getCurrentAdapter(adapter)).findOne({ - model: "account", - where: [{ - field: "accountId", - value: accountId - }, { - field: "providerId", - value: providerId - }] - }); - }, - findAccountByUserId: async (userId) => { - return await (await getCurrentAdapter(adapter)).findMany({ - model: "account", - where: [{ - field: "userId", - value: userId - }] - }); - }, - updateAccount: async (id, data) => { - return await updateWithHooks(data, [{ - field: "id", - value: id - }], "account", void 0); - }, - createVerificationValue: async (data) => { - return await createWithHooks({ - createdAt: /* @__PURE__ */ new Date(), - updatedAt: /* @__PURE__ */ new Date(), - ...data - }, "verification", void 0); - }, - findVerificationValue: async (identifier) => { - const verification = await (await getCurrentAdapter(adapter)).findMany({ - model: "verification", - where: [{ - field: "identifier", - value: identifier - }], - sortBy: { - field: "createdAt", - direction: "desc" - }, - limit: 1 - }); - if (!options.verification?.disableCleanup) await deleteManyWithHooks([{ - field: "expiresAt", - value: /* @__PURE__ */ new Date(), - operator: "lt" - }], "verification", void 0); - return verification[0]; - }, - deleteVerificationValue: async (id) => { - await deleteWithHooks([{ - field: "id", - value: id - }], "verification", void 0); - }, - deleteVerificationByIdentifier: async (identifier) => { - await deleteWithHooks([{ - field: "identifier", - value: identifier - }], "verification", void 0); - }, - updateVerificationValue: async (id, data) => { - return await updateWithHooks(data, [{ - field: "id", - value: id - }], "verification", void 0); - } - }; -}; -function toZodSchema({ fields, isClientSide }) { - const zodFields = Object.keys(fields).reduce((acc, key) => { - const field = fields[key]; - if (!field) return acc; - if (isClientSide && field.input === false) return acc; - let schema2; - if (field.type === "json") schema2 = z.json ? z.json() : z.any(); - else if (field.type === "string[]" || field.type === "number[]") schema2 = z.array(field.type === "string[]" ? z.string() : z.number()); - else if (Array.isArray(field.type)) schema2 = z.any(); - else schema2 = z[field.type](); - if (field?.required === false) schema2 = schema2.optional(); - if (!isClientSide && field?.returned === false) return acc; - return { - ...acc, - [key]: schema2 - }; - }, {}); - return z.object(zodFields); -} -function getSchema(config2) { - const tables = (0, db_exports.getAuthTables)(config2); - const schema2 = {}; - for (const key in tables) { - const table = tables[key]; - const fields = table.fields; - const actualFields = {}; - Object.entries(fields).forEach(([key$1, field]) => { - actualFields[field.fieldName || key$1] = field; - if (field.references) { - const refTable = tables[field.references.model]; - if (refTable) actualFields[field.fieldName || key$1].references = { - ...field.references, - model: refTable.modelName, - field: field.references.field - }; - } - }); - if (schema2[table.modelName]) { - schema2[table.modelName].fields = { - ...schema2[table.modelName].fields, - ...actualFields - }; - continue; - } - schema2[table.modelName] = { - fields: actualFields, - order: table.order || Infinity - }; - } - return schema2; -} -function getKyselyDatabaseType(db2) { - if (!db2) return null; - if ("dialect" in db2) return getKyselyDatabaseType(db2.dialect); - if ("createDriver" in db2) { - if (db2 instanceof SqliteDialect) return "sqlite"; - if (db2 instanceof MysqlDialect) return "mysql"; - if (db2 instanceof PostgresDialect) return "postgres"; - if (db2 instanceof MssqlDialect) return "mssql"; - } - if ("aggregate" in db2) return "sqlite"; - if ("getConnection" in db2) return "mysql"; - if ("connect" in db2) return "postgres"; - if ("fileControl" in db2) return "sqlite"; - if ("open" in db2 && "close" in db2 && "prepare" in db2) return "sqlite"; - return null; -} -const createKyselyAdapter = async (config2) => { - const db2 = config2.database; - if (!db2) return { - kysely: null, - databaseType: null, - transaction: void 0 - }; - if ("db" in db2) return { - kysely: db2.db, - databaseType: db2.type, - transaction: db2.transaction - }; - if ("dialect" in db2) return { - kysely: new Kysely({ dialect: db2.dialect }), - databaseType: db2.type, - transaction: db2.transaction - }; - let dialect = void 0; - const databaseType = getKyselyDatabaseType(db2); - if ("createDriver" in db2) dialect = db2; - if ("aggregate" in db2 && !("createSession" in db2)) dialect = new SqliteDialect({ database: db2 }); - if ("getConnection" in db2) dialect = new MysqlDialect(db2); - if ("connect" in db2) dialect = new PostgresDialect({ pool: db2 }); - if ("fileControl" in db2) { - const { BunSqliteDialect } = await import("./bun-sqlite-dialect.js"); - dialect = new BunSqliteDialect({ database: db2 }); - } - if ("createSession" in db2) { - let DatabaseSync = void 0; - try { - const nodeSqlite = "node:sqlite"; - ({ DatabaseSync } = await import( - /* @vite-ignore */ - /* webpackIgnore: true */ - nodeSqlite - )); - } catch (error2) { - if (error2 !== null && typeof error2 === "object" && "code" in error2 && error2.code !== "ERR_UNKNOWN_BUILTIN_MODULE") throw error2; - } - if (DatabaseSync && db2 instanceof DatabaseSync) { - const { NodeSqliteDialect } = await import("./node-sqlite-dialect.js"); - dialect = new NodeSqliteDialect({ database: db2 }); - } - } - return { - kysely: dialect ? new Kysely({ dialect }) : null, - databaseType, - transaction: void 0 - }; -}; -const map = { - postgres: { - string: [ - "character varying", - "varchar", - "text", - "uuid" - ], - number: [ - "int4", - "integer", - "bigint", - "smallint", - "numeric", - "real", - "double precision" - ], - boolean: ["bool", "boolean"], - date: [ - "timestamptz", - "timestamp", - "date" - ], - json: ["json", "jsonb"] - }, - mysql: { - string: [ - "varchar", - "text", - "uuid" - ], - number: [ - "integer", - "int", - "bigint", - "smallint", - "decimal", - "float", - "double" - ], - boolean: ["boolean", "tinyint"], - date: [ - "timestamp", - "datetime", - "date" - ], - json: ["json"] - }, - sqlite: { - string: ["TEXT"], - number: ["INTEGER", "REAL"], - boolean: ["INTEGER", "BOOLEAN"], - date: ["DATE", "INTEGER"], - json: ["TEXT"] - }, - mssql: { - string: [ - "varchar", - "nvarchar", - "uniqueidentifier" - ], - number: [ - "int", - "bigint", - "smallint", - "decimal", - "float", - "double" - ], - boolean: ["bit", "smallint"], - date: [ - "datetime2", - "date", - "datetime" - ], - json: ["varchar", "nvarchar"] - } -}; -function matchType(columnDataType, fieldType, dbType) { - function normalize(type) { - return type.toLowerCase().split("(")[0].trim(); - } - if (fieldType === "string[]" || fieldType === "number[]") return columnDataType.toLowerCase().includes("json"); - const types2 = map[dbType]; - return (Array.isArray(fieldType) ? types2["string"].map((t) => t.toLowerCase()) : types2[fieldType].map((t) => t.toLowerCase())).includes(normalize(columnDataType)); -} -async function getPostgresSchema(db2) { - try { - const result = await sql`SHOW search_path`.execute(db2); - if (result.rows[0]?.search_path) return result.rows[0].search_path.split(",").map((s) => s.trim()).map((s) => s.replace(/^["']|["']$/g, "")).filter((s) => !s.startsWith("$"))[0] || "public"; - } catch { - } - return "public"; -} -async function getMigrations(config2) { - const betterAuthSchema = getSchema(config2); - const logger$1 = createLogger(config2.logger); - let { kysely: db2, databaseType: dbType } = await createKyselyAdapter(config2); - if (!dbType) { - logger$1.warn("Could not determine database type, defaulting to sqlite. Please provide a type in the database options to avoid this."); - dbType = "sqlite"; - } - if (!db2) { - logger$1.error("Only kysely adapter is supported for migrations. You can use `generate` command to generate the schema, if you're using a different adapter."); - process.exit(1); - } - let currentSchema = "public"; - if (dbType === "postgres") { - currentSchema = await getPostgresSchema(db2); - logger$1.debug(`PostgreSQL migration: Using schema '${currentSchema}' (from search_path)`); - try { - if (!(await sql` - SELECT schema_name - FROM information_schema.schemata - WHERE schema_name = ${currentSchema} - `.execute(db2)).rows[0]) logger$1.warn(`Schema '${currentSchema}' does not exist. Tables will be inspected from available schemas. Consider creating the schema first or checking your database configuration.`); - } catch (error2) { - logger$1.debug(`Could not verify schema existence: ${error2 instanceof Error ? error2.message : String(error2)}`); - } - } - const allTableMetadata = await db2.introspection.getTables(); - let tableMetadata = allTableMetadata; - if (dbType === "postgres") try { - const tablesInSchema = await sql` - SELECT table_name - FROM information_schema.tables - WHERE table_schema = ${currentSchema} - AND table_type = 'BASE TABLE' - `.execute(db2); - const tableNamesInSchema = new Set(tablesInSchema.rows.map((row) => row.table_name)); - tableMetadata = allTableMetadata.filter((table) => table.schema === currentSchema && tableNamesInSchema.has(table.name)); - logger$1.debug(`Found ${tableMetadata.length} table(s) in schema '${currentSchema}': ${tableMetadata.map((t) => t.name).join(", ") || "(none)"}`); - } catch (error2) { - logger$1.warn(`Could not filter tables by schema. Using all discovered tables. Error: ${error2 instanceof Error ? error2.message : String(error2)}`); - } - const toBeCreated = []; - const toBeAdded = []; - for (const [key, value] of Object.entries(betterAuthSchema)) { - const table = tableMetadata.find((t) => t.name === key); - if (!table) { - const tIndex = toBeCreated.findIndex((t) => t.table === key); - const tableData = { - table: key, - fields: value.fields, - order: value.order || Infinity - }; - const insertIndex = toBeCreated.findIndex((t) => (t.order || Infinity) > tableData.order); - if (insertIndex === -1) if (tIndex === -1) toBeCreated.push(tableData); - else toBeCreated[tIndex].fields = { - ...toBeCreated[tIndex].fields, - ...value.fields - }; - else toBeCreated.splice(insertIndex, 0, tableData); - continue; - } - const toBeAddedFields = {}; - for (const [fieldName, field] of Object.entries(value.fields)) { - const column = table.columns.find((c) => c.name === fieldName); - if (!column) { - toBeAddedFields[fieldName] = field; - continue; - } - if (matchType(column.dataType, field.type, dbType)) continue; - else logger$1.warn(`Field ${fieldName} in table ${key} has a different type in the database. Expected ${field.type} but got ${column.dataType}.`); - } - if (Object.keys(toBeAddedFields).length > 0) toBeAdded.push({ - table: key, - fields: toBeAddedFields, - order: value.order || Infinity - }); - } - const migrations = []; - const useUUIDs = config2.advanced?.database?.generateId === "uuid"; - const useNumberId = config2.advanced?.database?.useNumberId || config2.advanced?.database?.generateId === "serial"; - function getType(field, fieldName) { - const type = field.type; - const provider = dbType || "sqlite"; - const typeMap = { - string: { - sqlite: "text", - postgres: "text", - mysql: field.unique ? "varchar(255)" : field.references ? "varchar(36)" : field.sortable ? "varchar(255)" : field.index ? "varchar(255)" : "text", - mssql: field.unique || field.sortable ? "varchar(255)" : field.references ? "varchar(36)" : "varchar(8000)" - }, - boolean: { - sqlite: "integer", - postgres: "boolean", - mysql: "boolean", - mssql: "smallint" - }, - number: { - sqlite: field.bigint ? "bigint" : "integer", - postgres: field.bigint ? "bigint" : "integer", - mysql: field.bigint ? "bigint" : "integer", - mssql: field.bigint ? "bigint" : "integer" - }, - date: { - sqlite: "date", - postgres: "timestamptz", - mysql: "timestamp(3)", - mssql: sql`datetime2(3)` - }, - json: { - sqlite: "text", - postgres: "jsonb", - mysql: "json", - mssql: "varchar(8000)" - }, - id: { - postgres: useNumberId ? sql`integer GENERATED BY DEFAULT AS IDENTITY` : useUUIDs ? "uuid" : "text", - mysql: useNumberId ? "integer" : useUUIDs ? "varchar(36)" : "varchar(36)", - mssql: useNumberId ? "integer" : useUUIDs ? "varchar(36)" : "varchar(36)", - sqlite: useNumberId ? "integer" : "text" - }, - foreignKeyId: { - postgres: useNumberId ? "integer" : useUUIDs ? "uuid" : "text", - mysql: useNumberId ? "integer" : useUUIDs ? "varchar(36)" : "varchar(36)", - mssql: useNumberId ? "integer" : useUUIDs ? "varchar(36)" : "varchar(36)", - sqlite: useNumberId ? "integer" : "text" - }, - "string[]": { - sqlite: "text", - postgres: "jsonb", - mysql: "json", - mssql: "varchar(8000)" - }, - "number[]": { - sqlite: "text", - postgres: "jsonb", - mysql: "json", - mssql: "varchar(8000)" - } - }; - if (fieldName === "id" || field.references?.field === "id") { - if (fieldName === "id") return typeMap.id[provider]; - return typeMap.foreignKeyId[provider]; - } - if (Array.isArray(type)) return "text"; - if (!(type in typeMap)) throw new Error(`Unsupported field type '${String(type)}' for field '${fieldName}'. Allowed types are: string, number, boolean, date, string[], number[]. If you need to store structured data, store it as a JSON string (type: "string") or split it into primitive fields. See https://better-auth.com/docs/advanced/schema#additional-fields`); - return typeMap[type][provider]; - } - const getModelName = initGetModelName({ - schema: getAuthTables(config2), - usePlural: false - }); - const getFieldName = initGetFieldName({ - schema: getAuthTables(config2), - usePlural: false - }); - function getReferencePath(model, field) { - try { - return `${getModelName(model)}.${getFieldName({ - model, - field - })}`; - } catch { - return `${model}.${field}`; - } - } - if (toBeAdded.length) for (const table of toBeAdded) for (const [fieldName, field] of Object.entries(table.fields)) { - const type = getType(field, fieldName); - const builder = db2.schema.alterTable(table.table); - if (field.index) { - const index = db2.schema.alterTable(table.table).addIndex(`${table.table}_${fieldName}_idx`); - migrations.push(index); - } - const built = builder.addColumn(fieldName, type, (col) => { - col = field.required !== false ? col.notNull() : col; - if (field.references) col = col.references(getReferencePath(field.references.model, field.references.field)).onDelete(field.references.onDelete || "cascade"); - if (field.unique) col = col.unique(); - if (field.type === "date" && typeof field.defaultValue === "function" && (dbType === "postgres" || dbType === "mysql" || dbType === "mssql")) if (dbType === "mysql") col = col.defaultTo(sql`CURRENT_TIMESTAMP(3)`); - else col = col.defaultTo(sql`CURRENT_TIMESTAMP`); - return col; - }); - migrations.push(built); - } - const toBeIndexed = []; - if (config2.advanced?.database?.useNumberId) logger$1.warn("`useNumberId` is deprecated. Please use `generateId` with `serial` instead."); - if (toBeCreated.length) for (const table of toBeCreated) { - const idType = getType({ type: useNumberId ? "number" : "string" }, "id"); - let dbT = db2.schema.createTable(table.table).addColumn("id", idType, (col) => { - if (useNumberId) { - if (dbType === "postgres") return col.primaryKey().notNull(); - else if (dbType === "sqlite") return col.primaryKey().notNull(); - else if (dbType === "mssql") return col.identity().primaryKey().notNull(); - return col.autoIncrement().primaryKey().notNull(); - } - if (useUUIDs) { - if (dbType === "postgres") return col.primaryKey().defaultTo(sql`pg_catalog.gen_random_uuid()`).notNull(); - return col.primaryKey().notNull(); - } - return col.primaryKey().notNull(); - }); - for (const [fieldName, field] of Object.entries(table.fields)) { - const type = getType(field, fieldName); - dbT = dbT.addColumn(fieldName, type, (col) => { - col = field.required !== false ? col.notNull() : col; - if (field.references) col = col.references(getReferencePath(field.references.model, field.references.field)).onDelete(field.references.onDelete || "cascade"); - if (field.unique) col = col.unique(); - if (field.type === "date" && typeof field.defaultValue === "function" && (dbType === "postgres" || dbType === "mysql" || dbType === "mssql")) if (dbType === "mysql") col = col.defaultTo(sql`CURRENT_TIMESTAMP(3)`); - else col = col.defaultTo(sql`CURRENT_TIMESTAMP`); - return col; - }); - if (field.index) { - const builder = db2.schema.createIndex(`${table.table}_${fieldName}_${field.unique ? "uidx" : "idx"}`).on(table.table).columns([fieldName]); - toBeIndexed.push(field.unique ? builder.unique() : builder); - } - } - migrations.push(dbT); - } - if (toBeIndexed.length) for (const index of toBeIndexed) migrations.push(index); - async function runMigrations() { - for (const migration of migrations) await migration.execute(); - } - async function compileMigrations() { - return migrations.map((m) => m.compile().sql).join(";\n\n") + ";"; - } - return { - toBeCreated, - toBeAdded, - runMigrations, - compileMigrations - }; -} -var db_exports = /* @__PURE__ */ __export({ - convertFromDB: () => convertFromDB, - convertToDB: () => convertToDB, - createFieldAttribute: () => createFieldAttribute, - createInternalAdapter: () => createInternalAdapter, - getAdapter: () => getAdapter, - getBaseAdapter: () => getBaseAdapter, - getMigrations: () => getMigrations, - getSchema: () => getSchema, - getWithHooks: () => getWithHooks, - matchType: () => matchType, - mergeSchema: () => mergeSchema, - parseAccountInput: () => parseAccountInput, - parseAccountOutput: () => parseAccountOutput, - parseAdditionalUserInput: () => parseAdditionalUserInput, - parseInputData: () => parseInputData, - parseSessionInput: () => parseSessionInput, - parseSessionOutput: () => parseSessionOutput, - parseUserInput: () => parseUserInput, - parseUserOutput: () => parseUserOutput, - toZodSchema: () => toZodSchema -}); -__reExport(db_exports, import___better_auth_core_db); -async function signJWT(payload, secret, expiresIn = 3600) { - return await new SignJWT(payload).setProtectedHeader({ alg: "HS256" }).setIssuedAt().setExpirationTime(Math.floor(Date.now() / 1e3) + expiresIn).sign(new TextEncoder().encode(secret)); -} -async function verifyJWT(token, secret) { - try { - return (await jwtVerify(token, new TextEncoder().encode(secret))).payload; - } catch { - return null; - } -} -const info = new Uint8Array([ - 66, - 101, - 116, - 116, - 101, - 114, - 65, - 117, - 116, - 104, - 46, - 106, - 115, - 32, - 71, - 101, - 110, - 101, - 114, - 97, - 116, - 101, - 100, - 32, - 69, - 110, - 99, - 114, - 121, - 112, - 116, - 105, - 111, - 110, - 32, - 75, - 101, - 121 -]); -const now = () => Date.now() / 1e3 | 0; -const alg = "dir"; -const enc = "A256CBC-HS512"; -async function symmetricEncodeJWT(payload, secret, salt, expiresIn = 3600) { - const encryptionSecret = hkdf(sha256, new TextEncoder().encode(secret), new TextEncoder().encode(salt), info, 64); - const thumbprint = await calculateJwkThumbprint({ - kty: "oct", - k: base64url.encode(encryptionSecret) - }, "sha256"); - return await new EncryptJWT(payload).setProtectedHeader({ - alg, - enc, - kid: thumbprint - }).setIssuedAt().setExpirationTime(now() + expiresIn).setJti(crypto.randomUUID()).encrypt(encryptionSecret); -} -async function symmetricDecodeJWT(token, secret, salt) { - if (!token) return null; - try { - const { payload } = await jwtDecrypt(token, async ({ kid }) => { - const encryptionSecret = hkdf(sha256, new TextEncoder().encode(secret), new TextEncoder().encode(salt), info, 64); - if (kid === void 0) return encryptionSecret; - if (kid === await calculateJwkThumbprint({ - kty: "oct", - k: base64url.encode(encryptionSecret) - }, "sha256")) return encryptionSecret; - throw new Error("no matching decryption secret"); - }, { - clockTolerance: 15, - keyManagementAlgorithms: [alg], - contentEncryptionAlgorithms: [enc, "A256GCM"] - }); - return payload; - } catch { - return null; - } -} -function constantTimeEqual(a, b) { - if (typeof a === "string") a = new TextEncoder().encode(a); - if (typeof b === "string") b = new TextEncoder().encode(b); - const aBuffer = new Uint8Array(a); - const bBuffer = new Uint8Array(b); - let c = aBuffer.length ^ bBuffer.length; - const length = Math.max(aBuffer.length, bBuffer.length); - for (let i = 0; i < length; i++) c |= (i < aBuffer.length ? aBuffer[i] : 0) ^ (i < bBuffer.length ? bBuffer[i] : 0); - return c === 0; -} -const config = { - N: 16384, - r: 16, - p: 1, - dkLen: 64 -}; -async function generateKey(password, salt) { - return await scryptAsync(password.normalize("NFKC"), salt, { - N: config.N, - p: config.p, - r: config.r, - dkLen: config.dkLen, - maxmem: 128 * config.N * config.r * 2 - }); -} -const hashPassword = async (password) => { - const salt = hex.encode(crypto.getRandomValues(new Uint8Array(16))); - const key = await generateKey(password, salt); - return `${salt}:${hex.encode(key)}`; -}; -const verifyPassword$1 = async ({ hash, password }) => { - const [salt, key] = hash.split(":"); - if (!salt || !key) throw new BetterAuthError("Invalid password hash"); - return constantTimeEqual(await generateKey(password, salt), hexToBytes(key)); -}; -const generateRandomString = createRandomStringGenerator("a-z", "0-9", "A-Z", "-_"); -const symmetricEncrypt = async ({ key, data }) => { - const keyAsBytes = await createHash("SHA-256").digest(key); - const dataAsBytes = utf8ToBytes(data); - return bytesToHex(managedNonce(xchacha20poly1305)(new Uint8Array(keyAsBytes)).encrypt(dataAsBytes)); -}; -const symmetricDecrypt = async ({ key, data }) => { - const keyAsBytes = await createHash("SHA-256").digest(key); - const dataAsBytes = hexToBytes$1(data); - const chacha = managedNonce(xchacha20poly1305)(new Uint8Array(keyAsBytes)); - return new TextDecoder().decode(chacha.decrypt(dataAsBytes)); -}; -const ALLOWED_COOKIE_SIZE = 4096; -const ESTIMATED_EMPTY_COOKIE_SIZE = 200; -const CHUNK_SIZE = ALLOWED_COOKIE_SIZE - ESTIMATED_EMPTY_COOKIE_SIZE; -function parseCookiesFromContext(ctx) { - const cookieHeader = ctx.headers?.get("cookie"); - if (!cookieHeader) return {}; - const cookies = {}; - const pairs = cookieHeader.split("; "); - for (const pair of pairs) { - const [name, ...valueParts] = pair.split("="); - if (name && valueParts.length > 0) cookies[name] = valueParts.join("="); - } - return cookies; -} -function getChunkIndex(cookieName) { - const parts = cookieName.split("."); - const lastPart = parts[parts.length - 1]; - const index = parseInt(lastPart || "0", 10); - return isNaN(index) ? 0 : index; -} -function readExistingChunks(cookieName, ctx) { - const chunks = {}; - const cookies = parseCookiesFromContext(ctx); - for (const [name, value] of Object.entries(cookies)) if (name.startsWith(cookieName)) chunks[name] = value; - return chunks; -} -function joinChunks(chunks) { - return Object.keys(chunks).sort((a, b) => { - return getChunkIndex(a) - getChunkIndex(b); - }).map((key) => chunks[key]).join(""); -} -function chunkCookie(storeName, cookie, chunks, logger2) { - const chunkCount = Math.ceil(cookie.value.length / CHUNK_SIZE); - if (chunkCount === 1) { - chunks[cookie.name] = cookie.value; - return [cookie]; - } - const cookies = []; - for (let i = 0; i < chunkCount; i++) { - const name = `${cookie.name}.${i}`; - const start = i * CHUNK_SIZE; - const value = cookie.value.substring(start, start + CHUNK_SIZE); - cookies.push({ - ...cookie, - name, - value - }); - chunks[name] = value; - } - logger2.debug(`CHUNKING_${storeName.toUpperCase()}_COOKIE`, { - message: `${storeName} cookie exceeds allowed ${ALLOWED_COOKIE_SIZE} bytes.`, - emptyCookieSize: ESTIMATED_EMPTY_COOKIE_SIZE, - valueSize: cookie.value.length, - chunkCount, - chunks: cookies.map((c) => c.value.length + ESTIMATED_EMPTY_COOKIE_SIZE) - }); - return cookies; -} -function getCleanCookies(chunks, cookieOptions) { - const cleanedChunks = {}; - for (const name in chunks) cleanedChunks[name] = { - name, - value: "", - attributes: { - ...cookieOptions, - maxAge: 0 - } - }; - return cleanedChunks; -} -const storeFactory = (storeName) => (cookieName, cookieOptions, ctx) => { - const chunks = readExistingChunks(cookieName, ctx); - const logger2 = ctx.context.logger; - return { - getValue() { - return joinChunks(chunks); - }, - hasChunks() { - return Object.keys(chunks).length > 0; - }, - chunk(value, options) { - const cleanedChunks = getCleanCookies(chunks, cookieOptions); - for (const name in chunks) delete chunks[name]; - const cookies = cleanedChunks; - const chunked = chunkCookie(storeName, { - name: cookieName, - value, - attributes: { - ...cookieOptions, - ...options - } - }, chunks, logger2); - for (const chunk of chunked) cookies[chunk.name] = chunk; - return Object.values(cookies); - }, - clean() { - const cleanedChunks = getCleanCookies(chunks, cookieOptions); - for (const name in chunks) delete chunks[name]; - return Object.values(cleanedChunks); - }, - setCookies(cookies) { - for (const cookie of cookies) ctx.setCookie(cookie.name, cookie.value, cookie.attributes); - } - }; -}; -const createSessionStore = storeFactory("Session"); -const createAccountStore = storeFactory("Account"); -function getChunkedCookie(ctx, cookieName) { - const value = ctx.getCookie(cookieName); - if (value) return value; - const chunks = []; - const cookieHeader = ctx.headers?.get("cookie"); - if (!cookieHeader) return null; - const cookies = {}; - const pairs = cookieHeader.split("; "); - for (const pair of pairs) { - const [name, ...valueParts] = pair.split("="); - if (name && valueParts.length > 0) cookies[name] = valueParts.join("="); - } - for (const [name, val] of Object.entries(cookies)) if (name.startsWith(cookieName + ".")) { - const indexStr = name.split(".").at(-1); - const index = parseInt(indexStr || "0", 10); - if (!isNaN(index)) chunks.push({ - index, - value: val - }); - } - if (chunks.length > 0) { - chunks.sort((a, b) => a.index - b.index); - return chunks.map((c) => c.value).join(""); - } - return null; -} -async function setAccountCookie(c, accountData) { - const accountDataCookie = c.context.authCookies.accountData; - const options = { - maxAge: 300, - ...accountDataCookie.attributes - }; - const data = await symmetricEncodeJWT(accountData, c.context.secret, "better-auth-account", options.maxAge); - if (data.length > ALLOWED_COOKIE_SIZE) { - const accountStore = createAccountStore(accountDataCookie.name, options, c); - const cookies = accountStore.chunk(data, options); - accountStore.setCookies(cookies); - } else { - const accountStore = createAccountStore(accountDataCookie.name, options, c); - if (accountStore.hasChunks()) { - const cleanCookies = accountStore.clean(); - accountStore.setCookies(cleanCookies); - } - c.setCookie(accountDataCookie.name, data, options); - } -} -async function getAccountCookie(c) { - const accountCookie = getChunkedCookie(c, c.context.authCookies.accountData.name); - if (accountCookie) { - const accountData = safeJSONParse(await symmetricDecodeJWT(accountCookie, c.context.secret, "better-auth-account")); - if (accountData) return accountData; - } - return null; -} -const getSessionQuerySchema = z.optional(z.object({ - disableCookieCache: z.coerce.boolean().meta({ description: "Disable cookie cache and fetch session from database" }).optional(), - disableRefresh: z.coerce.boolean().meta({ description: "Disable session refresh. Useful for checking session status, without updating the session" }).optional() -})); -function isPromise(obj) { - return !!obj && (typeof obj === "object" || typeof obj === "function") && typeof obj.then === "function"; -} -const SEC = 1e3; -const MIN = SEC * 60; -const HOUR = MIN * 60; -const DAY = HOUR * 24; -const WEEK = DAY * 7; -const MONTH = DAY * 30; -const YEAR = DAY * 365.25; -const REGEX = /^(\+|\-)? ?(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|months?|mo|years?|yrs?|y)(?: (ago|from now))?$/i; -function parse(value) { - const match = REGEX.exec(value); - if (!match || match[4] && match[1]) throw new TypeError(`Invalid time string format: "${value}". Use formats like "7d", "30m", "1 hour", etc.`); - const n = parseFloat(match[2]); - const unit = match[3].toLowerCase(); - let result; - switch (unit) { - case "years": - case "year": - case "yrs": - case "yr": - case "y": - result = n * YEAR; - break; - case "months": - case "month": - case "mo": - result = n * MONTH; - break; - case "weeks": - case "week": - case "w": - result = n * WEEK; - break; - case "days": - case "day": - case "d": - result = n * DAY; - break; - case "hours": - case "hour": - case "hrs": - case "hr": - case "h": - result = n * HOUR; - break; - case "minutes": - case "minute": - case "mins": - case "min": - case "m": - result = n * MIN; - break; - case "seconds": - case "second": - case "secs": - case "sec": - case "s": - result = n * SEC; - break; - default: - throw new TypeError(`Unknown time unit: "${unit}"`); - } - if (match[1] === "-" || match[4] === "ago") return -result; - return result; -} -function ms(value) { - return parse(value); -} -function sec(value) { - return Math.round(parse(value) / 1e3); -} -const SECURE_COOKIE_PREFIX = "__Secure-"; -function splitSetCookieHeader(setCookie) { - if (!setCookie) return []; - const result = []; - let current = ""; - let i = 0; - while (i < setCookie.length) { - const c = setCookie[i]; - if (c === ",") { - const lower = current.toLowerCase(); - if (lower.includes("expires=") && !lower.includes("gmt")) { - current += c; - i++; - } else { - const trimmed$1 = current.trim(); - if (trimmed$1) result.push(trimmed$1); - current = ""; - i++; - if (i < setCookie.length && setCookie[i] === " ") i++; - } - continue; - } - current += c; - i++; - } - const trimmed = current.trim(); - if (trimmed) result.push(trimmed); - return result; -} -function parseSetCookieHeader(setCookie) { - const cookies = /* @__PURE__ */ new Map(); - splitSetCookieHeader(setCookie).forEach((cookieString) => { - const [nameValue, ...attributes] = cookieString.split(";").map((part) => part.trim()); - const [name, ...valueParts] = (nameValue || "").split("="); - const value = valueParts.join("="); - if (!name || value === void 0) return; - const attrObj = { value }; - attributes.forEach((attribute) => { - const [attrName, ...attrValueParts] = attribute.split("="); - const attrValue = attrValueParts.join("="); - const normalizedAttrName = attrName.trim().toLowerCase(); - switch (normalizedAttrName) { - case "max-age": - attrObj["max-age"] = attrValue ? parseInt(attrValue.trim(), 10) : void 0; - break; - case "expires": - attrObj.expires = attrValue ? new Date(attrValue.trim()) : void 0; - break; - case "domain": - attrObj.domain = attrValue ? attrValue.trim() : void 0; - break; - case "path": - attrObj.path = attrValue ? attrValue.trim() : void 0; - break; - case "secure": - attrObj.secure = true; - break; - case "httponly": - attrObj.httponly = true; - break; - case "samesite": - attrObj.samesite = attrValue ? attrValue.trim().toLowerCase() : void 0; - break; - default: - attrObj[normalizedAttrName] = attrValue ? attrValue.trim() : true; - break; - } - }); - cookies.set(name, attrObj); - }); - return cookies; -} -function createCookieGetter(options) { - const secureCookiePrefix = (options.advanced?.useSecureCookies !== void 0 ? options.advanced?.useSecureCookies : options.baseURL ? options.baseURL.startsWith("https://") ? true : false : isProduction) ? SECURE_COOKIE_PREFIX : ""; - const crossSubdomainEnabled = !!options.advanced?.crossSubDomainCookies?.enabled; - const domain = crossSubdomainEnabled ? options.advanced?.crossSubDomainCookies?.domain || (options.baseURL ? new URL(options.baseURL).hostname : void 0) : void 0; - if (crossSubdomainEnabled && !domain) throw new BetterAuthError("baseURL is required when crossSubdomainCookies are enabled"); - function createCookie(cookieName, overrideAttributes = {}) { - const prefix = options.advanced?.cookiePrefix || "better-auth"; - const name = options.advanced?.cookies?.[cookieName]?.name || `${prefix}.${cookieName}`; - const attributes = options.advanced?.cookies?.[cookieName]?.attributes; - return { - name: `${secureCookiePrefix}${name}`, - attributes: { - secure: !!secureCookiePrefix, - sameSite: "lax", - path: "/", - httpOnly: true, - ...crossSubdomainEnabled ? { domain } : {}, - ...options.advanced?.defaultCookieAttributes, - ...overrideAttributes, - ...attributes - } - }; - } - return createCookie; -} -function getCookies(options) { - const createCookie = createCookieGetter(options); - const sessionToken = createCookie("session_token", { maxAge: options.session?.expiresIn || sec("7d") }); - const sessionData = createCookie("session_data", { maxAge: options.session?.cookieCache?.maxAge || 300 }); - const accountData = createCookie("account_data", { maxAge: options.session?.cookieCache?.maxAge || 300 }); - const dontRememberToken = createCookie("dont_remember"); - return { - sessionToken: { - name: sessionToken.name, - attributes: sessionToken.attributes - }, - sessionData: { - name: sessionData.name, - attributes: sessionData.attributes - }, - dontRememberToken: { - name: dontRememberToken.name, - attributes: dontRememberToken.attributes - }, - accountData: { - name: accountData.name, - attributes: accountData.attributes - } - }; -} -async function setCookieCache(ctx, session, dontRememberMe) { - if (!ctx.context.options.session?.cookieCache?.enabled) return; - const filteredSession = filterOutputFields(session.session, ctx.context.options.session?.additionalFields); - const filteredUser = parseUserOutput(ctx.context.options, session.user); - const versionConfig = ctx.context.options.session?.cookieCache?.version; - let version = "1"; - if (versionConfig) { - if (typeof versionConfig === "string") version = versionConfig; - else if (typeof versionConfig === "function") { - const result = versionConfig(session.session, session.user); - version = isPromise(result) ? await result : result; - } - } - const sessionData = { - session: filteredSession, - user: filteredUser, - updatedAt: Date.now(), - version - }; - const options = { - ...ctx.context.authCookies.sessionData.attributes, - maxAge: dontRememberMe ? void 0 : ctx.context.authCookies.sessionData.attributes.maxAge - }; - const expiresAtDate = getDate(options.maxAge || 60, "sec").getTime(); - const strategy = ctx.context.options.session?.cookieCache?.strategy || "compact"; - let data; - if (strategy === "jwe") data = await symmetricEncodeJWT(sessionData, ctx.context.secret, "better-auth-session", options.maxAge || 300); - else if (strategy === "jwt") data = await signJWT(sessionData, ctx.context.secret, options.maxAge || 300); - else data = base64Url.encode(JSON.stringify({ - session: sessionData, - expiresAt: expiresAtDate, - signature: await createHMAC("SHA-256", "base64urlnopad").sign(ctx.context.secret, JSON.stringify({ - ...sessionData, - expiresAt: expiresAtDate - })) - }), { padding: false }); - if (data.length > 4093) { - const sessionStore = createSessionStore(ctx.context.authCookies.sessionData.name, options, ctx); - const cookies = sessionStore.chunk(data, options); - sessionStore.setCookies(cookies); - } else { - const sessionStore = createSessionStore(ctx.context.authCookies.sessionData.name, options, ctx); - if (sessionStore.hasChunks()) { - const cleanCookies = sessionStore.clean(); - sessionStore.setCookies(cleanCookies); - } - ctx.setCookie(ctx.context.authCookies.sessionData.name, data, options); - } - if (ctx.context.options.account?.storeAccountCookie) { - const accountData = await getAccountCookie(ctx); - if (accountData) await setAccountCookie(ctx, accountData); - } -} -async function setSessionCookie(ctx, session, dontRememberMe, overrides) { - const dontRememberMeCookie = await ctx.getSignedCookie(ctx.context.authCookies.dontRememberToken.name, ctx.context.secret); - dontRememberMe = dontRememberMe !== void 0 ? dontRememberMe : !!dontRememberMeCookie; - const options = ctx.context.authCookies.sessionToken.attributes; - const maxAge = dontRememberMe ? void 0 : ctx.context.sessionConfig.expiresIn; - await ctx.setSignedCookie(ctx.context.authCookies.sessionToken.name, session.session.token, ctx.context.secret, { - ...options, - maxAge, - ...overrides - }); - if (dontRememberMe) await ctx.setSignedCookie(ctx.context.authCookies.dontRememberToken.name, "true", ctx.context.secret, ctx.context.authCookies.dontRememberToken.attributes); - await setCookieCache(ctx, session, dontRememberMe); - ctx.context.setNewSession(session); -} -function expireCookie(ctx, cookie) { - ctx.setCookie(cookie.name, "", { - ...cookie.attributes, - maxAge: 0 - }); -} -function deleteSessionCookie(ctx, skipDontRememberMe) { - expireCookie(ctx, ctx.context.authCookies.sessionToken); - expireCookie(ctx, ctx.context.authCookies.sessionData); - if (ctx.context.options.account?.storeAccountCookie) { - expireCookie(ctx, ctx.context.authCookies.accountData); - const accountStore = createAccountStore(ctx.context.authCookies.accountData.name, ctx.context.authCookies.accountData.attributes, ctx); - const cleanCookies$1 = accountStore.clean(); - accountStore.setCookies(cleanCookies$1); - } - if (ctx.context.oauthConfig.storeStateStrategy === "cookie") expireCookie(ctx, ctx.context.createAuthCookie("oauth_state")); - const sessionStore = createSessionStore(ctx.context.authCookies.sessionData.name, ctx.context.authCookies.sessionData.attributes, ctx); - const cleanCookies = sessionStore.clean(); - sessionStore.setCookies(cleanCookies); - expireCookie(ctx, ctx.context.authCookies.dontRememberToken); -} -const getSession = () => createAuthEndpoint("/get-session", { - method: "GET", - operationId: "getSession", - query: getSessionQuerySchema, - requireHeaders: true, - metadata: { openapi: { - operationId: "getSession", - description: "Get the current session", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - nullable: true, - properties: { - session: { $ref: "#/components/schemas/Session" }, - user: { $ref: "#/components/schemas/User" } - }, - required: ["session", "user"] - } } } - } } - } } -}, async (ctx) => { - try { - const sessionCookieToken = await ctx.getSignedCookie(ctx.context.authCookies.sessionToken.name, ctx.context.secret); - if (!sessionCookieToken) return null; - const sessionDataCookie = getChunkedCookie(ctx, ctx.context.authCookies.sessionData.name); - let sessionDataPayload = null; - if (sessionDataCookie) { - const strategy = ctx.context.options.session?.cookieCache?.strategy || "compact"; - if (strategy === "jwe") { - const payload = await symmetricDecodeJWT(sessionDataCookie, ctx.context.secret, "better-auth-session"); - if (payload && payload.session && payload.user) sessionDataPayload = { - session: { - session: payload.session, - user: payload.user, - updatedAt: payload.updatedAt, - version: payload.version - }, - expiresAt: payload.exp ? payload.exp * 1e3 : Date.now() - }; - else { - expireCookie(ctx, ctx.context.authCookies.sessionData); - return ctx.json(null); - } - } else if (strategy === "jwt") { - const payload = await verifyJWT(sessionDataCookie, ctx.context.secret); - if (payload && payload.session && payload.user) sessionDataPayload = { - session: { - session: payload.session, - user: payload.user, - updatedAt: payload.updatedAt, - version: payload.version - }, - expiresAt: payload.exp ? payload.exp * 1e3 : Date.now() - }; - else { - expireCookie(ctx, ctx.context.authCookies.sessionData); - return ctx.json(null); - } - } else { - const parsed = safeJSONParse(binary.decode(base64Url.decode(sessionDataCookie))); - if (parsed) if (await createHMAC("SHA-256", "base64urlnopad").verify(ctx.context.secret, JSON.stringify({ - ...parsed.session, - expiresAt: parsed.expiresAt - }), parsed.signature)) sessionDataPayload = parsed; - else { - expireCookie(ctx, ctx.context.authCookies.sessionData); - return ctx.json(null); - } - } - } - const dontRememberMe = await ctx.getSignedCookie(ctx.context.authCookies.dontRememberToken.name, ctx.context.secret); - if (sessionDataPayload?.session && ctx.context.options.session?.cookieCache?.enabled && !ctx.query?.disableCookieCache) { - const session$1 = sessionDataPayload.session; - const versionConfig = ctx.context.options.session?.cookieCache?.version; - let expectedVersion = "1"; - if (versionConfig) { - if (typeof versionConfig === "string") expectedVersion = versionConfig; - else if (typeof versionConfig === "function") { - const result = versionConfig(session$1.session, session$1.user); - expectedVersion = result instanceof Promise ? await result : result; - } - } - if ((session$1.version || "1") !== expectedVersion) expireCookie(ctx, ctx.context.authCookies.sessionData); - else { - const cachedSessionExpiresAt = new Date(session$1.session.expiresAt); - if (sessionDataPayload.expiresAt < Date.now() || cachedSessionExpiresAt < /* @__PURE__ */ new Date()) expireCookie(ctx, ctx.context.authCookies.sessionData); - else { - const cookieRefreshCache = ctx.context.sessionConfig.cookieRefreshCache; - if (cookieRefreshCache === false) { - ctx.context.session = session$1; - const parsedSession$2 = parseSessionOutput(ctx.context.options, { - ...session$1.session, - expiresAt: new Date(session$1.session.expiresAt), - createdAt: new Date(session$1.session.createdAt), - updatedAt: new Date(session$1.session.updatedAt) - }); - const parsedUser$2 = parseUserOutput(ctx.context.options, { - ...session$1.user, - createdAt: new Date(session$1.user.createdAt), - updatedAt: new Date(session$1.user.updatedAt) - }); - return ctx.json({ - session: parsedSession$2, - user: parsedUser$2 - }); - } - if (sessionDataPayload.expiresAt - Date.now() < cookieRefreshCache.updateAge * 1e3) { - const newExpiresAt = getDate(ctx.context.options.session?.cookieCache?.maxAge || 300, "sec"); - const refreshedSession = { - session: { - ...session$1.session, - expiresAt: newExpiresAt - }, - user: session$1.user, - updatedAt: Date.now() - }; - await setCookieCache(ctx, refreshedSession, false); - const parsedRefreshedSession = parseSessionOutput(ctx.context.options, { - ...refreshedSession.session, - expiresAt: new Date(refreshedSession.session.expiresAt), - createdAt: new Date(refreshedSession.session.createdAt), - updatedAt: new Date(refreshedSession.session.updatedAt) - }); - const parsedRefreshedUser = parseUserOutput(ctx.context.options, { - ...refreshedSession.user, - createdAt: new Date(refreshedSession.user.createdAt), - updatedAt: new Date(refreshedSession.user.updatedAt) - }); - ctx.context.session = { - session: parsedRefreshedSession, - user: parsedRefreshedUser - }; - return ctx.json({ - session: parsedRefreshedSession, - user: parsedRefreshedUser - }); - } - const parsedSession$1 = parseSessionOutput(ctx.context.options, { - ...session$1.session, - expiresAt: new Date(session$1.session.expiresAt), - createdAt: new Date(session$1.session.createdAt), - updatedAt: new Date(session$1.session.updatedAt) - }); - const parsedUser$1 = parseUserOutput(ctx.context.options, { - ...session$1.user, - createdAt: new Date(session$1.user.createdAt), - updatedAt: new Date(session$1.user.updatedAt) - }); - ctx.context.session = { - session: parsedSession$1, - user: parsedUser$1 - }; - return ctx.json({ - session: parsedSession$1, - user: parsedUser$1 - }); - } - } - } - const session = await ctx.context.internalAdapter.findSession(sessionCookieToken); - ctx.context.session = session; - if (!session || session.session.expiresAt < /* @__PURE__ */ new Date()) { - deleteSessionCookie(ctx); - if (session) - await ctx.context.internalAdapter.deleteSession(session.session.token); - return ctx.json(null); - } - if (dontRememberMe || ctx.query?.disableRefresh) { - const parsedSession$1 = parseSessionOutput(ctx.context.options, session.session); - const parsedUser$1 = parseUserOutput(ctx.context.options, session.user); - return ctx.json({ - session: parsedSession$1, - user: parsedUser$1 - }); - } - const expiresIn = ctx.context.sessionConfig.expiresIn; - const updateAge = ctx.context.sessionConfig.updateAge; - if (session.session.expiresAt.valueOf() - expiresIn * 1e3 + updateAge * 1e3 <= Date.now() && (!ctx.query?.disableRefresh || !ctx.context.options.session?.disableSessionRefresh)) { - const updatedSession = await ctx.context.internalAdapter.updateSession(session.session.token, { - expiresAt: getDate(ctx.context.sessionConfig.expiresIn, "sec"), - updatedAt: /* @__PURE__ */ new Date() - }); - if (!updatedSession) { - deleteSessionCookie(ctx); - return ctx.json(null, { status: 401 }); - } - const maxAge = (updatedSession.expiresAt.valueOf() - Date.now()) / 1e3; - await setSessionCookie(ctx, { - session: updatedSession, - user: session.user - }, false, { maxAge }); - const parsedUpdatedSession = parseSessionOutput(ctx.context.options, updatedSession); - const parsedUser$1 = parseUserOutput(ctx.context.options, session.user); - return ctx.json({ - session: parsedUpdatedSession, - user: parsedUser$1 - }); - } - await setCookieCache(ctx, session, !!dontRememberMe); - const parsedSession = parseSessionOutput(ctx.context.options, session.session); - const parsedUser = parseUserOutput(ctx.context.options, session.user); - return ctx.json({ - session: parsedSession, - user: parsedUser - }); - } catch (error2) { - ctx.context.logger.error("INTERNAL_SERVER_ERROR", error2); - throw new APIError("INTERNAL_SERVER_ERROR", { message: BASE_ERROR_CODES.FAILED_TO_GET_SESSION }); - } -}); -const getSessionFromCtx = async (ctx, config2) => { - if (ctx.context.session) return ctx.context.session; - const session = await getSession()({ - ...ctx, - asResponse: false, - headers: ctx.headers, - returnHeaders: false, - returnStatus: false, - query: { - ...config2, - ...ctx.query - } - }).catch((e) => { - return null; - }); - ctx.context.session = session; - return session; -}; -const sessionMiddleware = createAuthMiddleware(async (ctx) => { - const session = await getSessionFromCtx(ctx); - if (!session?.session) throw new APIError("UNAUTHORIZED"); - return { session }; -}); -const sensitiveSessionMiddleware = createAuthMiddleware(async (ctx) => { - const session = await getSessionFromCtx(ctx, { disableCookieCache: true }); - if (!session?.session) throw new APIError("UNAUTHORIZED"); - return { session }; -}); -createAuthMiddleware(async (ctx) => { - const session = await getSessionFromCtx(ctx); - if (!session?.session && (ctx.request || ctx.headers)) throw new APIError("UNAUTHORIZED"); - return { session }; -}); -const freshSessionMiddleware = createAuthMiddleware(async (ctx) => { - const session = await getSessionFromCtx(ctx); - if (!session?.session) throw new APIError("UNAUTHORIZED"); - if (ctx.context.sessionConfig.freshAge === 0) return { session }; - const freshAge = ctx.context.sessionConfig.freshAge; - const lastUpdated = new Date(session.session.updatedAt || session.session.createdAt).getTime(); - if (!(Date.now() - lastUpdated < freshAge * 1e3)) throw new APIError("FORBIDDEN", { message: "Session is not fresh" }); - return { session }; -}); -const listSessions = () => createAuthEndpoint("/list-sessions", { - method: "GET", - operationId: "listUserSessions", - use: [sessionMiddleware], - requireHeaders: true, - metadata: { openapi: { - operationId: "listUserSessions", - description: "List all active sessions for the user", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "array", - items: { $ref: "#/components/schemas/Session" } - } } } - } } - } } -}, async (ctx) => { - try { - const activeSessions = (await ctx.context.internalAdapter.listSessions(ctx.context.session.user.id)).filter((session) => { - return session.expiresAt > /* @__PURE__ */ new Date(); - }); - return ctx.json(activeSessions.map((session) => parseSessionOutput(ctx.context.options, session))); - } catch (e) { - ctx.context.logger.error(e); - throw ctx.error("INTERNAL_SERVER_ERROR"); - } -}); -const revokeSession = createAuthEndpoint("/revoke-session", { - method: "POST", - body: z.object({ token: z.string().meta({ description: "The token to revoke" }) }), - use: [sensitiveSessionMiddleware], - requireHeaders: true, - metadata: { openapi: { - description: "Revoke a single session", - requestBody: { content: { "application/json": { schema: { - type: "object", - properties: { token: { - type: "string", - description: "The token to revoke" - } }, - required: ["token"] - } } } }, - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { status: { - type: "boolean", - description: "Indicates if the session was revoked successfully" - } }, - required: ["status"] - } } } - } } - } } -}, async (ctx) => { - const token = ctx.body.token; - if ((await ctx.context.internalAdapter.findSession(token))?.session.userId === ctx.context.session.user.id) try { - await ctx.context.internalAdapter.deleteSession(token); - } catch (error2) { - ctx.context.logger.error(error2 && typeof error2 === "object" && "name" in error2 ? error2.name : "", error2); - throw new APIError("INTERNAL_SERVER_ERROR"); - } - return ctx.json({ status: true }); -}); -const revokeSessions = createAuthEndpoint("/revoke-sessions", { - method: "POST", - use: [sensitiveSessionMiddleware], - requireHeaders: true, - metadata: { openapi: { - description: "Revoke all sessions for the user", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { status: { - type: "boolean", - description: "Indicates if all sessions were revoked successfully" - } }, - required: ["status"] - } } } - } } - } } -}, async (ctx) => { - try { - await ctx.context.internalAdapter.deleteSessions(ctx.context.session.user.id); - } catch (error2) { - ctx.context.logger.error(error2 && typeof error2 === "object" && "name" in error2 ? error2.name : "", error2); - throw new APIError("INTERNAL_SERVER_ERROR"); - } - return ctx.json({ status: true }); -}); -const revokeOtherSessions = createAuthEndpoint("/revoke-other-sessions", { - method: "POST", - requireHeaders: true, - use: [sensitiveSessionMiddleware], - metadata: { openapi: { - description: "Revoke all other sessions for the user except the current one", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { status: { - type: "boolean", - description: "Indicates if all other sessions were revoked successfully" - } }, - required: ["status"] - } } } - } } - } } -}, async (ctx) => { - const session = ctx.context.session; - if (!session.user) throw new APIError("UNAUTHORIZED"); - const otherSessions = (await ctx.context.internalAdapter.listSessions(session.user.id)).filter((session$1) => { - return session$1.expiresAt > /* @__PURE__ */ new Date(); - }).filter((session$1) => session$1.token !== ctx.context.session.session.token); - await Promise.all(otherSessions.map((session$1) => ctx.context.internalAdapter.deleteSession(session$1.token))); - return ctx.json({ status: true }); -}); -const stateDataSchema = z.looseObject({ - callbackURL: z.string(), - codeVerifier: z.string(), - errorURL: z.string().optional(), - newUserURL: z.string().optional(), - expiresAt: z.number(), - link: z.object({ - email: z.string(), - userId: z.coerce.string() - }).optional(), - requestSignUp: z.boolean().optional() -}); -var StateError = class extends BetterAuthError { - code; - details; - constructor(message, options) { - super(message, options); - this.code = options.code; - this.details = options.details; - } -}; -async function generateGenericState(c, stateData, settings) { - const state = generateRandomString(32); - if (c.context.oauthConfig.storeStateStrategy === "cookie") { - const encryptedData = await symmetricEncrypt({ - key: c.context.secret, - data: JSON.stringify(stateData) - }); - const stateCookie$1 = c.context.createAuthCookie("oauth_state", { maxAge: 600 }); - c.setCookie(stateCookie$1.name, encryptedData, stateCookie$1.attributes); - return { - state, - codeVerifier: stateData.codeVerifier - }; - } - const stateCookie = c.context.createAuthCookie("state", { maxAge: 300 }); - await c.setSignedCookie(stateCookie.name, state, c.context.secret, stateCookie.attributes); - const expiresAt = /* @__PURE__ */ new Date(); - expiresAt.setMinutes(expiresAt.getMinutes() + 10); - const verification = await c.context.internalAdapter.createVerificationValue({ - value: JSON.stringify(stateData), - identifier: state, - expiresAt - }); - if (!verification) throw new StateError("Unable to create verification. Make sure the database adapter is properly working and there is a verification table in the database", { code: "state_generation_error" }); - return { - state: verification.identifier, - codeVerifier: stateData.codeVerifier - }; -} -async function parseGenericState(c, state, settings) { - const storeStateStrategy = c.context.oauthConfig.storeStateStrategy; - let parsedData; - if (storeStateStrategy === "cookie") { - const stateCookie = c.context.createAuthCookie("oauth_state"); - const encryptedData = c.getCookie(stateCookie.name); - if (!encryptedData) throw new StateError("State mismatch: auth state cookie not found", { - code: "state_mismatch", - details: { state } - }); - try { - const decryptedData = await symmetricDecrypt({ - key: c.context.secret, - data: encryptedData - }); - parsedData = stateDataSchema.parse(JSON.parse(decryptedData)); - } catch (error2) { - throw new StateError("State invalid: Failed to decrypt or parse auth state", { - code: "state_invalid", - details: { state }, - cause: error2 - }); - } - expireCookie(c, stateCookie); - } else { - const data = await c.context.internalAdapter.findVerificationValue(state); - if (!data) throw new StateError("State mismatch: verification not found", { - code: "state_mismatch", - details: { state } - }); - parsedData = stateDataSchema.parse(JSON.parse(data.value)); - const stateCookie = c.context.createAuthCookie("state"); - const stateCookieValue = await c.getSignedCookie(stateCookie.name, c.context.secret); - if (!c.context.oauthConfig.skipStateCookieCheck && (!stateCookieValue || stateCookieValue !== state)) throw new StateError("State mismatch: State not persisted correctly", { - code: "state_security_mismatch", - details: { state } - }); - expireCookie(c, stateCookie); - await c.context.internalAdapter.deleteVerificationValue(data.id); - } - if (parsedData.expiresAt < Date.now()) throw new StateError("Invalid state: request expired", { - code: "state_mismatch", - details: { expiresAt: parsedData.expiresAt } - }); - return parsedData; -} -async function generateState(c, link, additionalData) { - const callbackURL = c.body?.callbackURL || c.context.options.baseURL; - if (!callbackURL) throw new APIError("BAD_REQUEST", { message: "callbackURL is required" }); - const codeVerifier = generateRandomString(128); - const stateData = { - ...additionalData ? additionalData : {}, - callbackURL, - codeVerifier, - errorURL: c.body?.errorCallbackURL, - newUserURL: c.body?.newUserCallbackURL, - link, - expiresAt: Date.now() + 600 * 1e3, - requestSignUp: c.body?.requestSignUp - }; - await setOAuthState(stateData); - try { - return generateGenericState(c, stateData); - } catch (error2) { - c.context.logger.error("Failed to create verification", error2); - throw new APIError("INTERNAL_SERVER_ERROR", { - message: "Unable to create verification", - cause: error2 - }); - } -} -async function parseState(c) { - const state = c.query.state || c.body.state; - const errorURL = c.context.options.onAPIError?.errorURL || `${c.context.baseURL}/error`; - let parsedData; - try { - parsedData = await parseGenericState(c, state); - } catch (error2) { - c.context.logger.error("Failed to parse state", error2); - if (error2 instanceof StateError && error2.code === "state_security_mismatch") throw c.redirect(`${errorURL}?error=state_mismatch`); - throw c.redirect(`${errorURL}?error=please_restart_the_process`); - } - if (!parsedData.errorURL) parsedData.errorURL = errorURL; - if (parsedData) await setOAuthState(parsedData); - return parsedData; -} -function decryptOAuthToken(token, ctx) { - if (!token) return token; - if (ctx.options.account?.encryptOAuthTokens) return symmetricDecrypt({ - key: ctx.secret, - data: token - }); - return token; -} -function setTokenUtil(token, ctx) { - if (ctx.options.account?.encryptOAuthTokens && token) return symmetricEncrypt({ - key: ctx.secret, - data: token - }); - return token; -} -const listUserAccounts = createAuthEndpoint("/list-accounts", { - method: "GET", - use: [sessionMiddleware], - metadata: { openapi: { - operationId: "listUserAccounts", - description: "List all accounts linked to the user", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "array", - items: { - type: "object", - properties: { - id: { type: "string" }, - providerId: { type: "string" }, - createdAt: { - type: "string", - format: "date-time" - }, - updatedAt: { - type: "string", - format: "date-time" - }, - accountId: { type: "string" }, - userId: { type: "string" }, - scopes: { - type: "array", - items: { type: "string" } - } - }, - required: [ - "id", - "providerId", - "createdAt", - "updatedAt", - "accountId", - "userId", - "scopes" - ] - } - } } } - } } - } } -}, async (c) => { - const session = c.context.session; - const accounts = await c.context.internalAdapter.findAccounts(session.user.id); - return c.json(accounts.map((a) => { - const { scope, ...parsed } = parseAccountOutput(c.context.options, a); - return { - ...parsed, - scopes: scope?.split(",") || [] - }; - })); -}); -const linkSocialAccount = createAuthEndpoint("/link-social", { - method: "POST", - requireHeaders: true, - body: z.object({ - callbackURL: z.string().meta({ description: "The URL to redirect to after the user has signed in" }).optional(), - provider: SocialProviderListEnum, - idToken: z.object({ - token: z.string(), - nonce: z.string().optional(), - accessToken: z.string().optional(), - refreshToken: z.string().optional(), - scopes: z.array(z.string()).optional() - }).optional(), - requestSignUp: z.boolean().optional(), - scopes: z.array(z.string()).meta({ description: "Additional scopes to request from the provider" }).optional(), - errorCallbackURL: z.string().meta({ description: "The URL to redirect to if there is an error during the link process" }).optional(), - disableRedirect: z.boolean().meta({ description: "Disable automatic redirection to the provider. Useful for handling the redirection yourself" }).optional(), - additionalData: z.record(z.string(), z.any()).optional() - }), - use: [sessionMiddleware], - metadata: { openapi: { - description: "Link a social account to the user", - operationId: "linkSocialAccount", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { - url: { - type: "string", - description: "The authorization URL to redirect the user to" - }, - redirect: { - type: "boolean", - description: "Indicates if the user should be redirected to the authorization URL" - }, - status: { type: "boolean" } - }, - required: ["redirect"] - } } } - } } - } } -}, async (c) => { - const session = c.context.session; - const provider = c.context.socialProviders.find((p) => p.id === c.body.provider); - if (!provider) { - c.context.logger.error("Provider not found. Make sure to add the provider in your auth config", { provider: c.body.provider }); - throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.PROVIDER_NOT_FOUND }); - } - if (c.body.idToken) { - if (!provider.verifyIdToken) { - c.context.logger.error("Provider does not support id token verification", { provider: c.body.provider }); - throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.ID_TOKEN_NOT_SUPPORTED }); - } - const { token, nonce } = c.body.idToken; - if (!await provider.verifyIdToken(token, nonce)) { - c.context.logger.error("Invalid id token", { provider: c.body.provider }); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.INVALID_TOKEN }); - } - const linkingUserInfo = await provider.getUserInfo({ - idToken: token, - accessToken: c.body.idToken.accessToken, - refreshToken: c.body.idToken.refreshToken - }); - if (!linkingUserInfo || !linkingUserInfo?.user) { - c.context.logger.error("Failed to get user info", { provider: c.body.provider }); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.FAILED_TO_GET_USER_INFO }); - } - const linkingUserId = String(linkingUserInfo.user.id); - if (!linkingUserInfo.user.email) { - c.context.logger.error("User email not found", { provider: c.body.provider }); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.USER_EMAIL_NOT_FOUND }); - } - if ((await c.context.internalAdapter.findAccounts(session.user.id)).find((a) => a.providerId === provider.id && a.accountId === linkingUserId)) return c.json({ - url: "", - status: true, - redirect: false - }); - if (!c.context.options.account?.accountLinking?.trustedProviders?.includes(provider.id) && !linkingUserInfo.user.emailVerified || c.context.options.account?.accountLinking?.enabled === false) throw new APIError("UNAUTHORIZED", { message: "Account not linked - linking not allowed" }); - if (linkingUserInfo.user.email?.toLowerCase() !== session.user.email.toLowerCase() && c.context.options.account?.accountLinking?.allowDifferentEmails !== true) throw new APIError("UNAUTHORIZED", { message: "Account not linked - different emails not allowed" }); - try { - await c.context.internalAdapter.createAccount({ - userId: session.user.id, - providerId: provider.id, - accountId: linkingUserId, - accessToken: c.body.idToken.accessToken, - idToken: token, - refreshToken: c.body.idToken.refreshToken, - scope: c.body.idToken.scopes?.join(",") - }); - } catch { - throw new APIError("EXPECTATION_FAILED", { message: "Account not linked - unable to create account" }); - } - if (c.context.options.account?.accountLinking?.updateUserInfoOnLink === true) try { - await c.context.internalAdapter.updateUser(session.user.id, { - name: linkingUserInfo.user?.name, - image: linkingUserInfo.user?.image - }); - } catch (e) { - console.warn("Could not update user - " + e.toString()); - } - return c.json({ - url: "", - status: true, - redirect: false - }); - } - const state = await generateState(c, { - userId: session.user.id, - email: session.user.email - }, c.body.additionalData); - const url = await provider.createAuthorizationURL({ - state: state.state, - codeVerifier: state.codeVerifier, - redirectURI: `${c.context.baseURL}/callback/${provider.id}`, - scopes: c.body.scopes - }); - if (!c.body.disableRedirect) c.setHeader("Location", url.toString()); - return c.json({ - url: url.toString(), - redirect: !c.body.disableRedirect - }); -}); -const unlinkAccount = createAuthEndpoint("/unlink-account", { - method: "POST", - body: z.object({ - providerId: z.string(), - accountId: z.string().optional() - }), - use: [freshSessionMiddleware], - metadata: { openapi: { - description: "Unlink an account", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { status: { type: "boolean" } } - } } } - } } - } } -}, async (ctx) => { - const { providerId, accountId } = ctx.body; - const accounts = await ctx.context.internalAdapter.findAccounts(ctx.context.session.user.id); - if (accounts.length === 1 && !ctx.context.options.account?.accountLinking?.allowUnlinkingAll) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.FAILED_TO_UNLINK_LAST_ACCOUNT }); - const accountExist = accounts.find((account) => accountId ? account.accountId === accountId && account.providerId === providerId : account.providerId === providerId); - if (!accountExist) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.ACCOUNT_NOT_FOUND }); - await ctx.context.internalAdapter.deleteAccount(accountExist.id); - return ctx.json({ status: true }); -}); -const getAccessToken = createAuthEndpoint("/get-access-token", { - method: "POST", - body: z.object({ - providerId: z.string().meta({ description: "The provider ID for the OAuth provider" }), - accountId: z.string().meta({ description: "The account ID associated with the refresh token" }).optional(), - userId: z.string().meta({ description: "The user ID associated with the account" }).optional() - }), - metadata: { openapi: { - description: "Get a valid access token, doing a refresh if needed", - responses: { - 200: { - description: "A Valid access token", - content: { "application/json": { schema: { - type: "object", - properties: { - tokenType: { type: "string" }, - idToken: { type: "string" }, - accessToken: { type: "string" }, - accessTokenExpiresAt: { - type: "string", - format: "date-time" - } - } - } } } - }, - 400: { description: "Invalid refresh token or provider configuration" } - } - } } -}, async (ctx) => { - const { providerId, accountId, userId } = ctx.body || {}; - const req = ctx.request; - const session = await getSessionFromCtx(ctx); - if (req && !session) throw ctx.error("UNAUTHORIZED"); - const resolvedUserId = session?.user?.id || userId; - if (!resolvedUserId) throw ctx.error("UNAUTHORIZED"); - if (!ctx.context.socialProviders.find((p) => p.id === providerId)) throw new APIError("BAD_REQUEST", { message: `Provider ${providerId} is not supported.` }); - const accountData = await getAccountCookie(ctx); - let account = void 0; - if (accountData && providerId === accountData.providerId && (!accountId || accountData.id === accountId)) account = accountData; - else account = (await ctx.context.internalAdapter.findAccounts(resolvedUserId)).find((acc) => accountId ? acc.id === accountId && acc.providerId === providerId : acc.providerId === providerId); - if (!account) throw new APIError("BAD_REQUEST", { message: "Account not found" }); - const provider = ctx.context.socialProviders.find((p) => p.id === providerId); - if (!provider) throw new APIError("BAD_REQUEST", { message: `Provider ${providerId} not found.` }); - try { - let newTokens = null; - const accessTokenExpired = account.accessTokenExpiresAt && new Date(account.accessTokenExpiresAt).getTime() - Date.now() < 5e3; - if (account.refreshToken && accessTokenExpired && provider.refreshAccessToken) { - const refreshToken$1 = await decryptOAuthToken(account.refreshToken, ctx.context); - newTokens = await provider.refreshAccessToken(refreshToken$1); - const updatedData = { - accessToken: await setTokenUtil(newTokens.accessToken, ctx.context), - accessTokenExpiresAt: newTokens.accessTokenExpiresAt, - refreshToken: await setTokenUtil(newTokens.refreshToken, ctx.context), - refreshTokenExpiresAt: newTokens.refreshTokenExpiresAt - }; - let updatedAccount = null; - if (account.id) updatedAccount = await ctx.context.internalAdapter.updateAccount(account.id, updatedData); - if (ctx.context.options.account?.storeAccountCookie) await setAccountCookie(ctx, { - ...account, - ...updatedAccount ?? updatedData - }); - } - const accessTokenExpiresAt = (() => { - if (newTokens?.accessTokenExpiresAt) { - if (typeof newTokens.accessTokenExpiresAt === "string") return new Date(newTokens.accessTokenExpiresAt); - return newTokens.accessTokenExpiresAt; - } - if (account.accessTokenExpiresAt) { - if (typeof account.accessTokenExpiresAt === "string") return new Date(account.accessTokenExpiresAt); - return account.accessTokenExpiresAt; - } - })(); - const tokens = { - accessToken: newTokens?.accessToken ?? await decryptOAuthToken(account.accessToken ?? "", ctx.context), - accessTokenExpiresAt, - scopes: account.scope?.split(",") ?? [], - idToken: newTokens?.idToken ?? account.idToken ?? void 0 - }; - return ctx.json(tokens); - } catch (error2) { - throw new APIError("BAD_REQUEST", { - message: "Failed to get a valid access token", - cause: error2 - }); - } -}); -const refreshToken = createAuthEndpoint("/refresh-token", { - method: "POST", - body: z.object({ - providerId: z.string().meta({ description: "The provider ID for the OAuth provider" }), - accountId: z.string().meta({ description: "The account ID associated with the refresh token" }).optional(), - userId: z.string().meta({ description: "The user ID associated with the account" }).optional() - }), - metadata: { openapi: { - description: "Refresh the access token using a refresh token", - responses: { - 200: { - description: "Access token refreshed successfully", - content: { "application/json": { schema: { - type: "object", - properties: { - tokenType: { type: "string" }, - idToken: { type: "string" }, - accessToken: { type: "string" }, - refreshToken: { type: "string" }, - accessTokenExpiresAt: { - type: "string", - format: "date-time" - }, - refreshTokenExpiresAt: { - type: "string", - format: "date-time" - } - } - } } } - }, - 400: { description: "Invalid refresh token or provider configuration" } - } - } } -}, async (ctx) => { - const { providerId, accountId, userId } = ctx.body; - const req = ctx.request; - const session = await getSessionFromCtx(ctx); - if (req && !session) throw ctx.error("UNAUTHORIZED"); - const resolvedUserId = session?.user?.id || userId; - if (!resolvedUserId) throw new APIError("BAD_REQUEST", { message: `Either userId or session is required` }); - const provider = ctx.context.socialProviders.find((p) => p.id === providerId); - if (!provider) throw new APIError("BAD_REQUEST", { message: `Provider ${providerId} not found.` }); - if (!provider.refreshAccessToken) throw new APIError("BAD_REQUEST", { message: `Provider ${providerId} does not support token refreshing.` }); - let account = void 0; - const accountData = await getAccountCookie(ctx); - if (accountData && (!providerId || providerId === accountData?.providerId)) account = accountData; - else account = (await ctx.context.internalAdapter.findAccounts(resolvedUserId)).find((acc) => accountId ? acc.id === accountId && acc.providerId === providerId : acc.providerId === providerId); - if (!account) throw new APIError("BAD_REQUEST", { message: "Account not found" }); - let refreshToken$1 = void 0; - if (accountData && providerId === accountData.providerId) refreshToken$1 = accountData.refreshToken ?? void 0; - else refreshToken$1 = account.refreshToken ?? void 0; - if (!refreshToken$1) throw new APIError("BAD_REQUEST", { message: "Refresh token not found" }); - try { - const decryptedRefreshToken = await decryptOAuthToken(refreshToken$1, ctx.context); - const tokens = await provider.refreshAccessToken(decryptedRefreshToken); - if (account.id) { - const updateData = { - ...account || {}, - accessToken: await setTokenUtil(tokens.accessToken, ctx.context), - refreshToken: await setTokenUtil(tokens.refreshToken, ctx.context), - accessTokenExpiresAt: tokens.accessTokenExpiresAt, - refreshTokenExpiresAt: tokens.refreshTokenExpiresAt, - scope: tokens.scopes?.join(",") || account.scope, - idToken: tokens.idToken || account.idToken - }; - await ctx.context.internalAdapter.updateAccount(account.id, updateData); - } - if (accountData && providerId === accountData.providerId && ctx.context.options.account?.storeAccountCookie) await setAccountCookie(ctx, { - ...accountData, - accessToken: await setTokenUtil(tokens.accessToken, ctx.context), - refreshToken: await setTokenUtil(tokens.refreshToken, ctx.context), - accessTokenExpiresAt: tokens.accessTokenExpiresAt, - refreshTokenExpiresAt: tokens.refreshTokenExpiresAt, - scope: tokens.scopes?.join(",") || accountData.scope, - idToken: tokens.idToken || accountData.idToken - }); - return ctx.json({ - accessToken: tokens.accessToken, - refreshToken: tokens.refreshToken, - accessTokenExpiresAt: tokens.accessTokenExpiresAt, - refreshTokenExpiresAt: tokens.refreshTokenExpiresAt, - scope: tokens.scopes?.join(",") || account.scope, - idToken: tokens.idToken || account.idToken, - providerId: account.providerId, - accountId: account.accountId - }); - } catch (error2) { - throw new APIError("BAD_REQUEST", { - message: "Failed to refresh access token", - cause: error2 - }); - } -}); -const accountInfoQuerySchema = z.optional(z.object({ accountId: z.string().meta({ description: "The provider given account id for which to get the account info" }).optional() })); -const accountInfo = createAuthEndpoint("/account-info", { - method: "GET", - use: [sessionMiddleware], - metadata: { openapi: { - description: "Get the account info provided by the provider", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { - user: { - type: "object", - properties: { - id: { type: "string" }, - name: { type: "string" }, - email: { type: "string" }, - image: { type: "string" }, - emailVerified: { type: "boolean" } - }, - required: ["id", "emailVerified"] - }, - data: { - type: "object", - properties: {}, - additionalProperties: true - } - }, - required: ["user", "data"], - additionalProperties: false - } } } - } } - } }, - query: accountInfoQuerySchema -}, async (ctx) => { - const providedAccountId = ctx.query?.accountId; - let account = void 0; - if (!providedAccountId) { - if (ctx.context.options.account?.storeAccountCookie) { - const accountData = await getAccountCookie(ctx); - if (accountData) account = accountData; - } - } else { - const accountData = await ctx.context.internalAdapter.findAccount(providedAccountId); - if (accountData) account = accountData; - } - if (!account || account.userId !== ctx.context.session.user.id) throw new APIError("BAD_REQUEST", { message: "Account not found" }); - const provider = ctx.context.socialProviders.find((p) => p.id === account.providerId); - if (!provider) throw new APIError("INTERNAL_SERVER_ERROR", { message: `Provider account provider is ${account.providerId} but it is not configured` }); - const tokens = await getAccessToken({ - ...ctx, - method: "POST", - body: { - accountId: account.id, - providerId: account.providerId - }, - returnHeaders: false, - returnStatus: false - }); - if (!tokens.accessToken) throw new APIError("BAD_REQUEST", { message: "Access token not found" }); - const info2 = await provider.getUserInfo({ - ...tokens, - accessToken: tokens.accessToken - }); - return ctx.json(info2); -}); -async function createEmailVerificationToken(secret, email, updateTo, expiresIn = 3600, extraPayload) { - return await signJWT({ - email: email.toLowerCase(), - updateTo, - ...extraPayload - }, secret, expiresIn); -} -async function sendVerificationEmailFn(ctx, user) { - if (!ctx.context.options.emailVerification?.sendVerificationEmail) { - ctx.context.logger.error("Verification email isn't enabled."); - throw new APIError("BAD_REQUEST", { message: "Verification email isn't enabled" }); - } - const token = await createEmailVerificationToken(ctx.context.secret, user.email, void 0, ctx.context.options.emailVerification?.expiresIn); - const callbackURL = ctx.body.callbackURL ? encodeURIComponent(ctx.body.callbackURL) : encodeURIComponent("/"); - const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${callbackURL}`; - await ctx.context.runInBackgroundOrAwait(ctx.context.options.emailVerification.sendVerificationEmail({ - user, - url, - token - }, ctx.request)); -} -const sendVerificationEmail = createAuthEndpoint("/send-verification-email", { - method: "POST", - operationId: "sendVerificationEmail", - body: z.object({ - email: z.email().meta({ description: "The email to send the verification email to" }), - callbackURL: z.string().meta({ description: "The URL to use for email verification callback" }).optional() - }), - metadata: { openapi: { - operationId: "sendVerificationEmail", - description: "Send a verification email to the user", - requestBody: { content: { "application/json": { schema: { - type: "object", - properties: { - email: { - type: "string", - description: "The email to send the verification email to", - example: "user@example.com" - }, - callbackURL: { - type: "string", - description: "The URL to use for email verification callback", - example: "https://example.com/callback", - nullable: true - } - }, - required: ["email"] - } } } }, - responses: { - "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { status: { - type: "boolean", - description: "Indicates if the email was sent successfully", - example: true - } } - } } } - }, - "400": { - description: "Bad Request", - content: { "application/json": { schema: { - type: "object", - properties: { message: { - type: "string", - description: "Error message", - example: "Verification email isn't enabled" - } } - } } } - } - } - } } -}, async (ctx) => { - if (!ctx.context.options.emailVerification?.sendVerificationEmail) { - ctx.context.logger.error("Verification email isn't enabled."); - throw new APIError("BAD_REQUEST", { message: "Verification email isn't enabled" }); - } - const { email } = ctx.body; - const session = await getSessionFromCtx(ctx); - if (!session) { - const user = await ctx.context.internalAdapter.findUserByEmail(email); - if (!user || user.user.emailVerified) { - await createEmailVerificationToken(ctx.context.secret, email, void 0, ctx.context.options.emailVerification?.expiresIn); - return ctx.json({ status: true }); - } - await sendVerificationEmailFn(ctx, user.user); - return ctx.json({ status: true }); - } - if (session?.user.email !== email) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.EMAIL_MISMATCH }); - if (session?.user.emailVerified) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.EMAIL_ALREADY_VERIFIED }); - await sendVerificationEmailFn(ctx, session.user); - return ctx.json({ status: true }); -}); -const verifyEmail = createAuthEndpoint("/verify-email", { - method: "GET", - operationId: "verifyEmail", - query: z.object({ - token: z.string().meta({ description: "The token to verify the email" }), - callbackURL: z.string().meta({ description: "The URL to redirect to after email verification" }).optional() - }), - use: [originCheck((ctx) => ctx.query.callbackURL)], - metadata: { openapi: { - description: "Verify the email of the user", - parameters: [{ - name: "token", - in: "query", - description: "The token to verify the email", - required: true, - schema: { type: "string" } - }, { - name: "callbackURL", - in: "query", - description: "The URL to redirect to after email verification", - required: false, - schema: { type: "string" } - }], - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { - user: { - type: "object", - $ref: "#/components/schemas/User" - }, - status: { - type: "boolean", - description: "Indicates if the email was verified successfully" - } - }, - required: ["user", "status"] - } } } - } } - } } -}, async (ctx) => { - function redirectOnError(error2) { - if (ctx.query.callbackURL) { - if (ctx.query.callbackURL.includes("?")) throw ctx.redirect(`${ctx.query.callbackURL}&error=${error2}`); - throw ctx.redirect(`${ctx.query.callbackURL}?error=${error2}`); - } - throw new APIError("UNAUTHORIZED", { message: error2 }); - } - const { token } = ctx.query; - let jwt; - try { - jwt = await jwtVerify(token, new TextEncoder().encode(ctx.context.secret), { algorithms: ["HS256"] }); - } catch (e) { - if (e instanceof JWTExpired) return redirectOnError("token_expired"); - return redirectOnError("invalid_token"); - } - const parsed = z.object({ - email: z.email(), - updateTo: z.string().optional(), - requestType: z.string().optional() - }).parse(jwt.payload); - const user = await ctx.context.internalAdapter.findUserByEmail(parsed.email); - if (!user) return redirectOnError("user_not_found"); - if (parsed.updateTo) { - const session = await getSessionFromCtx(ctx); - if (session && session.user.email !== parsed.email) return redirectOnError("unauthorized"); - switch (parsed.requestType) { - case "change-email-confirmation": { - const newToken = await createEmailVerificationToken(ctx.context.secret, parsed.email, parsed.updateTo, ctx.context.options.emailVerification?.expiresIn, { requestType: "change-email-verification" }); - const updateCallbackURL = ctx.query.callbackURL ? encodeURIComponent(ctx.query.callbackURL) : encodeURIComponent("/"); - const url = `${ctx.context.baseURL}/verify-email?token=${newToken}&callbackURL=${updateCallbackURL}`; - if (ctx.context.options.emailVerification?.sendVerificationEmail) await ctx.context.runInBackgroundOrAwait(ctx.context.options.emailVerification.sendVerificationEmail({ - user: { - ...user.user, - email: parsed.updateTo - }, - url, - token: newToken - }, ctx.request)); - if (ctx.query.callbackURL) throw ctx.redirect(ctx.query.callbackURL); - return ctx.json({ status: true }); - } - case "change-email-verification": { - let activeSession = session; - if (!activeSession) { - const newSession = await ctx.context.internalAdapter.createSession(user.user.id); - if (!newSession) throw new APIError("INTERNAL_SERVER_ERROR", { message: BASE_ERROR_CODES.FAILED_TO_CREATE_SESSION }); - activeSession = { - session: newSession, - user: user.user - }; - } - if (ctx.context.options.emailVerification?.onEmailVerification) await ctx.context.options.emailVerification.onEmailVerification(user.user, ctx.request); - const updatedUser$1 = await ctx.context.internalAdapter.updateUserByEmail(parsed.email, { - email: parsed.updateTo, - emailVerified: true - }); - if (ctx.context.options.emailVerification?.afterEmailVerification) await ctx.context.options.emailVerification.afterEmailVerification(updatedUser$1, ctx.request); - await setSessionCookie(ctx, { - session: activeSession.session, - user: { - ...activeSession.user, - email: parsed.updateTo, - emailVerified: true - } - }); - if (ctx.query.callbackURL) throw ctx.redirect(ctx.query.callbackURL); - return ctx.json({ - status: true, - user: parseUserOutput(ctx.context.options, updatedUser$1) - }); - } - default: { - let activeSession = session; - if (!activeSession) { - const newSession = await ctx.context.internalAdapter.createSession(user.user.id); - if (!newSession) throw new APIError("INTERNAL_SERVER_ERROR", { message: BASE_ERROR_CODES.FAILED_TO_CREATE_SESSION }); - activeSession = { - session: newSession, - user: user.user - }; - } - const updatedUser$1 = await ctx.context.internalAdapter.updateUserByEmail(parsed.email, { - email: parsed.updateTo, - emailVerified: false - }); - const newToken = await createEmailVerificationToken(ctx.context.secret, parsed.updateTo); - const updateCallbackURL = ctx.query.callbackURL ? encodeURIComponent(ctx.query.callbackURL) : encodeURIComponent("/"); - if (ctx.context.options.emailVerification?.sendVerificationEmail) await ctx.context.runInBackgroundOrAwait(ctx.context.options.emailVerification.sendVerificationEmail({ - user: updatedUser$1, - url: `${ctx.context.baseURL}/verify-email?token=${newToken}&callbackURL=${updateCallbackURL}`, - token: newToken - }, ctx.request)); - await setSessionCookie(ctx, { - session: activeSession.session, - user: { - ...activeSession.user, - email: parsed.updateTo, - emailVerified: false - } - }); - if (ctx.query.callbackURL) throw ctx.redirect(ctx.query.callbackURL); - return ctx.json({ - status: true, - user: parseUserOutput(ctx.context.options, updatedUser$1) - }); - } - } - } - if (user.user.emailVerified) { - if (ctx.query.callbackURL) throw ctx.redirect(ctx.query.callbackURL); - return ctx.json({ - status: true, - user: null - }); - } - if (ctx.context.options.emailVerification?.beforeEmailVerification) await ctx.context.options.emailVerification.beforeEmailVerification(user.user, ctx.request); - if (ctx.context.options.emailVerification?.onEmailVerification) await ctx.context.options.emailVerification.onEmailVerification(user.user, ctx.request); - const updatedUser = await ctx.context.internalAdapter.updateUserByEmail(parsed.email, { emailVerified: true }); - if (ctx.context.options.emailVerification?.afterEmailVerification) await ctx.context.options.emailVerification.afterEmailVerification(updatedUser, ctx.request); - if (ctx.context.options.emailVerification?.autoSignInAfterVerification) { - const currentSession = await getSessionFromCtx(ctx); - if (!currentSession || currentSession.user.email !== parsed.email) { - const session = await ctx.context.internalAdapter.createSession(user.user.id); - if (!session) throw new APIError("INTERNAL_SERVER_ERROR", { message: "Failed to create session" }); - await setSessionCookie(ctx, { - session, - user: { - ...user.user, - emailVerified: true - } - }); - } else await setSessionCookie(ctx, { - session: currentSession.session, - user: { - ...currentSession.user, - emailVerified: true - } - }); - } - if (ctx.query.callbackURL) throw ctx.redirect(ctx.query.callbackURL); - return ctx.json({ - status: true, - user: null - }); -}); -async function handleOAuthUserInfo(c, opts) { - const { userInfo, account, callbackURL, disableSignUp, overrideUserInfo } = opts; - const dbUser = await c.context.internalAdapter.findOAuthUser(userInfo.email.toLowerCase(), account.accountId, account.providerId).catch((e) => { - logger.error("Better auth was unable to query your database.\nError: ", e); - const errorURL = c.context.options.onAPIError?.errorURL || `${c.context.baseURL}/error`; - throw c.redirect(`${errorURL}?error=internal_server_error`); - }); - let user = dbUser?.user; - const isRegister = !user; - if (dbUser) { - const linkedAccount = dbUser.linkedAccount ?? dbUser.accounts.find((acc) => acc.providerId === account.providerId && acc.accountId === account.accountId); - if (!linkedAccount) { - const accountLinking = c.context.options.account?.accountLinking; - const trustedProviders = c.context.options.account?.accountLinking?.trustedProviders; - if (!(opts.isTrustedProvider || trustedProviders?.includes(account.providerId)) && !userInfo.emailVerified || accountLinking?.enabled === false || accountLinking?.disableImplicitLinking === true) { - if (isDevelopment()) logger.warn(`User already exist but account isn't linked to ${account.providerId}. To read more about how account linking works in Better Auth see https://www.better-auth.com/docs/concepts/users-accounts#account-linking.`); - return { - error: "account not linked", - data: null - }; - } - try { - await c.context.internalAdapter.linkAccount({ - providerId: account.providerId, - accountId: userInfo.id.toString(), - userId: dbUser.user.id, - accessToken: await setTokenUtil(account.accessToken, c.context), - refreshToken: await setTokenUtil(account.refreshToken, c.context), - idToken: account.idToken, - accessTokenExpiresAt: account.accessTokenExpiresAt, - refreshTokenExpiresAt: account.refreshTokenExpiresAt, - scope: account.scope - }); - } catch (e) { - logger.error("Unable to link account", e); - return { - error: "unable to link account", - data: null - }; - } - if (userInfo.emailVerified && !dbUser.user.emailVerified && userInfo.email.toLowerCase() === dbUser.user.email) await c.context.internalAdapter.updateUser(dbUser.user.id, { emailVerified: true }); - } else { - const freshTokens = c.context.options.account?.updateAccountOnSignIn !== false ? Object.fromEntries(Object.entries({ - idToken: account.idToken, - accessToken: await setTokenUtil(account.accessToken, c.context), - refreshToken: await setTokenUtil(account.refreshToken, c.context), - accessTokenExpiresAt: account.accessTokenExpiresAt, - refreshTokenExpiresAt: account.refreshTokenExpiresAt, - scope: account.scope - }).filter(([_, value]) => value !== void 0)) : {}; - if (c.context.options.account?.storeAccountCookie) await setAccountCookie(c, { - ...linkedAccount, - ...freshTokens - }); - if (Object.keys(freshTokens).length > 0) await c.context.internalAdapter.updateAccount(linkedAccount.id, freshTokens); - if (userInfo.emailVerified && !dbUser.user.emailVerified && userInfo.email.toLowerCase() === dbUser.user.email) await c.context.internalAdapter.updateUser(dbUser.user.id, { emailVerified: true }); - } - if (overrideUserInfo) { - const { id: _, ...restUserInfo } = userInfo; - user = await c.context.internalAdapter.updateUser(dbUser.user.id, { - ...restUserInfo, - email: userInfo.email.toLowerCase(), - emailVerified: userInfo.email.toLowerCase() === dbUser.user.email ? dbUser.user.emailVerified || userInfo.emailVerified : userInfo.emailVerified - }); - } - } else { - if (disableSignUp) return { - error: "signup disabled", - data: null, - isRegister: false - }; - try { - const { id: _, ...restUserInfo } = userInfo; - const accountData = { - accessToken: await setTokenUtil(account.accessToken, c.context), - refreshToken: await setTokenUtil(account.refreshToken, c.context), - idToken: account.idToken, - accessTokenExpiresAt: account.accessTokenExpiresAt, - refreshTokenExpiresAt: account.refreshTokenExpiresAt, - scope: account.scope, - providerId: account.providerId, - accountId: userInfo.id.toString() - }; - const { user: createdUser, account: createdAccount } = await c.context.internalAdapter.createOAuthUser({ - ...restUserInfo, - email: userInfo.email.toLowerCase() - }, accountData); - user = createdUser; - if (c.context.options.account?.storeAccountCookie) await setAccountCookie(c, createdAccount); - if (!userInfo.emailVerified && user && c.context.options.emailVerification?.sendOnSignUp && c.context.options.emailVerification?.sendVerificationEmail) { - const token = await createEmailVerificationToken(c.context.secret, user.email, void 0, c.context.options.emailVerification?.expiresIn); - const url = `${c.context.baseURL}/verify-email?token=${token}&callbackURL=${callbackURL}`; - await c.context.runInBackgroundOrAwait(c.context.options.emailVerification.sendVerificationEmail({ - user, - url, - token - }, c.request)); - } - } catch (e) { - logger.error(e); - if (e instanceof APIError) return { - error: e.message, - data: null, - isRegister: false - }; - return { - error: "unable to create user", - data: null, - isRegister: false - }; - } - } - if (!user) return { - error: "unable to create user", - data: null, - isRegister: false - }; - const session = await c.context.internalAdapter.createSession(user.id); - if (!session) return { - error: "unable to create session", - data: null, - isRegister: false - }; - return { - data: { - session, - user - }, - error: null, - isRegister - }; -} -const HIDE_METADATA = { scope: "server" }; -const schema = z.object({ - code: z.string().optional(), - error: z.string().optional(), - device_id: z.string().optional(), - error_description: z.string().optional(), - state: z.string().optional(), - user: z.string().optional() -}); -const callbackOAuth = createAuthEndpoint("/callback/:id", { - method: ["GET", "POST"], - operationId: "handleOAuthCallback", - body: schema.optional(), - query: schema.optional(), - metadata: { - ...HIDE_METADATA, - allowedMediaTypes: ["application/x-www-form-urlencoded", "application/json"] - } -}, async (c) => { - let queryOrBody; - const defaultErrorURL = c.context.options.onAPIError?.errorURL || `${c.context.baseURL}/error`; - if (c.method === "POST") { - const postData = c.body ? schema.parse(c.body) : {}; - const queryData = c.query ? schema.parse(c.query) : {}; - const mergedData = schema.parse({ - ...postData, - ...queryData - }); - const params = new URLSearchParams(); - for (const [key, value] of Object.entries(mergedData)) if (value !== void 0 && value !== null) params.set(key, String(value)); - const redirectURL = `${c.context.baseURL}/callback/${c.params.id}?${params.toString()}`; - throw c.redirect(redirectURL); - } - try { - if (c.method === "GET") queryOrBody = schema.parse(c.query); - else if (c.method === "POST") queryOrBody = schema.parse(c.body); - else throw new Error("Unsupported method"); - } catch (e) { - c.context.logger.error("INVALID_CALLBACK_REQUEST", e); - throw c.redirect(`${defaultErrorURL}?error=invalid_callback_request`); - } - const { code, error: error2, state, error_description, device_id, user: userData } = queryOrBody; - if (!state) { - c.context.logger.error("State not found", error2); - const url = `${defaultErrorURL}${defaultErrorURL.includes("?") ? "&" : "?"}state=state_not_found`; - throw c.redirect(url); - } - const { codeVerifier, callbackURL, link, errorURL, newUserURL, requestSignUp } = await parseState(c); - function redirectOnError(error$1, description) { - const baseURL = errorURL ?? defaultErrorURL; - const params = new URLSearchParams({ error: error$1 }); - if (description) params.set("error_description", description); - const url = `${baseURL}${baseURL.includes("?") ? "&" : "?"}${params.toString()}`; - throw c.redirect(url); - } - if (error2) redirectOnError(error2, error_description); - if (!code) { - c.context.logger.error("Code not found"); - throw redirectOnError("no_code"); - } - const provider = c.context.socialProviders.find((p) => p.id === c.params.id); - if (!provider) { - c.context.logger.error("Oauth provider with id", c.params.id, "not found"); - throw redirectOnError("oauth_provider_not_found"); - } - let tokens; - try { - tokens = await provider.validateAuthorizationCode({ - code, - codeVerifier, - deviceId: device_id, - redirectURI: `${c.context.baseURL}/callback/${provider.id}` - }); - } catch (e) { - c.context.logger.error("", e); - throw redirectOnError("invalid_code"); - } - if (!tokens) throw redirectOnError("invalid_code"); - const parsedUserData = userData ? safeJSONParse(userData) : null; - const userInfo = await provider.getUserInfo({ - ...tokens, - user: parsedUserData ?? void 0 - }).then((res) => res?.user); - if (!userInfo) { - c.context.logger.error("Unable to get user info"); - return redirectOnError("unable_to_get_user_info"); - } - if (!callbackURL) { - c.context.logger.error("No callback URL found"); - throw redirectOnError("no_callback_url"); - } - if (link) { - if (!c.context.options.account?.accountLinking?.trustedProviders?.includes(provider.id) && !userInfo.emailVerified || c.context.options.account?.accountLinking?.enabled === false) { - c.context.logger.error("Unable to link account - untrusted provider"); - return redirectOnError("unable_to_link_account"); - } - if (userInfo.email?.toLowerCase() !== link.email.toLowerCase() && c.context.options.account?.accountLinking?.allowDifferentEmails !== true) return redirectOnError("email_doesn't_match"); - const existingAccount = await c.context.internalAdapter.findAccount(String(userInfo.id)); - if (existingAccount) { - if (existingAccount.userId.toString() !== link.userId.toString()) return redirectOnError("account_already_linked_to_different_user"); - const updateData = Object.fromEntries(Object.entries({ - accessToken: await setTokenUtil(tokens.accessToken, c.context), - refreshToken: await setTokenUtil(tokens.refreshToken, c.context), - idToken: tokens.idToken, - accessTokenExpiresAt: tokens.accessTokenExpiresAt, - refreshTokenExpiresAt: tokens.refreshTokenExpiresAt, - scope: tokens.scopes?.join(",") - }).filter(([_, value]) => value !== void 0)); - await c.context.internalAdapter.updateAccount(existingAccount.id, updateData); - } else if (!await c.context.internalAdapter.createAccount({ - userId: link.userId, - providerId: provider.id, - accountId: String(userInfo.id), - ...tokens, - accessToken: await setTokenUtil(tokens.accessToken, c.context), - refreshToken: await setTokenUtil(tokens.refreshToken, c.context), - scope: tokens.scopes?.join(",") - })) return redirectOnError("unable_to_link_account"); - let toRedirectTo$1; - try { - toRedirectTo$1 = callbackURL.toString(); - } catch { - toRedirectTo$1 = callbackURL; - } - throw c.redirect(toRedirectTo$1); - } - if (!userInfo.email) { - c.context.logger.error("Provider did not return email. This could be due to misconfiguration in the provider settings."); - return redirectOnError("email_not_found"); - } - const accountData = { - providerId: provider.id, - accountId: String(userInfo.id), - ...tokens, - scope: tokens.scopes?.join(",") - }; - const result = await handleOAuthUserInfo(c, { - userInfo: { - ...userInfo, - id: String(userInfo.id), - email: userInfo.email, - name: userInfo.name || userInfo.email - }, - account: accountData, - callbackURL, - disableSignUp: provider.disableImplicitSignUp && !requestSignUp || provider.options?.disableSignUp, - overrideUserInfo: provider.options?.overrideUserInfoOnSignIn - }); - if (result.error) { - c.context.logger.error(result.error.split(" ").join("_")); - return redirectOnError(result.error.split(" ").join("_")); - } - const { session, user } = result.data; - await setSessionCookie(c, { - session, - user - }); - let toRedirectTo; - try { - toRedirectTo = (result.isRegister ? newUserURL || callbackURL : callbackURL).toString(); - } catch { - toRedirectTo = result.isRegister ? newUserURL || callbackURL : callbackURL; - } - throw c.redirect(toRedirectTo); -}); -function sanitize(input) { - return input.replace(//g, ">").replace(/"/g, """).replace(/'/g, "'").replace(/&(?!amp;|lt;|gt;|quot;|#39;|#x[0-9a-fA-F]+;|#[0-9]+;)/g, "&"); -} -const html = (options, code = "Unknown", description = null) => { - const custom = options.onAPIError?.customizeDefaultErrorPage; - return ` - - - - - Error - - - -
-${custom?.disableBackgroundGrid ? "" : ` -
-
-`} - -
- ${custom?.disableCornerDecorations ? "" : ` - -
-
- -
-
`} - -
-
-
-

- ERROR -

-
-
-
- -

- Something went wrong -

- -
- - CODE: - - - ${sanitize(code)} - -
- -

- ${!description ? `We encountered an unexpected error. Please try again or return to the home page. If you're a developer, you can find more information about the error here.` : description} -

-
- - -
-
- -`; -}; -const error = createAuthEndpoint("/error", { - method: "GET", - metadata: { - ...HIDE_METADATA, - openapi: { - description: "Displays an error page", - responses: { "200": { - description: "Success", - content: { "text/html": { schema: { - type: "string", - description: "The HTML content of the error page" - } } } - } } - } - } -}, async (c) => { - const url = new URL(c.request?.url || ""); - const unsanitizedCode = url.searchParams.get("error") || "UNKNOWN"; - const unsanitizedDescription = url.searchParams.get("error_description") || null; - const safeCode = /^[\'A-Za-z0-9_-]+$/.test(unsanitizedCode) ? unsanitizedCode : "UNKNOWN"; - const safeDescription = unsanitizedDescription ? sanitize(unsanitizedDescription) : null; - const queryParams = new URLSearchParams(); - queryParams.set("error", safeCode); - if (unsanitizedDescription) queryParams.set("error_description", unsanitizedDescription); - const options = c.context.options; - const errorURL = options.onAPIError?.errorURL; - if (errorURL) return new Response(null, { - status: 302, - headers: { Location: `${errorURL}${errorURL.includes("?") ? "&" : "?"}${queryParams.toString()}` } - }); - if (isProduction && !options.onAPIError?.customizeDefaultErrorPage) return new Response(null, { - status: 302, - headers: { Location: `/?${queryParams.toString()}` } - }); - return new Response(html(c.context.options, safeCode, safeDescription), { headers: { "Content-Type": "text/html" } }); -}); -const ok = createAuthEndpoint("/ok", { - method: "GET", - metadata: { - ...HIDE_METADATA, - openapi: { - description: "Check if the API is working", - responses: { "200": { - description: "API is working", - content: { "application/json": { schema: { - type: "object", - properties: { ok: { - type: "boolean", - description: "Indicates if the API is working" - } }, - required: ["ok"] - } } } - } } - } - } -}, async (ctx) => { - return ctx.json({ ok: true }); -}); -async function validatePassword(ctx, data) { - const credentialAccount = (await ctx.context.internalAdapter.findAccounts(data.userId))?.find((account) => account.providerId === "credential"); - const currentPassword = credentialAccount?.password; - if (!credentialAccount || !currentPassword) return false; - return await ctx.context.password.verify({ - hash: currentPassword, - password: data.password - }); -} -async function checkPassword(userId, c) { - const credentialAccount = (await c.context.internalAdapter.findAccounts(userId))?.find((account) => account.providerId === "credential"); - const currentPassword = credentialAccount?.password; - if (!credentialAccount || !currentPassword || !c.body.password) throw new APIError("BAD_REQUEST", { message: "No password credential found" }); - if (!await c.context.password.verify({ - hash: currentPassword, - password: c.body.password - })) throw new APIError("BAD_REQUEST", { message: "Invalid password" }); - return true; -} -function redirectError(ctx, callbackURL, query) { - const url = callbackURL ? new URL(callbackURL, ctx.baseURL) : new URL(`${ctx.baseURL}/error`); - if (query) Object.entries(query).forEach(([k, v]) => url.searchParams.set(k, v)); - return url.href; -} -function redirectCallback(ctx, callbackURL, query) { - const url = new URL(callbackURL, ctx.baseURL); - if (query) Object.entries(query).forEach(([k, v]) => url.searchParams.set(k, v)); - return url.href; -} -const requestPasswordReset = createAuthEndpoint("/request-password-reset", { - method: "POST", - body: z.object({ - email: z.email().meta({ description: "The email address of the user to send a password reset email to" }), - redirectTo: z.string().meta({ description: "The URL to redirect the user to reset their password. If the token isn't valid or expired, it'll be redirected with a query parameter `?error=INVALID_TOKEN`. If the token is valid, it'll be redirected with a query parameter `?token=VALID_TOKEN" }).optional() - }), - metadata: { openapi: { - operationId: "requestPasswordReset", - description: "Send a password reset email to the user", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { - status: { type: "boolean" }, - message: { type: "string" } - } - } } } - } } - } } -}, async (ctx) => { - if (!ctx.context.options.emailAndPassword?.sendResetPassword) { - ctx.context.logger.error("Reset password isn't enabled.Please pass an emailAndPassword.sendResetPassword function in your auth config!"); - throw new APIError("BAD_REQUEST", { message: "Reset password isn't enabled" }); - } - const { email, redirectTo } = ctx.body; - const user = await ctx.context.internalAdapter.findUserByEmail(email, { includeAccounts: true }); - if (!user) { - generateId(24); - await ctx.context.internalAdapter.findVerificationValue("dummy-verification-token"); - ctx.context.logger.error("Reset Password: User not found", { email }); - return ctx.json({ - status: true, - message: "If this email exists in our system, check your email for the reset link" - }); - } - const expiresAt = getDate(ctx.context.options.emailAndPassword.resetPasswordTokenExpiresIn || 3600 * 1, "sec"); - const verificationToken = generateId(24); - await ctx.context.internalAdapter.createVerificationValue({ - value: user.user.id, - identifier: `reset-password:${verificationToken}`, - expiresAt - }); - const callbackURL = redirectTo ? encodeURIComponent(redirectTo) : ""; - const url = `${ctx.context.baseURL}/reset-password/${verificationToken}?callbackURL=${callbackURL}`; - await ctx.context.runInBackgroundOrAwait(ctx.context.options.emailAndPassword.sendResetPassword({ - user: user.user, - url, - token: verificationToken - }, ctx.request)); - return ctx.json({ - status: true, - message: "If this email exists in our system, check your email for the reset link" - }); -}); -const requestPasswordResetCallback = createAuthEndpoint("/reset-password/:token", { - method: "GET", - operationId: "forgetPasswordCallback", - query: z.object({ callbackURL: z.string().meta({ description: "The URL to redirect the user to reset their password" }) }), - use: [originCheck((ctx) => ctx.query.callbackURL)], - metadata: { openapi: { - operationId: "resetPasswordCallback", - description: "Redirects the user to the callback URL with the token", - parameters: [{ - name: "token", - in: "path", - required: true, - description: "The token to reset the password", - schema: { type: "string" } - }, { - name: "callbackURL", - in: "query", - required: true, - description: "The URL to redirect the user to reset their password", - schema: { type: "string" } - }], - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { token: { type: "string" } } - } } } - } } - } } -}, async (ctx) => { - const { token } = ctx.params; - const { callbackURL } = ctx.query; - if (!token || !callbackURL) throw ctx.redirect(redirectError(ctx.context, callbackURL, { error: "INVALID_TOKEN" })); - const verification = await ctx.context.internalAdapter.findVerificationValue(`reset-password:${token}`); - if (!verification || verification.expiresAt < /* @__PURE__ */ new Date()) throw ctx.redirect(redirectError(ctx.context, callbackURL, { error: "INVALID_TOKEN" })); - throw ctx.redirect(redirectCallback(ctx.context, callbackURL, { token })); -}); -const resetPassword = createAuthEndpoint("/reset-password", { - method: "POST", - operationId: "resetPassword", - query: z.object({ token: z.string().optional() }).optional(), - body: z.object({ - newPassword: z.string().meta({ description: "The new password to set" }), - token: z.string().meta({ description: "The token to reset the password" }).optional() - }), - metadata: { openapi: { - operationId: "resetPassword", - description: "Reset the password for a user", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { status: { type: "boolean" } } - } } } - } } - } } -}, async (ctx) => { - const token = ctx.body.token || ctx.query?.token; - if (!token) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_TOKEN }); - const { newPassword } = ctx.body; - const minLength = ctx.context.password?.config.minPasswordLength; - const maxLength = ctx.context.password?.config.maxPasswordLength; - if (newPassword.length < minLength) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_SHORT }); - if (newPassword.length > maxLength) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_LONG }); - const id = `reset-password:${token}`; - const verification = await ctx.context.internalAdapter.findVerificationValue(id); - if (!verification || verification.expiresAt < /* @__PURE__ */ new Date()) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_TOKEN }); - const userId = verification.value; - const hashedPassword = await ctx.context.password.hash(newPassword); - if (!(await ctx.context.internalAdapter.findAccounts(userId)).find((ac) => ac.providerId === "credential")) await ctx.context.internalAdapter.createAccount({ - userId, - providerId: "credential", - password: hashedPassword, - accountId: userId - }); - else await ctx.context.internalAdapter.updatePassword(userId, hashedPassword); - await ctx.context.internalAdapter.deleteVerificationValue(verification.id); - if (ctx.context.options.emailAndPassword?.onPasswordReset) { - const user = await ctx.context.internalAdapter.findUserById(userId); - if (user) await ctx.context.options.emailAndPassword.onPasswordReset({ user }, ctx.request); - } - if (ctx.context.options.emailAndPassword?.revokeSessionsOnPasswordReset) await ctx.context.internalAdapter.deleteSessions(userId); - return ctx.json({ status: true }); -}); -const verifyPassword = createAuthEndpoint("/verify-password", { - method: "POST", - body: z.object({ password: z.string().meta({ description: "The password to verify" }) }), - metadata: { - scope: "server", - openapi: { - operationId: "verifyPassword", - description: "Verify the current user's password", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { status: { type: "boolean" } } - } } } - } } - } - }, - use: [sensitiveSessionMiddleware] -}, async (ctx) => { - const { password } = ctx.body; - const session = ctx.context.session; - if (!await validatePassword(ctx, { - password, - userId: session.user.id - })) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_PASSWORD }); - return ctx.json({ status: true }); -}); -const socialSignInBodySchema = z.object({ - callbackURL: z.string().meta({ description: "Callback URL to redirect to after the user has signed in" }).optional(), - newUserCallbackURL: z.string().optional(), - errorCallbackURL: z.string().meta({ description: "Callback URL to redirect to if an error happens" }).optional(), - provider: SocialProviderListEnum, - disableRedirect: z.boolean().meta({ description: "Disable automatic redirection to the provider. Useful for handling the redirection yourself" }).optional(), - idToken: z.optional(z.object({ - token: z.string().meta({ description: "ID token from the provider" }), - nonce: z.string().meta({ description: "Nonce used to generate the token" }).optional(), - accessToken: z.string().meta({ description: "Access token from the provider" }).optional(), - refreshToken: z.string().meta({ description: "Refresh token from the provider" }).optional(), - expiresAt: z.number().meta({ description: "Expiry date of the token" }).optional() - })), - scopes: z.array(z.string()).meta({ description: "Array of scopes to request from the provider. This will override the default scopes passed." }).optional(), - requestSignUp: z.boolean().meta({ description: "Explicitly request sign-up. Useful when disableImplicitSignUp is true for this provider" }).optional(), - loginHint: z.string().meta({ description: "The login hint to use for the authorization code request" }).optional(), - additionalData: z.record(z.string(), z.any()).optional().meta({ description: "Additional data to be passed through the OAuth flow" }) -}); -const signInSocial = () => createAuthEndpoint("/sign-in/social", { - method: "POST", - operationId: "socialSignIn", - body: socialSignInBodySchema, - metadata: { - $Infer: { - body: {}, - returned: {} - }, - openapi: { - description: "Sign in with a social provider", - operationId: "socialSignIn", - responses: { "200": { - description: "Success - Returns either session details or redirect URL", - content: { "application/json": { schema: { - type: "object", - description: "Session response when idToken is provided", - properties: { - token: { type: "string" }, - user: { - type: "object", - $ref: "#/components/schemas/User" - }, - url: { type: "string" }, - redirect: { - type: "boolean", - enum: [false] - } - }, - required: [ - "redirect", - "token", - "user" - ] - } } } - } } - } - } -}, async (c) => { - const provider = c.context.socialProviders.find((p) => p.id === c.body.provider); - if (!provider) { - c.context.logger.error("Provider not found. Make sure to add the provider in your auth config", { provider: c.body.provider }); - throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.PROVIDER_NOT_FOUND }); - } - if (c.body.idToken) { - if (!provider.verifyIdToken) { - c.context.logger.error("Provider does not support id token verification", { provider: c.body.provider }); - throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.ID_TOKEN_NOT_SUPPORTED }); - } - const { token, nonce } = c.body.idToken; - if (!await provider.verifyIdToken(token, nonce)) { - c.context.logger.error("Invalid id token", { provider: c.body.provider }); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.INVALID_TOKEN }); - } - const userInfo = await provider.getUserInfo({ - idToken: token, - accessToken: c.body.idToken.accessToken, - refreshToken: c.body.idToken.refreshToken - }); - if (!userInfo || !userInfo?.user) { - c.context.logger.error("Failed to get user info", { provider: c.body.provider }); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.FAILED_TO_GET_USER_INFO }); - } - if (!userInfo.user.email) { - c.context.logger.error("User email not found", { provider: c.body.provider }); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.USER_EMAIL_NOT_FOUND }); - } - const data = await handleOAuthUserInfo(c, { - userInfo: { - ...userInfo.user, - email: userInfo.user.email, - id: String(userInfo.user.id), - name: userInfo.user.name || "", - image: userInfo.user.image, - emailVerified: userInfo.user.emailVerified || false - }, - account: { - providerId: provider.id, - accountId: String(userInfo.user.id), - accessToken: c.body.idToken.accessToken - }, - callbackURL: c.body.callbackURL, - disableSignUp: provider.disableImplicitSignUp && !c.body.requestSignUp || provider.disableSignUp - }); - if (data.error) throw new APIError("UNAUTHORIZED", { message: data.error }); - await setSessionCookie(c, data.data); - return c.json({ - redirect: false, - token: data.data.session.token, - url: void 0, - user: parseUserOutput(c.context.options, data.data.user) - }); - } - const { codeVerifier, state } = await generateState(c, void 0, c.body.additionalData); - const url = await provider.createAuthorizationURL({ - state, - codeVerifier, - redirectURI: `${c.context.baseURL}/callback/${provider.id}`, - scopes: c.body.scopes, - loginHint: c.body.loginHint - }); - if (!c.body.disableRedirect) c.setHeader("Location", url.toString()); - return c.json({ - url: url.toString(), - redirect: !c.body.disableRedirect - }); -}); -const signInEmail = () => createAuthEndpoint("/sign-in/email", { - method: "POST", - operationId: "signInEmail", - use: [formCsrfMiddleware], - body: z.object({ - email: z.string().meta({ description: "Email of the user" }), - password: z.string().meta({ description: "Password of the user" }), - callbackURL: z.string().meta({ description: "Callback URL to use as a redirect for email verification" }).optional(), - rememberMe: z.boolean().meta({ description: "If this is false, the session will not be remembered. Default is `true`." }).default(true).optional() - }), - metadata: { - allowedMediaTypes: ["application/x-www-form-urlencoded", "application/json"], - $Infer: { - body: {}, - returned: {} - }, - openapi: { - operationId: "signInEmail", - description: "Sign in with email and password", - responses: { "200": { - description: "Success - Returns either session details or redirect URL", - content: { "application/json": { schema: { - type: "object", - description: "Session response when idToken is provided", - properties: { - redirect: { - type: "boolean", - enum: [false] - }, - token: { - type: "string", - description: "Session token" - }, - url: { - type: "string", - nullable: true - }, - user: { - type: "object", - $ref: "#/components/schemas/User" - } - }, - required: [ - "redirect", - "token", - "user" - ] - } } } - } } - } - } -}, async (ctx) => { - if (!ctx.context.options?.emailAndPassword?.enabled) { - ctx.context.logger.error("Email and password is not enabled. Make sure to enable it in the options on you `auth.ts` file. Check `https://better-auth.com/docs/authentication/email-password` for more!"); - throw new APIError("BAD_REQUEST", { message: "Email and password is not enabled" }); - } - const { email, password } = ctx.body; - if (!z.email().safeParse(email).success) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_EMAIL }); - const user = await ctx.context.internalAdapter.findUserByEmail(email, { includeAccounts: true }); - if (!user) { - await ctx.context.password.hash(password); - ctx.context.logger.error("User not found", { email }); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD }); - } - const credentialAccount = user.accounts.find((a) => a.providerId === "credential"); - if (!credentialAccount) { - await ctx.context.password.hash(password); - ctx.context.logger.error("Credential account not found", { email }); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD }); - } - const currentPassword = credentialAccount?.password; - if (!currentPassword) { - await ctx.context.password.hash(password); - ctx.context.logger.error("Password not found", { email }); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD }); - } - if (!await ctx.context.password.verify({ - hash: currentPassword, - password - })) { - ctx.context.logger.error("Invalid password"); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD }); - } - if (ctx.context.options?.emailAndPassword?.requireEmailVerification && !user.user.emailVerified) { - if (!ctx.context.options?.emailVerification?.sendVerificationEmail) throw new APIError("FORBIDDEN", { message: BASE_ERROR_CODES.EMAIL_NOT_VERIFIED }); - if (ctx.context.options?.emailVerification?.sendOnSignIn) { - const token = await createEmailVerificationToken(ctx.context.secret, user.user.email, void 0, ctx.context.options.emailVerification?.expiresIn); - const callbackURL = ctx.body.callbackURL ? encodeURIComponent(ctx.body.callbackURL) : encodeURIComponent("/"); - const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${callbackURL}`; - await ctx.context.runInBackgroundOrAwait(ctx.context.options.emailVerification.sendVerificationEmail({ - user: user.user, - url, - token - }, ctx.request)); - } - throw new APIError("FORBIDDEN", { message: BASE_ERROR_CODES.EMAIL_NOT_VERIFIED }); - } - const session = await ctx.context.internalAdapter.createSession(user.user.id, ctx.body.rememberMe === false); - if (!session) { - ctx.context.logger.error("Failed to create session"); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.FAILED_TO_CREATE_SESSION }); - } - await setSessionCookie(ctx, { - session, - user: user.user - }, ctx.body.rememberMe === false); - if (ctx.body.callbackURL) ctx.setHeader("Location", ctx.body.callbackURL); - return ctx.json({ - redirect: !!ctx.body.callbackURL, - token: session.token, - url: ctx.body.callbackURL, - user: parseUserOutput(ctx.context.options, user.user) - }); -}); -const signOut = createAuthEndpoint("/sign-out", { - method: "POST", - operationId: "signOut", - requireHeaders: true, - metadata: { openapi: { - operationId: "signOut", - description: "Sign out the current user", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { success: { type: "boolean" } } - } } } - } } - } } -}, async (ctx) => { - const sessionCookieToken = await ctx.getSignedCookie(ctx.context.authCookies.sessionToken.name, ctx.context.secret); - if (sessionCookieToken) try { - await ctx.context.internalAdapter.deleteSession(sessionCookieToken); - } catch (e) { - ctx.context.logger.error("Failed to delete session from database", e); - } - deleteSessionCookie(ctx); - return ctx.json({ success: true }); -}); -const signUpEmailBodySchema = z.object({ - name: z.string(), - email: z.email(), - password: z.string().nonempty(), - image: z.string().optional(), - callbackURL: z.string().optional(), - rememberMe: z.boolean().optional() -}).and(z.record(z.string(), z.any())); -const signUpEmail = () => createAuthEndpoint("/sign-up/email", { - method: "POST", - operationId: "signUpWithEmailAndPassword", - use: [formCsrfMiddleware], - body: signUpEmailBodySchema, - metadata: { - allowedMediaTypes: ["application/x-www-form-urlencoded", "application/json"], - $Infer: { - body: {}, - returned: {} - }, - openapi: { - operationId: "signUpWithEmailAndPassword", - description: "Sign up a user using email and password", - requestBody: { content: { "application/json": { schema: { - type: "object", - properties: { - name: { - type: "string", - description: "The name of the user" - }, - email: { - type: "string", - description: "The email of the user" - }, - password: { - type: "string", - description: "The password of the user" - }, - image: { - type: "string", - description: "The profile image URL of the user" - }, - callbackURL: { - type: "string", - description: "The URL to use for email verification callback" - }, - rememberMe: { - type: "boolean", - description: "If this is false, the session will not be remembered. Default is `true`." - } - }, - required: [ - "name", - "email", - "password" - ] - } } } }, - responses: { - "200": { - description: "Successfully created user", - content: { "application/json": { schema: { - type: "object", - properties: { - token: { - type: "string", - nullable: true, - description: "Authentication token for the session" - }, - user: { - type: "object", - properties: { - id: { - type: "string", - description: "The unique identifier of the user" - }, - email: { - type: "string", - format: "email", - description: "The email address of the user" - }, - name: { - type: "string", - description: "The name of the user" - }, - image: { - type: "string", - format: "uri", - nullable: true, - description: "The profile image URL of the user" - }, - emailVerified: { - type: "boolean", - description: "Whether the email has been verified" - }, - createdAt: { - type: "string", - format: "date-time", - description: "When the user was created" - }, - updatedAt: { - type: "string", - format: "date-time", - description: "When the user was last updated" - } - }, - required: [ - "id", - "email", - "name", - "emailVerified", - "createdAt", - "updatedAt" - ] - } - }, - required: ["user"] - } } } - }, - "422": { - description: "Unprocessable Entity. User already exists or failed to create user.", - content: { "application/json": { schema: { - type: "object", - properties: { message: { type: "string" } } - } } } - } - } - } - } -}, async (ctx) => { - return runWithTransaction(ctx.context.adapter, async () => { - if (!ctx.context.options.emailAndPassword?.enabled || ctx.context.options.emailAndPassword?.disableSignUp) throw new APIError("BAD_REQUEST", { message: "Email and password sign up is not enabled" }); - const body = ctx.body; - const { name, email, password, image, callbackURL: _callbackURL, rememberMe, ...rest } = body; - if (!z.email().safeParse(email).success) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_EMAIL }); - if (!password || typeof password !== "string") throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_PASSWORD }); - const minPasswordLength = ctx.context.password.config.minPasswordLength; - if (password.length < minPasswordLength) { - ctx.context.logger.error("Password is too short"); - throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_SHORT }); - } - const maxPasswordLength = ctx.context.password.config.maxPasswordLength; - if (password.length > maxPasswordLength) { - ctx.context.logger.error("Password is too long"); - throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_LONG }); - } - if ((await ctx.context.internalAdapter.findUserByEmail(email))?.user) { - ctx.context.logger.info(`Sign-up attempt for existing email: ${email}`); - throw new APIError("UNPROCESSABLE_ENTITY", { message: BASE_ERROR_CODES.USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL }); - } - const hash = await ctx.context.password.hash(password); - let createdUser; - try { - const data = parseUserInput(ctx.context.options, rest, "create"); - createdUser = await ctx.context.internalAdapter.createUser({ - email: email.toLowerCase(), - name, - image, - ...data, - emailVerified: false - }); - if (!createdUser) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.FAILED_TO_CREATE_USER }); - } catch (e) { - if (isDevelopment()) ctx.context.logger.error("Failed to create user", e); - if (e instanceof APIError) throw e; - ctx.context.logger?.error("Failed to create user", e); - throw new APIError("UNPROCESSABLE_ENTITY", { message: BASE_ERROR_CODES.FAILED_TO_CREATE_USER }); - } - if (!createdUser) throw new APIError("UNPROCESSABLE_ENTITY", { message: BASE_ERROR_CODES.FAILED_TO_CREATE_USER }); - await ctx.context.internalAdapter.linkAccount({ - userId: createdUser.id, - providerId: "credential", - accountId: createdUser.id, - password: hash - }); - if (ctx.context.options.emailVerification?.sendOnSignUp ?? ctx.context.options.emailAndPassword.requireEmailVerification) { - const token = await createEmailVerificationToken(ctx.context.secret, createdUser.email, void 0, ctx.context.options.emailVerification?.expiresIn); - const callbackURL = body.callbackURL ? encodeURIComponent(body.callbackURL) : encodeURIComponent("/"); - const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${callbackURL}`; - if (ctx.context.options.emailVerification?.sendVerificationEmail) await ctx.context.runInBackgroundOrAwait(ctx.context.options.emailVerification.sendVerificationEmail({ - user: createdUser, - url, - token - }, ctx.request)); - } - if (ctx.context.options.emailAndPassword.autoSignIn === false || ctx.context.options.emailAndPassword.requireEmailVerification) return ctx.json({ - token: null, - user: parseUserOutput(ctx.context.options, createdUser) - }); - const session = await ctx.context.internalAdapter.createSession(createdUser.id, rememberMe === false); - if (!session) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.FAILED_TO_CREATE_SESSION }); - await setSessionCookie(ctx, { - session, - user: createdUser - }, rememberMe === false); - return ctx.json({ - token: session.token, - user: parseUserOutput(ctx.context.options, createdUser) - }); - }); -}); -const updateUserBodySchema = z.record(z.string().meta({ description: "Field name must be a string" }), z.any()); -const updateUser = () => createAuthEndpoint("/update-user", { - method: "POST", - operationId: "updateUser", - body: updateUserBodySchema, - use: [sessionMiddleware], - metadata: { - $Infer: { body: {} }, - openapi: { - operationId: "updateUser", - description: "Update the current user", - requestBody: { content: { "application/json": { schema: { - type: "object", - properties: { - name: { - type: "string", - description: "The name of the user" - }, - image: { - type: "string", - description: "The image of the user", - nullable: true - } - } - } } } }, - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { user: { - type: "object", - $ref: "#/components/schemas/User" - } } - } } } - } } - } - } -}, async (ctx) => { - const body = ctx.body; - if (typeof body !== "object" || Array.isArray(body)) throw new APIError("BAD_REQUEST", { message: "Body must be an object" }); - if (body.email) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.EMAIL_CAN_NOT_BE_UPDATED }); - const { name, image, ...rest } = body; - const session = ctx.context.session; - const additionalFields = parseUserInput(ctx.context.options, rest, "update"); - if (image === void 0 && name === void 0 && Object.keys(additionalFields).length === 0) throw new APIError("BAD_REQUEST", { message: "No fields to update" }); - const updatedUser = await ctx.context.internalAdapter.updateUser(session.user.id, { - name, - image, - ...additionalFields - }) ?? { - ...session.user, - ...name !== void 0 && { name }, - ...image !== void 0 && { image }, - ...additionalFields - }; - await setSessionCookie(ctx, { - session: session.session, - user: updatedUser - }); - return ctx.json({ status: true }); -}); -const changePassword = createAuthEndpoint("/change-password", { - method: "POST", - operationId: "changePassword", - body: z.object({ - newPassword: z.string().meta({ description: "The new password to set" }), - currentPassword: z.string().meta({ description: "The current password is required" }), - revokeOtherSessions: z.boolean().meta({ description: "Must be a boolean value" }).optional() - }), - use: [sensitiveSessionMiddleware], - metadata: { openapi: { - operationId: "changePassword", - description: "Change the password of the user", - responses: { "200": { - description: "Password successfully changed", - content: { "application/json": { schema: { - type: "object", - properties: { - token: { - type: "string", - nullable: true, - description: "New session token if other sessions were revoked" - }, - user: { - type: "object", - properties: { - id: { - type: "string", - description: "The unique identifier of the user" - }, - email: { - type: "string", - format: "email", - description: "The email address of the user" - }, - name: { - type: "string", - description: "The name of the user" - }, - image: { - type: "string", - format: "uri", - nullable: true, - description: "The profile image URL of the user" - }, - emailVerified: { - type: "boolean", - description: "Whether the email has been verified" - }, - createdAt: { - type: "string", - format: "date-time", - description: "When the user was created" - }, - updatedAt: { - type: "string", - format: "date-time", - description: "When the user was last updated" - } - }, - required: [ - "id", - "email", - "name", - "emailVerified", - "createdAt", - "updatedAt" - ] - } - }, - required: ["user"] - } } } - } } - } } -}, async (ctx) => { - const { newPassword, currentPassword, revokeOtherSessions: revokeOtherSessions2 } = ctx.body; - const session = ctx.context.session; - const minPasswordLength = ctx.context.password.config.minPasswordLength; - if (newPassword.length < minPasswordLength) { - ctx.context.logger.error("Password is too short"); - throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_SHORT }); - } - const maxPasswordLength = ctx.context.password.config.maxPasswordLength; - if (newPassword.length > maxPasswordLength) { - ctx.context.logger.error("Password is too long"); - throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_LONG }); - } - const account = (await ctx.context.internalAdapter.findAccounts(session.user.id)).find((account$1) => account$1.providerId === "credential" && account$1.password); - if (!account || !account.password) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.CREDENTIAL_ACCOUNT_NOT_FOUND }); - const passwordHash = await ctx.context.password.hash(newPassword); - if (!await ctx.context.password.verify({ - hash: account.password, - password: currentPassword - })) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_PASSWORD }); - await ctx.context.internalAdapter.updateAccount(account.id, { password: passwordHash }); - let token = null; - if (revokeOtherSessions2) { - await ctx.context.internalAdapter.deleteSessions(session.user.id); - const newSession = await ctx.context.internalAdapter.createSession(session.user.id); - if (!newSession) throw new APIError("INTERNAL_SERVER_ERROR", { message: BASE_ERROR_CODES.FAILED_TO_GET_SESSION }); - await setSessionCookie(ctx, { - session: newSession, - user: session.user - }); - token = newSession.token; - } - return ctx.json({ - token, - user: parseUserOutput(ctx.context.options, session.user) - }); -}); -const setPassword = createAuthEndpoint({ - method: "POST", - body: z.object({ newPassword: z.string().meta({ description: "The new password to set is required" }) }), - use: [sensitiveSessionMiddleware] -}, async (ctx) => { - const { newPassword } = ctx.body; - const session = ctx.context.session; - const minPasswordLength = ctx.context.password.config.minPasswordLength; - if (newPassword.length < minPasswordLength) { - ctx.context.logger.error("Password is too short"); - throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_SHORT }); - } - const maxPasswordLength = ctx.context.password.config.maxPasswordLength; - if (newPassword.length > maxPasswordLength) { - ctx.context.logger.error("Password is too long"); - throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_LONG }); - } - const account = (await ctx.context.internalAdapter.findAccounts(session.user.id)).find((account$1) => account$1.providerId === "credential" && account$1.password); - const passwordHash = await ctx.context.password.hash(newPassword); - if (!account) { - await ctx.context.internalAdapter.linkAccount({ - userId: session.user.id, - providerId: "credential", - accountId: session.user.id, - password: passwordHash - }); - return ctx.json({ status: true }); - } - throw new APIError("BAD_REQUEST", { message: "user already has a password" }); -}); -const deleteUser = createAuthEndpoint("/delete-user", { - method: "POST", - use: [sensitiveSessionMiddleware], - body: z.object({ - callbackURL: z.string().meta({ description: "The callback URL to redirect to after the user is deleted" }).optional(), - password: z.string().meta({ description: "The password of the user is required to delete the user" }).optional(), - token: z.string().meta({ description: "The token to delete the user is required" }).optional() - }), - metadata: { openapi: { - operationId: "deleteUser", - description: "Delete the user", - requestBody: { content: { "application/json": { schema: { - type: "object", - properties: { - callbackURL: { - type: "string", - description: "The callback URL to redirect to after the user is deleted" - }, - password: { - type: "string", - description: "The user's password. Required if session is not fresh" - }, - token: { - type: "string", - description: "The deletion verification token" - } - } - } } } }, - responses: { "200": { - description: "User deletion processed successfully", - content: { "application/json": { schema: { - type: "object", - properties: { - success: { - type: "boolean", - description: "Indicates if the operation was successful" - }, - message: { - type: "string", - enum: ["User deleted", "Verification email sent"], - description: "Status message of the deletion process" - } - }, - required: ["success", "message"] - } } } - } } - } } -}, async (ctx) => { - if (!ctx.context.options.user?.deleteUser?.enabled) { - ctx.context.logger.error("Delete user is disabled. Enable it in the options"); - throw new APIError("NOT_FOUND"); - } - const session = ctx.context.session; - if (ctx.body.password) { - const account = (await ctx.context.internalAdapter.findAccounts(session.user.id)).find((account$1) => account$1.providerId === "credential" && account$1.password); - if (!account || !account.password) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.CREDENTIAL_ACCOUNT_NOT_FOUND }); - if (!await ctx.context.password.verify({ - hash: account.password, - password: ctx.body.password - })) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_PASSWORD }); - } - if (ctx.body.token) { - await deleteUserCallback({ - ...ctx, - query: { token: ctx.body.token } - }); - return ctx.json({ - success: true, - message: "User deleted" - }); - } - if (ctx.context.options.user.deleteUser?.sendDeleteAccountVerification) { - const token = generateRandomString(32, "0-9", "a-z"); - await ctx.context.internalAdapter.createVerificationValue({ - value: session.user.id, - identifier: `delete-account-${token}`, - expiresAt: new Date(Date.now() + (ctx.context.options.user.deleteUser?.deleteTokenExpiresIn || 3600 * 24) * 1e3) - }); - const url = `${ctx.context.baseURL}/delete-user/callback?token=${token}&callbackURL=${encodeURIComponent(ctx.body.callbackURL || "/")}`; - await ctx.context.runInBackgroundOrAwait(ctx.context.options.user.deleteUser.sendDeleteAccountVerification({ - user: session.user, - url, - token - }, ctx.request)); - return ctx.json({ - success: true, - message: "Verification email sent" - }); - } - if (!ctx.body.password && ctx.context.sessionConfig.freshAge !== 0) { - const currentAge = new Date(session.session.createdAt).getTime(); - const freshAge = ctx.context.sessionConfig.freshAge * 1e3; - if (Date.now() - currentAge > freshAge * 1e3) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.SESSION_EXPIRED }); - } - const beforeDelete = ctx.context.options.user.deleteUser?.beforeDelete; - if (beforeDelete) await beforeDelete(session.user, ctx.request); - await ctx.context.internalAdapter.deleteUser(session.user.id); - await ctx.context.internalAdapter.deleteSessions(session.user.id); - deleteSessionCookie(ctx); - const afterDelete = ctx.context.options.user.deleteUser?.afterDelete; - if (afterDelete) await afterDelete(session.user, ctx.request); - return ctx.json({ - success: true, - message: "User deleted" - }); -}); -const deleteUserCallback = createAuthEndpoint("/delete-user/callback", { - method: "GET", - query: z.object({ - token: z.string().meta({ description: "The token to verify the deletion request" }), - callbackURL: z.string().meta({ description: "The URL to redirect to after deletion" }).optional() - }), - use: [originCheck((ctx) => ctx.query.callbackURL)], - metadata: { openapi: { - description: "Callback to complete user deletion with verification token", - responses: { "200": { - description: "User successfully deleted", - content: { "application/json": { schema: { - type: "object", - properties: { - success: { - type: "boolean", - description: "Indicates if the deletion was successful" - }, - message: { - type: "string", - enum: ["User deleted"], - description: "Confirmation message" - } - }, - required: ["success", "message"] - } } } - } } - } } -}, async (ctx) => { - if (!ctx.context.options.user?.deleteUser?.enabled) { - ctx.context.logger.error("Delete user is disabled. Enable it in the options"); - throw new APIError("NOT_FOUND"); - } - const session = await getSessionFromCtx(ctx); - if (!session) throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.FAILED_TO_GET_USER_INFO }); - const token = await ctx.context.internalAdapter.findVerificationValue(`delete-account-${ctx.query.token}`); - if (!token || token.expiresAt < /* @__PURE__ */ new Date()) throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.INVALID_TOKEN }); - if (token.value !== session.user.id) throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.INVALID_TOKEN }); - const beforeDelete = ctx.context.options.user.deleteUser?.beforeDelete; - if (beforeDelete) await beforeDelete(session.user, ctx.request); - await ctx.context.internalAdapter.deleteUser(session.user.id); - await ctx.context.internalAdapter.deleteSessions(session.user.id); - await ctx.context.internalAdapter.deleteAccounts(session.user.id); - await ctx.context.internalAdapter.deleteVerificationValue(token.id); - deleteSessionCookie(ctx); - const afterDelete = ctx.context.options.user.deleteUser?.afterDelete; - if (afterDelete) await afterDelete(session.user, ctx.request); - if (ctx.query.callbackURL) throw ctx.redirect(ctx.query.callbackURL || "/"); - return ctx.json({ - success: true, - message: "User deleted" - }); -}); -const changeEmail = createAuthEndpoint("/change-email", { - method: "POST", - body: z.object({ - newEmail: z.email().meta({ description: "The new email address to set must be a valid email address" }), - callbackURL: z.string().meta({ description: "The URL to redirect to after email verification" }).optional() - }), - use: [sensitiveSessionMiddleware], - metadata: { openapi: { - operationId: "changeEmail", - responses: { - "200": { - description: "Email change request processed successfully", - content: { "application/json": { schema: { - type: "object", - properties: { - user: { - type: "object", - $ref: "#/components/schemas/User" - }, - status: { - type: "boolean", - description: "Indicates if the request was successful" - }, - message: { - type: "string", - enum: ["Email updated", "Verification email sent"], - description: "Status message of the email change process", - nullable: true - } - }, - required: ["status"] - } } } - }, - "422": { - description: "Unprocessable Entity. Email already exists", - content: { "application/json": { schema: { - type: "object", - properties: { message: { type: "string" } } - } } } - } - } - } } -}, async (ctx) => { - if (!ctx.context.options.user?.changeEmail?.enabled) { - ctx.context.logger.error("Change email is disabled."); - throw new APIError("BAD_REQUEST", { message: "Change email is disabled" }); - } - const newEmail = ctx.body.newEmail.toLowerCase(); - if (newEmail === ctx.context.session.user.email) { - ctx.context.logger.error("Email is the same"); - throw new APIError("BAD_REQUEST", { message: "Email is the same" }); - } - if (await ctx.context.internalAdapter.findUserByEmail(newEmail)) { - ctx.context.logger.error("Email already exists"); - throw new APIError("UNPROCESSABLE_ENTITY", { message: BASE_ERROR_CODES.USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL }); - } - if (ctx.context.session.user.emailVerified !== true && ctx.context.options.user.changeEmail.updateEmailWithoutVerification) { - await ctx.context.internalAdapter.updateUserByEmail(ctx.context.session.user.email, { email: newEmail }); - await setSessionCookie(ctx, { - session: ctx.context.session.session, - user: { - ...ctx.context.session.user, - email: newEmail - } - }); - if (ctx.context.options.emailVerification?.sendVerificationEmail) { - const token$1 = await createEmailVerificationToken(ctx.context.secret, newEmail, void 0, ctx.context.options.emailVerification?.expiresIn); - const url$1 = `${ctx.context.baseURL}/verify-email?token=${token$1}&callbackURL=${ctx.body.callbackURL || "/"}`; - await ctx.context.runInBackgroundOrAwait(ctx.context.options.emailVerification.sendVerificationEmail({ - user: { - ...ctx.context.session.user, - email: newEmail - }, - url: url$1, - token: token$1 - }, ctx.request)); - } - return ctx.json({ status: true }); - } - if (ctx.context.session.user.emailVerified && (ctx.context.options.user.changeEmail.sendChangeEmailConfirmation || ctx.context.options.user.changeEmail.sendChangeEmailVerification)) { - const token$1 = await createEmailVerificationToken(ctx.context.secret, ctx.context.session.user.email, newEmail, ctx.context.options.emailVerification?.expiresIn, { requestType: "change-email-confirmation" }); - const url$1 = `${ctx.context.baseURL}/verify-email?token=${token$1}&callbackURL=${ctx.body.callbackURL || "/"}`; - const sendFn = ctx.context.options.user.changeEmail.sendChangeEmailConfirmation || ctx.context.options.user.changeEmail.sendChangeEmailVerification; - if (sendFn) await ctx.context.runInBackgroundOrAwait(sendFn({ - user: ctx.context.session.user, - newEmail, - url: url$1, - token: token$1 - }, ctx.request)); - return ctx.json({ status: true }); - } - if (!ctx.context.options.emailVerification?.sendVerificationEmail) { - ctx.context.logger.error("Verification email isn't enabled."); - throw new APIError("BAD_REQUEST", { message: "Verification email isn't enabled" }); - } - const token = await createEmailVerificationToken(ctx.context.secret, ctx.context.session.user.email, newEmail, ctx.context.options.emailVerification?.expiresIn, { requestType: "change-email-verification" }); - const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${ctx.body.callbackURL || "/"}`; - await ctx.context.runInBackgroundOrAwait(ctx.context.options.emailVerification.sendVerificationEmail({ - user: { - ...ctx.context.session.user, - email: newEmail - }, - url, - token - }, ctx.request)); - return ctx.json({ status: true }); -}); -const defuReplaceArrays = createDefu((obj, key, value) => { - if (Array.isArray(obj[key]) && Array.isArray(value)) { - obj[key] = value; - return true; - } -}); -const hooksSourceWeakMap = /* @__PURE__ */ new WeakMap(); -function toAuthEndpoints(endpoints, ctx) { - const api = {}; - for (const [key, endpoint] of Object.entries(endpoints)) { - api[key] = async (context) => { - const run = async () => { - const authContext = await ctx; - let internalContext = { - ...context, - context: { - ...authContext, - returned: void 0, - responseHeaders: void 0, - session: null - }, - path: endpoint.path, - headers: context?.headers ? new Headers(context?.headers) : void 0 - }; - return runWithEndpointContext(internalContext, async () => { - const { beforeHooks, afterHooks } = getHooks(authContext); - const before = await runBeforeHooks(internalContext, beforeHooks); - if ("context" in before && before.context && typeof before.context === "object") { - const { headers, ...rest } = before.context; - if (headers) headers.forEach((value, key$1) => { - internalContext.headers.set(key$1, value); - }); - internalContext = defuReplaceArrays(rest, internalContext); - } else if (before) return context?.asResponse ? toResponse(before, { headers: context?.headers }) : context?.returnHeaders ? { - headers: context?.headers, - response: before - } : before; - internalContext.asResponse = false; - internalContext.returnHeaders = true; - internalContext.returnStatus = true; - const result = await runWithEndpointContext(internalContext, () => endpoint(internalContext)).catch((e) => { - if (e instanceof APIError) - return { - response: e, - status: e.statusCode, - headers: e.headers ? new Headers(e.headers) : null - }; - throw e; - }); - if (result && result instanceof Response) return result; - internalContext.context.returned = result.response; - internalContext.context.responseHeaders = result.headers; - const after = await runAfterHooks(internalContext, afterHooks); - if (after.response) result.response = after.response; - if (result.response instanceof APIError && shouldPublishLog(authContext.logger.level, "debug")) result.response.stack = result.response.errorStack; - if (result.response instanceof APIError && !context?.asResponse) throw result.response; - return context?.asResponse ? toResponse(result.response, { - headers: result.headers, - status: result.status - }) : context?.returnHeaders ? context?.returnStatus ? { - headers: result.headers, - response: result.response, - status: result.status - } : { - headers: result.headers, - response: result.response - } : context?.returnStatus ? { - response: result.response, - status: result.status - } : result.response; - }); - }; - if (await hasRequestState()) return run(); - else return runWithRequestState(/* @__PURE__ */ new WeakMap(), run); - }; - api[key].path = endpoint.path; - api[key].options = endpoint.options; - } - return api; -} -async function runBeforeHooks(context, hooks) { - let modifiedContext = {}; - for (const hook of hooks) { - let matched = false; - try { - matched = hook.matcher(context); - } catch (error2) { - const hookSource = hooksSourceWeakMap.get(hook.handler) ?? "unknown"; - context.context.logger.error(`An error occurred during ${hookSource} hook matcher execution:`, error2); - throw new APIError("INTERNAL_SERVER_ERROR", { message: `An error occurred during hook matcher execution. Check the logs for more details.` }); - } - if (matched) { - const result = await hook.handler({ - ...context, - returnHeaders: false - }).catch((e) => { - if (e instanceof APIError && shouldPublishLog(context.context.logger.level, "debug")) e.stack = e.errorStack; - throw e; - }); - if (result && typeof result === "object") { - if ("context" in result && typeof result.context === "object") { - const { headers, ...rest } = result.context; - if (headers instanceof Headers) if (modifiedContext.headers) headers.forEach((value, key) => { - modifiedContext.headers?.set(key, value); - }); - else modifiedContext.headers = headers; - modifiedContext = defuReplaceArrays(rest, modifiedContext); - continue; - } - return result; - } - } - } - return { context: modifiedContext }; -} -async function runAfterHooks(context, hooks) { - for (const hook of hooks) if (hook.matcher(context)) { - const result = await hook.handler(context).catch((e) => { - if (e instanceof APIError) { - if (shouldPublishLog(context.context.logger.level, "debug")) e.stack = e.errorStack; - return { - response: e, - headers: e.headers ? new Headers(e.headers) : null - }; - } - throw e; - }); - if (result.headers) result.headers.forEach((value, key) => { - if (!context.context.responseHeaders) context.context.responseHeaders = new Headers({ [key]: value }); - else if (key.toLowerCase() === "set-cookie") context.context.responseHeaders.append(key, value); - else context.context.responseHeaders.set(key, value); - }); - if (result.response) context.context.returned = result.response; - } - return { - response: context.context.returned, - headers: context.context.responseHeaders - }; -} -function getHooks(authContext) { - const plugins = authContext.options.plugins || []; - const beforeHooks = []; - const afterHooks = []; - const beforeHookHandler = authContext.options.hooks?.before; - if (beforeHookHandler) { - hooksSourceWeakMap.set(beforeHookHandler, "user"); - beforeHooks.push({ - matcher: () => true, - handler: beforeHookHandler - }); - } - const afterHookHandler = authContext.options.hooks?.after; - if (afterHookHandler) { - hooksSourceWeakMap.set(afterHookHandler, "user"); - afterHooks.push({ - matcher: () => true, - handler: afterHookHandler - }); - } - const pluginBeforeHooks = plugins.filter((plugin) => plugin.hooks?.before).map((plugin) => plugin.hooks?.before).flat(); - const pluginAfterHooks = plugins.filter((plugin) => plugin.hooks?.after).map((plugin) => plugin.hooks?.after).flat(); - if (pluginBeforeHooks.length) beforeHooks.push(...pluginBeforeHooks); - if (pluginAfterHooks.length) afterHooks.push(...pluginAfterHooks); - return { - beforeHooks, - afterHooks - }; -} -function checkEndpointConflicts(options, logger$1) { - const endpointRegistry = /* @__PURE__ */ new Map(); - options.plugins?.forEach((plugin) => { - if (plugin.endpoints) { - for (const [key, endpoint] of Object.entries(plugin.endpoints)) if (endpoint && "path" in endpoint && typeof endpoint.path === "string") { - const path = endpoint.path; - let methods = []; - if (endpoint.options && "method" in endpoint.options) { - if (Array.isArray(endpoint.options.method)) methods = endpoint.options.method; - else if (typeof endpoint.options.method === "string") methods = [endpoint.options.method]; - } - if (methods.length === 0) methods = ["*"]; - if (!endpointRegistry.has(path)) endpointRegistry.set(path, []); - endpointRegistry.get(path).push({ - pluginId: plugin.id, - endpointKey: key, - methods - }); - } - } - }); - const conflicts = []; - for (const [path, entries] of endpointRegistry.entries()) if (entries.length > 1) { - const methodMap = /* @__PURE__ */ new Map(); - let hasConflict = false; - for (const entry of entries) for (const method of entry.methods) { - if (!methodMap.has(method)) methodMap.set(method, []); - methodMap.get(method).push(entry.pluginId); - if (methodMap.get(method).length > 1) hasConflict = true; - if (method === "*" && entries.length > 1) hasConflict = true; - else if (method !== "*" && methodMap.has("*")) hasConflict = true; - } - if (hasConflict) { - const uniquePlugins = [...new Set(entries.map((e) => e.pluginId))]; - const conflictingMethods = []; - for (const [method, plugins] of methodMap.entries()) if (plugins.length > 1 || method === "*" && entries.length > 1 || method !== "*" && methodMap.has("*")) conflictingMethods.push(method); - conflicts.push({ - path, - plugins: uniquePlugins, - conflictingMethods - }); - } - } - if (conflicts.length > 0) { - const conflictMessages = conflicts.map((conflict) => ` - "${conflict.path}" [${conflict.conflictingMethods.join(", ")}] used by plugins: ${conflict.plugins.join(", ")}`).join("\n"); - logger$1.error(`Endpoint path conflicts detected! Multiple plugins are trying to use the same endpoint paths with conflicting HTTP methods: -${conflictMessages} - -To resolve this, you can: - 1. Use only one of the conflicting plugins - 2. Configure the plugins to use different paths (if supported) - 3. Ensure plugins use different HTTP methods for the same path -`); - } -} -function getEndpoints(ctx, options) { - const pluginEndpoints = options.plugins?.reduce((acc, plugin) => { - return { - ...acc, - ...plugin.endpoints - }; - }, {}) ?? {}; - const middlewares = options.plugins?.map((plugin) => plugin.middlewares?.map((m) => { - const middleware = (async (context) => { - const authContext = await ctx; - return m.middleware({ - ...context, - context: { - ...authContext, - ...context.context - } - }); - }); - middleware.options = m.middleware.options; - return { - path: m.path, - middleware - }; - })).filter((plugin) => plugin !== void 0).flat() || []; - return { - api: toAuthEndpoints({ - signInSocial: signInSocial(), - callbackOAuth, - getSession: getSession(), - signOut, - signUpEmail: signUpEmail(), - signInEmail: signInEmail(), - resetPassword, - verifyPassword, - verifyEmail, - sendVerificationEmail, - changeEmail, - changePassword, - setPassword, - updateUser: updateUser(), - deleteUser, - requestPasswordReset, - requestPasswordResetCallback, - listSessions: listSessions(), - revokeSession, - revokeSessions, - revokeOtherSessions, - linkSocialAccount, - listUserAccounts, - deleteUserCallback, - unlinkAccount, - refreshToken, - getAccessToken, - accountInfo, - ...pluginEndpoints, - ok, - error - }, ctx), - middlewares - }; -} -const router = (ctx, options) => { - const { api, middlewares } = getEndpoints(ctx, options); - const basePath = new URL(ctx.baseURL).pathname; - return createRouter(api, { - routerContext: ctx, - openapi: { disabled: true }, - basePath, - routerMiddleware: [{ - path: "/**", - middleware: originCheckMiddleware - }, ...middlewares], - allowedMediaTypes: ["application/json"], - skipTrailingSlashes: options.advanced?.skipTrailingSlashes ?? false, - async onRequest(req) { - const disabledPaths = ctx.options.disabledPaths || []; - const normalizedPath = normalizePathname(req.url, basePath); - if (disabledPaths.includes(normalizedPath)) return new Response("Not Found", { status: 404 }); - let currentRequest = req; - for (const plugin of ctx.options.plugins || []) if (plugin.onRequest) { - const response = await plugin.onRequest(currentRequest, ctx); - if (response && "response" in response) return response.response; - if (response && "request" in response) currentRequest = response.request; - } - const rateLimitResponse2 = await onRequestRateLimit(currentRequest, ctx); - if (rateLimitResponse2) return rateLimitResponse2; - return currentRequest; - }, - async onResponse(res) { - for (const plugin of ctx.options.plugins || []) if (plugin.onResponse) { - const response = await plugin.onResponse(res, ctx); - if (response) return response.response; - } - return res; - }, - onError(e) { - if (e instanceof APIError && e.status === "FOUND") return; - if (options.onAPIError?.throw) throw e; - if (options.onAPIError?.onError) { - options.onAPIError.onError(e, ctx); - return; - } - const optLogLevel = options.logger?.level; - const log = optLogLevel === "error" || optLogLevel === "warn" || optLogLevel === "debug" ? logger : void 0; - if (options.logger?.disabled !== true) { - if (e && typeof e === "object" && "message" in e && typeof e.message === "string") { - if (e.message.includes("no column") || e.message.includes("column") || e.message.includes("relation") || e.message.includes("table") || e.message.includes("does not exist")) { - ctx.logger?.error(e.message); - return; - } - } - if (e instanceof APIError) { - if (e.status === "INTERNAL_SERVER_ERROR") ctx.logger.error(e.status, e); - log?.error(e.message); - } else ctx.logger?.error(e && typeof e === "object" && "name" in e ? e.name : "", e); - } - } - }); -}; -async function runPluginInit(ctx) { - let options = ctx.options; - const plugins = options.plugins || []; - let context = ctx; - const dbHooks = []; - for (const plugin of plugins) if (plugin.init) { - const initPromise = plugin.init(context); - let result; - if (isPromise(initPromise)) result = await initPromise; - else result = initPromise; - if (typeof result === "object") { - if (result.options) { - const { databaseHooks, ...restOpts } = result.options; - if (databaseHooks) dbHooks.push(databaseHooks); - options = defu(options, restOpts); - } - if (result.context) context = { - ...context, - ...result.context - }; - } - } - dbHooks.push(options.databaseHooks); - context.internalAdapter = createInternalAdapter(context.adapter, { - options, - logger: context.logger, - hooks: dbHooks.filter((u) => u !== void 0), - generateId: context.generateId - }); - context.options = options; - return { context }; -} -function getInternalPlugins(options) { - const plugins = []; - if (options.advanced?.crossSubDomainCookies?.enabled) ; - return plugins; -} -async function getTrustedOrigins(options, request) { - const baseURL = getBaseURL(options.baseURL, options.basePath, request); - const trustedOrigins = baseURL ? [new URL(baseURL).origin] : []; - if (options.trustedOrigins) { - if (Array.isArray(options.trustedOrigins)) trustedOrigins.push(...options.trustedOrigins); - if (typeof options.trustedOrigins === "function") { - const validOrigins = await options.trustedOrigins(request); - trustedOrigins.push(...validOrigins); - } - } - const envTrustedOrigins = env.BETTER_AUTH_TRUSTED_ORIGINS; - if (envTrustedOrigins) trustedOrigins.push(...envTrustedOrigins.split(",")); - return trustedOrigins.filter((v) => Boolean(v)); -} -const createBetterAuth = (options, initFn) => { - const authContext = initFn(options); - const { api } = getEndpoints(authContext, options); - return { - handler: async (request) => { - const ctx = await authContext; - const basePath = ctx.options.basePath || "/api/auth"; - if (!ctx.options.baseURL) { - const baseURL = getBaseURL(void 0, basePath, request, void 0, ctx.options.advanced?.trustedProxyHeaders); - if (baseURL) { - ctx.baseURL = baseURL; - ctx.options.baseURL = getOrigin(ctx.baseURL) || void 0; - } else throw new BetterAuthError("Could not get base URL from request. Please provide a valid base URL."); - } - ctx.trustedOrigins = await getTrustedOrigins(ctx.options, request); - const { handler } = router(ctx, options); - return runWithAdapter(ctx.adapter, () => handler(request)); - }, - api, - options, - $context: authContext, - $ERROR_CODES: { - ...options.plugins?.reduce((acc, plugin) => { - if (plugin.$ERROR_CODES) return { - ...acc, - ...plugin.$ERROR_CODES - }; - return acc; - }, {}), - ...BASE_ERROR_CODES - } - }; -}; -const DEFAULT_SECRET = "better-auth-secret-12345678901234567890"; -function estimateEntropy(str) { - const unique = new Set(str).size; - if (unique === 0) return 0; - return Math.log2(Math.pow(unique, str.length)); -} -function validateSecret(secret, logger$1) { - const isDefaultSecret = secret === DEFAULT_SECRET; - if (isTest()) return; - if (isDefaultSecret && isProduction) throw new BetterAuthError("You are using the default secret. Please set `BETTER_AUTH_SECRET` in your environment variables or pass `secret` in your auth config."); - if (secret.length < 32) logger$1.warn(`[better-auth] Warning: your BETTER_AUTH_SECRET should be at least 32 characters long for adequate security. Generate one with \`npx @better-auth/cli secret\` or \`openssl rand -base64 32\`.`); - if (estimateEntropy(secret) < 120) logger$1.warn("[better-auth] Warning: your BETTER_AUTH_SECRET appears low-entropy. Use a randomly generated secret for production."); -} -async function createAuthContext(adapter, options, getDatabaseType) { - if (!options.database) options = defu$1(options, { - session: { cookieCache: { - enabled: true, - strategy: "jwe", - refreshCache: true - } }, - account: { - storeStateStrategy: "cookie", - storeAccountCookie: true - } - }); - const plugins = options.plugins || []; - const internalPlugins = getInternalPlugins(options); - const logger$1 = createLogger(options.logger); - const baseURL = getBaseURL(options.baseURL, options.basePath); - if (!baseURL) logger$1.warn(`[better-auth] Base URL could not be determined. Please set a valid base URL using the baseURL config option or the BETTER_AUTH_URL environment variable. Without this, callbacks and redirects may not work correctly.`); - if (adapter.id === "memory" && options.advanced?.database?.generateId === false) logger$1.error(`[better-auth] Misconfiguration detected. -You are using the memory DB with generateId: false. -This will cause no id to be generated for any model. -Most of the features of Better Auth will not work correctly.`); - const secret = options.secret || env.BETTER_AUTH_SECRET || env.AUTH_SECRET || DEFAULT_SECRET; - validateSecret(secret, logger$1); - options = { - ...options, - secret, - baseURL: baseURL ? new URL(baseURL).origin : "", - basePath: options.basePath || "/api/auth", - plugins: plugins.concat(internalPlugins) - }; - checkEndpointConflicts(options, logger$1); - const cookies = getCookies(options); - const tables = getAuthTables(options); - const providers = Object.entries(options.socialProviders || {}).map(([key, config2]) => { - if (config2 == null) return null; - if (config2.enabled === false) return null; - if (!config2.clientId) logger$1.warn(`Social provider ${key} is missing clientId or clientSecret`); - const provider = socialProviders[key](config2); - provider.disableImplicitSignUp = config2.disableImplicitSignUp; - return provider; - }).filter((x) => x !== null); - const generateIdFunc = ({ model, size }) => { - if (typeof options.advanced?.generateId === "function") return options.advanced.generateId({ - model, - size - }); - const dbGenerateId = options?.advanced?.database?.generateId; - if (typeof dbGenerateId === "function") return dbGenerateId({ - model, - size - }); - if (dbGenerateId === "uuid") return crypto.randomUUID(); - if (dbGenerateId === "serial" || dbGenerateId === false) return false; - return generateId(size); - }; - const { publish } = await createTelemetry(options, { - adapter: adapter.id, - database: typeof options.database === "function" ? "adapter" : getDatabaseType(options.database) - }); - const trustedOrigins = await getTrustedOrigins(options); - const initOrPromise = runPluginInit({ - appName: options.appName || "Better Auth", - baseURL: baseURL || "", - version: getBetterAuthVersion(), - socialProviders: providers, - options, - oauthConfig: { - storeStateStrategy: options.account?.storeStateStrategy || (options.database ? "database" : "cookie"), - skipStateCookieCheck: !!options.account?.skipStateCookieCheck - }, - tables, - trustedOrigins, - isTrustedOrigin(url, settings) { - return this.trustedOrigins.some((origin) => matchesOriginPattern(url, origin, settings)); - }, - sessionConfig: { - updateAge: options.session?.updateAge !== void 0 ? options.session.updateAge : 1440 * 60, - expiresIn: options.session?.expiresIn || 3600 * 24 * 7, - freshAge: options.session?.freshAge === void 0 ? 3600 * 24 : options.session.freshAge, - cookieRefreshCache: (() => { - const refreshCache = options.session?.cookieCache?.refreshCache; - const maxAge = options.session?.cookieCache?.maxAge || 300; - if ((!!options.database || !!options.secondaryStorage) && refreshCache) { - logger$1.warn("[better-auth] `session.cookieCache.refreshCache` is enabled while `database` or `secondaryStorage` is configured. `refreshCache` is meant for stateless (DB-less) setups. Disabling `refreshCache` — remove it from your config to silence this warning."); - return false; - } - if (refreshCache === false || refreshCache === void 0) return false; - if (refreshCache === true) return { - enabled: true, - updateAge: Math.floor(maxAge * 0.2) - }; - return { - enabled: true, - updateAge: refreshCache.updateAge !== void 0 ? refreshCache.updateAge : Math.floor(maxAge * 0.2) - }; - })() - }, - secret, - rateLimit: { - ...options.rateLimit, - enabled: options.rateLimit?.enabled ?? isProduction, - window: options.rateLimit?.window || 10, - max: options.rateLimit?.max || 100, - storage: options.rateLimit?.storage || (options.secondaryStorage ? "secondary-storage" : "memory") - }, - authCookies: cookies, - logger: logger$1, - generateId: generateIdFunc, - session: null, - secondaryStorage: options.secondaryStorage, - password: { - hash: options.emailAndPassword?.password?.hash || hashPassword, - verify: options.emailAndPassword?.password?.verify || verifyPassword$1, - config: { - minPasswordLength: options.emailAndPassword?.minPasswordLength || 8, - maxPasswordLength: options.emailAndPassword?.maxPasswordLength || 128 - }, - checkPassword - }, - setNewSession(session) { - this.newSession = session; - }, - newSession: null, - adapter, - internalAdapter: createInternalAdapter(adapter, { - options, - logger: logger$1, - hooks: options.databaseHooks ? [options.databaseHooks] : [], - generateId: generateIdFunc - }), - createAuthCookie: createCookieGetter(options), - async runMigrations() { - throw new BetterAuthError("runMigrations will be set by the specific init implementation"); - }, - publishTelemetry: publish, - skipCSRFCheck: !!options.advanced?.disableCSRFCheck, - skipOriginCheck: options.advanced?.disableOriginCheck !== void 0 ? options.advanced.disableOriginCheck : isTest() ? true : false, - runInBackground: options.advanced?.backgroundTasks?.handler ?? ((p) => { - p.catch(() => { - }); - }), - async runInBackgroundOrAwait(promise) { - try { - if (options.advanced?.backgroundTasks?.handler) { - if (promise instanceof Promise) options.advanced.backgroundTasks.handler(promise.catch((e) => { - logger$1.error("Failed to run background task:", e); - })); - } else await promise; - } catch (e) { - logger$1.error("Failed to run background task:", e); - } - }, - getPlugin: (id) => options.plugins.find((p) => p.id === id) ?? null - }); - let context; - if (isPromise(initOrPromise)) ({ context } = await initOrPromise); - else ({ context } = initOrPromise); - if (typeof context.options.emailVerification?.onEmailVerification === "function") context.options.emailVerification.onEmailVerification = deprecate(context.options.emailVerification.onEmailVerification, "Use `afterEmailVerification` instead. This will be removed in 1.5", context.logger); - return context; -} -const initMinimal = async (options) => { - const adapter = await getBaseAdapter(options, async () => { - throw new BetterAuthError("Direct database connection requires Kysely. Please use `better-auth` instead of `better-auth/minimal`, or provide an adapter (drizzleAdapter, prismaAdapter, etc.)"); - }); - const getDatabaseType = (_database) => "unknown"; - const ctx = await createAuthContext(adapter, options, getDatabaseType); - ctx.runMigrations = async function() { - throw new BetterAuthError("Migrations are not supported in 'better-auth/minimal'. Please use 'better-auth' for migration support."); - }; - return ctx; -}; -const betterAuth = (options) => { - return createBetterAuth(options, initMinimal); -}; -const drizzleAdapter = (db2, config2) => { - let lazyOptions = null; - const createCustomAdapter = (db$1) => ({ getFieldName, getDefaultFieldName, options }) => { - function getSchema2(model) { - const schema2 = config2.schema || db$1._.fullSchema; - if (!schema2) throw new BetterAuthError("Drizzle adapter failed to initialize. Schema not found. Please provide a schema object in the adapter options object."); - const schemaModel = schema2[model]; - if (!schemaModel) throw new BetterAuthError(`[# Drizzle Adapter]: The model "${model}" was not found in the schema object. Please pass the schema directly to the adapter options.`); - return schemaModel; - } - const withReturning = async (model, builder, data, where) => { - if (config2.provider !== "mysql") return (await builder.returning())[0]; - await builder.execute(); - const schemaModel = getSchema2(model); - const builderVal = builder.config?.values; - if (where?.length) { - const clause = convertWhereClause(where.map((w) => { - if (data[w.field] !== void 0) return { - ...w, - value: data[w.field] - }; - return w; - }), model); - return (await db$1.select().from(schemaModel).where(...clause))[0]; - } else if (builderVal && builderVal[0]?.id?.value) { - let tId = builderVal[0]?.id?.value; - if (!tId) tId = (await db$1.select({ id: sql$1`LAST_INSERT_ID()` }).from(schemaModel).orderBy(desc(schemaModel.id)).limit(1))[0].id; - return (await db$1.select().from(schemaModel).where(eq(schemaModel.id, tId)).limit(1).execute())[0]; - } else if (data.id) return (await db$1.select().from(schemaModel).where(eq(schemaModel.id, data.id)).limit(1).execute())[0]; - else { - if (!("id" in schemaModel)) throw new BetterAuthError(`The model "${model}" does not have an "id" field. Please use the "id" field as your primary key.`); - return (await db$1.select().from(schemaModel).orderBy(desc(schemaModel.id)).limit(1).execute())[0]; - } - }; - function convertWhereClause(where, model) { - const schemaModel = getSchema2(model); - if (!where) return []; - if (where.length === 1) { - const w = where[0]; - if (!w) return []; - const field = getFieldName({ - model, - field: w.field - }); - if (!schemaModel[field]) throw new BetterAuthError(`The field "${w.field}" does not exist in the schema for the model "${model}". Please update your schema.`); - if (w.operator === "in") { - if (!Array.isArray(w.value)) throw new BetterAuthError(`The value for the field "${w.field}" must be an array when using the "in" operator.`); - return [inArray(schemaModel[field], w.value)]; - } - if (w.operator === "not_in") { - if (!Array.isArray(w.value)) throw new BetterAuthError(`The value for the field "${w.field}" must be an array when using the "not_in" operator.`); - return [notInArray(schemaModel[field], w.value)]; - } - if (w.operator === "contains") return [like(schemaModel[field], `%${w.value}%`)]; - if (w.operator === "starts_with") return [like(schemaModel[field], `${w.value}%`)]; - if (w.operator === "ends_with") return [like(schemaModel[field], `%${w.value}`)]; - if (w.operator === "lt") return [lt(schemaModel[field], w.value)]; - if (w.operator === "lte") return [lte(schemaModel[field], w.value)]; - if (w.operator === "ne") return [ne(schemaModel[field], w.value)]; - if (w.operator === "gt") return [gt(schemaModel[field], w.value)]; - if (w.operator === "gte") return [gte(schemaModel[field], w.value)]; - return [eq(schemaModel[field], w.value)]; - } - const andGroup = where.filter((w) => w.connector === "AND" || !w.connector); - const orGroup = where.filter((w) => w.connector === "OR"); - const andClause = and(...andGroup.map((w) => { - const field = getFieldName({ - model, - field: w.field - }); - if (w.operator === "in") { - if (!Array.isArray(w.value)) throw new BetterAuthError(`The value for the field "${w.field}" must be an array when using the "in" operator.`); - return inArray(schemaModel[field], w.value); - } - if (w.operator === "not_in") { - if (!Array.isArray(w.value)) throw new BetterAuthError(`The value for the field "${w.field}" must be an array when using the "not_in" operator.`); - return notInArray(schemaModel[field], w.value); - } - if (w.operator === "contains") return like(schemaModel[field], `%${w.value}%`); - if (w.operator === "starts_with") return like(schemaModel[field], `${w.value}%`); - if (w.operator === "ends_with") return like(schemaModel[field], `%${w.value}`); - if (w.operator === "lt") return lt(schemaModel[field], w.value); - if (w.operator === "lte") return lte(schemaModel[field], w.value); - if (w.operator === "gt") return gt(schemaModel[field], w.value); - if (w.operator === "gte") return gte(schemaModel[field], w.value); - if (w.operator === "ne") return ne(schemaModel[field], w.value); - return eq(schemaModel[field], w.value); - })); - const orClause = or(...orGroup.map((w) => { - const field = getFieldName({ - model, - field: w.field - }); - if (w.operator === "in") { - if (!Array.isArray(w.value)) throw new BetterAuthError(`The value for the field "${w.field}" must be an array when using the "in" operator.`); - return inArray(schemaModel[field], w.value); - } - if (w.operator === "not_in") { - if (!Array.isArray(w.value)) throw new BetterAuthError(`The value for the field "${w.field}" must be an array when using the "not_in" operator.`); - return notInArray(schemaModel[field], w.value); - } - if (w.operator === "contains") return like(schemaModel[field], `%${w.value}%`); - if (w.operator === "starts_with") return like(schemaModel[field], `${w.value}%`); - if (w.operator === "ends_with") return like(schemaModel[field], `%${w.value}`); - if (w.operator === "lt") return lt(schemaModel[field], w.value); - if (w.operator === "lte") return lte(schemaModel[field], w.value); - if (w.operator === "gt") return gt(schemaModel[field], w.value); - if (w.operator === "gte") return gte(schemaModel[field], w.value); - if (w.operator === "ne") return ne(schemaModel[field], w.value); - return eq(schemaModel[field], w.value); - })); - const clause = []; - if (andGroup.length) clause.push(andClause); - if (orGroup.length) clause.push(orClause); - return clause; - } - function checkMissingFields(schema2, model, values) { - if (!schema2) throw new BetterAuthError("Drizzle adapter failed to initialize. Drizzle Schema not found. Please provide a schema object in the adapter options object."); - for (const key in values) if (!schema2[key]) throw new BetterAuthError(`The field "${key}" does not exist in the "${model}" Drizzle schema. Please update your drizzle schema or re-generate using "npx @better-auth/cli@latest generate".`); - } - return { - async create({ model, data: values }) { - const schemaModel = getSchema2(model); - checkMissingFields(schemaModel, model, values); - return await withReturning(model, db$1.insert(schemaModel).values(values), values); - }, - async findOne({ model, where, select, join }) { - const schemaModel = getSchema2(model); - const clause = convertWhereClause(where, model); - if (options.experimental?.joins) if (!db$1.query || !db$1.query[model]) { - logger.error(`[# Drizzle Adapter]: The model "${model}" was not found in the query object. Please update your Drizzle schema to include relations or re-generate using "npx @better-auth/cli@latest generate".`); - logger.info("Falling back to regular query"); - } else { - let includes; - const pluralJoinResults = []; - if (join) { - includes = {}; - const joinEntries = Object.entries(join); - for (const [model$1, joinAttr] of joinEntries) { - const limit = joinAttr.limit ?? options.advanced?.database?.defaultFindManyLimit ?? 100; - const isUnique = joinAttr.relation === "one-to-one"; - const pluralSuffix = isUnique || config2.usePlural ? "" : "s"; - includes[`${model$1}${pluralSuffix}`] = isUnique ? true : { limit }; - if (!isUnique) pluralJoinResults.push(`${model$1}${pluralSuffix}`); - } - } - const res$1 = await db$1.query[model].findFirst({ - where: clause[0], - columns: select?.length && select.length > 0 ? select.reduce((acc, field) => { - acc[getFieldName({ - model, - field - })] = true; - return acc; - }, {}) : void 0, - with: includes - }); - if (res$1) for (const pluralJoinResult of pluralJoinResults) { - const singularKey = !config2.usePlural ? pluralJoinResult.slice(0, -1) : pluralJoinResult; - res$1[singularKey] = res$1[pluralJoinResult]; - if (pluralJoinResult !== singularKey) delete res$1[pluralJoinResult]; - } - return res$1; - } - const res = await db$1.select(select?.length && select.length > 0 ? select.reduce((acc, field) => { - const fieldName = getFieldName({ - model, - field - }); - return { - ...acc, - [fieldName]: schemaModel[fieldName] - }; - }, {}) : void 0).from(schemaModel).where(...clause); - if (!res.length) return null; - return res[0]; - }, - async findMany({ model, where, sortBy, limit, select, offset, join }) { - const schemaModel = getSchema2(model); - const clause = where ? convertWhereClause(where, model) : []; - const sortFn = sortBy?.direction === "desc" ? desc : asc; - if (options.experimental?.joins) if (!db$1.query[model]) { - logger.error(`[# Drizzle Adapter]: The model "${model}" was not found in the query object. Please update your Drizzle schema to include relations or re-generate using "npx @better-auth/cli@latest generate".`); - logger.info("Falling back to regular query"); - } else { - let includes; - const pluralJoinResults = []; - if (join) { - includes = {}; - const joinEntries = Object.entries(join); - for (const [model$1, joinAttr] of joinEntries) { - const isUnique = joinAttr.relation === "one-to-one"; - const limit$1 = joinAttr.limit ?? options.advanced?.database?.defaultFindManyLimit ?? 100; - const pluralSuffix = isUnique || config2.usePlural ? "" : "s"; - includes[`${model$1}${pluralSuffix}`] = isUnique ? true : { limit: limit$1 }; - if (!isUnique) pluralJoinResults.push(`${model$1}${pluralSuffix}`); - } - } - let orderBy = void 0; - if (sortBy?.field) orderBy = [sortFn(schemaModel[getFieldName({ - model, - field: sortBy?.field - })])]; - const res = await db$1.query[model].findMany({ - where: clause[0], - with: includes, - columns: select?.length && select.length > 0 ? select.reduce((acc, field) => { - acc[getFieldName({ - model, - field - })] = true; - return acc; - }, {}) : void 0, - limit: limit ?? 100, - offset: offset ?? 0, - orderBy - }); - if (res) for (const item of res) for (const pluralJoinResult of pluralJoinResults) { - const singularKey = !config2.usePlural ? pluralJoinResult.slice(0, -1) : pluralJoinResult; - if (singularKey === pluralJoinResult) continue; - item[singularKey] = item[pluralJoinResult]; - delete item[pluralJoinResult]; - } - return res; - } - let builder = db$1.select(select?.length && select.length > 0 ? select.reduce((acc, field) => { - const fieldName = getFieldName({ - model, - field - }); - return { - ...acc, - [fieldName]: schemaModel[fieldName] - }; - }, {}) : void 0).from(schemaModel); - const effectiveLimit = limit; - const effectiveOffset = offset; - if (typeof effectiveLimit !== "undefined") builder = builder.limit(effectiveLimit); - if (typeof effectiveOffset !== "undefined") builder = builder.offset(effectiveOffset); - if (sortBy?.field) builder = builder.orderBy(sortFn(schemaModel[getFieldName({ - model, - field: sortBy?.field - })])); - return await builder.where(...clause); - }, - async count({ model, where }) { - const schemaModel = getSchema2(model); - const clause = where ? convertWhereClause(where, model) : []; - return (await db$1.select({ count: count() }).from(schemaModel).where(...clause))[0].count; - }, - async update({ model, where, update: values }) { - const schemaModel = getSchema2(model); - const clause = convertWhereClause(where, model); - return await withReturning(model, db$1.update(schemaModel).set(values).where(...clause), values, where); - }, - async updateMany({ model, where, update: values }) { - const schemaModel = getSchema2(model); - const clause = convertWhereClause(where, model); - return await db$1.update(schemaModel).set(values).where(...clause); - }, - async delete({ model, where }) { - const schemaModel = getSchema2(model); - const clause = convertWhereClause(where, model); - return await db$1.delete(schemaModel).where(...clause); - }, - async deleteMany({ model, where }) { - const schemaModel = getSchema2(model); - const clause = convertWhereClause(where, model); - const res = await db$1.delete(schemaModel).where(...clause); - let count$1 = 0; - if (res && "rowCount" in res) count$1 = res.rowCount; - else if (Array.isArray(res)) count$1 = res.length; - else if (res && ("affectedRows" in res || "rowsAffected" in res || "changes" in res)) count$1 = res.affectedRows ?? res.rowsAffected ?? res.changes; - if (typeof count$1 !== "number") logger.error("[Drizzle Adapter] The result of the deleteMany operation is not a number. This is likely a bug in the adapter. Please report this issue to the Better Auth team.", { - res, - model, - where - }); - return count$1; - }, - options: config2 - }; - }; - let adapterOptions = null; - adapterOptions = { - config: { - adapterId: "drizzle", - adapterName: "Drizzle Adapter", - usePlural: config2.usePlural ?? false, - debugLogs: config2.debugLogs ?? false, - supportsUUIDs: config2.provider === "pg" ? true : false, - supportsJSON: config2.provider === "pg" ? true : false, - supportsArrays: config2.provider === "pg" ? true : false, - transaction: config2.transaction ?? false ? (cb) => db2.transaction((tx) => { - return cb(createAdapterFactory({ - config: adapterOptions.config, - adapter: createCustomAdapter(tx) - })(lazyOptions)); - }) : false - }, - adapter: createCustomAdapter(db2) - }; - const adapter = createAdapterFactory(adapterOptions); - return (options) => { - lazyOptions = options; - return adapter(options); - }; -}; -const svelteKitHandler = async ({ auth: auth2, event, resolve, building }) => { - if (building) return resolve(event); - const { request, url } = event; - if (isAuthPath(url.toString(), auth2.options)) return auth2.handler(request); - return resolve(event); -}; -function isAuthPath(url, options) { - const _url = new URL(url); - const baseURL = new URL(`${options.baseURL || _url.origin}${options.basePath || "/api/auth"}`); - if (_url.origin !== baseURL.origin) return false; - if (!_url.pathname.startsWith(baseURL.pathname.endsWith("/") ? baseURL.pathname : `${baseURL.pathname}/`)) return false; - return true; -} -const sveltekitCookies = (getRequestEvent2) => { - return { - id: "sveltekit-cookies", - hooks: { after: [{ - matcher() { - return true; - }, - handler: createAuthMiddleware(async (ctx) => { - const returned = ctx.context.responseHeaders; - if ("_flag" in ctx && ctx._flag === "router") return; - if (returned instanceof Headers) { - const setCookies = returned?.get("set-cookie"); - if (!setCookies) return; - const event = getRequestEvent2(); - if (!event) return; - const parsed = parseSetCookieHeader(setCookies); - for (const [name, { value, ...ops }] of parsed) try { - event.cookies.set(name, decodeURIComponent(value), { - sameSite: ops.samesite, - path: ops.path || "/", - expires: ops.expires, - secure: ops.secure, - httpOnly: ops.httponly, - domain: ops.domain, - maxAge: ops["max-age"] - }); - } catch { - } - } - }) - }] } - }; -}; -defineErrorCodes({ - FAILED_TO_CREATE_USER: "Failed to create user", - USER_ALREADY_EXISTS: "User already exists.", - USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL: "User already exists. Use another email.", - YOU_CANNOT_BAN_YOURSELF: "You cannot ban yourself", - YOU_ARE_NOT_ALLOWED_TO_CHANGE_USERS_ROLE: "You are not allowed to change users role", - YOU_ARE_NOT_ALLOWED_TO_CREATE_USERS: "You are not allowed to create users", - YOU_ARE_NOT_ALLOWED_TO_LIST_USERS: "You are not allowed to list users", - YOU_ARE_NOT_ALLOWED_TO_LIST_USERS_SESSIONS: "You are not allowed to list users sessions", - YOU_ARE_NOT_ALLOWED_TO_BAN_USERS: "You are not allowed to ban users", - YOU_ARE_NOT_ALLOWED_TO_IMPERSONATE_USERS: "You are not allowed to impersonate users", - YOU_ARE_NOT_ALLOWED_TO_REVOKE_USERS_SESSIONS: "You are not allowed to revoke users sessions", - YOU_ARE_NOT_ALLOWED_TO_DELETE_USERS: "You are not allowed to delete users", - YOU_ARE_NOT_ALLOWED_TO_SET_USERS_PASSWORD: "You are not allowed to set users password", - BANNED_USER: "You have been banned from this application", - YOU_ARE_NOT_ALLOWED_TO_GET_USER: "You are not allowed to get user", - NO_DATA_TO_UPDATE: "No data to update", - YOU_ARE_NOT_ALLOWED_TO_UPDATE_USERS: "You are not allowed to update users", - YOU_CANNOT_REMOVE_YOURSELF: "You cannot remove yourself", - YOU_ARE_NOT_ALLOWED_TO_SET_NON_EXISTENT_VALUE: "You are not allowed to set a non-existent role value", - YOU_CANNOT_IMPERSONATE_ADMINS: "You cannot impersonate admins", - INVALID_ROLE_TYPE: "Invalid role type" -}); -createAuthMiddleware(async (ctx) => { - const session = await getSessionFromCtx(ctx); - if (!session) throw new APIError("UNAUTHORIZED"); - return { session }; -}); -z.object({ - userId: z.coerce.string().meta({ description: "The user id" }), - role: z.union([z.string().meta({ description: "The role to set. `admin` or `user` by default" }), z.array(z.string().meta({ description: "The roles to set. `admin` or `user` by default" }))]).meta({ description: "The role to set, this can be a string or an array of strings. Eg: `admin` or `[admin, user]`" }) -}); -z.object({ id: z.string().meta({ description: "The id of the User" }) }); -z.object({ - email: z.string().meta({ description: "The email of the user" }), - password: z.string().optional().meta({ description: "The password of the user. If not provided, the user will be created without a credential account (useful for magic link or social login only users)." }), - name: z.string().meta({ description: "The name of the user" }), - role: z.union([z.string().meta({ description: "The role of the user" }), z.array(z.string().meta({ description: "The roles of user" }))]).optional().meta({ description: `A string or array of strings representing the roles to apply to the new user. Eg: "user"` }), - data: z.record(z.string(), z.any()).optional().meta({ description: "Extra fields for the user. Including custom additional fields." }) -}); -z.object({ - userId: z.coerce.string().meta({ description: "The user id" }), - data: z.record(z.any(), z.any()).meta({ description: "The user data to update" }) -}); -z.object({ - searchValue: z.string().optional().meta({ description: 'The value to search for. Eg: "some name"' }), - searchField: z.enum(["email", "name"]).meta({ description: 'The field to search in, defaults to email. Can be `email` or `name`. Eg: "name"' }).optional(), - searchOperator: z.enum([ - "contains", - "starts_with", - "ends_with" - ]).meta({ description: 'The operator to use for the search. Can be `contains`, `starts_with` or `ends_with`. Eg: "contains"' }).optional(), - limit: z.string().meta({ description: "The number of users to return" }).or(z.number()).optional(), - offset: z.string().meta({ description: "The offset to start from" }).or(z.number()).optional(), - sortBy: z.string().meta({ description: "The field to sort by" }).optional(), - sortDirection: z.enum(["asc", "desc"]).meta({ description: "The direction to sort by" }).optional(), - filterField: z.string().meta({ description: "The field to filter by" }).optional(), - filterValue: z.string().meta({ description: "The value to filter by" }).or(z.number()).or(z.boolean()).optional(), - filterOperator: z.enum([ - "eq", - "ne", - "lt", - "lte", - "gt", - "gte", - "contains" - ]).meta({ description: "The operator to use for the filter" }).optional() -}); -z.object({ userId: z.coerce.string().meta({ description: "The user id" }) }); -z.object({ userId: z.coerce.string().meta({ description: "The user id" }) }); -z.object({ - userId: z.coerce.string().meta({ description: "The user id" }), - banReason: z.string().meta({ description: "The reason for the ban" }).optional(), - banExpiresIn: z.number().meta({ description: "The number of seconds until the ban expires" }).optional() -}); -z.object({ userId: z.coerce.string().meta({ description: "The user id" }) }); -z.object({ sessionToken: z.string().meta({ description: "The session token" }) }); -z.object({ userId: z.coerce.string().meta({ description: "The user id" }) }); -z.object({ userId: z.coerce.string().meta({ description: "The user id" }) }); -z.object({ - newPassword: z.string().nonempty("newPassword cannot be empty").meta({ description: "The new password" }), - userId: z.coerce.string().nonempty("userId cannot be empty").meta({ description: "The user id" }) -}); -z.object({ - userId: z.coerce.string().optional().meta({ description: `The user id. Eg: "user-id"` }), - role: z.string().optional().meta({ description: `The role to check permission for. Eg: "admin"` }) -}).and(z.union([z.object({ - permission: z.record(z.string(), z.array(z.string())), - permissions: z.undefined() -}), z.object({ - permission: z.undefined(), - permissions: z.record(z.string(), z.array(z.string())) -})])); -defineErrorCodes({ - INVALID_EMAIL_FORMAT: "Email was not generated in a valid format", - FAILED_TO_CREATE_USER: "Failed to create user", - COULD_NOT_CREATE_SESSION: "Could not create session", - ANONYMOUS_USERS_CANNOT_SIGN_IN_AGAIN_ANONYMOUSLY: "Anonymous users cannot sign in again anonymously", - FAILED_TO_DELETE_ANONYMOUS_USER: "Failed to delete anonymous user", - USER_IS_NOT_ANONYMOUS: "User is not anonymous", - DELETE_ANONYMOUS_USER_DISABLED: "Deleting anonymous users is disabled" -}); -z.object({ - key: z.string().meta({ description: "The key to verify" }), - permissions: z.record(z.string(), z.array(z.string())).meta({ description: "The permissions to verify." }).optional() -}); -z.object({ - name: z.string().meta({ description: "Name of the Api Key" }).optional(), - expiresIn: z.number().meta({ description: "Expiration time of the Api Key in seconds" }).min(1).optional().nullable().default(null), - userId: z.coerce.string().meta({ description: 'User Id of the user that the Api Key belongs to. server-only. Eg: "user-id"' }).optional(), - prefix: z.string().meta({ description: "Prefix of the Api Key" }).regex(/^[a-zA-Z0-9_-]+$/, { message: "Invalid prefix format, must be alphanumeric and contain only underscores and hyphens." }).optional(), - remaining: z.number().meta({ description: "Remaining number of requests. Server side only" }).min(0).optional().nullable().default(null), - metadata: z.any().optional(), - refillAmount: z.number().meta({ description: "Amount to refill the remaining count of the Api Key. server-only. Eg: 100" }).min(1).optional(), - refillInterval: z.number().meta({ description: "Interval to refill the Api Key in milliseconds. server-only. Eg: 1000" }).optional(), - rateLimitTimeWindow: z.number().meta({ description: "The duration in milliseconds where each request is counted. Once the `maxRequests` is reached, the request will be rejected until the `timeWindow` has passed, at which point the `timeWindow` will be reset. server-only. Eg: 1000" }).optional(), - rateLimitMax: z.number().meta({ description: "Maximum amount of requests allowed within a window. Once the `maxRequests` is reached, the request will be rejected until the `timeWindow` has passed, at which point the `timeWindow` will be reset. server-only. Eg: 100" }).optional(), - rateLimitEnabled: z.boolean().meta({ description: "Whether the key has rate limiting enabled. server-only. Eg: true" }).optional(), - permissions: z.record(z.string(), z.array(z.string())).meta({ description: "Permissions of the Api Key." }).optional() -}); -z.object({ keyId: z.string().meta({ description: "The id of the Api Key" }) }); -z.object({ id: z.string().meta({ description: "The id of the Api Key" }) }); -z.object({ - keyId: z.string().meta({ description: "The id of the Api Key" }), - userId: z.coerce.string().meta({ description: 'The id of the user which the api key belongs to. server-only. Eg: "some-user-id"' }).optional(), - name: z.string().meta({ description: "The name of the key" }).optional(), - enabled: z.boolean().meta({ description: "Whether the Api Key is enabled or not" }).optional(), - remaining: z.number().meta({ description: "The number of remaining requests" }).min(1).optional(), - refillAmount: z.number().meta({ description: "The refill amount" }).optional(), - refillInterval: z.number().meta({ description: "The refill interval" }).optional(), - metadata: z.any().optional(), - expiresIn: z.number().meta({ description: "Expiration time of the Api Key in seconds" }).min(1).optional().nullable(), - rateLimitEnabled: z.boolean().meta({ description: "Whether the key has rate limiting enabled." }).optional(), - rateLimitTimeWindow: z.number().meta({ description: "The duration in milliseconds where each request is counted. server-only. Eg: 1000" }).optional(), - rateLimitMax: z.number().meta({ description: "Maximum amount of requests allowed within a window. Once the `maxRequests` is reached, the request will be rejected until the `timeWindow` has passed, at which point the `timeWindow` will be reset. server-only. Eg: 100" }).optional(), - permissions: z.record(z.string(), z.array(z.string())).meta({ description: "Update the permissions on the API Key. server-only." }).optional().nullable() -}); -defineErrorCodes({ - INVALID_METADATA_TYPE: "metadata must be an object or undefined", - REFILL_AMOUNT_AND_INTERVAL_REQUIRED: "refillAmount is required when refillInterval is provided", - REFILL_INTERVAL_AND_AMOUNT_REQUIRED: "refillInterval is required when refillAmount is provided", - USER_BANNED: "User is banned", - UNAUTHORIZED_SESSION: "Unauthorized or invalid session", - KEY_NOT_FOUND: "API Key not found", - KEY_DISABLED: "API Key is disabled", - KEY_EXPIRED: "API Key has expired", - USAGE_EXCEEDED: "API Key has reached its usage limit", - KEY_NOT_RECOVERABLE: "API Key is not recoverable", - EXPIRES_IN_IS_TOO_SMALL: "The expiresIn is smaller than the predefined minimum value.", - EXPIRES_IN_IS_TOO_LARGE: "The expiresIn is larger than the predefined maximum value.", - INVALID_REMAINING: "The remaining count is either too large or too small.", - INVALID_PREFIX_LENGTH: "The prefix length is either too large or too small.", - INVALID_NAME_LENGTH: "The name length is either too large or too small.", - METADATA_DISABLED: "Metadata is disabled.", - RATE_LIMIT_EXCEEDED: "Rate limit exceeded.", - NO_VALUES_TO_UPDATE: "No values to update.", - KEY_DISABLED_EXPIRATION: "Custom key expiration values are disabled.", - INVALID_API_KEY: "Invalid API key.", - INVALID_USER_ID_FROM_API_KEY: "The user id from the API key is invalid.", - INVALID_API_KEY_GETTER_RETURN_TYPE: "API Key getter returned an invalid key type. Expected string.", - SERVER_ONLY_PROPERTY: "The property you're trying to set can only be set from the server auth instance only.", - FAILED_TO_UPDATE_API_KEY: "Failed to update API key", - NAME_REQUIRED: "API Key name is required." -}); -defineErrorCodes({ - VERIFICATION_FAILED: "Captcha verification failed", - MISSING_RESPONSE: "Missing CAPTCHA response", - UNKNOWN_ERROR: "Something went wrong" -}); -defineErrorCodes({ - MISSING_SECRET_KEY: "Missing secret key", - SERVICE_UNAVAILABLE: "CAPTCHA service unavailable" -}); -z.optional(z.object({ - disableCookieCache: z.boolean().meta({ description: "Disable cookie cache and fetch session from database" }).or(z.string().transform((v) => v === "true")).optional(), - disableRefresh: z.boolean().meta({ description: "Disable session refresh. Useful for checking session status, without updating the session" }).optional() -})); -const DEVICE_AUTHORIZATION_ERROR_CODES = defineErrorCodes({ - INVALID_DEVICE_CODE: "Invalid device code", - EXPIRED_DEVICE_CODE: "Device code has expired", - EXPIRED_USER_CODE: "User code has expired", - AUTHORIZATION_PENDING: "Authorization pending", - ACCESS_DENIED: "Access denied", - INVALID_USER_CODE: "Invalid user code", - DEVICE_CODE_ALREADY_PROCESSED: "Device code already processed", - POLLING_TOO_FREQUENTLY: "Polling too frequently", - USER_NOT_FOUND: "User not found", - FAILED_TO_CREATE_SESSION: "Failed to create session", - INVALID_DEVICE_CODE_STATUS: "Invalid device code status", - AUTHENTICATION_REQUIRED: "Authentication required" -}); -z.object({ - client_id: z.string().meta({ description: "The client ID of the application" }), - scope: z.string().meta({ description: "Space-separated list of scopes" }).optional() -}); -z.object({ - error: z.enum(["invalid_request", "invalid_client"]).meta({ description: "Error code" }), - error_description: z.string().meta({ description: "Detailed error description" }) -}); -z.object({ - grant_type: z.literal("urn:ietf:params:oauth:grant-type:device_code").meta({ description: "The grant type for device flow" }), - device_code: z.string().meta({ description: "The device verification code" }), - client_id: z.string().meta({ description: "The client ID of the application" }) -}); -z.object({ - error: z.enum([ - "authorization_pending", - "slow_down", - "expired_token", - "access_denied", - "invalid_request", - "invalid_grant" - ]).meta({ description: "Error code" }), - error_description: z.string().meta({ description: "Detailed error description" }) -}); -createAuthEndpoint("/device", { - method: "GET", - query: z.object({ user_code: z.string().meta({ description: "The user code to verify" }) }), - error: z.object({ - error: z.enum(["invalid_request"]).meta({ description: "Error code" }), - error_description: z.string().meta({ description: "Detailed error description" }) - }), - metadata: { openapi: { - description: "Verify user code and get device authorization status", - responses: { 200: { - description: "Device authorization status", - content: { "application/json": { schema: { - type: "object", - properties: { - user_code: { - type: "string", - description: "The user code to verify" - }, - status: { - type: "string", - enum: [ - "pending", - "approved", - "denied" - ], - description: "Current status of the device authorization" - } - } - } } } - } } - } } -}, async (ctx) => { - const { user_code } = ctx.query; - const cleanUserCode = user_code.replace(/-/g, ""); - const deviceCodeRecord = await ctx.context.adapter.findOne({ - model: "deviceCode", - where: [{ - field: "userCode", - value: cleanUserCode - }] - }); - if (!deviceCodeRecord) throw new APIError("BAD_REQUEST", { - error: "invalid_request", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.INVALID_USER_CODE - }); - if (deviceCodeRecord.expiresAt < /* @__PURE__ */ new Date()) throw new APIError("BAD_REQUEST", { - error: "expired_token", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.EXPIRED_USER_CODE - }); - return ctx.json({ - user_code, - status: deviceCodeRecord.status - }); -}); -createAuthEndpoint("/device/approve", { - method: "POST", - body: z.object({ userCode: z.string().meta({ description: "The user code to approve" }) }), - error: z.object({ - error: z.enum([ - "invalid_request", - "expired_token", - "device_code_already_processed", - "unauthorized", - "access_denied" - ]).meta({ description: "Error code" }), - error_description: z.string().meta({ description: "Detailed error description" }) - }), - requireHeaders: true, - metadata: { openapi: { - description: "Approve device authorization", - responses: { 200: { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { success: { type: "boolean" } } - } } } - } } - } } -}, async (ctx) => { - const session = await getSessionFromCtx(ctx); - if (!session) throw new APIError("UNAUTHORIZED", { - error: "unauthorized", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.AUTHENTICATION_REQUIRED - }); - const { userCode } = ctx.body; - const cleanUserCode = userCode.replace(/-/g, ""); - const deviceCodeRecord = await ctx.context.adapter.findOne({ - model: "deviceCode", - where: [{ - field: "userCode", - value: cleanUserCode - }] - }); - if (!deviceCodeRecord) throw new APIError("BAD_REQUEST", { - error: "invalid_request", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.INVALID_USER_CODE - }); - if (deviceCodeRecord.expiresAt < /* @__PURE__ */ new Date()) throw new APIError("BAD_REQUEST", { - error: "expired_token", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.EXPIRED_USER_CODE - }); - if (deviceCodeRecord.status !== "pending") throw new APIError("BAD_REQUEST", { - error: "invalid_request", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.DEVICE_CODE_ALREADY_PROCESSED - }); - if (deviceCodeRecord.userId && deviceCodeRecord.userId !== session.user.id) throw new APIError("FORBIDDEN", { - error: "access_denied", - error_description: "You are not authorized to approve this device authorization" - }); - await ctx.context.adapter.update({ - model: "deviceCode", - where: [{ - field: "id", - value: deviceCodeRecord.id - }], - update: { - status: "approved", - userId: session.user.id - } - }); - return ctx.json({ success: true }); -}); -createAuthEndpoint("/device/deny", { - method: "POST", - body: z.object({ userCode: z.string().meta({ description: "The user code to deny" }) }), - error: z.object({ - error: z.enum([ - "invalid_request", - "expired_token", - "unauthorized", - "access_denied" - ]).meta({ description: "Error code" }), - error_description: z.string().meta({ description: "Detailed error description" }) - }), - requireHeaders: true, - metadata: { openapi: { - description: "Deny device authorization", - responses: { 200: { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { success: { type: "boolean" } } - } } } - } } - } } -}, async (ctx) => { - const session = await getSessionFromCtx(ctx); - if (!session) throw new APIError("UNAUTHORIZED", { - error: "unauthorized", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.AUTHENTICATION_REQUIRED - }); - const { userCode } = ctx.body; - const cleanUserCode = userCode.replace(/-/g, ""); - const deviceCodeRecord = await ctx.context.adapter.findOne({ - model: "deviceCode", - where: [{ - field: "userCode", - value: cleanUserCode - }] - }); - if (!deviceCodeRecord) throw new APIError("BAD_REQUEST", { - error: "invalid_request", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.INVALID_USER_CODE - }); - if (deviceCodeRecord.expiresAt < /* @__PURE__ */ new Date()) throw new APIError("BAD_REQUEST", { - error: "expired_token", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.EXPIRED_USER_CODE - }); - if (deviceCodeRecord.status !== "pending") throw new APIError("BAD_REQUEST", { - error: "invalid_request", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.DEVICE_CODE_ALREADY_PROCESSED - }); - if (deviceCodeRecord.userId && deviceCodeRecord.userId !== session.user.id) throw new APIError("FORBIDDEN", { - error: "access_denied", - error_description: "You are not authorized to deny this device authorization" - }); - await ctx.context.adapter.update({ - model: "deviceCode", - where: [{ - field: "id", - value: deviceCodeRecord.id - }], - update: { - status: "denied", - userId: deviceCodeRecord.userId || session.user.id - } - }); - return ctx.json({ success: true }); -}); -z.object({ - id: z.string(), - deviceCode: z.string(), - userCode: z.string(), - userId: z.string().optional(), - expiresAt: z.date(), - status: z.string(), - lastPolledAt: z.date().optional(), - pollingInterval: z.number().optional(), - clientId: z.string().optional(), - scope: z.string().optional() -}); -const timeStringSchema = z.custom((val) => { - if (typeof val !== "string") return false; - try { - ms(val); - return true; - } catch { - return false; - } -}, { message: "Invalid time string format. Use formats like '30m', '5s', '1h', etc." }); -z.object({ - expiresIn: timeStringSchema.default("30m").describe("Time in seconds until the device code expires. Use formats like '30m', '5s', '1h', etc."), - interval: timeStringSchema.default("5s").describe("Time in seconds between polling attempts. Use formats like '30m', '5s', '1h', etc."), - deviceCodeLength: z.number().int().positive().default(40).describe("Length of the device code to be generated. Default is 40 characters."), - userCodeLength: z.number().int().positive().default(8).describe("Length of the user code to be generated. Default is 8 characters."), - generateDeviceCode: z.custom((val) => typeof val === "function", { message: "generateDeviceCode must be a function that returns a string or a promise that resolves to a string." }).optional().describe("Function to generate a device code. If not provided, a default random string generator will be used."), - generateUserCode: z.custom((val) => typeof val === "function", { message: "generateUserCode must be a function that returns a string or a promise that resolves to a string." }).optional().describe("Function to generate a user code. If not provided, a default random string generator will be used."), - validateClient: z.custom((val) => typeof val === "function", { message: "validateClient must be a function that returns a boolean or a promise that resolves to a boolean." }).optional().describe("Function to validate the client ID. If not provided, no validation will be performed."), - onDeviceAuthRequest: z.custom((val) => typeof val === "function", { message: "onDeviceAuthRequest must be a function that returns void or a promise that resolves to void." }).optional().describe("Function to handle device authorization requests. If not provided, no additional actions will be taken."), - verificationUri: z.string().optional().describe("The URI where users verify their device code. Can be an absolute URL (https://example.com/device) or relative path (/custom-path). This will be returned as verification_uri in the device code response. If not provided, defaults to /device."), - schema: z.custom(() => true) -}); -const types = [ - "email-verification", - "sign-in", - "forget-password" -]; -defineErrorCodes({ - OTP_EXPIRED: "OTP expired", - INVALID_OTP: "Invalid OTP", - TOO_MANY_ATTEMPTS: "Too many attempts" -}); -z.object({ - email: z.string({}).meta({ description: "Email address to send the OTP" }), - type: z.enum(types).meta({ description: "Type of the OTP" }) -}); -z.object({ - email: z.string({}).meta({ description: "Email address to send the OTP" }), - type: z.enum(types).meta({ - required: true, - description: "Type of the OTP" - }) -}); -z.object({ - email: z.string({}).meta({ description: "Email address the OTP was sent to" }), - type: z.enum(types).meta({ - required: true, - description: "Type of the OTP" - }) -}); -z.object({ - email: z.string().meta({ description: "Email address the OTP was sent to" }), - type: z.enum(types).meta({ - required: true, - description: "Type of the OTP" - }), - otp: z.string().meta({ - required: true, - description: "OTP to verify" - }) -}); -z.object({ - email: z.string({}).meta({ description: "Email address to verify" }), - otp: z.string().meta({ - required: true, - description: "OTP to verify" - }) -}); -z.object({ - email: z.string({}).meta({ description: "Email address to sign in" }), - otp: z.string().meta({ - required: true, - description: "OTP sent to the email" - }) -}); -z.object({ email: z.string().meta({ description: "Email address to send the OTP" }) }); -z.object({ email: z.string().meta({ description: "Email address to send the OTP" }) }); -z.object({ - email: z.string().meta({ description: "Email address to reset the password" }), - otp: z.string().meta({ description: "OTP sent to the email" }), - password: z.string().meta({ description: "New password" }) -}); -const GENERIC_OAUTH_ERROR_CODES = defineErrorCodes({ - INVALID_OAUTH_CONFIGURATION: "Invalid OAuth configuration", - TOKEN_URL_NOT_FOUND: "Invalid OAuth configuration. Token URL not found.", - PROVIDER_CONFIG_NOT_FOUND: "No config found for provider", - PROVIDER_ID_REQUIRED: "Provider ID is required", - INVALID_OAUTH_CONFIG: "Invalid OAuth configuration.", - SESSION_REQUIRED: "Session is required", - ISSUER_MISMATCH: "OAuth issuer mismatch. The authorization server issuer does not match the expected value (RFC 9207).", - ISSUER_MISSING: "OAuth issuer parameter missing. The authorization server did not include the required iss parameter (RFC 9207)." -}); -const signInWithOAuth2BodySchema = z.object({ - providerId: z.string().meta({ description: "The provider ID for the OAuth provider" }), - callbackURL: z.string().meta({ description: "The URL to redirect to after sign in" }).optional(), - errorCallbackURL: z.string().meta({ description: "The URL to redirect to if an error occurs" }).optional(), - newUserCallbackURL: z.string().meta({ description: 'The URL to redirect to after login if the user is new. Eg: "/welcome"' }).optional(), - disableRedirect: z.boolean().meta({ description: "Disable redirect" }).optional(), - scopes: z.array(z.string()).meta({ description: "Scopes to be passed to the provider authorization request." }).optional(), - requestSignUp: z.boolean().meta({ description: "Explicitly request sign-up. Useful when disableImplicitSignUp is true for this provider. Eg: false" }).optional(), - additionalData: z.record(z.string(), z.any()).optional() -}); -const signInWithOAuth2 = (options) => createAuthEndpoint("/sign-in/oauth2", { - method: "POST", - body: signInWithOAuth2BodySchema, - metadata: { openapi: { - description: "Sign in with OAuth2", - responses: { 200: { - description: "Sign in with OAuth2", - content: { "application/json": { schema: { - type: "object", - properties: { - url: { type: "string" }, - redirect: { type: "boolean" } - } - } } } - } } - } } -}, async (ctx) => { - const { providerId } = ctx.body; - const config2 = options.config.find((c) => c.providerId === providerId); - if (!config2) throw new APIError("BAD_REQUEST", { message: `${GENERIC_OAUTH_ERROR_CODES.PROVIDER_CONFIG_NOT_FOUND} ${providerId}` }); - const { discoveryUrl, authorizationUrl, tokenUrl, clientId, clientSecret, scopes, redirectURI, responseType, pkce, prompt, accessType, authorizationUrlParams, responseMode } = config2; - let finalAuthUrl = authorizationUrl; - let finalTokenUrl = tokenUrl; - if (discoveryUrl) { - const discovery = await betterFetch(discoveryUrl, { - method: "GET", - headers: config2.discoveryHeaders, - onError(context) { - ctx.context.logger.error(context.error.message, context.error, { discoveryUrl }); - } - }); - if (discovery.data) { - finalAuthUrl = discovery.data.authorization_endpoint; - finalTokenUrl = discovery.data.token_endpoint; - } - } - if (!finalAuthUrl || !finalTokenUrl) throw new APIError("BAD_REQUEST", { message: GENERIC_OAUTH_ERROR_CODES.INVALID_OAUTH_CONFIGURATION }); - if (authorizationUrlParams) { - const withAdditionalParams = new URL(finalAuthUrl); - for (const [paramName, paramValue] of Object.entries(authorizationUrlParams)) withAdditionalParams.searchParams.set(paramName, paramValue); - finalAuthUrl = withAdditionalParams.toString(); - } - const additionalParams = typeof authorizationUrlParams === "function" ? authorizationUrlParams(ctx) : authorizationUrlParams; - const { state, codeVerifier } = await generateState(ctx, void 0, ctx.body.additionalData); - const authUrl = await createAuthorizationURL({ - id: providerId, - options: { - clientId, - clientSecret, - redirectURI - }, - authorizationEndpoint: finalAuthUrl, - state, - codeVerifier: pkce ? codeVerifier : void 0, - scopes: ctx.body.scopes ? [...ctx.body.scopes, ...scopes || []] : scopes || [], - redirectURI: `${ctx.context.baseURL}/oauth2/callback/${providerId}`, - prompt, - accessType, - responseType, - responseMode, - additionalParams - }); - return ctx.json({ - url: authUrl.toString(), - redirect: !ctx.body.disableRedirect - }); -}); -const OAuth2CallbackQuerySchema = z.object({ - code: z.string().meta({ description: "The OAuth2 code" }).optional(), - error: z.string().meta({ description: "The error message, if any" }).optional(), - error_description: z.string().meta({ description: "The error description, if any" }).optional(), - state: z.string().meta({ description: "The state parameter from the OAuth2 request" }).optional(), - iss: z.string().meta({ description: "The issuer identifier" }).optional() -}); -const oAuth2Callback = (options) => createAuthEndpoint("/oauth2/callback/:providerId", { - method: "GET", - query: OAuth2CallbackQuerySchema, - metadata: { - ...HIDE_METADATA, - allowedMediaTypes: ["application/x-www-form-urlencoded", "application/json"], - openapi: { - description: "OAuth2 callback", - responses: { 200: { - description: "OAuth2 callback", - content: { "application/json": { schema: { - type: "object", - properties: { url: { type: "string" } } - } } } - } } - } - } -}, async (ctx) => { - const defaultErrorURL = ctx.context.options.onAPIError?.errorURL || `${ctx.context.baseURL}/error`; - if (ctx.query.error || !ctx.query.code) throw ctx.redirect(`${defaultErrorURL}?error=${ctx.query.error || "oAuth_code_missing"}&error_description=${ctx.query.error_description}`); - const providerId = ctx.params?.providerId; - if (!providerId) throw new APIError("BAD_REQUEST", { message: GENERIC_OAUTH_ERROR_CODES.PROVIDER_ID_REQUIRED }); - const providerConfig = options.config.find((p) => p.providerId === providerId); - if (!providerConfig) throw new APIError("BAD_REQUEST", { message: `${GENERIC_OAUTH_ERROR_CODES.PROVIDER_CONFIG_NOT_FOUND} ${providerId}` }); - let tokens = void 0; - const { callbackURL, codeVerifier, errorURL, requestSignUp, newUserURL, link } = await parseState(ctx); - const code = ctx.query.code; - function redirectOnError(error2) { - const defaultErrorURL$1 = ctx.context.options.onAPIError?.errorURL || `${ctx.context.baseURL}/error`; - let url = errorURL || defaultErrorURL$1; - if (url.includes("?")) url = `${url}&error=${error2}`; - else url = `${url}?error=${error2}`; - throw ctx.redirect(url); - } - let finalTokenUrl = providerConfig.tokenUrl; - let finalUserInfoUrl = providerConfig.userInfoUrl; - let expectedIssuer = providerConfig.issuer; - if (providerConfig.discoveryUrl) { - const discovery = await betterFetch(providerConfig.discoveryUrl, { - method: "GET", - headers: providerConfig.discoveryHeaders - }); - if (discovery.data) { - finalTokenUrl = discovery.data.token_endpoint; - finalUserInfoUrl = discovery.data.userinfo_endpoint; - if (!expectedIssuer && discovery.data.issuer) expectedIssuer = discovery.data.issuer; - } - } - if (expectedIssuer) { - if (ctx.query.iss) { - if (ctx.query.iss !== expectedIssuer) { - ctx.context.logger.error("OAuth issuer mismatch", { - expected: expectedIssuer, - received: ctx.query.iss - }); - return redirectOnError("issuer_mismatch"); - } - } else if (providerConfig.requireIssuerValidation) { - ctx.context.logger.error("OAuth issuer parameter missing", { expected: expectedIssuer }); - return redirectOnError("issuer_missing"); - } - } - try { - if (providerConfig.getToken) tokens = await providerConfig.getToken({ - code, - redirectURI: `${ctx.context.baseURL}/oauth2/callback/${providerConfig.providerId}`, - codeVerifier: providerConfig.pkce ? codeVerifier : void 0 - }); - else { - if (!finalTokenUrl) throw new APIError("BAD_REQUEST", { message: GENERIC_OAUTH_ERROR_CODES.INVALID_OAUTH_CONFIG }); - const additionalParams = typeof providerConfig.tokenUrlParams === "function" ? providerConfig.tokenUrlParams(ctx) : providerConfig.tokenUrlParams; - tokens = await validateAuthorizationCode({ - headers: providerConfig.authorizationHeaders, - code, - codeVerifier: providerConfig.pkce ? codeVerifier : void 0, - redirectURI: `${ctx.context.baseURL}/oauth2/callback/${providerConfig.providerId}`, - options: { - clientId: providerConfig.clientId, - clientSecret: providerConfig.clientSecret, - redirectURI: providerConfig.redirectURI - }, - tokenEndpoint: finalTokenUrl, - authentication: providerConfig.authentication, - additionalParams - }); - } - } catch (e) { - ctx.context.logger.error(e && typeof e === "object" && "name" in e ? e.name : "", e); - throw redirectOnError("oauth_code_verification_failed"); - } - if (!tokens) throw new APIError("BAD_REQUEST", { message: GENERIC_OAUTH_ERROR_CODES.INVALID_OAUTH_CONFIG }); - const userInfo = await (async function handleUserInfo() { - const userInfo$1 = providerConfig.getUserInfo ? await providerConfig.getUserInfo(tokens) : await getUserInfo(tokens, finalUserInfoUrl); - if (!userInfo$1) throw redirectOnError("user_info_is_missing"); - const mapUser = providerConfig.mapProfileToUser ? await providerConfig.mapProfileToUser(userInfo$1) : userInfo$1; - const email = mapUser.email ? mapUser.email.toLowerCase() : userInfo$1.email?.toLowerCase(); - if (!email) { - ctx.context.logger.error("Unable to get user info", userInfo$1); - throw redirectOnError("email_is_missing"); - } - const id = mapUser.id ? String(mapUser.id) : String(userInfo$1.id); - const name = mapUser.name ? mapUser.name : userInfo$1.name; - if (!name) { - ctx.context.logger.error("Unable to get user info", userInfo$1); - throw redirectOnError("name_is_missing"); - } - return { - ...userInfo$1, - ...mapUser, - email, - id, - name - }; - })(); - if (link) { - if (ctx.context.options.account?.accountLinking?.allowDifferentEmails !== true && link.email.toLowerCase() !== userInfo.email.toLowerCase()) return redirectOnError("email_doesn't_match"); - const existingAccount = await ctx.context.internalAdapter.findAccountByProviderId(String(userInfo.id), providerConfig.providerId); - if (existingAccount) { - if (existingAccount.userId !== link.userId) return redirectOnError("account_already_linked_to_different_user"); - const updateData = Object.fromEntries(Object.entries({ - accessToken: await setTokenUtil(tokens.accessToken, ctx.context), - idToken: tokens.idToken, - refreshToken: await setTokenUtil(tokens.refreshToken, ctx.context), - accessTokenExpiresAt: tokens.accessTokenExpiresAt, - refreshTokenExpiresAt: tokens.refreshTokenExpiresAt, - scope: tokens.scopes?.join(",") - }).filter(([_, value]) => value !== void 0)); - await ctx.context.internalAdapter.updateAccount(existingAccount.id, updateData); - } else if (!await ctx.context.internalAdapter.createAccount({ - userId: link.userId, - providerId: providerConfig.providerId, - accountId: userInfo.id, - accessToken: await setTokenUtil(tokens.accessToken, ctx.context), - accessTokenExpiresAt: tokens.accessTokenExpiresAt, - refreshTokenExpiresAt: tokens.refreshTokenExpiresAt, - scope: tokens.scopes?.join(","), - refreshToken: await setTokenUtil(tokens.refreshToken, ctx.context), - idToken: tokens.idToken - })) return redirectOnError("unable_to_link_account"); - let toRedirectTo$1; - try { - toRedirectTo$1 = callbackURL.toString(); - } catch { - toRedirectTo$1 = callbackURL; - } - throw ctx.redirect(toRedirectTo$1); - } - const result = await handleOAuthUserInfo(ctx, { - userInfo, - account: { - providerId: providerConfig.providerId, - accountId: userInfo.id, - ...tokens, - scope: tokens.scopes?.join(",") - }, - callbackURL, - disableSignUp: providerConfig.disableImplicitSignUp && !requestSignUp || providerConfig.disableSignUp, - overrideUserInfo: providerConfig.overrideUserInfo - }); - if (result.error) return redirectOnError(result.error.split(" ").join("_")); - const { session, user } = result.data; - await setSessionCookie(ctx, { - session, - user - }); - let toRedirectTo; - try { - toRedirectTo = (result.isRegister ? newUserURL || callbackURL : callbackURL).toString(); - } catch { - toRedirectTo = result.isRegister ? newUserURL || callbackURL : callbackURL; - } - throw ctx.redirect(toRedirectTo); -}); -const OAuth2LinkAccountBodySchema = z.object({ - providerId: z.string(), - callbackURL: z.string(), - scopes: z.array(z.string()).meta({ description: "Additional scopes to request when linking the account" }).optional(), - errorCallbackURL: z.string().meta({ description: "The URL to redirect to if there is an error during the link process" }).optional() -}); -const oAuth2LinkAccount = (options) => createAuthEndpoint("/oauth2/link", { - method: "POST", - body: OAuth2LinkAccountBodySchema, - use: [sessionMiddleware], - metadata: { openapi: { - description: "Link an OAuth2 account to the current user session", - responses: { "200": { - description: "Authorization URL generated successfully for linking an OAuth2 account", - content: { "application/json": { schema: { - type: "object", - properties: { - url: { - type: "string", - format: "uri", - description: "The authorization URL to redirect the user to for linking the OAuth2 account" - }, - redirect: { - type: "boolean", - description: "Indicates that the client should redirect to the provided URL", - enum: [true] - } - }, - required: ["url", "redirect"] - } } } - } } - } } -}, async (c) => { - const session = c.context.session; - if (!session) throw new APIError("UNAUTHORIZED", { message: GENERIC_OAUTH_ERROR_CODES.SESSION_REQUIRED }); - const provider = options.config.find((p) => p.providerId === c.body.providerId); - if (!provider) throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.PROVIDER_NOT_FOUND }); - const { providerId, clientId, clientSecret, redirectURI, authorizationUrl, discoveryUrl, pkce, scopes, prompt, accessType, authorizationUrlParams } = provider; - let finalAuthUrl = authorizationUrl; - if (!finalAuthUrl) { - if (!discoveryUrl) throw new APIError("BAD_REQUEST", { message: GENERIC_OAUTH_ERROR_CODES.INVALID_OAUTH_CONFIGURATION }); - const discovery = await betterFetch(discoveryUrl, { - method: "GET", - headers: provider.discoveryHeaders, - onError(context) { - c.context.logger.error(context.error.message, context.error, { discoveryUrl }); - } - }); - if (discovery.data) finalAuthUrl = discovery.data.authorization_endpoint; - } - if (!finalAuthUrl) throw new APIError("BAD_REQUEST", { message: GENERIC_OAUTH_ERROR_CODES.INVALID_OAUTH_CONFIGURATION }); - const state = await generateState(c, { - userId: session.user.id, - email: session.user.email - }, void 0); - const additionalParams = typeof authorizationUrlParams === "function" ? authorizationUrlParams(c) : authorizationUrlParams; - const url = await createAuthorizationURL({ - id: providerId, - options: { - clientId, - clientSecret, - redirectURI: redirectURI || `${c.context.baseURL}/oauth2/callback/${providerId}` - }, - authorizationEndpoint: finalAuthUrl, - state: state.state, - codeVerifier: pkce ? state.codeVerifier : void 0, - scopes: c.body.scopes || scopes || [], - redirectURI: redirectURI || `${c.context.baseURL}/oauth2/callback/${providerId}`, - prompt, - accessType, - additionalParams - }); - return c.json({ - url: url.toString(), - redirect: true - }); -}); -async function getUserInfo(tokens, finalUserInfoUrl) { - if (tokens.idToken) { - const decoded = decodeJwt(tokens.idToken); - if (decoded) { - if (decoded.sub && decoded.email) return { - id: decoded.sub, - emailVerified: decoded.email_verified, - image: decoded.picture, - ...decoded - }; - } - } - if (!finalUserInfoUrl) return null; - const userInfo = await betterFetch(finalUserInfoUrl, { - method: "GET", - headers: { Authorization: `Bearer ${tokens.accessToken}` } - }); - return { - id: userInfo.data?.sub ?? "", - emailVerified: userInfo.data?.email_verified ?? false, - email: userInfo.data?.email, - image: userInfo.data?.picture, - name: userInfo.data?.name, - ...userInfo.data - }; -} -const genericOAuth = (options) => { - const seenIds = /* @__PURE__ */ new Set(); - const nonUniqueIds = /* @__PURE__ */ new Set(); - for (const config2 of options.config) { - const id = config2.providerId; - if (seenIds.has(id)) nonUniqueIds.add(id); - seenIds.add(id); - } - if (nonUniqueIds.size > 0) console.warn(`Duplicate provider IDs found: ${Array.from(nonUniqueIds).join(", ")}`); - return { - id: "generic-oauth", - init: (ctx) => { - return { context: { socialProviders: options.config.map((c) => { - let finalUserInfoUrl = c.userInfoUrl; - return { - id: c.providerId, - name: c.providerId, - async createAuthorizationURL(data) { - let finalAuthUrl = c.authorizationUrl; - if (!finalAuthUrl && c.discoveryUrl) { - const discovery = await betterFetch(c.discoveryUrl, { - method: "GET", - headers: c.discoveryHeaders - }); - if (discovery.data) { - finalAuthUrl = discovery.data.authorization_endpoint; - finalUserInfoUrl = finalUserInfoUrl ?? discovery.data.userinfo_endpoint; - } - } - if (!finalAuthUrl) throw new APIError("BAD_REQUEST", { message: GENERIC_OAUTH_ERROR_CODES.INVALID_OAUTH_CONFIGURATION }); - return createAuthorizationURL({ - id: c.providerId, - options: { - clientId: c.clientId, - clientSecret: c.clientSecret, - redirectURI: c.redirectURI - }, - authorizationEndpoint: finalAuthUrl, - state: data.state, - codeVerifier: c.pkce ? data.codeVerifier : void 0, - scopes: c.scopes || [], - redirectURI: `${ctx.baseURL}/oauth2/callback/${c.providerId}` - }); - }, - async validateAuthorizationCode(data) { - if (c.getToken) return c.getToken(data); - let finalTokenUrl = c.tokenUrl; - if (c.discoveryUrl) { - const discovery = await betterFetch(c.discoveryUrl, { - method: "GET", - headers: c.discoveryHeaders - }); - if (discovery.data) { - finalTokenUrl = discovery.data.token_endpoint; - finalUserInfoUrl = discovery.data.userinfo_endpoint; - } - } - if (!finalTokenUrl) throw new APIError("BAD_REQUEST", { message: GENERIC_OAUTH_ERROR_CODES.TOKEN_URL_NOT_FOUND }); - return validateAuthorizationCode({ - headers: c.authorizationHeaders, - code: data.code, - codeVerifier: data.codeVerifier, - redirectURI: data.redirectURI, - options: { - clientId: c.clientId, - clientSecret: c.clientSecret, - redirectURI: c.redirectURI - }, - tokenEndpoint: finalTokenUrl, - authentication: c.authentication - }); - }, - async refreshAccessToken(refreshToken2) { - let finalTokenUrl = c.tokenUrl; - if (c.discoveryUrl) { - const discovery = await betterFetch(c.discoveryUrl, { - method: "GET", - headers: c.discoveryHeaders - }); - if (discovery.data) finalTokenUrl = discovery.data.token_endpoint; - } - if (!finalTokenUrl) throw new APIError("BAD_REQUEST", { message: GENERIC_OAUTH_ERROR_CODES.TOKEN_URL_NOT_FOUND }); - return refreshAccessToken({ - refreshToken: refreshToken2, - options: { - clientId: c.clientId, - clientSecret: c.clientSecret - }, - authentication: c.authentication, - tokenEndpoint: finalTokenUrl - }); - }, - async getUserInfo(tokens) { - const userInfo = c.getUserInfo ? await c.getUserInfo(tokens) : await getUserInfo(tokens, finalUserInfoUrl); - if (!userInfo) return null; - const userMap = await c.mapProfileToUser?.(userInfo); - return { - user: { - id: userInfo?.id, - email: userInfo?.email, - emailVerified: userInfo?.emailVerified, - image: userInfo?.image, - name: userInfo?.name, - ...userMap - }, - data: userInfo - }; - }, - options: { overrideUserInfoOnSignIn: c.overrideUserInfo } - }; - }).concat(ctx.socialProviders) } }; - }, - endpoints: { - signInWithOAuth2: signInWithOAuth2(options), - oAuth2Callback: oAuth2Callback(options), - oAuth2LinkAccount: oAuth2LinkAccount(options) - }, - options, - $ERROR_CODES: GENERIC_OAUTH_ERROR_CODES - }; -}; -defineErrorCodes({ PASSWORD_COMPROMISED: "The password you entered has been compromised. Please choose a different password." }); -z.object({ - payload: z.record(z.string(), z.any()), - overrideOptions: z.record(z.string(), z.any()).optional() -}); -z.object({ - token: z.string(), - issuer: z.string().optional() -}); -z.object({ - email: z.email().meta({ description: "Email address to send the magic link" }), - name: z.string().meta({ description: 'User display name. Only used if the user is registering for the first time. Eg: "my-name"' }).optional(), - callbackURL: z.string().meta({ description: "URL to redirect after magic link verification" }).optional(), - newUserCallbackURL: z.string().meta({ description: "URL to redirect after new user signup. Only used if the user is registering for the first time." }).optional(), - errorCallbackURL: z.string().meta({ description: "URL to redirect after error." }).optional() -}); -z.object({ - token: z.string().meta({ description: "Verification token" }), - callbackURL: z.string().meta({ description: 'URL to redirect after magic link verification, if not provided the user will be redirected to the root URL. Eg: "/dashboard"' }).optional(), - errorCallbackURL: z.string().meta({ description: "URL to redirect after error." }).optional(), - newUserCallbackURL: z.string().meta({ description: "URL to redirect after new user signup. Only used if the user is registering for the first time." }).optional() -}); -z.object({ - clientId: z.string(), - clientSecret: z.string().optional(), - type: z.enum([ - "web", - "native", - "user-agent-based", - "public" - ]), - name: z.string(), - icon: z.string().optional(), - metadata: z.string().optional(), - disabled: z.boolean().optional().default(false), - redirectUrls: z.string(), - userId: z.string().optional(), - createdAt: z.date(), - updatedAt: z.date() -}); -z.object({ - accept: z.boolean(), - consent_code: z.string().optional().nullish() -}); -z.record(z.any(), z.any()); -z.object({ - redirect_uris: z.array(z.string()).meta({ description: 'A list of redirect URIs. Eg: ["https://client.example.com/callback"]' }), - token_endpoint_auth_method: z.enum([ - "none", - "client_secret_basic", - "client_secret_post" - ]).meta({ description: 'The authentication method for the token endpoint. Eg: "client_secret_basic"' }).default("client_secret_basic").optional(), - grant_types: z.array(z.enum([ - "authorization_code", - "implicit", - "password", - "client_credentials", - "refresh_token", - "urn:ietf:params:oauth:grant-type:jwt-bearer", - "urn:ietf:params:oauth:grant-type:saml2-bearer" - ])).meta({ description: 'The grant types supported by the application. Eg: ["authorization_code"]' }).default(["authorization_code"]).optional(), - response_types: z.array(z.enum(["code", "token"])).meta({ description: 'The response types supported by the application. Eg: ["code"]' }).default(["code"]).optional(), - client_name: z.string().meta({ description: 'The name of the application. Eg: "My App"' }).optional(), - client_uri: z.string().meta({ description: 'The URI of the application. Eg: "https://client.example.com"' }).optional(), - logo_uri: z.string().meta({ description: 'The URI of the application logo. Eg: "https://client.example.com/logo.png"' }).optional(), - scope: z.string().meta({ description: 'The scopes supported by the application. Separated by spaces. Eg: "profile email"' }).optional(), - contacts: z.array(z.string()).meta({ description: 'The contact information for the application. Eg: ["admin@example.com"]' }).optional(), - tos_uri: z.string().meta({ description: 'The URI of the application terms of service. Eg: "https://client.example.com/tos"' }).optional(), - policy_uri: z.string().meta({ description: 'The URI of the application privacy policy. Eg: "https://client.example.com/policy"' }).optional(), - jwks_uri: z.string().meta({ description: 'The URI of the application JWKS. Eg: "https://client.example.com/jwks"' }).optional(), - jwks: z.record(z.any(), z.any()).meta({ description: 'The JWKS of the application. Eg: {"keys": [{"kty": "RSA", "alg": "RS256", "use": "sig", "n": "...", "e": "..."}]}' }).optional(), - metadata: z.record(z.any(), z.any()).meta({ description: 'The metadata of the application. Eg: {"key": "value"}' }).optional(), - software_id: z.string().meta({ description: 'The software ID of the application. Eg: "my-software"' }).optional(), - software_version: z.string().meta({ description: 'The software version of the application. Eg: "1.0.0"' }).optional(), - software_statement: z.string().meta({ description: "The software statement of the application." }).optional() -}); -z.object({ - redirect_uris: z.array(z.string()), - token_endpoint_auth_method: z.enum([ - "none", - "client_secret_basic", - "client_secret_post" - ]).default("client_secret_basic").optional(), - grant_types: z.array(z.enum([ - "authorization_code", - "implicit", - "password", - "client_credentials", - "refresh_token", - "urn:ietf:params:oauth:grant-type:jwt-bearer", - "urn:ietf:params:oauth:grant-type:saml2-bearer" - ])).default(["authorization_code"]).optional(), - response_types: z.array(z.enum(["code", "token"])).default(["code"]).optional(), - client_name: z.string().optional(), - client_uri: z.string().optional(), - logo_uri: z.string().optional(), - scope: z.string().optional(), - contacts: z.array(z.string()).optional(), - tos_uri: z.string().optional(), - policy_uri: z.string().optional(), - jwks_uri: z.string().optional(), - jwks: z.record(z.string(), z.any()).optional(), - metadata: z.record(z.any(), z.any()).optional(), - software_id: z.string().optional(), - software_version: z.string().optional(), - software_statement: z.string().optional() -}); -z.record(z.any(), z.any()); -defineErrorCodes({ INVALID_SESSION_TOKEN: "Invalid session token" }); -z.object({ sessionToken: z.string().meta({ description: "The session token to set as active" }) }); -z.object({ sessionToken: z.string().meta({ description: "The session token to revoke" }) }); -z.object({ - callbackURL: z.string().meta({ description: "The URL to redirect to after the proxy" }), - cookies: z.string().meta({ description: "The cookies to set after the proxy" }) -}); -z.object({ idToken: z.string().meta({ description: "Google ID token, which the client obtains from the One Tap API" }) }); -z.object({ token: z.string().meta({ description: 'The token to verify. Eg: "some-token"' }) }); -createAuthMiddleware(async () => { - return {}; -}); -createAuthMiddleware({ use: [sessionMiddleware] }, async (ctx) => { - return { session: ctx.context.session }; -}); -defineErrorCodes({ - YOU_ARE_NOT_ALLOWED_TO_CREATE_A_NEW_ORGANIZATION: "You are not allowed to create a new organization", - YOU_HAVE_REACHED_THE_MAXIMUM_NUMBER_OF_ORGANIZATIONS: "You have reached the maximum number of organizations", - ORGANIZATION_ALREADY_EXISTS: "Organization already exists", - ORGANIZATION_SLUG_ALREADY_TAKEN: "Organization slug already taken", - ORGANIZATION_NOT_FOUND: "Organization not found", - USER_IS_NOT_A_MEMBER_OF_THE_ORGANIZATION: "User is not a member of the organization", - YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_ORGANIZATION: "You are not allowed to update this organization", - YOU_ARE_NOT_ALLOWED_TO_DELETE_THIS_ORGANIZATION: "You are not allowed to delete this organization", - NO_ACTIVE_ORGANIZATION: "No active organization", - USER_IS_ALREADY_A_MEMBER_OF_THIS_ORGANIZATION: "User is already a member of this organization", - MEMBER_NOT_FOUND: "Member not found", - ROLE_NOT_FOUND: "Role not found", - YOU_ARE_NOT_ALLOWED_TO_CREATE_A_NEW_TEAM: "You are not allowed to create a new team", - TEAM_ALREADY_EXISTS: "Team already exists", - TEAM_NOT_FOUND: "Team not found", - YOU_CANNOT_LEAVE_THE_ORGANIZATION_AS_THE_ONLY_OWNER: "You cannot leave the organization as the only owner", - YOU_CANNOT_LEAVE_THE_ORGANIZATION_WITHOUT_AN_OWNER: "You cannot leave the organization without an owner", - YOU_ARE_NOT_ALLOWED_TO_DELETE_THIS_MEMBER: "You are not allowed to delete this member", - YOU_ARE_NOT_ALLOWED_TO_INVITE_USERS_TO_THIS_ORGANIZATION: "You are not allowed to invite users to this organization", - USER_IS_ALREADY_INVITED_TO_THIS_ORGANIZATION: "User is already invited to this organization", - INVITATION_NOT_FOUND: "Invitation not found", - YOU_ARE_NOT_THE_RECIPIENT_OF_THE_INVITATION: "You are not the recipient of the invitation", - EMAIL_VERIFICATION_REQUIRED_BEFORE_ACCEPTING_OR_REJECTING_INVITATION: "Email verification required before accepting or rejecting invitation", - YOU_ARE_NOT_ALLOWED_TO_CANCEL_THIS_INVITATION: "You are not allowed to cancel this invitation", - INVITER_IS_NO_LONGER_A_MEMBER_OF_THE_ORGANIZATION: "Inviter is no longer a member of the organization", - YOU_ARE_NOT_ALLOWED_TO_INVITE_USER_WITH_THIS_ROLE: "You are not allowed to invite a user with this role", - FAILED_TO_RETRIEVE_INVITATION: "Failed to retrieve invitation", - YOU_HAVE_REACHED_THE_MAXIMUM_NUMBER_OF_TEAMS: "You have reached the maximum number of teams", - UNABLE_TO_REMOVE_LAST_TEAM: "Unable to remove last team", - YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_MEMBER: "You are not allowed to update this member", - ORGANIZATION_MEMBERSHIP_LIMIT_REACHED: "Organization membership limit reached", - YOU_ARE_NOT_ALLOWED_TO_CREATE_TEAMS_IN_THIS_ORGANIZATION: "You are not allowed to create teams in this organization", - YOU_ARE_NOT_ALLOWED_TO_DELETE_TEAMS_IN_THIS_ORGANIZATION: "You are not allowed to delete teams in this organization", - YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_TEAM: "You are not allowed to update this team", - YOU_ARE_NOT_ALLOWED_TO_DELETE_THIS_TEAM: "You are not allowed to delete this team", - INVITATION_LIMIT_REACHED: "Invitation limit reached", - TEAM_MEMBER_LIMIT_REACHED: "Team member limit reached", - USER_IS_NOT_A_MEMBER_OF_THE_TEAM: "User is not a member of the team", - YOU_CAN_NOT_ACCESS_THE_MEMBERS_OF_THIS_TEAM: "You are not allowed to list the members of this team", - YOU_DO_NOT_HAVE_AN_ACTIVE_TEAM: "You do not have an active team", - YOU_ARE_NOT_ALLOWED_TO_CREATE_A_NEW_TEAM_MEMBER: "You are not allowed to create a new member", - YOU_ARE_NOT_ALLOWED_TO_REMOVE_A_TEAM_MEMBER: "You are not allowed to remove a team member", - YOU_ARE_NOT_ALLOWED_TO_ACCESS_THIS_ORGANIZATION: "You are not allowed to access this organization as an owner", - YOU_ARE_NOT_A_MEMBER_OF_THIS_ORGANIZATION: "You are not a member of this organization", - MISSING_AC_INSTANCE: "Dynamic Access Control requires a pre-defined ac instance on the server auth plugin. Read server logs for more information", - YOU_MUST_BE_IN_AN_ORGANIZATION_TO_CREATE_A_ROLE: "You must be in an organization to create a role", - YOU_ARE_NOT_ALLOWED_TO_CREATE_A_ROLE: "You are not allowed to create a role", - YOU_ARE_NOT_ALLOWED_TO_UPDATE_A_ROLE: "You are not allowed to update a role", - YOU_ARE_NOT_ALLOWED_TO_DELETE_A_ROLE: "You are not allowed to delete a role", - YOU_ARE_NOT_ALLOWED_TO_READ_A_ROLE: "You are not allowed to read a role", - YOU_ARE_NOT_ALLOWED_TO_LIST_A_ROLE: "You are not allowed to list a role", - YOU_ARE_NOT_ALLOWED_TO_GET_A_ROLE: "You are not allowed to get a role", - TOO_MANY_ROLES: "This organization has too many roles", - INVALID_RESOURCE: "The provided permission includes an invalid resource", - ROLE_NAME_IS_ALREADY_TAKEN: "That role name is already taken", - CANNOT_DELETE_A_PRE_DEFINED_ROLE: "Cannot delete a pre-defined role", - ROLE_IS_ASSIGNED_TO_MEMBERS: "Cannot delete a role that is assigned to members. Please reassign the members to a different role first" -}); -z.object({ - organizationId: z.string().optional().meta({ description: "The id of the organization to create the role in. If not provided, the user's active organization will be used." }), - role: z.string().meta({ description: "The name of the role to create" }), - permission: z.record(z.string(), z.array(z.string())).meta({ description: "The permission to assign to the role" }) -}); -z.object({ organizationId: z.string().optional().meta({ description: "The id of the organization to create the role in. If not provided, the user's active organization will be used." }) }).and(z.union([z.object({ roleName: z.string().nonempty().meta({ description: "The name of the role to delete" }) }), z.object({ roleId: z.string().nonempty().meta({ description: "The id of the role to delete" }) })])); -z.object({ organizationId: z.string().optional().meta({ description: "The id of the organization to list roles for. If not provided, the user's active organization will be used." }) }).optional(); -z.object({ organizationId: z.string().optional().meta({ description: "The id of the organization to read a role for. If not provided, the user's active organization will be used." }) }).and(z.union([z.object({ roleName: z.string().nonempty().meta({ description: "The name of the role to read" }) }), z.object({ roleId: z.string().nonempty().meta({ description: "The id of the role to read" }) })])).optional(); -z.union([z.object({ roleName: z.string().nonempty().meta({ description: "The name of the role to update" }) }), z.object({ roleId: z.string().nonempty().meta({ description: "The id of the role to update" }) })]); -z.object({ - email: z.string().meta({ description: "The email address of the user to invite" }), - role: z.union([z.string().meta({ description: "The role to assign to the user" }), z.array(z.string().meta({ description: "The roles to assign to the user" }))]).meta({ description: 'The role(s) to assign to the user. It can be `admin`, `member`, owner. Eg: "member"' }), - organizationId: z.string().meta({ description: "The organization ID to invite the user to" }).optional(), - resend: z.boolean().meta({ description: "Resend the invitation email, if the user is already invited. Eg: true" }).optional(), - teamId: z.union([z.string().meta({ description: "The team ID to invite the user to" }).optional(), z.array(z.string()).meta({ description: "The team IDs to invite the user to" }).optional()]) -}); -z.object({ invitationId: z.string().meta({ description: "The ID of the invitation to accept" }) }); -z.object({ invitationId: z.string().meta({ description: "The ID of the invitation to reject" }) }); -z.object({ invitationId: z.string().meta({ description: "The ID of the invitation to cancel" }) }); -z.object({ id: z.string().meta({ description: "The ID of the invitation to get" }) }); -z.object({ organizationId: z.string().meta({ description: "The ID of the organization to list invitations for" }).optional() }).optional(); -z.object({ - userId: z.coerce.string().meta({ description: 'The user Id which represents the user to be added as a member. If `null` is provided, then it\'s expected to provide session headers. Eg: "user-id"' }), - role: z.union([z.string(), z.array(z.string())]).meta({ description: 'The role(s) to assign to the new member. Eg: ["admin", "sale"]' }), - organizationId: z.string().meta({ description: `An optional organization ID to pass. If not provided, will default to the user's active organization. Eg: "org-id"` }).optional(), - teamId: z.string().meta({ description: 'An optional team ID to add the member to. Eg: "team-id"' }).optional() -}); -z.object({ - memberIdOrEmail: z.string().meta({ description: "The ID or email of the member to remove" }), - organizationId: z.string().meta({ description: 'The ID of the organization to remove the member from. If not provided, the active organization will be used. Eg: "org-id"' }).optional() -}); -z.object({ - role: z.union([z.string(), z.array(z.string())]).meta({ description: 'The new role to be applied. This can be a string or array of strings representing the roles. Eg: ["admin", "sale"]' }), - memberId: z.string().meta({ description: 'The member id to apply the role update to. Eg: "member-id"' }), - organizationId: z.string().meta({ description: 'An optional organization ID which the member is a part of to apply the role update. If not provided, you must provide session headers to get the active organization. Eg: "organization-id"' }).optional() -}); -z.object({ organizationId: z.string().meta({ description: 'The organization Id for the member to leave. Eg: "organization-id"' }) }); -z.object({ - userId: z.string().meta({ description: "The user ID to get the role for. If not provided, will default to the current user's" }).optional(), - organizationId: z.string().meta({ description: `The organization ID to list members for. If not provided, will default to the user's active organization. Eg: "organization-id"` }).optional(), - organizationSlug: z.string().meta({ description: `The organization slug to list members for. If not provided, will default to the user's active organization. Eg: "organization-slug"` }).optional() -}).optional(); -z.object({ - name: z.string().min(1).meta({ description: "The name of the organization" }), - slug: z.string().min(1).meta({ description: "The slug of the organization" }), - userId: z.coerce.string().meta({ description: 'The user id of the organization creator. If not provided, the current user will be used. Should only be used by admins or when called by the server. server-only. Eg: "user-id"' }).optional(), - logo: z.string().meta({ description: "The logo of the organization" }).optional(), - metadata: z.record(z.string(), z.any()).meta({ description: "The metadata of the organization" }).optional(), - keepCurrentActiveOrganization: z.boolean().meta({ description: "Whether to keep the current active organization active after creating a new one. Eg: true" }).optional() -}); -z.object({ slug: z.string().meta({ description: 'The organization slug to check. Eg: "my-org"' }) }); -z.object({ - name: z.string().min(1).meta({ description: "The name of the organization" }).optional(), - slug: z.string().min(1).meta({ description: "The slug of the organization" }).optional(), - logo: z.string().meta({ description: "The logo of the organization" }).optional(), - metadata: z.record(z.string(), z.any()).meta({ description: "The metadata of the organization" }).optional() -}); -z.object({ organizationId: z.string().meta({ description: "The organization id to delete" }) }); -z.optional(z.object({ - organizationId: z.string().meta({ description: "The organization id to get" }).optional(), - organizationSlug: z.string().meta({ description: "The organization slug to get" }).optional(), - membersLimit: z.number().or(z.string().transform((val) => parseInt(val))).meta({ description: "The limit of members to get. By default, it uses the membershipLimit option which defaults to 100." }).optional() -})); -z.object({ - organizationId: z.string().meta({ description: 'The organization id to set as active. It can be null to unset the active organization. Eg: "org-id"' }).nullable().optional(), - organizationSlug: z.string().meta({ description: 'The organization slug to set as active. It can be null to unset the active organization if organizationId is not provided. Eg: "org-slug"' }).optional() -}); -const roleSchema = z.string(); -const invitationStatus = z.enum([ - "pending", - "accepted", - "rejected", - "canceled" -]).default("pending"); -z.object({ - id: z.string().default(generateId), - name: z.string(), - slug: z.string(), - logo: z.string().nullish().optional(), - metadata: z.record(z.string(), z.unknown()).or(z.string().transform((v) => JSON.parse(v))).optional(), - createdAt: z.date() -}); -z.object({ - id: z.string().default(generateId), - organizationId: z.string(), - userId: z.coerce.string(), - role: roleSchema, - createdAt: z.date().default(() => /* @__PURE__ */ new Date()) -}); -z.object({ - id: z.string().default(generateId), - organizationId: z.string(), - email: z.string(), - role: roleSchema, - status: invitationStatus, - teamId: z.string().nullish(), - inviterId: z.string(), - expiresAt: z.date(), - createdAt: z.date().default(() => /* @__PURE__ */ new Date()) -}); -z.object({ - id: z.string().default(generateId), - name: z.string().min(1), - organizationId: z.string(), - createdAt: z.date(), - updatedAt: z.date().optional() -}); -z.object({ - id: z.string().default(generateId), - teamId: z.string(), - userId: z.string(), - createdAt: z.date().default(() => /* @__PURE__ */ new Date()) -}); -z.object({ - id: z.string().default(generateId), - organizationId: z.string(), - role: z.string(), - permission: z.record(z.string(), z.array(z.string())), - createdAt: z.date().default(() => /* @__PURE__ */ new Date()), - updatedAt: z.date().optional() -}); -const defaultRoles = [ - "admin", - "member", - "owner" -]; -z.union([z.enum(defaultRoles), z.array(z.enum(defaultRoles))]); -z.object({ - name: z.string().meta({ description: 'The name of the team. Eg: "my-team"' }), - organizationId: z.string().meta({ description: 'The organization ID which the team will be created in. Defaults to the active organization. Eg: "organization-id"' }).optional() -}); -z.object({ - teamId: z.string().meta({ description: `The team ID of the team to remove. Eg: "team-id"` }), - organizationId: z.string().meta({ description: `The organization ID which the team falls under. If not provided, it will default to the user's active organization. Eg: "organization-id"` }).optional() -}); -z.optional(z.object({ organizationId: z.string().meta({ description: `The organization ID which the teams are under to list. Defaults to the users active organization. Eg: "organization-id"` }).optional() })); -z.object({ teamId: z.string().meta({ description: "The team id to set as active. It can be null to unset the active team" }).nullable().optional() }); -z.optional(z.object({ teamId: z.string().optional().meta({ description: "The team whose members we should return. If this is not provided the members of the current active team get returned." }) })); -z.object({ - teamId: z.string().meta({ description: "The team the user should be a member of." }), - userId: z.coerce.string().meta({ description: "The user Id which represents the user to be added as a member." }) -}); -z.object({ - teamId: z.string().meta({ description: "The team the user should be removed from." }), - userId: z.coerce.string().meta({ description: "The user which should be removed from the team." }) -}); -z.object({ organizationId: z.string().optional() }).and(z.union([z.object({ - permission: z.record(z.string(), z.array(z.string())), - permissions: z.undefined() -}), z.object({ - permission: z.undefined(), - permissions: z.record(z.string(), z.array(z.string())) -})])); -defineErrorCodes({ - INVALID_PHONE_NUMBER: "Invalid phone number", - PHONE_NUMBER_EXIST: "Phone number already exists", - PHONE_NUMBER_NOT_EXIST: "phone number isn't registered", - INVALID_PHONE_NUMBER_OR_PASSWORD: "Invalid phone number or password", - UNEXPECTED_ERROR: "Unexpected error", - OTP_NOT_FOUND: "OTP not found", - OTP_EXPIRED: "OTP expired", - INVALID_OTP: "Invalid OTP", - PHONE_NUMBER_NOT_VERIFIED: "Phone number not verified", - PHONE_NUMBER_CANNOT_BE_UPDATED: "Phone number cannot be updated", - SEND_OTP_NOT_IMPLEMENTED: "sendOTP not implemented", - TOO_MANY_ATTEMPTS: "Too many attempts" -}); -z.object({ - phoneNumber: z.string().meta({ description: 'Phone number to sign in. Eg: "+1234567890"' }), - password: z.string().meta({ description: "Password to use for sign in." }), - rememberMe: z.boolean().meta({ description: "Remember the session. Eg: true" }).optional() -}); -z.object({ phoneNumber: z.string().meta({ description: 'Phone number to send OTP. Eg: "+1234567890"' }) }); -z.object({ - phoneNumber: z.string().meta({ description: 'Phone number to verify. Eg: "+1234567890"' }), - code: z.string().meta({ description: 'OTP code. Eg: "123456"' }), - disableSession: z.boolean().meta({ description: "Disable session creation after verification. Eg: false" }).optional(), - updatePhoneNumber: z.boolean().meta({ description: "Check if there is a session and update the phone number. Eg: true" }).optional() -}).and(z.record(z.string(), z.any())); -z.object({ phoneNumber: z.string() }); -z.object({ - otp: z.string().meta({ description: 'The one time password to reset the password. Eg: "123456"' }), - phoneNumber: z.string().meta({ description: 'The phone number to the account which intends to reset the password for. Eg: "+1234567890"' }), - newPassword: z.string().meta({ description: `The new password. Eg: "new-and-secure-password"` }) -}); -z.object({ - walletAddress: z.string().regex(/^0[xX][a-fA-F0-9]{40}$/i).length(42), - chainId: z.number().int().positive().max(2147483647).optional().default(1) -}); -defineErrorCodes({ - OTP_NOT_ENABLED: "OTP not enabled", - OTP_HAS_EXPIRED: "OTP has expired", - TOTP_NOT_ENABLED: "TOTP not enabled", - TWO_FACTOR_NOT_ENABLED: "Two factor isn't enabled", - BACKUP_CODES_NOT_ENABLED: "Backup codes aren't enabled", - INVALID_BACKUP_CODE: "Invalid backup code", - INVALID_CODE: "Invalid code", - TOO_MANY_ATTEMPTS_REQUEST_NEW_CODE: "Too many attempts. Please request a new code.", - INVALID_TWO_FACTOR_COOKIE: "Invalid two factor cookie" -}); -z.object({ - code: z.string().meta({ description: `A backup code to verify. Eg: "123456"` }), - disableSession: z.boolean().meta({ description: "If true, the session cookie will not be set." }).optional(), - trustDevice: z.boolean().meta({ description: "If true, the device will be trusted for 30 days. It'll be refreshed on every sign in request within this time. Eg: true" }).optional() -}); -z.object({ userId: z.coerce.string().meta({ description: `The user ID to view all backup codes. Eg: "user-id"` }) }); -z.object({ password: z.string().meta({ description: "The users password." }) }); -z.object({ - code: z.string().meta({ description: 'The otp code to verify. Eg: "012345"' }), - trustDevice: z.boolean().optional().meta({ description: "If true, the device will be trusted for 30 days. It'll be refreshed on every sign in request within this time. Eg: true" }) -}); -z.object({ trustDevice: z.boolean().optional().meta({ description: "If true, the device will be trusted for 30 days. It'll be refreshed on every sign in request within this time. Eg: true" }) }).optional(); -z.object({ secret: z.string().meta({ description: "The secret to generate the TOTP code" }) }); -z.object({ password: z.string().meta({ description: "User password" }) }); -z.object({ - code: z.string().meta({ description: 'The otp code to verify. Eg: "012345"' }), - trustDevice: z.boolean().meta({ description: "If true, the device will be trusted for 30 days. It'll be refreshed on every sign in request within this time. Eg: true" }).optional() -}); -z.object({ - password: z.string().meta({ description: "User password" }), - issuer: z.string().meta({ description: "Custom issuer for the TOTP URI" }).optional() -}); -z.object({ password: z.string().meta({ description: "User password" }) }); -defineErrorCodes({ - INVALID_USERNAME_OR_PASSWORD: "Invalid username or password", - EMAIL_NOT_VERIFIED: "Email not verified", - UNEXPECTED_ERROR: "Unexpected error", - USERNAME_IS_ALREADY_TAKEN: "Username is already taken. Please try another.", - USERNAME_TOO_SHORT: "Username is too short", - USERNAME_TOO_LONG: "Username is too long", - INVALID_USERNAME: "Username is invalid", - INVALID_DISPLAY_USERNAME: "Display username is invalid" -}); -z.object({ - username: z.string().meta({ description: "The username of the user" }), - password: z.string().meta({ description: "The password of the user" }), - rememberMe: z.boolean().meta({ description: "Remember the user session" }).optional(), - callbackURL: z.string().meta({ description: "The URL to redirect to after email verification" }).optional() -}); -z.object({ username: z.string().meta({ description: "The username to check" }) }); -const auth = betterAuth({ - baseURL: private_env.ORIGIN, - secret: private_env.BETTER_AUTH_SECRET, - database: drizzleAdapter(db, { provider: "pg" }), - emailAndPassword: { enabled: true }, - databaseHooks: { - user: { - create: { - after: async (user) => { - const [personalTeam] = await db.insert(team).values({ - name: user.name, - isPersonal: true, - ownerId: user.id, - avatarUrl: user.image - }).returning(); - await db.insert(teamMember).values({ - teamId: personalTeam.id, - userId: user.id, - role: "owner" - }); - } - } - } - }, - plugins: [ - genericOAuth({ - config: [ - { - providerId: "osu", - clientId: private_env.OSU_CLIENT_ID, - clientSecret: private_env.OSU_CLIENT_SECRET, - authorizationUrl: "https://osu.ppy.sh/oauth/authorize", - tokenUrl: "https://osu.ppy.sh/oauth/token", - userInfoUrl: "https://osu.ppy.sh/api/v2/me", - scopes: ["identify", "public"], - pkce: false, - authentication: "post", - // ── FIX: Use ORIGIN env var instead of hardcoded localhost ── - redirectURI: `${private_env.ORIGIN}/api/auth/oauth2/callback/osu`, - getToken: async ({ code, redirectURI }) => { - const res = await fetch("https://osu.ppy.sh/oauth/token", { - method: "POST", - headers: { - Accept: "application/json", - "Content-Type": "application/x-www-form-urlencoded" - }, - body: new URLSearchParams({ - client_id: private_env.OSU_CLIENT_ID, - client_secret: private_env.OSU_CLIENT_SECRET, - code, - grant_type: "authorization_code", - redirect_uri: redirectURI - }) - }); - const data = await res.json(); - if (!res.ok) { - console.error("osu! token exchange failed:", data); - throw new Error("Token exchange failed"); - } - return { - accessToken: data.access_token, - refreshToken: data.refresh_token, - accessTokenExpiresAt: new Date(Date.now() + data.expires_in * 1e3), - scopes: ["identify", "public"], - raw: data - }; - }, - mapProfileToUser(profile) { - return { - name: profile.username, - image: profile.avatar_url, - email: `${profile.id}@osu.local` - }; - } - } - ] - }), - sveltekitCookies(getRequestEvent) - // must be last - ] -}); -export { - auth as a, - createKyselyAdapter as c, - getKyselyDatabaseType as g, - svelteKitHandler as s -}; diff --git a/.svelte-kit/adapter-node/chunks/bun-sqlite-dialect.js b/.svelte-kit/adapter-node/chunks/bun-sqlite-dialect.js deleted file mode 100644 index 6fe94c6..0000000 --- a/.svelte-kit/adapter-node/chunks/bun-sqlite-dialect.js +++ /dev/null @@ -1,155 +0,0 @@ -import { CompiledQuery, DefaultQueryCompiler, DEFAULT_MIGRATION_TABLE, DEFAULT_MIGRATION_LOCK_TABLE, sql } from "kysely"; -var BunSqliteAdapter = class { - get supportsCreateIfNotExists() { - return true; - } - get supportsTransactionalDdl() { - return false; - } - get supportsReturning() { - return true; - } - async acquireMigrationLock() { - } - async releaseMigrationLock() { - } - get supportsOutput() { - return true; - } -}; -var BunSqliteDriver = class { - #config; - #connectionMutex = new ConnectionMutex(); - #db; - #connection; - constructor(config) { - this.#config = { ...config }; - } - async init() { - this.#db = this.#config.database; - this.#connection = new BunSqliteConnection(this.#db); - if (this.#config.onCreateConnection) await this.#config.onCreateConnection(this.#connection); - } - async acquireConnection() { - await this.#connectionMutex.lock(); - return this.#connection; - } - async beginTransaction(connection) { - await connection.executeQuery(CompiledQuery.raw("begin")); - } - async commitTransaction(connection) { - await connection.executeQuery(CompiledQuery.raw("commit")); - } - async rollbackTransaction(connection) { - await connection.executeQuery(CompiledQuery.raw("rollback")); - } - async releaseConnection() { - this.#connectionMutex.unlock(); - } - async destroy() { - this.#db?.close(); - } -}; -var BunSqliteConnection = class { - #db; - constructor(db) { - this.#db = db; - } - executeQuery(compiledQuery) { - const { sql: sql$1, parameters } = compiledQuery; - const stmt = this.#db.prepare(sql$1); - return Promise.resolve({ rows: stmt.all(parameters) }); - } - async *streamQuery() { - throw new Error("Streaming query is not supported by SQLite driver."); - } -}; -var ConnectionMutex = class { - #promise; - #resolve; - async lock() { - while (await this.#promise) await this.#promise; - this.#promise = new Promise((resolve) => { - this.#resolve = resolve; - }); - } - unlock() { - const resolve = this.#resolve; - this.#promise = void 0; - this.#resolve = void 0; - resolve?.(); - } -}; -var BunSqliteIntrospector = class { - #db; - constructor(db) { - this.#db = db; - } - async getSchemas() { - return []; - } - async getTables(options = { withInternalKyselyTables: false }) { - let query = this.#db.selectFrom("sqlite_schema").where("type", "=", "table").where("name", "not like", "sqlite_%").select("name").$castTo(); - if (!options.withInternalKyselyTables) query = query.where("name", "!=", DEFAULT_MIGRATION_TABLE).where("name", "!=", DEFAULT_MIGRATION_LOCK_TABLE); - const tables = await query.execute(); - return Promise.all(tables.map(({ name }) => this.#getTableMetadata(name))); - } - async getMetadata(options) { - return { tables: await this.getTables(options) }; - } - async #getTableMetadata(table) { - const db = this.#db; - const autoIncrementCol = (await db.selectFrom("sqlite_master").where("name", "=", table).select("sql").$castTo().execute())[0]?.sql?.split(/[\(\),]/)?.find((it) => it.toLowerCase().includes("autoincrement"))?.split(/\s+/)?.[0]?.replace(/["`]/g, ""); - return { - name: table, - columns: (await db.selectFrom(sql`pragma_table_info(${table})`.as("table_info")).select([ - "name", - "type", - "notnull", - "dflt_value" - ]).execute()).map((col) => ({ - name: col.name, - dataType: col.type, - isNullable: !col.notnull, - isAutoIncrementing: col.name === autoIncrementCol, - hasDefaultValue: col.dflt_value != null - })), - isView: true - }; - } -}; -var BunSqliteQueryCompiler = class extends DefaultQueryCompiler { - getCurrentParameterPlaceholder() { - return "?"; - } - getLeftIdentifierWrapper() { - return '"'; - } - getRightIdentifierWrapper() { - return '"'; - } - getAutoIncrement() { - return "autoincrement"; - } -}; -var BunSqliteDialect = class { - #config; - constructor(config) { - this.#config = { ...config }; - } - createDriver() { - return new BunSqliteDriver(this.#config); - } - createQueryCompiler() { - return new BunSqliteQueryCompiler(); - } - createAdapter() { - return new BunSqliteAdapter(); - } - createIntrospector(db) { - return new BunSqliteIntrospector(db); - } -}; -export { - BunSqliteDialect -}; diff --git a/.svelte-kit/adapter-node/chunks/engine.js b/.svelte-kit/adapter-node/chunks/engine.js deleted file mode 100644 index f6bafe4..0000000 --- a/.svelte-kit/adapter-node/chunks/engine.js +++ /dev/null @@ -1,350 +0,0 @@ -import { d as db, b as match, e as matchParticipant, t as teamMember, f as matchParticipantPlayer, g as matchGame, h as matchGameScore, i as matchQueue, p as playerRating } from "./index2.js"; -import { eq, sql, asc } from "drizzle-orm"; -const MATCH_STATES = { - CREATED: "CREATED", - LOBBY: "LOBBY", - ROLLING: "ROLLING", - PICKING: "PICKING", - PLAYING: "PLAYING", - FINISHED: "FINISHED", - CANCELLED: "CANCELLED" -}; -const GAME_STATES = { - PLAYING: "PLAYING", - FINISHED: "FINISHED" -}; -async function joinQueue(userId, teamId) { - let rating = await db.query.playerRating.findFirst({ - where: eq(playerRating.userId, userId) - }); - if (!rating) { - [rating] = await db.insert(playerRating).values({ userId, elo: 1e3 }).returning(); - } - const existing = await db.query.matchQueue.findFirst({ - where: eq(matchQueue.userId, userId) - }); - if (existing) throw new Error("Already in queue"); - await db.insert(matchQueue).values({ - userId, - teamId, - elo: rating.elo - }); - return tryMatchFromQueue(); -} -async function leaveQueue(userId) { - await db.delete(matchQueue).where(eq(matchQueue.userId, userId)); -} -async function getQueueStatus(userId) { - const entry = await db.query.matchQueue.findFirst({ - where: eq(matchQueue.userId, userId) - }); - const count = await db.select({ count: sql`count(*)` }).from(matchQueue); - return { - inQueue: !!entry, - queueSize: Number(count[0].count), - joinedAt: entry?.joinedAt ?? null - }; -} -async function tryMatchFromQueue() { - const queue = await db.query.matchQueue.findMany({ - orderBy: asc(matchQueue.elo) - }); - if (queue.length < 2) return null; - let bestPair = null; - let smallestGap = Infinity; - for (let i = 0; i < queue.length - 1; i++) { - const gap = Math.abs(queue[i].elo - queue[i + 1].elo); - if (gap < smallestGap) { - smallestGap = gap; - bestPair = [queue[i], queue[i + 1]]; - } - } - if (!bestPair) return null; - const avgElo = (bestPair[0].elo + bestPair[1].elo) / 2; - const selectedPool = await selectMappoolForRating(avgElo); - if (!selectedPool) throw new Error("No mappools available"); - await db.delete(matchQueue).where(eq(matchQueue.userId, bestPair[0].userId)); - await db.delete(matchQueue).where(eq(matchQueue.userId, bestPair[1].userId)); - const created = await createMatch({ - name: "Ranked Match", - config: { bestOf: 7, teamSize: 1, scoringType: "score" }, - mappoolId: selectedPool.id, - teams: [bestPair[0].teamId, bestPair[1].teamId], - createdBy: "system" - }); - return created; -} -async function selectMappoolForRating(avgElo) { - const pools = await db.query.mappool.findMany({ - with: { slots: true } - }); - if (pools.length === 0) return null; - const targetStars = 3 + (avgElo - 800) / 400 * 4; - const clampedTarget = Math.max(2, Math.min(8, targetStars)); - let bestPool = pools[0]; - let bestDiff = Infinity; - for (const pool of pools) { - if (pool.slots.length === 0) continue; - const avgStars = pool.slots.reduce((sum, s) => sum + (s.starRating ?? 0), 0) / pool.slots.length; - const diff = Math.abs(avgStars - clampedTarget); - if (diff < bestDiff) { - bestDiff = diff; - bestPool = pool; - } - } - return bestPool; -} -async function createMatch(opts) { - const { name, config, mappoolId, teams, createdBy } = opts; - const [created] = await db.insert(match).values({ - name, - config, - mappoolId, - createdBy, - state: MATCH_STATES.CREATED - }).returning(); - for (let i = 0; i < teams.length; i++) { - const [participant] = await db.insert(matchParticipant).values({ - matchId: created.id, - teamId: teams[i], - slot: i + 1 - }).returning(); - const members = await db.query.teamMember.findMany({ - where: eq(teamMember.teamId, teams[i]) - }); - for (const member of members) { - await db.insert(matchParticipantPlayer).values({ - participantId: participant.id, - userId: member.userId - }); - } - } - return getMatchFull(created.id); -} -async function moveToLobby(matchId, osuLobbyId) { - const m = await getMatchOrThrow(matchId); - assertState(m.state, MATCH_STATES.CREATED); - await db.update(match).set({ - state: MATCH_STATES.LOBBY, - osuLobbyId: osuLobbyId ?? null, - startedAt: /* @__PURE__ */ new Date() - }).where(eq(match.id, matchId)); - return getMatchFull(matchId); -} -async function moveToRolling(matchId) { - const m = await getMatchOrThrow(matchId); - assertState(m.state, MATCH_STATES.LOBBY); - await db.update(match).set({ state: MATCH_STATES.ROLLING }).where(eq(match.id, matchId)); - return getMatchFull(matchId); -} -async function submitRoll(matchId, participantId, value) { - const m = await getMatchOrThrow(matchId); - assertState(m.state, MATCH_STATES.ROLLING); - await db.update(matchParticipant).set({ rollValue: value }).where(eq(matchParticipant.id, participantId)); - const participants = await db.query.matchParticipant.findMany({ - where: eq(matchParticipant.matchId, matchId) - }); - const allRolled = participants.every( - (p) => p.id === participantId ? true : p.rollValue !== null - ); - if (allRolled) { - const sorted = [...participants].map((p) => ({ - ...p, - rollValue: p.id === participantId ? value : p.rollValue - })).sort((a, b) => b.rollValue - a.rollValue); - for (let i = 0; i < sorted.length; i++) { - await db.update(matchParticipant).set({ pickOrder: i + 1 }).where(eq(matchParticipant.id, sorted[i].id)); - } - await db.update(match).set({ state: MATCH_STATES.PICKING }).where(eq(match.id, matchId)); - } - return getMatchFull(matchId); -} -async function pickMap(matchId, participantId, mappoolSlotId) { - const m = await getMatchOrThrow(matchId); - assertState(m.state, MATCH_STATES.PICKING); - const participants = await db.query.matchParticipant.findMany({ - where: eq(matchParticipant.matchId, matchId) - }); - const totalGames = await db.query.matchGame.findMany({ - where: eq(matchGame.matchId, matchId) - }); - const expectedPicker = getExpectedPicker(participants, totalGames.length); - if (expectedPicker.id !== participantId) { - throw new Error("Not your turn to pick"); - } - const alreadyPlayed = totalGames.some((g) => g.mappoolSlotId === mappoolSlotId); - if (alreadyPlayed) { - throw new Error("This map has already been played"); - } - const [game] = await db.insert(matchGame).values({ - matchId, - gameNumber: totalGames.length + 1, - mappoolSlotId, - pickedByParticipantId: participantId, - state: GAME_STATES.PLAYING, - startedAt: /* @__PURE__ */ new Date() - }).returning(); - await db.update(match).set({ state: MATCH_STATES.PLAYING }).where(eq(match.id, matchId)); - return game; -} -async function submitGameScores(matchGameId, scores) { - const game = await db.query.matchGame.findFirst({ - where: eq(matchGame.id, matchGameId) - }); - if (!game) throw new Error("Game not found"); - if (game.state !== GAME_STATES.PLAYING) throw new Error(`Game is ${game.state}, not PLAYING`); - for (const s of scores) { - await db.insert(matchGameScore).values({ - matchGameId, - playerId: s.playerId, - score: s.score, - accuracy: s.accuracy ?? 0, - maxCombo: s.maxCombo ?? 0, - count300: s.count300 ?? 0, - count100: s.count100 ?? 0, - count50: s.count50 ?? 0, - countMiss: s.countMiss ?? 0, - mods: s.mods ?? [], - passed: s.passed ?? true - }); - } - const allScores = await db.query.matchGameScore.findMany({ - where: eq(matchGameScore.matchGameId, matchGameId), - with: { player: true } - }); - const participantScores = /* @__PURE__ */ new Map(); - for (const s of allScores) { - const pid = s.player.participantId; - participantScores.set(pid, (participantScores.get(pid) ?? 0) + s.score); - } - let winnerId = null; - let highScore = -1; - for (const [pid, total] of participantScores) { - if (total > highScore) { - highScore = total; - winnerId = pid; - } - } - await db.update(matchGame).set({ - state: GAME_STATES.FINISHED, - winnerParticipantId: winnerId, - finishedAt: /* @__PURE__ */ new Date() - }).where(eq(matchGame.id, matchGameId)); - if (winnerId) { - const participant = await db.query.matchParticipant.findFirst({ - where: eq(matchParticipant.id, winnerId) - }); - if (participant) { - await db.update(matchParticipant).set({ score: participant.score + 1 }).where(eq(matchParticipant.id, winnerId)); - } - } - const m = await getMatchOrThrow(game.matchId); - const config = m.config; - const winsNeeded = Math.ceil(config.bestOf / 2); - const participants = await db.query.matchParticipant.findMany({ - where: eq(matchParticipant.matchId, game.matchId) - }); - const matchWinner = participants.find((p) => p.score >= winsNeeded); - if (matchWinner) { - await db.update(match).set({ - state: MATCH_STATES.FINISHED, - winnerId: matchWinner.teamId, - finishedAt: /* @__PURE__ */ new Date() - }).where(eq(match.id, game.matchId)); - await updateElo(participants, matchWinner.id); - } else { - await db.update(match).set({ state: MATCH_STATES.PICKING }).where(eq(match.id, game.matchId)); - } - return getMatchFull(game.matchId); -} -async function updateElo(participants, winnerId) { - for (const p of participants) { - const players = await db.query.matchParticipantPlayer.findMany({ - where: eq(matchParticipantPlayer.participantId, p.id) - }); - const isWinner = p.id === winnerId; - for (const player of players) { - let rating = await db.query.playerRating.findFirst({ - where: eq(playerRating.userId, player.userId) - }); - if (!rating) { - [rating] = await db.insert(playerRating).values({ userId: player.userId, elo: 1e3 }).returning(); - } - const K = 32; - const expected = 0.5; - const actual = isWinner ? 1 : 0; - const newElo = Math.round(rating.elo + K * (actual - expected)); - await db.update(playerRating).set({ - elo: newElo, - wins: isWinner ? rating.wins + 1 : rating.wins, - losses: isWinner ? rating.losses : rating.losses + 1, - updatedAt: /* @__PURE__ */ new Date() - }).where(eq(playerRating.userId, player.userId)); - } - } -} -async function cancelMatch(matchId) { - await db.update(match).set({ - state: MATCH_STATES.CANCELLED, - finishedAt: /* @__PURE__ */ new Date() - }).where(eq(match.id, matchId)); - return getMatchFull(matchId); -} -function getExpectedPicker(participants, gameCount) { - const sorted = [...participants].sort((a, b) => (a.pickOrder ?? 99) - (b.pickOrder ?? 99)); - const pickerIndex = gameCount % sorted.length; - return sorted[pickerIndex]; -} -async function getMatchFull(matchId) { - const m = await db.query.match.findFirst({ - where: eq(match.id, matchId), - with: { - mappool: { - with: { slots: true } - }, - participants: { - with: { - team: true, - players: true - } - }, - games: { - with: { - slot: true, - scores: { - with: { player: true } - } - }, - orderBy: (g, { asc: asc2 }) => [asc2(g.gameNumber)] - } - } - }); - if (!m) throw new Error("Match not found"); - return m; -} -async function getMatchOrThrow(matchId) { - const m = await db.query.match.findFirst({ - where: eq(match.id, matchId) - }); - if (!m) throw new Error("Match not found"); - return m; -} -function assertState(current, expected) { - if (current !== expected) { - throw new Error(`Match is ${current}, expected ${expected}`); - } -} -export { - MATCH_STATES as M, - cancelMatch as a, - moveToRolling as b, - createMatch as c, - submitGameScores as d, - getQueueStatus as e, - getMatchFull as g, - joinQueue as j, - leaveQueue as l, - moveToLobby as m, - pickMap as p, - submitRoll as s -}; diff --git a/.svelte-kit/adapter-node/chunks/environment.js b/.svelte-kit/adapter-node/chunks/environment.js deleted file mode 100644 index d81356b..0000000 --- a/.svelte-kit/adapter-node/chunks/environment.js +++ /dev/null @@ -1,14 +0,0 @@ -let building = false; -let prerendering = false; -function set_building() { - building = true; -} -function set_prerendering() { - prerendering = true; -} -export { - set_prerendering as a, - building as b, - prerendering as p, - set_building as s -}; diff --git a/.svelte-kit/adapter-node/chunks/exports.js b/.svelte-kit/adapter-node/chunks/exports.js deleted file mode 100644 index 441ec91..0000000 --- a/.svelte-kit/adapter-node/chunks/exports.js +++ /dev/null @@ -1,70 +0,0 @@ -function validator(expected) { - function validate(module, file) { - if (!module) return; - for (const key in module) { - if (key[0] === "_" || expected.has(key)) continue; - const values = [...expected.values()]; - const hint = hint_for_supported_files(key, file?.slice(file.lastIndexOf("."))) ?? `valid exports are ${values.join(", ")}, or anything with a '_' prefix`; - throw new Error(`Invalid export '${key}'${file ? ` in ${file}` : ""} (${hint})`); - } - } - return validate; -} -function hint_for_supported_files(key, ext = ".js") { - const supported_files = []; - if (valid_layout_exports.has(key)) { - supported_files.push(`+layout${ext}`); - } - if (valid_page_exports.has(key)) { - supported_files.push(`+page${ext}`); - } - if (valid_layout_server_exports.has(key)) { - supported_files.push(`+layout.server${ext}`); - } - if (valid_page_server_exports.has(key)) { - supported_files.push(`+page.server${ext}`); - } - if (valid_server_exports.has(key)) { - supported_files.push(`+server${ext}`); - } - if (supported_files.length > 0) { - return `'${key}' is a valid export in ${supported_files.slice(0, -1).join(", ")}${supported_files.length > 1 ? " or " : ""}${supported_files.at(-1)}`; - } -} -const valid_layout_exports = /* @__PURE__ */ new Set([ - "load", - "prerender", - "csr", - "ssr", - "trailingSlash", - "config" -]); -const valid_page_exports = /* @__PURE__ */ new Set([...valid_layout_exports, "entries"]); -const valid_layout_server_exports = /* @__PURE__ */ new Set([...valid_layout_exports]); -const valid_page_server_exports = /* @__PURE__ */ new Set([...valid_layout_server_exports, "actions", "entries"]); -const valid_server_exports = /* @__PURE__ */ new Set([ - "GET", - "POST", - "PATCH", - "PUT", - "DELETE", - "OPTIONS", - "HEAD", - "fallback", - "prerender", - "trailingSlash", - "config", - "entries" -]); -const validate_layout_exports = validator(valid_layout_exports); -const validate_page_exports = validator(valid_page_exports); -const validate_layout_server_exports = validator(valid_layout_server_exports); -const validate_page_server_exports = validator(valid_page_server_exports); -const validate_server_exports = validator(valid_server_exports); -export { - validate_layout_exports as a, - validate_page_server_exports as b, - validate_page_exports as c, - validate_server_exports as d, - validate_layout_server_exports as v -}; diff --git a/.svelte-kit/adapter-node/chunks/false.js b/.svelte-kit/adapter-node/chunks/false.js deleted file mode 100644 index f3effd6..0000000 --- a/.svelte-kit/adapter-node/chunks/false.js +++ /dev/null @@ -1,4 +0,0 @@ -const DEV = false; -export { - DEV as D -}; diff --git a/.svelte-kit/adapter-node/chunks/index.js b/.svelte-kit/adapter-node/chunks/index.js deleted file mode 100644 index 14b637b..0000000 --- a/.svelte-kit/adapter-node/chunks/index.js +++ /dev/null @@ -1,60 +0,0 @@ -import { n as noop } from "./index3.js"; -import { s as safe_not_equal } from "./root.js"; -import "clsx"; -const subscriber_queue = []; -function readable(value, start) { - return { - subscribe: writable(value, start).subscribe - }; -} -function writable(value, start = noop) { - let stop = null; - const subscribers = /* @__PURE__ */ new Set(); - function set(new_value) { - if (safe_not_equal(value, new_value)) { - value = new_value; - if (stop) { - const run_queue = !subscriber_queue.length; - for (const subscriber of subscribers) { - subscriber[1](); - subscriber_queue.push(subscriber, value); - } - if (run_queue) { - for (let i = 0; i < subscriber_queue.length; i += 2) { - subscriber_queue[i][0](subscriber_queue[i + 1]); - } - subscriber_queue.length = 0; - } - } - } - } - function update(fn) { - set(fn( - /** @type {T} */ - value - )); - } - function subscribe(run, invalidate = noop) { - const subscriber = [run, invalidate]; - subscribers.add(subscriber); - if (subscribers.size === 1) { - stop = start(set, update) || noop; - } - run( - /** @type {T} */ - value - ); - return () => { - subscribers.delete(subscriber); - if (subscribers.size === 0 && stop) { - stop(); - stop = null; - } - }; - } - return { set, update, subscribe }; -} -export { - readable as r, - writable as w -}; diff --git a/.svelte-kit/adapter-node/chunks/index2.js b/.svelte-kit/adapter-node/chunks/index2.js deleted file mode 100644 index 2c507a6..0000000 --- a/.svelte-kit/adapter-node/chunks/index2.js +++ /dev/null @@ -1,302 +0,0 @@ -import { drizzle } from "drizzle-orm/postgres-js"; -import postgres from "postgres"; -import { pgTable, timestamp, text, boolean, index, uuid, real, integer, jsonb, uniqueIndex } from "drizzle-orm/pg-core"; -import { relations } from "drizzle-orm"; -import { b as private_env } from "./shared-server.js"; -const user = pgTable("user", { - id: text("id").primaryKey(), - name: text("name").notNull(), - email: text("email").notNull().unique(), - emailVerified: boolean("email_verified").default(false).notNull(), - image: text("image"), - // ── Staff role: 'player' | 'referee' | 'admin' ── - role: text("role").default("player").notNull(), - createdAt: timestamp("created_at").defaultNow().notNull(), - updatedAt: timestamp("updated_at").defaultNow().$onUpdate(() => /* @__PURE__ */ new Date()).notNull() -}); -const session = pgTable( - "session", - { - id: text("id").primaryKey(), - expiresAt: timestamp("expires_at").notNull(), - token: text("token").notNull().unique(), - createdAt: timestamp("created_at").defaultNow().notNull(), - updatedAt: timestamp("updated_at").$onUpdate(() => /* @__PURE__ */ new Date()).notNull(), - ipAddress: text("ip_address"), - userAgent: text("user_agent"), - userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }) - }, - (table) => [index("session_userId_idx").on(table.userId)] -); -const account = pgTable( - "account", - { - id: text("id").primaryKey(), - accountId: text("account_id").notNull(), - providerId: text("provider_id").notNull(), - userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }), - accessToken: text("access_token"), - refreshToken: text("refresh_token"), - idToken: text("id_token"), - accessTokenExpiresAt: timestamp("access_token_expires_at"), - refreshTokenExpiresAt: timestamp("refresh_token_expires_at"), - scope: text("scope"), - password: text("password"), - createdAt: timestamp("created_at").defaultNow().notNull(), - updatedAt: timestamp("updated_at").$onUpdate(() => /* @__PURE__ */ new Date()).notNull() - }, - (table) => [index("account_userId_idx").on(table.userId)] -); -const verification = pgTable( - "verification", - { - id: text("id").primaryKey(), - identifier: text("identifier").notNull(), - value: text("value").notNull(), - expiresAt: timestamp("expires_at").notNull(), - createdAt: timestamp("created_at").defaultNow().notNull(), - updatedAt: timestamp("updated_at").defaultNow().$onUpdate(() => /* @__PURE__ */ new Date()).notNull() - }, - (table) => [index("verification_identifier_idx").on(table.identifier)] -); -const userRelations = relations(user, ({ many }) => ({ - sessions: many(session), - accounts: many(account) -})); -const sessionRelations = relations(session, ({ one }) => ({ - user: one(user, { - fields: [session.userId], - references: [user.id] - }) -})); -const accountRelations = relations(account, ({ one }) => ({ - user: one(user, { - fields: [account.userId], - references: [user.id] - }) -})); -const team = pgTable("team", { - id: uuid("id").primaryKey().defaultRandom(), - name: text("name").notNull(), - isPersonal: boolean("is_personal").default(false).notNull(), - ownerId: text("owner_id"), - avatarUrl: text("avatar_url"), - createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull() -}); -const teamMember = pgTable("team_member", { - id: uuid("id").primaryKey().defaultRandom(), - teamId: uuid("team_id").notNull().references(() => team.id, { onDelete: "cascade" }), - userId: text("user_id").notNull(), - role: text("role").default("member"), - joinedAt: timestamp("joined_at", { withTimezone: true }).defaultNow() -}); -const mappool = pgTable("mappool", { - id: uuid("id").primaryKey().defaultRandom(), - name: text("name").notNull(), - createdBy: text("created_by"), - createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull() -}); -const mappoolSlot = pgTable("mappool_slot", { - id: uuid("id").primaryKey().defaultRandom(), - mappoolId: uuid("mappool_id").notNull().references(() => mappool.id, { onDelete: "cascade" }), - category: text("category").notNull(), - orderInCategory: integer("order_in_category").notNull(), - beatmapId: text("beatmap_id").notNull(), - starRating: real("star_rating"), - mods: text("mods").array().default([]).notNull() -}); -const match = pgTable( - "match", - { - id: uuid("id").primaryKey().defaultRandom(), - name: text("name"), - state: text("state").default("CREATED").notNull(), - config: jsonb("config").notNull(), - mappoolId: uuid("mappool_id").references(() => mappool.id), - osuLobbyId: integer("osu_lobby_id"), - scheduledAt: timestamp("scheduled_at", { withTimezone: true }), - startedAt: timestamp("started_at", { withTimezone: true }), - finishedAt: timestamp("finished_at", { withTimezone: true }), - winnerId: uuid("winner_id").references(() => team.id), - createdBy: text("created_by"), - createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull() - }, - (t) => [index("idx_match_state").on(t.state)] -); -const matchParticipant = pgTable( - "match_participant", - { - id: uuid("id").primaryKey().defaultRandom(), - matchId: uuid("match_id").notNull().references(() => match.id, { onDelete: "cascade" }), - teamId: uuid("team_id").notNull().references(() => team.id), - slot: integer("slot").notNull(), - score: integer("score").default(0).notNull(), - rollValue: integer("roll_value"), - pickOrder: integer("pick_order") - }, - (t) => [ - index("idx_mp_match_team").on(t.matchId, t.teamId), - uniqueIndex("idx_mp_match_slot").on(t.matchId, t.slot), - index("idx_mp_match").on(t.matchId) - ] -); -const matchParticipantPlayer = pgTable( - "match_participant_player", - { - id: uuid("id").primaryKey().defaultRandom(), - participantId: uuid("participant_id").notNull().references(() => matchParticipant.id, { onDelete: "cascade" }), - userId: text("user_id").notNull() - }, - (t) => [ - uniqueIndex("idx_mpp_participant_user").on(t.participantId, t.userId), - index("idx_mpp_participant").on(t.participantId) - ] -); -const matchGame = pgTable( - "match_game", - { - id: uuid("id").primaryKey().defaultRandom(), - matchId: uuid("match_id").notNull().references(() => match.id, { onDelete: "cascade" }), - gameNumber: integer("game_number").notNull(), - mappoolSlotId: uuid("mappool_slot_id").notNull().references(() => mappoolSlot.id), - pickedByParticipantId: uuid("picked_by_participant_id").references(() => matchParticipant.id), - winnerParticipantId: uuid("winner_participant_id").references(() => matchParticipant.id), - state: text("state").default("PENDING").notNull(), - startedAt: timestamp("started_at", { withTimezone: true }), - finishedAt: timestamp("finished_at", { withTimezone: true }) - }, - (t) => [index("idx_match_game_match").on(t.matchId)] -); -const matchGameScore = pgTable( - "match_game_score", - { - id: uuid("id").primaryKey().defaultRandom(), - matchGameId: uuid("match_game_id").notNull().references(() => matchGame.id, { onDelete: "cascade" }), - playerId: uuid("player_id").notNull().references(() => matchParticipantPlayer.id), - score: integer("score").default(0).notNull(), - accuracy: real("accuracy").default(0).notNull(), - maxCombo: integer("max_combo").default(0).notNull(), - count300: integer("count_300").default(0).notNull(), - count100: integer("count_100").default(0).notNull(), - count50: integer("count_50").default(0).notNull(), - countMiss: integer("count_miss").default(0).notNull(), - mods: text("mods").array().default([]).notNull(), - passed: boolean("passed").default(false).notNull() - }, - (t) => [index("idx_mgs_game").on(t.matchGameId)] -); -const matchQueue = pgTable( - "match_queue", - { - id: uuid("id").primaryKey().defaultRandom(), - userId: text("user_id").notNull(), - teamId: uuid("team_id").notNull().references(() => team.id), - elo: integer("elo").default(1e3).notNull(), - joinedAt: timestamp("joined_at", { withTimezone: true }).defaultNow().notNull() - }, - (t) => [ - uniqueIndex("idx_queue_user").on(t.userId), - index("idx_queue_elo").on(t.elo) - ] -); -const playerRating = pgTable("player_rating", { - id: uuid("id").primaryKey().defaultRandom(), - userId: text("user_id").notNull().unique(), - elo: integer("elo").default(1e3).notNull(), - wins: integer("wins").default(0).notNull(), - losses: integer("losses").default(0).notNull(), - updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull() -}); -const teamRelations = relations(team, ({ many }) => ({ - members: many(teamMember) -})); -const teamMemberRelations = relations(teamMember, ({ one }) => ({ - team: one(team, { fields: [teamMember.teamId], references: [team.id] }) -})); -const mappoolRelations = relations(mappool, ({ many }) => ({ - slots: many(mappoolSlot) -})); -const mappoolSlotRelations = relations(mappoolSlot, ({ one }) => ({ - mappool: one(mappool, { fields: [mappoolSlot.mappoolId], references: [mappool.id] }) -})); -const matchRelations = relations(match, ({ one, many }) => ({ - mappool: one(mappool, { fields: [match.mappoolId], references: [mappool.id] }), - participants: many(matchParticipant), - games: many(matchGame) -})); -const matchParticipantRelations = relations(matchParticipant, ({ one, many }) => ({ - match: one(match, { fields: [matchParticipant.matchId], references: [match.id] }), - team: one(team, { fields: [matchParticipant.teamId], references: [team.id] }), - players: many(matchParticipantPlayer) -})); -const matchParticipantPlayerRelations = relations(matchParticipantPlayer, ({ one }) => ({ - participant: one(matchParticipant, { - fields: [matchParticipantPlayer.participantId], - references: [matchParticipant.id] - }) -})); -const matchGameRelations = relations(matchGame, ({ one, many }) => ({ - match: one(match, { fields: [matchGame.matchId], references: [match.id] }), - slot: one(mappoolSlot, { fields: [matchGame.mappoolSlotId], references: [mappoolSlot.id] }), - scores: many(matchGameScore) -})); -const matchGameScoreRelations = relations(matchGameScore, ({ one }) => ({ - game: one(matchGame, { fields: [matchGameScore.matchGameId], references: [matchGame.id] }), - player: one(matchParticipantPlayer, { - fields: [matchGameScore.playerId], - references: [matchParticipantPlayer.id] - }) -})); -const matchQueueRelations = relations(matchQueue, ({ one }) => ({ - team: one(team, { fields: [matchQueue.teamId], references: [team.id] }) -})); -const schema = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({ - __proto__: null, - account, - accountRelations, - mappool, - mappoolRelations, - mappoolSlot, - mappoolSlotRelations, - match, - matchGame, - matchGameRelations, - matchGameScore, - matchGameScoreRelations, - matchParticipant, - matchParticipantPlayer, - matchParticipantPlayerRelations, - matchParticipantRelations, - matchQueue, - matchQueueRelations, - matchRelations, - playerRating, - session, - sessionRelations, - team, - teamMember, - teamMemberRelations, - teamRelations, - user, - userRelations, - verification -}, Symbol.toStringTag, { value: "Module" })); -if (!private_env.DATABASE_URL) throw new Error("DATABASE_URL is not set"); -const client = postgres(private_env.DATABASE_URL); -const db = drizzle(client, { schema }); -export { - mappoolSlot as a, - match as b, - team as c, - db as d, - matchParticipant as e, - matchParticipantPlayer as f, - matchGame as g, - matchGameScore as h, - matchQueue as i, - account as j, - mappool as m, - playerRating as p, - teamMember as t, - user as u -}; diff --git a/.svelte-kit/adapter-node/chunks/index3.js b/.svelte-kit/adapter-node/chunks/index3.js deleted file mode 100644 index 20b173b..0000000 --- a/.svelte-kit/adapter-node/chunks/index3.js +++ /dev/null @@ -1,1249 +0,0 @@ -import { clsx as clsx$1 } from "clsx"; -import * as devalue from "devalue"; -var is_array = Array.isArray; -var index_of = Array.prototype.indexOf; -var includes = Array.prototype.includes; -var array_from = Array.from; -var define_property = Object.defineProperty; -var get_descriptor = Object.getOwnPropertyDescriptor; -var object_prototype = Object.prototype; -var array_prototype = Array.prototype; -var get_prototype_of = Object.getPrototypeOf; -var is_extensible = Object.isExtensible; -var has_own_property = Object.prototype.hasOwnProperty; -const noop = () => { -}; -function run_all(arr) { - for (var i = 0; i < arr.length; i++) { - arr[i](); - } -} -function deferred() { - var resolve; - var reject; - var promise = new Promise((res, rej) => { - resolve = res; - reject = rej; - }); - return { promise, resolve, reject }; -} -const DERIVED = 1 << 1; -const EFFECT = 1 << 2; -const RENDER_EFFECT = 1 << 3; -const MANAGED_EFFECT = 1 << 24; -const BLOCK_EFFECT = 1 << 4; -const BRANCH_EFFECT = 1 << 5; -const ROOT_EFFECT = 1 << 6; -const BOUNDARY_EFFECT = 1 << 7; -const CONNECTED = 1 << 9; -const CLEAN = 1 << 10; -const DIRTY = 1 << 11; -const MAYBE_DIRTY = 1 << 12; -const INERT = 1 << 13; -const DESTROYED = 1 << 14; -const REACTION_RAN = 1 << 15; -const EFFECT_TRANSPARENT = 1 << 16; -const EAGER_EFFECT = 1 << 17; -const HEAD_EFFECT = 1 << 18; -const EFFECT_PRESERVED = 1 << 19; -const USER_EFFECT = 1 << 20; -const WAS_MARKED = 1 << 16; -const REACTION_IS_UPDATING = 1 << 21; -const ASYNC = 1 << 22; -const ERROR_VALUE = 1 << 23; -const STATE_SYMBOL = /* @__PURE__ */ Symbol("$state"); -const LEGACY_PROPS = /* @__PURE__ */ Symbol("legacy props"); -const STALE_REACTION = new class StaleReactionError extends Error { - name = "StaleReactionError"; - message = "The reaction that called `getAbortSignal()` was re-run or destroyed"; -}(); -const COMMENT_NODE = 8; -function lifecycle_outside_component(name) { - { - throw new Error(`https://svelte.dev/e/lifecycle_outside_component`); - } -} -const HYDRATION_START = "["; -const HYDRATION_START_ELSE = "[!"; -const HYDRATION_START_FAILED = "[?"; -const HYDRATION_END = "]"; -const HYDRATION_ERROR = {}; -const ELEMENT_IS_NAMESPACED = 1; -const ELEMENT_PRESERVE_ATTRIBUTE_CASE = 1 << 1; -const ELEMENT_IS_INPUT = 1 << 2; -const UNINITIALIZED = /* @__PURE__ */ Symbol(); -const DOM_BOOLEAN_ATTRIBUTES = [ - "allowfullscreen", - "async", - "autofocus", - "autoplay", - "checked", - "controls", - "default", - "disabled", - "formnovalidate", - "indeterminate", - "inert", - "ismap", - "loop", - "multiple", - "muted", - "nomodule", - "novalidate", - "open", - "playsinline", - "readonly", - "required", - "reversed", - "seamless", - "selected", - "webkitdirectory", - "defer", - "disablepictureinpicture", - "disableremoteplayback" -]; -function is_boolean_attribute(name) { - return DOM_BOOLEAN_ATTRIBUTES.includes(name); -} -const PASSIVE_EVENTS = ["touchstart", "touchmove"]; -function is_passive_event(name) { - return PASSIVE_EVENTS.includes(name); -} -const ATTR_REGEX = /[&"<]/g; -const CONTENT_REGEX = /[&<]/g; -function escape_html(value, is_attr) { - const str = String(value ?? ""); - const pattern = is_attr ? ATTR_REGEX : CONTENT_REGEX; - pattern.lastIndex = 0; - let escaped = ""; - let last = 0; - while (pattern.test(str)) { - const i = pattern.lastIndex - 1; - const ch = str[i]; - escaped += str.substring(last, i) + (ch === "&" ? "&" : ch === '"' ? """ : "<"); - last = i + 1; - } - return escaped + str.substring(last); -} -const replacements = { - translate: /* @__PURE__ */ new Map([ - [true, "yes"], - [false, "no"] - ]) -}; -function attr(name, value, is_boolean = false) { - if (name === "hidden" && value !== "until-found") { - is_boolean = true; - } - if (value == null || !value && is_boolean) return ""; - const normalized = has_own_property.call(replacements, name) && replacements[name].get(value) || value; - const assignment = is_boolean ? `=""` : `="${escape_html(normalized, true)}"`; - return ` ${name}${assignment}`; -} -function clsx(value) { - if (typeof value === "object") { - return clsx$1(value); - } else { - return value ?? ""; - } -} -const whitespace = [..." \n\r\f \v\uFEFF"]; -function to_class(value, hash, directives) { - var classname = value == null ? "" : "" + value; - if (hash) { - classname = classname ? classname + " " + hash : hash; - } - if (directives) { - for (var key of Object.keys(directives)) { - if (directives[key]) { - classname = classname ? classname + " " + key : key; - } else if (classname.length) { - var len = key.length; - var a = 0; - while ((a = classname.indexOf(key, a)) >= 0) { - var b = a + len; - if ((a === 0 || whitespace.includes(classname[a - 1])) && (b === classname.length || whitespace.includes(classname[b]))) { - classname = (a === 0 ? "" : classname.substring(0, a)) + classname.substring(b + 1); - } else { - a = b; - } - } - } - } - } - return classname === "" ? null : classname; -} -function append_styles(styles, important = false) { - var separator = important ? " !important;" : ";"; - var css = ""; - for (var key of Object.keys(styles)) { - var value = styles[key]; - if (value != null && value !== "") { - css += " " + key + ": " + value + separator; - } - } - return css; -} -function to_css_name(name) { - if (name[0] !== "-" || name[1] !== "-") { - return name.toLowerCase(); - } - return name; -} -function to_style(value, styles) { - if (styles) { - var new_style = ""; - var normal_styles; - var important_styles; - if (Array.isArray(styles)) { - normal_styles = styles[0]; - important_styles = styles[1]; - } else { - normal_styles = styles; - } - if (value) { - value = String(value).replaceAll(/\s*\/\*.*?\*\/\s*/g, "").trim(); - var in_str = false; - var in_apo = 0; - var in_comment = false; - var reserved_names = []; - if (normal_styles) { - reserved_names.push(...Object.keys(normal_styles).map(to_css_name)); - } - if (important_styles) { - reserved_names.push(...Object.keys(important_styles).map(to_css_name)); - } - var start_index = 0; - var name_index = -1; - const len = value.length; - for (var i = 0; i < len; i++) { - var c = value[i]; - if (in_comment) { - if (c === "/" && value[i - 1] === "*") { - in_comment = false; - } - } else if (in_str) { - if (in_str === c) { - in_str = false; - } - } else if (c === "/" && value[i + 1] === "*") { - in_comment = true; - } else if (c === '"' || c === "'") { - in_str = c; - } else if (c === "(") { - in_apo++; - } else if (c === ")") { - in_apo--; - } - if (!in_comment && in_str === false && in_apo === 0) { - if (c === ":" && name_index === -1) { - name_index = i; - } else if (c === ";" || i === len - 1) { - if (name_index !== -1) { - var name = to_css_name(value.substring(start_index, name_index).trim()); - if (!reserved_names.includes(name)) { - if (c !== ";") { - i++; - } - var property = value.substring(start_index, i).trim(); - new_style += " " + property + ";"; - } - } - start_index = i + 1; - name_index = -1; - } - } - } - } - if (normal_styles) { - new_style += append_styles(normal_styles); - } - if (important_styles) { - new_style += append_styles(important_styles, true); - } - new_style = new_style.trim(); - return new_style === "" ? null : new_style; - } - return value == null ? null : String(value); -} -const BLOCK_OPEN = ``; -const BLOCK_CLOSE = ``; -let controller = null; -function abort() { - controller?.abort(STALE_REACTION); - controller = null; -} -function await_invalid() { - const error = new Error(`await_invalid -Encountered asynchronous work while rendering synchronously. -https://svelte.dev/e/await_invalid`); - error.name = "Svelte error"; - throw error; -} -function invalid_csp() { - const error = new Error(`invalid_csp -\`csp.nonce\` was set while \`csp.hash\` was \`true\`. These options cannot be used simultaneously. -https://svelte.dev/e/invalid_csp`); - error.name = "Svelte error"; - throw error; -} -function server_context_required() { - const error = new Error(`server_context_required -Could not resolve \`render\` context. -https://svelte.dev/e/server_context_required`); - error.name = "Svelte error"; - throw error; -} -var ssr_context = null; -function set_ssr_context(v) { - ssr_context = v; -} -function getContext(key) { - const context_map = get_or_init_context_map(); - const result = ( - /** @type {T} */ - context_map.get(key) - ); - return result; -} -function setContext(key, context) { - get_or_init_context_map().set(key, context); - return context; -} -function get_or_init_context_map(name) { - if (ssr_context === null) { - lifecycle_outside_component(); - } - return ssr_context.c ??= new Map(get_parent_context(ssr_context) || void 0); -} -function push(fn) { - ssr_context = { p: ssr_context, c: null, r: null }; -} -function pop() { - ssr_context = /** @type {SSRContext} */ - ssr_context.p; -} -function get_parent_context(ssr_context2) { - let parent = ssr_context2.p; - while (parent !== null) { - const context_map = parent.c; - if (context_map !== null) { - return context_map; - } - parent = parent.p; - } - return null; -} -function unresolved_hydratable(key, stack) { - { - console.warn(`https://svelte.dev/e/unresolved_hydratable`); - } -} -function get_render_context() { - const store = als?.getStore(); - { - server_context_required(); - } - return store; -} -let als = null; -let text_encoder; -let crypto; -const obfuscated_import = (module_name) => import( - /* @vite-ignore */ - module_name -); -async function sha256(data) { - text_encoder ??= new TextEncoder(); - crypto ??= globalThis.crypto?.subtle?.digest ? globalThis.crypto : ( - // @ts-ignore - we don't install node types in the prod build - // don't use import('node:crypto') directly because static analysers will think we rely on node when we don't - (await obfuscated_import("node:crypto")).webcrypto - ); - const hash_buffer = await crypto.subtle.digest("SHA-256", text_encoder.encode(data)); - return base64_encode(hash_buffer); -} -function base64_encode(bytes) { - if (globalThis.Buffer) { - return globalThis.Buffer.from(bytes).toString("base64"); - } - let binary = ""; - for (let i = 0; i < bytes.length; i++) { - binary += String.fromCharCode(bytes[i]); - } - return btoa(binary); -} -class Renderer { - /** - * The contents of the renderer. - * @type {RendererItem[]} - */ - #out = []; - /** - * Any `onDestroy` callbacks registered during execution of this renderer. - * @type {(() => void)[] | undefined} - */ - #on_destroy = void 0; - /** - * Whether this renderer is a component body. - * @type {boolean} - */ - #is_component_body = false; - /** - * If set, this renderer is an error boundary. When async collection - * of the children fails, the failed snippet is rendered instead. - * @type {{ - * failed: (renderer: Renderer, error: unknown, reset: () => void) => void; - * transformError: (error: unknown) => unknown; - * context: SSRContext | null; - * } | null} - */ - #boundary = null; - /** - * The type of string content that this renderer is accumulating. - * @type {RendererType} - */ - type; - /** @type {Renderer | undefined} */ - #parent; - /** - * Asynchronous work associated with this renderer - * @type {Promise | undefined} - */ - promise = void 0; - /** - * State which is associated with the content tree as a whole. - * It will be re-exposed, uncopied, on all children. - * @type {SSRState} - * @readonly - */ - global; - /** - * State that is local to the branch it is declared in. - * It will be shallow-copied to all children. - * - * @type {{ select_value: string | undefined }} - */ - local; - /** - * @param {SSRState} global - * @param {Renderer | undefined} [parent] - */ - constructor(global, parent) { - this.#parent = parent; - this.global = global; - this.local = parent ? { ...parent.local } : { select_value: void 0 }; - this.type = parent ? parent.type : "body"; - } - /** - * @param {(renderer: Renderer) => void} fn - */ - head(fn) { - const head = new Renderer(this.global, this); - head.type = "head"; - this.#out.push(head); - head.child(fn); - } - /** - * @param {Array>} blockers - * @param {(renderer: Renderer) => void} fn - */ - async_block(blockers, fn) { - this.#out.push(BLOCK_OPEN); - this.async(blockers, fn); - this.#out.push(BLOCK_CLOSE); - } - /** - * @param {Array>} blockers - * @param {(renderer: Renderer) => void} fn - */ - async(blockers, fn) { - let callback = fn; - if (blockers.length > 0) { - const context = ssr_context; - callback = (renderer) => { - return Promise.all(blockers).then(() => { - const previous_context = ssr_context; - try { - set_ssr_context(context); - return fn(renderer); - } finally { - set_ssr_context(previous_context); - } - }); - }; - } - this.child(callback); - } - /** - * @param {Array<() => void>} thunks - */ - run(thunks) { - const context = ssr_context; - let promise = Promise.resolve(thunks[0]()); - const promises = [promise]; - for (const fn of thunks.slice(1)) { - promise = promise.then(() => { - const previous_context = ssr_context; - set_ssr_context(context); - try { - return fn(); - } finally { - set_ssr_context(previous_context); - } - }); - promises.push(promise); - } - promise.catch(noop); - this.promise = promise; - return promises; - } - /** - * @param {(renderer: Renderer) => MaybePromise} fn - */ - child_block(fn) { - this.#out.push(BLOCK_OPEN); - this.child(fn); - this.#out.push(BLOCK_CLOSE); - } - /** - * Create a child renderer. The child renderer inherits the state from the parent, - * but has its own content. - * @param {(renderer: Renderer) => MaybePromise} fn - */ - child(fn) { - const child = new Renderer(this.global, this); - this.#out.push(child); - const parent = ssr_context; - set_ssr_context({ - ...ssr_context, - p: parent, - c: null, - r: child - }); - const result = fn(child); - set_ssr_context(parent); - if (result instanceof Promise) { - result.catch(noop); - result.finally(() => set_ssr_context(null)).catch(noop); - if (child.global.mode === "sync") { - await_invalid(); - } - child.promise = result; - } - return child; - } - /** - * Render children inside an error boundary. If the children throw and the API-level - * `transformError` transform handles the error (doesn't re-throw), the `failed` snippet is - * rendered instead. Otherwise the error propagates. - * - * @param {{ failed?: (renderer: Renderer, error: unknown, reset: () => void) => void }} props - * @param {(renderer: Renderer) => MaybePromise} children_fn - */ - boundary(props, children_fn) { - const child = new Renderer(this.global, this); - this.#out.push(child); - const parent_context = ssr_context; - if (props.failed) { - child.#boundary = { - failed: props.failed, - transformError: this.global.transformError, - context: parent_context - }; - } - set_ssr_context({ - ...ssr_context, - p: parent_context, - c: null, - r: child - }); - try { - const result = children_fn(child); - set_ssr_context(parent_context); - if (result instanceof Promise) { - if (child.global.mode === "sync") { - await_invalid(); - } - result.catch(noop); - child.promise = result; - } - } catch (error) { - set_ssr_context(parent_context); - const failed_snippet = props.failed; - if (!failed_snippet) throw error; - const result = this.global.transformError(error); - child.#out.length = 0; - child.#boundary = null; - if (result instanceof Promise) { - if (this.global.mode === "sync") { - await_invalid(); - } - child.promise = /** @type {Promise} */ - result.then((transformed) => { - set_ssr_context(parent_context); - child.#out.push(Renderer.#serialize_failed_boundary(transformed)); - failed_snippet(child, transformed, noop); - child.#out.push(BLOCK_CLOSE); - }); - child.promise.catch(noop); - } else { - child.#out.push(Renderer.#serialize_failed_boundary(result)); - failed_snippet(child, result, noop); - child.#out.push(BLOCK_CLOSE); - } - } - } - /** - * Create a component renderer. The component renderer inherits the state from the parent, - * but has its own content. It is treated as an ordering boundary for ondestroy callbacks. - * @param {(renderer: Renderer) => MaybePromise} fn - * @param {Function} [component_fn] - * @returns {void} - */ - component(fn, component_fn) { - push(); - const child = this.child(fn); - child.#is_component_body = true; - pop(); - } - /** - * @param {Record} attrs - * @param {(renderer: Renderer) => void} fn - * @param {string | undefined} [css_hash] - * @param {Record | undefined} [classes] - * @param {Record | undefined} [styles] - * @param {number | undefined} [flags] - * @param {boolean | undefined} [is_rich] - * @returns {void} - */ - select(attrs, fn, css_hash, classes, styles, flags, is_rich) { - const { value, ...select_attrs } = attrs; - this.push(``); - this.child((renderer) => { - renderer.local.select_value = value; - fn(renderer); - }); - this.push(`${is_rich ? "" : ""}`); - } - /** - * @param {Record} attrs - * @param {string | number | boolean | ((renderer: Renderer) => void)} body - * @param {string | undefined} [css_hash] - * @param {Record | undefined} [classes] - * @param {Record | undefined} [styles] - * @param {number | undefined} [flags] - * @param {boolean | undefined} [is_rich] - */ - option(attrs, body, css_hash, classes, styles, flags, is_rich) { - this.#out.push(` { - if (has_own_property.call(attrs, "value")) { - value = attrs.value; - } - if (value === this.local.select_value) { - renderer.#out.push(' selected=""'); - } - renderer.#out.push(`>${body2}${is_rich ? "" : ""}`); - if (head) { - renderer.head((child) => child.push(head)); - } - }; - if (typeof body === "function") { - this.child((renderer) => { - const r = new Renderer(this.global, this); - body(r); - if (this.global.mode === "async") { - return r.#collect_content_async().then((content) => { - close(renderer, content.body.replaceAll("", ""), content); - }); - } else { - const content = r.#collect_content(); - close(renderer, content.body.replaceAll("", ""), content); - } - }); - } else { - close(this, body, { body: escape_html(body) }); - } - } - /** - * @param {(renderer: Renderer) => void} fn - */ - title(fn) { - const path = this.get_path(); - const close = (head) => { - this.global.set_title(head, path); - }; - this.child((renderer) => { - const r = new Renderer(renderer.global, renderer); - fn(r); - if (renderer.global.mode === "async") { - return r.#collect_content_async().then((content) => { - close(content.head); - }); - } else { - const content = r.#collect_content(); - close(content.head); - } - }); - } - /** - * @param {string | (() => Promise)} content - */ - push(content) { - if (typeof content === "function") { - this.child(async (renderer) => renderer.push(await content())); - } else { - this.#out.push(content); - } - } - /** - * @param {() => void} fn - */ - on_destroy(fn) { - (this.#on_destroy ??= []).push(fn); - } - /** - * @returns {number[]} - */ - get_path() { - return this.#parent ? [...this.#parent.get_path(), this.#parent.#out.indexOf(this)] : []; - } - /** - * @deprecated this is needed for legacy component bindings - */ - copy() { - const copy = new Renderer(this.global, this.#parent); - copy.#out = this.#out.map((item) => item instanceof Renderer ? item.copy() : item); - copy.promise = this.promise; - return copy; - } - /** - * @param {Renderer} other - * @deprecated this is needed for legacy component bindings - */ - subsume(other) { - if (this.global.mode !== other.global.mode) { - throw new Error( - "invariant: A renderer cannot switch modes. If you're seeing this, there's a compiler bug. File an issue!" - ); - } - this.local = other.local; - this.#out = other.#out.map((item) => { - if (item instanceof Renderer) { - item.subsume(item); - } - return item; - }); - this.promise = other.promise; - this.type = other.type; - } - get length() { - return this.#out.length; - } - /** - * Creates the hydration comment that marks the start of a failed boundary. - * The error is JSON-serialized and embedded inside an HTML comment for the client - * to parse during hydration. The JSON is escaped to prevent `-->` or ``; - } - /** - * Only available on the server and when compiling with the `server` option. - * Takes a component and returns an object with `body` and `head` properties on it, which you can use to populate the HTML when server-rendering your app. - * @template {Record} Props - * @param {Component} component - * @param {{ props?: Omit; context?: Map; idPrefix?: string; csp?: Csp }} [options] - * @returns {RenderOutput} - */ - static render(component, options = {}) { - let sync; - const result = ( - /** @type {RenderOutput} */ - {} - ); - Object.defineProperties(result, { - html: { - get: () => { - return (sync ??= Renderer.#render(component, options)).body; - } - }, - head: { - get: () => { - return (sync ??= Renderer.#render(component, options)).head; - } - }, - body: { - get: () => { - return (sync ??= Renderer.#render(component, options)).body; - } - }, - hashes: { - value: { - script: "" - } - }, - then: { - value: ( - /** - * this is not type-safe, but honestly it's the best I can do right now, and it's a straightforward function. - * - * @template TResult1 - * @template [TResult2=never] - * @param { (value: SyncRenderOutput) => TResult1 } onfulfilled - * @param { (reason: unknown) => TResult2 } onrejected - */ - (onfulfilled, onrejected) => { - { - const result2 = sync ??= Renderer.#render(component, options); - const user_result = onfulfilled({ - head: result2.head, - body: result2.body, - html: result2.body, - hashes: { script: [] } - }); - return Promise.resolve(user_result); - } - } - ) - } - }); - return result; - } - /** - * Collect all of the `onDestroy` callbacks registered during rendering. In an async context, this is only safe to call - * after awaiting `collect_async`. - * - * Child renderers are "porous" and don't affect execution order, but component body renderers - * create ordering boundaries. Within a renderer, callbacks run in order until hitting a component boundary. - * @returns {Iterable<() => void>} - */ - *#collect_on_destroy() { - for (const component of this.#traverse_components()) { - yield* component.#collect_ondestroy(); - } - } - /** - * Performs a depth-first search of renderers, yielding the deepest components first, then additional components as we backtrack up the tree. - * @returns {Iterable} - */ - *#traverse_components() { - for (const child of this.#out) { - if (typeof child !== "string") { - yield* child.#traverse_components(); - } - } - if (this.#is_component_body) { - yield this; - } - } - /** - * @returns {Iterable<() => void>} - */ - *#collect_ondestroy() { - if (this.#on_destroy) { - for (const fn of this.#on_destroy) { - yield fn; - } - } - for (const child of this.#out) { - if (child instanceof Renderer && !child.#is_component_body) { - yield* child.#collect_ondestroy(); - } - } - } - /** - * Render a component. Throws if any of the children are performing asynchronous work. - * - * @template {Record} Props - * @param {Component} component - * @param {{ props?: Omit; context?: Map; idPrefix?: string }} options - * @returns {AccumulatedContent} - */ - static #render(component, options) { - var previous_context = ssr_context; - try { - const renderer = Renderer.#open_render("sync", component, options); - const content = renderer.#collect_content(); - return Renderer.#close_render(content, renderer); - } finally { - abort(); - set_ssr_context(previous_context); - } - } - /** - * Render a component. - * - * @template {Record} Props - * @param {Component} component - * @param {{ props?: Omit; context?: Map; idPrefix?: string; csp?: Csp }} options - * @returns {Promise} - */ - static async #render_async(component, options) { - const previous_context = ssr_context; - try { - const renderer = Renderer.#open_render("async", component, options); - const content = await renderer.#collect_content_async(); - const hydratables = await renderer.#collect_hydratables(); - if (hydratables !== null) { - content.head = hydratables + content.head; - } - return Renderer.#close_render(content, renderer); - } finally { - set_ssr_context(previous_context); - abort(); - } - } - /** - * Collect all of the code from the `out` array and return it as a string, or a promise resolving to a string. - * @param {AccumulatedContent} content - * @returns {AccumulatedContent} - */ - #collect_content(content = { head: "", body: "" }) { - for (const item of this.#out) { - if (typeof item === "string") { - content[this.type] += item; - } else if (item instanceof Renderer) { - item.#collect_content(content); - } - } - return content; - } - /** - * Collect all of the code from the `out` array and return it as a string. - * @param {AccumulatedContent} content - * @returns {Promise} - */ - async #collect_content_async(content = { head: "", body: "" }) { - await this.promise; - for (const item of this.#out) { - if (typeof item === "string") { - content[this.type] += item; - } else if (item instanceof Renderer) { - if (item.#boundary) { - const boundary_content = { head: "", body: "" }; - try { - await item.#collect_content_async(boundary_content); - content.head += boundary_content.head; - content.body += boundary_content.body; - } catch (error) { - const { context, failed, transformError } = item.#boundary; - set_ssr_context(context); - let transformed = await transformError(error); - const failed_renderer = new Renderer(item.global, item); - failed_renderer.type = item.type; - failed_renderer.#out.push(Renderer.#serialize_failed_boundary(transformed)); - failed(failed_renderer, transformed, noop); - failed_renderer.#out.push(BLOCK_CLOSE); - await failed_renderer.#collect_content_async(content); - } - } else { - await item.#collect_content_async(content); - } - } - } - return content; - } - async #collect_hydratables() { - const ctx = get_render_context().hydratable; - for (const [_, key] of ctx.unresolved_promises) { - unresolved_hydratable(key, ctx.lookup.get(key)?.stack ?? ""); - } - for (const comparison of ctx.comparisons) { - await comparison; - } - return await this.#hydratable_block(ctx); - } - /** - * @template {Record} Props - * @param {'sync' | 'async'} mode - * @param {import('svelte').Component} component - * @param {{ props?: Omit; context?: Map; idPrefix?: string; csp?: Csp; transformError?: (error: unknown) => unknown }} options - * @returns {Renderer} - */ - static #open_render(mode, component, options) { - var previous_context = ssr_context; - try { - const renderer = new Renderer( - new SSRState( - mode, - options.idPrefix ? options.idPrefix + "-" : "", - options.csp, - options.transformError - ) - ); - const context = { p: null, c: options.context ?? null, r: renderer }; - set_ssr_context(context); - renderer.push(BLOCK_OPEN); - component(renderer, options.props ?? {}); - renderer.push(BLOCK_CLOSE); - return renderer; - } finally { - set_ssr_context(previous_context); - } - } - /** - * @param {AccumulatedContent} content - * @param {Renderer} renderer - * @returns {AccumulatedContent & { hashes: { script: Sha256Source[] } }} - */ - static #close_render(content, renderer) { - for (const cleanup of renderer.#collect_on_destroy()) { - cleanup(); - } - let head = content.head + renderer.global.get_title(); - let body = content.body; - for (const { hash, code } of renderer.global.css) { - head += ``; - } - return { - head, - body, - hashes: { - script: renderer.global.csp.script_hashes - } - }; - } - /** - * @param {HydratableContext} ctx - */ - async #hydratable_block(ctx) { - if (ctx.lookup.size === 0) { - return null; - } - let entries = []; - let has_promises = false; - for (const [k, v] of ctx.lookup) { - if (v.promises) { - has_promises = true; - for (const p of v.promises) await p; - } - entries.push(`[${devalue.uneval(k)},${v.serialized}]`); - } - let prelude = `const h = (window.__svelte ??= {}).h ??= new Map();`; - if (has_promises) { - prelude = `const r = (v) => Promise.resolve(v); - ${prelude}`; - } - const body = ` - { - ${prelude} - - for (const [k, v] of [ - ${entries.join(",\n ")} - ]) { - h.set(k, v); - } - } - `; - let csp_attr = ""; - if (this.global.csp.nonce) { - csp_attr = ` nonce="${this.global.csp.nonce}"`; - } else if (this.global.csp.hash) { - const hash = await sha256(body); - this.global.csp.script_hashes.push(`sha256-${hash}`); - } - return ` - ${body}<\/script>`; - } -} -class SSRState { - /** @readonly @type {Csp & { script_hashes: Sha256Source[] }} */ - csp; - /** @readonly @type {'sync' | 'async'} */ - mode; - /** @readonly @type {() => string} */ - uid; - /** @readonly @type {Set<{ hash: string; code: string }>} */ - css = /* @__PURE__ */ new Set(); - /** - * `transformError` passed to `render`. Called when an error boundary catches an error. - * Throws by default if unset in `render`. - * @type {(error: unknown) => unknown} - */ - transformError; - /** @type {{ path: number[], value: string }} */ - #title = { path: [], value: "" }; - /** - * @param {'sync' | 'async'} mode - * @param {string} id_prefix - * @param {Csp} csp - * @param {((error: unknown) => unknown) | undefined} [transformError] - */ - constructor(mode, id_prefix = "", csp = { hash: false }, transformError) { - this.mode = mode; - this.csp = { ...csp, script_hashes: [] }; - this.transformError = transformError ?? ((error) => { - throw error; - }); - let uid = 1; - this.uid = () => `${id_prefix}s${uid++}`; - } - get_title() { - return this.#title.value; - } - /** - * Performs a depth-first (lexicographic) comparison using the path. Rejects sets - * from earlier than or equal to the current value. - * @param {string} value - * @param {number[]} path - */ - set_title(value, path) { - const current = this.#title.path; - let i = 0; - let l = Math.min(path.length, current.length); - while (i < l && path[i] === current[i]) i += 1; - if (path[i] === void 0) return; - if (current[i] === void 0 || path[i] > current[i]) { - this.#title.path = path; - this.#title.value = value; - } - } -} -const INVALID_ATTR_NAME_CHAR_REGEX = /[\s'">/=\u{FDD0}-\u{FDEF}\u{FFFE}\u{FFFF}\u{1FFFE}\u{1FFFF}\u{2FFFE}\u{2FFFF}\u{3FFFE}\u{3FFFF}\u{4FFFE}\u{4FFFF}\u{5FFFE}\u{5FFFF}\u{6FFFE}\u{6FFFF}\u{7FFFE}\u{7FFFF}\u{8FFFE}\u{8FFFF}\u{9FFFE}\u{9FFFF}\u{AFFFE}\u{AFFFF}\u{BFFFE}\u{BFFFF}\u{CFFFE}\u{CFFFF}\u{DFFFE}\u{DFFFF}\u{EFFFE}\u{EFFFF}\u{FFFFE}\u{FFFFF}\u{10FFFE}\u{10FFFF}]/u; -function render(component, options = {}) { - if (options.csp?.hash && options.csp.nonce) { - invalid_csp(); - } - return Renderer.render( - /** @type {Component} */ - component, - options - ); -} -function attributes(attrs, css_hash, classes, styles, flags = 0) { - if (styles) { - attrs.style = to_style(attrs.style, styles); - } - if (attrs.class) { - attrs.class = clsx(attrs.class); - } - if (css_hash || classes) { - attrs.class = to_class(attrs.class, css_hash, classes); - } - let attr_str = ""; - let name; - const is_html = (flags & ELEMENT_IS_NAMESPACED) === 0; - const lowercase = (flags & ELEMENT_PRESERVE_ATTRIBUTE_CASE) === 0; - const is_input = (flags & ELEMENT_IS_INPUT) !== 0; - for (name of Object.keys(attrs)) { - if (typeof attrs[name] === "function") continue; - if (name[0] === "$" && name[1] === "$") continue; - if (INVALID_ATTR_NAME_CHAR_REGEX.test(name)) continue; - var value = attrs[name]; - if (lowercase) { - name = name.toLowerCase(); - } - if (name.length > 2 && name.startsWith("on")) continue; - if (is_input) { - if (name === "defaultvalue" || name === "defaultchecked") { - name = name === "defaultvalue" ? "value" : "checked"; - if (attrs[name]) continue; - } - } - attr_str += attr(name, value, is_html && is_boolean_attribute(name)); - } - return attr_str; -} -function stringify(value) { - return typeof value === "string" ? value : value == null ? "" : value + ""; -} -function attr_class(value, hash, directives) { - var result = to_class(value, hash, directives); - return result ? ` class="${escape_html(result, true)}"` : ""; -} -function ensure_array_like(array_like_or_iterator) { - if (array_like_or_iterator) { - return array_like_or_iterator.length !== void 0 ? array_like_or_iterator : Array.from(array_like_or_iterator); - } - return []; -} -function once(get_value) { - let value = ( - /** @type {V} */ - UNINITIALIZED - ); - return () => { - if (value === UNINITIALIZED) { - value = get_value(); - } - return value; - }; -} -function derived(fn) { - const get_value = ssr_context === null ? fn : once(fn); - let updated_value; - return function(new_value) { - if (arguments.length === 0) { - return updated_value ?? get_value(); - } - updated_value = new_value; - return updated_value; - }; -} -export { - is_passive_event as $, - ASYNC as A, - BOUNDARY_EFFECT as B, - COMMENT_NODE as C, - DIRTY as D, - ERROR_VALUE as E, - EFFECT_TRANSPARENT as F, - EFFECT_PRESERVED as G, - HYDRATION_ERROR as H, - INERT as I, - EAGER_EFFECT as J, - STATE_SYMBOL as K, - object_prototype as L, - MAYBE_DIRTY as M, - array_prototype as N, - get_descriptor as O, - get_prototype_of as P, - is_array as Q, - REACTION_RAN as R, - STALE_REACTION as S, - is_extensible as T, - UNINITIALIZED as U, - USER_EFFECT as V, - WAS_MARKED as W, - REACTION_IS_UPDATING as X, - index_of as Y, - define_property as Z, - array_from as _, - ensure_array_like as a, - LEGACY_PROPS as a0, - render as a1, - setContext as a2, - attr as b, - attr_class as c, - derived as d, - escape_html as e, - HYDRATION_END as f, - getContext as g, - HYDRATION_START as h, - HYDRATION_START_ELSE as i, - EFFECT as j, - CONNECTED as k, - CLEAN as l, - DERIVED as m, - noop as n, - BLOCK_EFFECT as o, - deferred as p, - BRANCH_EFFECT as q, - run_all as r, - stringify as s, - ROOT_EFFECT as t, - RENDER_EFFECT as u, - MANAGED_EFFECT as v, - HEAD_EFFECT as w, - DESTROYED as x, - includes as y, - HYDRATION_START_FAILED as z -}; diff --git a/.svelte-kit/adapter-node/chunks/index4.js b/.svelte-kit/adapter-node/chunks/index4.js deleted file mode 100644 index 2ae44a6..0000000 --- a/.svelte-kit/adapter-node/chunks/index4.js +++ /dev/null @@ -1,47 +0,0 @@ -import "./state.svelte.js"; -import "clsx"; -import "@sveltejs/kit/internal"; -import "./url.js"; -import "./utils.js"; -import { w as writable } from "./index.js"; -import "@sveltejs/kit/internal/server"; -import "./root.js"; -import "./exports.js"; -import { g as getContext } from "./index3.js"; -function create_updated_store() { - const { set, subscribe } = writable(false); - { - return { - subscribe, - // eslint-disable-next-line @typescript-eslint/require-await - check: async () => false - }; - } -} -const stores = { - updated: /* @__PURE__ */ create_updated_store() -}; -({ - check: stores.updated.check -}); -function context() { - return getContext("__request__"); -} -const page$1 = { - get data() { - return context().page.data; - }, - get error() { - return context().page.error; - }, - get status() { - return context().page.status; - }, - get url() { - return context().page.url; - } -}; -const page = page$1; -export { - page as p -}; diff --git a/.svelte-kit/adapter-node/chunks/index5.js b/.svelte-kit/adapter-node/chunks/index5.js deleted file mode 100644 index 5a5bcdc..0000000 --- a/.svelte-kit/adapter-node/chunks/index5.js +++ /dev/null @@ -1,224 +0,0 @@ -import { logger } from "@better-auth/core/env"; -import { createAdapterFactory } from "@better-auth/core/db/adapter"; -const memoryAdapter = (db, config) => { - let lazyOptions = null; - const adapterCreator = createAdapterFactory({ - config: { - adapterId: "memory", - adapterName: "Memory Adapter", - usePlural: false, - debugLogs: config?.debugLogs || false, - supportsArrays: true, - customTransformInput(props) { - if ((props.options.advanced?.database?.useNumberId || props.options.advanced?.database?.generateId === "serial") && props.field === "id" && props.action === "create") return db[props.model].length + 1; - return props.data; - }, - transaction: async (cb) => { - const clone = structuredClone(db); - try { - return await cb(adapterCreator(lazyOptions)); - } catch (error) { - Object.keys(db).forEach((key) => { - db[key] = clone[key]; - }); - throw error; - } - } - }, - adapter: ({ getFieldName, getDefaultFieldName, options, getModelName }) => { - const applySortToRecords = (records, sortBy, model) => { - if (!sortBy) return records; - return records.sort((a, b) => { - const field = getFieldName({ - model, - field: sortBy.field - }); - const aValue = a[field]; - const bValue = b[field]; - let comparison = 0; - if (aValue == null && bValue == null) comparison = 0; - else if (aValue == null) comparison = -1; - else if (bValue == null) comparison = 1; - else if (typeof aValue === "string" && typeof bValue === "string") comparison = aValue.localeCompare(bValue); - else if (aValue instanceof Date && bValue instanceof Date) comparison = aValue.getTime() - bValue.getTime(); - else if (typeof aValue === "number" && typeof bValue === "number") comparison = aValue - bValue; - else if (typeof aValue === "boolean" && typeof bValue === "boolean") comparison = aValue === bValue ? 0 : aValue ? 1 : -1; - else comparison = String(aValue).localeCompare(String(bValue)); - return sortBy.direction === "asc" ? comparison : -comparison; - }); - }; - function convertWhereClause(where, model, join, select) { - const baseRecords = (() => { - const table = db[model]; - if (!table) { - logger.error(`[MemoryAdapter] Model ${model} not found in the DB`, Object.keys(db)); - throw new Error(`Model ${model} not found`); - } - const evalClause = (record, clause) => { - const { field, value, operator } = clause; - switch (operator) { - case "in": - if (!Array.isArray(value)) throw new Error("Value must be an array"); - return value.includes(record[field]); - case "not_in": - if (!Array.isArray(value)) throw new Error("Value must be an array"); - return !value.includes(record[field]); - case "contains": - return record[field].includes(value); - case "starts_with": - return record[field].startsWith(value); - case "ends_with": - return record[field].endsWith(value); - case "ne": - return record[field] !== value; - case "gt": - return value != null && Boolean(record[field] > value); - case "gte": - return value != null && Boolean(record[field] >= value); - case "lt": - return value != null && Boolean(record[field] < value); - case "lte": - return value != null && Boolean(record[field] <= value); - default: - return record[field] === value; - } - }; - let records = table.filter((record) => { - if (!where.length || where.length === 0) return true; - let result = evalClause(record, where[0]); - for (const clause of where) { - const clauseResult = evalClause(record, clause); - if (clause.connector === "OR") result = result || clauseResult; - else result = result && clauseResult; - } - return result; - }); - if (select?.length && select.length > 0) records = records.map((record) => Object.fromEntries(Object.entries(record).filter(([key]) => select.includes(getDefaultFieldName({ - model, - field: key - }))))); - return records; - })(); - if (!join) return baseRecords; - const grouped = /* @__PURE__ */ new Map(); - const seenIds = /* @__PURE__ */ new Map(); - for (const baseRecord of baseRecords) { - const baseId = String(baseRecord.id); - if (!grouped.has(baseId)) { - const nested = { ...baseRecord }; - for (const [joinModel, joinAttr] of Object.entries(join)) { - const joinModelName = getModelName(joinModel); - if (joinAttr.relation === "one-to-one") nested[joinModelName] = null; - else { - nested[joinModelName] = []; - seenIds.set(`${baseId}-${joinModel}`, /* @__PURE__ */ new Set()); - } - } - grouped.set(baseId, nested); - } - const nestedEntry = grouped.get(baseId); - for (const [joinModel, joinAttr] of Object.entries(join)) { - const joinModelName = getModelName(joinModel); - const joinTable = db[joinModelName]; - if (!joinTable) { - logger.error(`[MemoryAdapter] JoinOption model ${joinModelName} not found in the DB`, Object.keys(db)); - throw new Error(`JoinOption model ${joinModelName} not found`); - } - const matchingRecords = joinTable.filter((joinRecord) => joinRecord[joinAttr.on.to] === baseRecord[joinAttr.on.from]); - if (joinAttr.relation === "one-to-one") nestedEntry[joinModelName] = matchingRecords[0] || null; - else { - const seenSet = seenIds.get(`${baseId}-${joinModel}`); - const limit = joinAttr.limit ?? 100; - let count = 0; - for (const matchingRecord of matchingRecords) { - if (count >= limit) break; - if (!seenSet.has(matchingRecord.id)) { - nestedEntry[joinModelName].push(matchingRecord); - seenSet.add(matchingRecord.id); - count++; - } - } - } - } - } - return Array.from(grouped.values()); - } - return { - create: async ({ model, data }) => { - if (options.advanced?.database?.useNumberId || options.advanced?.database?.generateId === "serial") data.id = db[getModelName(model)].length + 1; - if (!db[model]) db[model] = []; - db[model].push(data); - return data; - }, - findOne: async ({ model, where, select, join }) => { - const res = convertWhereClause(where, model, join, select); - if (join) { - const resArray = res; - if (!resArray.length) return null; - return resArray[0]; - } - return res[0] || null; - }, - findMany: async ({ model, where, sortBy, limit, select, offset, join }) => { - const res = convertWhereClause(where || [], model, join, select); - if (join) { - const resArray = res; - if (!resArray.length) return []; - applySortToRecords(resArray, sortBy, model); - let paginatedRecords = resArray; - if (offset !== void 0) paginatedRecords = paginatedRecords.slice(offset); - if (limit !== void 0) paginatedRecords = paginatedRecords.slice(0, limit); - return paginatedRecords; - } - let table = applySortToRecords(res, sortBy, model); - if (offset !== void 0) table = table.slice(offset); - if (limit !== void 0) table = table.slice(0, limit); - return table || []; - }, - count: async ({ model, where }) => { - if (where) return convertWhereClause(where, model).length; - return db[model].length; - }, - update: async ({ model, where, update }) => { - const res = convertWhereClause(where, model); - res.forEach((record) => { - Object.assign(record, update); - }); - return res[0] || null; - }, - delete: async ({ model, where }) => { - const table = db[model]; - const res = convertWhereClause(where, model); - db[model] = table.filter((record) => !res.includes(record)); - }, - deleteMany: async ({ model, where }) => { - const table = db[model]; - const res = convertWhereClause(where, model); - let count = 0; - db[model] = table.filter((record) => { - if (res.includes(record)) { - count++; - return false; - } - return !res.includes(record); - }); - return count; - }, - updateMany({ model, where, update }) { - const res = convertWhereClause(where, model); - res.forEach((record) => { - Object.assign(record, update); - }); - return res[0] || null; - } - }; - } - }); - return (options) => { - lazyOptions = options; - return adapterCreator(options); - }; -}; -export { - memoryAdapter -}; diff --git a/.svelte-kit/adapter-node/chunks/index6.js b/.svelte-kit/adapter-node/chunks/index6.js deleted file mode 100644 index f55374c..0000000 --- a/.svelte-kit/adapter-node/chunks/index6.js +++ /dev/null @@ -1,307 +0,0 @@ -import { c as createKyselyAdapter } from "./auth.js"; -import { g } from "./auth.js"; -import { sql } from "kysely"; -import { createAdapterFactory } from "@better-auth/core/db/adapter"; -const kyselyAdapter = (db, config) => { - let lazyOptions = null; - const createCustomAdapter = (db$1) => { - return ({ getFieldName, schema, getDefaultFieldName, getDefaultModelName, getFieldAttributes, getModelName }) => { - const selectAllJoins = (join) => { - const allSelects = []; - const allSelectsStr = []; - if (join) for (const [joinModel, _] of Object.entries(join)) { - const fields = schema[getDefaultModelName(joinModel)]?.fields; - const [_joinModelSchema, joinModelName] = joinModel.includes(".") ? joinModel.split(".") : [void 0, joinModel]; - if (!fields) continue; - fields.id = { type: "string" }; - for (const [field, fieldAttr] of Object.entries(fields)) { - allSelects.push(sql`${sql.ref(`join_${joinModelName}`)}.${sql.ref(fieldAttr.fieldName || field)} as ${sql.ref(`_joined_${joinModelName}_${fieldAttr.fieldName || field}`)}`); - allSelectsStr.push({ - joinModel, - joinModelRef: joinModelName, - fieldName: fieldAttr.fieldName || field - }); - } - } - return { - allSelectsStr, - allSelects - }; - }; - const withReturning = async (values, builder, model, where) => { - let res; - if (config?.type === "mysql") { - await builder.execute(); - const field = values.id ? "id" : where.length > 0 && where[0]?.field ? where[0].field : "id"; - if (!values.id && where.length === 0) { - res = await db$1.selectFrom(model).selectAll().orderBy(getFieldName({ - model, - field - }), "desc").limit(1).executeTakeFirst(); - return res; - } - const value = values[field] || where[0]?.value; - res = await db$1.selectFrom(model).selectAll().orderBy(getFieldName({ - model, - field - }), "desc").where(getFieldName({ - model, - field - }), "=", value).limit(1).executeTakeFirst(); - return res; - } - if (config?.type === "mssql") { - res = await builder.outputAll("inserted").executeTakeFirst(); - return res; - } - res = await builder.returningAll().executeTakeFirst(); - return res; - }; - function convertWhereClause(model, w) { - if (!w) return { - and: null, - or: null - }; - const conditions = { - and: [], - or: [] - }; - w.forEach((condition) => { - const { field: _field, value: _value, operator = "=", connector = "AND" } = condition; - const value = _value; - const field = getFieldName({ - model, - field: _field - }); - const expr = (eb) => { - const f = `${model}.${field}`; - if (operator.toLowerCase() === "in") return eb(f, "in", Array.isArray(value) ? value : [value]); - if (operator.toLowerCase() === "not_in") return eb(f, "not in", Array.isArray(value) ? value : [value]); - if (operator === "contains") return eb(f, "like", `%${value}%`); - if (operator === "starts_with") return eb(f, "like", `${value}%`); - if (operator === "ends_with") return eb(f, "like", `%${value}`); - if (operator === "eq") return eb(f, "=", value); - if (operator === "ne") return eb(f, "<>", value); - if (operator === "gt") return eb(f, ">", value); - if (operator === "gte") return eb(f, ">=", value); - if (operator === "lt") return eb(f, "<", value); - if (operator === "lte") return eb(f, "<=", value); - return eb(f, operator, value); - }; - if (connector === "OR") conditions.or.push(expr); - else conditions.and.push(expr); - }); - return { - and: conditions.and.length ? conditions.and : null, - or: conditions.or.length ? conditions.or : null - }; - } - function processJoinedResults(rows, joinConfig, allSelectsStr) { - if (!joinConfig || !rows.length) return rows; - const groupedByMainId = /* @__PURE__ */ new Map(); - for (const currentRow of rows) { - const mainModelFields = {}; - const joinedModelFields = {}; - for (const [joinModel] of Object.entries(joinConfig)) joinedModelFields[getModelName(joinModel)] = {}; - for (const [key, value] of Object.entries(currentRow)) { - const keyStr = String(key); - let assigned = false; - for (const { joinModel, fieldName, joinModelRef } of allSelectsStr) if (keyStr === `_joined_${joinModelRef}_${fieldName}`) { - joinedModelFields[getModelName(joinModel)][getFieldName({ - model: joinModel, - field: fieldName - })] = value; - assigned = true; - break; - } - if (!assigned) mainModelFields[key] = value; - } - const mainId = mainModelFields.id; - if (!mainId) continue; - if (!groupedByMainId.has(mainId)) { - const entry$1 = { ...mainModelFields }; - for (const [joinModel, joinAttr] of Object.entries(joinConfig)) entry$1[getModelName(joinModel)] = joinAttr.relation === "one-to-one" ? null : []; - groupedByMainId.set(mainId, entry$1); - } - const entry = groupedByMainId.get(mainId); - for (const [joinModel, joinAttr] of Object.entries(joinConfig)) { - const isUnique = joinAttr.relation === "one-to-one"; - const limit = joinAttr.limit ?? 100; - const joinedObj = joinedModelFields[getModelName(joinModel)]; - const hasData = joinedObj && Object.keys(joinedObj).length > 0 && Object.values(joinedObj).some((value) => value !== null && value !== void 0); - if (isUnique) entry[getModelName(joinModel)] = hasData ? joinedObj : null; - else { - const joinModelName = getModelName(joinModel); - if (Array.isArray(entry[joinModelName]) && hasData) { - if (entry[joinModelName].length >= limit) continue; - const idFieldName = getFieldName({ - model: joinModel, - field: "id" - }); - const joinedId = joinedObj[idFieldName]; - if (joinedId) { - if (!entry[joinModelName].some((item) => item[idFieldName] === joinedId) && entry[joinModelName].length < limit) entry[joinModelName].push(joinedObj); - } else if (entry[joinModelName].length < limit) entry[joinModelName].push(joinedObj); - } - } - } - } - const result = Array.from(groupedByMainId.values()); - for (const entry of result) for (const [joinModel, joinAttr] of Object.entries(joinConfig)) if (joinAttr.relation !== "one-to-one") { - const joinModelName = getModelName(joinModel); - if (Array.isArray(entry[joinModelName])) { - const limit = joinAttr.limit ?? 100; - if (entry[joinModelName].length > limit) entry[joinModelName] = entry[joinModelName].slice(0, limit); - } - } - return result; - } - return { - async create({ data, model }) { - return await withReturning(data, db$1.insertInto(model).values(data), model, []); - }, - async findOne({ model, where, select, join }) { - const { and, or } = convertWhereClause(model, where); - let query = db$1.selectFrom((eb) => { - let b = eb.selectFrom(model); - if (and) b = b.where((eb$1) => eb$1.and(and.map((expr) => expr(eb$1)))); - if (or) b = b.where((eb$1) => eb$1.or(or.map((expr) => expr(eb$1)))); - if (select?.length && select.length > 0) b = b.select(select.map((field) => getFieldName({ - model, - field - }))); - else b = b.selectAll(); - return b.as("primary"); - }).selectAll("primary"); - if (join) for (const [joinModel, joinAttr] of Object.entries(join)) { - const [_joinModelSchema, joinModelName] = joinModel.includes(".") ? joinModel.split(".") : [void 0, joinModel]; - query = query.leftJoin(`${joinModel} as join_${joinModelName}`, (join$1) => join$1.onRef(`join_${joinModelName}.${joinAttr.on.to}`, "=", `primary.${joinAttr.on.from}`)); - } - const { allSelectsStr, allSelects } = selectAllJoins(join); - query = query.select(allSelects); - const res = await query.execute(); - if (!res || !Array.isArray(res) || res.length === 0) return null; - const row = res[0]; - if (join) return processJoinedResults(res, join, allSelectsStr)[0]; - return row; - }, - async findMany({ model, where, limit, select, offset, sortBy, join }) { - const { and, or } = convertWhereClause(model, where); - let query = db$1.selectFrom((eb) => { - let b = eb.selectFrom(model); - if (config?.type === "mssql") { - if (offset !== void 0) { - if (!sortBy) b = b.orderBy(getFieldName({ - model, - field: "id" - })); - b = b.offset(offset).fetch(limit || 100); - } else if (limit !== void 0) b = b.top(limit); - } else { - if (limit !== void 0) b = b.limit(limit); - if (offset !== void 0) b = b.offset(offset); - } - if (sortBy?.field) b = b.orderBy(`${getFieldName({ - model, - field: sortBy.field - })}`, sortBy.direction); - if (and) b = b.where((eb$1) => eb$1.and(and.map((expr) => expr(eb$1)))); - if (or) b = b.where((eb$1) => eb$1.or(or.map((expr) => expr(eb$1)))); - if (select?.length && select.length > 0) b = b.select(select.map((field) => getFieldName({ - model, - field - }))); - else b = b.selectAll(); - return b.as("primary"); - }).selectAll("primary"); - if (join) for (const [joinModel, joinAttr] of Object.entries(join)) { - const [_joinModelSchema, joinModelName] = joinModel.includes(".") ? joinModel.split(".") : [void 0, joinModel]; - query = query.leftJoin(`${joinModel} as join_${joinModelName}`, (join$1) => join$1.onRef(`join_${joinModelName}.${joinAttr.on.to}`, "=", `primary.${joinAttr.on.from}`)); - } - const { allSelectsStr, allSelects } = selectAllJoins(join); - query = query.select(allSelects); - if (sortBy?.field) query = query.orderBy(`${getFieldName({ - model, - field: sortBy.field - })}`, sortBy.direction); - const res = await query.execute(); - if (!res) return []; - if (join) return processJoinedResults(res, join, allSelectsStr); - return res; - }, - async update({ model, where, update: values }) { - const { and, or } = convertWhereClause(model, where); - let query = db$1.updateTable(model).set(values); - if (and) query = query.where((eb) => eb.and(and.map((expr) => expr(eb)))); - if (or) query = query.where((eb) => eb.or(or.map((expr) => expr(eb)))); - return await withReturning(values, query, model, where); - }, - async updateMany({ model, where, update: values }) { - const { and, or } = convertWhereClause(model, where); - let query = db$1.updateTable(model).set(values); - if (and) query = query.where((eb) => eb.and(and.map((expr) => expr(eb)))); - if (or) query = query.where((eb) => eb.or(or.map((expr) => expr(eb)))); - const res = (await query.executeTakeFirst()).numUpdatedRows; - return res > Number.MAX_SAFE_INTEGER ? Number.MAX_SAFE_INTEGER : Number(res); - }, - async count({ model, where }) { - const { and, or } = convertWhereClause(model, where); - let query = db$1.selectFrom(model).select(db$1.fn.count("id").as("count")); - if (and) query = query.where((eb) => eb.and(and.map((expr) => expr(eb)))); - if (or) query = query.where((eb) => eb.or(or.map((expr) => expr(eb)))); - const res = await query.execute(); - if (typeof res[0].count === "number") return res[0].count; - if (typeof res[0].count === "bigint") return Number(res[0].count); - return parseInt(res[0].count); - }, - async delete({ model, where }) { - const { and, or } = convertWhereClause(model, where); - let query = db$1.deleteFrom(model); - if (and) query = query.where((eb) => eb.and(and.map((expr) => expr(eb)))); - if (or) query = query.where((eb) => eb.or(or.map((expr) => expr(eb)))); - await query.execute(); - }, - async deleteMany({ model, where }) { - const { and, or } = convertWhereClause(model, where); - let query = db$1.deleteFrom(model); - if (and) query = query.where((eb) => eb.and(and.map((expr) => expr(eb)))); - if (or) query = query.where((eb) => eb.or(or.map((expr) => expr(eb)))); - const res = (await query.executeTakeFirst()).numDeletedRows; - return res > Number.MAX_SAFE_INTEGER ? Number.MAX_SAFE_INTEGER : Number(res); - }, - options: config - }; - }; - }; - let adapterOptions = null; - adapterOptions = { - config: { - adapterId: "kysely", - adapterName: "Kysely Adapter", - usePlural: config?.usePlural, - debugLogs: config?.debugLogs, - supportsBooleans: config?.type === "sqlite" || config?.type === "mssql" || config?.type === "mysql" || !config?.type ? false : true, - supportsDates: config?.type === "sqlite" || config?.type === "mssql" || !config?.type ? false : true, - supportsJSON: config?.type === "postgres" ? true : false, - supportsArrays: false, - supportsUUIDs: config?.type === "postgres" ? true : false, - transaction: config?.transaction ? (cb) => db.transaction().execute((trx) => { - return cb(createAdapterFactory({ - config: adapterOptions.config, - adapter: createCustomAdapter(trx) - })(lazyOptions)); - }) : false - }, - adapter: createCustomAdapter(db) - }; - const adapter = createAdapterFactory(adapterOptions); - return (options) => { - lazyOptions = options; - return adapter(options); - }; -}; -export { - createKyselyAdapter, - g as getKyselyDatabaseType, - kyselyAdapter -}; diff --git a/.svelte-kit/adapter-node/chunks/internal.js b/.svelte-kit/adapter-node/chunks/internal.js deleted file mode 100644 index 55b3eeb..0000000 --- a/.svelte-kit/adapter-node/chunks/internal.js +++ /dev/null @@ -1,127 +0,0 @@ -import { r as root } from "./root.js"; -import "./environment.js"; -import "./server.js"; -import "./shared-server.js"; -let read_implementation = null; -function set_read_implementation(fn) { - read_implementation = fn; -} -function set_manifest(_) { -} -const options = { - app_template_contains_nonce: false, - async: false, - csp: { "mode": "auto", "directives": { "upgrade-insecure-requests": false, "block-all-mixed-content": false }, "reportOnly": { "upgrade-insecure-requests": false, "block-all-mixed-content": false } }, - csrf_check_origin: true, - csrf_trusted_origins: [], - embedded: false, - env_public_prefix: "PUBLIC_", - env_private_prefix: "", - hash_routing: false, - hooks: null, - // added lazily, via `get_hooks` - preload_strategy: "modulepreload", - root, - service_worker: false, - service_worker_options: void 0, - templates: { - app: ({ head, body, assets, nonce, env }) => '\n\n \n \n \n \n \n \n Vash Esports\n ' + head + '\n \n \n
' + body + "
\n \n\n", - error: ({ status, message }) => '\n\n \n \n ' + message + ` - - - - -
- ` + status + '\n
\n

' + message + "

\n
\n
\n \n\n" - }, - version_hash: "12t8tv8" -}; -async function get_hooks() { - let handle; - let handleFetch; - let handleError; - let handleValidationError; - let init; - ({ handle, handleFetch, handleError, handleValidationError, init } = await import("../entries/hooks.server.js")); - let reroute; - let transport; - return { - handle, - handleFetch, - handleError, - handleValidationError, - init, - reroute, - transport - }; -} -export { - set_manifest as a, - get_hooks as g, - options as o, - read_implementation as r, - set_read_implementation as s -}; diff --git a/.svelte-kit/adapter-node/chunks/node-sqlite-dialect.js b/.svelte-kit/adapter-node/chunks/node-sqlite-dialect.js deleted file mode 100644 index 68f03bc..0000000 --- a/.svelte-kit/adapter-node/chunks/node-sqlite-dialect.js +++ /dev/null @@ -1,155 +0,0 @@ -import { CompiledQuery, DefaultQueryCompiler, DEFAULT_MIGRATION_TABLE, DEFAULT_MIGRATION_LOCK_TABLE, sql } from "kysely"; -var NodeSqliteAdapter = class { - get supportsCreateIfNotExists() { - return true; - } - get supportsTransactionalDdl() { - return false; - } - get supportsReturning() { - return true; - } - async acquireMigrationLock() { - } - async releaseMigrationLock() { - } - get supportsOutput() { - return true; - } -}; -var NodeSqliteDriver = class { - #config; - #connectionMutex = new ConnectionMutex(); - #db; - #connection; - constructor(config) { - this.#config = { ...config }; - } - async init() { - this.#db = this.#config.database; - this.#connection = new NodeSqliteConnection(this.#db); - if (this.#config.onCreateConnection) await this.#config.onCreateConnection(this.#connection); - } - async acquireConnection() { - await this.#connectionMutex.lock(); - return this.#connection; - } - async beginTransaction(connection) { - await connection.executeQuery(CompiledQuery.raw("begin")); - } - async commitTransaction(connection) { - await connection.executeQuery(CompiledQuery.raw("commit")); - } - async rollbackTransaction(connection) { - await connection.executeQuery(CompiledQuery.raw("rollback")); - } - async releaseConnection() { - this.#connectionMutex.unlock(); - } - async destroy() { - this.#db?.close(); - } -}; -var NodeSqliteConnection = class { - #db; - constructor(db) { - this.#db = db; - } - executeQuery(compiledQuery) { - const { sql: sql$1, parameters } = compiledQuery; - const rows = this.#db.prepare(sql$1).all(...parameters); - return Promise.resolve({ rows }); - } - async *streamQuery() { - throw new Error("Streaming query is not supported by SQLite driver."); - } -}; -var ConnectionMutex = class { - #promise; - #resolve; - async lock() { - while (await this.#promise) await this.#promise; - this.#promise = new Promise((resolve) => { - this.#resolve = resolve; - }); - } - unlock() { - const resolve = this.#resolve; - this.#promise = void 0; - this.#resolve = void 0; - resolve?.(); - } -}; -var NodeSqliteIntrospector = class { - #db; - constructor(db) { - this.#db = db; - } - async getSchemas() { - return []; - } - async getTables(options = { withInternalKyselyTables: false }) { - let query = this.#db.selectFrom("sqlite_schema").where("type", "=", "table").where("name", "not like", "sqlite_%").select("name").$castTo(); - if (!options.withInternalKyselyTables) query = query.where("name", "!=", DEFAULT_MIGRATION_TABLE).where("name", "!=", DEFAULT_MIGRATION_LOCK_TABLE); - const tables = await query.execute(); - return Promise.all(tables.map(({ name }) => this.#getTableMetadata(name))); - } - async getMetadata(options) { - return { tables: await this.getTables(options) }; - } - async #getTableMetadata(table) { - const db = this.#db; - const autoIncrementCol = (await db.selectFrom("sqlite_master").where("name", "=", table).select("sql").$castTo().execute())[0]?.sql?.split(/[\(\),]/)?.find((it) => it.toLowerCase().includes("autoincrement"))?.split(/\s+/)?.[0]?.replace(/["`]/g, ""); - return { - name: table, - columns: (await db.selectFrom(sql`pragma_table_info(${table})`.as("table_info")).select([ - "name", - "type", - "notnull", - "dflt_value" - ]).execute()).map((col) => ({ - name: col.name, - dataType: col.type, - isNullable: !col.notnull, - isAutoIncrementing: col.name === autoIncrementCol, - hasDefaultValue: col.dflt_value != null - })), - isView: true - }; - } -}; -var NodeSqliteQueryCompiler = class extends DefaultQueryCompiler { - getCurrentParameterPlaceholder() { - return "?"; - } - getLeftIdentifierWrapper() { - return '"'; - } - getRightIdentifierWrapper() { - return '"'; - } - getAutoIncrement() { - return "autoincrement"; - } -}; -var NodeSqliteDialect = class { - #config; - constructor(config) { - this.#config = { ...config }; - } - createDriver() { - return new NodeSqliteDriver(this.#config); - } - createQueryCompiler() { - return new NodeSqliteQueryCompiler(); - } - createAdapter() { - return new NodeSqliteAdapter(); - } - createIntrospector(db) { - return new NodeSqliteIntrospector(db); - } -}; -export { - NodeSqliteDialect -}; diff --git a/.svelte-kit/adapter-node/chunks/orchestrator.js b/.svelte-kit/adapter-node/chunks/orchestrator.js deleted file mode 100644 index da259e9..0000000 --- a/.svelte-kit/adapter-node/chunks/orchestrator.js +++ /dev/null @@ -1,448 +0,0 @@ -import { d as db, b as match, u as user, g as matchGame } from "./index2.js"; -import { eq } from "drizzle-orm"; -import { g as getMatchFull, M as MATCH_STATES, s as submitRoll, p as pickMap, d as submitGameScores } from "./engine.js"; -import { b as private_env } from "./shared-server.js"; -let client = null; -let connecting = null; -async function getClient() { - if (client?.isConnected?.()) return client; - if (connecting) { - await connecting; - return client; - } - if (!private_env.OSU_IRC_USERNAME || !private_env.OSU_IRC_PASSWORD) { - throw new Error("OSU_IRC_USERNAME and OSU_IRC_PASSWORD must be set in .env"); - } - const banchoModule = await import("bancho.js"); - const BanchoClient = banchoModule.BanchoClient ?? banchoModule.default?.BanchoClient ?? banchoModule.default; - client = new BanchoClient({ - username: private_env.OSU_IRC_USERNAME, - password: private_env.OSU_IRC_PASSWORD - }); - connecting = client.connect().then(() => { - console.log("[Bancho] Connected as", private_env.OSU_IRC_USERNAME); - connecting = null; - }); - await connecting; - return client; -} -class TournamentLobby { - channel = null; - channelName = ""; - osuMatchId = 0; - // Score collection - collectedScores = []; - matchFinishedResolve = null; - // Ready tracking - allReadyResolve = null; - // Event callbacks (set by orchestrator) - onRollResult = null; - onPickCommand = null; - /** - * Create a new multiplayer lobby via !mp make. - */ - async create(name) { - const c = await getClient(); - return new Promise((resolve, reject) => { - const timeout = setTimeout( - () => reject(new Error("Lobby creation timed out")), - 15e3 - ); - const banchoBot = c.getUser("BanchoBot"); - const onPM = (msg) => { - const text = msg.message ?? String(msg); - const m = text.match(/https:\/\/osu\.ppy\.sh\/mp\/(\d+)/); - if (m) { - clearTimeout(timeout); - banchoBot.removeListener("message", onPM); - this.osuMatchId = parseInt(m[1]); - this.channelName = `#mp_${this.osuMatchId}`; - this.joinChannel(c).then( - () => resolve({ matchId: this.osuMatchId, channel: this.channelName }) - ); - } - }; - banchoBot.on("message", onPM); - banchoBot.sendMessage(`!mp make ${name}`); - }); - } - async joinChannel(c) { - this.channel = c.getChannel(this.channelName); - await this.channel.join(); - this.channel.on("message", (msg) => { - const text = msg.message ?? String(msg); - const sender = msg.user?.ircUsername ?? ""; - if (sender === "BanchoBot") { - this.parseBanchoMessage(text); - } else if (sender) { - this.parsePlayerMessage(sender, text); - } - }); - } - // ── Message Parsing ───────────────────────────────────────────────── - parseBanchoMessage(text) { - const scoreMatch = text.match( - /^(.+?) finished playing \(Score: ([\d,]+).*?(PASSED|FAILED)\)/i - ); - if (scoreMatch) { - this.collectedScores.push({ - username: scoreMatch[1].trim(), - score: parseInt(scoreMatch[2].replace(/,/g, "")), - passed: scoreMatch[3] === "PASSED" - }); - console.log(`[Bancho] Score: ${scoreMatch[1].trim()} = ${scoreMatch[2]}`); - return; - } - if (text.includes("The match has finished!")) { - console.log("[Bancho] Game finished. Scores:", this.collectedScores); - if (this.matchFinishedResolve) { - this.matchFinishedResolve([...this.collectedScores]); - this.matchFinishedResolve = null; - } - this.collectedScores = []; - return; - } - const rollMatch = text.match(/^(.+?) rolls (\d+) point\(s\)/); - if (rollMatch) { - const username = rollMatch[1].trim(); - const value = parseInt(rollMatch[2]); - console.log(`[Bancho] Roll: ${username} = ${value}`); - if (this.onRollResult) { - this.onRollResult(username, value); - } - return; - } - if (text.includes("All players are ready")) { - console.log("[Bancho] All players ready"); - if (this.allReadyResolve) { - this.allReadyResolve(); - this.allReadyResolve = null; - } - return; - } - } - parsePlayerMessage(sender, text) { - const pickMatch = text.match(/^!pick\s+([A-Z]{2})(\d*)/i); - if (pickMatch) { - const category = pickMatch[1].toUpperCase(); - const num = pickMatch[2] ? parseInt(pickMatch[2]) : 1; - const label = `${category}${num}`; - console.log(`[Bancho] Pick command from ${sender}: ${label}`); - if (this.onPickCommand) { - this.onPickCommand(sender, label); - } - return; - } - } - // ── IRC Commands ──────────────────────────────────────────────────── - async send(cmd) { - if (!this.channel) throw new Error("Lobby not created"); - console.log(`[Bancho] ${this.channelName} > ${cmd}`); - await this.channel.sendMessage(cmd); - } - async invite(username) { - await this.send(`!mp invite ${username.replace(/ /g, "_")}`); - } - async setProperties(teamMode, scoreMode, size) { - await this.send(`!mp set ${teamMode} ${scoreMode} ${size}`); - } - async setMap(beatmapId, playmode = 0) { - await this.send(`!mp map ${beatmapId} ${playmode}`); - } - async setMods(mods) { - const filtered = mods.filter((m) => !["NM", "TB", "None", "NF"].includes(m)); - if (mods.includes("FM") || mods.includes("Freemod")) { - await this.send("!mp mods Freemod NF"); - } else if (filtered.length > 0) { - await this.send(`!mp mods NF ${filtered.join(" ")}`); - } else { - await this.send("!mp mods NF"); - } - } - async startGame(delaySec = 5) { - await this.send(`!mp start ${delaySec}`); - } - async close() { - try { - await this.send("!mp close"); - } catch { - } - } - async chat(message) { - await this.send(message); - } - // ── Async Waiters ─────────────────────────────────────────────────── - /** - * Wait for all players to click "Ready" in osu! client. - * BanchoBot sends "All players are ready" when they do. - */ - waitForReady(timeoutMs = 18e4) { - return new Promise((resolve, reject) => { - const t = setTimeout(() => { - this.allReadyResolve = null; - reject(new Error("Timed out waiting for players to ready")); - }, timeoutMs); - this.allReadyResolve = () => { - clearTimeout(t); - resolve(); - }; - }); - } - /** - * Wait for "The match has finished!" and return all player scores. - */ - waitForScores(timeoutMs = 6e5) { - this.collectedScores = []; - return new Promise((resolve, reject) => { - const t = setTimeout(() => { - this.matchFinishedResolve = null; - reject(new Error("Timed out waiting for match scores")); - }, timeoutMs); - this.matchFinishedResolve = (scores) => { - clearTimeout(t); - resolve(scores); - }; - }); - } -} -const lobbies = /* @__PURE__ */ new Map(); -function getLobby(matchId) { - return lobbies.get(matchId); -} -function setLobby(matchId, lobby) { - lobbies.set(matchId, lobby); -} -function removeLobby(matchId) { - lobbies.delete(matchId); -} -function sleep(ms) { - return new Promise((r) => setTimeout(r, ms)); -} -async function initMatchLobby(matchId) { - const m = await getMatchFull(matchId); - const config = m.config; - const lobby = new TournamentLobby(); - const lobbyName = `VASH: (${m.participants[0]?.team.name}) vs (${m.participants[1]?.team.name})`; - console.log(`[Orchestrator] Creating lobby: ${lobbyName}`); - const { matchId: osuId, channel } = await lobby.create(lobbyName); - console.log(`[Orchestrator] Created ${channel} (osu mp/${osuId})`); - setLobby(matchId, lobby); - await db.update(match).set({ state: MATCH_STATES.LOBBY, osuLobbyId: osuId, startedAt: /* @__PURE__ */ new Date() }).where(eq(match.id, matchId)); - const scoreMode = config.scoringType === "score_v2" ? 3 : config.scoringType === "accuracy" ? 1 : config.scoringType === "combo" ? 2 : 0; - await lobby.setProperties(0, scoreMode, config.teamSize * 2); - await lobby.send("!mp password"); - await sleep(500); - const invited = /* @__PURE__ */ new Set(); - for (const p of m.participants) { - for (const pl of p.players) { - const u = await db.query.user.findFirst({ where: eq(user.id, pl.userId) }); - if (u?.name && !invited.has(u.name.toLowerCase())) { - await lobby.invite(u.name); - invited.add(u.name.toLowerCase()); - console.log(`[Orchestrator] Invited ${u.name}`); - await sleep(300); - } - } - } - setupChatHandlers(matchId, lobby); - await lobby.chat( - `Welcome! BO${config.bestOf}. Type !roll to decide pick order, or use the web UI.` - ); - await db.update(match).set({ state: MATCH_STATES.ROLLING }).where(eq(match.id, matchId)); - return { osuMatchId: osuId, channel }; -} -function setupChatHandlers(matchId, lobby) { - lobby.onRollResult = async (username, value) => { - try { - const m = await getMatchFull(matchId); - if (m.state !== MATCH_STATES.ROLLING) { - await lobby.chat(`Rolls are not active right now.`); - return; - } - let targetParticipant = null; - for (const p of m.participants) { - for (const pl of p.players) { - const u = await db.query.user.findFirst({ where: eq(user.id, pl.userId) }); - if (u?.name?.toLowerCase() === username.toLowerCase().replace(/_/g, " ")) { - if (p.rollValue === null) { - targetParticipant = p; - break; - } else if (!targetParticipant) { - const unrolled = m.participants.find((pp) => pp.rollValue === null); - if (unrolled) targetParticipant = unrolled; - } - } - } - if (targetParticipant?.rollValue === null) break; - } - if (!targetParticipant || targetParticipant.rollValue !== null) { - await lobby.chat(`${username}: already rolled or not in this match.`); - return; - } - await submitRoll(matchId, targetParticipant.id, value); - console.log(`[Orchestrator] IRC roll: ${username} = ${value}`); - const updated = await getMatchFull(matchId); - if (updated.state === MATCH_STATES.PICKING) { - const sorted = [...updated.participants].sort( - (a, b) => (a.pickOrder ?? 99) - (b.pickOrder ?? 99) - ); - await lobby.chat( - `Rolls complete! ${sorted[0]?.team.name} picks first. Use !pick (e.g. !pick NM1) or pick in web UI.` - ); - } - } catch (err) { - console.error("[Orchestrator] IRC roll error:", err.message); - } - }; - lobby.onPickCommand = async (username, slotLabel) => { - try { - const m = await getMatchFull(matchId); - if (m.state !== MATCH_STATES.PICKING) { - await lobby.chat(`Picks are not active right now.`); - return; - } - const labelMatch = slotLabel.match(/^([A-Z]{2})(\d+)$/); - if (!labelMatch) { - await lobby.chat(`${username}: Invalid slot. Use format like NM1, HD2, DT1.`); - return; - } - const category = labelMatch[1]; - const order = parseInt(labelMatch[2]); - const sorted = [...m.participants].sort( - (a, b) => (a.pickOrder ?? 99) - (b.pickOrder ?? 99) - ); - const expectedIdx = m.games.length % sorted.length; - const expectedPicker = sorted[expectedIdx]; - let isPickerTurn = false; - if (expectedPicker) { - for (const pl of expectedPicker.players) { - const u = await db.query.user.findFirst({ where: eq(user.id, pl.userId) }); - if (u?.name?.toLowerCase() === username.toLowerCase().replace(/_/g, " ")) { - isPickerTurn = true; - break; - } - } - } - if (!isPickerTurn && m.participants[0]?.teamId === m.participants[1]?.teamId) { - isPickerTurn = true; - } - if (!isPickerTurn) { - await lobby.chat(`${username}: It's not your turn to pick.`); - return; - } - const slot = m.mappool?.slots?.find( - (s) => s.category === category && s.orderInCategory === order - ); - if (!slot) { - await lobby.chat(`${username}: Slot ${slotLabel} not found in this mappool.`); - return; - } - const alreadyPlayed = m.games.some((g) => g.mappoolSlotId === slot.id); - if (alreadyPlayed) { - await lobby.chat(`${username}: ${slotLabel} has already been played.`); - return; - } - const game = await pickMap(matchId, expectedPicker.id, slot.id); - console.log(`[Orchestrator] IRC pick: ${username} picked ${slotLabel}`); - playPickedMap(matchId, game.id).catch( - (err) => console.error("[Orchestrator] IRC play failed:", err.message) - ); - } catch (err) { - console.error("[Orchestrator] IRC pick error:", err.message); - await lobby.chat(`Error: ${err.message}`).catch(() => { - }); - } - }; -} -async function playPickedMap(matchId, matchGameId) { - const lobby = getLobby(matchId); - if (!lobby) { - console.warn("[Orchestrator] No IRC lobby for", matchId, "— skipping IRC"); - return; - } - const game = await db.query.matchGame.findFirst({ - where: eq(matchGame.id, matchGameId), - with: { slot: true } - }); - if (!game) throw new Error("Game not found"); - const slot = game.slot; - await lobby.setMap(slot.beatmapId); - await sleep(1e3); - await lobby.setMods(slot.mods); - await sleep(500); - await lobby.chat( - `Playing ${slot.category}${slot.orderInCategory}. Ready up! (Game starts when all players are ready)` - ); - try { - await lobby.waitForReady(); - await lobby.chat("All ready — starting in 5s!"); - await lobby.startGame(5); - } catch (err) { - console.warn("[Orchestrator] Ready timeout:", err.message); - await lobby.chat("Ready timed out. Use the web UI to force start, or ready up!"); - return; - } - collectScores(matchId, matchGameId, lobby).catch( - (err) => console.error("[Orchestrator] Score collection failed:", err) - ); -} -async function forceStartGame(matchId) { - const lobby = getLobby(matchId); - if (!lobby) return; - await lobby.chat("Force starting in 10s!"); - await lobby.startGame(10); -} -async function collectScores(matchId, matchGameId, lobby) { - const ircScores = await lobby.waitForScores(); - console.log(`[Orchestrator] Scores for game ${matchGameId}:`, ircScores); - const m = await getMatchFull(matchId); - const scores = []; - for (const irc of ircScores) { - for (const participant of m.participants) { - for (const player of participant.players) { - const u = await db.query.user.findFirst({ where: eq(user.id, player.userId) }); - const ircName = irc.username.toLowerCase().replace(/_/g, " "); - const dbName = u?.name?.toLowerCase(); - if (dbName && (dbName === ircName || dbName === irc.username.toLowerCase())) { - scores.push({ playerId: player.id, score: irc.score, passed: irc.passed }); - } - } - } - } - if (scores.length === 0) { - console.warn("[Orchestrator] No scores matched any IRC usernames"); - return; - } - await submitGameScores(matchGameId, scores); - const updated = await getMatchFull(matchId); - if (updated.state === MATCH_STATES.FINISHED) { - const winner = updated.participants.find((p) => p.teamId === updated.winnerId); - await lobby.chat(`GG! ${winner?.team.name ?? "?"} wins the match!`); - await sleep(5e3); - await lobby.close(); - removeLobby(matchId); - } else { - const sorted = [...updated.participants].sort( - (a, b) => (a.pickOrder ?? 99) - (b.pickOrder ?? 99) - ); - const nextIdx = updated.games.length % sorted.length; - const nextPicker = sorted[nextIdx]; - await lobby.chat( - `${nextPicker?.team.name}'s turn to pick. Use !pick (e.g. !pick HD1) or pick in web UI.` - ); - } -} -async function closeLobby(matchId) { - const lobby = getLobby(matchId); - if (lobby) { - await lobby.close(); - removeLobby(matchId); - } -} -export { - closeLobby as c, - forceStartGame as f, - getLobby as g, - initMatchLobby as i, - playPickedMap as p -}; diff --git a/.svelte-kit/adapter-node/chunks/query.js b/.svelte-kit/adapter-node/chunks/query.js deleted file mode 100644 index a14a6fa..0000000 --- a/.svelte-kit/adapter-node/chunks/query.js +++ /dev/null @@ -1,258 +0,0 @@ -import { get_request_store, with_request_store } from "@sveltejs/kit/internal/server"; -import { z as stringify_remote_arg, f as create_remote_key, h as handle_error_and_jsonify } from "./shared.js"; -import { p as prerendering } from "./environment.js"; -import { parse } from "devalue"; -import { error } from "@sveltejs/kit"; -import { HttpError, SvelteKitError } from "@sveltejs/kit/internal"; -function create_validator(validate_or_fn, maybe_fn) { - if (!maybe_fn) { - return (arg) => { - if (arg !== void 0) { - error(400, "Bad Request"); - } - }; - } - if (validate_or_fn === "unchecked") { - return (arg) => arg; - } - if ("~standard" in validate_or_fn) { - return async (arg) => { - const { event, state } = get_request_store(); - const result = await validate_or_fn["~standard"].validate(arg); - if (result.issues) { - error( - 400, - await state.handleValidationError({ - issues: result.issues, - event - }) - ); - } - return result.value; - }; - } - throw new Error( - 'Invalid validator passed to remote function. Expected "unchecked" or a Standard Schema (https://standardschema.dev)' - ); -} -async function get_response(info, arg, state, get_result) { - await 0; - const cache = get_cache(info, state); - return cache[stringify_remote_arg(arg, state.transport)] ??= get_result(); -} -function parse_remote_response(data, transport) { - const revivers = {}; - for (const key in transport) { - revivers[key] = transport[key].decode; - } - return parse(data, revivers); -} -async function run_remote_function(event, state, allow_cookies, get_input, fn) { - const store = { - event: { - ...event, - setHeaders: () => { - throw new Error("setHeaders is not allowed in remote functions"); - }, - cookies: { - ...event.cookies, - set: (name, value, opts) => { - if (!allow_cookies) { - throw new Error("Cannot set cookies in `query` or `prerender` functions"); - } - if (opts.path && !opts.path.startsWith("/")) { - throw new Error("Cookies set in remote functions must have an absolute path"); - } - return event.cookies.set(name, value, opts); - }, - delete: (name, opts) => { - if (!allow_cookies) { - throw new Error("Cannot delete cookies in `query` or `prerender` functions"); - } - if (opts.path && !opts.path.startsWith("/")) { - throw new Error("Cookies deleted in remote functions must have an absolute path"); - } - return event.cookies.delete(name, opts); - } - } - }, - state: { - ...state, - is_in_remote_function: true - } - }; - const input = await with_request_store(store, get_input); - return with_request_store(store, () => fn(input)); -} -function get_cache(info, state = get_request_store().state) { - let cache = state.remote_data?.get(info); - if (cache === void 0) { - cache = {}; - (state.remote_data ??= /* @__PURE__ */ new Map()).set(info, cache); - } - return cache; -} -// @__NO_SIDE_EFFECTS__ -function query(validate_or_fn, maybe_fn) { - const fn = maybe_fn ?? validate_or_fn; - const validate = create_validator(validate_or_fn, maybe_fn); - const __ = { type: "query", id: "", name: "" }; - const wrapper = (arg) => { - if (prerendering) { - throw new Error( - `Cannot call query '${__.name}' while prerendering, as prerendered pages need static data. Use 'prerender' from $app/server instead` - ); - } - const { event, state } = get_request_store(); - const get_remote_function_result = () => run_remote_function(event, state, false, () => validate(arg), fn); - const promise = get_response(__, arg, state, get_remote_function_result); - promise.catch(() => { - }); - promise.set = (value) => update_refresh_value(get_refresh_context(__, "set", arg), value); - promise.refresh = () => { - const refresh_context = get_refresh_context(__, "refresh", arg); - const is_immediate_refresh = !refresh_context.cache[refresh_context.cache_key]; - const value = is_immediate_refresh ? promise : get_remote_function_result(); - return update_refresh_value(refresh_context, value, is_immediate_refresh); - }; - promise.withOverride = () => { - throw new Error(`Cannot call '${__.name}.withOverride()' on the server`); - }; - return ( - /** @type {RemoteQuery} */ - promise - ); - }; - Object.defineProperty(wrapper, "__", { value: __ }); - return wrapper; -} -// @__NO_SIDE_EFFECTS__ -function batch(validate_or_fn, maybe_fn) { - const fn = maybe_fn ?? validate_or_fn; - const validate = create_validator(validate_or_fn, maybe_fn); - const __ = { - type: "query_batch", - id: "", - name: "", - run: async (args, options) => { - const { event, state } = get_request_store(); - return run_remote_function( - event, - state, - false, - async () => Promise.all(args.map(validate)), - async (input) => { - const get_result = await fn(input); - return Promise.all( - input.map(async (arg, i) => { - try { - return { type: "result", data: get_result(arg, i) }; - } catch (error2) { - return { - type: "error", - error: await handle_error_and_jsonify(event, state, options, error2), - status: error2 instanceof HttpError || error2 instanceof SvelteKitError ? error2.status : 500 - }; - } - }) - ); - } - ); - } - }; - let batching = { args: [], resolvers: [] }; - const wrapper = (arg) => { - if (prerendering) { - throw new Error( - `Cannot call query.batch '${__.name}' while prerendering, as prerendered pages need static data. Use 'prerender' from $app/server instead` - ); - } - const { event, state } = get_request_store(); - const get_remote_function_result = () => { - return new Promise((resolve, reject) => { - batching.args.push(arg); - batching.resolvers.push({ resolve, reject }); - if (batching.args.length > 1) return; - setTimeout(async () => { - const batched = batching; - batching = { args: [], resolvers: [] }; - try { - return await run_remote_function( - event, - state, - false, - async () => Promise.all(batched.args.map(validate)), - async (input) => { - const get_result = await fn(input); - for (let i = 0; i < batched.resolvers.length; i++) { - try { - batched.resolvers[i].resolve(get_result(input[i], i)); - } catch (error2) { - batched.resolvers[i].reject(error2); - } - } - } - ); - } catch (error2) { - for (const resolver of batched.resolvers) { - resolver.reject(error2); - } - } - }, 0); - }); - }; - const promise = get_response(__, arg, state, get_remote_function_result); - promise.catch(() => { - }); - promise.set = (value) => update_refresh_value(get_refresh_context(__, "set", arg), value); - promise.refresh = () => { - const refresh_context = get_refresh_context(__, "refresh", arg); - const is_immediate_refresh = !refresh_context.cache[refresh_context.cache_key]; - const value = is_immediate_refresh ? promise : get_remote_function_result(); - return update_refresh_value(refresh_context, value, is_immediate_refresh); - }; - promise.withOverride = () => { - throw new Error(`Cannot call '${__.name}.withOverride()' on the server`); - }; - return ( - /** @type {RemoteQuery} */ - promise - ); - }; - Object.defineProperty(wrapper, "__", { value: __ }); - return wrapper; -} -Object.defineProperty(query, "batch", { value: batch, enumerable: true }); -function get_refresh_context(__, action, arg) { - const { state } = get_request_store(); - const { refreshes } = state; - if (!refreshes) { - const name = __.type === "query_batch" ? `query.batch '${__.name}'` : `query '${__.name}'`; - throw new Error( - `Cannot call ${action} on ${name} because it is not executed in the context of a command/form remote function` - ); - } - const cache = get_cache(__, state); - const cache_key = stringify_remote_arg(arg, state.transport); - const refreshes_key = create_remote_key(__.id, cache_key); - return { __, state, refreshes, refreshes_key, cache, cache_key }; -} -function update_refresh_value({ __, refreshes, refreshes_key, cache, cache_key }, value, is_immediate_refresh = false) { - const promise = Promise.resolve(value); - if (!is_immediate_refresh) { - cache[cache_key] = promise; - } - if (__.id) { - refreshes[refreshes_key] = promise; - } - return promise.then(() => { - }); -} -export { - get_response as a, - create_validator as c, - get_cache as g, - parse_remote_response as p, - query as q, - run_remote_function as r -}; diff --git a/.svelte-kit/adapter-node/chunks/root.js b/.svelte-kit/adapter-node/chunks/root.js deleted file mode 100644 index c678a5c..0000000 --- a/.svelte-kit/adapter-node/chunks/root.js +++ /dev/null @@ -1,2713 +0,0 @@ -import { H as HYDRATION_ERROR, C as COMMENT_NODE, f as HYDRATION_END, h as HYDRATION_START, i as HYDRATION_START_ELSE, r as run_all, B as BOUNDARY_EFFECT, R as REACTION_RAN, E as ERROR_VALUE, j as EFFECT, k as CONNECTED, l as CLEAN, M as MAYBE_DIRTY, D as DIRTY, m as DERIVED, W as WAS_MARKED, I as INERT, o as BLOCK_EFFECT, U as UNINITIALIZED, p as deferred, q as BRANCH_EFFECT, t as ROOT_EFFECT, u as RENDER_EFFECT, v as MANAGED_EFFECT, w as HEAD_EFFECT, x as DESTROYED, A as ASYNC, y as includes, z as HYDRATION_START_FAILED, F as EFFECT_TRANSPARENT, G as EFFECT_PRESERVED, S as STALE_REACTION, n as noop, J as EAGER_EFFECT, K as STATE_SYMBOL, L as object_prototype, N as array_prototype, O as get_descriptor, P as get_prototype_of, Q as is_array, T as is_extensible, V as USER_EFFECT, X as REACTION_IS_UPDATING, Y as index_of, Z as define_property, _ as array_from, $ as is_passive_event, a0 as LEGACY_PROPS, a1 as render, a2 as setContext, d as derived } from "./index3.js"; -import { D as DEV } from "./false.js"; -function equals(value) { - return value === this.v; -} -function safe_not_equal(a, b) { - return a != a ? b == b : a !== b || a !== null && typeof a === "object" || typeof a === "function"; -} -function safe_equals(value) { - return !safe_not_equal(value, this.v); -} -function effect_update_depth_exceeded() { - { - throw new Error(`https://svelte.dev/e/effect_update_depth_exceeded`); - } -} -function hydration_failed() { - { - throw new Error(`https://svelte.dev/e/hydration_failed`); - } -} -function state_descriptors_fixed() { - { - throw new Error(`https://svelte.dev/e/state_descriptors_fixed`); - } -} -function state_prototype_fixed() { - { - throw new Error(`https://svelte.dev/e/state_prototype_fixed`); - } -} -function state_unsafe_mutation() { - { - throw new Error(`https://svelte.dev/e/state_unsafe_mutation`); - } -} -function svelte_boundary_reset_onerror() { - { - throw new Error(`https://svelte.dev/e/svelte_boundary_reset_onerror`); - } -} -function hydration_mismatch(location) { - { - console.warn(`https://svelte.dev/e/hydration_mismatch`); - } -} -function svelte_boundary_reset_noop() { - { - console.warn(`https://svelte.dev/e/svelte_boundary_reset_noop`); - } -} -let hydrating = false; -function set_hydrating(value) { - hydrating = value; -} -let hydrate_node; -function set_hydrate_node(node) { - if (node === null) { - hydration_mismatch(); - throw HYDRATION_ERROR; - } - return hydrate_node = node; -} -function hydrate_next() { - return set_hydrate_node(/* @__PURE__ */ get_next_sibling(hydrate_node)); -} -function next(count = 1) { - if (hydrating) { - var i = count; - var node = hydrate_node; - while (i--) { - node = /** @type {TemplateNode} */ - /* @__PURE__ */ get_next_sibling(node); - } - hydrate_node = node; - } -} -function skip_nodes(remove = true) { - var depth = 0; - var node = hydrate_node; - while (true) { - if (node.nodeType === COMMENT_NODE) { - var data = ( - /** @type {Comment} */ - node.data - ); - if (data === HYDRATION_END) { - if (depth === 0) return node; - depth -= 1; - } else if (data === HYDRATION_START || data === HYDRATION_START_ELSE || // "[1", "[2", etc. for if blocks - data[0] === "[" && !isNaN(Number(data.slice(1)))) { - depth += 1; - } - } - var next2 = ( - /** @type {TemplateNode} */ - /* @__PURE__ */ get_next_sibling(node) - ); - if (remove) node.remove(); - node = next2; - } -} -let tracing_mode_flag = false; -let component_context = null; -function set_component_context(context) { - component_context = context; -} -function push(props, runes = false, fn) { - component_context = { - p: component_context, - i: false, - c: null, - e: null, - s: props, - x: null, - l: null - }; -} -function pop(component) { - var context = ( - /** @type {ComponentContext} */ - component_context - ); - var effects = context.e; - if (effects !== null) { - context.e = null; - for (var fn of effects) { - create_user_effect(fn); - } - } - context.i = true; - component_context = context.p; - return ( - /** @type {T} */ - {} - ); -} -function is_runes() { - return true; -} -let micro_tasks = []; -function run_micro_tasks() { - var tasks = micro_tasks; - micro_tasks = []; - run_all(tasks); -} -function queue_micro_task(fn) { - if (micro_tasks.length === 0 && !is_flushing_sync) { - var tasks = micro_tasks; - queueMicrotask(() => { - if (tasks === micro_tasks) run_micro_tasks(); - }); - } - micro_tasks.push(fn); -} -function flush_tasks() { - while (micro_tasks.length > 0) { - run_micro_tasks(); - } -} -function handle_error(error) { - var effect = active_effect; - if (effect === null) { - active_reaction.f |= ERROR_VALUE; - return error; - } - if ((effect.f & REACTION_RAN) === 0 && (effect.f & EFFECT) === 0) { - throw error; - } - invoke_error_boundary(error, effect); -} -function invoke_error_boundary(error, effect) { - while (effect !== null) { - if ((effect.f & BOUNDARY_EFFECT) !== 0) { - if ((effect.f & REACTION_RAN) === 0) { - throw error; - } - try { - effect.b.error(error); - return; - } catch (e) { - error = e; - } - } - effect = effect.parent; - } - throw error; -} -const STATUS_MASK = -7169; -function set_signal_status(signal, status) { - signal.f = signal.f & STATUS_MASK | status; -} -function update_derived_status(derived2) { - if ((derived2.f & CONNECTED) !== 0 || derived2.deps === null) { - set_signal_status(derived2, CLEAN); - } else { - set_signal_status(derived2, MAYBE_DIRTY); - } -} -function clear_marked(deps) { - if (deps === null) return; - for (const dep of deps) { - if ((dep.f & DERIVED) === 0 || (dep.f & WAS_MARKED) === 0) { - continue; - } - dep.f ^= WAS_MARKED; - clear_marked( - /** @type {Derived} */ - dep.deps - ); - } -} -function defer_effect(effect, dirty_effects, maybe_dirty_effects) { - if ((effect.f & DIRTY) !== 0) { - dirty_effects.add(effect); - } else if ((effect.f & MAYBE_DIRTY) !== 0) { - maybe_dirty_effects.add(effect); - } - clear_marked(effect.deps); - set_signal_status(effect, CLEAN); -} -const batches = /* @__PURE__ */ new Set(); -let current_batch = null; -let batch_values = null; -let queued_root_effects = []; -let last_scheduled_effect = null; -let is_flushing = false; -let is_flushing_sync = false; -class Batch { - /** - * The current values of any sources that are updated in this batch - * They keys of this map are identical to `this.#previous` - * @type {Map} - */ - current = /* @__PURE__ */ new Map(); - /** - * The values of any sources that are updated in this batch _before_ those updates took place. - * They keys of this map are identical to `this.#current` - * @type {Map} - */ - previous = /* @__PURE__ */ new Map(); - /** - * When the batch is committed (and the DOM is updated), we need to remove old branches - * and append new ones by calling the functions added inside (if/each/key/etc) blocks - * @type {Set<() => void>} - */ - #commit_callbacks = /* @__PURE__ */ new Set(); - /** - * If a fork is discarded, we need to destroy any effects that are no longer needed - * @type {Set<(batch: Batch) => void>} - */ - #discard_callbacks = /* @__PURE__ */ new Set(); - /** - * The number of async effects that are currently in flight - */ - #pending = 0; - /** - * The number of async effects that are currently in flight, _not_ inside a pending boundary - */ - #blocking_pending = 0; - /** - * A deferred that resolves when the batch is committed, used with `settled()` - * TODO replace with Promise.withResolvers once supported widely enough - * @type {{ promise: Promise, resolve: (value?: any) => void, reject: (reason: unknown) => void } | null} - */ - #deferred = null; - /** - * Deferred effects (which run after async work has completed) that are DIRTY - * @type {Set} - */ - #dirty_effects = /* @__PURE__ */ new Set(); - /** - * Deferred effects that are MAYBE_DIRTY - * @type {Set} - */ - #maybe_dirty_effects = /* @__PURE__ */ new Set(); - /** - * A map of branches that still exist, but will be destroyed when this batch - * is committed — we skip over these during `process`. - * The value contains child effects that were dirty/maybe_dirty before being reset, - * so they can be rescheduled if the branch survives. - * @type {Map} - */ - #skipped_branches = /* @__PURE__ */ new Map(); - is_fork = false; - #decrement_queued = false; - #is_deferred() { - return this.is_fork || this.#blocking_pending > 0; - } - /** - * Add an effect to the #skipped_branches map and reset its children - * @param {Effect} effect - */ - skip_effect(effect) { - if (!this.#skipped_branches.has(effect)) { - this.#skipped_branches.set(effect, { d: [], m: [] }); - } - } - /** - * Remove an effect from the #skipped_branches map and reschedule - * any tracked dirty/maybe_dirty child effects - * @param {Effect} effect - */ - unskip_effect(effect) { - var tracked = this.#skipped_branches.get(effect); - if (tracked) { - this.#skipped_branches.delete(effect); - for (var e of tracked.d) { - set_signal_status(e, DIRTY); - schedule_effect(e); - } - for (e of tracked.m) { - set_signal_status(e, MAYBE_DIRTY); - schedule_effect(e); - } - } - } - /** - * - * @param {Effect[]} root_effects - */ - process(root_effects) { - queued_root_effects = []; - this.apply(); - var effects = []; - var render_effects = []; - for (const root2 of root_effects) { - this.#traverse_effect_tree(root2, effects, render_effects); - } - if (this.#is_deferred()) { - this.#defer_effects(render_effects); - this.#defer_effects(effects); - for (const [e, t] of this.#skipped_branches) { - reset_branch(e, t); - } - } else { - for (const fn of this.#commit_callbacks) fn(); - this.#commit_callbacks.clear(); - if (this.#pending === 0) { - this.#commit(); - } - current_batch = null; - flush_queued_effects(render_effects); - flush_queued_effects(effects); - this.#dirty_effects.clear(); - this.#maybe_dirty_effects.clear(); - this.#deferred?.resolve(); - } - batch_values = null; - } - /** - * Traverse the effect tree, executing effects or stashing - * them for later execution as appropriate - * @param {Effect} root - * @param {Effect[]} effects - * @param {Effect[]} render_effects - */ - #traverse_effect_tree(root2, effects, render_effects) { - root2.f ^= CLEAN; - var effect = root2.first; - while (effect !== null) { - var flags2 = effect.f; - var is_branch = (flags2 & (BRANCH_EFFECT | ROOT_EFFECT)) !== 0; - var is_skippable_branch = is_branch && (flags2 & CLEAN) !== 0; - var skip = is_skippable_branch || (flags2 & INERT) !== 0 || this.#skipped_branches.has(effect); - if (!skip && effect.fn !== null) { - if (is_branch) { - effect.f ^= CLEAN; - } else if ((flags2 & EFFECT) !== 0) { - effects.push(effect); - } else if (is_dirty(effect)) { - if ((flags2 & BLOCK_EFFECT) !== 0) this.#maybe_dirty_effects.add(effect); - update_effect(effect); - } - var child = effect.first; - if (child !== null) { - effect = child; - continue; - } - } - while (effect !== null) { - var next2 = effect.next; - if (next2 !== null) { - effect = next2; - break; - } - effect = effect.parent; - } - } - } - /** - * @param {Effect[]} effects - */ - #defer_effects(effects) { - for (var i = 0; i < effects.length; i += 1) { - defer_effect(effects[i], this.#dirty_effects, this.#maybe_dirty_effects); - } - } - /** - * Associate a change to a given source with the current - * batch, noting its previous and current values - * @param {Source} source - * @param {any} value - */ - capture(source2, value) { - if (value !== UNINITIALIZED && !this.previous.has(source2)) { - this.previous.set(source2, value); - } - if ((source2.f & ERROR_VALUE) === 0) { - this.current.set(source2, source2.v); - batch_values?.set(source2, source2.v); - } - } - activate() { - current_batch = this; - this.apply(); - } - deactivate() { - if (current_batch !== this) return; - current_batch = null; - batch_values = null; - } - flush() { - this.activate(); - if (queued_root_effects.length > 0) { - flush_effects(); - if (current_batch !== null && current_batch !== this) { - return; - } - } else if (this.#pending === 0) { - this.process([]); - } - this.deactivate(); - } - discard() { - for (const fn of this.#discard_callbacks) fn(this); - this.#discard_callbacks.clear(); - } - #commit() { - if (batches.size > 1) { - this.previous.clear(); - var previous_batch_values = batch_values; - var is_earlier = true; - for (const batch of batches) { - if (batch === this) { - is_earlier = false; - continue; - } - const sources = []; - for (const [source2, value] of this.current) { - if (batch.current.has(source2)) { - if (is_earlier && value !== batch.current.get(source2)) { - batch.current.set(source2, value); - } else { - continue; - } - } - sources.push(source2); - } - if (sources.length === 0) { - continue; - } - const others = [...batch.current.keys()].filter((s) => !this.current.has(s)); - if (others.length > 0) { - var prev_queued_root_effects = queued_root_effects; - queued_root_effects = []; - const marked = /* @__PURE__ */ new Set(); - const checked = /* @__PURE__ */ new Map(); - for (const source2 of sources) { - mark_effects(source2, others, marked, checked); - } - if (queued_root_effects.length > 0) { - current_batch = batch; - batch.apply(); - for (const root2 of queued_root_effects) { - batch.#traverse_effect_tree(root2, [], []); - } - batch.deactivate(); - } - queued_root_effects = prev_queued_root_effects; - } - } - current_batch = null; - batch_values = previous_batch_values; - } - this.#skipped_branches.clear(); - batches.delete(this); - } - /** - * - * @param {boolean} blocking - */ - increment(blocking) { - this.#pending += 1; - if (blocking) this.#blocking_pending += 1; - } - /** - * - * @param {boolean} blocking - */ - decrement(blocking) { - this.#pending -= 1; - if (blocking) this.#blocking_pending -= 1; - if (this.#decrement_queued) return; - this.#decrement_queued = true; - queue_micro_task(() => { - this.#decrement_queued = false; - if (!this.#is_deferred()) { - this.revive(); - } else if (queued_root_effects.length > 0) { - this.flush(); - } - }); - } - revive() { - for (const e of this.#dirty_effects) { - this.#maybe_dirty_effects.delete(e); - set_signal_status(e, DIRTY); - schedule_effect(e); - } - for (const e of this.#maybe_dirty_effects) { - set_signal_status(e, MAYBE_DIRTY); - schedule_effect(e); - } - this.flush(); - } - /** @param {() => void} fn */ - oncommit(fn) { - this.#commit_callbacks.add(fn); - } - /** @param {(batch: Batch) => void} fn */ - ondiscard(fn) { - this.#discard_callbacks.add(fn); - } - settled() { - return (this.#deferred ??= deferred()).promise; - } - static ensure() { - if (current_batch === null) { - const batch = current_batch = new Batch(); - batches.add(current_batch); - if (!is_flushing_sync) { - queue_micro_task(() => { - if (current_batch !== batch) { - return; - } - batch.flush(); - }); - } - } - return current_batch; - } - apply() { - return; - } -} -function flushSync(fn) { - var was_flushing_sync = is_flushing_sync; - is_flushing_sync = true; - try { - var result; - if (fn) ; - while (true) { - flush_tasks(); - if (queued_root_effects.length === 0) { - current_batch?.flush(); - if (queued_root_effects.length === 0) { - last_scheduled_effect = null; - return ( - /** @type {T} */ - result - ); - } - } - flush_effects(); - } - } finally { - is_flushing_sync = was_flushing_sync; - } -} -function flush_effects() { - is_flushing = true; - var source_stacks = null; - try { - var flush_count = 0; - while (queued_root_effects.length > 0) { - var batch = Batch.ensure(); - if (flush_count++ > 1e3) { - var updates, entry; - if (DEV) ; - infinite_loop_guard(); - } - batch.process(queued_root_effects); - old_values.clear(); - if (DEV) ; - } - } finally { - queued_root_effects = []; - is_flushing = false; - last_scheduled_effect = null; - } -} -function infinite_loop_guard() { - try { - effect_update_depth_exceeded(); - } catch (error) { - invoke_error_boundary(error, last_scheduled_effect); - } -} -let eager_block_effects = null; -function flush_queued_effects(effects) { - var length = effects.length; - if (length === 0) return; - var i = 0; - while (i < length) { - var effect = effects[i++]; - if ((effect.f & (DESTROYED | INERT)) === 0 && is_dirty(effect)) { - eager_block_effects = /* @__PURE__ */ new Set(); - update_effect(effect); - if (effect.deps === null && effect.first === null && effect.nodes === null && effect.teardown === null && effect.ac === null) { - unlink_effect(effect); - } - if (eager_block_effects?.size > 0) { - old_values.clear(); - for (const e of eager_block_effects) { - if ((e.f & (DESTROYED | INERT)) !== 0) continue; - const ordered_effects = [e]; - let ancestor = e.parent; - while (ancestor !== null) { - if (eager_block_effects.has(ancestor)) { - eager_block_effects.delete(ancestor); - ordered_effects.push(ancestor); - } - ancestor = ancestor.parent; - } - for (let j = ordered_effects.length - 1; j >= 0; j--) { - const e2 = ordered_effects[j]; - if ((e2.f & (DESTROYED | INERT)) !== 0) continue; - update_effect(e2); - } - } - eager_block_effects.clear(); - } - } - } - eager_block_effects = null; -} -function mark_effects(value, sources, marked, checked) { - if (marked.has(value)) return; - marked.add(value); - if (value.reactions !== null) { - for (const reaction of value.reactions) { - const flags2 = reaction.f; - if ((flags2 & DERIVED) !== 0) { - mark_effects( - /** @type {Derived} */ - reaction, - sources, - marked, - checked - ); - } else if ((flags2 & (ASYNC | BLOCK_EFFECT)) !== 0 && (flags2 & DIRTY) === 0 && depends_on(reaction, sources, checked)) { - set_signal_status(reaction, DIRTY); - schedule_effect( - /** @type {Effect} */ - reaction - ); - } - } - } -} -function depends_on(reaction, sources, checked) { - const depends = checked.get(reaction); - if (depends !== void 0) return depends; - if (reaction.deps !== null) { - for (const dep of reaction.deps) { - if (includes.call(sources, dep)) { - return true; - } - if ((dep.f & DERIVED) !== 0 && depends_on( - /** @type {Derived} */ - dep, - sources, - checked - )) { - checked.set( - /** @type {Derived} */ - dep, - true - ); - return true; - } - } - } - checked.set(reaction, false); - return false; -} -function schedule_effect(signal) { - var effect = last_scheduled_effect = signal; - var boundary2 = effect.b; - if (boundary2?.is_pending && (signal.f & (EFFECT | RENDER_EFFECT | MANAGED_EFFECT)) !== 0 && (signal.f & REACTION_RAN) === 0) { - boundary2.defer_effect(signal); - return; - } - while (effect.parent !== null) { - effect = effect.parent; - var flags2 = effect.f; - if (is_flushing && effect === active_effect && (flags2 & BLOCK_EFFECT) !== 0 && (flags2 & HEAD_EFFECT) === 0 && (flags2 & REACTION_RAN) !== 0) { - return; - } - if ((flags2 & (ROOT_EFFECT | BRANCH_EFFECT)) !== 0) { - if ((flags2 & CLEAN) === 0) { - return; - } - effect.f ^= CLEAN; - } - } - queued_root_effects.push(effect); -} -function reset_branch(effect, tracked) { - if ((effect.f & BRANCH_EFFECT) !== 0 && (effect.f & CLEAN) !== 0) { - return; - } - if ((effect.f & DIRTY) !== 0) { - tracked.d.push(effect); - } else if ((effect.f & MAYBE_DIRTY) !== 0) { - tracked.m.push(effect); - } - set_signal_status(effect, CLEAN); - var e = effect.first; - while (e !== null) { - reset_branch(e, tracked); - e = e.next; - } -} -function createSubscriber(start) { - let subscribers = 0; - let version = source(0); - let stop; - return () => { - if (effect_tracking()) { - get(version); - render_effect(() => { - if (subscribers === 0) { - stop = untrack(() => start(() => increment(version))); - } - subscribers += 1; - return () => { - queue_micro_task(() => { - subscribers -= 1; - if (subscribers === 0) { - stop?.(); - stop = void 0; - increment(version); - } - }); - }; - }); - } - }; -} -var flags = EFFECT_TRANSPARENT | EFFECT_PRESERVED; -function boundary(node, props, children, transform_error) { - new Boundary(node, props, children, transform_error); -} -class Boundary { - /** @type {Boundary | null} */ - parent; - is_pending = false; - /** - * API-level transformError transform function. Transforms errors before they reach the `failed` snippet. - * Inherited from parent boundary, or defaults to identity. - * @type {(error: unknown) => unknown} - */ - transform_error; - /** @type {TemplateNode} */ - #anchor; - /** @type {TemplateNode | null} */ - #hydrate_open = hydrating ? hydrate_node : null; - /** @type {BoundaryProps} */ - #props; - /** @type {((anchor: Node) => void)} */ - #children; - /** @type {Effect} */ - #effect; - /** @type {Effect | null} */ - #main_effect = null; - /** @type {Effect | null} */ - #pending_effect = null; - /** @type {Effect | null} */ - #failed_effect = null; - /** @type {DocumentFragment | null} */ - #offscreen_fragment = null; - #local_pending_count = 0; - #pending_count = 0; - #pending_count_update_queued = false; - /** @type {Set} */ - #dirty_effects = /* @__PURE__ */ new Set(); - /** @type {Set} */ - #maybe_dirty_effects = /* @__PURE__ */ new Set(); - /** - * A source containing the number of pending async deriveds/expressions. - * Only created if `$effect.pending()` is used inside the boundary, - * otherwise updating the source results in needless `Batch.ensure()` - * calls followed by no-op flushes - * @type {Source | null} - */ - #effect_pending = null; - #effect_pending_subscriber = createSubscriber(() => { - this.#effect_pending = source(this.#local_pending_count); - return () => { - this.#effect_pending = null; - }; - }); - /** - * @param {TemplateNode} node - * @param {BoundaryProps} props - * @param {((anchor: Node) => void)} children - * @param {((error: unknown) => unknown) | undefined} [transform_error] - */ - constructor(node, props, children, transform_error) { - this.#anchor = node; - this.#props = props; - this.#children = (anchor) => { - var effect = ( - /** @type {Effect} */ - active_effect - ); - effect.b = this; - effect.f |= BOUNDARY_EFFECT; - children(anchor); - }; - this.parent = /** @type {Effect} */ - active_effect.b; - this.transform_error = transform_error ?? this.parent?.transform_error ?? ((e) => e); - this.#effect = block(() => { - if (hydrating) { - const comment = ( - /** @type {Comment} */ - this.#hydrate_open - ); - hydrate_next(); - const server_rendered_pending = comment.data === HYDRATION_START_ELSE; - const server_rendered_failed = comment.data.startsWith(HYDRATION_START_FAILED); - if (server_rendered_failed) { - const serialized_error = JSON.parse(comment.data.slice(HYDRATION_START_FAILED.length)); - this.#hydrate_failed_content(serialized_error); - } else if (server_rendered_pending) { - this.#hydrate_pending_content(); - } else { - this.#hydrate_resolved_content(); - } - } else { - this.#render(); - } - }, flags); - if (hydrating) { - this.#anchor = hydrate_node; - } - } - #hydrate_resolved_content() { - try { - this.#main_effect = branch(() => this.#children(this.#anchor)); - } catch (error) { - this.error(error); - } - } - /** - * @param {unknown} error The deserialized error from the server's hydration comment - */ - #hydrate_failed_content(error) { - const failed = this.#props.failed; - if (!failed) return; - this.#failed_effect = branch(() => { - failed( - this.#anchor, - () => error, - () => () => { - } - ); - }); - } - #hydrate_pending_content() { - const pending = this.#props.pending; - if (!pending) return; - this.is_pending = true; - this.#pending_effect = branch(() => pending(this.#anchor)); - queue_micro_task(() => { - var fragment = this.#offscreen_fragment = document.createDocumentFragment(); - var anchor = create_text(); - fragment.append(anchor); - this.#main_effect = this.#run(() => { - Batch.ensure(); - return branch(() => this.#children(anchor)); - }); - if (this.#pending_count === 0) { - this.#anchor.before(fragment); - this.#offscreen_fragment = null; - pause_effect( - /** @type {Effect} */ - this.#pending_effect, - () => { - this.#pending_effect = null; - } - ); - this.#resolve(); - } - }); - } - #render() { - try { - this.is_pending = this.has_pending_snippet(); - this.#pending_count = 0; - this.#local_pending_count = 0; - this.#main_effect = branch(() => { - this.#children(this.#anchor); - }); - if (this.#pending_count > 0) { - var fragment = this.#offscreen_fragment = document.createDocumentFragment(); - move_effect(this.#main_effect, fragment); - const pending = ( - /** @type {(anchor: Node) => void} */ - this.#props.pending - ); - this.#pending_effect = branch(() => pending(this.#anchor)); - } else { - this.#resolve(); - } - } catch (error) { - this.error(error); - } - } - #resolve() { - this.is_pending = false; - for (const e of this.#dirty_effects) { - set_signal_status(e, DIRTY); - schedule_effect(e); - } - for (const e of this.#maybe_dirty_effects) { - set_signal_status(e, MAYBE_DIRTY); - schedule_effect(e); - } - this.#dirty_effects.clear(); - this.#maybe_dirty_effects.clear(); - } - /** - * Defer an effect inside a pending boundary until the boundary resolves - * @param {Effect} effect - */ - defer_effect(effect) { - defer_effect(effect, this.#dirty_effects, this.#maybe_dirty_effects); - } - /** - * Returns `false` if the effect exists inside a boundary whose pending snippet is shown - * @returns {boolean} - */ - is_rendered() { - return !this.is_pending && (!this.parent || this.parent.is_rendered()); - } - has_pending_snippet() { - return !!this.#props.pending; - } - /** - * @template T - * @param {() => T} fn - */ - #run(fn) { - var previous_effect = active_effect; - var previous_reaction = active_reaction; - var previous_ctx = component_context; - set_active_effect(this.#effect); - set_active_reaction(this.#effect); - set_component_context(this.#effect.ctx); - try { - return fn(); - } catch (e) { - handle_error(e); - return null; - } finally { - set_active_effect(previous_effect); - set_active_reaction(previous_reaction); - set_component_context(previous_ctx); - } - } - /** - * Updates the pending count associated with the currently visible pending snippet, - * if any, such that we can replace the snippet with content once work is done - * @param {1 | -1} d - */ - #update_pending_count(d) { - if (!this.has_pending_snippet()) { - if (this.parent) { - this.parent.#update_pending_count(d); - } - return; - } - this.#pending_count += d; - if (this.#pending_count === 0) { - this.#resolve(); - if (this.#pending_effect) { - pause_effect(this.#pending_effect, () => { - this.#pending_effect = null; - }); - } - if (this.#offscreen_fragment) { - this.#anchor.before(this.#offscreen_fragment); - this.#offscreen_fragment = null; - } - } - } - /** - * Update the source that powers `$effect.pending()` inside this boundary, - * and controls when the current `pending` snippet (if any) is removed. - * Do not call from inside the class - * @param {1 | -1} d - */ - update_pending_count(d) { - this.#update_pending_count(d); - this.#local_pending_count += d; - if (!this.#effect_pending || this.#pending_count_update_queued) return; - this.#pending_count_update_queued = true; - queue_micro_task(() => { - this.#pending_count_update_queued = false; - if (this.#effect_pending) { - internal_set(this.#effect_pending, this.#local_pending_count); - } - }); - } - get_effect_pending() { - this.#effect_pending_subscriber(); - return get( - /** @type {Source} */ - this.#effect_pending - ); - } - /** @param {unknown} error */ - error(error) { - var onerror = this.#props.onerror; - let failed = this.#props.failed; - if (!onerror && !failed) { - throw error; - } - if (this.#main_effect) { - destroy_effect(this.#main_effect); - this.#main_effect = null; - } - if (this.#pending_effect) { - destroy_effect(this.#pending_effect); - this.#pending_effect = null; - } - if (this.#failed_effect) { - destroy_effect(this.#failed_effect); - this.#failed_effect = null; - } - if (hydrating) { - set_hydrate_node( - /** @type {TemplateNode} */ - this.#hydrate_open - ); - next(); - set_hydrate_node(skip_nodes()); - } - var did_reset = false; - var calling_on_error = false; - const reset = () => { - if (did_reset) { - svelte_boundary_reset_noop(); - return; - } - did_reset = true; - if (calling_on_error) { - svelte_boundary_reset_onerror(); - } - if (this.#failed_effect !== null) { - pause_effect(this.#failed_effect, () => { - this.#failed_effect = null; - }); - } - this.#run(() => { - Batch.ensure(); - this.#render(); - }); - }; - const handle_error_result = (transformed_error) => { - try { - calling_on_error = true; - onerror?.(transformed_error, reset); - calling_on_error = false; - } catch (error2) { - invoke_error_boundary(error2, this.#effect && this.#effect.parent); - } - if (failed) { - this.#failed_effect = this.#run(() => { - Batch.ensure(); - try { - return branch(() => { - var effect = ( - /** @type {Effect} */ - active_effect - ); - effect.b = this; - effect.f |= BOUNDARY_EFFECT; - failed( - this.#anchor, - () => transformed_error, - () => reset - ); - }); - } catch (error2) { - invoke_error_boundary( - error2, - /** @type {Effect} */ - this.#effect.parent - ); - return null; - } - }); - } - }; - queue_micro_task(() => { - var result; - try { - result = this.transform_error(error); - } catch (e) { - invoke_error_boundary(e, this.#effect && this.#effect.parent); - return; - } - if (result !== null && typeof result === "object" && typeof /** @type {any} */ - result.then === "function") { - result.then( - handle_error_result, - /** @param {unknown} e */ - (e) => invoke_error_boundary(e, this.#effect && this.#effect.parent) - ); - } else { - handle_error_result(result); - } - }); - } -} -function destroy_derived_effects(derived2) { - var effects = derived2.effects; - if (effects !== null) { - derived2.effects = null; - for (var i = 0; i < effects.length; i += 1) { - destroy_effect( - /** @type {Effect} */ - effects[i] - ); - } - } -} -function get_derived_parent_effect(derived2) { - var parent = derived2.parent; - while (parent !== null) { - if ((parent.f & DERIVED) === 0) { - return (parent.f & DESTROYED) === 0 ? ( - /** @type {Effect} */ - parent - ) : null; - } - parent = parent.parent; - } - return null; -} -function execute_derived(derived2) { - var value; - var prev_active_effect = active_effect; - set_active_effect(get_derived_parent_effect(derived2)); - { - try { - derived2.f &= ~WAS_MARKED; - destroy_derived_effects(derived2); - value = update_reaction(derived2); - } finally { - set_active_effect(prev_active_effect); - } - } - return value; -} -function update_derived(derived2) { - var value = execute_derived(derived2); - if (!derived2.equals(value)) { - derived2.wv = increment_write_version(); - if (!current_batch?.is_fork || derived2.deps === null) { - derived2.v = value; - if (derived2.deps === null) { - set_signal_status(derived2, CLEAN); - return; - } - } - } - if (is_destroying_effect) { - return; - } - if (batch_values !== null) { - if (effect_tracking() || current_batch?.is_fork) { - batch_values.set(derived2, value); - } - } else { - update_derived_status(derived2); - } -} -function freeze_derived_effects(derived2) { - if (derived2.effects === null) return; - for (const e of derived2.effects) { - if (e.teardown || e.ac) { - e.teardown?.(); - e.ac?.abort(STALE_REACTION); - e.teardown = noop; - e.ac = null; - remove_reactions(e, 0); - destroy_effect_children(e); - } - } -} -function unfreeze_derived_effects(derived2) { - if (derived2.effects === null) return; - for (const e of derived2.effects) { - if (e.teardown) { - update_effect(e); - } - } -} -let eager_effects = /* @__PURE__ */ new Set(); -const old_values = /* @__PURE__ */ new Map(); -let eager_effects_deferred = false; -function source(v, stack) { - var signal = { - f: 0, - // TODO ideally we could skip this altogether, but it causes type errors - v, - reactions: null, - equals, - rv: 0, - wv: 0 - }; - return signal; -} -// @__NO_SIDE_EFFECTS__ -function state(v, stack) { - const s = source(v); - push_reaction_value(s); - return s; -} -// @__NO_SIDE_EFFECTS__ -function mutable_source(initial_value, immutable = false, trackable = true) { - const s = source(initial_value); - if (!immutable) { - s.equals = safe_equals; - } - return s; -} -function set(source2, value, should_proxy = false) { - if (active_reaction !== null && // since we are untracking the function inside `$inspect.with` we need to add this check - // to ensure we error if state is set inside an inspect effect - (!untracking || (active_reaction.f & EAGER_EFFECT) !== 0) && is_runes() && (active_reaction.f & (DERIVED | BLOCK_EFFECT | ASYNC | EAGER_EFFECT)) !== 0 && (current_sources === null || !includes.call(current_sources, source2))) { - state_unsafe_mutation(); - } - let new_value = should_proxy ? proxy(value) : value; - return internal_set(source2, new_value); -} -function internal_set(source2, value) { - if (!source2.equals(value)) { - var old_value = source2.v; - if (is_destroying_effect) { - old_values.set(source2, value); - } else { - old_values.set(source2, old_value); - } - source2.v = value; - var batch = Batch.ensure(); - batch.capture(source2, old_value); - if ((source2.f & DERIVED) !== 0) { - const derived2 = ( - /** @type {Derived} */ - source2 - ); - if ((source2.f & DIRTY) !== 0) { - execute_derived(derived2); - } - update_derived_status(derived2); - } - source2.wv = increment_write_version(); - mark_reactions(source2, DIRTY); - if (active_effect !== null && (active_effect.f & CLEAN) !== 0 && (active_effect.f & (BRANCH_EFFECT | ROOT_EFFECT)) === 0) { - if (untracked_writes === null) { - set_untracked_writes([source2]); - } else { - untracked_writes.push(source2); - } - } - if (!batch.is_fork && eager_effects.size > 0 && !eager_effects_deferred) { - flush_eager_effects(); - } - } - return value; -} -function flush_eager_effects() { - eager_effects_deferred = false; - for (const effect of eager_effects) { - if ((effect.f & CLEAN) !== 0) { - set_signal_status(effect, MAYBE_DIRTY); - } - if (is_dirty(effect)) { - update_effect(effect); - } - } - eager_effects.clear(); -} -function increment(source2) { - set(source2, source2.v + 1); -} -function mark_reactions(signal, status) { - var reactions = signal.reactions; - if (reactions === null) return; - var length = reactions.length; - for (var i = 0; i < length; i++) { - var reaction = reactions[i]; - var flags2 = reaction.f; - var not_dirty = (flags2 & DIRTY) === 0; - if (not_dirty) { - set_signal_status(reaction, status); - } - if ((flags2 & DERIVED) !== 0) { - var derived2 = ( - /** @type {Derived} */ - reaction - ); - batch_values?.delete(derived2); - if ((flags2 & WAS_MARKED) === 0) { - if (flags2 & CONNECTED) { - reaction.f |= WAS_MARKED; - } - mark_reactions(derived2, MAYBE_DIRTY); - } - } else if (not_dirty) { - if ((flags2 & BLOCK_EFFECT) !== 0 && eager_block_effects !== null) { - eager_block_effects.add( - /** @type {Effect} */ - reaction - ); - } - schedule_effect( - /** @type {Effect} */ - reaction - ); - } - } -} -function proxy(value) { - if (typeof value !== "object" || value === null || STATE_SYMBOL in value) { - return value; - } - const prototype = get_prototype_of(value); - if (prototype !== object_prototype && prototype !== array_prototype) { - return value; - } - var sources = /* @__PURE__ */ new Map(); - var is_proxied_array = is_array(value); - var version = /* @__PURE__ */ state(0); - var parent_version = update_version; - var with_parent = (fn) => { - if (update_version === parent_version) { - return fn(); - } - var reaction = active_reaction; - var version2 = update_version; - set_active_reaction(null); - set_update_version(parent_version); - var result = fn(); - set_active_reaction(reaction); - set_update_version(version2); - return result; - }; - if (is_proxied_array) { - sources.set("length", /* @__PURE__ */ state( - /** @type {any[]} */ - value.length - )); - } - return new Proxy( - /** @type {any} */ - value, - { - defineProperty(_, prop, descriptor) { - if (!("value" in descriptor) || descriptor.configurable === false || descriptor.enumerable === false || descriptor.writable === false) { - state_descriptors_fixed(); - } - var s = sources.get(prop); - if (s === void 0) { - with_parent(() => { - var s2 = /* @__PURE__ */ state(descriptor.value); - sources.set(prop, s2); - return s2; - }); - } else { - set(s, descriptor.value, true); - } - return true; - }, - deleteProperty(target, prop) { - var s = sources.get(prop); - if (s === void 0) { - if (prop in target) { - const s2 = with_parent(() => /* @__PURE__ */ state(UNINITIALIZED)); - sources.set(prop, s2); - increment(version); - } - } else { - set(s, UNINITIALIZED); - increment(version); - } - return true; - }, - get(target, prop, receiver) { - if (prop === STATE_SYMBOL) { - return value; - } - var s = sources.get(prop); - var exists = prop in target; - if (s === void 0 && (!exists || get_descriptor(target, prop)?.writable)) { - s = with_parent(() => { - var p = proxy(exists ? target[prop] : UNINITIALIZED); - var s2 = /* @__PURE__ */ state(p); - return s2; - }); - sources.set(prop, s); - } - if (s !== void 0) { - var v = get(s); - return v === UNINITIALIZED ? void 0 : v; - } - return Reflect.get(target, prop, receiver); - }, - getOwnPropertyDescriptor(target, prop) { - var descriptor = Reflect.getOwnPropertyDescriptor(target, prop); - if (descriptor && "value" in descriptor) { - var s = sources.get(prop); - if (s) descriptor.value = get(s); - } else if (descriptor === void 0) { - var source2 = sources.get(prop); - var value2 = source2?.v; - if (source2 !== void 0 && value2 !== UNINITIALIZED) { - return { - enumerable: true, - configurable: true, - value: value2, - writable: true - }; - } - } - return descriptor; - }, - has(target, prop) { - if (prop === STATE_SYMBOL) { - return true; - } - var s = sources.get(prop); - var has = s !== void 0 && s.v !== UNINITIALIZED || Reflect.has(target, prop); - if (s !== void 0 || active_effect !== null && (!has || get_descriptor(target, prop)?.writable)) { - if (s === void 0) { - s = with_parent(() => { - var p = has ? proxy(target[prop]) : UNINITIALIZED; - var s2 = /* @__PURE__ */ state(p); - return s2; - }); - sources.set(prop, s); - } - var value2 = get(s); - if (value2 === UNINITIALIZED) { - return false; - } - } - return has; - }, - set(target, prop, value2, receiver) { - var s = sources.get(prop); - var has = prop in target; - if (is_proxied_array && prop === "length") { - for (var i = value2; i < /** @type {Source} */ - s.v; i += 1) { - var other_s = sources.get(i + ""); - if (other_s !== void 0) { - set(other_s, UNINITIALIZED); - } else if (i in target) { - other_s = with_parent(() => /* @__PURE__ */ state(UNINITIALIZED)); - sources.set(i + "", other_s); - } - } - } - if (s === void 0) { - if (!has || get_descriptor(target, prop)?.writable) { - s = with_parent(() => /* @__PURE__ */ state(void 0)); - set(s, proxy(value2)); - sources.set(prop, s); - } - } else { - has = s.v !== UNINITIALIZED; - var p = with_parent(() => proxy(value2)); - set(s, p); - } - var descriptor = Reflect.getOwnPropertyDescriptor(target, prop); - if (descriptor?.set) { - descriptor.set.call(receiver, value2); - } - if (!has) { - if (is_proxied_array && typeof prop === "string") { - var ls = ( - /** @type {Source} */ - sources.get("length") - ); - var n = Number(prop); - if (Number.isInteger(n) && n >= ls.v) { - set(ls, n + 1); - } - } - increment(version); - } - return true; - }, - ownKeys(target) { - get(version); - var own_keys = Reflect.ownKeys(target).filter((key2) => { - var source3 = sources.get(key2); - return source3 === void 0 || source3.v !== UNINITIALIZED; - }); - for (var [key, source2] of sources) { - if (source2.v !== UNINITIALIZED && !(key in target)) { - own_keys.push(key); - } - } - return own_keys; - }, - setPrototypeOf() { - state_prototype_fixed(); - } - } - ); -} -var $window; -var first_child_getter; -var next_sibling_getter; -function init_operations() { - if ($window !== void 0) { - return; - } - $window = window; - var element_prototype = Element.prototype; - var node_prototype = Node.prototype; - var text_prototype = Text.prototype; - first_child_getter = get_descriptor(node_prototype, "firstChild").get; - next_sibling_getter = get_descriptor(node_prototype, "nextSibling").get; - if (is_extensible(element_prototype)) { - element_prototype.__click = void 0; - element_prototype.__className = void 0; - element_prototype.__attributes = null; - element_prototype.__style = void 0; - element_prototype.__e = void 0; - } - if (is_extensible(text_prototype)) { - text_prototype.__t = void 0; - } -} -function create_text(value = "") { - return document.createTextNode(value); -} -// @__NO_SIDE_EFFECTS__ -function get_first_child(node) { - return ( - /** @type {TemplateNode | null} */ - first_child_getter.call(node) - ); -} -// @__NO_SIDE_EFFECTS__ -function get_next_sibling(node) { - return ( - /** @type {TemplateNode | null} */ - next_sibling_getter.call(node) - ); -} -function clear_text_content(node) { - node.textContent = ""; -} -function without_reactive_context(fn) { - var previous_reaction = active_reaction; - var previous_effect = active_effect; - set_active_reaction(null); - set_active_effect(null); - try { - return fn(); - } finally { - set_active_reaction(previous_reaction); - set_active_effect(previous_effect); - } -} -function push_effect(effect, parent_effect) { - var parent_last = parent_effect.last; - if (parent_last === null) { - parent_effect.last = parent_effect.first = effect; - } else { - parent_last.next = effect; - effect.prev = parent_last; - parent_effect.last = effect; - } -} -function create_effect(type, fn, sync) { - var parent = active_effect; - if (parent !== null && (parent.f & INERT) !== 0) { - type |= INERT; - } - var effect = { - ctx: component_context, - deps: null, - nodes: null, - f: type | DIRTY | CONNECTED, - first: null, - fn, - last: null, - next: null, - parent, - b: parent && parent.b, - prev: null, - teardown: null, - wv: 0, - ac: null - }; - if (sync) { - try { - update_effect(effect); - } catch (e2) { - destroy_effect(effect); - throw e2; - } - } else if (fn !== null) { - schedule_effect(effect); - } - var e = effect; - if (sync && e.deps === null && e.teardown === null && e.nodes === null && e.first === e.last && // either `null`, or a singular child - (e.f & EFFECT_PRESERVED) === 0) { - e = e.first; - if ((type & BLOCK_EFFECT) !== 0 && (type & EFFECT_TRANSPARENT) !== 0 && e !== null) { - e.f |= EFFECT_TRANSPARENT; - } - } - if (e !== null) { - e.parent = parent; - if (parent !== null) { - push_effect(e, parent); - } - if (active_reaction !== null && (active_reaction.f & DERIVED) !== 0 && (type & ROOT_EFFECT) === 0) { - var derived2 = ( - /** @type {Derived} */ - active_reaction - ); - (derived2.effects ??= []).push(e); - } - } - return effect; -} -function effect_tracking() { - return active_reaction !== null && !untracking; -} -function create_user_effect(fn) { - return create_effect(EFFECT | USER_EFFECT, fn, false); -} -function component_root(fn) { - Batch.ensure(); - const effect = create_effect(ROOT_EFFECT | EFFECT_PRESERVED, fn, true); - return (options = {}) => { - return new Promise((fulfil) => { - if (options.outro) { - pause_effect(effect, () => { - destroy_effect(effect); - fulfil(void 0); - }); - } else { - destroy_effect(effect); - fulfil(void 0); - } - }); - }; -} -function render_effect(fn, flags2 = 0) { - return create_effect(RENDER_EFFECT | flags2, fn, true); -} -function block(fn, flags2 = 0) { - var effect = create_effect(BLOCK_EFFECT | flags2, fn, true); - return effect; -} -function branch(fn) { - return create_effect(BRANCH_EFFECT | EFFECT_PRESERVED, fn, true); -} -function execute_effect_teardown(effect) { - var teardown = effect.teardown; - if (teardown !== null) { - const previously_destroying_effect = is_destroying_effect; - const previous_reaction = active_reaction; - set_is_destroying_effect(true); - set_active_reaction(null); - try { - teardown.call(null); - } finally { - set_is_destroying_effect(previously_destroying_effect); - set_active_reaction(previous_reaction); - } - } -} -function destroy_effect_children(signal, remove_dom = false) { - var effect = signal.first; - signal.first = signal.last = null; - while (effect !== null) { - const controller = effect.ac; - if (controller !== null) { - without_reactive_context(() => { - controller.abort(STALE_REACTION); - }); - } - var next2 = effect.next; - if ((effect.f & ROOT_EFFECT) !== 0) { - effect.parent = null; - } else { - destroy_effect(effect, remove_dom); - } - effect = next2; - } -} -function destroy_block_effect_children(signal) { - var effect = signal.first; - while (effect !== null) { - var next2 = effect.next; - if ((effect.f & BRANCH_EFFECT) === 0) { - destroy_effect(effect); - } - effect = next2; - } -} -function destroy_effect(effect, remove_dom = true) { - var removed = false; - if ((remove_dom || (effect.f & HEAD_EFFECT) !== 0) && effect.nodes !== null && effect.nodes.end !== null) { - remove_effect_dom( - effect.nodes.start, - /** @type {TemplateNode} */ - effect.nodes.end - ); - removed = true; - } - destroy_effect_children(effect, remove_dom && !removed); - remove_reactions(effect, 0); - set_signal_status(effect, DESTROYED); - var transitions = effect.nodes && effect.nodes.t; - if (transitions !== null) { - for (const transition of transitions) { - transition.stop(); - } - } - execute_effect_teardown(effect); - var parent = effect.parent; - if (parent !== null && parent.first !== null) { - unlink_effect(effect); - } - effect.next = effect.prev = effect.teardown = effect.ctx = effect.deps = effect.fn = effect.nodes = effect.ac = null; -} -function remove_effect_dom(node, end) { - while (node !== null) { - var next2 = node === end ? null : /* @__PURE__ */ get_next_sibling(node); - node.remove(); - node = next2; - } -} -function unlink_effect(effect) { - var parent = effect.parent; - var prev = effect.prev; - var next2 = effect.next; - if (prev !== null) prev.next = next2; - if (next2 !== null) next2.prev = prev; - if (parent !== null) { - if (parent.first === effect) parent.first = next2; - if (parent.last === effect) parent.last = prev; - } -} -function pause_effect(effect, callback, destroy = true) { - var transitions = []; - pause_children(effect, transitions, true); - var fn = () => { - if (destroy) destroy_effect(effect); - if (callback) callback(); - }; - var remaining = transitions.length; - if (remaining > 0) { - var check = () => --remaining || fn(); - for (var transition of transitions) { - transition.out(check); - } - } else { - fn(); - } -} -function pause_children(effect, transitions, local) { - if ((effect.f & INERT) !== 0) return; - effect.f ^= INERT; - var t = effect.nodes && effect.nodes.t; - if (t !== null) { - for (const transition of t) { - if (transition.is_global || local) { - transitions.push(transition); - } - } - } - var child = effect.first; - while (child !== null) { - var sibling = child.next; - var transparent = (child.f & EFFECT_TRANSPARENT) !== 0 || // If this is a branch effect without a block effect parent, - // it means the parent block effect was pruned. In that case, - // transparency information was transferred to the branch effect. - (child.f & BRANCH_EFFECT) !== 0 && (effect.f & BLOCK_EFFECT) !== 0; - pause_children(child, transitions, transparent ? local : false); - child = sibling; - } -} -function move_effect(effect, fragment) { - if (!effect.nodes) return; - var node = effect.nodes.start; - var end = effect.nodes.end; - while (node !== null) { - var next2 = node === end ? null : /* @__PURE__ */ get_next_sibling(node); - fragment.append(node); - node = next2; - } -} -let is_updating_effect = false; -let is_destroying_effect = false; -function set_is_destroying_effect(value) { - is_destroying_effect = value; -} -let active_reaction = null; -let untracking = false; -function set_active_reaction(reaction) { - active_reaction = reaction; -} -let active_effect = null; -function set_active_effect(effect) { - active_effect = effect; -} -let current_sources = null; -function push_reaction_value(value) { - if (active_reaction !== null && true) { - if (current_sources === null) { - current_sources = [value]; - } else { - current_sources.push(value); - } - } -} -let new_deps = null; -let skipped_deps = 0; -let untracked_writes = null; -function set_untracked_writes(value) { - untracked_writes = value; -} -let write_version = 1; -let read_version = 0; -let update_version = read_version; -function set_update_version(value) { - update_version = value; -} -function increment_write_version() { - return ++write_version; -} -function is_dirty(reaction) { - var flags2 = reaction.f; - if ((flags2 & DIRTY) !== 0) { - return true; - } - if (flags2 & DERIVED) { - reaction.f &= ~WAS_MARKED; - } - if ((flags2 & MAYBE_DIRTY) !== 0) { - var dependencies = ( - /** @type {Value[]} */ - reaction.deps - ); - var length = dependencies.length; - for (var i = 0; i < length; i++) { - var dependency = dependencies[i]; - if (is_dirty( - /** @type {Derived} */ - dependency - )) { - update_derived( - /** @type {Derived} */ - dependency - ); - } - if (dependency.wv > reaction.wv) { - return true; - } - } - if ((flags2 & CONNECTED) !== 0 && // During time traveling we don't want to reset the status so that - // traversal of the graph in the other batches still happens - batch_values === null) { - set_signal_status(reaction, CLEAN); - } - } - return false; -} -function schedule_possible_effect_self_invalidation(signal, effect, root2 = true) { - var reactions = signal.reactions; - if (reactions === null) return; - if (current_sources !== null && includes.call(current_sources, signal)) { - return; - } - for (var i = 0; i < reactions.length; i++) { - var reaction = reactions[i]; - if ((reaction.f & DERIVED) !== 0) { - schedule_possible_effect_self_invalidation( - /** @type {Derived} */ - reaction, - effect, - false - ); - } else if (effect === reaction) { - if (root2) { - set_signal_status(reaction, DIRTY); - } else if ((reaction.f & CLEAN) !== 0) { - set_signal_status(reaction, MAYBE_DIRTY); - } - schedule_effect( - /** @type {Effect} */ - reaction - ); - } - } -} -function update_reaction(reaction) { - var previous_deps = new_deps; - var previous_skipped_deps = skipped_deps; - var previous_untracked_writes = untracked_writes; - var previous_reaction = active_reaction; - var previous_sources = current_sources; - var previous_component_context = component_context; - var previous_untracking = untracking; - var previous_update_version = update_version; - var flags2 = reaction.f; - new_deps = /** @type {null | Value[]} */ - null; - skipped_deps = 0; - untracked_writes = null; - active_reaction = (flags2 & (BRANCH_EFFECT | ROOT_EFFECT)) === 0 ? reaction : null; - current_sources = null; - set_component_context(reaction.ctx); - untracking = false; - update_version = ++read_version; - if (reaction.ac !== null) { - without_reactive_context(() => { - reaction.ac.abort(STALE_REACTION); - }); - reaction.ac = null; - } - try { - reaction.f |= REACTION_IS_UPDATING; - var fn = ( - /** @type {Function} */ - reaction.fn - ); - var result = fn(); - reaction.f |= REACTION_RAN; - var deps = reaction.deps; - var is_fork = current_batch?.is_fork; - if (new_deps !== null) { - var i; - if (!is_fork) { - remove_reactions(reaction, skipped_deps); - } - if (deps !== null && skipped_deps > 0) { - deps.length = skipped_deps + new_deps.length; - for (i = 0; i < new_deps.length; i++) { - deps[skipped_deps + i] = new_deps[i]; - } - } else { - reaction.deps = deps = new_deps; - } - if (effect_tracking() && (reaction.f & CONNECTED) !== 0) { - for (i = skipped_deps; i < deps.length; i++) { - (deps[i].reactions ??= []).push(reaction); - } - } - } else if (!is_fork && deps !== null && skipped_deps < deps.length) { - remove_reactions(reaction, skipped_deps); - deps.length = skipped_deps; - } - if (is_runes() && untracked_writes !== null && !untracking && deps !== null && (reaction.f & (DERIVED | MAYBE_DIRTY | DIRTY)) === 0) { - for (i = 0; i < /** @type {Source[]} */ - untracked_writes.length; i++) { - schedule_possible_effect_self_invalidation( - untracked_writes[i], - /** @type {Effect} */ - reaction - ); - } - } - if (previous_reaction !== null && previous_reaction !== reaction) { - read_version++; - if (previous_reaction.deps !== null) { - for (let i2 = 0; i2 < previous_skipped_deps; i2 += 1) { - previous_reaction.deps[i2].rv = read_version; - } - } - if (previous_deps !== null) { - for (const dep of previous_deps) { - dep.rv = read_version; - } - } - if (untracked_writes !== null) { - if (previous_untracked_writes === null) { - previous_untracked_writes = untracked_writes; - } else { - previous_untracked_writes.push(.../** @type {Source[]} */ - untracked_writes); - } - } - } - if ((reaction.f & ERROR_VALUE) !== 0) { - reaction.f ^= ERROR_VALUE; - } - return result; - } catch (error) { - return handle_error(error); - } finally { - reaction.f ^= REACTION_IS_UPDATING; - new_deps = previous_deps; - skipped_deps = previous_skipped_deps; - untracked_writes = previous_untracked_writes; - active_reaction = previous_reaction; - current_sources = previous_sources; - set_component_context(previous_component_context); - untracking = previous_untracking; - update_version = previous_update_version; - } -} -function remove_reaction(signal, dependency) { - let reactions = dependency.reactions; - if (reactions !== null) { - var index = index_of.call(reactions, signal); - if (index !== -1) { - var new_length = reactions.length - 1; - if (new_length === 0) { - reactions = dependency.reactions = null; - } else { - reactions[index] = reactions[new_length]; - reactions.pop(); - } - } - } - if (reactions === null && (dependency.f & DERIVED) !== 0 && // Destroying a child effect while updating a parent effect can cause a dependency to appear - // to be unused, when in fact it is used by the currently-updating parent. Checking `new_deps` - // allows us to skip the expensive work of disconnecting and immediately reconnecting it - (new_deps === null || !includes.call(new_deps, dependency))) { - var derived2 = ( - /** @type {Derived} */ - dependency - ); - if ((derived2.f & CONNECTED) !== 0) { - derived2.f ^= CONNECTED; - derived2.f &= ~WAS_MARKED; - } - update_derived_status(derived2); - freeze_derived_effects(derived2); - remove_reactions(derived2, 0); - } -} -function remove_reactions(signal, start_index) { - var dependencies = signal.deps; - if (dependencies === null) return; - for (var i = start_index; i < dependencies.length; i++) { - remove_reaction(signal, dependencies[i]); - } -} -function update_effect(effect) { - var flags2 = effect.f; - if ((flags2 & DESTROYED) !== 0) { - return; - } - set_signal_status(effect, CLEAN); - var previous_effect = active_effect; - var was_updating_effect = is_updating_effect; - active_effect = effect; - is_updating_effect = true; - try { - if ((flags2 & (BLOCK_EFFECT | MANAGED_EFFECT)) !== 0) { - destroy_block_effect_children(effect); - } else { - destroy_effect_children(effect); - } - execute_effect_teardown(effect); - var teardown = update_reaction(effect); - effect.teardown = typeof teardown === "function" ? teardown : null; - effect.wv = write_version; - var dep; - if (DEV && tracing_mode_flag && (effect.f & DIRTY) !== 0 && effect.deps !== null) ; - } finally { - is_updating_effect = was_updating_effect; - active_effect = previous_effect; - } -} -function get(signal) { - var flags2 = signal.f; - var is_derived = (flags2 & DERIVED) !== 0; - if (active_reaction !== null && !untracking) { - var destroyed = active_effect !== null && (active_effect.f & DESTROYED) !== 0; - if (!destroyed && (current_sources === null || !includes.call(current_sources, signal))) { - var deps = active_reaction.deps; - if ((active_reaction.f & REACTION_IS_UPDATING) !== 0) { - if (signal.rv < read_version) { - signal.rv = read_version; - if (new_deps === null && deps !== null && deps[skipped_deps] === signal) { - skipped_deps++; - } else if (new_deps === null) { - new_deps = [signal]; - } else { - new_deps.push(signal); - } - } - } else { - (active_reaction.deps ??= []).push(signal); - var reactions = signal.reactions; - if (reactions === null) { - signal.reactions = [active_reaction]; - } else if (!includes.call(reactions, active_reaction)) { - reactions.push(active_reaction); - } - } - } - } - if (is_destroying_effect && old_values.has(signal)) { - return old_values.get(signal); - } - if (is_derived) { - var derived2 = ( - /** @type {Derived} */ - signal - ); - if (is_destroying_effect) { - var value = derived2.v; - if ((derived2.f & CLEAN) === 0 && derived2.reactions !== null || depends_on_old_values(derived2)) { - value = execute_derived(derived2); - } - old_values.set(derived2, value); - return value; - } - var should_connect = (derived2.f & CONNECTED) === 0 && !untracking && active_reaction !== null && (is_updating_effect || (active_reaction.f & CONNECTED) !== 0); - var is_new = (derived2.f & REACTION_RAN) === 0; - if (is_dirty(derived2)) { - if (should_connect) { - derived2.f |= CONNECTED; - } - update_derived(derived2); - } - if (should_connect && !is_new) { - unfreeze_derived_effects(derived2); - reconnect(derived2); - } - } - if (batch_values?.has(signal)) { - return batch_values.get(signal); - } - if ((signal.f & ERROR_VALUE) !== 0) { - throw signal.v; - } - return signal.v; -} -function reconnect(derived2) { - derived2.f |= CONNECTED; - if (derived2.deps === null) return; - for (const dep of derived2.deps) { - (dep.reactions ??= []).push(derived2); - if ((dep.f & DERIVED) !== 0 && (dep.f & CONNECTED) === 0) { - unfreeze_derived_effects( - /** @type {Derived} */ - dep - ); - reconnect( - /** @type {Derived} */ - dep - ); - } - } -} -function depends_on_old_values(derived2) { - if (derived2.v === UNINITIALIZED) return true; - if (derived2.deps === null) return false; - for (const dep of derived2.deps) { - if (old_values.has(dep)) { - return true; - } - if ((dep.f & DERIVED) !== 0 && depends_on_old_values( - /** @type {Derived} */ - dep - )) { - return true; - } - } - return false; -} -function untrack(fn) { - var previous_untracking = untracking; - try { - untracking = true; - return fn(); - } finally { - untracking = previous_untracking; - } -} -const event_symbol = /* @__PURE__ */ Symbol("events"); -const all_registered_events = /* @__PURE__ */ new Set(); -const root_event_handles = /* @__PURE__ */ new Set(); -let last_propagated_event = null; -function handle_event_propagation(event) { - var handler_element = this; - var owner_document = ( - /** @type {Node} */ - handler_element.ownerDocument - ); - var event_name = event.type; - var path = event.composedPath?.() || []; - var current_target = ( - /** @type {null | Element} */ - path[0] || event.target - ); - last_propagated_event = event; - var path_idx = 0; - var handled_at = last_propagated_event === event && event[event_symbol]; - if (handled_at) { - var at_idx = path.indexOf(handled_at); - if (at_idx !== -1 && (handler_element === document || handler_element === /** @type {any} */ - window)) { - event[event_symbol] = handler_element; - return; - } - var handler_idx = path.indexOf(handler_element); - if (handler_idx === -1) { - return; - } - if (at_idx <= handler_idx) { - path_idx = at_idx; - } - } - current_target = /** @type {Element} */ - path[path_idx] || event.target; - if (current_target === handler_element) return; - define_property(event, "currentTarget", { - configurable: true, - get() { - return current_target || owner_document; - } - }); - var previous_reaction = active_reaction; - var previous_effect = active_effect; - set_active_reaction(null); - set_active_effect(null); - try { - var throw_error; - var other_errors = []; - while (current_target !== null) { - var parent_element = current_target.assignedSlot || current_target.parentNode || /** @type {any} */ - current_target.host || null; - try { - var delegated = current_target[event_symbol]?.[event_name]; - if (delegated != null && (!/** @type {any} */ - current_target.disabled || // DOM could've been updated already by the time this is reached, so we check this as well - // -> the target could not have been disabled because it emits the event in the first place - event.target === current_target)) { - delegated.call(current_target, event); - } - } catch (error) { - if (throw_error) { - other_errors.push(error); - } else { - throw_error = error; - } - } - if (event.cancelBubble || parent_element === handler_element || parent_element === null) { - break; - } - current_target = parent_element; - } - if (throw_error) { - for (let error of other_errors) { - queueMicrotask(() => { - throw error; - }); - } - throw throw_error; - } - } finally { - event[event_symbol] = handler_element; - delete event.currentTarget; - set_active_reaction(previous_reaction); - set_active_effect(previous_effect); - } -} -function assign_nodes(start, end) { - var effect = ( - /** @type {Effect} */ - active_effect - ); - if (effect.nodes === null) { - effect.nodes = { start, end, a: null, t: null }; - } -} -function mount(component, options) { - return _mount(component, options); -} -function hydrate(component, options) { - init_operations(); - options.intro = options.intro ?? false; - const target = options.target; - const was_hydrating = hydrating; - const previous_hydrate_node = hydrate_node; - try { - var anchor = /* @__PURE__ */ get_first_child(target); - while (anchor && (anchor.nodeType !== COMMENT_NODE || /** @type {Comment} */ - anchor.data !== HYDRATION_START)) { - anchor = /* @__PURE__ */ get_next_sibling(anchor); - } - if (!anchor) { - throw HYDRATION_ERROR; - } - set_hydrating(true); - set_hydrate_node( - /** @type {Comment} */ - anchor - ); - const instance = _mount(component, { ...options, anchor }); - set_hydrating(false); - return ( - /** @type {Exports} */ - instance - ); - } catch (error) { - if (error instanceof Error && error.message.split("\n").some((line) => line.startsWith("https://svelte.dev/e/"))) { - throw error; - } - if (error !== HYDRATION_ERROR) { - console.warn("Failed to hydrate: ", error); - } - if (options.recover === false) { - hydration_failed(); - } - init_operations(); - clear_text_content(target); - set_hydrating(false); - return mount(component, options); - } finally { - set_hydrating(was_hydrating); - set_hydrate_node(previous_hydrate_node); - } -} -const listeners = /* @__PURE__ */ new Map(); -function _mount(Component, { target, anchor, props = {}, events, context, intro = true, transformError }) { - init_operations(); - var component = void 0; - var unmount2 = component_root(() => { - var anchor_node = anchor ?? target.appendChild(create_text()); - boundary( - /** @type {TemplateNode} */ - anchor_node, - { - pending: () => { - } - }, - (anchor_node2) => { - push({}); - var ctx = ( - /** @type {ComponentContext} */ - component_context - ); - if (context) ctx.c = context; - if (events) { - props.$$events = events; - } - if (hydrating) { - assign_nodes( - /** @type {TemplateNode} */ - anchor_node2, - null - ); - } - component = Component(anchor_node2, props) || {}; - if (hydrating) { - active_effect.nodes.end = hydrate_node; - if (hydrate_node === null || hydrate_node.nodeType !== COMMENT_NODE || /** @type {Comment} */ - hydrate_node.data !== HYDRATION_END) { - hydration_mismatch(); - throw HYDRATION_ERROR; - } - } - pop(); - }, - transformError - ); - var registered_events = /* @__PURE__ */ new Set(); - var event_handle = (events2) => { - for (var i = 0; i < events2.length; i++) { - var event_name = events2[i]; - if (registered_events.has(event_name)) continue; - registered_events.add(event_name); - var passive = is_passive_event(event_name); - for (const node of [target, document]) { - var counts = listeners.get(node); - if (counts === void 0) { - counts = /* @__PURE__ */ new Map(); - listeners.set(node, counts); - } - var count = counts.get(event_name); - if (count === void 0) { - node.addEventListener(event_name, handle_event_propagation, { passive }); - counts.set(event_name, 1); - } else { - counts.set(event_name, count + 1); - } - } - } - }; - event_handle(array_from(all_registered_events)); - root_event_handles.add(event_handle); - return () => { - for (var event_name of registered_events) { - for (const node of [target, document]) { - var counts = ( - /** @type {Map} */ - listeners.get(node) - ); - var count = ( - /** @type {number} */ - counts.get(event_name) - ); - if (--count == 0) { - node.removeEventListener(event_name, handle_event_propagation); - counts.delete(event_name); - if (counts.size === 0) { - listeners.delete(node); - } - } else { - counts.set(event_name, count); - } - } - } - root_event_handles.delete(event_handle); - if (anchor_node !== anchor) { - anchor_node.parentNode?.removeChild(anchor_node); - } - }; - }); - mounted_components.set(component, unmount2); - return component; -} -let mounted_components = /* @__PURE__ */ new WeakMap(); -function unmount(component, options) { - const fn = mounted_components.get(component); - if (fn) { - mounted_components.delete(component); - return fn(options); - } - return Promise.resolve(); -} -function asClassComponent$1(component) { - return class extends Svelte4Component { - /** @param {any} options */ - constructor(options) { - super({ - component, - ...options - }); - } - }; -} -class Svelte4Component { - /** @type {any} */ - #events; - /** @type {Record} */ - #instance; - /** - * @param {ComponentConstructorOptions & { - * component: any; - * }} options - */ - constructor(options) { - var sources = /* @__PURE__ */ new Map(); - var add_source = (key, value) => { - var s = /* @__PURE__ */ mutable_source(value, false, false); - sources.set(key, s); - return s; - }; - const props = new Proxy( - { ...options.props || {}, $$events: {} }, - { - get(target, prop) { - return get(sources.get(prop) ?? add_source(prop, Reflect.get(target, prop))); - }, - has(target, prop) { - if (prop === LEGACY_PROPS) return true; - get(sources.get(prop) ?? add_source(prop, Reflect.get(target, prop))); - return Reflect.has(target, prop); - }, - set(target, prop, value) { - set(sources.get(prop) ?? add_source(prop, value), value); - return Reflect.set(target, prop, value); - } - } - ); - this.#instance = (options.hydrate ? hydrate : mount)(options.component, { - target: options.target, - anchor: options.anchor, - props, - context: options.context, - intro: options.intro ?? false, - recover: options.recover, - transformError: options.transformError - }); - if (!options?.props?.$$host || options.sync === false) { - flushSync(); - } - this.#events = props.$$events; - for (const key of Object.keys(this.#instance)) { - if (key === "$set" || key === "$destroy" || key === "$on") continue; - define_property(this, key, { - get() { - return this.#instance[key]; - }, - /** @param {any} value */ - set(value) { - this.#instance[key] = value; - }, - enumerable: true - }); - } - this.#instance.$set = /** @param {Record} next */ - (next2) => { - Object.assign(props, next2); - }; - this.#instance.$destroy = () => { - unmount(this.#instance); - }; - } - /** @param {Record} props */ - $set(props) { - this.#instance.$set(props); - } - /** - * @param {string} event - * @param {(...args: any[]) => any} callback - * @returns {any} - */ - $on(event, callback) { - this.#events[event] = this.#events[event] || []; - const cb = (...args) => callback.call(this, ...args); - this.#events[event].push(cb); - return () => { - this.#events[event] = this.#events[event].filter( - /** @param {any} fn */ - (fn) => fn !== cb - ); - }; - } - $destroy() { - this.#instance.$destroy(); - } -} -function asClassComponent(component) { - const component_constructor = asClassComponent$1(component); - const _render = (props, { context, csp, transformError } = {}) => { - const result = render(component, { props, context, csp, transformError }); - const munged = Object.defineProperties( - /** @type {LegacyRenderResult & PromiseLike} */ - {}, - { - css: { - value: { code: "", map: null } - }, - head: { - get: () => result.head - }, - html: { - get: () => result.body - }, - then: { - /** - * this is not type-safe, but honestly it's the best I can do right now, and it's a straightforward function. - * - * @template TResult1 - * @template [TResult2=never] - * @param { (value: LegacyRenderResult) => TResult1 } onfulfilled - * @param { (reason: unknown) => TResult2 } onrejected - */ - value: (onfulfilled, onrejected) => { - { - const user_result = onfulfilled({ - css: munged.css, - head: munged.head, - html: munged.html - }); - return Promise.resolve(user_result); - } - } - } - } - ); - return munged; - }; - component_constructor.render = _render; - return component_constructor; -} -function Root($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - let { - stores, - page, - constructors, - components = [], - form, - data_0 = null, - data_1 = null, - data_2 = null - } = $$props; - { - setContext("__svelte__", stores); - } - { - stores.page.set(page); - } - const Pyramid_2 = derived(() => constructors[2]); - if (constructors[1]) { - $$renderer2.push(""); - const Pyramid_0 = constructors[0]; - if (Pyramid_0) { - $$renderer2.push(""); - Pyramid_0($$renderer2, { - data: data_0, - form, - params: page.params, - children: ($$renderer3) => { - if (constructors[2]) { - $$renderer3.push(""); - const Pyramid_1 = constructors[1]; - if (Pyramid_1) { - $$renderer3.push(""); - Pyramid_1($$renderer3, { - data: data_1, - form, - params: page.params, - children: ($$renderer4) => { - if (Pyramid_2()) { - $$renderer4.push(""); - Pyramid_2()($$renderer4, { data: data_2, form, params: page.params }); - $$renderer4.push(""); - } else { - $$renderer4.push(""); - $$renderer4.push(""); - } - }, - $$slots: { default: true } - }); - $$renderer3.push(""); - } else { - $$renderer3.push(""); - $$renderer3.push(""); - } - } else { - $$renderer3.push(""); - const Pyramid_1 = constructors[1]; - if (Pyramid_1) { - $$renderer3.push(""); - Pyramid_1($$renderer3, { data: data_1, form, params: page.params }); - $$renderer3.push(""); - } else { - $$renderer3.push(""); - $$renderer3.push(""); - } - } - $$renderer3.push(``); - }, - $$slots: { default: true } - }); - $$renderer2.push(""); - } else { - $$renderer2.push(""); - $$renderer2.push(""); - } - } else { - $$renderer2.push(""); - const Pyramid_0 = constructors[0]; - if (Pyramid_0) { - $$renderer2.push(""); - Pyramid_0($$renderer2, { data: data_0, form, params: page.params }); - $$renderer2.push(""); - } else { - $$renderer2.push(""); - $$renderer2.push(""); - } - } - $$renderer2.push(` `); - { - $$renderer2.push(""); - } - $$renderer2.push(``); - }); -} -const root = asClassComponent(Root); -export { - root as r, - safe_not_equal as s -}; diff --git a/.svelte-kit/adapter-node/chunks/routing.js b/.svelte-kit/adapter-node/chunks/routing.js deleted file mode 100644 index 11c0ffa..0000000 --- a/.svelte-kit/adapter-node/chunks/routing.js +++ /dev/null @@ -1,85 +0,0 @@ -import { b as decode_params } from "./url.js"; -function affects_path(segment) { - return segment !== "" && !/^\([^)]+\)$/.test(segment); -} -function get_route_segments(route) { - return route.slice(1).split("/").filter(affects_path); -} -function exec(match, params, matchers) { - const result = {}; - const values = match.slice(1); - const values_needing_match = values.filter((value) => value !== void 0); - let buffered = 0; - for (let i = 0; i < params.length; i += 1) { - const param = params[i]; - let value = values[i - buffered]; - if (param.chained && param.rest && buffered) { - value = values.slice(i - buffered, i + 1).filter((s) => s).join("/"); - buffered = 0; - } - if (value === void 0) { - if (param.rest) { - value = ""; - } else { - continue; - } - } - if (!param.matcher || matchers[param.matcher](value)) { - result[param.name] = value; - const next_param = params[i + 1]; - const next_value = values[i + 1]; - if (next_param && !next_param.rest && next_param.optional && next_value && param.chained) { - buffered = 0; - } - if (!next_param && !next_value && Object.keys(result).length === values_needing_match.length) { - buffered = 0; - } - continue; - } - if (param.optional && param.chained) { - buffered++; - continue; - } - return; - } - if (buffered) return; - return result; -} -const basic_param_pattern = /\[(\[)?(\.\.\.)?(\w+?)(?:=(\w+))?\]\]?/g; -function resolve_route(id, params) { - const segments = get_route_segments(id); - const has_id_trailing_slash = id.endsWith("/"); - return "/" + segments.map( - (segment) => segment.replace(basic_param_pattern, (_, optional, rest, name) => { - const param_value = params[name]; - if (!param_value) { - if (optional) return ""; - if (rest && param_value !== void 0) return ""; - throw new Error(`Missing parameter '${name}' in route ${id}`); - } - if (param_value.startsWith("/") || param_value.endsWith("/")) - throw new Error( - `Parameter '${name}' in route ${id} cannot start or end with a slash -- this would cause an invalid route like foo//bar` - ); - return param_value; - }) - ).filter(Boolean).join("/") + (has_id_trailing_slash ? "/" : ""); -} -function find_route(path, routes, matchers) { - for (const route of routes) { - const match = route.pattern.exec(path); - if (!match) continue; - const matched = exec(match, route.params, matchers); - if (matched) { - return { - route, - params: decode_params(matched) - }; - } - } - return null; -} -export { - find_route as f, - resolve_route as r -}; diff --git a/.svelte-kit/adapter-node/chunks/server.js b/.svelte-kit/adapter-node/chunks/server.js deleted file mode 100644 index bf7eaa6..0000000 --- a/.svelte-kit/adapter-node/chunks/server.js +++ /dev/null @@ -1,27 +0,0 @@ -let base = ""; -let assets = base; -const app_dir = "_app"; -const relative = true; -const initial = { base, assets }; -const initial_base = initial.base; -function override(paths) { - base = paths.base; - assets = paths.assets; -} -function reset() { - base = initial.base; - assets = initial.assets; -} -function set_assets(path) { - assets = initial.assets = path; -} -export { - assets as a, - base as b, - app_dir as c, - reset as d, - initial_base as i, - override as o, - relative as r, - set_assets as s -}; diff --git a/.svelte-kit/adapter-node/chunks/shared-server.js b/.svelte-kit/adapter-node/chunks/shared-server.js deleted file mode 100644 index 4fa13e6..0000000 --- a/.svelte-kit/adapter-node/chunks/shared-server.js +++ /dev/null @@ -1,14 +0,0 @@ -let private_env = {}; -let public_env = {}; -function set_private_env(environment) { - private_env = environment; -} -function set_public_env(environment) { - public_env = environment; -} -export { - set_public_env as a, - private_env as b, - public_env as p, - set_private_env as s -}; diff --git a/.svelte-kit/adapter-node/chunks/shared.js b/.svelte-kit/adapter-node/chunks/shared.js deleted file mode 100644 index 9162124..0000000 --- a/.svelte-kit/adapter-node/chunks/shared.js +++ /dev/null @@ -1,789 +0,0 @@ -import { json, text } from "@sveltejs/kit"; -import { SvelteKitError, HttpError } from "@sveltejs/kit/internal"; -import { with_request_store } from "@sveltejs/kit/internal/server"; -import * as devalue from "devalue"; -import { t as text_decoder, b as base64_encode, c as base64_decode } from "./utils.js"; -const SVELTE_KIT_ASSETS = "/_svelte_kit_assets"; -const ENDPOINT_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"]; -const MUTATIVE_METHODS = ["POST", "PUT", "PATCH", "DELETE"]; -const PAGE_METHODS = ["GET", "POST", "HEAD"]; -function set_nested_value(object, path_string, value) { - if (path_string.startsWith("n:")) { - path_string = path_string.slice(2); - value = value === "" ? void 0 : parseFloat(value); - } else if (path_string.startsWith("b:")) { - path_string = path_string.slice(2); - value = value === "on"; - } - deep_set(object, split_path(path_string), value); -} -function convert_formdata(data) { - const result = {}; - for (let key of data.keys()) { - const is_array = key.endsWith("[]"); - let values = data.getAll(key); - if (is_array) key = key.slice(0, -2); - if (values.length > 1 && !is_array) { - throw new Error(`Form cannot contain duplicated keys — "${key}" has ${values.length} values`); - } - values = values.filter( - (entry) => typeof entry === "string" || entry.name !== "" || entry.size > 0 - ); - if (key.startsWith("n:")) { - key = key.slice(2); - values = values.map((v) => v === "" ? void 0 : parseFloat( - /** @type {string} */ - v - )); - } else if (key.startsWith("b:")) { - key = key.slice(2); - values = values.map((v) => v === "on"); - } - set_nested_value(result, key, is_array ? values : values[0]); - } - return result; -} -const BINARY_FORM_CONTENT_TYPE = "application/x-sveltekit-formdata"; -const BINARY_FORM_VERSION = 0; -const HEADER_BYTES = 1 + 4 + 2; -async function deserialize_binary_form(request) { - if (request.headers.get("content-type") !== BINARY_FORM_CONTENT_TYPE) { - const form_data = await request.formData(); - return { data: convert_formdata(form_data), meta: {}, form_data }; - } - if (!request.body) { - throw deserialize_error("no body"); - } - const content_length = parseInt(request.headers.get("content-length") ?? ""); - if (Number.isNaN(content_length)) { - throw deserialize_error("invalid Content-Length header"); - } - const reader = request.body.getReader(); - const chunks = []; - function get_chunk(index) { - if (index in chunks) return chunks[index]; - let i = chunks.length; - while (i <= index) { - chunks[i] = reader.read().then((chunk) => chunk.value); - i++; - } - return chunks[index]; - } - async function get_buffer(offset, length) { - let start_chunk; - let chunk_start = 0; - let chunk_index; - for (chunk_index = 0; ; chunk_index++) { - const chunk = await get_chunk(chunk_index); - if (!chunk) return null; - const chunk_end = chunk_start + chunk.byteLength; - if (offset >= chunk_start && offset < chunk_end) { - start_chunk = chunk; - break; - } - chunk_start = chunk_end; - } - if (offset + length <= chunk_start + start_chunk.byteLength) { - return start_chunk.subarray(offset - chunk_start, offset + length - chunk_start); - } - const chunks2 = [start_chunk.subarray(offset - chunk_start)]; - let cursor = start_chunk.byteLength - offset + chunk_start; - while (cursor < length) { - chunk_index++; - let chunk = await get_chunk(chunk_index); - if (!chunk) return null; - if (chunk.byteLength > length - cursor) { - chunk = chunk.subarray(0, length - cursor); - } - chunks2.push(chunk); - cursor += chunk.byteLength; - } - const buffer = new Uint8Array(length); - cursor = 0; - for (const chunk of chunks2) { - buffer.set(chunk, cursor); - cursor += chunk.byteLength; - } - return buffer; - } - const header = await get_buffer(0, HEADER_BYTES); - if (!header) throw deserialize_error("too short"); - if (header[0] !== BINARY_FORM_VERSION) { - throw deserialize_error(`got version ${header[0]}, expected version ${BINARY_FORM_VERSION}`); - } - const header_view = new DataView(header.buffer, header.byteOffset, header.byteLength); - const data_length = header_view.getUint32(1, true); - if (HEADER_BYTES + data_length > content_length) { - throw deserialize_error("data overflow"); - } - const file_offsets_length = header_view.getUint16(5, true); - if (HEADER_BYTES + data_length + file_offsets_length > content_length) { - throw deserialize_error("file offset table overflow"); - } - const data_buffer = await get_buffer(HEADER_BYTES, data_length); - if (!data_buffer) throw deserialize_error("data too short"); - let file_offsets; - let files_start_offset; - if (file_offsets_length > 0) { - const file_offsets_buffer = await get_buffer(HEADER_BYTES + data_length, file_offsets_length); - if (!file_offsets_buffer) throw deserialize_error("file offset table too short"); - const parsed_offsets = JSON.parse(text_decoder.decode(file_offsets_buffer)); - if (!Array.isArray(parsed_offsets) || parsed_offsets.some((n) => typeof n !== "number" || !Number.isInteger(n) || n < 0)) { - throw deserialize_error("invalid file offset table"); - } - file_offsets = /** @type {Array} */ - parsed_offsets; - files_start_offset = HEADER_BYTES + data_length + file_offsets_length; - } - const file_spans = []; - const [data, meta] = devalue.parse(text_decoder.decode(data_buffer), { - File: ([name, type, size, last_modified, index]) => { - if (typeof name !== "string" || typeof type !== "string" || typeof size !== "number" || typeof last_modified !== "number" || typeof index !== "number") { - throw deserialize_error("invalid file metadata"); - } - let offset = file_offsets[index]; - if (offset === void 0) { - throw deserialize_error("duplicate file offset table index"); - } - file_offsets[index] = void 0; - offset += files_start_offset; - if (offset + size > content_length) { - throw deserialize_error("file data overflow"); - } - file_spans.push({ offset, size }); - return new Proxy(new LazyFile(name, type, size, last_modified, get_chunk, offset), { - getPrototypeOf() { - return File.prototype; - } - }); - } - }); - file_spans.sort((a, b) => a.offset - b.offset || a.size - b.size); - for (let i = 1; i < file_spans.length; i++) { - const previous = file_spans[i - 1]; - const current = file_spans[i]; - const previous_end = previous.offset + previous.size; - if (previous_end < current.offset) { - throw deserialize_error("gaps in file data"); - } - if (previous_end > current.offset) { - throw deserialize_error("overlapping file data"); - } - } - void (async () => { - let has_more = true; - while (has_more) { - const chunk = await get_chunk(chunks.length); - has_more = !!chunk; - } - })(); - return { data, meta, form_data: null }; -} -function deserialize_error(message) { - return new SvelteKitError(400, "Bad Request", `Could not deserialize binary form: ${message}`); -} -class LazyFile { - /** @type {(index: number) => Promise | undefined>} */ - #get_chunk; - /** @type {number} */ - #offset; - /** - * @param {string} name - * @param {string} type - * @param {number} size - * @param {number} last_modified - * @param {(index: number) => Promise | undefined>} get_chunk - * @param {number} offset - */ - constructor(name, type, size, last_modified, get_chunk, offset) { - this.name = name; - this.type = type; - this.size = size; - this.lastModified = last_modified; - this.webkitRelativePath = ""; - this.#get_chunk = get_chunk; - this.#offset = offset; - this.arrayBuffer = this.arrayBuffer.bind(this); - this.bytes = this.bytes.bind(this); - this.slice = this.slice.bind(this); - this.stream = this.stream.bind(this); - this.text = this.text.bind(this); - } - /** @type {ArrayBuffer | undefined} */ - #buffer; - async arrayBuffer() { - this.#buffer ??= await new Response(this.stream()).arrayBuffer(); - return this.#buffer; - } - async bytes() { - return new Uint8Array(await this.arrayBuffer()); - } - /** - * @param {number=} start - * @param {number=} end - * @param {string=} contentType - */ - slice(start = 0, end = this.size, contentType = this.type) { - if (start < 0) { - start = Math.max(this.size + start, 0); - } else { - start = Math.min(start, this.size); - } - if (end < 0) { - end = Math.max(this.size + end, 0); - } else { - end = Math.min(end, this.size); - } - const size = Math.max(end - start, 0); - const file = new LazyFile( - this.name, - contentType, - size, - this.lastModified, - this.#get_chunk, - this.#offset + start - ); - return file; - } - stream() { - let cursor = 0; - let chunk_index = 0; - return new ReadableStream({ - start: async (controller) => { - let chunk_start = 0; - let start_chunk; - for (chunk_index = 0; ; chunk_index++) { - const chunk = await this.#get_chunk(chunk_index); - if (!chunk) return null; - const chunk_end = chunk_start + chunk.byteLength; - if (this.#offset >= chunk_start && this.#offset < chunk_end) { - start_chunk = chunk; - break; - } - chunk_start = chunk_end; - } - if (this.#offset + this.size <= chunk_start + start_chunk.byteLength) { - controller.enqueue( - start_chunk.subarray(this.#offset - chunk_start, this.#offset + this.size - chunk_start) - ); - controller.close(); - } else { - controller.enqueue(start_chunk.subarray(this.#offset - chunk_start)); - cursor = start_chunk.byteLength - this.#offset + chunk_start; - } - }, - pull: async (controller) => { - chunk_index++; - let chunk = await this.#get_chunk(chunk_index); - if (!chunk) { - controller.error("incomplete file data"); - controller.close(); - return; - } - if (chunk.byteLength > this.size - cursor) { - chunk = chunk.subarray(0, this.size - cursor); - } - controller.enqueue(chunk); - cursor += chunk.byteLength; - if (cursor >= this.size) { - controller.close(); - } - } - }); - } - async text() { - return text_decoder.decode(await this.arrayBuffer()); - } -} -const path_regex = /^[a-zA-Z_$]\w*(\.[a-zA-Z_$]\w*|\[\d+\])*$/; -function split_path(path) { - if (!path_regex.test(path)) { - throw new Error(`Invalid path ${path}`); - } - return path.split(/\.|\[|\]/).filter(Boolean); -} -function check_prototype_pollution(key) { - if (key === "__proto__" || key === "constructor" || key === "prototype") { - throw new Error( - `Invalid key "${key}"` - ); - } -} -function deep_set(object, keys, value) { - let current = object; - for (let i = 0; i < keys.length - 1; i += 1) { - const key = keys[i]; - check_prototype_pollution(key); - const is_array = /^\d+$/.test(keys[i + 1]); - const exists = Object.hasOwn(current, key); - const inner = current[key]; - if (exists && is_array !== Array.isArray(inner)) { - throw new Error(`Invalid array key ${keys[i + 1]}`); - } - if (!exists) { - current[key] = is_array ? [] : {}; - } - current = current[key]; - } - const final_key = keys[keys.length - 1]; - check_prototype_pollution(final_key); - current[final_key] = value; -} -function normalize_issue(issue, server = false) { - const normalized = { name: "", path: [], message: issue.message, server }; - if (issue.path !== void 0) { - let name = ""; - for (const segment of issue.path) { - const key = ( - /** @type {string | number} */ - typeof segment === "object" ? segment.key : segment - ); - normalized.path.push(key); - if (typeof key === "number") { - name += `[${key}]`; - } else if (typeof key === "string") { - name += name === "" ? key : "." + key; - } - } - normalized.name = name; - } - return normalized; -} -function flatten_issues(issues) { - const result = {}; - for (const issue of issues) { - (result.$ ??= []).push(issue); - let name = ""; - if (issue.path !== void 0) { - for (const key of issue.path) { - if (typeof key === "number") { - name += `[${key}]`; - } else if (typeof key === "string") { - name += name === "" ? key : "." + key; - } - (result[name] ??= []).push(issue); - } - } - } - return result; -} -function deep_get(object, path) { - let current = object; - for (const key of path) { - if (current == null || typeof current !== "object") { - return current; - } - current = current[key]; - } - return current; -} -function create_field_proxy(target, get_input, set_input, get_issues, path = []) { - const get_value = () => { - return deep_get(get_input(), path); - }; - return new Proxy(target, { - get(target2, prop) { - if (typeof prop === "symbol") return target2[prop]; - if (/^\d+$/.test(prop)) { - return create_field_proxy({}, get_input, set_input, get_issues, [ - ...path, - parseInt(prop, 10) - ]); - } - const key = build_path_string(path); - if (prop === "set") { - const set_func = function(newValue) { - set_input(path, newValue); - return newValue; - }; - return create_field_proxy(set_func, get_input, set_input, get_issues, [...path, prop]); - } - if (prop === "value") { - return create_field_proxy(get_value, get_input, set_input, get_issues, [...path, prop]); - } - if (prop === "issues" || prop === "allIssues") { - const issues_func = () => { - const all_issues = get_issues()[key === "" ? "$" : key]; - if (prop === "allIssues") { - return all_issues?.map((issue) => ({ - path: issue.path, - message: issue.message - })); - } - return all_issues?.filter((issue) => issue.name === key)?.map((issue) => ({ - path: issue.path, - message: issue.message - })); - }; - return create_field_proxy(issues_func, get_input, set_input, get_issues, [...path, prop]); - } - if (prop === "as") { - const as_func = (type, input_value) => { - const is_array = type === "file multiple" || type === "select multiple" || type === "checkbox" && typeof input_value === "string"; - const prefix = type === "number" || type === "range" ? "n:" : type === "checkbox" && !is_array ? "b:" : ""; - const base_props = { - name: prefix + key + (is_array ? "[]" : ""), - get "aria-invalid"() { - const issues = get_issues(); - return key in issues ? "true" : void 0; - } - }; - if (type !== "text" && type !== "select" && type !== "select multiple") { - base_props.type = type === "file multiple" ? "file" : type; - } - if (type === "submit" || type === "hidden") { - return Object.defineProperties(base_props, { - value: { value: input_value, enumerable: true } - }); - } - if (type === "select" || type === "select multiple") { - return Object.defineProperties(base_props, { - multiple: { value: is_array, enumerable: true }, - value: { - enumerable: true, - get() { - return get_value(); - } - } - }); - } - if (type === "checkbox" || type === "radio") { - return Object.defineProperties(base_props, { - value: { value: input_value ?? "on", enumerable: true }, - checked: { - enumerable: true, - get() { - const value = get_value(); - if (type === "radio") { - return value === input_value; - } - if (is_array) { - return (value ?? []).includes(input_value); - } - return value; - } - } - }); - } - if (type === "file" || type === "file multiple") { - return Object.defineProperties(base_props, { - multiple: { value: is_array, enumerable: true }, - files: { - enumerable: true, - get() { - const value = get_value(); - if (value instanceof File) { - if (typeof DataTransfer !== "undefined") { - const fileList = new DataTransfer(); - fileList.items.add(value); - return fileList.files; - } - return { 0: value, length: 1 }; - } - if (Array.isArray(value) && value.every((f) => f instanceof File)) { - if (typeof DataTransfer !== "undefined") { - const fileList = new DataTransfer(); - value.forEach((file) => fileList.items.add(file)); - return fileList.files; - } - const fileListLike = { length: value.length }; - value.forEach((file, index) => { - fileListLike[index] = file; - }); - return fileListLike; - } - return null; - } - } - }); - } - return Object.defineProperties(base_props, { - value: { - enumerable: true, - get() { - const value = get_value(); - return value != null ? String(value) : ""; - } - } - }); - }; - return create_field_proxy(as_func, get_input, set_input, get_issues, [...path, "as"]); - } - return create_field_proxy({}, get_input, set_input, get_issues, [...path, prop]); - } - }); -} -function build_path_string(path) { - let result = ""; - for (const segment of path) { - if (typeof segment === "number") { - result += `[${segment}]`; - } else { - result += result === "" ? segment : "." + segment; - } - } - return result; -} -function negotiate(accept, types) { - const parts = []; - accept.split(",").forEach((str, i) => { - const match = /([^/ \t]+)\/([^; \t]+)[ \t]*(?:;[ \t]*q=([0-9.]+))?/.exec(str); - if (match) { - const [, type, subtype, q = "1"] = match; - parts.push({ type, subtype, q: +q, i }); - } - }); - parts.sort((a, b) => { - if (a.q !== b.q) { - return b.q - a.q; - } - if (a.subtype === "*" !== (b.subtype === "*")) { - return a.subtype === "*" ? 1 : -1; - } - if (a.type === "*" !== (b.type === "*")) { - return a.type === "*" ? 1 : -1; - } - return a.i - b.i; - }); - let accepted; - let min_priority = Infinity; - for (const mimetype of types) { - const [type, subtype] = mimetype.split("/"); - const priority = parts.findIndex( - (part) => (part.type === type || part.type === "*") && (part.subtype === subtype || part.subtype === "*") - ); - if (priority !== -1 && priority < min_priority) { - accepted = mimetype; - min_priority = priority; - } - } - return accepted; -} -function is_content_type(request, ...types) { - const type = request.headers.get("content-type")?.split(";", 1)[0].trim() ?? ""; - return types.includes(type.toLowerCase()); -} -function is_form_content_type(request) { - return is_content_type( - request, - "application/x-www-form-urlencoded", - "multipart/form-data", - "text/plain", - BINARY_FORM_CONTENT_TYPE - ); -} -function coalesce_to_error(err) { - return err instanceof Error || err && /** @type {any} */ - err.name && /** @type {any} */ - err.message ? ( - /** @type {Error} */ - err - ) : new Error(JSON.stringify(err)); -} -function normalize_error(error) { - return ( - /** @type {import('../exports/internal/index.js').Redirect | HttpError | SvelteKitError | Error} */ - error - ); -} -function get_status(error) { - return error instanceof HttpError || error instanceof SvelteKitError ? error.status : 500; -} -function get_message(error) { - return error instanceof SvelteKitError ? error.text : "Internal Error"; -} -const escape_html_attr_dict = { - "&": "&", - '"': """ - // Svelte also escapes < because the escape function could be called inside a `noscript` there - // https://github.com/sveltejs/svelte/security/advisories/GHSA-8266-84wp-wv5c - // However, that doesn't apply in SvelteKit -}; -const escape_html_dict = { - "&": "&", - "<": "<" -}; -const surrogates = ( - // high surrogate without paired low surrogate - "[\\ud800-\\udbff](?![\\udc00-\\udfff])|[\\ud800-\\udbff][\\udc00-\\udfff]|[\\udc00-\\udfff]" -); -const escape_html_attr_regex = new RegExp( - `[${Object.keys(escape_html_attr_dict).join("")}]|` + surrogates, - "g" -); -const escape_html_regex = new RegExp( - `[${Object.keys(escape_html_dict).join("")}]|` + surrogates, - "g" -); -function escape_html(str, is_attr) { - const dict = is_attr ? escape_html_attr_dict : escape_html_dict; - const escaped_str = str.replace(is_attr ? escape_html_attr_regex : escape_html_regex, (match) => { - if (match.length === 2) { - return match; - } - return dict[match] ?? `&#${match.charCodeAt(0)};`; - }); - return escaped_str; -} -function method_not_allowed(mod, method) { - return text(`${method} method not allowed`, { - status: 405, - headers: { - // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/405 - // "The server must generate an Allow header field in a 405 status code response" - allow: allowed_methods(mod).join(", ") - } - }); -} -function allowed_methods(mod) { - const allowed = ENDPOINT_METHODS.filter((method) => method in mod); - if ("GET" in mod && !("HEAD" in mod)) { - allowed.push("HEAD"); - } - return allowed; -} -function get_global_name(options) { - return `__sveltekit_${options.version_hash}`; -} -function static_error_page(options, status, message) { - let page = options.templates.error({ status, message: escape_html(message) }); - return text(page, { - headers: { "content-type": "text/html; charset=utf-8" }, - status - }); -} -async function handle_fatal_error(event, state, options, error) { - error = error instanceof HttpError ? error : coalesce_to_error(error); - const status = get_status(error); - const body = await handle_error_and_jsonify(event, state, options, error); - const type = negotiate(event.request.headers.get("accept") || "text/html", [ - "application/json", - "text/html" - ]); - if (event.isDataRequest || type === "application/json") { - return json(body, { - status - }); - } - return static_error_page(options, status, body.message); -} -async function handle_error_and_jsonify(event, state, options, error) { - if (error instanceof HttpError) { - return { message: "Unknown Error", ...error.body }; - } - const status = get_status(error); - const message = get_message(error); - return await with_request_store( - { event, state }, - () => options.hooks.handleError({ error, event, status, message }) - ) ?? { message }; -} -function redirect_response(status, location) { - const response = new Response(void 0, { - status, - headers: { location } - }); - return response; -} -function clarify_devalue_error(event, error) { - if (error.path) { - return `Data returned from \`load\` while rendering ${event.route.id} is not serializable: ${error.message} (${error.path}). If you need to serialize/deserialize custom types, use transport hooks: https://svelte.dev/docs/kit/hooks#Universal-hooks-transport.`; - } - if (error.path === "") { - return `Data returned from \`load\` while rendering ${event.route.id} is not a plain object`; - } - return error.message; -} -function serialize_uses(node) { - const uses = {}; - if (node.uses && node.uses.dependencies.size > 0) { - uses.dependencies = Array.from(node.uses.dependencies); - } - if (node.uses && node.uses.search_params.size > 0) { - uses.search_params = Array.from(node.uses.search_params); - } - if (node.uses && node.uses.params.size > 0) { - uses.params = Array.from(node.uses.params); - } - if (node.uses?.parent) uses.parent = 1; - if (node.uses?.route) uses.route = 1; - if (node.uses?.url) uses.url = 1; - return uses; -} -function has_prerendered_path(manifest, pathname) { - return manifest._.prerendered_routes.has(pathname) || pathname.at(-1) === "/" && manifest._.prerendered_routes.has(pathname.slice(0, -1)); -} -function format_server_error(status, error, event) { - const formatted_text = ` -\x1B[1;31m[${status}] ${event.request.method} ${event.url.pathname}\x1B[0m`; - if (status === 404) { - return formatted_text; - } - return `${formatted_text} -${error.stack}`; -} -function get_node_type(node_id) { - const parts = node_id?.split("/"); - const filename = parts?.at(-1); - if (!filename) return "unknown"; - const dot_parts = filename.split("."); - return dot_parts.slice(0, -1).join("."); -} -const INVALIDATED_PARAM = "x-sveltekit-invalidated"; -const TRAILING_SLASH_PARAM = "x-sveltekit-trailing-slash"; -function stringify(data, transport) { - const encoders = Object.fromEntries(Object.entries(transport).map(([k, v]) => [k, v.encode])); - return devalue.stringify(data, encoders); -} -function stringify_remote_arg(value, transport) { - if (value === void 0) return ""; - const json_string = stringify(value, transport); - const bytes = new TextEncoder().encode(json_string); - return base64_encode(bytes).replaceAll("=", "").replaceAll("+", "-").replaceAll("/", "_"); -} -function parse_remote_arg(string, transport) { - if (!string) return void 0; - const json_string = text_decoder.decode( - // no need to add back `=` characters, atob can handle it - base64_decode(string.replaceAll("-", "+").replaceAll("_", "/")) - ); - const decoders = Object.fromEntries(Object.entries(transport).map(([k, v]) => [k, v.decode])); - return devalue.parse(json_string, decoders); -} -function create_remote_key(id, payload) { - return id + "/" + payload; -} -export { - ENDPOINT_METHODS as E, - INVALIDATED_PARAM as I, - MUTATIVE_METHODS as M, - PAGE_METHODS as P, - SVELTE_KIT_ASSETS as S, - TRAILING_SLASH_PARAM as T, - normalize_error as a, - get_global_name as b, - clarify_devalue_error as c, - get_node_type as d, - escape_html as e, - create_remote_key as f, - get_status as g, - handle_error_and_jsonify as h, - is_form_content_type as i, - static_error_page as j, - stringify as k, - deserialize_binary_form as l, - method_not_allowed as m, - negotiate as n, - has_prerendered_path as o, - parse_remote_arg as p, - handle_fatal_error as q, - redirect_response as r, - serialize_uses as s, - format_server_error as t, - create_field_proxy as u, - normalize_issue as v, - set_nested_value as w, - flatten_issues as x, - deep_set as y, - stringify_remote_arg as z -}; diff --git a/.svelte-kit/adapter-node/chunks/state.svelte.js b/.svelte-kit/adapter-node/chunks/state.svelte.js deleted file mode 100644 index 9cd4558..0000000 --- a/.svelte-kit/adapter-node/chunks/state.svelte.js +++ /dev/null @@ -1,18 +0,0 @@ -import "clsx"; -import { n as noop } from "./index3.js"; -import "./url.js"; -import "@sveltejs/kit/internal/server"; -import "./root.js"; -const is_legacy = noop.toString().includes("$$") || /function \w+\(\) \{\}/.test(noop.toString()); -if (is_legacy) { - ({ - data: {}, - form: null, - error: null, - params: {}, - route: { id: null }, - state: {}, - status: -1, - url: new URL("https://example.com") - }); -} diff --git a/.svelte-kit/adapter-node/chunks/url.js b/.svelte-kit/adapter-node/chunks/url.js deleted file mode 100644 index 2ba2c18..0000000 --- a/.svelte-kit/adapter-node/chunks/url.js +++ /dev/null @@ -1,106 +0,0 @@ -const SCHEME = /^[a-z][a-z\d+\-.]+:/i; -const internal = new URL("sveltekit-internal://"); -function resolve(base, path) { - if (path[0] === "/" && path[1] === "/") return path; - let url = new URL(base, internal); - url = new URL(path, url); - return url.protocol === internal.protocol ? url.pathname + url.search + url.hash : url.href; -} -function normalize_path(path, trailing_slash) { - if (path === "/" || trailing_slash === "ignore") return path; - if (trailing_slash === "never") { - return path.endsWith("/") ? path.slice(0, -1) : path; - } else if (trailing_slash === "always" && !path.endsWith("/")) { - return path + "/"; - } - return path; -} -function decode_pathname(pathname) { - return pathname.split("%25").map(decodeURI).join("%25"); -} -function decode_params(params) { - for (const key in params) { - params[key] = decodeURIComponent(params[key]); - } - return params; -} -function make_trackable(url, callback, search_params_callback, allow_hash = false) { - const tracked = new URL(url); - Object.defineProperty(tracked, "searchParams", { - value: new Proxy(tracked.searchParams, { - get(obj, key) { - if (key === "get" || key === "getAll" || key === "has") { - return (param, ...rest) => { - search_params_callback(param); - return obj[key](param, ...rest); - }; - } - callback(); - const value = Reflect.get(obj, key); - return typeof value === "function" ? value.bind(obj) : value; - } - }), - enumerable: true, - configurable: true - }); - const tracked_url_properties = ["href", "pathname", "search", "toString", "toJSON"]; - if (allow_hash) tracked_url_properties.push("hash"); - for (const property of tracked_url_properties) { - Object.defineProperty(tracked, property, { - get() { - callback(); - return url[property]; - }, - enumerable: true, - configurable: true - }); - } - { - tracked[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")] = (depth, opts, inspect) => { - return inspect(url, opts); - }; - tracked.searchParams[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")] = (depth, opts, inspect) => { - return inspect(url.searchParams, opts); - }; - } - if (!allow_hash) { - disable_hash(tracked); - } - return tracked; -} -function disable_hash(url) { - allow_nodejs_console_log(url); - Object.defineProperty(url, "hash", { - get() { - throw new Error( - "Cannot access event.url.hash. Consider using `page.url.hash` inside a component instead" - ); - } - }); -} -function disable_search(url) { - allow_nodejs_console_log(url); - for (const property of ["search", "searchParams"]) { - Object.defineProperty(url, property, { - get() { - throw new Error(`Cannot access url.${property} on a page with prerendering enabled`); - } - }); - } -} -function allow_nodejs_console_log(url) { - { - url[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")] = (depth, opts, inspect) => { - return inspect(new URL(url), opts); - }; - } -} -export { - SCHEME as S, - decode_pathname as a, - decode_params as b, - disable_search as d, - make_trackable as m, - normalize_path as n, - resolve as r -}; diff --git a/.svelte-kit/adapter-node/chunks/utils.js b/.svelte-kit/adapter-node/chunks/utils.js deleted file mode 100644 index 78e5bde..0000000 --- a/.svelte-kit/adapter-node/chunks/utils.js +++ /dev/null @@ -1,43 +0,0 @@ -const text_encoder = new TextEncoder(); -const text_decoder = new TextDecoder(); -function get_relative_path(from, to) { - const from_parts = from.split(/[/\\]/); - const to_parts = to.split(/[/\\]/); - from_parts.pop(); - while (from_parts[0] === to_parts[0]) { - from_parts.shift(); - to_parts.shift(); - } - let i = from_parts.length; - while (i--) from_parts[i] = ".."; - return from_parts.concat(to_parts).join("/"); -} -function base64_encode(bytes) { - if (globalThis.Buffer) { - return globalThis.Buffer.from(bytes).toString("base64"); - } - let binary = ""; - for (let i = 0; i < bytes.length; i++) { - binary += String.fromCharCode(bytes[i]); - } - return btoa(binary); -} -function base64_decode(encoded) { - if (globalThis.Buffer) { - const buffer = globalThis.Buffer.from(encoded, "base64"); - return new Uint8Array(buffer); - } - const binary = atob(encoded); - const bytes = new Uint8Array(binary.length); - for (let i = 0; i < binary.length; i++) { - bytes[i] = binary.charCodeAt(i); - } - return bytes; -} -export { - text_encoder as a, - base64_encode as b, - base64_decode as c, - get_relative_path as g, - text_decoder as t -}; diff --git a/.svelte-kit/adapter-node/entries/endpoints/api/health/_server.ts.js b/.svelte-kit/adapter-node/entries/endpoints/api/health/_server.ts.js deleted file mode 100644 index 203529d..0000000 --- a/.svelte-kit/adapter-node/entries/endpoints/api/health/_server.ts.js +++ /dev/null @@ -1,25 +0,0 @@ -import { json } from "@sveltejs/kit"; -import { d as db } from "../../../../chunks/index2.js"; -import { sql } from "drizzle-orm"; -const GET = async () => { - try { - await db.execute(sql`SELECT 1`); - return json({ - status: "ok", - timestamp: (/* @__PURE__ */ new Date()).toISOString(), - uptime: process.uptime() - }); - } catch (e) { - return json( - { - status: "error", - error: "Database connection failed", - timestamp: (/* @__PURE__ */ new Date()).toISOString() - }, - { status: 503 } - ); - } -}; -export { - GET -}; diff --git a/.svelte-kit/adapter-node/entries/endpoints/api/mappools/_id_/_server.ts.js b/.svelte-kit/adapter-node/entries/endpoints/api/mappools/_id_/_server.ts.js deleted file mode 100644 index 4d6b270..0000000 --- a/.svelte-kit/adapter-node/entries/endpoints/api/mappools/_id_/_server.ts.js +++ /dev/null @@ -1,24 +0,0 @@ -import { error, json } from "@sveltejs/kit"; -import { d as db, m as mappool, a as mappoolSlot } from "../../../../../chunks/index2.js"; -import { eq } from "drizzle-orm"; -const GET = async ({ params, locals }) => { - if (!locals.user) error(401, "Not logged in"); - const pool = await db.query.mappool.findFirst({ - where: eq(mappool.id, params.id) - }); - if (!pool) error(404, "Mappool not found"); - const slots = await db.query.mappoolSlot.findMany({ - where: eq(mappoolSlot.mappoolId, params.id), - orderBy: (s, { asc }) => [asc(s.category), asc(s.orderInCategory)] - }); - return json({ ...pool, slots }); -}; -const DELETE = async ({ params, locals }) => { - if (!locals.user) error(401, "Not logged in"); - await db.delete(mappool).where(eq(mappool.id, params.id)); - return json({ ok: true }); -}; -export { - DELETE, - GET -}; diff --git a/.svelte-kit/adapter-node/entries/endpoints/api/mappools/_id_/slots/_server.ts.js b/.svelte-kit/adapter-node/entries/endpoints/api/mappools/_id_/slots/_server.ts.js deleted file mode 100644 index b61da5c..0000000 --- a/.svelte-kit/adapter-node/entries/endpoints/api/mappools/_id_/slots/_server.ts.js +++ /dev/null @@ -1,27 +0,0 @@ -import { error, json } from "@sveltejs/kit"; -import { d as db, a as mappoolSlot } from "../../../../../../chunks/index2.js"; -import { and, eq } from "drizzle-orm"; -const POST = async ({ params, request, locals }) => { - if (!locals.user) error(401, "Not logged in"); - const { beatmapId, category, mods } = await request.json(); - if (!beatmapId || !category) { - error(400, "beatmapId and category are required"); - } - const existing = await db.query.mappoolSlot.findMany({ - where: and( - eq(mappoolSlot.mappoolId, params.id), - eq(mappoolSlot.category, category.toUpperCase()) - ) - }); - const [created] = await db.insert(mappoolSlot).values({ - mappoolId: params.id, - beatmapId: String(beatmapId), - category: category.toUpperCase(), - orderInCategory: existing.length + 1, - mods: mods ?? [] - }).returning(); - return json(created, { status: 201 }); -}; -export { - POST -}; diff --git a/.svelte-kit/adapter-node/entries/endpoints/api/mappools/_id_/slots/_slotId_/_server.ts.js b/.svelte-kit/adapter-node/entries/endpoints/api/mappools/_id_/slots/_slotId_/_server.ts.js deleted file mode 100644 index c77f59a..0000000 --- a/.svelte-kit/adapter-node/entries/endpoints/api/mappools/_id_/slots/_slotId_/_server.ts.js +++ /dev/null @@ -1,11 +0,0 @@ -import { error, json } from "@sveltejs/kit"; -import { d as db, a as mappoolSlot } from "../../../../../../../chunks/index2.js"; -import { eq } from "drizzle-orm"; -const DELETE = async ({ params, locals }) => { - if (!locals.user) error(401, "Not logged in"); - await db.delete(mappoolSlot).where(eq(mappoolSlot.id, params.slotId)); - return json({ ok: true }); -}; -export { - DELETE -}; diff --git a/.svelte-kit/adapter-node/entries/endpoints/api/mappools/_server.ts.js b/.svelte-kit/adapter-node/entries/endpoints/api/mappools/_server.ts.js deleted file mode 100644 index bf904be..0000000 --- a/.svelte-kit/adapter-node/entries/endpoints/api/mappools/_server.ts.js +++ /dev/null @@ -1,23 +0,0 @@ -import { error, json } from "@sveltejs/kit"; -import { d as db, m as mappool } from "../../../../chunks/index2.js"; -const GET = async ({ locals }) => { - if (!locals.user) error(401, "Not logged in"); - const mappools = await db.query.mappool.findMany({ - orderBy: (m, { desc }) => [desc(m.createdAt)] - }); - return json(mappools); -}; -const POST = async ({ request, locals }) => { - if (!locals.user) error(401, "Not logged in"); - const { name } = await request.json(); - if (!name?.trim()) error(400, "Name is required"); - const [created] = await db.insert(mappool).values({ - name: name.trim(), - createdBy: locals.user.id - }).returning(); - return json(created, { status: 201 }); -}; -export { - GET, - POST -}; diff --git a/.svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/_server.ts.js b/.svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/_server.ts.js deleted file mode 100644 index b383e98..0000000 --- a/.svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/_server.ts.js +++ /dev/null @@ -1,24 +0,0 @@ -import { error, json } from "@sveltejs/kit"; -import { a as cancelMatch, g as getMatchFull } from "../../../../../chunks/engine.js"; -const GET = async ({ params, locals }) => { - if (!locals.user) error(401, "Not logged in"); - try { - const m = await getMatchFull(params.id); - return json(m); - } catch (e) { - error(404, e.message); - } -}; -const DELETE = async ({ params, locals }) => { - if (!locals.user) error(401, "Not logged in"); - try { - const m = await cancelMatch(params.id); - return json(m); - } catch (e) { - error(400, e.message); - } -}; -export { - DELETE, - GET -}; diff --git a/.svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/lobby/_server.ts.js b/.svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/lobby/_server.ts.js deleted file mode 100644 index 35ed7aa..0000000 --- a/.svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/lobby/_server.ts.js +++ /dev/null @@ -1,15 +0,0 @@ -import { error, json } from "@sveltejs/kit"; -import { m as moveToLobby } from "../../../../../../chunks/engine.js"; -const POST = async ({ params, request, locals }) => { - if (!locals.user) error(401, "Not logged in"); - const body = await request.json().catch(() => ({})); - try { - const m = await moveToLobby(params.id, body.osuLobbyId); - return json(m); - } catch (e) { - error(400, e.message); - } -}; -export { - POST -}; diff --git a/.svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/pick/_server.ts.js b/.svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/pick/_server.ts.js deleted file mode 100644 index a655c49..0000000 --- a/.svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/pick/_server.ts.js +++ /dev/null @@ -1,18 +0,0 @@ -import { error, json } from "@sveltejs/kit"; -import { p as pickMap } from "../../../../../../chunks/engine.js"; -const POST = async ({ params, request, locals }) => { - if (!locals.user) error(401, "Not logged in"); - const { participantId, mappoolSlotId } = await request.json(); - if (!participantId || !mappoolSlotId) { - error(400, "participantId and mappoolSlotId required"); - } - try { - const game = await pickMap(params.id, participantId, mappoolSlotId); - return json(game); - } catch (e) { - error(400, e.message); - } -}; -export { - POST -}; diff --git a/.svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/roll/_server.ts.js b/.svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/roll/_server.ts.js deleted file mode 100644 index 21f102e..0000000 --- a/.svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/roll/_server.ts.js +++ /dev/null @@ -1,18 +0,0 @@ -import { error, json } from "@sveltejs/kit"; -import { s as submitRoll } from "../../../../../../chunks/engine.js"; -const POST = async ({ params, request, locals }) => { - if (!locals.user) error(401, "Not logged in"); - const { participantId, value } = await request.json(); - if (!participantId || value == null) { - error(400, "participantId and value required"); - } - try { - const m = await submitRoll(params.id, participantId, value); - return json(m); - } catch (e) { - error(400, e.message); - } -}; -export { - POST -}; diff --git a/.svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/rolling/_server.ts.js b/.svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/rolling/_server.ts.js deleted file mode 100644 index e5cc1e3..0000000 --- a/.svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/rolling/_server.ts.js +++ /dev/null @@ -1,14 +0,0 @@ -import { error, json } from "@sveltejs/kit"; -import { b as moveToRolling } from "../../../../../../chunks/engine.js"; -const POST = async ({ params, locals }) => { - if (!locals.user) error(401, "Not logged in"); - try { - const m = await moveToRolling(params.id); - return json(m); - } catch (e) { - error(400, e.message); - } -}; -export { - POST -}; diff --git a/.svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/score/_server.ts.js b/.svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/score/_server.ts.js deleted file mode 100644 index cd031cb..0000000 --- a/.svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/score/_server.ts.js +++ /dev/null @@ -1,18 +0,0 @@ -import { error, json } from "@sveltejs/kit"; -import { d as submitGameScores } from "../../../../../../chunks/engine.js"; -const POST = async ({ request, locals }) => { - if (!locals.user) error(401, "Not logged in"); - const { matchGameId, scores } = await request.json(); - if (!matchGameId || !scores?.length) { - error(400, "matchGameId and scores required"); - } - try { - const m = await submitGameScores(matchGameId, scores); - return json(m); - } catch (e) { - error(400, e.message); - } -}; -export { - POST -}; diff --git a/.svelte-kit/adapter-node/entries/endpoints/api/matches/_server.ts.js b/.svelte-kit/adapter-node/entries/endpoints/api/matches/_server.ts.js deleted file mode 100644 index 3732a25..0000000 --- a/.svelte-kit/adapter-node/entries/endpoints/api/matches/_server.ts.js +++ /dev/null @@ -1,37 +0,0 @@ -import { error, json } from "@sveltejs/kit"; -import { d as db } from "../../../../chunks/index2.js"; -import { c as createMatch } from "../../../../chunks/engine.js"; -const GET = async ({ locals }) => { - if (!locals.user) error(401, "Not logged in"); - const matches = await db.query.match.findMany({ - with: { - participants: { with: { team: true } } - }, - orderBy: (m, { desc }) => [desc(m.createdAt)] - }); - return json(matches); -}; -const POST = async ({ request, locals }) => { - if (!locals.user) error(401, "Not logged in"); - const body = await request.json(); - const { name, config, mappoolId, teams } = body; - if (!name || !config || !mappoolId || !teams?.length) { - error(400, "Missing required fields"); - } - try { - const result = await createMatch({ - name, - config, - mappoolId, - teams, - createdBy: locals.user.id - }); - return json(result, { status: 201 }); - } catch (e) { - error(400, e.message); - } -}; -export { - GET, - POST -}; diff --git a/.svelte-kit/adapter-node/entries/endpoints/api/osu/beatmap/_id_/_server.ts.js b/.svelte-kit/adapter-node/entries/endpoints/api/osu/beatmap/_id_/_server.ts.js deleted file mode 100644 index c258470..0000000 --- a/.svelte-kit/adapter-node/entries/endpoints/api/osu/beatmap/_id_/_server.ts.js +++ /dev/null @@ -1,14 +0,0 @@ -import { error, json } from "@sveltejs/kit"; -import { g as getBeatmap } from "../../../../../../chunks/api.js"; -const GET = async ({ params, locals }) => { - if (!locals.user) error(401, "Not logged in"); - try { - const beatmap = await getBeatmap(params.id); - return json(beatmap); - } catch { - error(404, "Beatmap not found"); - } -}; -export { - GET -}; diff --git a/.svelte-kit/adapter-node/entries/endpoints/api/queue/_server.ts.js b/.svelte-kit/adapter-node/entries/endpoints/api/queue/_server.ts.js deleted file mode 100644 index d6b0508..0000000 --- a/.svelte-kit/adapter-node/entries/endpoints/api/queue/_server.ts.js +++ /dev/null @@ -1,36 +0,0 @@ -import { error, json } from "@sveltejs/kit"; -import { l as leaveQueue, e as getQueueStatus, j as joinQueue } from "../../../../chunks/engine.js"; -import { d as db, t as teamMember } from "../../../../chunks/index2.js"; -import { eq } from "drizzle-orm"; -const GET = async ({ locals }) => { - if (!locals.user) error(401, "Not logged in"); - const status = await getQueueStatus(locals.user.id); - return json(status); -}; -const POST = async ({ locals }) => { - if (!locals.user) error(401, "Not logged in"); - const membership = await db.query.teamMember.findFirst({ - where: eq(teamMember.userId, locals.user.id), - with: { team: true } - }); - const personalTeam = membership?.team; - if (!personalTeam?.isPersonal) { - error(400, "No personal team found"); - } - try { - const result = await joinQueue(locals.user.id, personalTeam.id); - return json({ matched: !!result, match: result }); - } catch (e) { - error(400, e.message); - } -}; -const DELETE = async ({ locals }) => { - if (!locals.user) error(401, "Not logged in"); - await leaveQueue(locals.user.id); - return json({ ok: true }); -}; -export { - DELETE, - GET, - POST -}; diff --git a/.svelte-kit/adapter-node/entries/fallbacks/layout.svelte.js b/.svelte-kit/adapter-node/entries/fallbacks/layout.svelte.js deleted file mode 100644 index c3792df..0000000 --- a/.svelte-kit/adapter-node/entries/fallbacks/layout.svelte.js +++ /dev/null @@ -1,9 +0,0 @@ -import "clsx"; -function Layout($$renderer, $$props) { - let { children } = $$props; - children($$renderer); - $$renderer.push(``); -} -export { - Layout as default -}; diff --git a/.svelte-kit/adapter-node/entries/hooks.server.js b/.svelte-kit/adapter-node/entries/hooks.server.js deleted file mode 100644 index 35278f0..0000000 --- a/.svelte-kit/adapter-node/entries/hooks.server.js +++ /dev/null @@ -1,22 +0,0 @@ -import { b as building } from "../chunks/environment.js"; -import { a as auth, s as svelteKitHandler } from "../chunks/auth.js"; -import { d as db, u as user } from "../chunks/index2.js"; -import { eq } from "drizzle-orm"; -const handleBetterAuth = async ({ event, resolve }) => { - const session = await auth.api.getSession({ headers: event.request.headers }); - if (session) { - event.locals.session = session.session; - const dbUser = await db.query.user.findFirst({ - where: eq(user.id, session.user.id) - }); - event.locals.user = { - ...session.user, - role: dbUser?.role ?? "player" - }; - } - return svelteKitHandler({ event, resolve, auth, building }); -}; -const handle = handleBetterAuth; -export { - handle -}; diff --git a/.svelte-kit/adapter-node/entries/pages/(app)/_layout.server.ts.js b/.svelte-kit/adapter-node/entries/pages/(app)/_layout.server.ts.js deleted file mode 100644 index 18d72d1..0000000 --- a/.svelte-kit/adapter-node/entries/pages/(app)/_layout.server.ts.js +++ /dev/null @@ -1,14 +0,0 @@ -const load = async ({ locals }) => { - return { - user: locals.user ? { - id: locals.user.id, - name: locals.user.name, - email: locals.user.email, - image: locals.user.image, - role: locals.user.role ?? "player" - } : null - }; -}; -export { - load -}; diff --git a/.svelte-kit/adapter-node/entries/pages/(app)/_layout.svelte.js b/.svelte-kit/adapter-node/entries/pages/(app)/_layout.svelte.js deleted file mode 100644 index 068b523..0000000 --- a/.svelte-kit/adapter-node/entries/pages/(app)/_layout.svelte.js +++ /dev/null @@ -1,97 +0,0 @@ -import { a as ensure_array_like, b as attr, c as attr_class, s as stringify, e as escape_html, d as derived } from "../../../chunks/index3.js"; -import { p as page } from "../../../chunks/index4.js"; -import "@sveltejs/kit/internal"; -import "../../../chunks/url.js"; -import "../../../chunks/utils.js"; -import "@sveltejs/kit/internal/server"; -import "../../../chunks/root.js"; -import "../../../chunks/exports.js"; -import "../../../chunks/state.svelte.js"; -function Sidebar($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - const user = derived(() => page.data?.user); - const nav = [ - { href: "/", label: "Dashboard", icon: "⌂" }, - { href: "/matches", label: "Matches", icon: "⚔" }, - { href: "/mappools", label: "Mappools", icon: "♫" }, - { href: "/teams", label: "Teams", icon: "⚑" } - ]; - function isActive(href) { - if (href === "/") return page.url.pathname === "/"; - return page.url.pathname.startsWith(href); - } - const isAdmin = derived(() => user()?.role === "admin"); - $$renderer2.push(``); - }); -} -function Header($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - const user = derived(() => page.data?.user); - const roleBadge = { - referee: { label: "REF", color: "bg-yellow-500/20 text-yellow-400" }, - admin: { label: "ADMIN", color: "bg-red-500/20 text-red-400" } - }; - const badge = derived(() => user()?.role ? roleBadge[user().role] : null); - $$renderer2.push(`
`); - if (user()) { - $$renderer2.push(""); - $$renderer2.push(`
`); - if (badge()) { - $$renderer2.push(""); - $$renderer2.push(`${escape_html(badge().label)}`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (user().image) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` ${escape_html(user().name)}
`); - } else { - $$renderer2.push(""); - $$renderer2.push(`Sign in with osu!`); - } - $$renderer2.push(`
`); - }); -} -function _layout($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - let { children } = $$props; - const user = derived(() => page.data?.user); - if (user()) { - $$renderer2.push(""); - $$renderer2.push(`
`); - Sidebar($$renderer2); - $$renderer2.push(`
`); - Header($$renderer2); - $$renderer2.push(`
`); - children($$renderer2); - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - $$renderer2.push(`
V
Vash Esports
Sign in with osu!
`); - children($$renderer2); - $$renderer2.push(`
`); - } - $$renderer2.push(``); - }); -} -export { - _layout as default -}; diff --git a/.svelte-kit/adapter-node/entries/pages/(app)/_page.server.ts.js b/.svelte-kit/adapter-node/entries/pages/(app)/_page.server.ts.js deleted file mode 100644 index e04978c..0000000 --- a/.svelte-kit/adapter-node/entries/pages/(app)/_page.server.ts.js +++ /dev/null @@ -1,39 +0,0 @@ -import { d as db, b as match, c as team, m as mappool } from "../../../chunks/index2.js"; -import { desc, inArray, count, eq } from "drizzle-orm"; -const load = async ({ locals }) => { - if (!locals.user) { - return { - authenticated: false, - recentMatches: [], - liveMatches: [], - stats: { matches: 0, finished: 0, teams: 0, mappools: 0 } - }; - } - const recentMatches = await db.query.match.findMany({ - with: { participants: { with: { team: true } } }, - orderBy: desc(match.createdAt), - limit: 5 - }); - const liveMatches = await db.query.match.findMany({ - with: { participants: { with: { team: true } } }, - where: inArray(match.state, ["LOBBY", "ROLLING", "PICKING", "PLAYING"]) - }); - const [matchCount] = await db.select({ count: count() }).from(match); - const [teamCount] = await db.select({ count: count() }).from(team); - const [poolCount] = await db.select({ count: count() }).from(mappool); - const [finishedCount] = await db.select({ count: count() }).from(match).where(eq(match.state, "FINISHED")); - return { - authenticated: true, - recentMatches, - liveMatches, - stats: { - matches: matchCount.count, - finished: finishedCount.count, - teams: teamCount.count, - mappools: poolCount.count - } - }; -}; -export { - load -}; diff --git a/.svelte-kit/adapter-node/entries/pages/(app)/_page.svelte.js b/.svelte-kit/adapter-node/entries/pages/(app)/_page.svelte.js deleted file mode 100644 index 6f98657..0000000 --- a/.svelte-kit/adapter-node/entries/pages/(app)/_page.svelte.js +++ /dev/null @@ -1,118 +0,0 @@ -import { e as escape_html, a as ensure_array_like, b as attr, s as stringify, c as attr_class } from "../../../chunks/index3.js"; -function _page($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - let { data } = $$props; - const stateConfig = { - CREATED: { label: "Created", color: "text-text-secondary" }, - LOBBY: { label: "In Lobby", color: "text-yellow-400" }, - ROLLING: { - label: "Rolling", - color: "text-yellow-400", - dot: "bg-yellow-400" - }, - PICKING: { label: "Picking", color: "text-blue-400", dot: "bg-blue-400" }, - PLAYING: { label: "Live", color: "text-green-400", dot: "bg-green-400" }, - FINISHED: { label: "Finished", color: "text-text-secondary" }, - CANCELLED: { label: "Cancelled", color: "text-red-400" } - }; - let queueLoading = false; - function timeAgo(date) { - const d = new Date(date); - const diff = Date.now() - d.getTime(); - const mins = Math.floor(diff / 6e4); - if (mins < 1) return "just now"; - if (mins < 60) return `${mins}m ago`; - const hours = Math.floor(mins / 60); - if (hours < 24) return `${hours}h ago`; - const days = Math.floor(hours / 24); - return `${days}d ago`; - } - if (!data.user) { - $$renderer2.push(""); - $$renderer2.push(`
V

Welcome to Vash Esports

Automated tournament match management for osu! — lobbies, mappools, picks, bans, and - ELO tracking all in one place.

Sign in with osu!

Uses your osu! account. No extra registration needed.

`); - } else { - $$renderer2.push(""); - $$renderer2.push(`

Welcome back, ${escape_html(data.user.name)}

Automated esports match management for osu!

${escape_html(data.stats.matches)}

Total Matches

${escape_html(data.stats.finished)}

Completed

${escape_html(data.stats.teams)}

Teams

${escape_html(data.stats.mappools)}

Mappools

`); - if (data.liveMatches.length > 0) { - $$renderer2.push(""); - $$renderer2.push(`

Live Now

`); - const each_array = ensure_array_like(data.liveMatches); - for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) { - let m = each_array[$$index]; - const p1 = m.participants[0]; - const p2 = m.participants[1]; - const sc = stateConfig[m.state]; - $$renderer2.push(`
`); - if (p1?.team.avatarUrl) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` ${escape_html(p1?.team.name ?? "?")}
${escape_html(p1?.score ?? 0)} vs ${escape_html(p2?.score ?? 0)}
${escape_html(p2?.team.name ?? "?")} `); - if (p2?.team.avatarUrl) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - if (sc?.dot) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` ${escape_html(sc?.label)}`); - } - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`

Ranked Queue

Find a match at your skill level

`); - { - $$renderer2.push(""); - $$renderer2.push(`${escape_html("Find Match")}`); - } - $$renderer2.push(`

Recent Matches

`); - const each_array_1 = ensure_array_like(data.recentMatches); - if (each_array_1.length !== 0) { - $$renderer2.push(""); - for (let $$index_1 = 0, $$length = each_array_1.length; $$index_1 < $$length; $$index_1++) { - let m = each_array_1[$$index_1]; - const p1 = m.participants[0]; - const p2 = m.participants[1]; - const config = m.config; - const sc = stateConfig[m.state]; - $$renderer2.push(`
${escape_html(p1?.team.name ?? "?")} `); - if (m.state === "FINISHED") { - $$renderer2.push(""); - $$renderer2.push(` (p2?.score ?? 0) ? "text-green-400" : "text-text-secondary")}`)}>${escape_html(p1?.score ?? 0)} - (p1?.score ?? 0) ? "text-green-400" : "text-text-secondary")}`)}>${escape_html(p2?.score ?? 0)}`); - } else { - $$renderer2.push(""); - $$renderer2.push(`vs`); - } - $$renderer2.push(` ${escape_html(p2?.team.name ?? "?")}

${escape_html(m.name ? `${m.name} · ` : "")}BO${escape_html(config.bestOf)} - · ${escape_html(timeAgo(m.finishedAt ?? m.createdAt))}

`); - if (m.state === "FINISHED" && m.winnerId) { - $$renderer2.push(""); - const winner = m.participants.find((p) => p.teamId === m.winnerId); - $$renderer2.push(`🏆 ${escape_html(winner?.team.name)}`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` ${escape_html(sc?.label)}`); - } - } else { - $$renderer2.push(""); - $$renderer2.push(`

No matches yet. Create one

`); - } - $$renderer2.push(`
`); - } - $$renderer2.push(``); - }); -} -export { - _page as default -}; diff --git a/.svelte-kit/adapter-node/entries/pages/(app)/admin/_page.server.ts.js b/.svelte-kit/adapter-node/entries/pages/(app)/admin/_page.server.ts.js deleted file mode 100644 index 7f5e1cf..0000000 --- a/.svelte-kit/adapter-node/entries/pages/(app)/admin/_page.server.ts.js +++ /dev/null @@ -1,70 +0,0 @@ -import { d as db, u as user, p as playerRating } from "../../../../chunks/index2.js"; -import { eq, desc } from "drizzle-orm"; -import { error } from "@sveltejs/kit"; -const ROLE_HIERARCHY = { - player: 0, - referee: 1, - admin: 2 -}; -function hasRole(userRole, minRole) { - const level = ROLE_HIERARCHY[userRole] ?? 0; - const required = ROLE_HIERARCHY[minRole]; - return level >= required; -} -function requireRole(locals, minRole, message = "Insufficient permissions") { - if (!locals.user) { - error(401, "Not logged in"); - } - if (!hasRole(locals.user.role, minRole)) { - error(403, message); - } -} -async function setUserRole(userId, role) { - await db.update(user).set({ role }).where(eq(user.id, userId)); -} -const load = async ({ locals }) => { - requireRole(locals, "admin"); - const users = await db.query.user.findMany({ - orderBy: desc(user.createdAt) - }); - const usersWithRatings = await Promise.all( - users.map(async (u) => { - const rating = await db.query.playerRating.findFirst({ - where: eq(playerRating.userId, u.id) - }); - return { - id: u.id, - name: u.name, - email: u.email, - image: u.image, - role: u.role ?? "player", - createdAt: u.createdAt, - elo: rating?.elo ?? 1e3, - wins: rating?.wins ?? 0, - losses: rating?.losses ?? 0 - }; - }) - ); - return { users: usersWithRatings }; -}; -const actions = { - setRole: async ({ request, locals }) => { - requireRole(locals, "admin"); - const form = await request.formData(); - const userId = form.get("userId")?.toString(); - const role = form.get("role")?.toString(); - if (!userId || !role) return { error: "User ID and role are required" }; - if (!["player", "referee", "admin"].includes(role)) { - return { error: "Invalid role" }; - } - if (userId === locals.user.id && role !== "admin") { - return { error: "You can't demote yourself" }; - } - await setUserRole(userId, role); - return { success: true }; - } -}; -export { - actions, - load -}; diff --git a/.svelte-kit/adapter-node/entries/pages/(app)/admin/_page.svelte.js b/.svelte-kit/adapter-node/entries/pages/(app)/admin/_page.svelte.js deleted file mode 100644 index 59b9970..0000000 --- a/.svelte-kit/adapter-node/entries/pages/(app)/admin/_page.svelte.js +++ /dev/null @@ -1,70 +0,0 @@ -import { e as escape_html, a as ensure_array_like, b as attr, s as stringify } from "../../../../chunks/index3.js"; -import "@sveltejs/kit/internal"; -import "../../../../chunks/url.js"; -import "../../../../chunks/utils.js"; -import "@sveltejs/kit/internal/server"; -import "../../../../chunks/root.js"; -import "../../../../chunks/exports.js"; -import "../../../../chunks/state.svelte.js"; -function _page($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - let { data } = $$props; - const roleBadge = { - player: { - label: "Player", - color: "bg-surface-600 text-text-secondary border-border" - }, - referee: { - label: "Referee", - color: "bg-yellow-500/20 text-yellow-400 border-yellow-500/30" - }, - admin: { - label: "Admin", - color: "bg-red-500/20 text-red-400 border-red-500/30" - } - }; - $$renderer2.push(`

Admin Panel

${escape_html(data.users.length)} registered user${escape_html(data.users.length !== 1 ? "s" : "")}

`); - { - $$renderer2.push(""); - } - $$renderer2.push(`
Avatar User ELO W/L Role
`); - const each_array = ensure_array_like(data.users); - for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) { - let u = each_array[$$index]; - const badge = roleBadge[u.role] ?? roleBadge.player; - $$renderer2.push(`
`); - if (u.image) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - $$renderer2.push(`
${escape_html(u.name.charAt(0).toUpperCase())}
`); - } - $$renderer2.push(`

${escape_html(u.name)}

${escape_html(u.email)}

${escape_html(u.elo)} ${escape_html(u.wins)}W / ${escape_html(u.losses)}L
`); - $$renderer2.select( - { - name: "role", - value: u.role, - onchange: (e) => e.currentTarget.form?.requestSubmit(), - class: `rounded-md border px-2 py-1 text-xs font-500 ${stringify(badge.color)} cursor-pointer bg-transparent focus:outline-none` - }, - ($$renderer3) => { - $$renderer3.option({ value: "player", class: "bg-surface-800 text-text-primary" }, ($$renderer4) => { - $$renderer4.push(`Player`); - }); - $$renderer3.option({ value: "referee", class: "bg-surface-800 text-text-primary" }, ($$renderer4) => { - $$renderer4.push(`Referee`); - }); - $$renderer3.option({ value: "admin", class: "bg-surface-800 text-text-primary" }, ($$renderer4) => { - $$renderer4.push(`Admin`); - }); - } - ); - $$renderer2.push(`
`); - } - $$renderer2.push(`
`); - }); -} -export { - _page as default -}; diff --git a/.svelte-kit/adapter-node/entries/pages/(app)/mappools/_id_/_page.server.ts.js b/.svelte-kit/adapter-node/entries/pages/(app)/mappools/_id_/_page.server.ts.js deleted file mode 100644 index cbdf47b..0000000 --- a/.svelte-kit/adapter-node/entries/pages/(app)/mappools/_id_/_page.server.ts.js +++ /dev/null @@ -1,100 +0,0 @@ -import { d as db, m as mappool, a as mappoolSlot } from "../../../../../chunks/index2.js"; -import { eq, and } from "drizzle-orm"; -import { redirect, error } from "@sveltejs/kit"; -import { g as getBeatmap } from "../../../../../chunks/api.js"; -const load = async ({ params, locals }) => { - if (!locals.user) redirect(302, "/"); - const pool = await db.query.mappool.findFirst({ - where: eq(mappool.id, params.id), - with: { - slots: { - orderBy: (s, { asc }) => [asc(s.category), asc(s.orderInCategory)] - } - } - }); - if (!pool) error(404, "Mappool not found"); - const slotsWithBeatmaps = await Promise.all( - pool.slots.map(async (slot) => { - try { - const beatmap = await getBeatmap(slot.beatmapId); - return { - ...slot, - beatmap: { - title: beatmap.beatmapset.title, - artist: beatmap.beatmapset.artist, - version: beatmap.version, - starRating: beatmap.difficulty_rating, - bpm: beatmap.bpm, - totalLength: beatmap.total_length, - coverUrl: beatmap.beatmapset.covers["card@2x"], - url: beatmap.url - } - }; - } catch { - return { - ...slot, - beatmap: null - }; - } - }) - ); - return { - pool: { ...pool, slots: slotsWithBeatmaps } - }; -}; -const actions = { - addSlot: async ({ params, request, locals }) => { - if (!locals.user) redirect(302, "/"); - const form = await request.formData(); - let beatmapId = form.get("beatmapId")?.toString()?.trim(); - const category = form.get("category")?.toString()?.trim()?.toUpperCase(); - if (!beatmapId || !category) { - return { error: "Beatmap ID and category are required" }; - } - const urlMatch = beatmapId.match(/beatmaps\/(\d+)/); - const setMatch = beatmapId.match(/beatmapsets\/\d+#\w+\/(\d+)/); - if (urlMatch) beatmapId = urlMatch[1]; - else if (setMatch) beatmapId = setMatch[1]; - if (!/^\d+$/.test(beatmapId)) { - return { error: "Invalid beatmap ID" }; - } - let beatmap; - try { - beatmap = await getBeatmap(beatmapId); - } catch { - return { error: "Beatmap not found on osu!" }; - } - const existing = await db.query.mappoolSlot.findMany({ - where: and( - eq(mappoolSlot.mappoolId, params.id), - eq(mappoolSlot.category, category) - ) - }); - await db.insert(mappoolSlot).values({ - mappoolId: params.id, - beatmapId, - category, - orderInCategory: existing.length + 1, - starRating: beatmap.difficulty_rating, - mods: category === "NM" || category === "TB" || category === "FM" ? [] : [category] - }); - return { success: true }; - }, - removeSlot: async ({ request, locals }) => { - if (!locals.user) redirect(302, "/"); - const form = await request.formData(); - const slotId = form.get("slotId")?.toString(); - if (!slotId) return { error: "Missing slot ID" }; - await db.delete(mappoolSlot).where(eq(mappoolSlot.id, slotId)); - return { success: true }; - }, - deletePool: async ({ params, locals }) => { - if (!locals.user) redirect(302, "/"); - await db.delete(mappool).where(eq(mappool.id, params.id)); - redirect(303, "/mappools"); - } -}; -export { - actions, - load -}; diff --git a/.svelte-kit/adapter-node/entries/pages/(app)/mappools/_id_/_page.svelte.js b/.svelte-kit/adapter-node/entries/pages/(app)/mappools/_id_/_page.svelte.js deleted file mode 100644 index 0a8825e..0000000 --- a/.svelte-kit/adapter-node/entries/pages/(app)/mappools/_id_/_page.svelte.js +++ /dev/null @@ -1,98 +0,0 @@ -import { e as escape_html, a as ensure_array_like, b as attr, c as attr_class, d as derived, s as stringify } from "../../../../../chunks/index3.js"; -import "@sveltejs/kit/internal"; -import "../../../../../chunks/url.js"; -import "../../../../../chunks/utils.js"; -import "@sveltejs/kit/internal/server"; -import "../../../../../chunks/root.js"; -import "../../../../../chunks/exports.js"; -import "../../../../../chunks/state.svelte.js"; -function _page($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - let { data } = $$props; - const categories = ["NM", "HD", "HR", "DT", "FM", "TB"]; - let addingCategory = "NM"; - let beatmapInput = ""; - const grouped = derived(() => () => { - const groups = {}; - for (const cat of categories) { - const slots = data.pool.slots.filter((s) => s.category === cat); - if (slots.length > 0) groups[cat] = slots; - } - return groups; - }); - function formatLength(seconds) { - const m = Math.floor(seconds / 60); - const s = seconds % 60; - return `${m}:${s.toString().padStart(2, "0")}`; - } - const categoryColors = { - NM: "bg-blue-500/20 text-blue-400 border-blue-500/30", - HD: "bg-yellow-500/20 text-yellow-400 border-yellow-500/30", - HR: "bg-red-500/20 text-red-400 border-red-500/30", - DT: "bg-purple-500/20 text-purple-400 border-purple-500/30", - FM: "bg-green-500/20 text-green-400 border-green-500/30", - TB: "bg-pink-500/20 text-pink-400 border-pink-500/30" - }; - $$renderer2.push(`
←

${escape_html(data.pool.name)}

${escape_html(data.pool.slots.length)} map${escape_html(data.pool.slots.length !== 1 ? "s" : "")}

Add Map

`); - $$renderer2.select( - { - name: "category", - value: addingCategory, - class: "rounded-md border border-border bg-surface-700 px-3 py-2 text-sm text-text-primary focus:border-accent focus:outline-none" - }, - ($$renderer3) => { - $$renderer3.push(``); - const each_array = ensure_array_like(categories); - for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) { - let cat = each_array[$$index]; - $$renderer3.option({ value: cat }, ($$renderer4) => { - $$renderer4.push(`${escape_html(cat)}`); - }); - } - $$renderer3.push(``); - } - ); - $$renderer2.push(`
`); - { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - const each_array_1 = ensure_array_like(Object.entries(grouped()())); - if (each_array_1.length !== 0) { - $$renderer2.push(""); - for (let $$index_2 = 0, $$length = each_array_1.length; $$index_2 < $$length; $$index_2++) { - let [category, slots] = each_array_1[$$index_2]; - $$renderer2.push(`
${escape_html(category)} ${escape_html(slots.length)} map${escape_html(slots.length !== 1 ? "s" : "")}
`); - const each_array_2 = ensure_array_like(slots); - for (let i = 0, $$length2 = each_array_2.length; i < $$length2; i++) { - let slot = each_array_2[i]; - $$renderer2.push(`
`); - if (slot.beatmap?.coverUrl) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - $$renderer2.push(`
No cover
`); - } - $$renderer2.push(`
`); - if (slot.beatmap) { - $$renderer2.push(""); - $$renderer2.push(`${escape_html(slot.beatmap.artist)} - ${escape_html(slot.beatmap.title)}
[${escape_html(slot.beatmap.version)}] ★ ${escape_html(slot.beatmap.starRating.toFixed(2))} ${escape_html(slot.beatmap.bpm)} BPM ${escape_html(formatLength(slot.beatmap.totalLength))}
`); - } else { - $$renderer2.push(""); - $$renderer2.push(`

Beatmap #${escape_html(slot.beatmapId)}

`); - } - $$renderer2.push(`
${escape_html(category)}${escape_html(i + 1)}
`); - } - $$renderer2.push(`
`); - } - } else { - $$renderer2.push(""); - $$renderer2.push(`

No maps yet. Add your first map above.

`); - } - $$renderer2.push(`
`); - }); -} -export { - _page as default -}; diff --git a/.svelte-kit/adapter-node/entries/pages/(app)/mappools/_page.server.ts.js b/.svelte-kit/adapter-node/entries/pages/(app)/mappools/_page.server.ts.js deleted file mode 100644 index 77c98ad..0000000 --- a/.svelte-kit/adapter-node/entries/pages/(app)/mappools/_page.server.ts.js +++ /dev/null @@ -1,24 +0,0 @@ -import { d as db, m as mappool } from "../../../../chunks/index2.js"; -import { redirect } from "@sveltejs/kit"; -const load = async ({ locals }) => { - if (!locals.user) redirect(302, "/"); - const mappools = await db.query.mappool.findMany({ - with: { slots: true }, - orderBy: (m, { desc }) => [desc(m.createdAt)] - }); - return { mappools }; -}; -const actions = { - create: async ({ request, locals }) => { - if (!locals.user) redirect(302, "/"); - const form = await request.formData(); - const name = form.get("name")?.toString()?.trim(); - if (!name) return { error: "Name is required" }; - const [created] = await db.insert(mappool).values({ name, createdBy: locals.user.id }).returning(); - redirect(303, `/mappools/${created.id}`); - } -}; -export { - actions, - load -}; diff --git a/.svelte-kit/adapter-node/entries/pages/(app)/mappools/_page.svelte.js b/.svelte-kit/adapter-node/entries/pages/(app)/mappools/_page.svelte.js deleted file mode 100644 index c122aec..0000000 --- a/.svelte-kit/adapter-node/entries/pages/(app)/mappools/_page.svelte.js +++ /dev/null @@ -1,34 +0,0 @@ -import { e as escape_html, a as ensure_array_like, b as attr, s as stringify } from "../../../../chunks/index3.js"; -import "@sveltejs/kit/internal"; -import "../../../../chunks/url.js"; -import "../../../../chunks/utils.js"; -import "@sveltejs/kit/internal/server"; -import "../../../../chunks/root.js"; -import "../../../../chunks/exports.js"; -import "../../../../chunks/state.svelte.js"; -function _page($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - let { data } = $$props; - $$renderer2.push(`

Mappools

Create and manage your beatmap pools

`); - { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - const each_array = ensure_array_like(data.mappools); - if (each_array.length !== 0) { - $$renderer2.push(""); - for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) { - let pool = each_array[$$index]; - $$renderer2.push(`

${escape_html(pool.name)}

${escape_html(pool.slots.length)} map${escape_html(pool.slots.length !== 1 ? "s" : "")} - · Created ${escape_html(new Date(pool.createdAt).toLocaleDateString())}

→`); - } - } else { - $$renderer2.push(""); - $$renderer2.push(`

No mappools yet. Create one to get started.

`); - } - $$renderer2.push(`
`); - }); -} -export { - _page as default -}; diff --git a/.svelte-kit/adapter-node/entries/pages/(app)/matches/_id_/_page.server.ts.js b/.svelte-kit/adapter-node/entries/pages/(app)/matches/_id_/_page.server.ts.js deleted file mode 100644 index 497a952..0000000 --- a/.svelte-kit/adapter-node/entries/pages/(app)/matches/_id_/_page.server.ts.js +++ /dev/null @@ -1,129 +0,0 @@ -import { d as db, u as user } from "../../../../../chunks/index2.js"; -import { a as cancelMatch, g as getMatchFull, p as pickMap, s as submitRoll } from "../../../../../chunks/engine.js"; -import { c as closeLobby, f as forceStartGame, p as playPickedMap, g as getLobby } from "../../../../../chunks/orchestrator.js"; -import { redirect, error } from "@sveltejs/kit"; -import { g as getBeatmap } from "../../../../../chunks/api.js"; -import { eq } from "drizzle-orm"; -const load = async ({ params, locals }) => { - if (!locals.user) redirect(302, "/"); - let m; - try { - m = await getMatchFull(params.id); - } catch { - error(404, "Match not found"); - } - const beatmapCache = {}; - if (m.mappool?.slots) { - await Promise.allSettled( - m.mappool.slots.map(async (slot) => { - try { - const bm = await getBeatmap(slot.beatmapId); - beatmapCache[slot.beatmapId] = { - title: bm.beatmapset.title, - artist: bm.beatmapset.artist, - version: bm.version, - starRating: bm.difficulty_rating, - bpm: bm.bpm, - totalLength: bm.total_length, - coverUrl: bm.beatmapset.covers["card@2x"], - listCoverUrl: bm.beatmapset.covers["list@2x"] - }; - } catch { - } - }) - ); - } - return { match: m, beatmapCache, userId: locals.user.id }; -}; -const actions = { - reinvite: async ({ params, locals }) => { - if (!locals.user) redirect(302, "/"); - const lobby = getLobby(params.id); - if (!lobby) return { error: "No active IRC lobby for this match" }; - const m = await getMatchFull(params.id); - const invited = []; - for (const p of m.participants) { - for (const pl of p.players) { - const u = await db.query.user.findFirst({ where: eq(user.id, pl.userId) }); - if (u?.name) { - await lobby.invite(u.name); - invited.push(u.name); - } - } - } - return { reinvited: invited }; - }, - roll: async ({ params, locals }) => { - if (!locals.user) redirect(302, "/"); - const m = await getMatchFull(params.id); - let myParticipant = m.participants.find( - (p) => p.players.some((pl) => pl.userId === locals.user.id) - ); - if (!myParticipant) { - return { error: "You are not in this match" }; - } - if (myParticipant.rollValue !== null) { - const unrolled = m.participants.find((p) => p.rollValue === null); - if (unrolled) { - myParticipant = unrolled; - } else { - return { error: "All participants have already rolled" }; - } - } - const value = Math.floor(Math.random() * 100) + 1; - await submitRoll(params.id, myParticipant.id, value); - const lobby = getLobby(params.id); - if (lobby) { - lobby.chat(`${myParticipant.team?.name ?? "Player"} rolled ${value} (via web)`).catch(() => { - }); - const updated = await getMatchFull(params.id); - if (updated.state === "PICKING") { - const sorted = [...updated.participants].sort( - (a, b) => (a.pickOrder ?? 99) - (b.pickOrder ?? 99) - ); - lobby.chat( - `Rolls complete! ${sorted[0]?.team.name} picks first. Use !pick (e.g. !pick NM1) or pick in web UI.` - ).catch(() => { - }); - } - } - return { rolled: value, participantId: myParticipant.id }; - }, - pick: async ({ params, request, locals }) => { - if (!locals.user) redirect(302, "/"); - const form = await request.formData(); - const slotId = form.get("slotId")?.toString(); - if (!slotId) return { error: "No map selected" }; - const m = await getMatchFull(params.id); - const sorted = [...m.participants].sort( - (a, b) => (a.pickOrder ?? 99) - (b.pickOrder ?? 99) - ); - const expectedIdx = m.games.length % sorted.length; - const expectedPicker = sorted[expectedIdx]; - if (!expectedPicker) return { error: "Cannot determine picker" }; - try { - const game = await pickMap(params.id, expectedPicker.id, slotId); - playPickedMap(params.id, game.id).catch( - (err) => console.error("[Match] IRC play failed:", err.message) - ); - return { picked: true, gameId: game.id }; - } catch (e) { - return { error: e.message }; - } - }, - forceStart: async ({ params, locals }) => { - if (!locals.user) redirect(302, "/"); - await forceStartGame(params.id); - return { started: true }; - }, - cancel: async ({ params, locals }) => { - if (!locals.user) redirect(302, "/"); - await cancelMatch(params.id); - await closeLobby(params.id); - redirect(303, "/matches"); - } -}; -export { - actions, - load -}; diff --git a/.svelte-kit/adapter-node/entries/pages/(app)/matches/_id_/_page.svelte.js b/.svelte-kit/adapter-node/entries/pages/(app)/matches/_id_/_page.svelte.js deleted file mode 100644 index e6b854f..0000000 --- a/.svelte-kit/adapter-node/entries/pages/(app)/matches/_id_/_page.svelte.js +++ /dev/null @@ -1,323 +0,0 @@ -import { e as escape_html, b as attr, s as stringify, c as attr_class, a as ensure_array_like, d as derived } from "../../../../../chunks/index3.js"; -import "@sveltejs/kit/internal"; -import "../../../../../chunks/url.js"; -import "../../../../../chunks/utils.js"; -import "@sveltejs/kit/internal/server"; -import "../../../../../chunks/root.js"; -import "../../../../../chunks/exports.js"; -import "../../../../../chunks/state.svelte.js"; -function _page($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - let { data } = $$props; - let m = derived(() => data.match); - let p1 = derived(() => m().participants[0]); - let p2 = derived(() => m().participants[1]); - const config = derived(() => m().config); - const winsNeeded = derived(() => Math.ceil(config().bestOf / 2)); - const playedSlotIds = derived(() => new Set(m().games.map((g) => g.mappoolSlotId))); - const sortedByPick = derived(() => [...m().participants].sort((a, b) => (a.pickOrder ?? 99) - (b.pickOrder ?? 99))); - const expectedPickerIdx = derived(() => m().games.length % sortedByPick().length); - const expectedPicker = derived(() => sortedByPick()[expectedPickerIdx()]); - const canRoll = derived(() => m().state === "ROLLING" && m().participants.some((p) => p.rollValue === null)); - const catColors = { - NM: "bg-blue-500/20 text-blue-400 border-blue-500/30", - HD: "bg-yellow-500/20 text-yellow-400 border-yellow-500/30", - HR: "bg-red-500/20 text-red-400 border-red-500/30", - DT: "bg-purple-500/20 text-purple-400 border-purple-500/30", - FM: "bg-green-500/20 text-green-400 border-green-500/30", - TB: "bg-pink-500/20 text-pink-400 border-pink-500/30" - }; - const groupedSlots = derived(() => () => { - if (!m().mappool?.slots) return {}; - const groups = {}; - for (const slot of m().mappool.slots) { - if (!groups[slot.category]) groups[slot.category] = []; - groups[slot.category].push(slot); - } - for (const cat of Object.keys(groups)) { - groups[cat].sort((a, b) => a.orderInCategory - b.orderInCategory); - } - return groups; - }); - let rolling = false; - let picking = false; - let forceStarting = false; - function formatLength(seconds) { - const mins = Math.floor(seconds / 60); - const secs = seconds % 60; - return `${mins}:${secs.toString().padStart(2, "0")}`; - } - function stateLabel(s) { - return { - CREATED: "Waiting", - LOBBY: "In Lobby", - ROLLING: "Rolling", - PICKING: "Pick Phase", - PLAYING: "Playing", - FINISHED: "Finished", - CANCELLED: "Cancelled" - }[s] ?? s; - } - function stateBorder(s) { - return { - ROLLING: "border-yellow-500/30", - PICKING: "border-blue-500/30", - PLAYING: "border-green-500/30", - FINISHED: "border-accent/30" - }[s] ?? "border-border"; - } - $$renderer2.push(`
←

${escape_html(m().name || "Match")}

Best of ${escape_html(config().bestOf)} · First to ${escape_html(winsNeeded())} `); - if (m().osuLobbyId) { - $$renderer2.push(""); - $$renderer2.push(`· osu! mp/${escape_html(m().osuLobbyId)}`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`

${escape_html(stateLabel(m().state))} `); - if (!["FINISHED", "CANCELLED"].includes(m().state)) { - $$renderer2.push(""); - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - if (p1() && p2()) { - $$renderer2.push(""); - $$renderer2.push(`
`); - if (p1().team.avatarUrl) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`

${escape_html(p1().team.name)}

`); - if (p1().rollValue != null) { - $$renderer2.push(""); - $$renderer2.push(`

Roll: ${escape_html(p1().rollValue)}${escape_html(p1().pickOrder === 1 ? " ★" : "")}

`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
= winsNeeded() ? "text-green-400" : "text-text-primary")}`)}>${escape_html(p1().score)}
vs = winsNeeded() ? "text-green-400" : "text-text-primary")}`)}>${escape_html(p2().score)}

${escape_html(p2().team.name)}

`); - if (p2().rollValue != null) { - $$renderer2.push(""); - $$renderer2.push(`

${escape_html(p2().pickOrder === 1 ? "★ " : "")}Roll: ${escape_html(p2().rollValue)}

`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - if (p2().team.avatarUrl) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (["LOBBY", "ROLLING", "PICKING", "PLAYING"].includes(m().state)) { - $$renderer2.push(""); - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (m().state === "ROLLING") { - $$renderer2.push(""); - $$renderer2.push(`

🎲 Roll Phase

Highest roll picks first

`); - const each_array = ensure_array_like(m().participants); - for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) { - let p = each_array[$$index]; - $$renderer2.push(`

${escape_html(p.team.name)}

`); - if (p.rollValue != null) { - $$renderer2.push(""); - $$renderer2.push(`

${escape_html(p.rollValue)}

`); - } else { - $$renderer2.push(""); - $$renderer2.push(`

—

`); - } - $$renderer2.push(`
`); - } - $$renderer2.push(`
`); - if (canRoll()) { - $$renderer2.push(""); - $$renderer2.push(`

or type !roll in osu! chat

`); - } else { - $$renderer2.push(""); - $$renderer2.push(`

Waiting for all rolls...

`); - } - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (m().state === "PICKING") { - $$renderer2.push(""); - $$renderer2.push(`

🎯 Pick a Map

${escape_html(expectedPicker()?.team.name)}'s turn to pick

or type !pick NM1 in osu! chat

`); - { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - const each_array_1 = ensure_array_like(Object.entries(groupedSlots()())); - for (let $$index_2 = 0, $$length = each_array_1.length; $$index_2 < $$length; $$index_2++) { - let [category, slots] = each_array_1[$$index_2]; - $$renderer2.push(`
${escape_html(category)}
`); - const each_array_2 = ensure_array_like(slots); - for (let i = 0, $$length2 = each_array_2.length; i < $$length2; i++) { - let slot = each_array_2[i]; - const bm = data.beatmapCache[slot.beatmapId]; - const isPlayed = playedSlotIds().has(slot.id); - $$renderer2.push(`
`); - } - $$renderer2.push(`
`); - } - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (m().state === "PLAYING") { - $$renderer2.push(""); - const currentGame = m().games[m().games.length - 1]; - const bm = currentGame ? data.beatmapCache[currentGame.slot?.beatmapId] : null; - $$renderer2.push(`
Now Playing
`); - if (bm) { - $$renderer2.push(""); - $$renderer2.push(`

${escape_html(bm.artist)} - ${escape_html(bm.title)} [${escape_html(bm.version)}]

★${escape_html(bm.starRating.toFixed(1))} · ${escape_html(bm.bpm)}bpm · ${escape_html(formatLength(bm.totalLength))}

`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`

Waiting for players to ready up & play in osu!...

`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (m().state === "FINISHED") { - $$renderer2.push(""); - const winner = m().participants.find((p) => p.teamId === m().winnerId); - $$renderer2.push(`
🏆

${escape_html(winner?.team.name)} wins!

${escape_html(p1()?.score)} – ${escape_html(p2()?.score)}

`); - const each_array_3 = ensure_array_like(m().games); - for (let $$index_3 = 0, $$length = each_array_3.length; $$index_3 < $$length; $$index_3++) { - let game = each_array_3[$$index_3]; - const bm = data.beatmapCache[game.slot?.beatmapId]; - const winnerP = m().participants.find((p) => p.id === game.winnerParticipantId); - $$renderer2.push(`
${escape_html(game.slot?.category)}${escape_html(game.slot?.orderInCategory)} ${escape_html(bm ? `${bm.artist} - ${bm.title}` : `#${game.slot?.beatmapId}`)} ${escape_html(winnerP?.team.name)}
`); - } - $$renderer2.push(`
Back to Dashboard
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (m().games.length > 0) { - $$renderer2.push(""); - $$renderer2.push(`

Games Played

`); - const each_array_4 = ensure_array_like(m().games); - for (let $$index_4 = 0, $$length = each_array_4.length; $$index_4 < $$length; $$index_4++) { - let game = each_array_4[$$index_4]; - const bm = data.beatmapCache[game.slot?.beatmapId]; - const pickerTeam = m().participants.find((p) => p.id === game.pickedByParticipantId)?.team; - const winnerTeam = m().participants.find((p) => p.id === game.winnerParticipantId)?.team; - $$renderer2.push(`
${escape_html(game.gameNumber)} `); - if (bm?.listCoverUrl) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - if (bm) { - $$renderer2.push(""); - $$renderer2.push(`

${escape_html(bm.artist)} - ${escape_html(bm.title)} [${escape_html(bm.version)}]

`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
${escape_html(game.slot?.category)}${escape_html(game.slot?.orderInCategory)} `); - if (pickerTeam) { - $$renderer2.push(""); - $$renderer2.push(`Picked by ${escape_html(pickerTeam.name)}`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - if (game.state === "FINISHED" && p1() && p2()) { - $$renderer2.push(""); - const p1Score = game.scores.filter((s) => s.player?.participantId === p1().id).reduce((sum, s) => sum + s.score, 0); - const p2Score = game.scores.filter((s) => s.player?.participantId === p2().id).reduce((sum, s) => sum + s.score, 0); - $$renderer2.push(`
p2Score ? "font-700 text-green-400" : "text-text-secondary")}>${escape_html(p1Score.toLocaleString())} - p1Score ? "font-700 text-green-400" : "text-text-secondary")}>${escape_html(p2Score.toLocaleString())}
`); - } else if (game.state === "PLAYING") { - $$renderer2.push(""); - $$renderer2.push(`Live`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (winnerTeam) { - $$renderer2.push(""); - $$renderer2.push(`✓ ${escape_html(winnerTeam.name)}`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - } - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (m().state === "CREATED") { - $$renderer2.push(""); - $$renderer2.push(`

Creating osu! lobby...

`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (m().state === "LOBBY") { - $$renderer2.push(""); - $$renderer2.push(`

Lobby created. Waiting for players to join...

`); - if (m().osuLobbyId) { - $$renderer2.push(""); - $$renderer2.push(`

osu! mp/${escape_html(m().osuLobbyId)}

`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (m().state === "CANCELLED") { - $$renderer2.push(""); - $$renderer2.push(`

This match was cancelled.

`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(``); - }); -} -export { - _page as default -}; diff --git a/.svelte-kit/adapter-node/entries/pages/(app)/matches/_page.server.ts.js b/.svelte-kit/adapter-node/entries/pages/(app)/matches/_page.server.ts.js deleted file mode 100644 index 2891ac2..0000000 --- a/.svelte-kit/adapter-node/entries/pages/(app)/matches/_page.server.ts.js +++ /dev/null @@ -1,58 +0,0 @@ -import { d as db, b as match } from "../../../../chunks/index2.js"; -import { redirect } from "@sveltejs/kit"; -import { desc } from "drizzle-orm"; -import { c as createMatch } from "../../../../chunks/engine.js"; -import { i as initMatchLobby } from "../../../../chunks/orchestrator.js"; -const load = async ({ locals }) => { - if (!locals.user) redirect(302, "/"); - const matches = await db.query.match.findMany({ - with: { participants: { with: { team: true } } }, - orderBy: desc(match.createdAt), - limit: 50 - }); - const teams = await db.query.team.findMany({ - orderBy: (t, { asc }) => [asc(t.name)] - }); - const mappools = await db.query.mappool.findMany({ - with: { slots: true }, - orderBy: (m, { desc: desc2 }) => [desc2(m.createdAt)] - }); - return { matches, teams, mappools }; -}; -const actions = { - createMatch: async ({ request, locals }) => { - if (!locals.user) redirect(302, "/"); - const form = await request.formData(); - const name = form.get("name")?.toString()?.trim() || "Custom Match"; - const team1Id = form.get("team1")?.toString(); - const team2Id = form.get("team2")?.toString(); - const mappoolId = form.get("mappool")?.toString(); - const bestOf = parseInt(form.get("bestOf")?.toString() ?? "7"); - console.log("[Matches] CREATE:", { name, team1Id, team2Id, mappoolId, bestOf }); - if (!team1Id || !team2Id || !mappoolId) { - return { error: "All fields are required" }; - } - let result; - try { - result = await createMatch({ - name, - config: { bestOf, teamSize: 1, scoringType: "score" }, - mappoolId, - teams: [team1Id, team2Id], - createdBy: locals.user.id - }); - console.log("[Matches] Created:", result.id); - } catch (e) { - console.error("[Matches] Error:", e); - return { error: e.message }; - } - initMatchLobby(result.id).catch((err) => { - console.error("[Matches] IRC lobby failed:", err.message); - }); - redirect(303, `/matches/${result.id}`); - } -}; -export { - actions, - load -}; diff --git a/.svelte-kit/adapter-node/entries/pages/(app)/matches/_page.svelte.js b/.svelte-kit/adapter-node/entries/pages/(app)/matches/_page.svelte.js deleted file mode 100644 index 9af67ae..0000000 --- a/.svelte-kit/adapter-node/entries/pages/(app)/matches/_page.svelte.js +++ /dev/null @@ -1,164 +0,0 @@ -import { e as escape_html, a as ensure_array_like, b as attr, s as stringify, c as attr_class, d as derived } from "../../../../chunks/index3.js"; -import "@sveltejs/kit/internal"; -import "../../../../chunks/url.js"; -import "../../../../chunks/utils.js"; -import "@sveltejs/kit/internal/server"; -import "../../../../chunks/root.js"; -import "../../../../chunks/exports.js"; -import "../../../../chunks/state.svelte.js"; -function _page($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - let { data } = $$props; - const stateConfig = { - CREATED: { label: "Created", color: "text-text-secondary border-border" }, - LOBBY: { - label: "In Lobby", - color: "text-yellow-400 border-yellow-500/30" - }, - ROLLING: { - label: "Rolling", - color: "text-yellow-400 border-yellow-500/30", - dot: "bg-yellow-400" - }, - PICKING: { - label: "Picking", - color: "text-blue-400 border-blue-500/30", - dot: "bg-blue-400" - }, - PLAYING: { - label: "Live", - color: "text-green-400 border-green-500/30", - dot: "bg-green-400" - }, - FINISHED: { - label: "Finished", - color: "text-text-secondary border-border" - }, - CANCELLED: { label: "Cancelled", color: "text-red-400 border-red-500/30" } - }; - const liveStates = ["LOBBY", "ROLLING", "PICKING", "PLAYING"]; - const liveMatches = derived(() => data.matches.filter((m) => liveStates.includes(m.state))); - const recentMatches = derived(() => data.matches.filter((m) => !liveStates.includes(m.state))); - function teamDisplay(m) { - const p1 = m.participants[0]; - const p2 = m.participants[1]; - return { p1, p2 }; - } - function timeAgo(date) { - const d = new Date(date); - const diff = Date.now() - d.getTime(); - const mins = Math.floor(diff / 6e4); - if (mins < 1) return "just now"; - if (mins < 60) return `${mins}m ago`; - const hours = Math.floor(mins / 60); - if (hours < 24) return `${hours}h ago`; - const days = Math.floor(hours / 24); - return `${days}d ago`; - } - $$renderer2.push(`

Matches

${escape_html(data.matches.length)} match${escape_html(data.matches.length !== 1 ? "es" : "")} `); - if (liveMatches().length > 0) { - $$renderer2.push(""); - $$renderer2.push(`· ${escape_html(liveMatches().length)} live`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`

`); - { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (liveMatches().length > 0) { - $$renderer2.push(""); - $$renderer2.push(`

Live Now

`); - const each_array_4 = ensure_array_like(liveMatches()); - for (let $$index_4 = 0, $$length = each_array_4.length; $$index_4 < $$length; $$index_4++) { - let m = each_array_4[$$index_4]; - const { p1, p2 } = teamDisplay(m); - const sc = stateConfig[m.state]; - $$renderer2.push(`
`); - if (p1?.team.avatarUrl) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` ${escape_html(p1?.team.name ?? "?")}
${escape_html(p1?.score ?? 0)} vs ${escape_html(p2?.score ?? 0)}
${escape_html(p2?.team.name ?? "?")} `); - if (p2?.team.avatarUrl) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - if (sc?.dot) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` ${escape_html(sc?.label ?? m.state)}`); - } - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - if (liveMatches().length > 0) { - $$renderer2.push(""); - $$renderer2.push(`

Past Matches

`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - const each_array_5 = ensure_array_like(recentMatches()); - if (each_array_5.length !== 0) { - $$renderer2.push(""); - for (let $$index_5 = 0, $$length = each_array_5.length; $$index_5 < $$length; $$index_5++) { - let m = each_array_5[$$index_5]; - const { p1, p2 } = teamDisplay(m); - const config = m.config; - const sc = stateConfig[m.state]; - $$renderer2.push(`
${escape_html(p1?.team.name ?? "?")} `); - if (m.state === "FINISHED") { - $$renderer2.push(""); - $$renderer2.push(` (p2?.score ?? 0) ? "text-green-400" : "text-text-secondary")}`)}>${escape_html(p1?.score ?? 0)} - (p1?.score ?? 0) ? "text-green-400" : "text-text-secondary")}`)}>${escape_html(p2?.score ?? 0)}`); - } else { - $$renderer2.push(""); - $$renderer2.push(`vs`); - } - $$renderer2.push(` ${escape_html(p2?.team.name ?? "?")}

${escape_html(m.name ? `${m.name} · ` : "")}BO${escape_html(config.bestOf)} `); - if (m.finishedAt) { - $$renderer2.push(""); - $$renderer2.push(`· ${escape_html(timeAgo(m.finishedAt))}`); - } else if (m.createdAt) { - $$renderer2.push(""); - $$renderer2.push(`· ${escape_html(timeAgo(m.createdAt))}`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`

`); - if (m.state === "FINISHED" && m.winnerId) { - $$renderer2.push(""); - const winner = m.participants.find((p) => p.teamId === m.winnerId); - $$renderer2.push(`🏆 ${escape_html(winner?.team.name)}`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` ${escape_html(sc?.label ?? m.state)}`); - } - } else { - $$renderer2.push(""); - if (liveMatches().length === 0) { - $$renderer2.push(""); - $$renderer2.push(`

No matches yet. Create one to get started.

`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(``); - } - $$renderer2.push(`
`); - }); -} -export { - _page as default -}; diff --git a/.svelte-kit/adapter-node/entries/pages/(app)/settings/_page.server.ts.js b/.svelte-kit/adapter-node/entries/pages/(app)/settings/_page.server.ts.js deleted file mode 100644 index 0198d65..0000000 --- a/.svelte-kit/adapter-node/entries/pages/(app)/settings/_page.server.ts.js +++ /dev/null @@ -1,37 +0,0 @@ -import { redirect } from "@sveltejs/kit"; -import { a as auth } from "../../../../chunks/auth.js"; -import { d as db, p as playerRating, j as account } from "../../../../chunks/index2.js"; -import { eq, and } from "drizzle-orm"; -const load = async ({ locals }) => { - if (!locals.user) redirect(302, "/"); - const rating = await db.query.playerRating.findFirst({ - where: eq(playerRating.userId, locals.user.id) - }); - const osuAccount = await db.query.account.findFirst({ - where: and(eq(account.userId, locals.user.id), eq(account.providerId, "osu")) - }); - return { - profile: { - id: locals.user.id, - name: locals.user.name, - email: locals.user.email, - image: locals.user.image, - role: locals.user.role ?? "player", - createdAt: locals.user.createdAt - }, - rating: rating ? { elo: rating.elo, wins: rating.wins, losses: rating.losses } : { elo: 1e3, wins: 0, losses: 0 }, - hasOsuLinked: !!osuAccount - }; -}; -const actions = { - logout: async (event) => { - await auth.api.signOut({ - headers: event.request.headers - }); - redirect(302, "/"); - } -}; -export { - actions, - load -}; diff --git a/.svelte-kit/adapter-node/entries/pages/(app)/settings/_page.svelte.js b/.svelte-kit/adapter-node/entries/pages/(app)/settings/_page.svelte.js deleted file mode 100644 index 3b24951..0000000 --- a/.svelte-kit/adapter-node/entries/pages/(app)/settings/_page.svelte.js +++ /dev/null @@ -1,48 +0,0 @@ -import { b as attr, e as escape_html, c as attr_class, s as stringify, d as derived } from "../../../../chunks/index3.js"; -import "@sveltejs/kit/internal"; -import "../../../../chunks/url.js"; -import "../../../../chunks/utils.js"; -import "@sveltejs/kit/internal/server"; -import "../../../../chunks/root.js"; -import "../../../../chunks/exports.js"; -import "../../../../chunks/state.svelte.js"; -function _page($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - let { data } = $$props; - const roleBadge = { - player: { label: "Player", color: "bg-surface-600 text-text-secondary" }, - referee: { label: "Referee", color: "bg-yellow-500/20 text-yellow-400" }, - admin: { label: "Admin", color: "bg-red-500/20 text-red-400" } - }; - const badge = derived(() => roleBadge[data.profile.role] ?? roleBadge.player); - const winRate = derived(() => data.rating.wins + data.rating.losses > 0 ? (data.rating.wins / (data.rating.wins + data.rating.losses) * 100).toFixed(1) : "—"); - $$renderer2.push(`

Settings

Your profile and account settings

`); - if (data.profile.image) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - $$renderer2.push(`
${escape_html(data.profile.name.charAt(0).toUpperCase())}
`); - } - $$renderer2.push(`

${escape_html(data.profile.name)}

${escape_html(badge().label)}

${escape_html(data.profile.email)}

Connected Accounts

🎮

osu!

`); - if (data.hasOsuLinked) { - $$renderer2.push(""); - $$renderer2.push(`Connected as ${escape_html(data.profile.name)}`); - } else { - $$renderer2.push(""); - $$renderer2.push(`Not connected`); - } - $$renderer2.push(`

`); - if (data.hasOsuLinked) { - $$renderer2.push(""); - $$renderer2.push(`Linked`); - } else { - $$renderer2.push(""); - $$renderer2.push(`Connect`); - } - $$renderer2.push(`

Ranked Stats

${escape_html(data.rating.elo)}

ELO Rating

${escape_html(data.rating.wins)}

Wins

${escape_html(data.rating.losses)}

Losses

${escape_html(winRate())}${escape_html(winRate() !== "—" ? "%" : "")}

Win Rate

Account

`); - }); -} -export { - _page as default -}; diff --git a/.svelte-kit/adapter-node/entries/pages/(app)/teams/_page.server.ts.js b/.svelte-kit/adapter-node/entries/pages/(app)/teams/_page.server.ts.js deleted file mode 100644 index dbeb11a..0000000 --- a/.svelte-kit/adapter-node/entries/pages/(app)/teams/_page.server.ts.js +++ /dev/null @@ -1,88 +0,0 @@ -import { d as db, c as team, t as teamMember, u as user } from "../../../../chunks/index2.js"; -import { eq } from "drizzle-orm"; -import { redirect } from "@sveltejs/kit"; -const load = async ({ locals }) => { - if (!locals.user) redirect(302, "/"); - const teams = await db.query.team.findMany({ - with: { - members: true - }, - orderBy: (t, { desc }) => [desc(t.createdAt)] - }); - const teamsWithUsers = await Promise.all( - teams.map(async (t) => { - const membersWithUsers = await Promise.all( - t.members.map(async (m) => { - const u = await db.query.user.findFirst({ - where: eq(user.id, m.userId) - }); - return { ...m, user: u ? { id: u.id, name: u.name, image: u.image } : null }; - }) - ); - return { ...t, members: membersWithUsers }; - }) - ); - return { teams: teamsWithUsers, userId: locals.user.id }; -}; -const actions = { - create: async ({ request, locals }) => { - if (!locals.user) redirect(302, "/"); - const form = await request.formData(); - const name = form.get("name")?.toString()?.trim(); - if (!name) return { error: "Team name is required" }; - const [created] = await db.insert(team).values({ - name, - ownerId: locals.user.id, - isPersonal: false - }).returning(); - await db.insert(teamMember).values({ - teamId: created.id, - userId: locals.user.id, - role: "captain" - }); - return { success: true }; - }, - addMember: async ({ request, locals }) => { - if (!locals.user) redirect(302, "/"); - const form = await request.formData(); - const teamId = form.get("teamId")?.toString(); - const username = form.get("username")?.toString()?.trim(); - if (!teamId || !username) return { error: "Team and username are required" }; - const u = await db.query.user.findFirst({ - where: eq(user.name, username) - }); - if (!u) return { error: `User "${username}" not found. They need to log in first.` }; - const existing = await db.query.teamMember.findFirst({ - where: (m, { and, eq: eq2 }) => and(eq2(m.teamId, teamId), eq2(m.userId, u.id)) - }); - if (existing) return { error: `${username} is already on this team` }; - await db.insert(teamMember).values({ - teamId, - userId: u.id, - role: "member" - }); - return { success: true }; - }, - removeMember: async ({ request, locals }) => { - if (!locals.user) redirect(302, "/"); - const form = await request.formData(); - const memberId = form.get("memberId")?.toString(); - if (!memberId) return { error: "Missing member ID" }; - await db.delete(teamMember).where(eq(teamMember.id, memberId)); - return { success: true }; - }, - deleteTeam: async ({ request, locals }) => { - if (!locals.user) redirect(302, "/"); - const form = await request.formData(); - const teamId = form.get("teamId")?.toString(); - if (!teamId) return { error: "Missing team ID" }; - const t = await db.query.team.findFirst({ where: eq(team.id, teamId) }); - if (!t || t.ownerId !== locals.user.id) return { error: "Not authorized" }; - await db.delete(team).where(eq(team.id, teamId)); - return { success: true }; - } -}; -export { - actions, - load -}; diff --git a/.svelte-kit/adapter-node/entries/pages/(app)/teams/_page.svelte.js b/.svelte-kit/adapter-node/entries/pages/(app)/teams/_page.svelte.js deleted file mode 100644 index e5203aa..0000000 --- a/.svelte-kit/adapter-node/entries/pages/(app)/teams/_page.svelte.js +++ /dev/null @@ -1,138 +0,0 @@ -import { e as escape_html, a as ensure_array_like, b as attr, c as attr_class, s as stringify, d as derived } from "../../../../chunks/index3.js"; -import "@sveltejs/kit/internal"; -import "../../../../chunks/url.js"; -import "../../../../chunks/utils.js"; -import "@sveltejs/kit/internal/server"; -import "../../../../chunks/root.js"; -import "../../../../chunks/exports.js"; -import "../../../../chunks/state.svelte.js"; -function _page($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - let { data } = $$props; - let expandedTeam = null; - let addingMemberTo = null; - let memberUsername = ""; - const myTeams = derived(() => data.teams.filter((t) => t.members.some((m) => m.userId === data.userId))); - const otherTeams = derived(() => data.teams.filter((t) => !t.members.some((m) => m.userId === data.userId))); - function isOwner(t) { - return t.ownerId === data.userId; - } - $$renderer2.push(`

Teams

${escape_html(data.teams.length)} team${escape_html(data.teams.length !== 1 ? "s" : "")}

`); - { - $$renderer2.push(""); - } - $$renderer2.push(` `); - { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (myTeams().length > 0) { - $$renderer2.push(""); - $$renderer2.push(`

My Teams

`); - const each_array = ensure_array_like(myTeams()); - for (let $$index_1 = 0, $$length = each_array.length; $$index_1 < $$length; $$index_1++) { - let t = each_array[$$index_1]; - $$renderer2.push(`
`); - if (expandedTeam === t.id) { - $$renderer2.push(""); - $$renderer2.push(`
`); - const each_array_1 = ensure_array_like(t.members); - for (let $$index = 0, $$length2 = each_array_1.length; $$index < $$length2; $$index++) { - let member = each_array_1[$$index]; - $$renderer2.push(`
`); - if (member.user?.image) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - $$renderer2.push(`
`); - } - $$renderer2.push(` ${escape_html(member.user?.name ?? "Unknown")} ${escape_html(member.role)} `); - if (isOwner(t) && member.userId !== data.userId) { - $$renderer2.push(""); - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - } - $$renderer2.push(`
`); - if (isOwner(t) && !t.isPersonal) { - $$renderer2.push(""); - if (addingMemberTo === t.id) { - $$renderer2.push(""); - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - $$renderer2.push(``); - } - $$renderer2.push(``); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (isOwner(t) && !t.isPersonal) { - $$renderer2.push(""); - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - } - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (otherTeams().length > 0) { - $$renderer2.push(""); - $$renderer2.push(`

Other Teams

`); - const each_array_2 = ensure_array_like(otherTeams()); - for (let $$index_2 = 0, $$length = each_array_2.length; $$index_2 < $$length; $$index_2++) { - let t = each_array_2[$$index_2]; - $$renderer2.push(`
`); - if (t.avatarUrl) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - $$renderer2.push(`
${escape_html(t.name.charAt(0).toUpperCase())}
`); - } - $$renderer2.push(`
${escape_html(t.name)}

${escape_html(t.members.length)} member${escape_html(t.members.length !== 1 ? "s" : "")}

`); - } - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (data.teams.length === 0) { - $$renderer2.push(""); - $$renderer2.push(`

No teams yet. Your personal team is created when you sign in.

`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - }); -} -export { - _page as default -}; diff --git a/.svelte-kit/adapter-node/entries/pages/_error.svelte.js b/.svelte-kit/adapter-node/entries/pages/_error.svelte.js deleted file mode 100644 index 85b4f7d..0000000 --- a/.svelte-kit/adapter-node/entries/pages/_error.svelte.js +++ /dev/null @@ -1,25 +0,0 @@ -import { e as escape_html } from "../../chunks/index3.js"; -import "clsx"; -import { p as page } from "../../chunks/index4.js"; -function _error($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - $$renderer2.push(`

${escape_html(page.status)}

`); - if (page.status === 404) { - $$renderer2.push(""); - $$renderer2.push(`Page not found`); - } else if (page.status === 403) { - $$renderer2.push(""); - $$renderer2.push(`Access denied`); - } else if (page.status === 401) { - $$renderer2.push(""); - $$renderer2.push(`Not logged in`); - } else { - $$renderer2.push(""); - $$renderer2.push(`Something went wrong`); - } - $$renderer2.push(`

${escape_html(page.error?.message ?? "An unexpected error occurred.")}

Back to Dashboard
`); - }); -} -export { - _error as default -}; diff --git a/.svelte-kit/adapter-node/entries/pages/demo/_page.svelte.js b/.svelte-kit/adapter-node/entries/pages/demo/_page.svelte.js deleted file mode 100644 index 1b9e0e2..0000000 --- a/.svelte-kit/adapter-node/entries/pages/demo/_page.svelte.js +++ /dev/null @@ -1,31 +0,0 @@ -import { b as attr } from "../../../chunks/index3.js"; -import { i as initial_base, b as base } from "../../../chunks/server.js"; -import { r as resolve_route } from "../../../chunks/routing.js"; -import "../../../chunks/url.js"; -import { try_get_request_store } from "@sveltejs/kit/internal/server"; -import "../../../chunks/root.js"; -function resolve(id, params) { - const resolved = resolve_route( - id, - /** @type {Record} */ - params - ); - { - const store = try_get_request_store(); - if (store && !store.state.prerendering?.fallback) { - const after_base = store.event.url.pathname.slice(initial_base.length); - const segments = after_base.split("/").slice(2); - const prefix = segments.map(() => "..").join("/") || "."; - return prefix + resolved; - } - } - return base + resolved; -} -function _page($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - $$renderer2.push(`better-auth`); - }); -} -export { - _page as default -}; diff --git a/.svelte-kit/adapter-node/entries/pages/demo/better-auth/_page.server.ts.js b/.svelte-kit/adapter-node/entries/pages/demo/better-auth/_page.server.ts.js deleted file mode 100644 index 8fa1822..0000000 --- a/.svelte-kit/adapter-node/entries/pages/demo/better-auth/_page.server.ts.js +++ /dev/null @@ -1,20 +0,0 @@ -import { redirect } from "@sveltejs/kit"; -import { a as auth } from "../../../../chunks/auth.js"; -const load = async (event) => { - if (!event.locals.user) { - return redirect(302, "/demo/better-auth/login"); - } - return { user: event.locals.user }; -}; -const actions = { - signOut: async (event) => { - await auth.api.signOut({ - headers: event.request.headers - }); - return redirect(302, "/demo/better-auth/login"); - } -}; -export { - actions, - load -}; diff --git a/.svelte-kit/adapter-node/entries/pages/demo/better-auth/_page.svelte.js b/.svelte-kit/adapter-node/entries/pages/demo/better-auth/_page.svelte.js deleted file mode 100644 index 42126b3..0000000 --- a/.svelte-kit/adapter-node/entries/pages/demo/better-auth/_page.svelte.js +++ /dev/null @@ -1,18 +0,0 @@ -import { e as escape_html } from "../../../../chunks/index3.js"; -import "clsx"; -import "@sveltejs/kit/internal"; -import "../../../../chunks/url.js"; -import "../../../../chunks/utils.js"; -import "@sveltejs/kit/internal/server"; -import "../../../../chunks/root.js"; -import "../../../../chunks/exports.js"; -import "../../../../chunks/state.svelte.js"; -function _page($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - let { data } = $$props; - $$renderer2.push(`

Hi, ${escape_html(data.user.name)}!

Your user ID is ${escape_html(data.user.id)}.

`); - }); -} -export { - _page as default -}; diff --git a/.svelte-kit/adapter-node/entries/pages/demo/better-auth/login/_page.server.ts.js b/.svelte-kit/adapter-node/entries/pages/demo/better-auth/login/_page.server.ts.js deleted file mode 100644 index 2e2ee65..0000000 --- a/.svelte-kit/adapter-node/entries/pages/demo/better-auth/login/_page.server.ts.js +++ /dev/null @@ -1,75 +0,0 @@ -import { redirect, fail } from "@sveltejs/kit"; -import { a as auth } from "../../../../../chunks/auth.js"; -import "@better-auth/core/env"; -import "@better-auth/core/utils"; -import { APIError } from "better-call"; -import "@better-auth/core/api"; -const load = async (event) => { - if (event.locals.user) { - return redirect(302, "/demo/better-auth"); - } - return {}; -}; -const actions = { - signInEmail: async (event) => { - const formData = await event.request.formData(); - const email = formData.get("email")?.toString() ?? ""; - const password = formData.get("password")?.toString() ?? ""; - try { - await auth.api.signInEmail({ - body: { - email, - password, - callbackURL: "/auth/verification-success" - } - }); - } catch (error) { - if (error instanceof APIError) { - return fail(400, { message: error.message || "Signin failed" }); - } - return fail(500, { message: "Unexpected error" }); - } - return redirect(302, "/demo/better-auth"); - }, - signUpEmail: async (event) => { - const formData = await event.request.formData(); - const email = formData.get("email")?.toString() ?? ""; - const password = formData.get("password")?.toString() ?? ""; - const name = formData.get("name")?.toString() ?? ""; - try { - await auth.api.signUpEmail({ - body: { - email, - password, - name, - callbackURL: "/auth/verification-success" - } - }); - } catch (error) { - if (error instanceof APIError) { - return fail(400, { message: error.message || "Registration failed" }); - } - return fail(500, { message: "Unexpected error" }); - } - return redirect(302, "/demo/better-auth"); - }, - signInSocial: async (event) => { - const formData = await event.request.formData(); - const provider = formData.get("provider")?.toString() ?? "osu"; - const callbackURL = formData.get("callbackURL")?.toString() ?? "/demo/better-auth"; - const result = await auth.api.signInSocial({ - body: { - provider, - callbackURL - } - }); - if (result.url) { - return redirect(302, result.url); - } - return fail(400, { message: "Social sign-in failed" }); - } -}; -export { - actions, - load -}; diff --git a/.svelte-kit/adapter-node/entries/pages/demo/better-auth/login/_page.svelte.js b/.svelte-kit/adapter-node/entries/pages/demo/better-auth/login/_page.svelte.js deleted file mode 100644 index c17dfef..0000000 --- a/.svelte-kit/adapter-node/entries/pages/demo/better-auth/login/_page.svelte.js +++ /dev/null @@ -1,18 +0,0 @@ -import { e as escape_html } from "../../../../../chunks/index3.js"; -import "clsx"; -import "@sveltejs/kit/internal"; -import "../../../../../chunks/url.js"; -import "../../../../../chunks/utils.js"; -import "@sveltejs/kit/internal/server"; -import "../../../../../chunks/root.js"; -import "../../../../../chunks/exports.js"; -import "../../../../../chunks/state.svelte.js"; -function _page($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - let { form } = $$props; - $$renderer2.push(`

Login

${escape_html(form?.message ?? "")}


`); - }); -} -export { - _page as default -}; diff --git a/.svelte-kit/adapter-node/entries/pages/login/_page.server.ts.js b/.svelte-kit/adapter-node/entries/pages/login/_page.server.ts.js deleted file mode 100644 index a8c7c75..0000000 --- a/.svelte-kit/adapter-node/entries/pages/login/_page.server.ts.js +++ /dev/null @@ -1,16 +0,0 @@ -import { redirect } from "@sveltejs/kit"; -import { a as auth } from "../../../chunks/auth.js"; -const load = async (event) => { - if (event.locals.user) redirect(302, "/"); - const result = await auth.api.signInSocial({ - body: { - provider: "osu", - callbackURL: "/" - } - }); - if (result.url) redirect(302, result.url); - return {}; -}; -export { - load -}; diff --git a/.svelte-kit/adapter-node/index.js b/.svelte-kit/adapter-node/index.js deleted file mode 100644 index fb8a806..0000000 --- a/.svelte-kit/adapter-node/index.js +++ /dev/null @@ -1,3698 +0,0 @@ -import { D as DEV } from "./chunks/false.js"; -import { json, text, error } from "@sveltejs/kit"; -import { Redirect, SvelteKitError, ActionFailure, HttpError } from "@sveltejs/kit/internal"; -import { with_request_store, merge_tracing, try_get_request_store } from "@sveltejs/kit/internal/server"; -import { a as assets, b as base, c as app_dir, r as relative, o as override, d as reset } from "./chunks/server.js"; -import { E as ENDPOINT_METHODS, P as PAGE_METHODS, n as negotiate, m as method_not_allowed, h as handle_error_and_jsonify, g as get_status, i as is_form_content_type, a as normalize_error, b as get_global_name, s as serialize_uses, c as clarify_devalue_error, d as get_node_type, e as escape_html, S as SVELTE_KIT_ASSETS, f as create_remote_key, j as static_error_page, r as redirect_response, p as parse_remote_arg, k as stringify, l as deserialize_binary_form, o as has_prerendered_path, T as TRAILING_SLASH_PARAM, I as INVALIDATED_PARAM, q as handle_fatal_error, M as MUTATIVE_METHODS, t as format_server_error } from "./chunks/shared.js"; -import * as devalue from "devalue"; -import { m as make_trackable, d as disable_search, S as SCHEME, n as normalize_path, r as resolve, a as decode_pathname } from "./chunks/url.js"; -import { b as base64_encode, t as text_decoder, a as text_encoder, g as get_relative_path } from "./chunks/utils.js"; -import { w as writable, r as readable } from "./chunks/index.js"; -import { p as public_env, s as set_private_env, a as set_public_env } from "./chunks/shared-server.js"; -import { f as find_route } from "./chunks/routing.js"; -import { v as validate_layout_server_exports, a as validate_layout_exports, b as validate_page_server_exports, c as validate_page_exports, d as validate_server_exports } from "./chunks/exports.js"; -import { parse, serialize } from "cookie"; -import * as set_cookie_parser from "set-cookie-parser"; -import { r as read_implementation, o as options, g as get_hooks, s as set_read_implementation } from "./chunks/internal.js"; -function with_resolvers() { - let resolve2; - let reject; - const promise = new Promise((res, rej) => { - resolve2 = res; - reject = rej; - }); - return { promise, resolve: resolve2, reject }; -} -const NULL_BODY_STATUS = [101, 103, 204, 205, 304]; -const IN_WEBCONTAINER = !!globalThis.process?.versions?.webcontainer; -async function render_endpoint(event, event_state, mod, state) { - const method = ( - /** @type {import('types').HttpMethod} */ - event.request.method - ); - let handler = mod[method] || mod.fallback; - if (method === "HEAD" && !mod.HEAD && mod.GET) { - handler = mod.GET; - } - if (!handler) { - return method_not_allowed(mod, method); - } - const prerender = mod.prerender ?? state.prerender_default; - if (prerender && (mod.POST || mod.PATCH || mod.PUT || mod.DELETE)) { - throw new Error("Cannot prerender endpoints that have mutative methods"); - } - if (state.prerendering && !state.prerendering.inside_reroute && !prerender) { - if (state.depth > 0) { - throw new Error(`${event.route.id} is not prerenderable`); - } else { - return new Response(void 0, { status: 204 }); - } - } - try { - event_state.allows_commands = true; - const response = await with_request_store( - { event, state: event_state }, - () => handler( - /** @type {import('@sveltejs/kit').RequestEvent>} */ - event - ) - ); - if (!(response instanceof Response)) { - throw new Error( - `Invalid response from route ${event.url.pathname}: handler should return a Response object` - ); - } - if (state.prerendering && (!state.prerendering.inside_reroute || prerender)) { - const cloned = new Response(response.clone().body, { - status: response.status, - statusText: response.statusText, - headers: new Headers(response.headers) - }); - cloned.headers.set("x-sveltekit-prerender", String(prerender)); - if (state.prerendering.inside_reroute && prerender) { - cloned.headers.set( - "x-sveltekit-routeid", - encodeURI( - /** @type {string} */ - event.route.id - ) - ); - state.prerendering.dependencies.set(event.url.pathname, { response: cloned, body: null }); - } else { - return cloned; - } - } - return response; - } catch (e) { - if (e instanceof Redirect) { - return new Response(void 0, { - status: e.status, - headers: { location: e.location } - }); - } - throw e; - } -} -function is_endpoint_request(event) { - const { method, headers: headers2 } = event.request; - if (ENDPOINT_METHODS.includes(method) && !PAGE_METHODS.includes(method)) { - return true; - } - if (method === "POST" && headers2.get("x-sveltekit-action") === "true") return false; - const accept = event.request.headers.get("accept") ?? "*/*"; - return negotiate(accept, ["*", "text/html"]) !== "text/html"; -} -function compact(arr) { - return arr.filter( - /** @returns {val is NonNullable} */ - (val) => val != null - ); -} -const DATA_SUFFIX = "/__data.json"; -const HTML_DATA_SUFFIX = ".html__data.json"; -function has_data_suffix(pathname) { - return pathname.endsWith(DATA_SUFFIX) || pathname.endsWith(HTML_DATA_SUFFIX); -} -function add_data_suffix(pathname) { - if (pathname.endsWith(".html")) return pathname.replace(/\.html$/, HTML_DATA_SUFFIX); - return pathname.replace(/\/$/, "") + DATA_SUFFIX; -} -function strip_data_suffix(pathname) { - if (pathname.endsWith(HTML_DATA_SUFFIX)) { - return pathname.slice(0, -HTML_DATA_SUFFIX.length) + ".html"; - } - return pathname.slice(0, -DATA_SUFFIX.length); -} -const ROUTE_SUFFIX = "/__route.js"; -function has_resolution_suffix(pathname) { - return pathname.endsWith(ROUTE_SUFFIX); -} -function add_resolution_suffix(pathname) { - return pathname.replace(/\/$/, "") + ROUTE_SUFFIX; -} -function strip_resolution_suffix(pathname) { - return pathname.slice(0, -ROUTE_SUFFIX.length); -} -const noop_span = { - spanContext() { - return noop_span_context; - }, - setAttribute() { - return this; - }, - setAttributes() { - return this; - }, - addEvent() { - return this; - }, - setStatus() { - return this; - }, - updateName() { - return this; - }, - end() { - return this; - }, - isRecording() { - return false; - }, - recordException() { - return this; - }, - addLink() { - return this; - }, - addLinks() { - return this; - } -}; -const noop_span_context = { - traceId: "", - spanId: "", - traceFlags: 0 -}; -async function record_span({ name, attributes, fn }) { - { - return fn(noop_span); - } -} -function is_action_json_request(event) { - const accept = negotiate(event.request.headers.get("accept") ?? "*/*", [ - "application/json", - "text/html" - ]); - return accept === "application/json" && event.request.method === "POST"; -} -async function handle_action_json_request(event, event_state, options2, server) { - const actions = server?.actions; - if (!actions) { - const no_actions_error = new SvelteKitError( - 405, - "Method Not Allowed", - `POST method not allowed. No form actions exist for ${"this page"}` - ); - return action_json( - { - type: "error", - error: await handle_error_and_jsonify(event, event_state, options2, no_actions_error) - }, - { - status: no_actions_error.status, - headers: { - // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/405 - // "The server must generate an Allow header field in a 405 status code response" - allow: "GET" - } - } - ); - } - check_named_default_separate(actions); - try { - const data = await call_action(event, event_state, actions); - if (DEV) ; - if (data instanceof ActionFailure) { - return action_json({ - type: "failure", - status: data.status, - // @ts-expect-error we assign a string to what is supposed to be an object. That's ok - // because we don't use the object outside, and this way we have better code navigation - // through knowing where the related interface is used. - data: stringify_action_response( - data.data, - /** @type {string} */ - event.route.id, - options2.hooks.transport - ) - }); - } else { - return action_json({ - type: "success", - status: data ? 200 : 204, - // @ts-expect-error see comment above - data: stringify_action_response( - data, - /** @type {string} */ - event.route.id, - options2.hooks.transport - ) - }); - } - } catch (e) { - const err = normalize_error(e); - if (err instanceof Redirect) { - return action_json_redirect(err); - } - return action_json( - { - type: "error", - error: await handle_error_and_jsonify( - event, - event_state, - options2, - check_incorrect_fail_use(err) - ) - }, - { - status: get_status(err) - } - ); - } -} -function check_incorrect_fail_use(error2) { - return error2 instanceof ActionFailure ? new Error('Cannot "throw fail()". Use "return fail()"') : error2; -} -function action_json_redirect(redirect) { - return action_json({ - type: "redirect", - status: redirect.status, - location: redirect.location - }); -} -function action_json(data, init2) { - return json(data, init2); -} -function is_action_request(event) { - return event.request.method === "POST"; -} -async function handle_action_request(event, event_state, server) { - const actions = server?.actions; - if (!actions) { - event.setHeaders({ - // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/405 - // "The server must generate an Allow header field in a 405 status code response" - allow: "GET" - }); - return { - type: "error", - error: new SvelteKitError( - 405, - "Method Not Allowed", - `POST method not allowed. No form actions exist for ${"this page"}` - ) - }; - } - check_named_default_separate(actions); - try { - const data = await call_action(event, event_state, actions); - if (DEV) ; - if (data instanceof ActionFailure) { - return { - type: "failure", - status: data.status, - data: data.data - }; - } else { - return { - type: "success", - status: 200, - // @ts-expect-error this will be removed upon serialization, so `undefined` is the same as omission - data - }; - } - } catch (e) { - const err = normalize_error(e); - if (err instanceof Redirect) { - return { - type: "redirect", - status: err.status, - location: err.location - }; - } - return { - type: "error", - error: check_incorrect_fail_use(err) - }; - } -} -function check_named_default_separate(actions) { - if (actions.default && Object.keys(actions).length > 1) { - throw new Error( - "When using named actions, the default action cannot be used. See the docs for more info: https://svelte.dev/docs/kit/form-actions#named-actions" - ); - } -} -async function call_action(event, event_state, actions) { - const url = new URL(event.request.url); - let name = "default"; - for (const param of url.searchParams) { - if (param[0].startsWith("/")) { - name = param[0].slice(1); - if (name === "default") { - throw new Error('Cannot use reserved action name "default"'); - } - break; - } - } - const action = actions[name]; - if (!action) { - throw new SvelteKitError(404, "Not Found", `No action with name '${name}' found`); - } - if (!is_form_content_type(event.request)) { - throw new SvelteKitError( - 415, - "Unsupported Media Type", - `Form actions expect form-encoded data — received ${event.request.headers.get( - "content-type" - )}` - ); - } - return record_span({ - name: "sveltekit.form_action", - attributes: { - "http.route": event.route.id || "unknown" - }, - fn: async (current2) => { - const traced_event = merge_tracing(event, current2); - event_state.allows_commands = true; - const result = await with_request_store( - { event: traced_event, state: event_state }, - () => action(traced_event) - ); - if (result instanceof ActionFailure) { - current2.setAttributes({ - "sveltekit.form_action.result.type": "failure", - "sveltekit.form_action.result.status": result.status - }); - } - return result; - } - }); -} -function validate_action_return(data) { - if (data instanceof Redirect) { - throw new Error("Cannot `return redirect(...)` — use `redirect(...)` instead"); - } - if (data instanceof HttpError) { - throw new Error("Cannot `return error(...)` — use `error(...)` or `return fail(...)` instead"); - } -} -function uneval_action_response(data, route_id, transport) { - const replacer = (thing) => { - for (const key2 in transport) { - const encoded = transport[key2].encode(thing); - if (encoded) { - return `app.decode('${key2}', ${devalue.uneval(encoded, replacer)})`; - } - } - }; - return try_serialize(data, (value) => devalue.uneval(value, replacer), route_id); -} -function stringify_action_response(data, route_id, transport) { - const encoders = Object.fromEntries( - Object.entries(transport).map(([key2, value]) => [key2, value.encode]) - ); - return try_serialize(data, (value) => devalue.stringify(value, encoders), route_id); -} -function try_serialize(data, fn, route_id) { - try { - return fn(data); - } catch (e) { - const error2 = ( - /** @type {any} */ - e - ); - if (data instanceof Response) { - throw new Error( - `Data returned from action inside ${route_id} is not serializable. Form actions need to return plain objects or fail(). E.g. return { success: true } or return fail(400, { message: "invalid" });`, - { cause: e } - ); - } - if ("path" in error2) { - let message = `Data returned from action inside ${route_id} is not serializable: ${error2.message}`; - if (error2.path !== "") message += ` (data.${error2.path})`; - throw new Error(message, { cause: e }); - } - throw error2; - } -} -function create_async_iterator() { - let resolved = -1; - let returned = -1; - const deferred = []; - return { - iterate: (transform = (x) => x) => { - return { - [Symbol.asyncIterator]() { - return { - next: async () => { - const next = deferred[++returned]; - if (!next) return { value: null, done: true }; - const value = await next.promise; - return { value: transform(value), done: false }; - } - }; - } - }; - }, - add: (promise) => { - deferred.push(with_resolvers()); - void promise.then((value) => { - deferred[++resolved].resolve(value); - }); - } - }; -} -function server_data_serializer(event, event_state, options2) { - let promise_id = 1; - let max_nodes = -1; - const iterator = create_async_iterator(); - const global = get_global_name(options2); - function get_replacer(index) { - return function replacer(thing) { - if (typeof thing?.then === "function") { - const id = promise_id++; - const promise = thing.then( - /** @param {any} data */ - (data) => ({ data }) - ).catch( - /** @param {any} error */ - async (error2) => ({ - error: await handle_error_and_jsonify(event, event_state, options2, error2) - }) - ).then( - /** - * @param {{data: any; error: any}} result - */ - async ({ data, error: error2 }) => { - let str; - try { - str = devalue.uneval(error2 ? [, error2] : [data], replacer); - } catch { - error2 = await handle_error_and_jsonify( - event, - event_state, - options2, - new Error(`Failed to serialize promise while rendering ${event.route.id}`) - ); - str = devalue.uneval([, error2], replacer); - } - return { - index, - str: `${global}.resolve(${id}, ${str.includes("app.decode") ? `(app) => ${str}` : `() => ${str}`})` - }; - } - ); - iterator.add(promise); - return `${global}.defer(${id})`; - } else { - for (const key2 in options2.hooks.transport) { - const encoded = options2.hooks.transport[key2].encode(thing); - if (encoded) { - return `app.decode('${key2}', ${devalue.uneval(encoded, replacer)})`; - } - } - } - }; - } - const strings = ( - /** @type {string[]} */ - [] - ); - return { - set_max_nodes(i) { - max_nodes = i; - }, - add_node(i, node) { - try { - if (!node) { - strings[i] = "null"; - return; - } - const payload = { type: "data", data: node.data, uses: serialize_uses(node) }; - if (node.slash) payload.slash = node.slash; - strings[i] = devalue.uneval(payload, get_replacer(i)); - } catch (e) { - e.path = e.path.slice(1); - throw new Error(clarify_devalue_error( - event, - /** @type {any} */ - e - ), { cause: e }); - } - }, - get_data(csp) { - const open = ``; - const close = `<\/script> -`; - return { - data: `[${compact(max_nodes > -1 ? strings.slice(0, max_nodes) : strings).join(",")}]`, - chunks: promise_id > 1 ? iterator.iterate(({ index, str }) => { - if (max_nodes > -1 && index >= max_nodes) { - return ""; - } - return open + str + close; - }) : null - }; - } - }; -} -function server_data_serializer_json(event, event_state, options2) { - let promise_id = 1; - const iterator = create_async_iterator(); - const reducers = { - ...Object.fromEntries( - Object.entries(options2.hooks.transport).map(([key2, value]) => [key2, value.encode]) - ), - /** @param {any} thing */ - Promise: (thing) => { - if (typeof thing?.then !== "function") { - return; - } - const id = promise_id++; - let key2 = "data"; - const promise = thing.catch( - /** @param {any} e */ - async (e) => { - key2 = "error"; - return handle_error_and_jsonify( - event, - event_state, - options2, - /** @type {any} */ - e - ); - } - ).then( - /** @param {any} value */ - async (value) => { - let str; - try { - str = devalue.stringify(value, reducers); - } catch { - const error2 = await handle_error_and_jsonify( - event, - event_state, - options2, - new Error(`Failed to serialize promise while rendering ${event.route.id}`) - ); - key2 = "error"; - str = devalue.stringify(error2, reducers); - } - return `{"type":"chunk","id":${id},"${key2}":${str}} -`; - } - ); - iterator.add(promise); - return id; - } - }; - const strings = ( - /** @type {string[]} */ - [] - ); - return { - add_node(i, node) { - try { - if (!node) { - strings[i] = "null"; - return; - } - if (node.type === "error" || node.type === "skip") { - strings[i] = JSON.stringify(node); - return; - } - strings[i] = `{"type":"data","data":${devalue.stringify(node.data, reducers)},"uses":${JSON.stringify( - serialize_uses(node) - )}${node.slash ? `,"slash":${JSON.stringify(node.slash)}` : ""}}`; - } catch (e) { - e.path = "data" + e.path; - throw new Error(clarify_devalue_error( - event, - /** @type {any} */ - e - ), { cause: e }); - } - }, - get_data() { - return { - data: `{"type":"data","nodes":[${strings.join(",")}]} -`, - chunks: promise_id > 1 ? iterator.iterate() : null - }; - } - }; -} -async function load_server_data({ event, event_state, state, node, parent }) { - if (!node?.server) return null; - let is_tracking = true; - const uses = { - dependencies: /* @__PURE__ */ new Set(), - params: /* @__PURE__ */ new Set(), - parent: false, - route: false, - url: false, - search_params: /* @__PURE__ */ new Set() - }; - const load = node.server.load; - const slash = node.server.trailingSlash; - if (!load) { - return { type: "data", data: null, uses, slash }; - } - const url = make_trackable( - event.url, - () => { - if (is_tracking) { - uses.url = true; - } - }, - (param) => { - if (is_tracking) { - uses.search_params.add(param); - } - } - ); - if (state.prerendering) { - disable_search(url); - } - const result = await record_span({ - name: "sveltekit.load", - attributes: { - "sveltekit.load.node_id": node.server_id || "unknown", - "sveltekit.load.node_type": get_node_type(node.server_id), - "http.route": event.route.id || "unknown" - }, - fn: async (current2) => { - const traced_event = merge_tracing(event, current2); - const result2 = await with_request_store( - { event: traced_event, state: event_state }, - () => load.call(null, { - ...traced_event, - fetch: (info, init2) => { - new URL(info instanceof Request ? info.url : info, event.url); - return event.fetch(info, init2); - }, - /** @param {string[]} deps */ - depends: (...deps) => { - for (const dep of deps) { - const { href } = new URL(dep, event.url); - uses.dependencies.add(href); - } - }, - params: new Proxy(event.params, { - get: (target, key2) => { - if (is_tracking) { - uses.params.add(key2); - } - return target[ - /** @type {string} */ - key2 - ]; - } - }), - parent: async () => { - if (is_tracking) { - uses.parent = true; - } - return parent(); - }, - route: new Proxy(event.route, { - get: (target, key2) => { - if (is_tracking) { - uses.route = true; - } - return target[ - /** @type {'id'} */ - key2 - ]; - } - }), - url, - untrack(fn) { - is_tracking = false; - try { - return fn(); - } finally { - is_tracking = true; - } - } - }) - ); - return result2; - } - }); - return { - type: "data", - data: result ?? null, - uses, - slash - }; -} -async function load_data({ - event, - event_state, - fetched, - node, - parent, - server_data_promise, - state, - resolve_opts, - csr -}) { - const server_data_node = await server_data_promise; - const load = node?.universal?.load; - if (!load) { - return server_data_node?.data ?? null; - } - const result = await record_span({ - name: "sveltekit.load", - attributes: { - "sveltekit.load.node_id": node.universal_id || "unknown", - "sveltekit.load.node_type": get_node_type(node.universal_id), - "http.route": event.route.id || "unknown" - }, - fn: async (current2) => { - const traced_event = merge_tracing(event, current2); - return await with_request_store( - { event: traced_event, state: event_state }, - () => load.call(null, { - url: event.url, - params: event.params, - data: server_data_node?.data ?? null, - route: event.route, - fetch: create_universal_fetch(event, state, fetched, csr, resolve_opts), - setHeaders: event.setHeaders, - depends: () => { - }, - parent, - untrack: (fn) => fn(), - tracing: traced_event.tracing - }) - ); - } - }); - return result ?? null; -} -function create_universal_fetch(event, state, fetched, csr, resolve_opts) { - const universal_fetch = async (input, init2) => { - const cloned_body = input instanceof Request && input.body ? input.clone().body : null; - const cloned_headers = input instanceof Request && [...input.headers].length ? new Headers(input.headers) : init2?.headers; - let response = await event.fetch(input, init2); - const url = new URL(input instanceof Request ? input.url : input, event.url); - const same_origin = url.origin === event.url.origin; - let dependency; - if (same_origin) { - if (state.prerendering) { - dependency = { response, body: null }; - state.prerendering.dependencies.set(url.pathname, dependency); - } - } else if (url.protocol === "https:" || url.protocol === "http:") { - const mode = input instanceof Request ? input.mode : init2?.mode ?? "cors"; - if (mode === "no-cors") { - response = new Response("", { - status: response.status, - statusText: response.statusText, - headers: response.headers - }); - } else { - const acao = response.headers.get("access-control-allow-origin"); - if (!acao || acao !== event.url.origin && acao !== "*") { - throw new Error( - `CORS error: ${acao ? "Incorrect" : "No"} 'Access-Control-Allow-Origin' header is present on the requested resource` - ); - } - } - } - let teed_body; - const proxy = new Proxy(response, { - get(response2, key2, receiver) { - async function push_fetched(body2, is_b64) { - const status_number = Number(response2.status); - if (isNaN(status_number)) { - throw new Error( - `response.status is not a number. value: "${response2.status}" type: ${typeof response2.status}` - ); - } - fetched.push({ - url: same_origin ? url.href.slice(event.url.origin.length) : url.href, - method: event.request.method, - request_body: ( - /** @type {string | ArrayBufferView | undefined} */ - input instanceof Request && cloned_body ? await stream_to_string(cloned_body) : init2?.body - ), - request_headers: cloned_headers, - response_body: body2, - response: response2, - is_b64 - }); - } - if (key2 === "body") { - if (response2.body === null) { - return null; - } - if (teed_body) { - return teed_body; - } - const [a, b] = response2.body.tee(); - void (async () => { - let result = new Uint8Array(); - for await (const chunk of a) { - const combined = new Uint8Array(result.length + chunk.length); - combined.set(result, 0); - combined.set(chunk, result.length); - result = combined; - } - if (dependency) { - dependency.body = new Uint8Array(result); - } - void push_fetched(base64_encode(result), true); - })(); - return teed_body = b; - } - if (key2 === "arrayBuffer") { - return async () => { - const buffer = await response2.arrayBuffer(); - const bytes = new Uint8Array(buffer); - if (dependency) { - dependency.body = bytes; - } - if (buffer instanceof ArrayBuffer) { - await push_fetched(base64_encode(bytes), true); - } - return buffer; - }; - } - async function text2() { - const body2 = await response2.text(); - if (body2 === "" && NULL_BODY_STATUS.includes(response2.status)) { - await push_fetched(void 0, false); - return void 0; - } - if (!body2 || typeof body2 === "string") { - await push_fetched(body2, false); - } - if (dependency) { - dependency.body = body2; - } - return body2; - } - if (key2 === "text") { - return text2; - } - if (key2 === "json") { - return async () => { - const body2 = await text2(); - return body2 ? JSON.parse(body2) : void 0; - }; - } - const value = Reflect.get(response2, key2, response2); - if (value instanceof Function) { - return Object.defineProperties( - /** - * @this {any} - */ - function() { - return Reflect.apply(value, this === receiver ? response2 : this, arguments); - }, - { - name: { value: value.name }, - length: { value: value.length } - } - ); - } - return value; - } - }); - if (csr) { - const get = response.headers.get; - response.headers.get = (key2) => { - const lower = key2.toLowerCase(); - const value = get.call(response.headers, lower); - if (value && !lower.startsWith("x-sveltekit-")) { - const included = resolve_opts.filterSerializedResponseHeaders(lower, value); - if (!included) { - throw new Error( - `Failed to get response header "${lower}" — it must be included by the \`filterSerializedResponseHeaders\` option: https://svelte.dev/docs/kit/hooks#Server-hooks-handle (at ${event.route.id})` - ); - } - } - return value; - }; - } - return proxy; - }; - return (input, init2) => { - const response = universal_fetch(input, init2); - response.catch(() => { - }); - return response; - }; -} -async function stream_to_string(stream) { - let result = ""; - const reader = stream.getReader(); - while (true) { - const { done, value } = await reader.read(); - if (done) { - break; - } - result += text_decoder.decode(value); - } - return result; -} -function hash(...values) { - let hash2 = 5381; - for (const value of values) { - if (typeof value === "string") { - let i = value.length; - while (i) hash2 = hash2 * 33 ^ value.charCodeAt(--i); - } else if (ArrayBuffer.isView(value)) { - const buffer = new Uint8Array(value.buffer, value.byteOffset, value.byteLength); - let i = buffer.length; - while (i) hash2 = hash2 * 33 ^ buffer[--i]; - } else { - throw new TypeError("value must be a string or TypedArray"); - } - } - return (hash2 >>> 0).toString(36); -} -const replacements = { - "<": "\\u003C", - "\u2028": "\\u2028", - "\u2029": "\\u2029" -}; -const pattern = new RegExp(`[${Object.keys(replacements).join("")}]`, "g"); -function serialize_data(fetched, filter, prerendering = false) { - const headers2 = {}; - let cache_control = null; - let age = null; - let varyAny = false; - for (const [key2, value] of fetched.response.headers) { - if (filter(key2, value)) { - headers2[key2] = value; - } - if (key2 === "cache-control") cache_control = value; - else if (key2 === "age") age = value; - else if (key2 === "vary" && value.trim() === "*") varyAny = true; - } - const payload = { - status: fetched.response.status, - statusText: fetched.response.statusText, - headers: headers2, - body: fetched.response_body - }; - const safe_payload = JSON.stringify(payload).replace(pattern, (match) => replacements[match]); - const attrs = [ - 'type="application/json"', - "data-sveltekit-fetched", - `data-url="${escape_html(fetched.url, true)}"` - ]; - if (fetched.is_b64) { - attrs.push("data-b64"); - } - if (fetched.request_headers || fetched.request_body) { - const values = []; - if (fetched.request_headers) { - values.push([...new Headers(fetched.request_headers)].join(",")); - } - if (fetched.request_body) { - values.push(fetched.request_body); - } - attrs.push(`data-hash="${hash(...values)}"`); - } - if (!prerendering && fetched.method === "GET" && cache_control && !varyAny) { - const match = /s-maxage=(\d+)/g.exec(cache_control) ?? /max-age=(\d+)/g.exec(cache_control); - if (match) { - const ttl = +match[1] - +(age ?? "0"); - attrs.push(`data-ttl="${ttl}"`); - } - } - return ` - -{#if constructors[1]} - {@const Pyramid_0 = constructors[0]} - - - {#if constructors[2]} - {@const Pyramid_1 = constructors[1]} - - - - - - - {:else} - {@const Pyramid_1 = constructors[1]} - - - - {/if} - - -{:else} - {@const Pyramid_0 = constructors[0]} - - - -{/if} - -{#if mounted} -
- {#if navigated} - {title} - {/if} -
-{/if} \ No newline at end of file diff --git a/.svelte-kit/generated/server/internal.js b/.svelte-kit/generated/server/internal.js deleted file mode 100644 index db0dd6a..0000000 --- a/.svelte-kit/generated/server/internal.js +++ /dev/null @@ -1,53 +0,0 @@ - -import root from '../root.js'; -import { set_building, set_prerendering } from '__sveltekit/environment'; -import { set_assets } from '$app/paths/internal/server'; -import { set_manifest, set_read_implementation } from '__sveltekit/server'; -import { set_private_env, set_public_env } from '../../../node_modules/@sveltejs/kit/src/runtime/shared-server.js'; - -export const options = { - app_template_contains_nonce: false, - async: false, - csp: {"mode":"auto","directives":{"upgrade-insecure-requests":false,"block-all-mixed-content":false},"reportOnly":{"upgrade-insecure-requests":false,"block-all-mixed-content":false}}, - csrf_check_origin: true, - csrf_trusted_origins: [], - embedded: false, - env_public_prefix: 'PUBLIC_', - env_private_prefix: '', - hash_routing: false, - hooks: null, // added lazily, via `get_hooks` - preload_strategy: "modulepreload", - root, - service_worker: false, - service_worker_options: undefined, - templates: { - app: ({ head, body, assets, nonce, env }) => "\n\n\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\tVash Esports\n\t\t" + head + "\n\t\n\t\n\t\t
" + body + "
\n\t\n\n", - error: ({ status, message }) => "\n\n\t\n\t\t\n\t\t" + message + "\n\n\t\t\n\t\n\t\n\t\t
\n\t\t\t" + status + "\n\t\t\t
\n\t\t\t\t

" + message + "

\n\t\t\t
\n\t\t
\n\t\n\n" - }, - version_hash: "12t8tv8" -}; - -export async function get_hooks() { - let handle; - let handleFetch; - let handleError; - let handleValidationError; - let init; - ({ handle, handleFetch, handleError, handleValidationError, init } = await import("../../../src/hooks.server.ts")); - - let reroute; - let transport; - - - return { - handle, - handleFetch, - handleError, - handleValidationError, - init, - reroute, - transport - }; -} - -export { set_assets, set_building, set_manifest, set_prerendering, set_private_env, set_public_env, set_read_implementation }; diff --git a/.svelte-kit/non-ambient.d.ts b/.svelte-kit/non-ambient.d.ts deleted file mode 100644 index c14fd87..0000000 --- a/.svelte-kit/non-ambient.d.ts +++ /dev/null @@ -1,81 +0,0 @@ - -// this file is generated — do not edit it - - -declare module "svelte/elements" { - export interface HTMLAttributes { - 'data-sveltekit-keepfocus'?: true | '' | 'off' | undefined | null; - 'data-sveltekit-noscroll'?: true | '' | 'off' | undefined | null; - 'data-sveltekit-preload-code'?: - | true - | '' - | 'eager' - | 'viewport' - | 'hover' - | 'tap' - | 'off' - | undefined - | null; - 'data-sveltekit-preload-data'?: true | '' | 'hover' | 'tap' | 'off' | undefined | null; - 'data-sveltekit-reload'?: true | '' | 'off' | undefined | null; - 'data-sveltekit-replacestate'?: true | '' | 'off' | undefined | null; - } -} - -export {}; - - -declare module "$app/types" { - export interface AppTypes { - RouteId(): "/(app)" | "/" | "/(app)/admin" | "/api" | "/api/health" | "/api/mappools" | "/api/mappools/[id]" | "/api/mappools/[id]/slots" | "/api/mappools/[id]/slots/[slotId]" | "/api/matches" | "/api/matches/[id]" | "/api/matches/[id]/lobby" | "/api/matches/[id]/pick" | "/api/matches/[id]/rolling" | "/api/matches/[id]/roll" | "/api/matches/[id]/score" | "/api/osu" | "/api/osu/beatmap" | "/api/osu/beatmap/[id]" | "/api/queue" | "/demo" | "/demo/better-auth" | "/demo/better-auth/login" | "/login" | "/(app)/mappools" | "/(app)/mappools/[id]" | "/(app)/matches" | "/(app)/matches/[id]" | "/(app)/settings" | "/(app)/teams"; - RouteParams(): { - "/api/mappools/[id]": { id: string }; - "/api/mappools/[id]/slots": { id: string }; - "/api/mappools/[id]/slots/[slotId]": { id: string; slotId: string }; - "/api/matches/[id]": { id: string }; - "/api/matches/[id]/lobby": { id: string }; - "/api/matches/[id]/pick": { id: string }; - "/api/matches/[id]/rolling": { id: string }; - "/api/matches/[id]/roll": { id: string }; - "/api/matches/[id]/score": { id: string }; - "/api/osu/beatmap/[id]": { id: string }; - "/(app)/mappools/[id]": { id: string }; - "/(app)/matches/[id]": { id: string } - }; - LayoutParams(): { - "/(app)": { id?: string }; - "/": { id?: string; slotId?: string }; - "/(app)/admin": Record; - "/api": { id?: string; slotId?: string }; - "/api/health": Record; - "/api/mappools": { id?: string; slotId?: string }; - "/api/mappools/[id]": { id: string; slotId?: string }; - "/api/mappools/[id]/slots": { id: string; slotId?: string }; - "/api/mappools/[id]/slots/[slotId]": { id: string; slotId: string }; - "/api/matches": { id?: string }; - "/api/matches/[id]": { id: string }; - "/api/matches/[id]/lobby": { id: string }; - "/api/matches/[id]/pick": { id: string }; - "/api/matches/[id]/rolling": { id: string }; - "/api/matches/[id]/roll": { id: string }; - "/api/matches/[id]/score": { id: string }; - "/api/osu": { id?: string }; - "/api/osu/beatmap": { id?: string }; - "/api/osu/beatmap/[id]": { id: string }; - "/api/queue": Record; - "/demo": Record; - "/demo/better-auth": Record; - "/demo/better-auth/login": Record; - "/login": Record; - "/(app)/mappools": { id?: string }; - "/(app)/mappools/[id]": { id: string }; - "/(app)/matches": { id?: string }; - "/(app)/matches/[id]": { id: string }; - "/(app)/settings": Record; - "/(app)/teams": Record - }; - Pathname(): "/" | "/admin" | "/api/health" | "/api/mappools" | `/api/mappools/${string}` & {} | `/api/mappools/${string}/slots` & {} | `/api/mappools/${string}/slots/${string}` & {} | "/api/matches" | `/api/matches/${string}` & {} | `/api/matches/${string}/lobby` & {} | `/api/matches/${string}/pick` & {} | `/api/matches/${string}/rolling` & {} | `/api/matches/${string}/roll` & {} | `/api/matches/${string}/score` & {} | `/api/osu/beatmap/${string}` & {} | "/api/queue" | "/demo" | "/demo/better-auth" | "/demo/better-auth/login" | "/login" | "/mappools" | `/mappools/${string}` & {} | "/matches" | `/matches/${string}` & {} | "/settings" | "/teams"; - ResolvedPathname(): `${"" | `/${string}`}${ReturnType}`; - Asset(): "/android-chrome-192x192.png" | "/android-chrome-512x512.png" | "/apple-touch-icon.png" | "/favicon-16x16.png" | "/favicon-32x32.png" | "/favicon.ico" | "/robots.txt" | "/site.webmanifest" | string & {}; - } -} \ No newline at end of file diff --git a/.svelte-kit/output/client/.vite/manifest.json b/.svelte-kit/output/client/.vite/manifest.json deleted file mode 100644 index f1cdb44..0000000 --- a/.svelte-kit/output/client/.vite/manifest.json +++ /dev/null @@ -1,394 +0,0 @@ -{ - ".svelte-kit/generated/client-optimized/app.js": { - "file": "_app/immutable/entry/app.DL20j9gb.js", - "name": "entry/app", - "src": ".svelte-kit/generated/client-optimized/app.js", - "isEntry": true, - "imports": [ - "_BxEwC6Zc.js", - "_DoLu9QLy.js", - "_DsnmJJEf.js", - "_CvGSsBh3.js", - "_BQKoxf2Q.js", - "_kALFGdUG.js" - ], - "dynamicImports": [ - ".svelte-kit/generated/client-optimized/nodes/0.js", - ".svelte-kit/generated/client-optimized/nodes/1.js", - ".svelte-kit/generated/client-optimized/nodes/2.js", - ".svelte-kit/generated/client-optimized/nodes/3.js", - ".svelte-kit/generated/client-optimized/nodes/4.js", - ".svelte-kit/generated/client-optimized/nodes/5.js", - ".svelte-kit/generated/client-optimized/nodes/6.js", - ".svelte-kit/generated/client-optimized/nodes/7.js", - ".svelte-kit/generated/client-optimized/nodes/8.js", - ".svelte-kit/generated/client-optimized/nodes/9.js", - ".svelte-kit/generated/client-optimized/nodes/10.js", - ".svelte-kit/generated/client-optimized/nodes/11.js", - ".svelte-kit/generated/client-optimized/nodes/12.js", - ".svelte-kit/generated/client-optimized/nodes/13.js", - "_BQKoxf2Q.js" - ] - }, - ".svelte-kit/generated/client-optimized/nodes/0.js": { - "file": "_app/immutable/nodes/0.9C686m9W.js", - "name": "nodes/0", - "src": ".svelte-kit/generated/client-optimized/nodes/0.js", - "isEntry": true, - "isDynamicEntry": true, - "imports": [ - "_DsnmJJEf.js", - "_BxEwC6Zc.js", - "_CyUoLS3q.js" - ] - }, - ".svelte-kit/generated/client-optimized/nodes/1.js": { - "file": "_app/immutable/nodes/1.RyK1bdTz.js", - "name": "nodes/1", - "src": ".svelte-kit/generated/client-optimized/nodes/1.js", - "isEntry": true, - "isDynamicEntry": true, - "imports": [ - "_DsnmJJEf.js", - "_TpZZa089.js", - "_BxEwC6Zc.js", - "_DoLu9QLy.js", - "_BQKoxf2Q.js", - "_D2SGgx9j.js" - ] - }, - ".svelte-kit/generated/client-optimized/nodes/10.js": { - "file": "_app/immutable/nodes/10.BPlEN6_G.js", - "name": "nodes/10", - "src": ".svelte-kit/generated/client-optimized/nodes/10.js", - "isEntry": true, - "isDynamicEntry": true, - "imports": [ - "_DsnmJJEf.js", - "_BxEwC6Zc.js", - "_DoLu9QLy.js", - "_BQKoxf2Q.js", - "_BLQQas77.js", - "_BAocuFgQ.js", - "_BnX5ZnVA.js", - "_BqOsL1Vv.js", - "_CAkKRSSs.js", - "_DAtZQVjv.js" - ] - }, - ".svelte-kit/generated/client-optimized/nodes/11.js": { - "file": "_app/immutable/nodes/11.DR1Vz7m0.js", - "name": "nodes/11", - "src": ".svelte-kit/generated/client-optimized/nodes/11.js", - "isEntry": true, - "isDynamicEntry": true, - "imports": [ - "_DsnmJJEf.js", - "_TpZZa089.js", - "_BxEwC6Zc.js", - "_BnX5ZnVA.js", - "_DAtZQVjv.js" - ] - }, - ".svelte-kit/generated/client-optimized/nodes/12.js": { - "file": "_app/immutable/nodes/12.C9UZWAjJ.js", - "name": "nodes/12", - "src": ".svelte-kit/generated/client-optimized/nodes/12.js", - "isEntry": true, - "isDynamicEntry": true, - "imports": [ - "_DsnmJJEf.js", - "_BxEwC6Zc.js", - "_DoLu9QLy.js", - "_BAocuFgQ.js" - ] - }, - ".svelte-kit/generated/client-optimized/nodes/13.js": { - "file": "_app/immutable/nodes/13.CyZ4e6yK.js", - "name": "nodes/13", - "src": ".svelte-kit/generated/client-optimized/nodes/13.js", - "isEntry": true, - "isDynamicEntry": true, - "imports": [ - "_DsnmJJEf.js", - "_BxEwC6Zc.js", - "_DoLu9QLy.js", - "_BAocuFgQ.js" - ] - }, - ".svelte-kit/generated/client-optimized/nodes/2.js": { - "file": "_app/immutable/nodes/2.BsR2_q_w.js", - "name": "nodes/2", - "src": ".svelte-kit/generated/client-optimized/nodes/2.js", - "isEntry": true, - "isDynamicEntry": true, - "imports": [ - "_DsnmJJEf.js", - "_BxEwC6Zc.js", - "_CyUoLS3q.js", - "_BQKoxf2Q.js", - "_DoLu9QLy.js", - "_BLQQas77.js", - "_BnX5ZnVA.js", - "_BqOsL1Vv.js", - "_D2SGgx9j.js", - "_BAocuFgQ.js" - ], - "css": [ - "_app/immutable/assets/2.Dv2no-8m.css" - ] - }, - ".svelte-kit/generated/client-optimized/nodes/3.js": { - "file": "_app/immutable/nodes/3.CMuy9Bx3.js", - "name": "nodes/3", - "src": ".svelte-kit/generated/client-optimized/nodes/3.js", - "isEntry": true, - "isDynamicEntry": true, - "imports": [ - "_DsnmJJEf.js", - "_BxEwC6Zc.js", - "_DoLu9QLy.js", - "_BQKoxf2Q.js", - "_BLQQas77.js", - "_BnX5ZnVA.js", - "_BqOsL1Vv.js" - ] - }, - ".svelte-kit/generated/client-optimized/nodes/4.js": { - "file": "_app/immutable/nodes/4.BdC-uDW-.js", - "name": "nodes/4", - "src": ".svelte-kit/generated/client-optimized/nodes/4.js", - "isEntry": true, - "isDynamicEntry": true, - "imports": [ - "_DsnmJJEf.js", - "_BxEwC6Zc.js", - "_DoLu9QLy.js", - "_BQKoxf2Q.js", - "_BLQQas77.js", - "_BAocuFgQ.js", - "_BnX5ZnVA.js", - "_BqOsL1Vv.js", - "_Cy2QBcXt.js" - ] - }, - ".svelte-kit/generated/client-optimized/nodes/5.js": { - "file": "_app/immutable/nodes/5.CyqZcxti.js", - "name": "nodes/5", - "src": ".svelte-kit/generated/client-optimized/nodes/5.js", - "isEntry": true, - "isDynamicEntry": true, - "imports": [ - "_DsnmJJEf.js", - "_BxEwC6Zc.js", - "_DoLu9QLy.js", - "_BQKoxf2Q.js", - "_BLQQas77.js", - "_BAocuFgQ.js", - "_BnX5ZnVA.js" - ] - }, - ".svelte-kit/generated/client-optimized/nodes/6.js": { - "file": "_app/immutable/nodes/6.CEe0czaO.js", - "name": "nodes/6", - "src": ".svelte-kit/generated/client-optimized/nodes/6.js", - "isEntry": true, - "isDynamicEntry": true, - "imports": [ - "_DsnmJJEf.js", - "_BxEwC6Zc.js", - "_DoLu9QLy.js", - "_BQKoxf2Q.js", - "_BLQQas77.js", - "_BAocuFgQ.js", - "_BnX5ZnVA.js", - "_BqOsL1Vv.js", - "_CAkKRSSs.js", - "_Cy2QBcXt.js", - "_DAtZQVjv.js" - ] - }, - ".svelte-kit/generated/client-optimized/nodes/7.js": { - "file": "_app/immutable/nodes/7._nuD3LlN.js", - "name": "nodes/7", - "src": ".svelte-kit/generated/client-optimized/nodes/7.js", - "isEntry": true, - "isDynamicEntry": true, - "imports": [ - "_DsnmJJEf.js", - "_BxEwC6Zc.js", - "_DoLu9QLy.js", - "_BQKoxf2Q.js", - "_BLQQas77.js", - "_BAocuFgQ.js", - "_BnX5ZnVA.js", - "_BqOsL1Vv.js" - ] - }, - ".svelte-kit/generated/client-optimized/nodes/8.js": { - "file": "_app/immutable/nodes/8.CkbqikZq.js", - "name": "nodes/8", - "src": ".svelte-kit/generated/client-optimized/nodes/8.js", - "isEntry": true, - "isDynamicEntry": true, - "imports": [ - "_DsnmJJEf.js", - "_BxEwC6Zc.js", - "_DoLu9QLy.js", - "_BQKoxf2Q.js", - "_BLQQas77.js", - "_BAocuFgQ.js", - "_BnX5ZnVA.js", - "_BqOsL1Vv.js", - "_BkIq08el.js" - ] - }, - ".svelte-kit/generated/client-optimized/nodes/9.js": { - "file": "_app/immutable/nodes/9.BTBc_Eli.js", - "name": "nodes/9", - "src": ".svelte-kit/generated/client-optimized/nodes/9.js", - "isEntry": true, - "isDynamicEntry": true, - "imports": [ - "_DsnmJJEf.js", - "_BxEwC6Zc.js", - "_DoLu9QLy.js", - "_BQKoxf2Q.js", - "_BAocuFgQ.js", - "_BnX5ZnVA.js", - "_BqOsL1Vv.js" - ] - }, - "_BAocuFgQ.js": { - "file": "_app/immutable/chunks/BAocuFgQ.js", - "name": "forms", - "imports": [ - "_BxEwC6Zc.js", - "_BkIq08el.js" - ] - }, - "_BLQQas77.js": { - "file": "_app/immutable/chunks/BLQQas77.js", - "name": "each", - "imports": [ - "_BxEwC6Zc.js" - ] - }, - "_BQKoxf2Q.js": { - "file": "_app/immutable/chunks/BQKoxf2Q.js", - "name": "14", - "isDynamicEntry": true, - "imports": [ - "_BxEwC6Zc.js", - "_kALFGdUG.js" - ] - }, - "_BkIq08el.js": { - "file": "_app/immutable/chunks/BkIq08el.js", - "name": "entry", - "imports": [ - "_CvGSsBh3.js", - "_DAtZQVjv.js", - "_BxEwC6Zc.js" - ] - }, - "_BnX5ZnVA.js": { - "file": "_app/immutable/chunks/BnX5ZnVA.js", - "name": "attributes", - "imports": [ - "_BxEwC6Zc.js" - ] - }, - "_BqOsL1Vv.js": { - "file": "_app/immutable/chunks/BqOsL1Vv.js", - "name": "class", - "imports": [ - "_BxEwC6Zc.js" - ] - }, - "_BxEwC6Zc.js": { - "file": "_app/immutable/chunks/BxEwC6Zc.js", - "name": "template" - }, - "_CAkKRSSs.js": { - "file": "_app/immutable/chunks/CAkKRSSs.js", - "name": "input", - "imports": [ - "_BxEwC6Zc.js" - ] - }, - "_CvGSsBh3.js": { - "file": "_app/immutable/chunks/CvGSsBh3.js", - "name": "index-client", - "imports": [ - "_BxEwC6Zc.js", - "_DoLu9QLy.js" - ] - }, - "_Cy2QBcXt.js": { - "file": "_app/immutable/chunks/Cy2QBcXt.js", - "name": "select", - "imports": [ - "_BxEwC6Zc.js" - ] - }, - "_CyUoLS3q.js": { - "file": "_app/immutable/chunks/CyUoLS3q.js", - "name": "snippet", - "imports": [ - "_BxEwC6Zc.js", - "_kALFGdUG.js" - ] - }, - "_D2SGgx9j.js": { - "file": "_app/immutable/chunks/D2SGgx9j.js", - "name": "index", - "imports": [ - "_DAtZQVjv.js", - "_BkIq08el.js" - ] - }, - "_DAtZQVjv.js": { - "file": "_app/immutable/chunks/DAtZQVjv.js", - "name": "state.svelte", - "imports": [ - "_CvGSsBh3.js", - "_BxEwC6Zc.js" - ] - }, - "_DoLu9QLy.js": { - "file": "_app/immutable/chunks/DoLu9QLy.js", - "name": "render", - "imports": [ - "_BxEwC6Zc.js" - ] - }, - "_DsnmJJEf.js": { - "file": "_app/immutable/chunks/DsnmJJEf.js", - "name": "disclose-version" - }, - "_TpZZa089.js": { - "file": "_app/immutable/chunks/TpZZa089.js", - "name": "legacy", - "imports": [ - "_BxEwC6Zc.js" - ] - }, - "_kALFGdUG.js": { - "file": "_app/immutable/chunks/kALFGdUG.js", - "name": "branches", - "imports": [ - "_BxEwC6Zc.js" - ] - }, - "node_modules/@sveltejs/kit/src/runtime/client/entry.js": { - "file": "_app/immutable/entry/start.Df1GVxyt.js", - "name": "entry/start", - "src": "node_modules/@sveltejs/kit/src/runtime/client/entry.js", - "isEntry": true, - "imports": [ - "_BkIq08el.js", - "_DAtZQVjv.js" - ] - } -} \ No newline at end of file diff --git a/.svelte-kit/output/client/_app/immutable/assets/2.Dv2no-8m.css b/.svelte-kit/output/client/_app/immutable/assets/2.Dv2no-8m.css deleted file mode 100644 index d32e9ae..0000000 --- a/.svelte-kit/output/client/_app/immutable/assets/2.Dv2no-8m.css +++ /dev/null @@ -1 +0,0 @@ -@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:"Geist Mono", ui-monospace, monospace;--color-red-400:oklch(70.4% .191 22.216);--color-red-500:oklch(63.7% .237 25.331);--color-yellow-400:oklch(85.2% .199 91.936);--color-yellow-500:oklch(79.5% .184 86.047);--color-green-400:oklch(79.2% .209 151.711);--color-green-500:oklch(72.3% .219 149.579);--color-blue-400:oklch(70.7% .165 254.624);--color-blue-500:oklch(62.3% .214 259.815);--color-blue-600:oklch(54.6% .245 262.881);--color-blue-700:oklch(48.8% .243 264.376);--color-purple-400:oklch(71.4% .203 305.504);--color-purple-500:oklch(62.7% .265 303.9);--color-pink-400:oklch(71.8% .202 349.761);--color-pink-500:oklch(65.6% .241 354.308);--color-gray-300:oklch(87.2% .01 258.338);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-md:28rem;--container-2xl:42rem;--container-3xl:48rem;--container-4xl:56rem;--container-5xl:64rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height: 1.5 ;--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height: 1.2 ;--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--text-6xl:3.75rem;--text-6xl--line-height:1;--tracking-tight:-.025em;--tracking-wider:.05em;--tracking-widest:.1em;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--animate-ping:ping 1s cubic-bezier(0, 0, .2, 1) infinite;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--blur-sm:8px;--blur-md:12px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-surface-900:#0a0a0f;--color-surface-800:#12121a;--color-surface-700:#1a1a25;--color-surface-600:#24243a;--color-accent:#ff66ab;--color-accent-hover:#ff85be;--color-accent-dim:#ff66ab33;--color-text-primary:#eeeef0;--color-text-secondary:#8888a0;--color-border:#2a2a3d;--font-body:"Geist", system-ui, sans-serif}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing) * 0)}.start{inset-inline-start:var(--spacing)}.top-0{top:calc(var(--spacing) * 0)}.left-0{left:calc(var(--spacing) * 0)}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.col-span-2{grid-column:span 2/span 2}.mx-auto{margin-inline:auto}.my-4{margin-block:calc(var(--spacing) * 4)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.ml-56{margin-left:calc(var(--spacing) * 56)}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline-block{display:inline-block}.table{display:table}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-2{height:calc(var(--spacing) * 2)}.h-3{height:calc(var(--spacing) * 3)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-10{height:calc(var(--spacing) * 10)}.h-12{height:calc(var(--spacing) * 12)}.h-14{height:calc(var(--spacing) * 14)}.h-16{height:calc(var(--spacing) * 16)}.h-full{height:100%}.max-h-\[80vh\]{max-height:80vh}.min-h-\[70vh\]{min-height:70vh}.min-h-dvh{min-height:100dvh}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-2{width:calc(var(--spacing) * 2)}.w-3{width:calc(var(--spacing) * 3)}.w-6{width:calc(var(--spacing) * 6)}.w-7{width:calc(var(--spacing) * 7)}.w-8{width:calc(var(--spacing) * 8)}.w-10{width:calc(var(--spacing) * 10)}.w-16{width:calc(var(--spacing) * 16)}.w-20{width:calc(var(--spacing) * 20)}.w-24{width:calc(var(--spacing) * 24)}.w-56{width:calc(var(--spacing) * 56)}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-3xl{max-width:var(--container-3xl)}.max-w-4xl{max-width:var(--container-4xl)}.max-w-5xl{max-width:var(--container-5xl)}.max-w-md{max-width:var(--container-md)}.min-w-0{min-width:calc(var(--spacing) * 0)}.flex-1{flex:1}.rotate-90{rotate:90deg}.animate-ping{animation:var(--animate-ping)}.animate-pulse{animation:var(--animate-pulse)}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-\[auto_1fr_auto_auto_auto\]{grid-template-columns:auto 1fr auto auto auto}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-6{gap:calc(var(--spacing) * 6)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-accent\/20{border-color:#ff66ab33}@supports (color:color-mix(in lab,red,red)){.border-accent\/20{border-color:color-mix(in oklab,var(--color-accent) 20%,transparent)}}.border-accent\/30{border-color:#ff66ab4d}@supports (color:color-mix(in lab,red,red)){.border-accent\/30{border-color:color-mix(in oklab,var(--color-accent) 30%,transparent)}}.border-blue-500\/30{border-color:#3080ff4d}@supports (color:color-mix(in lab,red,red)){.border-blue-500\/30{border-color:color-mix(in oklab,var(--color-blue-500) 30%,transparent)}}.border-border{border-color:var(--color-border)}.border-border\/50{border-color:#2a2a3d80}@supports (color:color-mix(in lab,red,red)){.border-border\/50{border-color:color-mix(in oklab,var(--color-border) 50%,transparent)}}.border-gray-300{border-color:var(--color-gray-300)}.border-green-500\/20{border-color:#00c75833}@supports (color:color-mix(in lab,red,red)){.border-green-500\/20{border-color:color-mix(in oklab,var(--color-green-500) 20%,transparent)}}.border-green-500\/30{border-color:#00c7584d}@supports (color:color-mix(in lab,red,red)){.border-green-500\/30{border-color:color-mix(in oklab,var(--color-green-500) 30%,transparent)}}.border-green-500\/40{border-color:#00c75866}@supports (color:color-mix(in lab,red,red)){.border-green-500\/40{border-color:color-mix(in oklab,var(--color-green-500) 40%,transparent)}}.border-pink-500\/30{border-color:#f6339a4d}@supports (color:color-mix(in lab,red,red)){.border-pink-500\/30{border-color:color-mix(in oklab,var(--color-pink-500) 30%,transparent)}}.border-purple-500\/30{border-color:#ac4bff4d}@supports (color:color-mix(in lab,red,red)){.border-purple-500\/30{border-color:color-mix(in oklab,var(--color-purple-500) 30%,transparent)}}.border-red-500\/30{border-color:#fb2c364d}@supports (color:color-mix(in lab,red,red)){.border-red-500\/30{border-color:color-mix(in oklab,var(--color-red-500) 30%,transparent)}}.border-yellow-500\/30{border-color:#edb2004d}@supports (color:color-mix(in lab,red,red)){.border-yellow-500\/30{border-color:color-mix(in oklab,var(--color-yellow-500) 30%,transparent)}}.bg-accent{background-color:var(--color-accent)}.bg-accent-dim{background-color:var(--color-accent-dim)}.bg-accent\/10{background-color:#ff66ab1a}@supports (color:color-mix(in lab,red,red)){.bg-accent\/10{background-color:color-mix(in oklab,var(--color-accent) 10%,transparent)}}.bg-black\/70{background-color:#000000b3}@supports (color:color-mix(in lab,red,red)){.bg-black\/70{background-color:color-mix(in oklab,var(--color-black) 70%,transparent)}}.bg-blue-400{background-color:var(--color-blue-400)}.bg-blue-500\/10{background-color:#3080ff1a}@supports (color:color-mix(in lab,red,red)){.bg-blue-500\/10{background-color:color-mix(in oklab,var(--color-blue-500) 10%,transparent)}}.bg-blue-500\/20{background-color:#3080ff33}@supports (color:color-mix(in lab,red,red)){.bg-blue-500\/20{background-color:color-mix(in oklab,var(--color-blue-500) 20%,transparent)}}.bg-blue-600{background-color:var(--color-blue-600)}.bg-green-400{background-color:var(--color-green-400)}.bg-green-500\/5{background-color:#00c7580d}@supports (color:color-mix(in lab,red,red)){.bg-green-500\/5{background-color:color-mix(in oklab,var(--color-green-500) 5%,transparent)}}.bg-green-500\/20{background-color:#00c75833}@supports (color:color-mix(in lab,red,red)){.bg-green-500\/20{background-color:color-mix(in oklab,var(--color-green-500) 20%,transparent)}}.bg-pink-500\/20{background-color:#f6339a33}@supports (color:color-mix(in lab,red,red)){.bg-pink-500\/20{background-color:color-mix(in oklab,var(--color-pink-500) 20%,transparent)}}.bg-purple-500\/10{background-color:#ac4bff1a}@supports (color:color-mix(in lab,red,red)){.bg-purple-500\/10{background-color:color-mix(in oklab,var(--color-purple-500) 10%,transparent)}}.bg-purple-500\/20{background-color:#ac4bff33}@supports (color:color-mix(in lab,red,red)){.bg-purple-500\/20{background-color:color-mix(in oklab,var(--color-purple-500) 20%,transparent)}}.bg-red-500\/5{background-color:#fb2c360d}@supports (color:color-mix(in lab,red,red)){.bg-red-500\/5{background-color:color-mix(in oklab,var(--color-red-500) 5%,transparent)}}.bg-red-500\/10{background-color:#fb2c361a}@supports (color:color-mix(in lab,red,red)){.bg-red-500\/10{background-color:color-mix(in oklab,var(--color-red-500) 10%,transparent)}}.bg-red-500\/20{background-color:#fb2c3633}@supports (color:color-mix(in lab,red,red)){.bg-red-500\/20{background-color:color-mix(in oklab,var(--color-red-500) 20%,transparent)}}.bg-surface-600{background-color:var(--color-surface-600)}.bg-surface-700{background-color:var(--color-surface-700)}.bg-surface-800{background-color:var(--color-surface-800)}.bg-surface-900{background-color:var(--color-surface-900)}.bg-surface-900\/80{background-color:#0a0a0fcc}@supports (color:color-mix(in lab,red,red)){.bg-surface-900\/80{background-color:color-mix(in oklab,var(--color-surface-900) 80%,transparent)}}.bg-transparent{background-color:#0000}.bg-white{background-color:var(--color-white)}.bg-yellow-400{background-color:var(--color-yellow-400)}.bg-yellow-500\/5{background-color:#edb2000d}@supports (color:color-mix(in lab,red,red)){.bg-yellow-500\/5{background-color:color-mix(in oklab,var(--color-yellow-500) 5%,transparent)}}.bg-yellow-500\/20{background-color:#edb20033}@supports (color:color-mix(in lab,red,red)){.bg-yellow-500\/20{background-color:color-mix(in oklab,var(--color-yellow-500) 20%,transparent)}}.object-cover{object-fit:cover}.p-1{padding:calc(var(--spacing) * 1)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-3\.5{padding-inline:calc(var(--spacing) * 3.5)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.px-8{padding-inline:calc(var(--spacing) * 8)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-5{padding-block:calc(var(--spacing) * 5)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-12{padding-block:calc(var(--spacing) * 12)}.pt-3{padding-top:calc(var(--spacing) * 3)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.text-accent{color:var(--color-accent)}.text-blue-400{color:var(--color-blue-400)}.text-green-400{color:var(--color-green-400)}.text-pink-400{color:var(--color-pink-400)}.text-purple-400{color:var(--color-purple-400)}.text-red-400{color:var(--color-red-400)}.text-red-500{color:var(--color-red-500)}.text-surface-900{color:var(--color-surface-900)}.text-text-primary{color:var(--color-text-primary)}.text-text-secondary{color:var(--color-text-secondary)}.text-text-secondary\/30{color:#8888a04d}@supports (color:color-mix(in lab,red,red)){.text-text-secondary\/30{color:color-mix(in oklab,var(--color-text-secondary) 30%,transparent)}}.text-white{color:var(--color-white)}.text-yellow-400{color:var(--color-yellow-400)}.uppercase{text-transform:uppercase}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.opacity-0{opacity:0}.opacity-30{opacity:.3}.opacity-50{opacity:.5}.opacity-75{opacity:.75}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.backdrop-blur-md{--tw-backdrop-blur:blur(var(--blur-md));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-blur-sm{--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media(hover:hover){.group-hover\:text-accent:is(:where(.group):hover *){color:var(--color-accent)}.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}.placeholder\:text-text-secondary\/50::placeholder{color:#8888a080}@supports (color:color-mix(in lab,red,red)){.placeholder\:text-text-secondary\/50::placeholder{color:color-mix(in oklab,var(--color-text-secondary) 50%,transparent)}}.last\:border-b-0:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}@media(hover:hover){.hover\:border-accent:hover{border-color:var(--color-accent)}.hover\:border-accent\/30:hover{border-color:#ff66ab4d}@supports (color:color-mix(in lab,red,red)){.hover\:border-accent\/30:hover{border-color:color-mix(in oklab,var(--color-accent) 30%,transparent)}}.hover\:border-accent\/40:hover{border-color:#ff66ab66}@supports (color:color-mix(in lab,red,red)){.hover\:border-accent\/40:hover{border-color:color-mix(in oklab,var(--color-accent) 40%,transparent)}}.hover\:border-green-500\/40:hover{border-color:#00c75866}@supports (color:color-mix(in lab,red,red)){.hover\:border-green-500\/40:hover{border-color:color-mix(in oklab,var(--color-green-500) 40%,transparent)}}.hover\:border-red-500\/30:hover{border-color:#fb2c364d}@supports (color:color-mix(in lab,red,red)){.hover\:border-red-500\/30:hover{border-color:color-mix(in oklab,var(--color-red-500) 30%,transparent)}}.hover\:bg-accent-hover:hover{background-color:var(--color-accent-hover)}.hover\:bg-blue-700:hover{background-color:var(--color-blue-700)}.hover\:bg-red-500\/10:hover{background-color:#fb2c361a}@supports (color:color-mix(in lab,red,red)){.hover\:bg-red-500\/10:hover{background-color:color-mix(in oklab,var(--color-red-500) 10%,transparent)}}.hover\:bg-surface-600:hover{background-color:var(--color-surface-600)}.hover\:bg-surface-700:hover{background-color:var(--color-surface-700)}.hover\:bg-yellow-500\/10:hover{background-color:#edb2001a}@supports (color:color-mix(in lab,red,red)){.hover\:bg-yellow-500\/10:hover{background-color:color-mix(in oklab,var(--color-yellow-500) 10%,transparent)}}.hover\:text-accent:hover{color:var(--color-accent)}.hover\:text-red-400:hover{color:var(--color-red-400)}.hover\:text-text-primary:hover{color:var(--color-text-primary)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}}.focus\:border-accent:focus{border-color:var(--color-accent)}.focus\:border-blue-500:focus{border-color:var(--color-blue-500)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-blue-500:focus{--tw-ring-color:var(--color-blue-500)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.disabled\:opacity-50:disabled{opacity:.5}@media(min-width:40rem){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}@media(min-width:64rem){.lg\:col-span-1{grid-column:span 1/span 1}.lg\:col-span-2{grid-column:span 2/span 2}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}}html{background-color:var(--color-surface-900);color:var(--color-text-primary);font-family:var(--font-body)}body{min-height:100dvh}::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:var(--color-surface-900)}::-webkit-scrollbar-thumb{background:var(--color-surface-600);border-radius:3px}::-webkit-scrollbar-thumb:hover{background:var(--color-accent)}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@keyframes ping{75%,to{opacity:0;transform:scale(2)}}@keyframes pulse{50%{opacity:.5}} diff --git a/.svelte-kit/output/client/_app/immutable/chunks/BAocuFgQ.js b/.svelte-kit/output/client/_app/immutable/chunks/BAocuFgQ.js deleted file mode 100644 index 4fefbc4..0000000 --- a/.svelte-kit/output/client/_app/immutable/chunks/BAocuFgQ.js +++ /dev/null @@ -1 +0,0 @@ -import{q as h,C as w,D as A,am as E,ap as L}from"./BxEwC6Zc.js";import{i as x,a as T,p as k,b as D}from"./BkIq08el.js";function C(t,r,s){h(()=>{var n=w(()=>r(t,s?.())||{});if(s&&n?.update){var a=!1,o={};A(()=>{var e=s();E(e),a&&L(o,e)&&(o=e,n.update(e))}),a=!0}if(n?.destroy)return()=>n.destroy()})}function H(t){const r=JSON.parse(t);return r.data&&(r.data=k(r.data,D.decoders)),r}function d(t){return HTMLElement.prototype.cloneNode.call(t)}function S(t,r=()=>{}){const s=async({action:a,result:o,reset:e=!0,invalidateAll:c=!0})=>{o.type==="success"&&(e&&HTMLFormElement.prototype.reset.call(t),c&&await x()),(location.origin+location.pathname===a.origin+a.pathname||o.type==="redirect"||o.type==="error")&&await T(o)};async function n(a){if((a.submitter?.hasAttribute("formmethod")?a.submitter.formMethod:d(t).method)!=="post")return;a.preventDefault();const e=new URL(a.submitter?.hasAttribute("formaction")?a.submitter.formAction:d(t).action),c=a.submitter?.hasAttribute("formenctype")?a.submitter.formEnctype:d(t).enctype,p=new FormData(t,a.submitter),u=new AbortController;let m=!1;const y=await r({action:e,cancel:()=>m=!0,controller:u,formData:p,formElement:t,submitter:a.submitter})??s;if(m)return;let l;try{const i=new Headers({accept:"application/json","x-sveltekit-action":"true"});c!=="multipart/form-data"&&i.set("Content-Type",/^(:?application\/x-www-form-urlencoded|text\/plain)$/.test(c)?c:"application/x-www-form-urlencoded");const b=c==="multipart/form-data"?p:new URLSearchParams(p),f=await fetch(e,{method:"POST",headers:i,cache:"no-store",body:b,signal:u.signal});l=H(await f.text()),l.type==="error"&&(l.status=f.status)}catch(i){if(i?.name==="AbortError")return;l={type:"error",error:i}}await y({action:e,formData:p,formElement:t,update:i=>s({action:e,result:l,reset:i?.reset,invalidateAll:i?.invalidateAll}),result:l})}return HTMLFormElement.prototype.addEventListener.call(t,"submit",n),{destroy(){HTMLFormElement.prototype.removeEventListener.call(t,"submit",n)}}}export{C as a,S as e}; diff --git a/.svelte-kit/output/client/_app/immutable/chunks/BLQQas77.js b/.svelte-kit/output/client/_app/immutable/chunks/BLQQas77.js deleted file mode 100644 index a308712..0000000 --- a/.svelte-kit/output/client/_app/immutable/chunks/BLQQas77.js +++ /dev/null @@ -1 +0,0 @@ -import{G as b,h as Z,H as J,F as H,I as D,J as $,K as y,k as q,L as j,M as ee,N as B,O as F,P as O,Q as re,R as ne,S as U,z as ae,T as m,U as L,V as fe,W as ie,X as le,w as ue,Y,Z as se,_ as oe,$ as te,a0 as X,a1 as ve,a2 as K,a3 as P,a4 as z,a5 as de,a6 as ce,a7 as pe,a8 as _e,a9 as he,aa as ge}from"./BxEwC6Zc.js";function Ce(e,i){return i}function Ee(e,i,l){for(var d=[],g=i.length,s,u=i.length,p=0;p{if(s){if(s.pending.delete(E),s.done.add(E),s.pending.size===0){var o=e.outrogroups;V(Y(s.done)),o.delete(s),o.size===0&&(e.outrogroups=null)}}else u-=1},!1)}if(u===0){var f=d.length===0&&l!==null;if(f){var t=l,n=t.parentNode;_e(n),n.append(t),e.items.clear()}V(i,!f)}else s={pending:new Set(i),done:new Set},(e.outrogroups??=new Set).add(s)}function V(e,i=!0){for(var l=0;l{var a=l();return ue(a)?a:a==null?[]:Y(a)}),o,c=!0;function A(){r.fallback=n,me(r,o,u,i,d),n!==null&&(o.length===0?(n.f&m)===0?K(n):(n.f^=m,k(n,null,u)):P(n,()=>{n=null}))}var I=Z(()=>{o=q(E);var a=o.length;let N=!1;if(H){var S=j(u)===ee;S!==(a===0)&&(u=B(),D(u),F(!1),N=!0)}for(var h=new Set,C=ae,x=ie(),_=0;_s(u)):(n=L(()=>s(G??=b())),n.f|=m)),a>h.size&&fe(),H&&a>0&&D(B()),!c)if(x){for(const[Q,W]of p)h.has(Q)||C.skip_effect(W.e);C.oncommit(A),C.ondiscard(()=>{})}else A();N&&F(!0),q(E)}),r={effect:I,items:p,outrogroups:null,fallback:n};c=!1,H&&(u=O)}function M(e){for(;e!==null&&(e.f&ce)===0;)e=e.next;return e}function me(e,i,l,d,g){var s=(d&pe)!==0,u=i.length,p=e.items,f=M(e.effect.first),t,n=null,E,o=[],c=[],A,I,r,a;if(s)for(a=0;a0){var R=(d&J)!==0&&u===0?l:null;if(s){for(a=0;a{if(E!==void 0)for(r of E)r.nodes?.a?.apply()})}function Te(e,i,l,d,g,s,u,p){var f=(u&se)!==0?(u&oe)===0?te(l,!1,!1):X(l):null,t=(u&ve)!==0?X(g):null;return{v:f,i:t,e:L(()=>(s(i,f??l,t??g,p),()=>{e.delete(d)}))}}function k(e,i,l){if(e.nodes)for(var d=e.nodes.start,g=e.nodes.end,s=i&&(i.f&m)===0?i.nodes.start:l;d!==null;){var u=ge(d);if(s.before(d),d===g)return;d=u}}function T(e,i,l){i===null?e.effect.first=l:i.next=l,l===null?e.effect.last=i:l.prev=i}export{we as e,Ce as i}; diff --git a/.svelte-kit/output/client/_app/immutable/chunks/BQKoxf2Q.js b/.svelte-kit/output/client/_app/immutable/chunks/BQKoxf2Q.js deleted file mode 100644 index 1911957..0000000 --- a/.svelte-kit/output/client/_app/immutable/chunks/BQKoxf2Q.js +++ /dev/null @@ -1 +0,0 @@ -import{h as b,F as f,K as h,E as p,L as v,aP as g,M as m,N as A,I as E,O as _,P as R}from"./BxEwC6Zc.js";import{B as S}from"./kALFGdUG.js";function O(l,u,c=!1){var t;f&&(t=R,h());var n=new S(l),T=c?p:0;function i(a,e){if(f){var r=v(t),s;if(r===g?s=0:r===m?s=!1:s=parseInt(r.substring(1)),a!==s){var o=A();E(o),n.anchor=o,_(!1),n.ensure(a,e),_(!0);return}}n.ensure(a,e)}b(()=>{var a=!1;u((e,r=0)=>{a=!0,i(r,e)}),a||i(!1,null)},T)}const I=Object.freeze(Object.defineProperty({__proto__:null},Symbol.toStringTag,{value:"Module"}));export{I as _,O as i}; diff --git a/.svelte-kit/output/client/_app/immutable/chunks/BkIq08el.js b/.svelte-kit/output/client/_app/immutable/chunks/BkIq08el.js deleted file mode 100644 index 609fb01..0000000 --- a/.svelte-kit/output/client/_app/immutable/chunks/BkIq08el.js +++ /dev/null @@ -1,3 +0,0 @@ -import{s as ft}from"./CvGSsBh3.js";import{a as ut,e as dt,c as ht,H as B,N as G,d as Ve,i as Ae,b as L,s as x,p as R,n as ge,f as Ke,g as ye,h as ee,j as pe,S as Ye,P as pt,u as Se,k as _t,l as mt,o as He,m as V,q as gt,t as yt,v as Ge,w as wt,x as vt,y as ze,z as bt,A as xe}from"./DAtZQVjv.js";import{B as te,as as Et}from"./BxEwC6Zc.js";class fe{constructor(t,a){this.status=t,typeof a=="string"?this.body={message:a}:a?this.body=a:this.body={message:`Error: ${t}`}}toString(){return JSON.stringify(this.body)}}class Re{constructor(t,a){this.status=t,this.location=a}}class Ie extends Error{constructor(t,a,n){super(n),this.status=t,this.text=a}}function kt({nodes:e,server_loads:t,dictionary:a,matchers:n}){const r=new Set(t);return Object.entries(a).map(([c,[i,l,h]])=>{const{pattern:d,params:m}=ut(c),u={id:c,exec:f=>{const y=d.exec(f);if(y)return dt(y,m,n)},errors:[1,...h||[]].map(f=>e[f]),layouts:[0,...l||[]].map(s),leaf:o(i)};return u.errors.length=u.layouts.length=Math.max(u.errors.length,u.layouts.length),u});function o(c){const i=c<0;return i&&(c=~c),[i,e[c]]}function s(c){return c===void 0?c:[r.has(c),e[c]]}}function Je(e,t=JSON.parse){try{return t(sessionStorage[e])}catch{}}function Be(e,t,a=JSON.stringify){const n=a(t);try{sessionStorage[e]=n}catch{}}function At(e){const t=Rt(e),a=new ArrayBuffer(t.length),n=new DataView(a);for(let r=0;r>16),t+=String.fromCharCode((a&65280)>>8),t+=String.fromCharCode(a&255),a=n=0);return n===12?(a>>=4,t+=String.fromCharCode(a)):n===18&&(a>>=2,t+=String.fromCharCode((a&65280)>>8),t+=String.fromCharCode(a&255)),t}const It=-1,Tt=-2,Lt=-3,Pt=-4,Ut=-5,Nt=-6,Ot=-7;function oa(e,t){return We(JSON.parse(e),t)}function We(e,t){if(typeof e=="number")return o(e,!0);if(!Array.isArray(e)||e.length===0)throw new Error("Invalid input");const a=e,n=Array(a.length);let r=null;function o(s,c=!1){if(s===It)return;if(s===Lt)return NaN;if(s===Pt)return 1/0;if(s===Ut)return-1/0;if(s===Nt)return-0;if(c||typeof s!="number")throw new Error("Invalid input");if(s in n)return n[s];const i=a[s];if(!i||typeof i!="object")n[s]=i;else if(Array.isArray(i))if(typeof i[0]=="string"){const l=i[0],h=t&&Object.hasOwn(t,l)?t[l]:void 0;if(h){let d=i[1];if(typeof d!="number"&&(d=a.push(i[1])-1),r??=new Set,r.has(d))throw new Error("Invalid circular reference");return r.add(d),n[s]=h(o(d)),r.delete(d),n[s]}switch(l){case"Date":n[s]=new Date(i[1]);break;case"Set":const d=new Set;n[s]=d;for(let f=1;ft!=null)}const jt="x-sveltekit-invalidated",Dt="x-sveltekit-trailing-slash";function ae(e){return e instanceof fe||e instanceof Ie?e.status:500}function xt(e){return e instanceof Ie?e.text:"Internal Error"}const Bt="/__data.json",Ft=".html__data.json";function Mt(e){return e.endsWith(".html")?e.replace(/\.html$/,Ft):e.replace(/\/$/,"")+Bt}const{tick:Xe}=ft,$t=new Set(["icon","shortcut icon","apple-touch-icon"]),D=Je(ze)??{},z=Je(Ge)??{},j={url:xe({}),page:xe({}),navigating:bt(null),updated:ht()};function Te(e){D[e]=x()}function qt(e,t){let a=e+1;for(;D[a];)delete D[a],a+=1;for(a=t+1;z[a];)delete z[a],a+=1}function $(e,t=!1){return t?location.replace(e.href):location.href=e.href,new Promise(()=>{})}async function Ze(){if("serviceWorker"in navigator){const e=await navigator.serviceWorker.getRegistration(L||"/");e&&await e.update()}}function we(){}let Le,ve,ne,N,be,E;const re=[],oe=[];let P=null;function se(){P?.fork?.then(e=>e?.discard()),P=null}const Q=new Map,Qe=new Set,Vt=new Set,Y=new Set;let p={branch:[],error:null,url:null},Pe=!1,ie=!1,Fe=!0,J=!1,K=!1,et=!1,X=!1,q,S,I,O;const H=new Set;let _e;const ce=new Map;async function sa(e,t,a){globalThis.__sveltekit_12t8tv8?.data&&globalThis.__sveltekit_12t8tv8.data,document.URL!==location.href&&(location.href=location.href),E=e,await e.hooks.init?.(),Le=kt(e),N=document.documentElement,be=t,ve=e.nodes[0],ne=e.nodes[1],ve(),ne(),S=history.state?.[B],I=history.state?.[G],S||(S=I=Date.now(),history.replaceState({...history.state,[B]:S,[G]:I},""));const n=D[S];function r(){n&&(history.scrollRestoration="manual",scrollTo(n.x,n.y))}a?(r(),await ea(be,a)):(await F({type:"enter",url:Ve(E.hash?ta(new URL(location.href)):location.href),replace_state:!0}),r()),Qt()}async function Kt(e=!0,t=!0){if(await(_e||=Promise.resolve()),!_e)return;_e=null;const a=O={},n=await Z(p.url,!0);if(se(),X&&ce.forEach(({resource:r})=>{r.refresh?.()}),e){const r=R.state,o=n&&await Ce(n);if(!o||a!==O)return;if(o.type==="redirect")return Ue(new URL(o.location,p.url).href,{replaceState:!0},1,a);t||(o.props.page.state=r),Se(o.props.page),p=o.state,Ee(),q.$set(o.props)}else Ee();await Promise.all([...ce.values()].map(({resource:r})=>r)).catch(we)}function Ee(){re.length=0,X=!1}function tt(e){oe.some(t=>t?.snapshot)&&(z[e]=oe.map(t=>t?.snapshot?.capture()))}function at(e){z[e]?.forEach((t,a)=>{oe[a]?.snapshot?.restore(t)})}function Me(){Te(S),Be(ze,D),tt(I),Be(Ge,z)}async function Ue(e,t,a,n){let r;t.invalidateAll&&se(),await F({type:"goto",url:Ve(e),keepfocus:t.keepFocus,noscroll:t.noScroll,replace_state:t.replaceState,state:t.state,redirect_count:a,nav_token:n,accept:()=>{t.invalidateAll&&(X=!0,r=[...ce.keys()]),t.invalidate&&t.invalidate.forEach(Xt)}}),t.invalidateAll&&te().then(te).then(()=>{ce.forEach(({resource:o},s)=>{r?.includes(s)&&o.refresh?.()})})}async function Yt(e){if(e.id!==P?.id){se();const t={};H.add(t),P={id:e.id,token:t,promise:Ce({...e,preload:t}).then(a=>(H.delete(t),a.type==="loaded"&&a.state.error&&se(),a)),fork:null}}return P.promise}async function me(e){const t=(await Z(e,!1))?.route;t&&await Promise.all([...t.layouts,t.leaf].filter(Boolean).map(a=>a[1]()))}async function nt(e,t,a){p=e.state;const n=document.querySelector("style[data-sveltekit]");if(n&&n.remove(),Object.assign(R,e.props.page),q=new E.root({target:t,props:{...e.props,stores:j,components:oe},hydrate:a,sync:!1}),await Promise.resolve(),at(I),a){const r={from:null,to:{params:p.params,route:{id:p.route?.id??null},url:new URL(location.href),scroll:D[S]??x()},willUnload:!1,type:"enter",complete:Promise.resolve()};Y.forEach(o=>o(r))}ie=!0}function W({url:e,params:t,branch:a,status:n,error:r,route:o,form:s}){let c="never";if(L&&(e.pathname===L||e.pathname===L+"/"))c="always";else for(const u of a)u?.slash!==void 0&&(c=u.slash);e.pathname=mt(e.pathname,c),e.search=e.search;const i={type:"loaded",state:{url:e,params:t,branch:a,error:r,route:o},props:{constructors:Ct(a).map(u=>u.node.component),page:de(R)}};s!==void 0&&(i.props.form=s);let l={},h=!R,d=0;for(let u=0;uc(new URL(s))))return!0;return!1}function Oe(e,t){return e?.type==="data"?e:e?.type==="skip"?t??null:null}function Gt(e,t){if(!e)return new Set(t.searchParams.keys());const a=new Set([...e.searchParams.keys(),...t.searchParams.keys()]);for(const n of a){const r=e.searchParams.getAll(n),o=t.searchParams.getAll(n);r.every(s=>o.includes(s))&&o.every(s=>r.includes(s))&&a.delete(n)}return a}function qe({error:e,url:t,route:a,params:n}){return{type:"loaded",state:{error:e,url:t,route:a,params:n,branch:[]},props:{page:de(R),constructors:[]}}}async function Ce({id:e,invalidating:t,url:a,params:n,route:r,preload:o}){if(P?.id===e)return H.delete(P.token),P.promise;const{errors:s,layouts:c,leaf:i}=r,l=[...c,i];s.forEach(g=>g?.().catch(()=>{})),l.forEach(g=>g?.[1]().catch(()=>{}));let h=null;const d=p.url?e!==le(p.url):!1,m=p.route?r.id!==p.route.id:!1,u=Gt(p.url,a);let f=!1;{const g=l.map((w,k)=>{const A=p.branch[k],v=!!w?.[0]&&(A?.loader!==w[1]||$e(f,m,d,u,A.server?.uses,n));return v&&(f=!0),v});if(g.some(Boolean)){try{h=await it(a,g)}catch(w){const k=await M(w,{url:a,params:n,route:{id:e}});return H.has(o)?qe({error:k,url:a,params:n,route:r}):ue({status:ae(w),error:k,url:a,route:r})}if(h.type==="redirect")return h}}const y=h?.nodes;let b=!1;const _=l.map(async(g,w)=>{if(!g)return;const k=p.branch[w],A=y?.[w];if((!A||A.type==="skip")&&g[1]===k?.loader&&!$e(b,m,d,u,k.universal?.uses,n))return k;if(b=!0,A?.type==="error")throw A;return Ne({loader:g[1],url:a,params:n,route:r,parent:async()=>{const C={};for(let U=0;U{});const T=[];for(let g=0;gPromise.resolve({}),server_data_node:Oe(o)}),c={node:await ne(),loader:ne,universal:null,server:null,data:null};return W({url:a,params:r,branch:[s,c],status:e,error:t,route:null})}catch(s){if(s instanceof Re)return Ue(new URL(s.location,location.href),{},0);throw s}}async function zt(e){const t=e.href;if(Q.has(t))return Q.get(t);let a;try{const n=(async()=>{let r=await E.hooks.reroute({url:new URL(e),fetch:async(o,s)=>Ht(o,s,e).promise})??e;if(typeof r=="string"){const o=new URL(e);E.hash?o.hash=r:o.pathname=r,r=o}return r})();Q.set(t,n),a=await n}catch{Q.delete(t);return}return a}async function Z(e,t){if(e&&!Ae(e,L,E.hash)){const a=await zt(e);if(!a)return;const n=Jt(a);for(const r of Le){const o=r.exec(n);if(o)return{id:le(e),invalidating:t,route:r,params:_t(o),url:e}}}}function Jt(e){return gt(E.hash?e.hash.replace(/^#/,"").replace(/[?#].+/,""):e.pathname.slice(L.length))||"/"}function le(e){return(E.hash?e.hash.replace(/^#/,""):e.pathname)+e.search}function ot({url:e,type:t,intent:a,delta:n,event:r,scroll:o}){let s=!1;const c=De(p,a,e,t,o??null);n!==void 0&&(c.navigation.delta=n),r!==void 0&&(c.navigation.event=r);const i={...c.navigation,cancel:()=>{s=!0,c.reject(new Error("navigation cancelled"))}};return J||Qe.forEach(l=>l(i)),s?null:c}async function F({type:e,url:t,popped:a,keepfocus:n,noscroll:r,replace_state:o,state:s={},redirect_count:c=0,nav_token:i={},accept:l=we,block:h=we,event:d}){const m=O;O=i;const u=await Z(t,!1),f=e==="enter"?De(p,u,t,e):ot({url:t,type:e,delta:a?.delta,intent:u,scroll:a?.scroll,event:d});if(!f){h(),O===i&&(O=m);return}const y=S,b=I;l(),J=!0,ie&&f.navigation.type!=="enter"&&j.navigating.set(ge.current=f.navigation);let _=u&&await Ce(u);if(!_){if(Ae(t,L,E.hash))return await $(t,o);_=await st(t,{id:null},await M(new Ie(404,"Not Found",`Not found: ${t.pathname}`),{url:t,params:{},route:{id:null}}),404,o)}if(t=u?.url||t,O!==i)return f.reject(new Error("navigation aborted")),!1;if(_.type==="redirect"){if(c<20){await F({type:e,url:new URL(_.location,t),popped:a,keepfocus:n,noscroll:r,replace_state:o,state:s,redirect_count:c+1,nav_token:i}),f.fulfil(void 0);return}_=await ue({status:500,error:await M(new Error("Redirect loop"),{url:t,params:{},route:{id:null}}),url:t,route:{id:null}})}else _.props.page.status>=400&&await j.updated.check()&&(await Ze(),await $(t,o));if(Ee(),Te(y),tt(b),_.props.page.url.pathname!==t.pathname&&(t.pathname=_.props.page.url.pathname),s=a?a.state:s,!a){const v=o?0:1,C={[B]:S+=v,[G]:I+=v,[Ye]:s};(o?history.replaceState:history.pushState).call(history,C,"",t),o||qt(S,I)}const T=u&&P?.id===u.id?P.fork:null;P=null,_.props.page.state=s;let g;if(ie){const v=(await Promise.all(Array.from(Vt,U=>U(f.navigation)))).filter(U=>typeof U=="function");if(v.length>0){let U=function(){v.forEach(he=>{Y.delete(he)})};v.push(U),v.forEach(he=>{Y.add(he)})}p=_.state,_.props.page&&(_.props.page.url=t);const C=T&&await T;C?g=C.commit():(q.$set(_.props),Se(_.props.page),g=Et?.()),et=!0}else await nt(_,be,!1);const{activeElement:w}=document;await g,await te(),await te();let k=null;if(Fe){const v=a?a.scroll:r?x():null;v?scrollTo(v.x,v.y):(k=t.hash&&document.getElementById(lt(t)))?k.scrollIntoView():scrollTo(0,0)}const A=document.activeElement!==w&&document.activeElement!==document.body;!n&&!A&&je(t,!k),Fe=!0,_.props.page&&Object.assign(R,_.props.page),J=!1,e==="popstate"&&at(I),f.fulfil(void 0),f.navigation.to&&(f.navigation.to.scroll=x()),Y.forEach(v=>v(f.navigation)),j.navigating.set(ge.current=null)}async function st(e,t,a,n,r){return e.origin===He&&e.pathname===location.pathname&&!Pe?await ue({status:n,error:a,url:e,route:t}):await $(e,r)}function Wt(){let e,t={element:void 0,href:void 0},a;N.addEventListener("mousemove",c=>{const i=c.target;clearTimeout(e),e=setTimeout(()=>{o(i,V.hover)},20)});function n(c){c.defaultPrevented||o(c.composedPath()[0],V.tap)}N.addEventListener("mousedown",n),N.addEventListener("touchstart",n,{passive:!0});const r=new IntersectionObserver(c=>{for(const i of c)i.isIntersecting&&(me(new URL(i.target.href)),r.unobserve(i.target))},{threshold:0});async function o(c,i){const l=Ke(c,N),h=l===t.element&&l?.href===t.href&&i>=a;if(!l||h)return;const{url:d,external:m,download:u}=ye(l,L,E.hash);if(m||u)return;const f=ee(l),y=d&&le(p.url)===le(d);if(!(f.reload||y))if(i<=f.preload_data){t={element:l,href:l.href},a=V.tap;const b=await Z(d,!1);if(!b)return;Yt(b)}else i<=f.preload_code&&(t={element:l,href:l.href},a=i,me(d))}function s(){r.disconnect();for(const c of N.querySelectorAll("a")){const{url:i,external:l,download:h}=ye(c,L,E.hash);if(l||h)continue;const d=ee(c);d.reload||(d.preload_code===V.viewport&&r.observe(c),d.preload_code===V.eager&&me(i))}}Y.add(s),s()}function M(e,t){if(e instanceof fe)return e.body;const a=ae(e),n=xt(e);return E.hooks.handleError({error:e,event:t,status:a,message:n})??{message:n}}function Xt(e){if(typeof e=="function")re.push(e);else{const{href:t}=new URL(e,location.href);re.push(a=>a.href===t)}}function ia(){return X=!0,Kt()}async function ca(e){e.type==="error"?await Zt(e.error,e.status):e.type==="redirect"?await Ue(e.location,{invalidateAll:!0},0):(R.form=e.data,R.status=e.status,q.$set({form:null,page:de(R)}),await Xe(),q.$set({form:e.data}),e.type==="success"&&je(R.url))}async function Zt(e,t=500){const a=new URL(location.href),{branch:n,route:r}=p;if(!r)return;const o=await rt(p.branch.length,n,r.errors);if(o){const s=W({url:a,params:p.params,branch:n.slice(0,o.idx).concat(o.node),status:t,error:e,route:r});p=s.state,q.$set(s.props),Se(s.props.page),Xe().then(()=>je(p.url))}}function Qt(){history.scrollRestoration="manual",addEventListener("beforeunload",t=>{let a=!1;if(Me(),!J){const n=De(p,void 0,null,"leave"),r={...n.navigation,cancel:()=>{a=!0,n.reject(new Error("navigation cancelled"))}};Qe.forEach(o=>o(r))}a?(t.preventDefault(),t.returnValue=""):history.scrollRestoration="auto"}),addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&Me()}),navigator.connection?.saveData||Wt(),N.addEventListener("click",async t=>{if(t.button||t.which!==1||t.metaKey||t.ctrlKey||t.shiftKey||t.altKey||t.defaultPrevented)return;const a=Ke(t.composedPath()[0],N);if(!a)return;const{url:n,external:r,target:o,download:s}=ye(a,L,E.hash);if(!n)return;if(o==="_parent"||o==="_top"){if(window.parent!==window)return}else if(o&&o!=="_self")return;const c=ee(a);if(!(a instanceof SVGAElement)&&n.protocol!==location.protocol&&!(n.protocol==="https:"||n.protocol==="http:")||s)return;const[l,h]=(E.hash?n.hash.replace(/^#/,""):n.href).split("#"),d=l===pe(location);if(r||c.reload&&(!d||!h)){ot({url:n,type:"link",event:t})?J=!0:t.preventDefault();return}if(h!==void 0&&d){const[,m]=p.url.href.split("#");if(m===h){if(t.preventDefault(),h===""||h==="top"&&a.ownerDocument.getElementById("top")===null)scrollTo({top:0});else{const u=a.ownerDocument.getElementById(decodeURIComponent(h));u&&(u.scrollIntoView(),u.focus())}return}if(K=!0,Te(S),e(n),!c.replace_state)return;K=!1}t.preventDefault(),await new Promise(m=>{requestAnimationFrame(()=>{setTimeout(m,0)}),setTimeout(m,100)}),await F({type:"link",url:n,keepfocus:c.keepfocus,noscroll:c.noscroll,replace_state:c.replace_state??n.href===location.href,event:t})}),N.addEventListener("submit",t=>{if(t.defaultPrevented)return;const a=HTMLFormElement.prototype.cloneNode.call(t.target),n=t.submitter;if((n?.formTarget||a.target)==="_blank"||(n?.formMethod||a.method)!=="get")return;const s=new URL(n?.hasAttribute("formaction")&&n?.formAction||a.action);if(Ae(s,L,!1))return;const c=t.target,i=ee(c);if(i.reload)return;t.preventDefault(),t.stopPropagation();const l=new FormData(c,n);s.search=new URLSearchParams(l).toString(),F({type:"form",url:s,keepfocus:i.keepfocus,noscroll:i.noscroll,replace_state:i.replace_state??s.href===location.href,event:t})}),addEventListener("popstate",async t=>{if(!ke){if(t.state?.[B]){const a=t.state[B];if(O={},a===S)return;const n=D[a],r=t.state[Ye]??{},o=new URL(t.state[pt]??location.href),s=t.state[G],c=p.url?pe(location)===pe(p.url):!1;if(s===I&&(et||c)){r!==R.state&&(R.state=r),e(o),D[S]=x(),n&&scrollTo(n.x,n.y),S=a;return}const l=a-S;await F({type:"popstate",url:o,popped:{state:r,scroll:n,delta:l},accept:()=>{S=a,I=s},block:()=>{history.go(-l)},nav_token:O,event:t})}else if(!K){const a=new URL(location.href);e(a),E.hash&&location.reload()}}}),addEventListener("hashchange",()=>{K&&(K=!1,history.replaceState({...history.state,[B]:++S,[G]:I},"",location.href))});for(const t of document.querySelectorAll("link"))$t.has(t.rel)&&(t.href=t.href);addEventListener("pageshow",t=>{t.persisted&&j.navigating.set(ge.current=null)});function e(t){p.url=R.url=t,j.page.set(de(R)),j.page.notify()}}async function ea(e,{status:t=200,error:a,node_ids:n,params:r,route:o,server_route:s,data:c,form:i}){Pe=!0;const l=new URL(location.href);let h;({params:r={},route:o={id:null}}=await Z(l,!1)||{}),h=Le.find(({id:u})=>u===o.id);let d,m=!0;try{const u=n.map(async(y,b)=>{const _=c[b];return _?.uses&&(_.uses=ct(_.uses)),Ne({loader:E.nodes[y],url:l,params:r,route:o,parent:async()=>{const T={};for(let g=0;go?"1":"0").join(""));const n=window.fetch,r=await n(a.href,{});if(!r.ok){let o;throw r.headers.get("content-type")?.includes("application/json")?o=await r.json():r.status===404?o="Not Found":r.status===500&&(o="Internal Error"),new fe(r.status,o)}return new Promise(async o=>{const s=new Map,c=r.body.getReader();function i(h){return We(h,{...E.decoders,Promise:d=>new Promise((m,u)=>{s.set(d,{fulfil:m,reject:u})})})}let l="";for(;;){const{done:h,value:d}=await c.read();if(h&&!l)break;for(l+=!d&&l?` -`:yt.decode(d,{stream:!0});;){const m=l.indexOf(` -`);if(m===-1)break;const u=JSON.parse(l.slice(0,m));if(l=l.slice(m+1),u.type==="redirect")return o(u);if(u.type==="data")u.nodes?.forEach(f=>{f?.type==="data"&&(f.uses=ct(f.uses),f.data=i(f.data))}),o(u);else if(u.type==="chunk"){const{id:f,data:y,error:b}=u,_=s.get(f);s.delete(f),b?_.reject(i(b)):_.fulfil(i(y))}}}})}function ct(e){return{dependencies:new Set(e?.dependencies??[]),params:new Set(e?.params??[]),parent:!!e?.parent,route:!!e?.route,url:!!e?.url,search_params:new Set(e?.search_params??[])}}let ke=!1;function je(e,t=!0){const a=document.querySelector("[autofocus]");if(a)a.focus();else{const n=lt(e);if(n&&document.getElementById(n)){const{x:o,y:s}=x();setTimeout(()=>{const c=history.state;ke=!0,location.replace(new URL(`#${n}`,location.href)),history.replaceState(c,"",e),t&&scrollTo(o,s),ke=!1})}else{const o=document.body,s=o.getAttribute("tabindex");o.tabIndex=-1,o.focus({preventScroll:!0,focusVisible:!1}),s!==null?o.setAttribute("tabindex",s):o.removeAttribute("tabindex")}const r=getSelection();if(r&&r.type!=="None"){const o=[];for(let s=0;s{if(r.rangeCount===o.length){for(let s=0;s{o=l,s=h});return c.catch(()=>{}),{navigation:{from:{params:e.params,route:{id:e.route?.id??null},url:e.url,scroll:x()},to:a&&{params:t?.params??null,route:{id:t?.route?.id??null},url:a,scroll:r},willUnload:!t,type:n,complete:c},fulfil:o,reject:s}}function de(e){return{data:e.data,error:e.error,form:e.form,params:e.params,route:e.route,state:e.state,status:e.status,url:e.url}}function ta(e){const t=new URL(e);return t.hash=decodeURIComponent(e.hash),t}function lt(e){let t;if(E.hash){const[,,a]=e.hash.split("#",3);t=a??""}else t=e.hash.slice(1);return decodeURIComponent(t)}export{ca as a,E as b,sa as c,ia as i,oa as p,j as s}; diff --git a/.svelte-kit/output/client/_app/immutable/chunks/BnX5ZnVA.js b/.svelte-kit/output/client/_app/immutable/chunks/BnX5ZnVA.js deleted file mode 100644 index af55481..0000000 --- a/.svelte-kit/output/client/_app/immutable/chunks/BnX5ZnVA.js +++ /dev/null @@ -1 +0,0 @@ -import{ac as u,ad as v,F as _,ae as h,af as f,a5 as A,ag as l,ah as g}from"./BxEwC6Zc.js";const S=Symbol("is custom element"),p=Symbol("is html"),N=f?"link":"LINK",T=f?"progress":"PROGRESS";function M(s){if(_){var r=!1,e=()=>{if(!r){if(r=!0,s.hasAttribute("value")){var a=s.value;c(s,"value",null),s.value=a}if(s.hasAttribute("checked")){var t=s.checked;c(s,"checked",null),s.checked=t}}};s.__on_r=e,A(e),l()}}function k(s,r){var e=d(s);e.value===(e.value=r??void 0)||s.value===r&&(r!==0||s.nodeName!==T)||(s.value=r??"")}function y(s,r){r?s.hasAttribute("selected")||s.setAttribute("selected",""):s.removeAttribute("selected")}function c(s,r,e,a){var t=d(s);_&&(t[r]=s.getAttribute(r),r==="src"||r==="srcset"||r==="href"&&s.nodeName===N)||t[r]!==(t[r]=e)&&(r==="loading"&&(s[g]=e),e==null?s.removeAttribute(r):typeof e!="string"&&E(s).includes(r)?s[r]=e:s.setAttribute(r,e))}function d(s){return s.__attributes??={[S]:s.nodeName.includes("-"),[p]:s.namespaceURI===u}}var i=new Map;function E(s){var r=s.getAttribute("is")||s.nodeName,e=i.get(r);if(e)return e;i.set(r,e=[]);for(var a,t=s,n=Element.prototype;n!==t;){a=h(t);for(var o in a)a[o].set&&e.push(o);t=v(t)}return e}export{k as a,y as b,M as r,c as s}; diff --git a/.svelte-kit/output/client/_app/immutable/chunks/BqOsL1Vv.js b/.svelte-kit/output/client/_app/immutable/chunks/BqOsL1Vv.js deleted file mode 100644 index 3f264a6..0000000 --- a/.svelte-kit/output/client/_app/immutable/chunks/BqOsL1Vv.js +++ /dev/null @@ -1 +0,0 @@ -import{F as i}from"./BxEwC6Zc.js";function n(s,l,r){var t=s==null?"":""+s;return t===""?null:t}function h(s,l,r,t,f,c){var a=s.__className;if(i||a!==r||a===void 0){var e=n(r);(!i||e!==s.getAttribute("class"))&&(e==null?s.removeAttribute("class"):s.className=e),s.__className=r}return c}export{h as s}; diff --git a/.svelte-kit/output/client/_app/immutable/chunks/BxEwC6Zc.js b/.svelte-kit/output/client/_app/immutable/chunks/BxEwC6Zc.js deleted file mode 100644 index 7c1d4c2..0000000 --- a/.svelte-kit/output/client/_app/immutable/chunks/BxEwC6Zc.js +++ /dev/null @@ -1 +0,0 @@ -var Vt=Array.isArray,Ut=Array.prototype.indexOf,le=Array.prototype.includes,qn=Array.from,Vn=Object.defineProperty,de=Object.getOwnPropertyDescriptor,Bt=Object.getOwnPropertyDescriptors,Gt=Object.prototype,zt=Array.prototype,ft=Object.getPrototypeOf,Ze=Object.isExtensible;const Kt=()=>{};function Un(e){return e()}function Xt(e){for(var t=0;t{e=r,t=s});return{promise:n,resolve:e,reject:t}}function Bn(e,t){if(Array.isArray(e))return e;if(!(Symbol.iterator in e))return Array.from(e);const n=[];for(const r of e)if(n.push(r),n.length===t)break;return n}const g=2,we=4,me=8,ot=1<<24,q=16,L=32,fe=64,$t=128,O=512,m=1024,A=2048,F=4096,M=8192,U=16384,z=32768,Re=65536,Je=1<<17,ut=1<<18,Ee=1<<19,ct=1<<20,Gn=1<<25,ne=65536,Ce=1<<21,Ye=1<<22,B=1<<23,Q=Symbol("$state"),zn=Symbol("legacy props"),Kn=Symbol(""),W=new class extends Error{name="StaleReactionError";message="The reaction that called `getAbortSignal()` was re-run or destroyed"},$n=!!globalThis.document?.contentType&&globalThis.document.contentType.includes("xml"),ge=3,_t=8;function Wt(){throw new Error("https://svelte.dev/e/async_derived_orphan")}function Wn(e,t,n){throw new Error("https://svelte.dev/e/each_key_duplicate")}function Zt(e){throw new Error("https://svelte.dev/e/effect_in_teardown")}function Jt(){throw new Error("https://svelte.dev/e/effect_in_unowned_derived")}function Qt(e){throw new Error("https://svelte.dev/e/effect_orphan")}function en(){throw new Error("https://svelte.dev/e/effect_update_depth_exceeded")}function Zn(){throw new Error("https://svelte.dev/e/hydration_failed")}function Jn(e){throw new Error("https://svelte.dev/e/props_invalid_value")}function tn(){throw new Error("https://svelte.dev/e/state_descriptors_fixed")}function nn(){throw new Error("https://svelte.dev/e/state_prototype_fixed")}function rn(){throw new Error("https://svelte.dev/e/state_unsafe_mutation")}function Qn(){throw new Error("https://svelte.dev/e/svelte_boundary_reset_onerror")}const er=1,tr=2,nr=4,rr=8,sr=16,ir=1,ar=2,fr=4,lr=8,or=16,sn=1,an=2,fn="[",ln="[!",ur="[?",on="]",qe={},E=Symbol(),un="http://www.w3.org/1999/xhtml";function Ve(e){console.warn("https://svelte.dev/e/hydration_mismatch")}function cr(){console.warn("https://svelte.dev/e/select_multiple_invalid_value")}function _r(){console.warn("https://svelte.dev/e/svelte_boundary_reset_noop")}let C=!1;function vr(e){C=e}let y;function re(e){if(e===null)throw Ve(),qe;return y=e}function cn(){return re(X(y))}function dr(e){if(C){if(X(y)!==null)throw Ve(),qe;y=e}}function hr(e=1){if(C){for(var t=e,n=y;t--;)n=X(n);y=n}}function pr(e=!0){for(var t=0,n=y;;){if(n.nodeType===_t){var r=n.data;if(r===on){if(t===0)return n;t-=1}else(r===fn||r===ln||r[0]==="["&&!isNaN(Number(r.slice(1))))&&(t+=1)}var s=X(n);e&&n.remove(),n=s}}function yr(e){if(!e||e.nodeType!==_t)throw Ve(),qe;return e.data}function vt(e){return e===this.v}function _n(e,t){return e!=e?t==t:e!==t||e!==null&&typeof e=="object"||typeof e=="function"}function dt(e){return!_n(e,this.v)}let Oe=!1;function wr(){Oe=!0}let T=null;function xe(e){T=e}function mr(e,t=!1,n){T={p:T,i:!1,c:null,e:null,s:e,x:null,l:Oe&&!t?{s:null,u:null,$:[]}:null}}function Er(e){var t=T,n=t.e;if(n!==null){t.e=null;for(var r of n)kt(r)}return t.i=!0,T=t.p,{}}function be(){return!Oe||T!==null&&T.l===null}let Z=[];function ht(){var e=Z;Z=[],Xt(e)}function Qe(e){if(Z.length===0&&!he){var t=Z;queueMicrotask(()=>{t===Z&&ht()})}Z.push(e)}function vn(){for(;Z.length>0;)ht()}function dn(e){var t=d;if(t===null)return v.f|=B,e;if((t.f&z)===0&&(t.f&we)===0)throw e;Ne(e,t)}function Ne(e,t){for(;t!==null;){if((t.f&$t)!==0){if((t.f&z)===0)throw e;try{t.b.error(e);return}catch(n){e=n}}t=t.parent}throw e}const hn=-7169;function w(e,t){e.f=e.f&hn|t}function Ue(e){(e.f&O)!==0||e.deps===null?w(e,m):w(e,F)}function pt(e){if(e!==null)for(const t of e)(t.f&g)===0||(t.f&ne)===0||(t.f^=ne,pt(t.deps))}function pn(e,t,n){(e.f&A)!==0?t.add(e):(e.f&F)!==0&&n.add(e),pt(e.deps),w(e,m)}const Ae=new Set;let p=null,et=null,I=null,S=[],ke=null,Me=!1,he=!1;class ce{current=new Map;previous=new Map;#r=new Set;#s=new Set;#n=0;#i=0;#l=null;#a=new Set;#t=new Set;#e=new Map;is_fork=!1;#f=!1;#o(){return this.is_fork||this.#i>0}skip_effect(t){this.#e.has(t)||this.#e.set(t,{d:[],m:[]})}unskip_effect(t){var n=this.#e.get(t);if(n){this.#e.delete(t);for(var r of n.d)w(r,A),Y(r);for(r of n.m)w(r,F),Y(r)}}process(t){S=[],this.apply();var n=[],r=[];for(const s of t)this.#u(s,n,r);if(this.#o()){this.#c(r),this.#c(n);for(const[s,i]of this.#e)Et(s,i)}else{for(const s of this.#r)s();this.#r.clear(),this.#n===0&&this.#_(),et=this,p=null,tt(r),tt(n),this.#a.clear(),this.#t.clear(),et=null,this.#l?.resolve()}I=null}#u(t,n,r){t.f^=m;for(var s=t.first;s!==null;){var i=s.f,l=(i&(L|fe))!==0,f=l&&(i&m)!==0,a=f||(i&M)!==0||this.#e.has(s);if(!a&&s.fn!==null){l?s.f^=m:(i&we)!==0?n.push(s):Te(s)&&((i&q)!==0&&this.#t.add(s),ue(s));var o=s.first;if(o!==null){s=o;continue}}for(;s!==null;){var c=s.next;if(c!==null){s=c;break}s=s.parent}}}#c(t){for(var n=0;n0){if(yt(),p!==null&&p!==this)return}else this.#n===0&&this.process([]);this.deactivate()}discard(){for(const t of this.#s)t(this);this.#s.clear()}#_(){if(Ae.size>1){this.previous.clear();var t=I,n=!0;for(const s of Ae){if(s===this){n=!1;continue}const i=[];for(const[f,a]of this.current){if(s.current.has(f))if(n&&a!==s.current.get(f))s.current.set(f,a);else continue;i.push(f)}if(i.length===0)continue;const l=[...s.current.keys()].filter(f=>!this.current.has(f));if(l.length>0){var r=S;S=[];const f=new Set,a=new Map;for(const o of i)wt(o,l,f,a);if(S.length>0){p=s,s.apply();for(const o of S)s.#u(o,[],[]);s.deactivate()}S=r}}p=null,I=t}this.#e.clear(),Ae.delete(this)}increment(t){this.#n+=1,t&&(this.#i+=1)}decrement(t){this.#n-=1,t&&(this.#i-=1),!this.#f&&(this.#f=!0,Qe(()=>{this.#f=!1,this.#o()?S.length>0&&this.flush():this.revive()}))}revive(){for(const t of this.#a)this.#t.delete(t),w(t,A),Y(t);for(const t of this.#t)w(t,F),Y(t);this.flush()}oncommit(t){this.#r.add(t)}ondiscard(t){this.#s.add(t)}settled(){return(this.#l??=lt()).promise}static ensure(){if(p===null){const t=p=new ce;Ae.add(p),he||Qe(()=>{p===t&&t.flush()})}return p}apply(){}}function yn(e){var t=he;he=!0;try{for(var n;;){if(vn(),S.length===0&&(p?.flush(),S.length===0))return ke=null,n;yt()}}finally{he=t}}function yt(){Me=!0;var e=null;try{for(var t=0;S.length>0;){var n=ce.ensure();if(t++>1e3){var r,s;wn()}n.process(S),G.clear()}}finally{S=[],Me=!1,ke=null}}function wn(){try{en()}catch(e){Ne(e,ke)}}let H=null;function tt(e){var t=e.length;if(t!==0){for(var n=0;n0)){G.clear();for(const s of H){if((s.f&(U|M))!==0)continue;const i=[s];let l=s.parent;for(;l!==null;)H.has(l)&&(H.delete(l),i.push(l)),l=l.parent;for(let f=i.length-1;f>=0;f--){const a=i[f];(a.f&(U|M))===0&&ue(a)}}H.clear()}}H=null}}function wt(e,t,n,r){if(!n.has(e)&&(n.add(e),e.reactions!==null))for(const s of e.reactions){const i=s.f;(i&g)!==0?wt(s,t,n,r):(i&(Ye|q))!==0&&(i&A)===0&&mt(s,t,r)&&(w(s,A),Y(s))}}function mt(e,t,n){const r=n.get(e);if(r!==void 0)return r;if(e.deps!==null)for(const s of e.deps){if(le.call(t,s))return!0;if((s.f&g)!==0&&mt(s,t,n))return n.set(s,!0),!0}return n.set(e,!1),!1}function Y(e){var t=ke=e,n=t.b;if(n?.is_pending&&(e.f&(we|me|ot))!==0&&(e.f&z)===0){n.defer_effect(e);return}for(;t.parent!==null;){t=t.parent;var r=t.f;if(Me&&t===d&&(r&q)!==0&&(r&ut)===0&&(r&z)!==0)return;if((r&(fe|L))!==0){if((r&m)===0)return;t.f^=m}}S.push(t)}function Et(e,t){if(!((e.f&L)!==0&&(e.f&m)!==0)){(e.f&A)!==0?t.d.push(e):(e.f&F)!==0&&t.m.push(e),w(e,m);for(var n=e.first;n!==null;)Et(n,t),n=n.next}}function mn(e,t,n,r){const s=be()?Be:Tn;var i=e.filter(u=>!u.settled);if(n.length===0&&i.length===0){r(t.map(s));return}var l=d,f=En(),a=i.length===1?i[0].promise:i.length>1?Promise.all(i.map(u=>u.promise)):null;function o(u){f();try{r(u)}catch(_){(l.f&U)===0&&Ne(_,l)}Fe()}if(n.length===0){a.then(()=>o(t.map(s)));return}function c(){f(),Promise.all(n.map(u=>bn(u))).then(u=>o([...t.map(s),...u])).catch(u=>Ne(u,l))}a?a.then(c):c()}function En(){var e=d,t=v,n=T,r=p;return function(i=!0){oe(e),K(t),xe(n),i&&r?.activate()}}function Fe(e=!0){oe(null),K(null),xe(null),e&&p?.deactivate()}function gn(){var e=d.b,t=p,n=e.is_rendered();return e.update_pending_count(1),t.increment(n),()=>{e.update_pending_count(-1),t.decrement(n)}}function Be(e){var t=g|A,n=v!==null&&(v.f&g)!==0?v:null;return d!==null&&(d.f|=Ee),{ctx:T,deps:null,effects:null,equals:vt,f:t,fn:e,reactions:null,rv:0,v:E,wv:0,parent:n??d,ac:null}}function bn(e,t,n){d===null&&Wt();var s=void 0,i=ze(E),l=!v,f=new Map;return In(()=>{var a=lt();s=a.promise;try{Promise.resolve(e()).then(a.resolve,a.reject).finally(Fe)}catch(_){a.reject(_),Fe()}var o=p;if(l){var c=gn();f.get(o)?.reject(W),f.delete(o),f.set(o,a)}const u=(_,b=void 0)=>{if(o.activate(),b)b!==W&&(i.f|=B,je(i,b));else{(i.f&B)!==0&&(i.f^=B),je(i,_);for(const[h,D]of f){if(f.delete(h),h===o)break;D.reject(W)}}c&&c()};a.promise.then(u,_=>u(null,_||"unknown"))}),Dn(()=>{for(const a of f.values())a.reject(W)}),new Promise(a=>{function o(c){function u(){c===s?a(i):o(s)}c.then(u,u)}o(s)})}function gr(e){const t=Be(e);return Mt(t),t}function Tn(e){const t=Be(e);return t.equals=dt,t}function An(e){var t=e.effects;if(t!==null){e.effects=null;for(var n=0;n0&&!Tt&&xn()}return t}function xn(){Tt=!1;for(const e of Le)(e.f&m)!==0&&w(e,F),Te(e)&&ue(e);Le.clear()}function Pe(e){$(e,e.v+1)}function At(e,t){var n=e.reactions;if(n!==null)for(var r=be(),s=n.length,i=0;i{if(ee===i)return f();var a=v,o=ee;K(null),at(i);var c=f();return K(a),at(o),c};return r&&n.set("length",V(e.length)),new Proxy(e,{defineProperty(f,a,o){(!("value"in o)||o.configurable===!1||o.enumerable===!1||o.writable===!1)&&tn();var c=n.get(a);return c===void 0?l(()=>{var u=V(o.value);return n.set(a,u),u}):$(c,o.value,!0),!0},deleteProperty(f,a){var o=n.get(a);if(o===void 0){if(a in f){const c=l(()=>V(E));n.set(a,c),Pe(s)}}else $(o,E),Pe(s);return!0},get(f,a,o){if(a===Q)return e;var c=n.get(a),u=a in f;if(c===void 0&&(!u||de(f,a)?.writable)&&(c=l(()=>{var b=_e(u?f[a]:E),h=V(b);return h}),n.set(a,c)),c!==void 0){var _=ve(c);return _===E?void 0:_}return Reflect.get(f,a,o)},getOwnPropertyDescriptor(f,a){var o=Reflect.getOwnPropertyDescriptor(f,a);if(o&&"value"in o){var c=n.get(a);c&&(o.value=ve(c))}else if(o===void 0){var u=n.get(a),_=u?.v;if(u!==void 0&&_!==E)return{enumerable:!0,configurable:!0,value:_,writable:!0}}return o},has(f,a){if(a===Q)return!0;var o=n.get(a),c=o!==void 0&&o.v!==E||Reflect.has(f,a);if(o!==void 0||d!==null&&(!c||de(f,a)?.writable)){o===void 0&&(o=l(()=>{var _=c?_e(f[a]):E,b=V(_);return b}),n.set(a,o));var u=ve(o);if(u===E)return!1}return c},set(f,a,o,c){var u=n.get(a),_=a in f;if(r&&a==="length")for(var b=o;bV(E)),n.set(b+"",h))}if(u===void 0)(!_||de(f,a)?.writable)&&(u=l(()=>V(void 0)),$(u,_e(o)),n.set(a,u));else{_=u.v!==E;var D=l(()=>_e(o));$(u,D)}var $e=Reflect.getOwnPropertyDescriptor(f,a);if($e?.set&&$e.set.call(c,o),!_){if(r&&typeof a=="string"){var We=n.get("length"),Ie=Number(a);Number.isInteger(Ie)&&Ie>=We.v&&$(We,Ie+1)}Pe(s)}return!0},ownKeys(f){ve(s);var a=Reflect.ownKeys(f).filter(u=>{var _=n.get(u);return _===void 0||_.v!==E});for(var[o,c]of n)c.v!==E&&!(o in f)&&a.push(o);return a},setPrototypeOf(){nn()}})}function nt(e){try{if(e!==null&&typeof e=="object"&&Q in e)return e[Q]}catch{}return e}function Tr(e,t){return Object.is(nt(e),nt(t))}var rt,St,Rt,xt;function Ar(){if(rt===void 0){rt=window,St=/Firefox/.test(navigator.userAgent);var e=Element.prototype,t=Node.prototype,n=Text.prototype;Rt=de(t,"firstChild").get,xt=de(t,"nextSibling").get,Ze(e)&&(e.__click=void 0,e.__className=void 0,e.__attributes=null,e.__style=void 0,e.__e=void 0),Ze(n)&&(n.__t=void 0)}}function se(e=""){return document.createTextNode(e)}function pe(e){return Rt.call(e)}function X(e){return xt.call(e)}function Sr(e,t){if(!C)return pe(e);var n=pe(y);if(n===null)n=y.appendChild(se());else if(t&&n.nodeType!==ge){var r=se();return n?.before(r),re(r),r}return t&&De(n),re(n),n}function Rr(e,t=!1){if(!C){var n=pe(e);return n instanceof Comment&&n.data===""?X(n):n}if(t){if(y?.nodeType!==ge){var r=se();return y?.before(r),re(r),r}De(y)}return y}function xr(e,t=1,n=!1){let r=C?y:e;for(var s;t--;)s=r,r=X(r);if(!C)return r;if(n){if(r?.nodeType!==ge){var i=se();return r===null?s?.after(i):r.before(i),re(i),i}De(r)}return re(r),r}function Nr(e){e.textContent=""}function Or(){return!1}function Nn(e,t,n){return document.createElementNS(un,e,void 0)}function De(e){if(e.nodeValue.length<65536)return;let t=e.nextSibling;for(;t!==null&&t.nodeType===ge;)t.remove(),e.nodeValue+=t.nodeValue,t=e.nextSibling}let st=!1;function On(){st||(st=!0,document.addEventListener("reset",e=>{Promise.resolve().then(()=>{if(!e.defaultPrevented)for(const t of e.target.elements)t.__on_r?.()})},{capture:!0}))}function Ke(e){var t=v,n=d;K(null),oe(null);try{return e()}finally{K(t),oe(n)}}function kr(e,t,n,r=n){e.addEventListener(t,()=>Ke(n));const s=e.__on_r;s?e.__on_r=()=>{s(),r(!0)}:e.__on_r=()=>r(!0),On()}function Nt(e){d===null&&(v===null&&Qt(),Jt()),ae&&Zt()}function kn(e,t){var n=t.last;n===null?t.last=t.first=e:(n.next=e,e.prev=n,t.last=e)}function j(e,t,n){var r=d;r!==null&&(r.f&M)!==0&&(e|=M);var s={ctx:T,deps:null,nodes:null,f:e|A|O,first:null,fn:t,last:null,next:null,parent:r,b:r&&r.b,prev:null,teardown:null,wv:0,ac:null};if(n)try{ue(s)}catch(f){throw ie(s),f}else t!==null&&Y(s);var i=s;if(n&&i.deps===null&&i.teardown===null&&i.nodes===null&&i.first===i.last&&(i.f&Ee)===0&&(i=i.first,(e&q)!==0&&(e&Re)!==0&&i!==null&&(i.f|=Re)),i!==null&&(i.parent=r,r!==null&&kn(i,r),v!==null&&(v.f&g)!==0&&(e&fe)===0)){var l=v;(l.effects??=[]).push(i)}return s}function Ot(){return v!==null&&!P}function Dn(e){const t=j(me,null,!1);return w(t,m),t.teardown=e,t}function Dr(e){Nt();var t=d.f,n=!v&&(t&L)!==0&&(t&z)===0;if(n){var r=T;(r.e??=[]).push(e)}else return kt(e)}function kt(e){return j(we|ct,e,!1)}function Ir(e){return Nt(),j(me|ct,e,!0)}function Pr(e){ce.ensure();const t=j(fe|Ee,e,!0);return(n={})=>new Promise(r=>{n.outro?Mn(t,()=>{ie(t),r(void 0)}):(ie(t),r(void 0))})}function Cr(e){return j(we,e,!1)}function In(e){return j(Ye|Ee,e,!0)}function Mr(e,t=0){return j(me|t,e,!0)}function Fr(e,t=[],n=[],r=[]){mn(r,t,n,s=>{j(me,()=>e(...s.map(ve)),!0)})}function Lr(e,t=0){var n=j(q|t,e,!0);return n}function jr(e){return j(L|Ee,e,!0)}function Dt(e){var t=e.teardown;if(t!==null){const n=ae,r=v;it(!0),K(null);try{t.call(null)}finally{it(n),K(r)}}}function Xe(e,t=!1){var n=e.first;for(e.first=e.last=null;n!==null;){const s=n.ac;s!==null&&Ke(()=>{s.abort(W)});var r=n.next;(n.f&fe)!==0?n.parent=null:ie(n,t),n=r}}function Pn(e){for(var t=e.first;t!==null;){var n=t.next;(t.f&L)===0&&ie(t),t=n}}function ie(e,t=!0){var n=!1;(t||(e.f&ut)!==0)&&e.nodes!==null&&e.nodes.end!==null&&(Cn(e.nodes.start,e.nodes.end),n=!0),Xe(e,t&&!n),ye(e,0),w(e,U);var r=e.nodes&&e.nodes.t;if(r!==null)for(const i of r)i.stop();Dt(e);var s=e.parent;s!==null&&s.first!==null&&It(e),e.next=e.prev=e.teardown=e.ctx=e.deps=e.fn=e.nodes=e.ac=null}function Cn(e,t){for(;e!==null;){var n=e===t?null:X(e);e.remove(),e=n}}function It(e){var t=e.parent,n=e.prev,r=e.next;n!==null&&(n.next=r),r!==null&&(r.prev=n),t!==null&&(t.first===e&&(t.first=r),t.last===e&&(t.last=n))}function Mn(e,t,n=!0){var r=[];Pt(e,r,!0);var s=()=>{n&&ie(e),t&&t()},i=r.length;if(i>0){var l=()=>--i||s();for(var f of r)f.out(l)}else s()}function Pt(e,t,n){if((e.f&M)===0){e.f^=M;var r=e.nodes&&e.nodes.t;if(r!==null)for(const f of r)(f.is_global||n)&&t.push(f);for(var s=e.first;s!==null;){var i=s.next,l=(s.f&Re)!==0||(s.f&L)!==0&&(e.f&q)!==0;Pt(s,t,l?n:!1),s=i}}}function Hr(e){Ct(e,!0)}function Ct(e,t){if((e.f&M)!==0){e.f^=M,(e.f&m)===0&&(w(e,A),Y(e));for(var n=e.first;n!==null;){var r=n.next,s=(n.f&Re)!==0||(n.f&L)!==0;Ct(n,s?t:!1),n=r}var i=e.nodes&&e.nodes.t;if(i!==null)for(const l of i)(l.is_global||t)&&l.in()}}function Yr(e,t){if(e.nodes)for(var n=e.nodes.start,r=e.nodes.end;n!==null;){var s=n===r?null:X(n);t.append(n),n=s}}let Se=!1,ae=!1;function it(e){ae=e}let v=null,P=!1;function K(e){v=e}let d=null;function oe(e){d=e}let k=null;function Mt(e){v!==null&&(k===null?k=[e]:k.push(e))}let R=null,x=0,N=null;function Fn(e){N=e}let Ft=1,J=0,ee=J;function at(e){ee=e}function Lt(){return++Ft}function Te(e){var t=e.f;if((t&A)!==0)return!0;if(t&g&&(e.f&=~ne),(t&F)!==0){for(var n=e.deps,r=n.length,s=0;se.wv)return!0}(t&O)!==0&&I===null&&w(e,m)}return!1}function jt(e,t,n=!0){var r=e.reactions;if(r!==null&&!(k!==null&&le.call(k,e)))for(var s=0;s{e.ac.abort(W)}),e.ac=null);try{e.f|=Ce;var c=e.fn,u=c();e.f|=z;var _=e.deps,b=p?.is_fork;if(R!==null){var h;if(b||ye(e,x),_!==null&&x>0)for(_.length=x+R.length,h=0;he});function Hn(e){return jn?.createHTML(e)??e}function Yn(e){var t=Nn("template");return t.innerHTML=Hn(e.replaceAll("","")),t.content}function te(e,t){var n=d;n.nodes===null&&(n.nodes={start:e,end:t,a:null,t:null})}function Gr(e,t){var n=(t&sn)!==0,r=(t&an)!==0,s,i=!e.startsWith("");return()=>{if(C)return te(y,null),y;s===void 0&&(s=Yn(i?e:""+e),n||(s=pe(s)));var l=r||St?document.importNode(s,!0):s.cloneNode(!0);if(n){var f=pe(l),a=l.lastChild;te(f,a)}else te(l,l);return l}}function zr(e=""){if(!C){var t=se(e+"");return te(t,t),t}var n=y;return n.nodeType!==ge?(n.before(n=se()),re(n)):De(n),te(n,n),n}function Kr(){if(C)return te(y,null),y;var e=document.createDocumentFragment(),t=document.createComment(""),n=se();return e.append(t,n),te(t,n),e}function Xr(e,t){if(C){var n=d;((n.f&z)===0||n.nodes.end===null)&&(n.nodes.end=y),cn();return}e!==null&&e.before(t)}export{br as $,et as A,qr as B,Ur as C,Mr as D,Re as E,C as F,se as G,nr as H,re as I,pe as J,cn as K,yr as L,ln as M,pr as N,vr as O,y as P,_t as Q,on as R,je as S,Gn as T,jr as U,Wn as V,Or as W,Tn as X,qn as Y,er as Z,sr as _,Xr as a,U as a$,ze as a0,tr as a1,Hr as a2,Mn as a3,M as a4,Qe as a5,L as a6,rr as a7,Nr as a8,ie as a9,A as aA,Y as aB,F as aC,pn as aD,oe as aE,K as aF,xe as aG,dn as aH,v as aI,Ne as aJ,Ee as aK,Qn as aL,_r as aM,Vn as aN,Ar as aO,fn as aP,qe as aQ,Zn as aR,Pr as aS,te as aT,Ve as aU,Q as aV,de as aW,Jn as aX,fr as aY,_e as aZ,ae as a_,X as aa,Yr as ab,un as ac,ft as ad,Bt as ae,$n as af,On as ag,Kn as ah,T as ai,Ir as aj,Xt as ak,Un as al,Br as am,Be as an,wr as ao,_n as ap,Oe as aq,yn as ar,Vr as as,Ot as at,Pe as au,d as av,$t as aw,ur as ax,ce as ay,w as az,Er as b,lr as b0,ar as b1,ir as b2,or as b3,zn as b4,Kt as b5,Kr as c,Gr as d,Sr as e,Rr as f,zr as g,Lr as h,$ as i,V as j,ve as k,gr as l,Bn as m,hr as n,kr as o,mr as p,Cr as q,dr as r,xr as s,Fr as t,Dr as u,Dn as v,Vt as w,cr as x,Tr as y,p as z}; diff --git a/.svelte-kit/output/client/_app/immutable/chunks/CAkKRSSs.js b/.svelte-kit/output/client/_app/immutable/chunks/CAkKRSSs.js deleted file mode 100644 index 17691ab..0000000 --- a/.svelte-kit/output/client/_app/immutable/chunks/CAkKRSSs.js +++ /dev/null @@ -1 +0,0 @@ -import{o as _,B as b,C as i,D as m,F as y,z as v,A as h}from"./BxEwC6Zc.js";function E(e,l,u=l){var f=new WeakSet;_(e,"input",async r=>{var a=r?e.defaultValue:e.value;if(a=o(e)?t(a):a,u(a),v!==null&&f.add(v),await b(),a!==(a=l())){var d=e.selectionStart,s=e.selectionEnd,n=e.value.length;if(e.value=a??"",s!==null){var c=e.value.length;d===s&&s===n&&c>n?(e.selectionStart=c,e.selectionEnd=c):(e.selectionStart=d,e.selectionEnd=Math.min(s,c))}}}),(y&&e.defaultValue!==e.value||i(l)==null&&e.value)&&(u(o(e)?t(e.value):e.value),v!==null&&f.add(v)),m(()=>{var r=l();if(e===document.activeElement){var a=h??v;if(f.has(a))return}o(e)&&r===t(e.value)||e.type==="date"&&!r&&!e.value||r!==e.value&&(e.value=r??"")})}function o(e){var l=e.type;return l==="number"||l==="range"}function t(e){return e===""?null:+e}export{E as b}; diff --git a/.svelte-kit/output/client/_app/immutable/chunks/CvGSsBh3.js b/.svelte-kit/output/client/_app/immutable/chunks/CvGSsBh3.js deleted file mode 100644 index 4c73729..0000000 --- a/.svelte-kit/output/client/_app/immutable/chunks/CvGSsBh3.js +++ /dev/null @@ -1 +0,0 @@ -import{u as a,ai as o,aq as s,C as n,B as l,ar as u,as as c}from"./BxEwC6Zc.js";import{h as r,m as i,u as f}from"./DoLu9QLy.js";function m(e){throw new Error("https://svelte.dev/e/lifecycle_outside_component")}function _(e){o===null&&m(),s&&o.l!==null?p(o).m.push(e):a(()=>{const t=n(e);if(typeof t=="function")return t})}function p(e){var t=e.l;return t.u??={a:[],b:[],m:[]}}const h=Object.freeze(Object.defineProperty({__proto__:null,flushSync:u,hydrate:r,mount:i,onMount:_,settled:c,tick:l,unmount:f,untrack:n},Symbol.toStringTag,{value:"Module"}));export{_ as o,h as s}; diff --git a/.svelte-kit/output/client/_app/immutable/chunks/Cy2QBcXt.js b/.svelte-kit/output/client/_app/immutable/chunks/Cy2QBcXt.js deleted file mode 100644 index 4b54476..0000000 --- a/.svelte-kit/output/client/_app/immutable/chunks/Cy2QBcXt.js +++ /dev/null @@ -1 +0,0 @@ -import{o as _,q as o,v as c,w as b,x as m,y as h,z as v,A as y}from"./BxEwC6Zc.js";function d(e,r,f=!1){if(e.multiple){if(r==null)return;if(!b(r))return m();for(var a of e.options)a.selected=r.includes(i(a));return}for(a of e.options){var t=i(a);if(h(t,r)){a.selected=!0;return}}(!f||r!==void 0)&&(e.selectedIndex=-1)}function q(e){var r=new MutationObserver(()=>{d(e,e.__value)});r.observe(e,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["value"]}),c(()=>{r.disconnect()})}function p(e,r,f=r){var a=new WeakSet,t=!0;_(e,"change",u=>{var l=u?"[selected]":":checked",n;if(e.multiple)n=[].map.call(e.querySelectorAll(l),i);else{var s=e.querySelector(l)??e.querySelector("option:not([disabled])");n=s&&i(s)}f(n),v!==null&&a.add(v)}),o(()=>{var u=r();if(e===document.activeElement){var l=y??v;if(a.has(l))return}if(d(e,u,t),t&&u===void 0){var n=e.querySelector(":checked");n!==null&&(u=i(n),f(u))}e.__value=u,t=!1}),q(e)}function i(e){return"__value"in e?e.__value:e.value}export{p as b,q as i,d as s}; diff --git a/.svelte-kit/output/client/_app/immutable/chunks/CyUoLS3q.js b/.svelte-kit/output/client/_app/immutable/chunks/CyUoLS3q.js deleted file mode 100644 index 80818c3..0000000 --- a/.svelte-kit/output/client/_app/immutable/chunks/CyUoLS3q.js +++ /dev/null @@ -1 +0,0 @@ -import{h as p,E as t}from"./BxEwC6Zc.js";import{B as c}from"./kALFGdUG.js";function E(r,s,...a){var e=new c(r);p(()=>{const n=s()??null;e.ensure(n,n&&(o=>n(o,...a)))},t)}export{E as s}; diff --git a/.svelte-kit/output/client/_app/immutable/chunks/D2SGgx9j.js b/.svelte-kit/output/client/_app/immutable/chunks/D2SGgx9j.js deleted file mode 100644 index ddb898d..0000000 --- a/.svelte-kit/output/client/_app/immutable/chunks/D2SGgx9j.js +++ /dev/null @@ -1 +0,0 @@ -import{p as r}from"./DAtZQVjv.js";import{s as t}from"./BkIq08el.js";const e={get data(){return r.data},get error(){return r.error},get status(){return r.status},get url(){return r.url}};t.updated.check;const o=e;export{o as p}; diff --git a/.svelte-kit/output/client/_app/immutable/chunks/DAtZQVjv.js b/.svelte-kit/output/client/_app/immutable/chunks/DAtZQVjv.js deleted file mode 100644 index 8e3bd4b..0000000 --- a/.svelte-kit/output/client/_app/immutable/chunks/DAtZQVjv.js +++ /dev/null @@ -1 +0,0 @@ -import{o as x}from"./CvGSsBh3.js";import{b5 as w,ap as q,j as u,k as f,i as d}from"./BxEwC6Zc.js";const p=[];function E(e,t=w){let r=null;const n=new Set;function s(a){if(q(e,a)&&(e=a,r)){const i=!p.length;for(const c of n)c[1](),p.push(c,e);if(i){for(let c=0;c{n.delete(c),n.size===0&&r&&(r(),r=null)}}return{set:s,update:l,subscribe:o}}new URL("sveltekit-internal://");function Q(e,t){return e==="/"||t==="ignore"?e:t==="never"?e.endsWith("/")?e.slice(0,-1):e:t==="always"&&!e.endsWith("/")?e+"/":e}function Z(e){return e.split("%25").map(decodeURI).join("%25")}function ee(e){for(const t in e)e[t]=decodeURIComponent(e[t]);return e}function te({href:e}){return e.split("#")[0]}function P(...e){let t=5381;for(const r of e)if(typeof r=="string"){let n=r.length;for(;n;)t=t*33^r.charCodeAt(--n)}else if(ArrayBuffer.isView(r)){const n=new Uint8Array(r.buffer,r.byteOffset,r.byteLength);let s=n.length;for(;s;)t=t*33^n[--s]}else throw new TypeError("value must be a string or TypedArray");return(t>>>0).toString(36)}new TextEncoder;const ne=new TextDecoder;function W(e){const t=atob(e),r=new Uint8Array(t.length);for(let n=0;n((e instanceof Request?e.method:t?.method||"GET")!=="GET"&&m.delete(k(e)),V(e,t));const m=new Map;function re(e,t){const r=k(e,t),n=document.querySelector(r);if(n?.textContent){n.remove();let{body:s,...l}=JSON.parse(n.textContent);const o=n.getAttribute("data-ttl");return o&&m.set(r,{body:s,init:l,ttl:1e3*Number(o)}),n.getAttribute("data-b64")!==null&&(s=W(s)),Promise.resolve(new Response(s,l))}return window.fetch(e,t)}function se(e,t,r){if(m.size>0){const n=k(e,r),s=m.get(n);if(s){if(performance.now(){const s=/^\[\.\.\.(\w+)(?:=(\w+))?\]$/.exec(n);if(s)return t.push({name:s[1],matcher:s[2],optional:!1,rest:!0,chained:!0}),"(?:/([^]*))?";const l=/^\[\[(\w+)(?:=(\w+))?\]\]$/.exec(n);if(l)return t.push({name:l[1],matcher:l[2],optional:!0,rest:!1,chained:!0}),"(?:/([^/]+))?";if(!n)return;const o=n.split(/\[(.+?)\](?!\])/);return"/"+o.map((i,c)=>{if(c%2){if(i.startsWith("x+"))return v(String.fromCharCode(parseInt(i.slice(2),16)));if(i.startsWith("u+"))return v(String.fromCharCode(...i.slice(2).split("-").map(C=>parseInt(C,16))));const h=z.exec(i),[,_,b,j,L]=h;return t.push({name:j,matcher:L,optional:!!_,rest:!!b,chained:b?c===1&&o[0]==="":!1}),b?"([^]*?)":_?"([^/]*)?":"([^/]+?)"}return v(i)}).join("")}).join("")}/?$`),params:t}}function G(e){return e!==""&&!/^\([^)]+\)$/.test(e)}function T(e){return e.slice(1).split("/").filter(G)}function oe(e,t,r){const n={},s=e.slice(1),l=s.filter(a=>a!==void 0);let o=0;for(let a=0;ah).join("/"),o=0),c===void 0)if(i.rest)c="";else continue;if(!i.matcher||r[i.matcher](c)){n[i.name]=c;const h=t[a+1],_=s[a+1];h&&!h.rest&&h.optional&&_&&i.chained&&(o=0),!h&&!_&&Object.keys(n).length===l.length&&(o=0);continue}if(i.optional&&i.chained){o++;continue}return}if(!o)return n}function v(e){return e.normalize().replace(/[[\]]/g,"\\$&").replace(/%/g,"%25").replace(/\//g,"%2[Ff]").replace(/\?/g,"%3[Ff]").replace(/#/g,"%23").replace(/[.*+?^${}()|\\]/g,"\\$&")}const Y=/\[(\[)?(\.\.\.)?(\w+?)(?:=(\w+))?\]\]?/g;function ie(e,t){const r=T(e),n=e!="/"&&e.endsWith("/");return"/"+r.map(s=>s.replace(Y,(l,o,a,i)=>{const c=t[i];if(!c){if(o||a&&c!==void 0)return"";throw new Error(`Missing parameter '${i}' in route ${e}`)}if(c.startsWith("/")||c.endsWith("/"))throw new Error(`Parameter '${i}' in route ${e} cannot start or end with a slash -- this would cause an invalid route like foo//bar`);return c})).filter(Boolean).join("/")+(n?"/":"")}const B=globalThis.__sveltekit_12t8tv8?.base??"",D=globalThis.__sveltekit_12t8tv8?.assets??B??"",H="1772254297287",ce="sveltekit:snapshot",le="sveltekit:scroll",ue="sveltekit:states",fe="sveltekit:pageurl",de="sveltekit:history",he="sveltekit:navigation",A={tap:1,hover:2,viewport:3,eager:4,off:-1,false:-1},U=location.origin;function pe(e){if(e instanceof URL)return e;let t=document.baseURI;if(!t){const r=document.getElementsByTagName("base");t=r.length?r[0].href:document.URL}return new URL(e,t)}function ge(){return{x:pageXOffset,y:pageYOffset}}function g(e,t){return e.getAttribute(`data-sveltekit-${t}`)}const R={...A,"":A.hover};function I(e){let t=e.assignedSlot??e.parentNode;return t?.nodeType===11&&(t=t.host),t}function _e(e,t){for(;e&&e!==t;){if(e.nodeName.toUpperCase()==="A"&&e.hasAttribute("href"))return e;e=I(e)}}function me(e,t,r){let n;try{if(n=new URL(e instanceof SVGAElement?e.href.baseVal:e.href,document.baseURI),r&&n.hash.match(/^#[^/]/)){const a=location.hash.split("#")[1]||"/";n.hash=`#${a}${n.hash}`}}catch{}const s=e instanceof SVGAElement?e.target.baseVal:e.target,l=!n||!!s||K(n,t,r)||(e.getAttribute("rel")||"").split(/\s+/).includes("external"),o=n?.origin===U&&e.hasAttribute("download");return{url:n,external:l,target:s,download:o}}function be(e){let t=null,r=null,n=null,s=null,l=null,o=null,a=e;for(;a&&a!==document.documentElement;)n===null&&(n=g(a,"preload-code")),s===null&&(s=g(a,"preload-data")),t===null&&(t=g(a,"keepfocus")),r===null&&(r=g(a,"noscroll")),l===null&&(l=g(a,"reload")),o===null&&(o=g(a,"replacestate")),a=I(a);function i(c){switch(c){case"":case"true":return!0;case"off":case"false":return!1;default:return}}return{preload_code:R[n??"off"],preload_data:R[s??"off"],keepfocus:i(t),noscroll:i(r),reload:i(l),replace_state:i(o)}}function we(e){const t=E(e);let r=!0;function n(){r=!0,t.update(o=>o)}function s(o){r=!1,t.set(o)}function l(o){let a;return t.subscribe(i=>{(a===void 0||r&&i!==a)&&o(a=i)})}return{notify:n,set:s,subscribe:l}}const N={v:()=>{}};function ve(){const{set:e,subscribe:t}=E(!1);let r;async function n(){clearTimeout(r);try{const s=await fetch(`${D}/_app/version.json`,{headers:{pragma:"no-cache","cache-control":"no-cache"}});if(!s.ok)return!1;const o=(await s.json()).version!==H;return o&&(e(!0),N.v(),clearTimeout(r)),o}catch{return!1}}return{subscribe:t,check:n}}function K(e,t,r){return e.origin!==U||!e.pathname.startsWith(t)?!0:r?e.pathname!==location.pathname:!1}function ye(e){}const O=new Set(["load","prerender","csr","ssr","trailingSlash","config"]);[...O];const M=new Set([...O]);[...M];let S,$,y;const X=x.toString().includes("$$")||/function \w+\(\) \{\}/.test(x.toString());X?(S={data:{},form:null,error:null,params:{},route:{id:null},state:{},status:-1,url:new URL("https://example.com")},$={current:null},y={current:!1}):(S=new class{#e=u({});get data(){return f(this.#e)}set data(t){d(this.#e,t)}#t=u(null);get form(){return f(this.#t)}set form(t){d(this.#t,t)}#n=u(null);get error(){return f(this.#n)}set error(t){d(this.#n,t)}#r=u({});get params(){return f(this.#r)}set params(t){d(this.#r,t)}#s=u({id:null});get route(){return f(this.#s)}set route(t){d(this.#s,t)}#a=u({});get state(){return f(this.#a)}set state(t){d(this.#a,t)}#o=u(-1);get status(){return f(this.#o)}set status(t){d(this.#o,t)}#i=u(new URL("https://example.com"));get url(){return f(this.#i)}set url(t){d(this.#i,t)}},$=new class{#e=u(null);get current(){return f(this.#e)}set current(t){d(this.#e,t)}},y=new class{#e=u(!1);get current(){return f(this.#e)}set current(t){d(this.#e,t)}},N.v=()=>y.current=!0);function Ae(e){Object.assign(S,e)}export{we as A,ye as B,de as H,he as N,fe as P,ue as S,ae as a,B as b,ve as c,pe as d,oe as e,_e as f,me as g,be as h,K as i,te as j,ee as k,Q as l,A as m,$ as n,U as o,S as p,Z as q,ie as r,ge as s,ne as t,Ae as u,ce as v,se as w,re as x,le as y,E as z}; diff --git a/.svelte-kit/output/client/_app/immutable/chunks/DoLu9QLy.js b/.svelte-kit/output/client/_app/immutable/chunks/DoLu9QLy.js deleted file mode 100644 index 176717a..0000000 --- a/.svelte-kit/output/client/_app/immutable/chunks/DoLu9QLy.js +++ /dev/null @@ -1,2 +0,0 @@ -import{at as te,k as W,D as re,C as se,au as H,a5 as D,a0 as j,P as g,F as v,av as b,aw as L,h as ie,K as ae,M as ne,ax as V,U as p,G,ay as I,a3 as k,ab as fe,az as $,aA as oe,aB as q,aC as he,aD as le,aE as N,aF as A,aG as z,aH as de,aI as K,ai as Q,S as ce,a9 as Y,I as O,n as ue,N as _e,aJ as w,E as pe,aK as ge,aL as ve,aM as ye,aN as me,aO as x,J as be,Q as X,aP as Ee,aa as Te,aQ as M,O as R,aR as we,a8 as Re,aS as Se,Y as De,p as Ne,aT as Ae,R as Oe,aU as Fe,b as Ie}from"./BxEwC6Zc.js";function ke(t){let e=0,r=j(0),i;return()=>{te()&&(W(r),re(()=>(e===0&&(i=se(()=>t(()=>H(r)))),e+=1,()=>{D(()=>{e-=1,e===0&&(i?.(),i=void 0,H(r))})})))}}var Ye=pe|ge;function xe(t,e,r,i){new Me(t,e,r,i)}class Me{parent;is_pending=!1;transform_error;#t;#g=v?g:null;#i;#h;#e;#a=null;#r=null;#s=null;#n=null;#l=0;#o=0;#d=!1;#c=new Set;#u=new Set;#f=null;#m=ke(()=>(this.#f=j(this.#l),()=>{this.#f=null}));constructor(e,r,i,f){this.#t=e,this.#i=r,this.#h=s=>{var a=b;a.b=this,a.f|=L,i(s)},this.parent=b.b,this.transform_error=f??this.parent?.transform_error??(s=>s),this.#e=ie(()=>{if(v){const s=this.#g;ae();const a=s.data===ne;if(s.data.startsWith(V)){const n=JSON.parse(s.data.slice(V.length));this.#E(n)}else a?this.#T():this.#b()}else this.#v()},Ye),v&&(this.#t=g)}#b(){try{this.#a=p(()=>this.#h(this.#t))}catch(e){this.error(e)}}#E(e){const r=this.#i.failed;r&&(this.#s=p(()=>{r(this.#t,()=>e,()=>()=>{})}))}#T(){const e=this.#i.pending;e&&(this.is_pending=!0,this.#r=p(()=>e(this.#t)),D(()=>{var r=this.#n=document.createDocumentFragment(),i=G();r.append(i),this.#a=this.#p(()=>(I.ensure(),p(()=>this.#h(i)))),this.#o===0&&(this.#t.before(r),this.#n=null,k(this.#r,()=>{this.#r=null}),this.#_())}))}#v(){try{if(this.is_pending=this.has_pending_snippet(),this.#o=0,this.#l=0,this.#a=p(()=>{this.#h(this.#t)}),this.#o>0){var e=this.#n=document.createDocumentFragment();fe(this.#a,e);const r=this.#i.pending;this.#r=p(()=>r(this.#t))}else this.#_()}catch(r){this.error(r)}}#_(){this.is_pending=!1;for(const e of this.#c)$(e,oe),q(e);for(const e of this.#u)$(e,he),q(e);this.#c.clear(),this.#u.clear()}defer_effect(e){le(e,this.#c,this.#u)}is_rendered(){return!this.is_pending&&(!this.parent||this.parent.is_rendered())}has_pending_snippet(){return!!this.#i.pending}#p(e){var r=b,i=K,f=Q;N(this.#e),A(this.#e),z(this.#e.ctx);try{return e()}catch(s){return de(s),null}finally{N(r),A(i),z(f)}}#y(e){if(!this.has_pending_snippet()){this.parent&&this.parent.#y(e);return}this.#o+=e,this.#o===0&&(this.#_(),this.#r&&k(this.#r,()=>{this.#r=null}),this.#n&&(this.#t.before(this.#n),this.#n=null))}update_pending_count(e){this.#y(e),this.#l+=e,!(!this.#f||this.#d)&&(this.#d=!0,D(()=>{this.#d=!1,this.#f&&ce(this.#f,this.#l)}))}get_effect_pending(){return this.#m(),W(this.#f)}error(e){var r=this.#i.onerror;let i=this.#i.failed;if(!r&&!i)throw e;this.#a&&(Y(this.#a),this.#a=null),this.#r&&(Y(this.#r),this.#r=null),this.#s&&(Y(this.#s),this.#s=null),v&&(O(this.#g),ue(),O(_e()));var f=!1,s=!1;const a=()=>{if(f){ye();return}f=!0,s&&ve(),this.#s!==null&&k(this.#s,()=>{this.#s=null}),this.#p(()=>{I.ensure(),this.#v()})},c=n=>{try{s=!0,r?.(n,a),s=!1}catch(o){w(o,this.#e&&this.#e.parent)}i&&(this.#s=this.#p(()=>{I.ensure();try{return p(()=>{var o=b;o.b=this,o.f|=L,i(this.#t,()=>n,()=>a)})}catch(o){return w(o,this.#e.parent),null}}))};D(()=>{var n;try{n=this.transform_error(e)}catch(o){w(o,this.#e&&this.#e.parent);return}n!==null&&typeof n=="object"&&typeof n.then=="function"?n.then(c,o=>w(o,this.#e&&this.#e.parent)):c(n)})}}const Ce=["touchstart","touchmove"];function Pe(t){return Ce.includes(t)}const T=Symbol("events"),Z=new Set,C=new Set;function Le(t,e,r){(e[T]??={})[t]=r}function Ve(t){for(var e=0;e{throw u});throw _}}finally{t[T]=e,delete t.currentTarget,A(y),N(E)}}}function $e(t,e){var r=e==null?"":typeof e=="object"?`${e}`:e;r!==(t.__t??=t.nodeValue)&&(t.__t=r,t.nodeValue=`${r}`)}function Be(t,e){return ee(t,e)}function qe(t,e){x(),e.intro=e.intro??!1;const r=e.target,i=v,f=g;try{for(var s=be(r);s&&(s.nodeType!==X||s.data!==Ee);)s=Te(s);if(!s)throw M;R(!0),O(s);const a=ee(t,{...e,anchor:s});return R(!1),a}catch(a){if(a instanceof Error&&a.message.split(` -`).some(c=>c.startsWith("https://svelte.dev/e/")))throw a;return a!==M&&console.warn("Failed to hydrate: ",a),e.recover===!1&&we(),x(),Re(r),R(!1),Be(t,e)}finally{R(i),O(f)}}const S=new Map;function ee(t,{target:e,anchor:r,props:i={},events:f,context:s,intro:a=!0,transformError:c}){x();var n=void 0,o=Se(()=>{var y=r??e.appendChild(G());xe(y,{pending:()=>{}},l=>{Ne({});var h=Q;if(s&&(h.c=s),f&&(i.$$events=f),v&&Ae(l,null),n=t(l,i)||{},v&&(b.nodes.end=g,g===null||g.nodeType!==X||g.data!==Oe))throw Fe(),M;Ie()},c);var E=new Set,_=l=>{for(var h=0;h{for(var l of E)for(const u of[e,document]){var h=S.get(u),d=h.get(l);--d==0?(u.removeEventListener(l,U),h.delete(l),h.size===0&&S.delete(u)):h.set(l,d)}C.delete(_),y!==r&&y.parentNode?.removeChild(y)}});return P.set(n,o),n}let P=new WeakMap;function ze(t,e){const r=P.get(t);return r?(P.delete(t),r(e)):Promise.resolve()}export{Le as a,Ve as d,qe as h,Be as m,$e as s,ze as u}; diff --git a/.svelte-kit/output/client/_app/immutable/chunks/DsnmJJEf.js b/.svelte-kit/output/client/_app/immutable/chunks/DsnmJJEf.js deleted file mode 100644 index ca27dc7..0000000 --- a/.svelte-kit/output/client/_app/immutable/chunks/DsnmJJEf.js +++ /dev/null @@ -1 +0,0 @@ -typeof window<"u"&&((window.__svelte??={}).v??=new Set).add("5"); diff --git a/.svelte-kit/output/client/_app/immutable/chunks/TpZZa089.js b/.svelte-kit/output/client/_app/immutable/chunks/TpZZa089.js deleted file mode 100644 index b7981bb..0000000 --- a/.svelte-kit/output/client/_app/immutable/chunks/TpZZa089.js +++ /dev/null @@ -1 +0,0 @@ -import{ai as d,aj as g,u as c,C as m,ak as i,al as b,k as p,am as k,an as v,ao as h}from"./BxEwC6Zc.js";function x(n=!1){const a=d,e=a.l.u;if(!e)return;let f=()=>k(a.s);if(n){let t=0,s={};const _=v(()=>{let l=!1;const r=a.s;for(const o in r)r[o]!==s[o]&&(s[o]=r[o],l=!0);return l&&t++,t});f=()=>p(_)}e.b.length&&g(()=>{u(a,f),i(e.b)}),c(()=>{const t=m(()=>e.m.map(b));return()=>{for(const s of t)typeof s=="function"&&s()}}),e.a.length&&c(()=>{u(a,f),i(e.a)})}function u(n,a){if(n.l.s)for(const e of n.l.s)p(e);a()}h();export{x as i}; diff --git a/.svelte-kit/output/client/_app/immutable/chunks/kALFGdUG.js b/.svelte-kit/output/client/_app/immutable/chunks/kALFGdUG.js deleted file mode 100644 index 886d5c7..0000000 --- a/.svelte-kit/output/client/_app/immutable/chunks/kALFGdUG.js +++ /dev/null @@ -1 +0,0 @@ -import{z as n,a2 as u,a9 as o,a3 as m,G as d,U as l,F as p,P as _,ab as v,W as b}from"./BxEwC6Zc.js";class w{anchor;#t=new Map;#s=new Map;#e=new Map;#i=new Set;#a=!0;constructor(e,s=!0){this.anchor=e,this.#a=s}#f=()=>{var e=n;if(this.#t.has(e)){var s=this.#t.get(e),t=this.#s.get(s);if(t)u(t),this.#i.delete(s);else{var a=this.#e.get(s);a&&(this.#s.set(s,a.effect),this.#e.delete(s),a.fragment.lastChild.remove(),this.anchor.before(a.fragment),t=a.effect)}for(const[i,f]of this.#t){if(this.#t.delete(i),i===e)break;const h=this.#e.get(f);h&&(o(h.effect),this.#e.delete(f))}for(const[i,f]of this.#s){if(i===s||this.#i.has(i))continue;const h=()=>{if(Array.from(this.#t.values()).includes(i)){var c=document.createDocumentFragment();v(f,c),c.append(d()),this.#e.set(i,{effect:f,fragment:c})}else o(f);this.#i.delete(i),this.#s.delete(i)};this.#a||!t?(this.#i.add(i),m(f,h,!1)):h()}}};#h=e=>{this.#t.delete(e);const s=Array.from(this.#t.values());for(const[t,a]of this.#e)s.includes(t)||(o(a.effect),this.#e.delete(t))};ensure(e,s){var t=n,a=b();if(s&&!this.#s.has(e)&&!this.#e.has(e))if(a){var i=document.createDocumentFragment(),f=d();i.append(f),this.#e.set(e,{effect:l(()=>s(f)),fragment:i})}else this.#s.set(e,l(()=>s(this.anchor)));if(this.#t.set(t,e),a){for(const[h,r]of this.#s)h===e?t.unskip_effect(r):t.skip_effect(r);for(const[h,r]of this.#e)h===e?t.unskip_effect(r.effect):t.skip_effect(r.effect);t.oncommit(this.#f),t.ondiscard(this.#h)}else p&&(this.anchor=_),this.#f()}}export{w as B}; diff --git a/.svelte-kit/output/client/_app/immutable/entry/app.DL20j9gb.js b/.svelte-kit/output/client/_app/immutable/entry/app.DL20j9gb.js deleted file mode 100644 index 72ad082..0000000 --- a/.svelte-kit/output/client/_app/immutable/entry/app.DL20j9gb.js +++ /dev/null @@ -1,2 +0,0 @@ -const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["../nodes/0.9C686m9W.js","../chunks/DsnmJJEf.js","../chunks/BxEwC6Zc.js","../chunks/CyUoLS3q.js","../chunks/kALFGdUG.js","../nodes/1.RyK1bdTz.js","../chunks/TpZZa089.js","../chunks/DoLu9QLy.js","../chunks/BQKoxf2Q.js","../chunks/D2SGgx9j.js","../chunks/DAtZQVjv.js","../chunks/CvGSsBh3.js","../chunks/BkIq08el.js","../nodes/2.BsR2_q_w.js","../chunks/BLQQas77.js","../chunks/BnX5ZnVA.js","../chunks/BqOsL1Vv.js","../chunks/BAocuFgQ.js","../assets/2.Dv2no-8m.css","../nodes/3.CMuy9Bx3.js","../nodes/4.BdC-uDW-.js","../chunks/Cy2QBcXt.js","../nodes/5.CyqZcxti.js","../nodes/6.CEe0czaO.js","../chunks/CAkKRSSs.js","../nodes/7._nuD3LlN.js","../nodes/8.CkbqikZq.js","../nodes/9.BTBc_Eli.js","../nodes/10.BPlEN6_G.js","../nodes/11.DR1Vz7m0.js","../nodes/12.C9UZWAjJ.js","../nodes/13.CyZ4e6yK.js"])))=>i.map(i=>d[i]); -import{F as X,K as ot,h as ut,E as ct,L as _t,N as lt,I as dt,O as Z,aP as ft,P as mt,q as vt,D as ht,C as H,a5 as gt,aV as K,aW as Et,aX as Pt,aY as bt,k as f,aZ as yt,i as N,a_ as Rt,av as Ot,a$ as pt,b0 as At,aq as Tt,b1 as It,b2 as Lt,an as St,X as Dt,b3 as Vt,b4 as J,ar as wt,aN as xt,$ as Nt,p as jt,aj as kt,u as Ct,B as Bt,f as A,s as Mt,a as O,b as qt,j as U,c as I,e as Yt,r as Ut,d as Q,g as Ft,t as Wt,l as V}from"../chunks/BxEwC6Zc.js";import{h as Xt,m as Zt,u as zt,s as Gt}from"../chunks/DoLu9QLy.js";import"../chunks/DsnmJJEf.js";import{o as Ht}from"../chunks/CvGSsBh3.js";import{i as j}from"../chunks/BQKoxf2Q.js";import{B as Kt}from"../chunks/kALFGdUG.js";function w(r,t,a){var u;X&&(u=mt,ot());var s=new Kt(r);ut(()=>{var e=t()??null;if(X){var n=_t(u),i=n===ft,P=e!==null;if(i!==P){var b=lt();dt(b),s.anchor=b,Z(!1),s.ensure(e,e&&(o=>a(o,e))),Z(!0);return}}s.ensure(e,e&&(o=>a(o,e)))},ct)}function z(r,t){return r===t||r?.[K]===t}function x(r={},t,a,u){return vt(()=>{var s,e;return ht(()=>{s=e,e=[],H(()=>{r!==a(...e)&&(t(r,...e),s&&z(a(...s),r)&&t(null,...s))})}),()=>{gt(()=>{e&&z(a(...e),r)&&t(null,...e)})}}),r}let k=!1;function Jt(r){var t=k;try{return k=!1,[r(),k]}finally{k=t}}function C(r,t,a,u){var s=!Tt||(a&It)!==0,e=(a&At)!==0,n=(a&Vt)!==0,i=u,P=!0,b=()=>(P&&(P=!1,i=n?H(u):u),i),o;if(e){var g=K in r||J in r;o=Et(r,t)?.set??(g&&t in r?c=>r[t]=c:void 0)}var m,v=!1;e?[m,v]=Jt(()=>r[t]):m=r[t],m===void 0&&u!==void 0&&(m=b(),o&&(s&&Pt(),o(m)));var d;if(s?d=()=>{var c=r[t];return c===void 0?b():(P=!0,c)}:d=()=>{var c=r[t];return c!==void 0&&(i=void 0),c===void 0?i:c},s&&(a&bt)===0)return d;if(o){var p=r.$$legacy;return(function(c,E){return arguments.length>0?((!s||!E||p||v)&&o(E?d():c),c):d()})}var _=!1,h=((a&Lt)!==0?St:Dt)(()=>(_=!1,d()));e&&f(h);var y=Ot;return(function(c,E){if(arguments.length>0){const R=E?f(h):s&&e?yt(c):c;return N(h,R),_=!0,i!==void 0&&(i=R),c}return Rt&&_||(y.f&pt)!==0?h.v:f(h)})}function Qt(r){return class extends $t{constructor(t){super({component:r,...t})}}}class $t{#e;#t;constructor(t){var a=new Map,u=(e,n)=>{var i=Nt(n,!1,!1);return a.set(e,i),i};const s=new Proxy({...t.props||{},$$events:{}},{get(e,n){return f(a.get(n)??u(n,Reflect.get(e,n)))},has(e,n){return n===J?!0:(f(a.get(n)??u(n,Reflect.get(e,n))),Reflect.has(e,n))},set(e,n,i){return N(a.get(n)??u(n,i),i),Reflect.set(e,n,i)}});this.#t=(t.hydrate?Xt:Zt)(t.component,{target:t.target,anchor:t.anchor,props:s,context:t.context,intro:t.intro??!1,recover:t.recover,transformError:t.transformError}),(!t?.props?.$$host||t.sync===!1)&&wt(),this.#e=s.$$events;for(const e of Object.keys(this.#t))e==="$set"||e==="$destroy"||e==="$on"||xt(this,e,{get(){return this.#t[e]},set(n){this.#t[e]=n},enumerable:!0});this.#t.$set=e=>{Object.assign(s,e)},this.#t.$destroy=()=>{zt(this.#t)}}$set(t){this.#t.$set(t)}$on(t,a){this.#e[t]=this.#e[t]||[];const u=(...s)=>a.call(this,...s);return this.#e[t].push(u),()=>{this.#e[t]=this.#e[t].filter(s=>s!==u)}}$destroy(){this.#t.$destroy()}}const te="modulepreload",ee=function(r,t){return new URL(r,t).href},G={},l=function(t,a,u){let s=Promise.resolve();if(a&&a.length>0){let b=function(o){return Promise.all(o.map(g=>Promise.resolve(g).then(m=>({status:"fulfilled",value:m}),m=>({status:"rejected",reason:m}))))};const n=document.getElementsByTagName("link"),i=document.querySelector("meta[property=csp-nonce]"),P=i?.nonce||i?.getAttribute("nonce");s=b(a.map(o=>{if(o=ee(o,u),o in G)return;G[o]=!0;const g=o.endsWith(".css"),m=g?'[rel="stylesheet"]':"";if(u)for(let d=n.length-1;d>=0;d--){const p=n[d];if(p.href===o&&(!g||p.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${o}"]${m}`))return;const v=document.createElement("link");if(v.rel=g?"stylesheet":te,g||(v.as="script"),v.crossOrigin="",v.href=o,P&&v.setAttribute("nonce",P),document.head.appendChild(v),g)return new Promise((d,p)=>{v.addEventListener("load",d),v.addEventListener("error",()=>p(new Error(`Unable to preload CSS for ${o}`)))})}))}function e(n){const i=new Event("vite:preloadError",{cancelable:!0});if(i.payload=n,window.dispatchEvent(i),!i.defaultPrevented)throw n}return s.then(n=>{for(const i of n||[])i.status==="rejected"&&e(i.reason);return t().catch(e)})},me={};var re=Q('
'),ae=Q(" ",1);function ne(r,t){jt(t,!0);let a=C(t,"components",23,()=>[]),u=C(t,"data_0",3,null),s=C(t,"data_1",3,null),e=C(t,"data_2",3,null);kt(()=>t.stores.page.set(t.page)),Ct(()=>{t.stores,t.page,t.constructors,a(),t.form,u(),s(),e(),t.stores.page.notify()});let n=U(!1),i=U(!1),P=U(null);Ht(()=>{const _=t.stores.page.subscribe(()=>{f(n)&&(N(i,!0),Bt().then(()=>{N(P,document.title||"untitled page",!0)}))});return N(n,!0),_});const b=V(()=>t.constructors[2]);var o=ae(),g=A(o);{var m=_=>{const h=V(()=>t.constructors[0]);var y=I(),c=A(y);w(c,()=>f(h),(E,R)=>{x(R(E,{get data(){return u()},get form(){return t.form},get params(){return t.page.params},children:(L,ie)=>{var F=I(),tt=A(F);{var et=T=>{const B=V(()=>t.constructors[1]);var S=I(),M=A(S);w(M,()=>f(B),(q,Y)=>{x(Y(q,{get data(){return s()},get form(){return t.form},get params(){return t.page.params},children:(D,oe)=>{var W=I(),at=A(W);w(at,()=>f(b),(nt,st)=>{x(st(nt,{get data(){return e()},get form(){return t.form},get params(){return t.page.params}}),it=>a()[2]=it,()=>a()?.[2])}),O(D,W)},$$slots:{default:!0}}),D=>a()[1]=D,()=>a()?.[1])}),O(T,S)},rt=T=>{const B=V(()=>t.constructors[1]);var S=I(),M=A(S);w(M,()=>f(B),(q,Y)=>{x(Y(q,{get data(){return s()},get form(){return t.form},get params(){return t.page.params}}),D=>a()[1]=D,()=>a()?.[1])}),O(T,S)};j(tt,T=>{t.constructors[2]?T(et):T(rt,!1)})}O(L,F)},$$slots:{default:!0}}),L=>a()[0]=L,()=>a()?.[0])}),O(_,y)},v=_=>{const h=V(()=>t.constructors[0]);var y=I(),c=A(y);w(c,()=>f(h),(E,R)=>{x(R(E,{get data(){return u()},get form(){return t.form},get params(){return t.page.params}}),L=>a()[0]=L,()=>a()?.[0])}),O(_,y)};j(g,_=>{t.constructors[1]?_(m):_(v,!1)})}var d=Mt(g,2);{var p=_=>{var h=re(),y=Yt(h);{var c=E=>{var R=Ft();Wt(()=>Gt(R,f(P))),O(E,R)};j(y,E=>{f(i)&&E(c)})}Ut(h),O(_,h)};j(d,_=>{f(n)&&_(p)})}O(r,o),qt()}const ve=Qt(ne),he=[()=>l(()=>import("../nodes/0.9C686m9W.js"),__vite__mapDeps([0,1,2,3,4]),import.meta.url),()=>l(()=>import("../nodes/1.RyK1bdTz.js"),__vite__mapDeps([5,1,6,2,7,8,4,9,10,11,12]),import.meta.url),()=>l(()=>import("../nodes/2.BsR2_q_w.js"),__vite__mapDeps([13,1,2,3,4,8,7,14,15,16,9,10,11,12,17,18]),import.meta.url),()=>l(()=>import("../nodes/3.CMuy9Bx3.js"),__vite__mapDeps([19,1,2,7,8,4,14,15,16]),import.meta.url),()=>l(()=>import("../nodes/4.BdC-uDW-.js"),__vite__mapDeps([20,1,2,7,8,4,14,17,12,11,10,15,16,21]),import.meta.url),()=>l(()=>import("../nodes/5.CyqZcxti.js"),__vite__mapDeps([22,1,2,7,8,4,14,17,12,11,10,15]),import.meta.url),()=>l(()=>import("../nodes/6.CEe0czaO.js"),__vite__mapDeps([23,1,2,7,8,4,14,17,12,11,10,15,16,24,21]),import.meta.url),()=>l(()=>import("../nodes/7._nuD3LlN.js"),__vite__mapDeps([25,1,2,7,8,4,14,17,12,11,10,15,16]),import.meta.url),()=>l(()=>import("../nodes/8.CkbqikZq.js"),__vite__mapDeps([26,1,2,7,8,4,14,17,12,11,10,15,16]),import.meta.url),()=>l(()=>import("../nodes/9.BTBc_Eli.js"),__vite__mapDeps([27,1,2,7,8,4,17,12,11,10,15,16]),import.meta.url),()=>l(()=>import("../nodes/10.BPlEN6_G.js"),__vite__mapDeps([28,1,2,7,8,4,14,17,12,11,10,15,16,24]),import.meta.url),()=>l(()=>import("../nodes/11.DR1Vz7m0.js"),__vite__mapDeps([29,1,6,2,15,10,11,7]),import.meta.url),()=>l(()=>import("../nodes/12.C9UZWAjJ.js"),__vite__mapDeps([30,1,2,7,17,12,11,10]),import.meta.url),()=>l(()=>import("../nodes/13.CyZ4e6yK.js"),__vite__mapDeps([31,1,2,7,17,12,11,10]),import.meta.url),()=>l(()=>import("../chunks/BQKoxf2Q.js").then(r=>r._),__vite__mapDeps([8,2,4]),import.meta.url)],ge=[2],Ee={"/(app)":[-4,[2]],"/(app)/admin":[-5,[2]],"/demo":[11],"/demo/better-auth":[-13],"/demo/better-auth/login":[-14],"/login":[-15],"/(app)/mappools":[-6,[2]],"/(app)/mappools/[id]":[-7,[2]],"/(app)/matches":[-8,[2]],"/(app)/matches/[id]":[-9,[2]],"/(app)/settings":[-10,[2]],"/(app)/teams":[-11,[2]]},$={handleError:(({error:r})=>{console.error(r)}),reroute:(()=>{}),transport:{}},se=Object.fromEntries(Object.entries($.transport).map(([r,t])=>[r,t.decode])),Pe=Object.fromEntries(Object.entries($.transport).map(([r,t])=>[r,t.encode])),be=!1,ye=(r,t)=>se[r](t);export{ye as decode,se as decoders,Ee as dictionary,Pe as encoders,be as hash,$ as hooks,me as matchers,he as nodes,ve as root,ge as server_loads}; diff --git a/.svelte-kit/output/client/_app/immutable/entry/start.Df1GVxyt.js b/.svelte-kit/output/client/_app/immutable/entry/start.Df1GVxyt.js deleted file mode 100644 index 93acd60..0000000 --- a/.svelte-kit/output/client/_app/immutable/entry/start.Df1GVxyt.js +++ /dev/null @@ -1 +0,0 @@ -import{c as s}from"../chunks/BkIq08el.js";import{B as t}from"../chunks/DAtZQVjv.js";export{t as load_css,s as start}; diff --git a/.svelte-kit/output/client/_app/immutable/nodes/0.9C686m9W.js b/.svelte-kit/output/client/_app/immutable/nodes/0.9C686m9W.js deleted file mode 100644 index 0e2b0f5..0000000 --- a/.svelte-kit/output/client/_app/immutable/nodes/0.9C686m9W.js +++ /dev/null @@ -1 +0,0 @@ -import"../chunks/DsnmJJEf.js";import{c as n,f as m,a as p}from"../chunks/BxEwC6Zc.js";import{s as e}from"../chunks/CyUoLS3q.js";function f(a,r){var o=n(),t=m(o);e(t,()=>r.children),p(a,o)}export{f as component}; diff --git a/.svelte-kit/output/client/_app/immutable/nodes/1.RyK1bdTz.js b/.svelte-kit/output/client/_app/immutable/nodes/1.RyK1bdTz.js deleted file mode 100644 index f7b0d81..0000000 --- a/.svelte-kit/output/client/_app/immutable/nodes/1.RyK1bdTz.js +++ /dev/null @@ -1 +0,0 @@ -import"../chunks/DsnmJJEf.js";import{i as w}from"../chunks/TpZZa089.js";import{p as A,t as j,a,b as B,d as D,e as s,r,s as x,n as N,g as i}from"../chunks/BxEwC6Zc.js";import{s as f}from"../chunks/DoLu9QLy.js";import{i as P}from"../chunks/BQKoxf2Q.js";import{p as o}from"../chunks/D2SGgx9j.js";var S=D('');function H(l,d){A(d,!1),w();var n=S(),m=s(n),c=s(m),u=s(c,!0);r(c);var p=x(c,2),h=s(p);{var g=t=>{var e=i("Page not found");a(t,e)},_=t=>{var e=i("Access denied");a(t,e)},b=t=>{var e=i("Not logged in");a(t,e)},y=t=>{var e=i("Something went wrong");a(t,e)};P(h,t=>{o.status===404?t(g):o.status===403?t(_,1):o.status===401?t(b,2):t(y,!1)})}r(p);var v=x(p,2),k=s(v,!0);r(v),N(2),r(m),r(n),j(()=>{f(u,o.status),f(k,o.error?.message??"An unexpected error occurred.")}),a(l,n),B()}export{H as component}; diff --git a/.svelte-kit/output/client/_app/immutable/nodes/10.BPlEN6_G.js b/.svelte-kit/output/client/_app/immutable/nodes/10.BPlEN6_G.js deleted file mode 100644 index 6e9e279..0000000 --- a/.svelte-kit/output/client/_app/immutable/nodes/10.BPlEN6_G.js +++ /dev/null @@ -1 +0,0 @@ -import"../chunks/DsnmJJEf.js";import{p as Ge,t as m,a as d,b as He,i as h,k as e,d as n,j as F,s as o,e as r,r as t,l as G,n as Je,c as Ke,f as Le}from"../chunks/BxEwC6Zc.js";import{d as Qe,a as H,s as b}from"../chunks/DoLu9QLy.js";import{i as l}from"../chunks/BQKoxf2Q.js";import{e as ce,i as le}from"../chunks/BLQQas77.js";import{a as W,e as X}from"../chunks/BAocuFgQ.js";import{s as me,r as Z,a as ue}from"../chunks/BnX5ZnVA.js";import{s as Re}from"../chunks/BqOsL1Vv.js";import{b as Se}from"../chunks/CAkKRSSs.js";import"../chunks/DAtZQVjv.js";var Ve=n('
'),We=n('

'),Xe=n(''),Ze=n('
'),$e=n('solo'),et=n(''),tt=n('
'),at=n('
'),rt=n('
'),st=n('
'),ot=n(''),dt=n('
'),nt=n('
'),it=n('
'),vt=n('

My Teams

'),ct=n(''),lt=n('
'),mt=n('

'),ut=n('

Other Teams

'),xt=n('

No teams yet. Your personal team is created when you sign in.

'),ft=n('

Teams

');function Ut(we,_){Ge(_,!0);let O=F(!1),J=F(null),K=F(null),$=F(""),L=F("");const xe=G(()=>_.data.teams.filter(s=>s.members.some(i=>i.userId===_.data.userId))),fe=G(()=>_.data.teams.filter(s=>!s.members.some(i=>i.userId===_.data.userId)));function ee(s){return s.ownerId===_.data.userId}var te=ft(),ae=r(te),re=r(ae),pe=o(r(re),2),Ie=r(pe);t(pe),t(re);var se=o(re,2),ke=r(se,!0);t(se),t(ae);var be=o(ae,2);{var Te=s=>{var i=Ve();W(i,(u,C)=>X?.(u,C),()=>()=>async({result:u,update:C})=>{u.type==="success"&&u.data?.success&&(h(O,!1),await C())}),d(s,i)};l(be,s=>{e(O)&&s(Te)})}var _e=o(be,2);{var Ue=s=>{var i=We(),u=r(i,!0);t(i),m(()=>b(u,e(L))),d(s,i)};l(_e,s=>{e(L)&&s(Ue)})}var ge=o(_e,2);{var Ce=s=>{var i=vt(),u=o(r(i),2);ce(u,21,()=>e(xe),le,(C,a)=>{var M=it(),j=r(M),Q=r(j);{var oe=v=>{var x=Xe();m(()=>me(x,"src",e(a).avatarUrl)),d(v,x)},R=v=>{var x=Ze(),Y=r(x,!0);t(x),m(V=>b(Y,V),[()=>e(a).name.charAt(0).toUpperCase()]),d(v,x)};l(Q,v=>{e(a).avatarUrl?v(oe):v(R,!1)})}var A=o(Q,2),E=r(A),P=r(E),de=r(P,!0);t(P);var k=o(P,2);{var T=v=>{var x=$e();d(v,x)};l(k,v=>{e(a).isPersonal&&v(T)})}t(E);var S=o(E,2),ne=r(S);t(S),t(A);var qe=o(A,2);t(j);var De=o(j,2);{var Pe=v=>{var x=nt(),Y=r(x);ce(Y,21,()=>e(a).members,le,(y,c)=>{var w=rt(),N=r(w);{var q=g=>{var I=et();m(()=>me(I,"src",e(c).user.image)),d(g,I)},U=g=>{var I=tt();d(g,I)};l(N,g=>{e(c).user?.image?g(q):g(U,!1)})}var f=o(N,2),z=r(f,!0);t(f);var D=o(f,2),ie=r(D,!0);t(D);var p=o(D,2);{var B=g=>{var I=at(),ye=r(I);Z(ye),Je(2),t(I),W(I,(ve,Fe)=>X?.(ve,Fe),()=>()=>async({update:ve})=>{await ve()}),m(()=>ue(ye,e(c).id)),d(g,I)},Be=G(()=>ee(e(a))&&e(c).userId!==_.data.userId);l(p,g=>{e(Be)&&g(B)})}t(w),m(()=>{b(z,e(c).user?.name??"Unknown"),b(ie,e(c).role)}),d(y,w)}),t(Y);var V=o(Y,2);{var Ne=y=>{var c=Ke(),w=Le(c);{var N=U=>{var f=st(),z=r(f);Z(z);var D=o(z,2);Z(D);var ie=o(D,4);t(f),W(f,(p,B)=>X?.(p,B),()=>()=>(h(L,""),async({result:p,update:B})=>{p.type==="success"&&p.data?.success?(h($,""),h(K,null),await B()):p.type==="success"&&p.data?.error&&h(L,p.data.error,!0)})),m(()=>ue(z,e(a).id)),Se(D,()=>e($),p=>h($,p)),H("click",ie,()=>h(K,null)),d(U,f)},q=U=>{var f=ot();H("click",f,()=>h(K,e(a).id,!0)),d(U,f)};l(w,U=>{e(K)===e(a).id?U(N):U(q,!1)})}d(y,c)},Oe=G(()=>ee(e(a))&&!e(a).isPersonal);l(V,y=>{e(Oe)&&y(Ne)})}var Ee=o(V,2);{var Ye=y=>{var c=dt(),w=r(c);Z(w);var N=o(w,2);t(c),W(c,q=>X?.(q)),m(()=>ue(w,e(a).id)),H("click",N,q=>{confirm(`Delete ${e(a).name}?`)||q.preventDefault()}),d(y,c)},ze=G(()=>ee(e(a))&&!e(a).isPersonal);l(Ee,y=>{e(ze)&&y(Ye)})}t(x),d(v,x)};l(De,v=>{e(J)===e(a).id&&v(Pe)})}t(M),m(()=>{b(de,e(a).name),b(ne,`${e(a).members.length??""} member${e(a).members.length!==1?"s":""}`),Re(qe,1,`text-sm text-text-secondary transition-transform ${e(J)===e(a).id?"rotate-90":""}`)}),H("click",j,()=>h(J,e(J)===e(a).id?null:e(a).id,!0)),d(C,M)}),t(u),t(i),d(s,i)};l(ge,s=>{e(xe).length>0&&s(Ce)})}var he=o(ge,2);{var Me=s=>{var i=ut(),u=o(r(i),2);ce(u,21,()=>e(fe),le,(C,a)=>{var M=mt(),j=r(M);{var Q=k=>{var T=ct();m(()=>me(T,"src",e(a).avatarUrl)),d(k,T)},oe=k=>{var T=lt(),S=r(T,!0);t(T),m(ne=>b(S,ne),[()=>e(a).name.charAt(0).toUpperCase()]),d(k,T)};l(j,k=>{e(a).avatarUrl?k(Q):k(oe,!1)})}var R=o(j,2),A=r(R),E=r(A,!0);t(A);var P=o(A,2),de=r(P);t(P),t(R),t(M),m(()=>{b(E,e(a).name),b(de,`${e(a).members.length??""} member${e(a).members.length!==1?"s":""}`)}),d(C,M)}),t(u),t(i),d(s,i)};l(he,s=>{e(fe).length>0&&s(Me)})}var je=o(he,2);{var Ae=s=>{var i=xt();d(s,i)};l(je,s=>{_.data.teams.length===0&&s(Ae)})}t(te),m(()=>{b(Ie,`${_.data.teams.length??""} team${_.data.teams.length!==1?"s":""}`),b(ke,e(O)?"Cancel":"New Team")}),H("click",se,()=>h(O,!e(O))),d(we,te),He()}Qe(["click"]);export{Ut as component}; diff --git a/.svelte-kit/output/client/_app/immutable/nodes/11.DR1Vz7m0.js b/.svelte-kit/output/client/_app/immutable/nodes/11.DR1Vz7m0.js deleted file mode 100644 index 67e6c80..0000000 --- a/.svelte-kit/output/client/_app/immutable/nodes/11.DR1Vz7m0.js +++ /dev/null @@ -1 +0,0 @@ -import"../chunks/DsnmJJEf.js";import{i as o}from"../chunks/TpZZa089.js";import{p,t as s,a as m,b as f,d as i}from"../chunks/BxEwC6Zc.js";import{s as n}from"../chunks/BnX5ZnVA.js";import{b as u,r as b}from"../chunks/DAtZQVjv.js";const h="";function _(...t){return u+h+b(t[0],t[1])}var c=i("better-auth");function j(t,a){p(a,!1),o();var e=c();s(r=>n(e,"href",r),[()=>_("/demo/better-auth")]),m(t,e),f()}export{j as component}; diff --git a/.svelte-kit/output/client/_app/immutable/nodes/12.C9UZWAjJ.js b/.svelte-kit/output/client/_app/immutable/nodes/12.C9UZWAjJ.js deleted file mode 100644 index 0276207..0000000 --- a/.svelte-kit/output/client/_app/immutable/nodes/12.C9UZWAjJ.js +++ /dev/null @@ -1 +0,0 @@ -import"../chunks/DsnmJJEf.js";import{p as h,f as c,t as b,a as l,b as v,d as g,e as o,r as s,s as i}from"../chunks/BxEwC6Zc.js";import{s as n}from"../chunks/DoLu9QLy.js";import{a as x,e as _}from"../chunks/BAocuFgQ.js";var w=g('

',1);function O(m,t){h(t,!0);var r=w(),a=c(r),p=o(a);s(a);var e=i(a,2),u=o(e);s(e);var f=i(e,2);x(f,d=>_?.(d)),b(()=>{n(p,`Hi, ${t.data.user.name??""}!`),n(u,`Your user ID is ${t.data.user.id??""}.`)}),l(m,r),v()}export{O as component}; diff --git a/.svelte-kit/output/client/_app/immutable/nodes/13.CyZ4e6yK.js b/.svelte-kit/output/client/_app/immutable/nodes/13.CyZ4e6yK.js deleted file mode 100644 index 501abea..0000000 --- a/.svelte-kit/output/client/_app/immutable/nodes/13.CyZ4e6yK.js +++ /dev/null @@ -1 +0,0 @@ -import"../chunks/DsnmJJEf.js";import{p as b,s as t,f as d,t as p,a as c,b as f,d as g,e as h,r as y}from"../chunks/BxEwC6Zc.js";import{s as w}from"../chunks/DoLu9QLy.js";import{a as n,e as i}from"../chunks/BAocuFgQ.js";var x=g('

Login


',1);function I(u,r){b(r,!0);var a=x(),s=t(d(a),2);n(s,o=>i?.(o));var e=t(s,2),l=h(e,!0);y(e);var m=t(e,4);n(m,o=>i?.(o)),p(()=>w(l,r.form?.message??"")),c(u,a),f()}export{I as component}; diff --git a/.svelte-kit/output/client/_app/immutable/nodes/2.BsR2_q_w.js b/.svelte-kit/output/client/_app/immutable/nodes/2.BsR2_q_w.js deleted file mode 100644 index e79d7eb..0000000 --- a/.svelte-kit/output/client/_app/immutable/nodes/2.BsR2_q_w.js +++ /dev/null @@ -1 +0,0 @@ -import"../chunks/DsnmJJEf.js";import{p as F,s as i,e as t,r as a,t as S,k as e,a as v,b as H,l as E,f as L,d as m,c as R}from"../chunks/BxEwC6Zc.js";import{s as I}from"../chunks/CyUoLS3q.js";import{i as A}from"../chunks/BQKoxf2Q.js";import{s as z}from"../chunks/DoLu9QLy.js";import{e as T,i as W}from"../chunks/BLQQas77.js";import{s as B}from"../chunks/BnX5ZnVA.js";import{s as M}from"../chunks/BqOsL1Vv.js";import{p as V}from"../chunks/D2SGgx9j.js";import{a as q,e as C}from"../chunks/BAocuFgQ.js";var G=m(' '),J=m('

Staff

⚡ Admin',1),K=m('');function O(j,_){F(_,!0);const d=E(()=>V.data?.user),k=[{href:"/",label:"Dashboard",icon:"⌂"},{href:"/matches",label:"Matches",icon:"⚔"},{href:"/mappools",label:"Mappools",icon:"♫"},{href:"/teams",label:"Teams",icon:"⚑"}];function p(r){return r==="/"?V.url.pathname==="/":V.url.pathname.startsWith(r)}const y=E(()=>e(d)?.role==="admin");var h=K(),o=i(t(h),2),n=t(o);T(n,17,()=>k,W,(r,f)=>{var b=G(),u=t(b),D=t(u,!0);a(u);var $=i(u);a(b),S(l=>{B(b,"href",e(f).href),M(b,1,`font-500 flex items-center gap-3 rounded-md px-3 py-2 text-sm transition-colors ${l??""}`),z(D,e(f).icon),z($,` ${e(f).label??""}`)},[()=>p(e(f).href)?"bg-accent-dim text-accent":"text-text-secondary hover:bg-surface-700 hover:text-text-primary"]),v(r,b)});var x=i(n,2);{var s=r=>{var f=J(),b=i(L(f),2);S(u=>M(b,1,`font-500 flex items-center gap-3 rounded-md px-3 py-2 text-sm transition-colors ${u??""}`),[()=>p("/admin")?"bg-red-500/10 text-red-400":"text-text-secondary hover:bg-surface-700 hover:text-text-primary"]),v(r,f)};A(x,r=>{e(y)&&r(s)})}a(o);var c=i(o,2),w=t(c);a(c),a(h),S(r=>M(w,1,`font-500 flex items-center gap-3 rounded-md px-3 py-2 text-sm text-text-secondary transition-colors hover:bg-surface-700 hover:text-text-primary ${r??""}`),[()=>p("/settings")?"bg-accent-dim text-accent":""]),v(j,h),H()}var P=m(" "),Q=m(''),U=m('
'),X=m('Sign in with osu!'),Y=m('
');function Z(j,_){F(_,!0);const d=E(()=>V.data?.user),k={referee:{label:"REF",color:"bg-yellow-500/20 text-yellow-400"},admin:{label:"ADMIN",color:"bg-red-500/20 text-red-400"}},p=E(()=>e(d)?.role?k[e(d).role]:null);var y=Y(),h=i(t(y),2),o=t(h);{var n=s=>{var c=U(),w=t(c);{var r=l=>{var g=P(),N=t(g,!0);a(g),S(()=>{M(g,1,`rounded px-1.5 py-0.5 text-[10px] font-700 ${e(p).color??""}`),z(N,e(p).label)}),v(l,g)};A(w,l=>{e(p)&&l(r)})}var f=i(w,2);{var b=l=>{var g=Q();S(()=>{B(g,"src",e(d).image),B(g,"alt",e(d).name)}),v(l,g)};A(f,l=>{e(d).image&&l(b)})}var u=i(f,2),D=t(u,!0);a(u);var $=i(u,2);q($,l=>C?.(l)),a(c),S(()=>z(D,e(d).name)),v(s,c)},x=s=>{var c=X();v(s,c)};A(o,s=>{e(d)?s(n):s(x,!1)})}a(h),a(y),v(j,y),H()}var ee=m('
'),te=m('');function fe(j,_){F(_,!0);const d=E(()=>V.data?.user);var k=R(),p=L(k);{var y=o=>{var n=ee(),x=t(n);O(x,{});var s=i(x,2),c=t(s);Z(c,{});var w=i(c,2),r=t(w);I(r,()=>_.children),a(w),a(s),a(n),v(o,n)},h=o=>{var n=te(),x=i(t(n),2),s=t(x);I(s,()=>_.children),a(x),a(n),v(o,n)};A(p,o=>{e(d)?o(y):o(h,!1)})}v(j,k),H()}export{fe as component}; diff --git a/.svelte-kit/output/client/_app/immutable/nodes/3.CMuy9Bx3.js b/.svelte-kit/output/client/_app/immutable/nodes/3.CMuy9Bx3.js deleted file mode 100644 index 2ffae4c..0000000 --- a/.svelte-kit/output/client/_app/immutable/nodes/3.CMuy9Bx3.js +++ /dev/null @@ -1,3 +0,0 @@ -import"../chunks/DsnmJJEf.js";import{p as Fe,u as Oe,c as Re,f as be,a as o,b as Ue,i as O,j as ge,e as a,s as r,r as t,n as R,k as e,t as m,l as k,d as i}from"../chunks/BxEwC6Zc.js";import{d as Be,s as n,a as he}from"../chunks/DoLu9QLy.js";import{i as L}from"../chunks/BQKoxf2Q.js";import{e as _e,i as ye}from"../chunks/BLQQas77.js";import{s as z}from"../chunks/BnX5ZnVA.js";import{s as U}from"../chunks/BqOsL1Vv.js";var Pe=i(`
V

Welcome to Vash Esports

Automated tournament match management for osu! — lobbies, mappools, picks, bans, and - ELO tracking all in one place.

Sign in with osu!

Uses your osu! account. No extra registration needed.

`),Ge=i(''),He=i(''),Ve=i(""),We=i('
vs
'),Ye=i('

Live Now

'),ze=i('
'),Je=i(''),Ke=i(' - ',1),Xe=i('vs'),Ze=i(' '),$e=i('

'),et=i('

No matches yet. Create one

'),tt=i('

Welcome back,

Automated esports match management for osu!

Total Matches

Completed

Teams

Mappools

Ranked Queue

Find a match at your skill level

');function dt(we,p){Fe(p,!0);const re={CREATED:{label:"Created",color:"text-text-secondary"},LOBBY:{label:"In Lobby",color:"text-yellow-400"},ROLLING:{label:"Rolling",color:"text-yellow-400",dot:"bg-yellow-400"},PICKING:{label:"Picking",color:"text-blue-400",dot:"bg-blue-400"},PLAYING:{label:"Live",color:"text-green-400",dot:"bg-green-400"},FINISHED:{label:"Finished",color:"text-text-secondary"},CANCELLED:{label:"Cancelled",color:"text-red-400"}};let J=ge(null),M=ge(!1);async function B(){try{const c=await fetch("/api/queue");c.ok&&O(J,await c.json(),!0)}catch{}}async function Ie(){O(M,!0);try{const u=await(await fetch("/api/queue",{method:"POST"})).json();if(u.matched&&u.match){window.location.href=`/matches/${u.match.id}`;return}await B()}catch{}O(M,!1)}async function ke(){O(M,!0);try{await fetch("/api/queue",{method:"DELETE"}),await B()}catch{}O(M,!1)}Oe(()=>{if(p.data.user){B();const c=setInterval(B,5e3);return()=>clearInterval(c)}});function Le(c){const u=new Date(c),Q=Date.now()-u.getTime(),j=Math.floor(Q/6e4);if(j<1)return"just now";if(j<60)return`${j}m ago`;const S=Math.floor(j/60);return S<24?`${S}h ago`:`${Math.floor(S/24)}d ago`}var ne=Re(),Me=be(ne);{var je=c=>{var u=Pe();o(c,u)},Ee=c=>{var u=tt(),Q=a(u),j=a(Q),S=r(a(j)),oe=a(S,!0);t(S),t(j),R(2),t(Q);var K=r(Q,2),X=a(K),ce=a(X),Ne=a(ce,!0);t(ce),R(2),t(X);var Z=r(X,2),le=a(Z),Ae=a(le,!0);t(le),R(2),t(Z);var $=r(Z,2),de=a($),Ce=a(de,!0);t(de),R(2),t($);var ie=r($,2),ve=a(ie),Se=a(ve,!0);t(ve),R(2),t(ie),t(K);var xe=r(K,2);{var De=l=>{var s=Ye(),v=r(a(s),2);_e(v,21,()=>p.data.liveMatches,ye,(h,b)=>{const E=k(()=>e(b).participants[0]),g=k(()=>e(b).participants[1]),_=k(()=>re[e(b).state]);var y=We(),N=a(y),P=a(N);{var G=f=>{var I=Ge();m(()=>z(I,"src",e(E).team.avatarUrl)),o(f,I)};L(P,f=>{e(E)?.team.avatarUrl&&f(G)})}var H=r(P,2),te=a(H,!0);t(H),t(N);var D=r(N,2),T=a(D),V=a(T,!0);t(T);var W=r(T,4),Y=a(W,!0);t(W),t(D);var F=r(D,2),A=a(F),ae=a(A,!0);t(A);var d=r(A,2);{var w=f=>{var I=He();m(()=>z(I,"src",e(g).team.avatarUrl)),o(f,I)};L(d,f=>{e(g)?.team.avatarUrl&&f(w)})}t(F);var x=r(F,2),q=a(x);{var C=f=>{var I=Ve();m(()=>U(I,1,`h-1.5 w-1.5 rounded-full ${e(_).dot??""}`)),o(f,I)};L(q,f=>{e(_)?.dot&&f(C)})}var se=r(q);t(x),t(y),m(()=>{z(y,"href",`/matches/${e(b).id??""}`),n(te,e(E)?.team.name??"?"),n(V,e(E)?.score??0),n(Y,e(g)?.score??0),n(ae,e(g)?.team.name??"?"),U(x,1,`flex items-center gap-1.5 text-xs font-500 ${e(_)?.color??""??""}`),n(se,` ${e(_)?.label??""}`)}),o(h,y)}),t(v),t(s),o(l,s)};L(xe,l=>{p.data.liveMatches.length>0&&l(De)})}var ee=r(xe,2),pe=a(ee),qe=r(a(pe),2);{var Qe=l=>{var s=ze(),v=a(s),h=r(a(v));t(v);var b=r(v,2);t(s),m(()=>{n(h,` In queue (${e(J).queueSize??""} searching)`),b.disabled=e(M)}),he("click",b,ke),o(l,s)},Te=l=>{var s=Je(),v=a(s,!0);t(s),m(()=>{s.disabled=e(M),n(v,e(M)?"Joining...":"Find Match")}),he("click",s,Ie),o(l,s)};L(qe,l=>{e(J)?.inQueue?l(Qe):l(Te,!1)})}t(pe),t(ee);var ue=r(ee,2),fe=r(a(ue),2),me=r(a(fe),2);_e(me,21,()=>p.data.recentMatches,ye,(l,s)=>{const v=k(()=>e(s).participants[0]),h=k(()=>e(s).participants[1]),b=k(()=>e(s).config),E=k(()=>re[e(s).state]);var g=$e(),_=a(g),y=a(_),N=a(y),P=a(N,!0);t(N);var G=r(N,2);{var H=d=>{var w=Ke(),x=be(w),q=a(x,!0);t(x);var C=r(x,4),se=a(C,!0);t(C),m(()=>{U(x,1,`text-xs font-700 tabular-nums ${(e(v)?.score??0)>(e(h)?.score??0)?"text-green-400":"text-text-secondary"}`),n(q,e(v)?.score??0),U(C,1,`text-xs font-700 tabular-nums ${(e(h)?.score??0)>(e(v)?.score??0)?"text-green-400":"text-text-secondary"}`),n(se,e(h)?.score??0)}),o(d,w)},te=d=>{var w=Xe();o(d,w)};L(G,d=>{e(s).state==="FINISHED"?d(H):d(te,!1)})}var D=r(G,2),T=a(D,!0);t(D),t(y);var V=r(y,2),W=a(V);t(V),t(_);var Y=r(_,2);{var F=d=>{const w=k(()=>e(s).participants.find(C=>C.teamId===e(s).winnerId));var x=Ze(),q=a(x);t(x),m(()=>n(q,`🏆 ${e(w)?.team.name??""}`)),o(d,x)};L(Y,d=>{e(s).state==="FINISHED"&&e(s).winnerId&&d(F)})}var A=r(Y,2),ae=a(A,!0);t(A),t(g),m(d=>{z(g,"href",`/matches/${e(s).id??""}`),n(P,e(v)?.team.name??"?"),n(T,e(h)?.team.name??"?"),n(W,`${e(s).name?`${e(s).name} · `:""}BO${e(b).bestOf??""} - · ${d??""}`),U(A,1,`text-xs ${e(E)?.color??"text-text-secondary"??""}`),n(ae,e(E)?.label)},[()=>Le(e(s).finishedAt??e(s).createdAt)]),o(l,g)},l=>{var s=et();o(l,s)}),t(me),t(fe),t(ue),t(u),m(()=>{n(oe,p.data.user.name),n(Ne,p.data.stats.matches),n(Ae,p.data.stats.finished),n(Ce,p.data.stats.teams),n(Se,p.data.stats.mappools)}),o(c,u)};L(Me,c=>{p.data.user?c(Ee,!1):c(je)})}o(we,ne),Ue()}Be(["click"]);export{dt as component}; diff --git a/.svelte-kit/output/client/_app/immutable/nodes/4.BdC-uDW-.js b/.svelte-kit/output/client/_app/immutable/nodes/4.BdC-uDW-.js deleted file mode 100644 index 52a5797..0000000 --- a/.svelte-kit/output/client/_app/immutable/nodes/4.BdC-uDW-.js +++ /dev/null @@ -1 +0,0 @@ -import"../chunks/DsnmJJEf.js";import{p as Z,t as p,a as c,b as $,d as x,e as t,s as o,r as a,k as r,j as ee,i as O,l as te}from"../chunks/BxEwC6Zc.js";import{d as ae,s as i,a as re}from"../chunks/DoLu9QLy.js";import{i as S}from"../chunks/BQKoxf2Q.js";import{e as se,i as oe}from"../chunks/BLQQas77.js";import{a as ne,e as le}from"../chunks/BAocuFgQ.js";import{r as ie,a as de,s as pe}from"../chunks/BnX5ZnVA.js";import{s as ce}from"../chunks/BqOsL1Vv.js";import{i as xe,s as ve}from"../chunks/Cy2QBcXt.js";var me=x('

'),_e=x(''),ue=x('
'),fe=x('

/
'),be=x('

Admin Panel

Avatar User ELO W/L Role
');function je(T,v){Z(v,!0);let m=ee("");const j={player:{label:"Player",color:"bg-surface-600 text-text-secondary border-border"},referee:{label:"Referee",color:"bg-yellow-500/20 text-yellow-400 border-yellow-500/30"},admin:{label:"Admin",color:"bg-red-500/20 text-red-400 border-red-500/30"}};var _=be(),u=t(_),E=o(t(u),2),z=t(E);a(E),a(u);var U=o(u,2);{var D=d=>{var e=me(),f=t(e,!0);a(e),p(()=>i(f,r(m))),c(d,e)};S(U,d=>{r(m)&&d(D)})}var W=o(U,2),G=o(t(W),2);se(G,17,()=>v.data.users,oe,(d,e)=>{const f=te(()=>j[r(e).role]??j.player);var b=fe(),q=t(b);{var H=s=>{var l=_e();p(()=>pe(l,"src",r(e).image)),c(s,l)},J=s=>{var l=ue(),X=t(l,!0);a(l),p(Y=>i(X,Y),[()=>r(e).name.charAt(0).toUpperCase()]),c(s,l)};S(q,s=>{r(e).image?s(H):s(J,!1)})}var g=o(q,2),y=t(g),K=t(y,!0);a(y);var B=o(y,2),M=t(B,!0);a(B),a(g);var h=o(g,2),N=t(h,!0);a(h);var w=o(h,2),A=t(w),Q=t(A);a(A);var C=o(A,2),V=t(C);a(C),a(w);var R=o(w,2),k=t(R);ie(k);var n=o(k,2),L=t(n);L.value=L.__value="player";var P=o(L);P.value=P.__value="referee";var F=o(P);F.value=F.__value="admin",a(n);var I;xe(n),a(R),ne(R,(s,l)=>le?.(s,l),()=>()=>(O(m,""),async({result:s})=>{(s.type==="failure"||s.type==="success"&&s.data?.error)&&O(m,s.data?.error??"Failed to update role",!0)})),a(b),p(()=>{i(K,r(e).name),i(M,r(e).email),i(N,r(e).elo),i(Q,`${r(e).wins??""}W`),i(V,`${r(e).losses??""}L`),de(k,r(e).id),ce(n,1,`rounded-md border px-2 py-1 text-xs font-500 ${r(f).color??""} cursor-pointer bg-transparent focus:outline-none`),I!==(I=r(e).role)&&(n.value=(n.__value=r(e).role)??"",ve(n,r(e).role))}),re("change",n,s=>s.currentTarget.form?.requestSubmit()),c(d,b)}),a(W),a(_),p(()=>i(z,`${v.data.users.length??""} registered user${v.data.users.length!==1?"s":""}`)),c(T,_),$()}ae(["change"]);export{je as component}; diff --git a/.svelte-kit/output/client/_app/immutable/nodes/5.CyqZcxti.js b/.svelte-kit/output/client/_app/immutable/nodes/5.CyqZcxti.js deleted file mode 100644 index 57e94eb..0000000 --- a/.svelte-kit/output/client/_app/immutable/nodes/5.CyqZcxti.js +++ /dev/null @@ -1,2 +0,0 @@ -import"../chunks/DsnmJJEf.js";import{p as M,t as y,a as d,b as N,k as t,d as i,e as o,s as c,r as a,n as P,i as $,j as q}from"../chunks/BxEwC6Zc.js";import{d as A,a as F,s as v}from"../chunks/DoLu9QLy.js";import{i as G}from"../chunks/BQKoxf2Q.js";import{e as L,i as S}from"../chunks/BLQQas77.js";import{a as z,e as B}from"../chunks/BAocuFgQ.js";import{s as E}from"../chunks/BnX5ZnVA.js";var H=i('
'),I=i('

→
'),J=i('

No mappools yet. Create one to get started.

'),K=i('

Mappools

Create and manage your beatmap pools

');function X(_,f){M(f,!0);let n=q(!1);var l=K(),p=o(l),m=c(o(p),2),k=o(m,!0);a(m),a(p);var b=c(p,2);{var w=r=>{var e=H();z(e,s=>B?.(s)),d(r,e)};G(b,r=>{t(n)&&r(w)})}var u=c(b,2);L(u,21,()=>f.data.mappools,S,(r,e)=>{var s=I(),g=o(s),x=o(g),C=o(x,!0);a(x);var h=c(x,2),j=o(h);a(h),a(g),P(2),a(s),y(D=>{E(s,"href",`/mappools/${t(e).id??""}`),v(C,t(e).name),v(j,`${t(e).slots.length??""} map${t(e).slots.length!==1?"s":""} - · Created ${D??""}`)},[()=>new Date(t(e).createdAt).toLocaleDateString()]),d(r,s)},r=>{var e=J();d(r,e)}),a(u),a(l),y(()=>v(k,t(n)?"Cancel":"New Pool")),F("click",m,()=>$(n,!t(n))),d(_,l),N()}A(["click"]);export{X as component}; diff --git a/.svelte-kit/output/client/_app/immutable/nodes/6.CEe0czaO.js b/.svelte-kit/output/client/_app/immutable/nodes/6.CEe0czaO.js deleted file mode 100644 index 008b31b..0000000 --- a/.svelte-kit/output/client/_app/immutable/nodes/6.CEe0czaO.js +++ /dev/null @@ -1 +0,0 @@ -import"../chunks/DsnmJJEf.js";import{p as St,t as m,k as r,a as l,b as Tt,e as a,s,d as c,l as st,r as e,i as b,m as Lt,n as Pt,j as M,f as Ut}from"../chunks/BxEwC6Zc.js";import{d as Ct,a as Et,s as i}from"../chunks/DoLu9QLy.js";import{i as q}from"../chunks/BQKoxf2Q.js";import{e as z,i as G}from"../chunks/BLQQas77.js";import{a as J,e as K}from"../chunks/BAocuFgQ.js";import{r as dt,a as Ot,s as nt}from"../chunks/BnX5ZnVA.js";import{s as qt}from"../chunks/BqOsL1Vv.js";import{b as zt}from"../chunks/CAkKRSSs.js";import{b as Gt}from"../chunks/Cy2QBcXt.js";import"../chunks/DAtZQVjv.js";var Jt=c(""),Kt=c('

'),Qt=c(''),Vt=c('
No cover
'),Wt=c('
',1),Xt=c('

'),Yt=c('
'),Zt=c('
'),te=c('

No maps yet. Add your first map above.

'),ee=c('

Add Map

');function me(it,_){St(_,!0);const Q=["NM","HD","HR","DT","FM","TB"];let V=M("NM"),g=M(""),y=M(""),h=M(!1);const pt=st(()=>()=>{const t={};for(const o of Q){const d=_.data.pool.slots.filter(x=>x.category===o);d.length>0&&(t[o]=d)}return t});function vt(t){const o=Math.floor(t/60),d=t%60;return`${o}:${d.toString().padStart(2,"0")}`}const lt={NM:"bg-blue-500/20 text-blue-400 border-blue-500/30",HD:"bg-yellow-500/20 text-yellow-400 border-yellow-500/30",HR:"bg-red-500/20 text-red-400 border-red-500/30",DT:"bg-purple-500/20 text-purple-400 border-purple-500/30",FM:"bg-green-500/20 text-green-400 border-green-500/30",TB:"bg-pink-500/20 text-pink-400 border-pink-500/30"};var j=ee(),B=a(j),I=a(B),W=s(a(I),2),N=a(W),ct=a(N,!0);e(N);var X=s(N,2),mt=a(X);e(X),e(W),e(I);var $=s(I,2),xt=a($);e($),J($,t=>K?.(t)),e(B);var k=s(B,2),A=s(a(k),2),w=a(A);z(w,21,()=>Q,G,(t,o)=>{var d=Jt(),x=a(d,!0);e(d);var f={};m(()=>{i(x,r(o)),f!==(f=r(o))&&(d.value=(d.__value=r(o))??"")}),l(t,d)}),e(w);var F=s(w,2);dt(F);var H=s(F,2),bt=a(H,!0);e(H),e(A);var ft=s(A,2);{var ut=t=>{var o=Kt(),d=a(o,!0);e(o),m(()=>i(d,r(y))),l(t,o)};q(ft,t=>{r(y)&&t(ut)})}e(k),J(k,(t,o)=>K?.(t,o),()=>()=>(b(h,!0),b(y,""),async({result:t,update:o})=>{b(h,!1),t.type==="success"?(b(g,""),await o()):t.type==="failure"&&b(y,t.data?.error??"Failed to add map",!0)}));var Y=s(k,2);z(Y,21,()=>Object.entries(r(pt)()),G,(t,o)=>{var d=st(()=>Lt(r(o),2));let x=()=>r(d)[0],f=()=>r(d)[1];var R=Zt(),S=a(R),D=a(S),_t=a(D,!0);e(D);var Z=s(D,2),gt=a(Z);e(Z),e(S);var tt=s(S,2);z(tt,21,f,G,(yt,p,ht)=>{var T=Yt(),et=a(T);{var kt=n=>{var v=Qt();m(()=>nt(v,"src",r(p).beatmap.coverUrl)),l(n,v)},wt=n=>{var v=Vt();l(n,v)};q(et,n=>{r(p).beatmap?.coverUrl?n(kt):n(wt,!1)})}var L=s(et,2),Dt=a(L);{var Mt=n=>{var v=Wt(),u=Ut(v),It=a(u);e(u);var rt=s(u,2),C=a(rt),Nt=a(C);e(C);var E=s(C,2),$t=a(E);e(E);var O=s(E,2),At=a(O);e(O);var ot=s(O,2),Ft=a(ot,!0);e(ot),e(rt),m((Ht,Rt)=>{nt(u,"href",r(p).beatmap.url),i(It,`${r(p).beatmap.artist??""} - ${r(p).beatmap.title??""}`),i(Nt,`[${r(p).beatmap.version??""}]`),i($t,`★ ${Ht??""}`),i(At,`${r(p).beatmap.bpm??""} BPM`),i(Ft,Rt)},[()=>r(p).beatmap.starRating.toFixed(2),()=>vt(r(p).beatmap.totalLength)]),l(n,v)},jt=n=>{var v=Xt(),u=a(v);e(v),m(()=>i(u,`Beatmap #${r(p).beatmapId??""}`)),l(n,v)};q(Dt,n=>{r(p).beatmap?n(Mt):n(jt,!1)})}e(L);var P=s(L,2),Bt=a(P);e(P);var U=s(P,2),at=a(U);dt(at),Pt(2),e(U),J(U,n=>K?.(n)),e(T),m(()=>{i(Bt,`${x()??""}${ht+1}`),Ot(at,r(p).id)}),l(yt,T)}),e(tt),e(R),m(()=>{qt(D,1,`rounded border px-2 py-0.5 text-xs font-600 ${lt[x()]??"bg-surface-600 text-text-secondary border-border"??""}`),i(_t,x()),i(gt,`${f().length??""} map${f().length!==1?"s":""}`)}),l(t,R)},t=>{var o=te();l(t,o)}),e(Y),e(j),m(t=>{i(ct,_.data.pool.name),i(mt,`${_.data.pool.slots.length??""} map${_.data.pool.slots.length!==1?"s":""}`),H.disabled=t,i(bt,r(h)?"Adding...":"Add")},[()=>r(h)||!r(g).trim()]),Et("click",xt,t=>{confirm("Delete this mappool?")||t.preventDefault()}),Gt(w,()=>r(V),t=>b(V,t)),zt(F,()=>r(g),t=>b(g,t)),l(it,j),Tt()}Ct(["click"]);export{me as component}; diff --git a/.svelte-kit/output/client/_app/immutable/nodes/7._nuD3LlN.js b/.svelte-kit/output/client/_app/immutable/nodes/7._nuD3LlN.js deleted file mode 100644 index 025e27c..0000000 --- a/.svelte-kit/output/client/_app/immutable/nodes/7._nuD3LlN.js +++ /dev/null @@ -1 +0,0 @@ -import"../chunks/DsnmJJEf.js";import{p as ye,t as h,a as v,b as we,c as Ie,f as W,k as e,i as X,d as f,l as E,s,j as ie,e as a,r as t,n as Me,g as ve}from"../chunks/BxEwC6Zc.js";import{d as Ne,a as Ce,s as p}from"../chunks/DoLu9QLy.js";import{i as N}from"../chunks/BQKoxf2Q.js";import{e as T,i as U}from"../chunks/BLQQas77.js";import{a as Le,e as Oe}from"../chunks/BAocuFgQ.js";import{s as K,b as $e}from"../chunks/BnX5ZnVA.js";import{s as Y}from"../chunks/BqOsL1Vv.js";var Ae=f('· ',1),Se=f('

'),De=f(""),Ee=f(""),Pe=f(""),Be=f(""),ke=f('

Create Match

'),Ge=f(''),je=f(''),Fe=f(""),Re=f('
vs
'),Te=f('

Live Now

'),Ue=f('

Past Matches

'),Ye=f(' - ',1),qe=f('vs'),He=f(' '),Ke=f('

'),ze=f('

No matches yet. Create one to get started.

'),Je=f('

Matches

');function rt(pe,$){ye($,!0);let q=ie(!1),H=ie("");const Z={CREATED:{label:"Created",color:"text-text-secondary border-border"},LOBBY:{label:"In Lobby",color:"text-yellow-400 border-yellow-500/30"},ROLLING:{label:"Rolling",color:"text-yellow-400 border-yellow-500/30",dot:"bg-yellow-400"},PICKING:{label:"Picking",color:"text-blue-400 border-blue-500/30",dot:"bg-blue-400"},PLAYING:{label:"Live",color:"text-green-400 border-green-500/30",dot:"bg-green-400"},FINISHED:{label:"Finished",color:"text-text-secondary border-border"},CANCELLED:{label:"Cancelled",color:"text-red-400 border-red-500/30"}},ee=["LOBBY","ROLLING","PICKING","PLAYING"],j=E(()=>$.data.matches.filter(l=>ee.includes(l.state))),xe=E(()=>$.data.matches.filter(l=>!ee.includes(l.state)));function te(l){const r=l.participants[0],i=l.participants[1];return{p1:r,p2:i}}function ae(l){const r=new Date(l),i=Date.now()-r.getTime(),y=Math.floor(i/6e4);if(y<1)return"just now";if(y<60)return`${y}m ago`;const m=Math.floor(y/60);return m<24?`${m}h ago`:`${Math.floor(m/24)}d ago`}var z=Je(),J=a(z),Q=a(J),re=s(a(Q),2),se=a(re),fe=s(se);{var me=l=>{var r=Ae(),i=s(W(r)),y=a(i);t(i),h(()=>p(y,`${e(j).length??""} live`)),v(l,r)};N(fe,l=>{e(j).length>0&&l(me)})}t(re),t(Q);var V=s(Q,2),ue=a(V,!0);t(V),t(J);var oe=s(J,2);{var _e=l=>{var r=ke(),i=s(a(r),2);{var y=d=>{var o=Se(),n=a(o,!0);t(o),h(()=>p(n,e(H))),v(d,o)};N(i,d=>{e(H)&&d(y)})}var m=s(i,2),x=s(a(m),2),C=s(a(x),2);T(C,20,()=>[3,5,7,9,11,13],U,(d,o)=>{var n=De(),I=a(n);t(n);var u={};h(c=>{$e(n,o===7),p(I,`BO${o??""} (first to ${c??""})`),u!==(u=o)&&(n.value=(n.__value=o)??"")},[()=>Math.ceil(o/2)]),v(d,n)}),t(C),t(x);var M=s(x,2),L=s(a(M),2),A=a(L);A.value=A.__value="";var F=s(A);T(F,17,()=>$.data.teams,U,(d,o)=>{var n=Ee(),I=a(n);t(n);var u={};h(()=>{p(I,`${e(o).name??""}${e(o).isPersonal?" (solo)":""}`),u!==(u=e(o).id)&&(n.value=(n.__value=e(o).id)??"")}),v(d,n)}),t(L),t(M);var S=s(M,2),R=s(a(S),2),O=a(R);O.value=O.__value="";var P=s(O);T(P,17,()=>$.data.teams,U,(d,o)=>{var n=Pe(),I=a(n);t(n);var u={};h(()=>{p(I,`${e(o).name??""}${e(o).isPersonal?" (solo)":""}`),u!==(u=e(o).id)&&(n.value=(n.__value=e(o).id)??"")}),v(d,n)}),t(R),t(S);var B=s(S,2),D=s(a(B),2),k=a(D);k.value=k.__value="";var G=s(k);T(G,17,()=>$.data.mappools,U,(d,o)=>{var n=Be(),I=a(n);t(n);var u={};h(()=>{p(I,`${e(o).name??""} (${e(o).slots.length??""} maps)`),u!==(u=e(o).id)&&(n.value=(n.__value=e(o).id)??"")}),v(d,n)}),t(D),t(B),t(m),Me(2),t(r),Le(r,(d,o)=>Oe?.(d,o),()=>()=>(X(H,""),async({result:d,update:o})=>{d.type==="failure"||d.type==="success"&&d.data?.error?X(H,d.data?.error??"Failed to create match",!0):await o()})),v(l,r)};N(oe,l=>{e(q)&&l(_e)})}var ne=s(oe,2);{var be=l=>{var r=Te(),i=s(a(r),2);T(i,21,()=>e(j),U,(y,m)=>{const x=E(()=>{const{p1:_,p2:g}=te(e(m));return{p1:_,p2:g}}),C=E(()=>Z[e(m).state]);var M=Re(),L=a(M),A=a(L);{var F=_=>{var g=Ge();h(()=>K(g,"src",e(x).p1.team.avatarUrl)),v(_,g)};N(A,_=>{e(x).p1?.team.avatarUrl&&_(F)})}var S=s(A,2),R=a(S,!0);t(S),t(L);var O=s(L,2),P=a(O),B=a(P,!0);t(P);var D=s(P,4),k=a(D,!0);t(D),t(O);var G=s(O,2),d=a(G),o=a(d,!0);t(d);var n=s(d,2);{var I=_=>{var g=je();h(()=>K(g,"src",e(x).p2.team.avatarUrl)),v(_,g)};N(n,_=>{e(x).p2?.team.avatarUrl&&_(I)})}t(G);var u=s(G,2),c=a(u);{var b=_=>{var g=Fe();h(()=>Y(g,1,`h-1.5 w-1.5 rounded-full ${e(C).dot??""}`)),v(_,g)};N(c,_=>{e(C)?.dot&&_(b)})}var w=s(c);t(u),t(M),h(()=>{K(M,"href",`/matches/${e(m).id??""}`),p(R,e(x).p1?.team.name??"?"),p(B,e(x).p1?.score??0),p(k,e(x).p2?.score??0),p(o,e(x).p2?.team.name??"?"),Y(u,1,`flex items-center gap-1.5 rounded border px-2 py-0.5 text-xs font-500 ${e(C)?.color??"border-border"??""}`),p(w,` ${e(C)?.label??e(m).state??""}`)}),v(y,M)}),t(i),t(r),v(l,r)};N(ne,l=>{e(j).length>0&&l(be)})}var le=s(ne,2),de=a(le);{var ge=l=>{var r=Ue();v(l,r)};N(de,l=>{e(j).length>0&&l(ge)})}var ce=s(de,2);T(ce,21,()=>e(xe),U,(l,r)=>{const i=E(()=>{const{p1:c,p2:b}=te(e(r));return{p1:c,p2:b}}),y=E(()=>e(r).config),m=E(()=>Z[e(r).state]);var x=Ke(),C=a(x),M=a(C),L=a(M),A=a(L,!0);t(L);var F=s(L,2);{var S=c=>{var b=Ye(),w=W(b),_=a(w,!0);t(w);var g=s(w,4),he=a(g,!0);t(g),h(()=>{Y(w,1,`text-xs font-700 tabular-nums ${(e(i).p1?.score??0)>(e(i).p2?.score??0)?"text-green-400":"text-text-secondary"}`),p(_,e(i).p1?.score??0),Y(g,1,`text-xs font-700 tabular-nums ${(e(i).p2?.score??0)>(e(i).p1?.score??0)?"text-green-400":"text-text-secondary"}`),p(he,e(i).p2?.score??0)}),v(c,b)},R=c=>{var b=qe();v(c,b)};N(F,c=>{e(r).state==="FINISHED"?c(S):c(R,!1)})}var O=s(F,2),P=a(O,!0);t(O),t(M);var B=s(M,2),D=a(B),k=s(D);{var G=c=>{var b=ve();h(w=>p(b,`· ${w??""}`),[()=>ae(e(r).finishedAt)]),v(c,b)},d=c=>{var b=ve();h(w=>p(b,`· ${w??""}`),[()=>ae(e(r).createdAt)]),v(c,b)};N(k,c=>{e(r).finishedAt?c(G):e(r).createdAt&&c(d,1)})}t(B),t(C);var o=s(C,2);{var n=c=>{const b=E(()=>e(r).participants.find(g=>g.teamId===e(r).winnerId));var w=He(),_=a(w);t(w),h(()=>p(_,`🏆 ${e(b)?.team.name??""}`)),v(c,w)};N(o,c=>{e(r).state==="FINISHED"&&e(r).winnerId&&c(n)})}var I=s(o,2),u=a(I,!0);t(I),t(x),h(()=>{K(x,"href",`/matches/${e(r).id??""}`),p(A,e(i).p1?.team.name??"?"),p(P,e(i).p2?.team.name??"?"),p(D,`${e(r).name?`${e(r).name} · `:""}BO${e(y).bestOf??""} `),Y(I,1,`rounded border px-2 py-0.5 text-xs font-500 ${e(m)?.color??"border-border"??""}`),p(u,e(m)?.label??e(r).state)}),v(l,x)},l=>{var r=Ie(),i=W(r);{var y=m=>{var x=ze();v(m,x)};N(i,m=>{e(j).length===0&&m(y)})}v(l,r)}),t(ce),t(le),t(z),h(()=>{p(se,`${$.data.matches.length??""} match${$.data.matches.length!==1?"es":""} `),p(ue,e(q)?"Cancel":"New Match")}),Ce("click",V,()=>X(q,!e(q))),v(pe,z),we()}Ne(["click"]);export{rt as component}; diff --git a/.svelte-kit/output/client/_app/immutable/nodes/8.CkbqikZq.js b/.svelte-kit/output/client/_app/immutable/nodes/8.CkbqikZq.js deleted file mode 100644 index cc8ee6c..0000000 --- a/.svelte-kit/output/client/_app/immutable/nodes/8.CkbqikZq.js +++ /dev/null @@ -1 +0,0 @@ -import"../chunks/DsnmJJEf.js";import{p as xe,u as fe,k as t,t as _,a as d,b as me,d as i,l as g,e as r,s,r as e,f as vt,n as et,i as W,j as ct,m as _e}from"../chunks/BxEwC6Zc.js";import{d as ue,s as v,a as be}from"../chunks/DoLu9QLy.js";import{i as f}from"../chunks/BQKoxf2Q.js";import{e as rt,i as at}from"../chunks/BLQQas77.js";import{a as st,e as ot}from"../chunks/BAocuFgQ.js";import{s as Q,r as ge,a as ye}from"../chunks/BnX5ZnVA.js";import{s as F}from"../chunks/BqOsL1Vv.js";import{i as he}from"../chunks/BkIq08el.js";var Ie=i('· ',1),we=i('
'),Le=i(''),ke=i('

'),Ce=i('

'),$e=i(''),Ne=i('

vs

'),Pe=i('
'),Re=i('

'),Ge=i('

—

'),Se=i('

'),Ee=i('

or type !roll in osu! chat

',1),Oe=i('

Waiting for all rolls...

'),De=i('

🎲 Roll Phase

Highest roll picks first

'),Be=i('

'),je=i(''),Ae=i('
?
'),Fe=i('

',1),Ye=i('

'),He=i('✓'),Te=i('
'),Ue=i('
'),Me=i(`

🎯 Pick a Map

's turn to pick

or type !pick NM1 in osu! chat

`),Ve=i('

',1),Ke=i('
Now Playing

Waiting for players to ready up & play in osu!...

'),We=i('
'),ze=i(''),qe=i(''),Je=i('

'),Qe=i(" "),Xe=i('
-
'),Ze=i('Live'),tr=i(' '),er=i('
'),rr=i('

Games Played

'),ar=i('

Creating osu! lobby...

'),sr=i('

'),or=i('

Lobby created. Waiting for players to join...

'),nr=i('

This match was cancelled.

'),dr=i('');function ur(Dt,q){xe(q,!0);let n=g(()=>q.data.match),D=g(()=>t(n).participants[0]),j=g(()=>t(n).participants[1]);const ht=g(()=>t(n).config),pt=g(()=>Math.ceil(t(ht).bestOf/2)),Bt=g(()=>new Set(t(n).games.map(a=>a.mappoolSlotId))),It=g(()=>[...t(n).participants].sort((a,o)=>(a.pickOrder??99)-(o.pickOrder??99))),jt=g(()=>t(n).games.length%t(It).length),At=g(()=>t(It)[t(jt)]),Ft=g(()=>t(n).state==="ROLLING"&&t(n).participants.some(a=>a.rollValue===null)),xt={NM:"bg-blue-500/20 text-blue-400 border-blue-500/30",HD:"bg-yellow-500/20 text-yellow-400 border-yellow-500/30",HR:"bg-red-500/20 text-red-400 border-red-500/30",DT:"bg-purple-500/20 text-purple-400 border-purple-500/30",FM:"bg-green-500/20 text-green-400 border-green-500/30",TB:"bg-pink-500/20 text-pink-400 border-pink-500/30"},Yt=g(()=>()=>{if(!t(n).mappool?.slots)return{};const a={};for(const o of t(n).mappool.slots)a[o.category]||(a[o.category]=[]),a[o.category].push(o);for(const o of Object.keys(a))a[o].sort((l,c)=>l.orderInCategory-c.orderInCategory);return a});let nt=ct(!1),ft=ct(!1),dt=ct(""),it=ct(!1),mt=null;fe(()=>(["CREATED","LOBBY","ROLLING","PICKING","PLAYING"].includes(t(n).state)&&(mt=setInterval(()=>he(),3e3)),()=>{mt&&clearInterval(mt)}));function Ht(a){const o=Math.floor(a/60),l=a%60;return`${o}:${l.toString().padStart(2,"0")}`}function Tt(a){return{CREATED:"Waiting",LOBBY:"In Lobby",ROLLING:"Rolling",PICKING:"Pick Phase",PLAYING:"Playing",FINISHED:"Finished",CANCELLED:"Cancelled"}[a]??a}function Ut(a){return{ROLLING:"border-yellow-500/30",PICKING:"border-blue-500/30",PLAYING:"border-green-500/30",FINISHED:"border-accent/30"}[a]??"border-border"}var _t=dr(),ut=r(_t),bt=s(r(ut),2),gt=r(bt),Mt=r(gt,!0);e(gt);var wt=s(gt,2),Lt=r(wt),Vt=s(Lt);{var Kt=a=>{var o=Ie(),l=s(vt(o)),c=r(l);e(l),_(()=>{Q(l,"href",`https://osu.ppy.sh/mp/${t(n).osuLobbyId??""}`),v(c,`osu! mp/${t(n).osuLobbyId??""}`)}),d(a,o)};f(Vt,a=>{t(n).osuLobbyId&&a(Kt)})}e(wt),e(bt);var lt=s(bt,2),Wt=r(lt,!0);e(lt);var zt=s(lt,2);{var qt=a=>{var o=we(),l=r(o);e(o),st(o,c=>ot?.(c)),be("click",l,c=>{confirm("Cancel this match?")||c.preventDefault()}),d(a,o)},Jt=g(()=>!["FINISHED","CANCELLED"].includes(t(n).state));f(zt,a=>{t(Jt)&&a(qt)})}e(ut);var kt=s(ut,2);{var Qt=a=>{var o=Ne(),l=r(o),c=r(l);{var p=N=>{var G=Le();_(()=>Q(G,"src",t(D).team.avatarUrl)),d(N,G)};f(c,N=>{t(D).team.avatarUrl&&N(p)})}var h=s(c,2),P=r(h),b=r(P,!0);e(P);var R=s(P,2);{var u=N=>{var G=ke(),V=r(G);e(G),_(()=>v(V,`Roll: ${t(D).rollValue??""}${t(D).pickOrder===1?" ★":""}`)),d(N,G)};f(R,N=>{t(D).rollValue!=null&&N(u)})}e(h);var m=s(h,2),y=r(m,!0);e(m),e(l);var L=s(l,4),k=r(L),B=r(k,!0);e(k);var I=s(k,2),$=r(I),O=r($,!0);e($);var T=s($,2);{var M=N=>{var G=Ce(),V=r(G);e(G),_(()=>v(V,`${t(j).pickOrder===1?"★ ":""}Roll: ${t(j).rollValue??""}`)),d(N,G)};f(T,N=>{t(j).rollValue!=null&&N(M)})}e(I);var Y=s(I,2);{var S=N=>{var G=$e();_(()=>Q(G,"src",t(j).team.avatarUrl)),d(N,G)};f(Y,N=>{t(j).team.avatarUrl&&N(S)})}e(L),e(o),_(()=>{F(l,1,`flex flex-1 items-center gap-4 rounded-lg border p-4 ${t(n).winnerId===t(D).teamId?"border-green-500/40 bg-green-500/5":"border-border bg-surface-800"}`),v(b,t(D).team.name),F(m,1,`text-3xl font-800 tabular-nums ${t(D).score>=t(pt)?"text-green-400":"text-text-primary"}`),v(y,t(D).score),F(L,1,`flex flex-1 items-center gap-4 rounded-lg border p-4 ${t(n).winnerId===t(j).teamId?"border-green-500/40 bg-green-500/5":"border-border bg-surface-800"}`),F(k,1,`text-3xl font-800 tabular-nums ${t(j).score>=t(pt)?"text-green-400":"text-text-primary"}`),v(B,t(j).score),v(O,t(j).team.name)}),d(a,o)};f(kt,a=>{t(D)&&t(j)&&a(Qt)})}var Ct=s(kt,2);{var Xt=a=>{var o=Pe(),l=r(o);st(l,(c,p)=>ot?.(c,p),()=>()=>async({result:c,update:p})=>{c.type==="success"&&c.data?.reinvited&&await p()}),e(o),d(a,o)},Zt=g(()=>["LOBBY","ROLLING","PICKING","PLAYING"].includes(t(n).state));f(Ct,a=>{t(Zt)&&a(Xt)})}var $t=s(Ct,2);{var te=a=>{var o=De(),l=r(o),c=s(r(l),4);rt(c,21,()=>t(n).participants,at,(b,R)=>{var u=Se(),m=r(u),y=r(m,!0);e(m);var L=s(m,2);{var k=I=>{var $=Re(),O=r($,!0);e($),_(()=>v(O,t(R).rollValue)),d(I,$)},B=I=>{var $=Ge();d(I,$)};f(L,I=>{t(R).rollValue!=null?I(k):I(B,!1)})}e(u),_(()=>v(y,t(R).team.name)),d(b,u)}),e(c);var p=s(c,2);{var h=b=>{var R=Ee(),u=vt(R),m=r(u),y=r(m,!0);e(m),e(u),st(u,(L,k)=>ot?.(L,k),()=>()=>(W(nt,!0),async({update:L})=>{W(nt,!1),await L()})),et(2),_(()=>{m.disabled=t(nt),v(y,t(nt)?"Rolling...":"🎲 Roll!")}),d(b,R)},P=b=>{var R=Oe();d(b,R)};f(p,b=>{t(Ft)?b(h):b(P,!1)})}e(l),e(o),d(a,o)};f($t,a=>{t(n).state==="ROLLING"&&a(te)})}var Nt=s($t,2);{var ee=a=>{var o=Me(),l=r(o),c=r(l),p=s(r(c),2),h=r(p),P=r(h,!0);e(h),et(),e(p),et(2),e(c);var b=s(c,2);{var R=m=>{var y=Be(),L=r(y,!0);e(y),_(()=>v(L,t(dt))),d(m,y)};f(b,m=>{t(dt)&&m(R)})}var u=s(b,2);rt(u,21,()=>Object.entries(t(Yt)()),at,(m,y)=>{var L=g(()=>_e(t(y),2));let k=()=>t(L)[0],B=()=>t(L)[1];var I=Ue(),$=r(I),O=r($,!0);e($);var T=s($,2);rt(T,21,B,at,(M,Y)=>{const S=g(()=>q.data.beatmapCache[t(Y).beatmapId]),N=g(()=>t(Bt).has(t(Y).id));var G=Te(),V=r(G);ge(V);var J=s(V,2),x=r(J);{var C=w=>{var E=je();_(()=>Q(E,"src",t(S).listCoverUrl)),d(w,E)},A=w=>{var E=Ae();d(w,E)};f(x,w=>{t(S)?.listCoverUrl?w(C):w(A,!1)})}var U=s(x,2),K=r(U);{var yt=w=>{var E=Fe(),tt=vt(E),ve=r(tt);e(tt);var Ot=s(tt,2),ce=r(Ot);e(Ot),_(pe=>{v(ve,`${t(S).artist??""} - ${t(S).title??""}`),v(ce,`[${t(S).version??""}] · ★${pe??""} · ${t(S).bpm??""}bpm`)},[()=>t(S).starRating.toFixed(1)]),d(w,E)},X=w=>{var E=Ye(),tt=r(E);e(E),_(()=>v(tt,`#${t(Y).beatmapId??""}`)),d(w,E)};f(K,w=>{t(S)?w(yt):w(X,!1)})}e(U);var Z=s(U,2),H=r(Z);e(Z);var z=s(Z,2);{var le=w=>{var E=He();d(w,E)};f(z,w=>{t(N)&&w(le)})}e(J),e(G),st(G,(w,E)=>ot?.(w,E),()=>()=>(W(ft,!0),W(dt,""),async({result:w,update:E})=>{W(ft,!1),w.type==="failure"||w.type==="success"&&w.data?.error?W(dt,w.data?.error??"Pick failed",!0):await E()})),_(()=>{ye(V,t(Y).id),J.disabled=t(N)||t(ft),F(J,1,`flex w-full items-center gap-3 rounded-lg border p-2 text-left transition-all ${t(N)?"border-border/50 bg-surface-900 opacity-30 cursor-not-allowed":"border-border bg-surface-700 hover:border-accent hover:bg-surface-600 cursor-pointer"}`),v(H,`${k()??""}${t(Y).orderInCategory??""}`)}),d(M,G)}),e(T),e(I),_(()=>{F($,1,`mb-2 inline-block rounded border px-2 py-0.5 text-xs font-600 ${xt[k()]??"border-border"??""}`),v(O,k())}),d(m,I)}),e(u),e(l),e(o),_(()=>v(P,t(At)?.team.name)),d(a,o)};f(Nt,a=>{t(n).state==="PICKING"&&a(ee)})}var Pt=s(Nt,2);{var re=a=>{const o=g(()=>t(n).games[t(n).games.length-1]),l=g(()=>t(o)?q.data.beatmapCache[t(o).slot?.beatmapId]:null);var c=Ke(),p=s(r(c),2);{var h=u=>{var m=Ve(),y=vt(m),L=r(y),k=s(L),B=r(k);e(k),e(y);var I=s(y,2),$=r(I);e(I),_((O,T)=>{v(L,`${t(l).artist??""} - ${t(l).title??""} `),v(B,`[${t(l).version??""}]`),v($,`★${O??""} · ${t(l).bpm??""}bpm · ${T??""}`)},[()=>t(l).starRating.toFixed(1),()=>Ht(t(l).totalLength)]),d(u,m)};f(p,u=>{t(l)&&u(h)})}var P=s(p,4),b=r(P),R=r(b,!0);e(b),e(P),st(P,(u,m)=>ot?.(u,m),()=>()=>(W(it,!0),async({update:u})=>{W(it,!1),await u()})),e(c),_(()=>{b.disabled=t(it),v(R,t(it)?"Starting...":"Force Start (skip ready)")}),d(a,c)};f(Pt,a=>{t(n).state==="PLAYING"&&a(re)})}var Rt=s(Pt,2);{var ae=a=>{const o=g(()=>t(n).participants.find(m=>m.teamId===t(n).winnerId));var l=ze(),c=r(l),p=s(r(c),2),h=r(p),P=r(h,!0);e(h),et(),e(p);var b=s(p,2),R=r(b);e(b);var u=s(b,2);rt(u,21,()=>t(n).games,at,(m,y)=>{const L=g(()=>q.data.beatmapCache[t(y).slot?.beatmapId]),k=g(()=>t(n).participants.find(S=>S.id===t(y).winnerParticipantId));var B=We(),I=r(B),$=r(I);e(I);var O=s(I,2),T=r(O,!0);e(O);var M=s(O,2),Y=r(M,!0);e(M),e(B),_(S=>{F(I,1,`font-600 ${S??""}`),v($,`${t(y).slot?.category??""}${t(y).slot?.orderInCategory??""}`),v(T,t(L)?`${t(L).artist} - ${t(L).title}`:`#${t(y).slot?.beatmapId}`),F(M,1,`font-600 ${t(k)?.id===t(D)?.id?"text-blue-400":"text-red-400"}`),v(Y,t(k)?.team.name)},[()=>xt[t(y).slot?.category]?.split(" ")[1]??"text-text-secondary"]),d(m,B)}),e(u),et(2),e(c),e(l),_(()=>{v(P,t(o)?.team.name),v(R,`${t(D)?.score??""} – ${t(j)?.score??""}`)}),d(a,l)};f(Rt,a=>{t(n).state==="FINISHED"&&a(ae)})}var Gt=s(Rt,2);{var se=a=>{var o=rr(),l=s(r(o),2);rt(l,21,()=>t(n).games,at,(c,p)=>{const h=g(()=>q.data.beatmapCache[t(p).slot?.beatmapId]),P=g(()=>t(n).participants.find(x=>x.id===t(p).pickedByParticipantId)?.team),b=g(()=>t(n).participants.find(x=>x.id===t(p).winnerParticipantId)?.team);var R=er(),u=r(R),m=r(u,!0);e(u);var y=s(u,2);{var L=x=>{var C=qe();_(()=>Q(C,"src",t(h).listCoverUrl)),d(x,C)};f(y,x=>{t(h)?.listCoverUrl&&x(L)})}var k=s(y,2),B=r(k);{var I=x=>{var C=Je(),A=r(C),U=s(A),K=r(U);e(U),e(C),_(()=>{v(A,`${t(h).artist??""} - ${t(h).title??""} `),v(K,`[${t(h).version??""}]`)}),d(x,C)};f(B,x=>{t(h)&&x(I)})}var $=s(B,2),O=r($),T=r(O);e(O);var M=s(O,2);{var Y=x=>{var C=Qe(),A=r(C);e(C),_(()=>v(A,`Picked by ${t(P).name??""}`)),d(x,C)};f(M,x=>{t(P)&&x(Y)})}e($),e(k);var S=s(k,2);{var N=x=>{const C=g(()=>t(p).scores.filter(H=>H.player?.participantId===t(D).id).reduce((H,z)=>H+z.score,0)),A=g(()=>t(p).scores.filter(H=>H.player?.participantId===t(j).id).reduce((H,z)=>H+z.score,0));var U=Xe(),K=r(U),yt=r(K,!0);e(K);var X=s(K,4),Z=r(X,!0);e(X),e(U),_((H,z)=>{F(K,1,t(C)>t(A)?"font-700 text-green-400":"text-text-secondary"),v(yt,H),F(X,1,t(A)>t(C)?"font-700 text-green-400":"text-text-secondary"),v(Z,z)},[()=>t(C).toLocaleString(),()=>t(A).toLocaleString()]),d(x,U)},G=x=>{var C=Ze();d(x,C)};f(S,x=>{t(p).state==="FINISHED"&&t(D)&&t(j)?x(N):t(p).state==="PLAYING"&&x(G,1)})}var V=s(S,2);{var J=x=>{var C=tr(),A=r(C);e(C),_(()=>v(A,`✓ ${t(b).name??""}`)),d(x,C)};f(V,x=>{t(b)&&x(J)})}e(R),_(()=>{v(m,t(p).gameNumber),F(O,1,`rounded border px-1.5 py-0.5 ${xt[t(p).slot?.category]??"border-border"??""}`),v(T,`${t(p).slot?.category??""}${t(p).slot?.orderInCategory??""}`)}),d(c,R)}),e(l),e(o),d(a,o)};f(Gt,a=>{t(n).games.length>0&&a(se)})}var St=s(Gt,2);{var oe=a=>{var o=ar();d(a,o)};f(St,a=>{t(n).state==="CREATED"&&a(oe)})}var Et=s(St,2);{var ne=a=>{var o=or(),l=s(r(o),2);{var c=p=>{var h=sr(),P=r(h),b=r(P);e(P),e(h),_(()=>{Q(P,"href",`https://osu.ppy.sh/mp/${t(n).osuLobbyId??""}`),v(b,`osu! mp/${t(n).osuLobbyId??""}`)}),d(p,h)};f(l,p=>{t(n).osuLobbyId&&p(c)})}e(o),d(a,o)};f(Et,a=>{t(n).state==="LOBBY"&&a(ne)})}var de=s(Et,2);{var ie=a=>{var o=nr();d(a,o)};f(de,a=>{t(n).state==="CANCELLED"&&a(ie)})}e(_t),_((a,o)=>{v(Mt,t(n).name||"Match"),v(Lt,`Best of ${t(ht).bestOf??""} · First to ${t(pt)??""} `),F(lt,1,`rounded border px-2.5 py-1 text-xs font-600 ${a??""}`),v(Wt,o)},[()=>Ut(t(n).state),()=>Tt(t(n).state)]),d(Dt,_t),me()}ue(["click"]);export{ur as component}; diff --git a/.svelte-kit/output/client/_app/immutable/nodes/9.BTBc_Eli.js b/.svelte-kit/output/client/_app/immutable/nodes/9.BTBc_Eli.js deleted file mode 100644 index 07cdc33..0000000 --- a/.svelte-kit/output/client/_app/immutable/nodes/9.BTBc_Eli.js +++ /dev/null @@ -1 +0,0 @@ -import"../chunks/DsnmJJEf.js";import{p as lt,t as l,a as o,b as vt,d as n,s as d,e as t,r as e,n as v,k as c,l as D,g as G}from"../chunks/BxEwC6Zc.js";import{s as i}from"../chunks/DoLu9QLy.js";import{i as k}from"../chunks/BQKoxf2Q.js";import{a as ct,e as xt}from"../chunks/BAocuFgQ.js";import{s as H}from"../chunks/BnX5ZnVA.js";import{s as ft}from"../chunks/BqOsL1Vv.js";var mt=n(''),pt=n('
'),ut=n('Linked'),gt=n('Connect'),_t=n('

Settings

Your profile and account settings

Connected Accounts

🎮

osu!

Ranked Stats

ELO Rating

Wins

Losses

Win Rate

Account

');function At(I,r){lt(r,!0);const L={player:{label:"Player",color:"bg-surface-600 text-text-secondary"},referee:{label:"Referee",color:"bg-yellow-500/20 text-yellow-400"},admin:{label:"Admin",color:"bg-red-500/20 text-red-400"}},R=D(()=>L[r.data.profile.role]??L.player),A=D(()=>r.data.rating.wins+r.data.rating.losses>0?(r.data.rating.wins/(r.data.rating.wins+r.data.rating.losses)*100).toFixed(1):"—");var x=_t(),f=d(t(x),4),m=t(f),C=t(m);{var J=a=>{var s=mt();l(()=>{H(s,"src",r.data.profile.image),H(s,"alt",r.data.profile.name)}),o(a,s)},K=a=>{var s=pt(),ot=t(s,!0);e(s),l(nt=>i(ot,nt),[()=>r.data.profile.name.charAt(0).toUpperCase()]),o(a,s)};k(C,a=>{r.data.profile.image?a(J):a(K,!1)})}var O=d(C,2),p=t(O),u=t(p),M=t(u,!0);e(u);var g=d(u,2),Q=t(g,!0);e(g),e(p);var S=d(p,2),T=t(S,!0);e(S),e(O),e(m);var W=d(m,2),j=d(t(W),2),_=d(t(j),2),B=d(t(_),2),V=t(B);{var X=a=>{var s=G();l(()=>i(s,`Connected as ${r.data.profile.name??""}`)),o(a,s)},Z=a=>{var s=G("Not connected");o(a,s)};k(V,a=>{r.data.hasOsuLinked?a(X):a(Z,!1)})}e(B),e(_);var $=d(_,2);{var tt=a=>{var s=ut();o(a,s)},et=a=>{var s=gt();o(a,s)};k($,a=>{r.data.hasOsuLinked?a(tt):a(et,!1)})}e(j),e(W),e(f);var b=d(f,2),E=d(t(b),2),h=t(E),F=t(h),at=t(F,!0);e(F),v(2),e(h);var y=d(h,2),N=t(y),rt=t(N,!0);e(N),v(2),e(y);var w=d(y,2),P=t(w),st=t(P,!0);e(P),v(2),e(w);var U=d(w,2),Y=t(U),dt=t(Y);e(Y),v(2),e(U),e(E),e(b);var q=d(b,2),z=d(t(q),2),it=t(z);ct(it,a=>xt?.(a)),e(z),e(q),e(x),l(()=>{i(M,r.data.profile.name),ft(g,1,`rounded px-2 py-0.5 text-xs font-600 ${c(R).color??""}`),i(Q,c(R).label),i(T,r.data.profile.email),i(at,r.data.rating.elo),i(rt,r.data.rating.wins),i(st,r.data.rating.losses),i(dt,`${c(A)??""}${c(A)!=="—"?"%":""}`)}),o(I,x),vt()}export{At as component}; diff --git a/.svelte-kit/output/client/_app/version.json b/.svelte-kit/output/client/_app/version.json deleted file mode 100644 index 0e8f73c..0000000 --- a/.svelte-kit/output/client/_app/version.json +++ /dev/null @@ -1 +0,0 @@ -{"version":"1772254297287"} \ No newline at end of file diff --git a/.svelte-kit/output/client/android-chrome-192x192.png b/.svelte-kit/output/client/android-chrome-192x192.png deleted file mode 100644 index e15a9ab..0000000 Binary files a/.svelte-kit/output/client/android-chrome-192x192.png and /dev/null differ diff --git a/.svelte-kit/output/client/android-chrome-512x512.png b/.svelte-kit/output/client/android-chrome-512x512.png deleted file mode 100644 index 58bc4cb..0000000 Binary files a/.svelte-kit/output/client/android-chrome-512x512.png and /dev/null differ diff --git a/.svelte-kit/output/client/apple-touch-icon.png b/.svelte-kit/output/client/apple-touch-icon.png deleted file mode 100644 index fb8b64b..0000000 Binary files a/.svelte-kit/output/client/apple-touch-icon.png and /dev/null differ diff --git a/.svelte-kit/output/client/favicon-16x16.png b/.svelte-kit/output/client/favicon-16x16.png deleted file mode 100644 index 6700c23..0000000 Binary files a/.svelte-kit/output/client/favicon-16x16.png and /dev/null differ diff --git a/.svelte-kit/output/client/favicon-32x32.png b/.svelte-kit/output/client/favicon-32x32.png deleted file mode 100644 index 7837088..0000000 Binary files a/.svelte-kit/output/client/favicon-32x32.png and /dev/null differ diff --git a/.svelte-kit/output/client/favicon.ico b/.svelte-kit/output/client/favicon.ico deleted file mode 100644 index 2c9e68f..0000000 Binary files a/.svelte-kit/output/client/favicon.ico and /dev/null differ diff --git a/.svelte-kit/output/client/robots.txt b/.svelte-kit/output/client/robots.txt deleted file mode 100644 index b6dd667..0000000 --- a/.svelte-kit/output/client/robots.txt +++ /dev/null @@ -1,3 +0,0 @@ -# allow crawling everything by default -User-agent: * -Disallow: diff --git a/.svelte-kit/output/client/site.webmanifest b/.svelte-kit/output/client/site.webmanifest deleted file mode 100644 index 45dc8a2..0000000 --- a/.svelte-kit/output/client/site.webmanifest +++ /dev/null @@ -1 +0,0 @@ -{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file diff --git a/.svelte-kit/output/server/.vite/manifest.json b/.svelte-kit/output/server/.vite/manifest.json deleted file mode 100644 index 36de7fb..0000000 --- a/.svelte-kit/output/server/.vite/manifest.json +++ /dev/null @@ -1,661 +0,0 @@ -{ - ".svelte-kit/generated/server/internal.js": { - "file": "internal.js", - "name": "internal", - "src": ".svelte-kit/generated/server/internal.js", - "isEntry": true, - "imports": [ - "_root.js", - "_environment.js", - "_server.js", - "_internal.js", - "_shared-server.js" - ] - }, - "_api.js": { - "file": "chunks/api.js", - "name": "api", - "imports": [ - "_shared-server.js", - "_index2.js" - ] - }, - "_auth.js": { - "file": "chunks/auth.js", - "name": "auth", - "imports": [ - "_shared-server.js", - "_url.js", - "_root.js", - "_utils.js", - "_query.js", - "_index2.js" - ], - "dynamicImports": [ - "node_modules/better-auth/dist/adapters/memory-adapter/index.mjs", - "node_modules/better-auth/dist/adapters/kysely-adapter/index.mjs", - "node_modules/better-auth/dist/adapters/kysely-adapter/index.mjs", - "node_modules/better-auth/dist/adapters/kysely-adapter/bun-sqlite-dialect.mjs", - "node_modules/better-auth/dist/adapters/kysely-adapter/node-sqlite-dialect.mjs" - ] - }, - "_engine.js": { - "file": "chunks/engine.js", - "name": "engine", - "imports": [ - "_index2.js" - ] - }, - "_environment.js": { - "file": "chunks/environment.js", - "name": "environment" - }, - "_exports.js": { - "file": "chunks/exports.js", - "name": "exports" - }, - "_false.js": { - "file": "chunks/false.js", - "name": "false" - }, - "_index.js": { - "file": "chunks/index.js", - "name": "index", - "imports": [ - "_index3.js", - "_root.js" - ] - }, - "_index2.js": { - "file": "chunks/index2.js", - "name": "index", - "imports": [ - "_shared-server.js" - ] - }, - "_index3.js": { - "file": "chunks/index3.js", - "name": "index" - }, - "_index4.js": { - "file": "chunks/index4.js", - "name": "index", - "imports": [ - "_state.svelte.js", - "_url.js", - "_utils.js", - "_index.js", - "_root.js", - "_exports.js", - "_index3.js" - ] - }, - "_internal.js": { - "file": "chunks/internal.js", - "name": "internal", - "imports": [ - "_root.js", - "_environment.js", - "_server.js", - "_shared-server.js" - ], - "dynamicImports": [ - "src/hooks.server.ts" - ] - }, - "_orchestrator.js": { - "file": "chunks/orchestrator.js", - "name": "orchestrator", - "imports": [ - "_index2.js", - "_engine.js", - "_shared-server.js" - ] - }, - "_query.js": { - "file": "chunks/query.js", - "name": "query", - "imports": [ - "_shared.js", - "_environment.js" - ] - }, - "_root.js": { - "file": "chunks/root.js", - "name": "root", - "imports": [ - "_index3.js", - "_false.js" - ] - }, - "_routing.js": { - "file": "chunks/routing.js", - "name": "routing", - "imports": [ - "_url.js" - ] - }, - "_server.js": { - "file": "chunks/server.js", - "name": "server" - }, - "_shared-server.js": { - "file": "chunks/shared-server.js", - "name": "shared-server" - }, - "_shared.js": { - "file": "chunks/shared.js", - "name": "shared", - "imports": [ - "_utils.js" - ] - }, - "_state.svelte.js": { - "file": "chunks/state.svelte.js", - "name": "state.svelte", - "imports": [ - "_index3.js", - "_url.js", - "_root.js" - ] - }, - "_url.js": { - "file": "chunks/url.js", - "name": "url" - }, - "_utils.js": { - "file": "chunks/utils.js", - "name": "utils" - }, - "node_modules/@sveltejs/kit/src/runtime/app/server/remote/index.js": { - "file": "remote-entry.js", - "name": "remote-entry", - "src": "node_modules/@sveltejs/kit/src/runtime/app/server/remote/index.js", - "isEntry": true, - "imports": [ - "_query.js", - "_shared.js", - "_false.js", - "_server.js" - ] - }, - "node_modules/@sveltejs/kit/src/runtime/components/svelte-5/layout.svelte": { - "file": "entries/fallbacks/layout.svelte.js", - "name": "entries/fallbacks/layout.svelte", - "src": "node_modules/@sveltejs/kit/src/runtime/components/svelte-5/layout.svelte", - "isEntry": true - }, - "node_modules/@sveltejs/kit/src/runtime/server/index.js": { - "file": "index.js", - "name": "index", - "src": "node_modules/@sveltejs/kit/src/runtime/server/index.js", - "isEntry": true, - "imports": [ - "_false.js", - "_server.js", - "_shared.js", - "_url.js", - "_utils.js", - "_index.js", - "_shared-server.js", - "_routing.js", - "_exports.js", - "_internal.js" - ] - }, - "node_modules/better-auth/dist/adapters/kysely-adapter/bun-sqlite-dialect.mjs": { - "file": "chunks/bun-sqlite-dialect.js", - "name": "bun-sqlite-dialect", - "src": "node_modules/better-auth/dist/adapters/kysely-adapter/bun-sqlite-dialect.mjs", - "isDynamicEntry": true - }, - "node_modules/better-auth/dist/adapters/kysely-adapter/index.mjs": { - "file": "chunks/index6.js", - "name": "index", - "src": "node_modules/better-auth/dist/adapters/kysely-adapter/index.mjs", - "isDynamicEntry": true, - "imports": [ - "_auth.js" - ] - }, - "node_modules/better-auth/dist/adapters/kysely-adapter/node-sqlite-dialect.mjs": { - "file": "chunks/node-sqlite-dialect.js", - "name": "node-sqlite-dialect", - "src": "node_modules/better-auth/dist/adapters/kysely-adapter/node-sqlite-dialect.mjs", - "isDynamicEntry": true - }, - "node_modules/better-auth/dist/adapters/memory-adapter/index.mjs": { - "file": "chunks/index5.js", - "name": "index", - "src": "node_modules/better-auth/dist/adapters/memory-adapter/index.mjs", - "isDynamicEntry": true - }, - "src/hooks.server.ts": { - "file": "entries/hooks.server.js", - "name": "entries/hooks.server", - "src": "src/hooks.server.ts", - "isEntry": true, - "isDynamicEntry": true, - "imports": [ - "_environment.js", - "_auth.js", - "_index2.js" - ] - }, - "src/routes/(app)/+layout.server.ts": { - "file": "entries/pages/(app)/_layout.server.ts.js", - "name": "entries/pages/(app)/_layout.server.ts", - "src": "src/routes/(app)/+layout.server.ts", - "isEntry": true - }, - "src/routes/(app)/+layout.svelte": { - "file": "entries/pages/(app)/_layout.svelte.js", - "name": "entries/pages/(app)/_layout.svelte", - "src": "src/routes/(app)/+layout.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_index4.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ], - "css": [ - "_app/immutable/assets/_layout.Dv2no-8m.css" - ] - }, - "src/routes/(app)/+page.server.ts": { - "file": "entries/pages/(app)/_page.server.ts.js", - "name": "entries/pages/(app)/_page.server.ts", - "src": "src/routes/(app)/+page.server.ts", - "isEntry": true, - "imports": [ - "_index2.js" - ] - }, - "src/routes/(app)/+page.svelte": { - "file": "entries/pages/(app)/_page.svelte.js", - "name": "entries/pages/(app)/_page.svelte", - "src": "src/routes/(app)/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js" - ] - }, - "src/routes/(app)/admin/+page.server.ts": { - "file": "entries/pages/(app)/admin/_page.server.ts.js", - "name": "entries/pages/(app)/admin/_page.server.ts", - "src": "src/routes/(app)/admin/+page.server.ts", - "isEntry": true, - "imports": [ - "_index2.js" - ] - }, - "src/routes/(app)/admin/+page.svelte": { - "file": "entries/pages/(app)/admin/_page.svelte.js", - "name": "entries/pages/(app)/admin/_page.svelte", - "src": "src/routes/(app)/admin/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ] - }, - "src/routes/(app)/mappools/+page.server.ts": { - "file": "entries/pages/(app)/mappools/_page.server.ts.js", - "name": "entries/pages/(app)/mappools/_page.server.ts", - "src": "src/routes/(app)/mappools/+page.server.ts", - "isEntry": true, - "imports": [ - "_index2.js" - ] - }, - "src/routes/(app)/mappools/+page.svelte": { - "file": "entries/pages/(app)/mappools/_page.svelte.js", - "name": "entries/pages/(app)/mappools/_page.svelte", - "src": "src/routes/(app)/mappools/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ] - }, - "src/routes/(app)/mappools/[id]/+page.server.ts": { - "file": "entries/pages/(app)/mappools/_id_/_page.server.ts.js", - "name": "entries/pages/(app)/mappools/_id_/_page.server.ts", - "src": "src/routes/(app)/mappools/[id]/+page.server.ts", - "isEntry": true, - "imports": [ - "_index2.js", - "_api.js" - ] - }, - "src/routes/(app)/mappools/[id]/+page.svelte": { - "file": "entries/pages/(app)/mappools/_id_/_page.svelte.js", - "name": "entries/pages/(app)/mappools/_id_/_page.svelte", - "src": "src/routes/(app)/mappools/[id]/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ] - }, - "src/routes/(app)/matches/+page.server.ts": { - "file": "entries/pages/(app)/matches/_page.server.ts.js", - "name": "entries/pages/(app)/matches/_page.server.ts", - "src": "src/routes/(app)/matches/+page.server.ts", - "isEntry": true, - "imports": [ - "_index2.js", - "_engine.js", - "_orchestrator.js" - ] - }, - "src/routes/(app)/matches/+page.svelte": { - "file": "entries/pages/(app)/matches/_page.svelte.js", - "name": "entries/pages/(app)/matches/_page.svelte", - "src": "src/routes/(app)/matches/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ] - }, - "src/routes/(app)/matches/[id]/+page.server.ts": { - "file": "entries/pages/(app)/matches/_id_/_page.server.ts.js", - "name": "entries/pages/(app)/matches/_id_/_page.server.ts", - "src": "src/routes/(app)/matches/[id]/+page.server.ts", - "isEntry": true, - "imports": [ - "_index2.js", - "_engine.js", - "_orchestrator.js", - "_api.js" - ] - }, - "src/routes/(app)/matches/[id]/+page.svelte": { - "file": "entries/pages/(app)/matches/_id_/_page.svelte.js", - "name": "entries/pages/(app)/matches/_id_/_page.svelte", - "src": "src/routes/(app)/matches/[id]/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ] - }, - "src/routes/(app)/settings/+page.server.ts": { - "file": "entries/pages/(app)/settings/_page.server.ts.js", - "name": "entries/pages/(app)/settings/_page.server.ts", - "src": "src/routes/(app)/settings/+page.server.ts", - "isEntry": true, - "imports": [ - "_auth.js", - "_index2.js" - ] - }, - "src/routes/(app)/settings/+page.svelte": { - "file": "entries/pages/(app)/settings/_page.svelte.js", - "name": "entries/pages/(app)/settings/_page.svelte", - "src": "src/routes/(app)/settings/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ] - }, - "src/routes/(app)/teams/+page.server.ts": { - "file": "entries/pages/(app)/teams/_page.server.ts.js", - "name": "entries/pages/(app)/teams/_page.server.ts", - "src": "src/routes/(app)/teams/+page.server.ts", - "isEntry": true, - "imports": [ - "_index2.js" - ] - }, - "src/routes/(app)/teams/+page.svelte": { - "file": "entries/pages/(app)/teams/_page.svelte.js", - "name": "entries/pages/(app)/teams/_page.svelte", - "src": "src/routes/(app)/teams/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ] - }, - "src/routes/+error.svelte": { - "file": "entries/pages/_error.svelte.js", - "name": "entries/pages/_error.svelte", - "src": "src/routes/+error.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_index4.js" - ] - }, - "src/routes/api/health/+server.ts": { - "file": "entries/endpoints/api/health/_server.ts.js", - "name": "entries/endpoints/api/health/_server.ts", - "src": "src/routes/api/health/+server.ts", - "isEntry": true, - "imports": [ - "_index2.js" - ] - }, - "src/routes/api/mappools/+server.ts": { - "file": "entries/endpoints/api/mappools/_server.ts.js", - "name": "entries/endpoints/api/mappools/_server.ts", - "src": "src/routes/api/mappools/+server.ts", - "isEntry": true, - "imports": [ - "_index2.js" - ] - }, - "src/routes/api/mappools/[id]/+server.ts": { - "file": "entries/endpoints/api/mappools/_id_/_server.ts.js", - "name": "entries/endpoints/api/mappools/_id_/_server.ts", - "src": "src/routes/api/mappools/[id]/+server.ts", - "isEntry": true, - "imports": [ - "_index2.js" - ] - }, - "src/routes/api/mappools/[id]/slots/+server.ts": { - "file": "entries/endpoints/api/mappools/_id_/slots/_server.ts.js", - "name": "entries/endpoints/api/mappools/_id_/slots/_server.ts", - "src": "src/routes/api/mappools/[id]/slots/+server.ts", - "isEntry": true, - "imports": [ - "_index2.js" - ] - }, - "src/routes/api/mappools/[id]/slots/[slotId]/+server.ts": { - "file": "entries/endpoints/api/mappools/_id_/slots/_slotId_/_server.ts.js", - "name": "entries/endpoints/api/mappools/_id_/slots/_slotId_/_server.ts", - "src": "src/routes/api/mappools/[id]/slots/[slotId]/+server.ts", - "isEntry": true, - "imports": [ - "_index2.js" - ] - }, - "src/routes/api/matches/+server.ts": { - "file": "entries/endpoints/api/matches/_server.ts.js", - "name": "entries/endpoints/api/matches/_server.ts", - "src": "src/routes/api/matches/+server.ts", - "isEntry": true, - "imports": [ - "_index2.js", - "_engine.js" - ] - }, - "src/routes/api/matches/[id]/+server.ts": { - "file": "entries/endpoints/api/matches/_id_/_server.ts.js", - "name": "entries/endpoints/api/matches/_id_/_server.ts", - "src": "src/routes/api/matches/[id]/+server.ts", - "isEntry": true, - "imports": [ - "_engine.js" - ] - }, - "src/routes/api/matches/[id]/lobby/+server.ts": { - "file": "entries/endpoints/api/matches/_id_/lobby/_server.ts.js", - "name": "entries/endpoints/api/matches/_id_/lobby/_server.ts", - "src": "src/routes/api/matches/[id]/lobby/+server.ts", - "isEntry": true, - "imports": [ - "_engine.js" - ] - }, - "src/routes/api/matches/[id]/pick/+server.ts": { - "file": "entries/endpoints/api/matches/_id_/pick/_server.ts.js", - "name": "entries/endpoints/api/matches/_id_/pick/_server.ts", - "src": "src/routes/api/matches/[id]/pick/+server.ts", - "isEntry": true, - "imports": [ - "_engine.js" - ] - }, - "src/routes/api/matches/[id]/roll/+server.ts": { - "file": "entries/endpoints/api/matches/_id_/roll/_server.ts.js", - "name": "entries/endpoints/api/matches/_id_/roll/_server.ts", - "src": "src/routes/api/matches/[id]/roll/+server.ts", - "isEntry": true, - "imports": [ - "_engine.js" - ] - }, - "src/routes/api/matches/[id]/rolling/+server.ts": { - "file": "entries/endpoints/api/matches/_id_/rolling/_server.ts.js", - "name": "entries/endpoints/api/matches/_id_/rolling/_server.ts", - "src": "src/routes/api/matches/[id]/rolling/+server.ts", - "isEntry": true, - "imports": [ - "_engine.js" - ] - }, - "src/routes/api/matches/[id]/score/+server.ts": { - "file": "entries/endpoints/api/matches/_id_/score/_server.ts.js", - "name": "entries/endpoints/api/matches/_id_/score/_server.ts", - "src": "src/routes/api/matches/[id]/score/+server.ts", - "isEntry": true, - "imports": [ - "_engine.js" - ] - }, - "src/routes/api/osu/beatmap/[id]/+server.ts": { - "file": "entries/endpoints/api/osu/beatmap/_id_/_server.ts.js", - "name": "entries/endpoints/api/osu/beatmap/_id_/_server.ts", - "src": "src/routes/api/osu/beatmap/[id]/+server.ts", - "isEntry": true, - "imports": [ - "_api.js" - ] - }, - "src/routes/api/queue/+server.ts": { - "file": "entries/endpoints/api/queue/_server.ts.js", - "name": "entries/endpoints/api/queue/_server.ts", - "src": "src/routes/api/queue/+server.ts", - "isEntry": true, - "imports": [ - "_engine.js", - "_index2.js" - ] - }, - "src/routes/demo/+page.svelte": { - "file": "entries/pages/demo/_page.svelte.js", - "name": "entries/pages/demo/_page.svelte", - "src": "src/routes/demo/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_server.js", - "_routing.js", - "_url.js", - "_root.js" - ] - }, - "src/routes/demo/better-auth/+page.server.ts": { - "file": "entries/pages/demo/better-auth/_page.server.ts.js", - "name": "entries/pages/demo/better-auth/_page.server.ts", - "src": "src/routes/demo/better-auth/+page.server.ts", - "isEntry": true, - "imports": [ - "_auth.js" - ] - }, - "src/routes/demo/better-auth/+page.svelte": { - "file": "entries/pages/demo/better-auth/_page.svelte.js", - "name": "entries/pages/demo/better-auth/_page.svelte", - "src": "src/routes/demo/better-auth/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ] - }, - "src/routes/demo/better-auth/login/+page.server.ts": { - "file": "entries/pages/demo/better-auth/login/_page.server.ts.js", - "name": "entries/pages/demo/better-auth/login/_page.server.ts", - "src": "src/routes/demo/better-auth/login/+page.server.ts", - "isEntry": true, - "imports": [ - "_auth.js" - ] - }, - "src/routes/demo/better-auth/login/+page.svelte": { - "file": "entries/pages/demo/better-auth/login/_page.svelte.js", - "name": "entries/pages/demo/better-auth/login/_page.svelte", - "src": "src/routes/demo/better-auth/login/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ] - }, - "src/routes/login/+page.server.ts": { - "file": "entries/pages/login/_page.server.ts.js", - "name": "entries/pages/login/_page.server.ts", - "src": "src/routes/login/+page.server.ts", - "isEntry": true, - "imports": [ - "_auth.js" - ] - } -} \ No newline at end of file diff --git a/.svelte-kit/output/server/_app/immutable/assets/_layout.Dv2no-8m.css b/.svelte-kit/output/server/_app/immutable/assets/_layout.Dv2no-8m.css deleted file mode 100644 index d32e9ae..0000000 --- a/.svelte-kit/output/server/_app/immutable/assets/_layout.Dv2no-8m.css +++ /dev/null @@ -1 +0,0 @@ -@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:"Geist Mono", ui-monospace, monospace;--color-red-400:oklch(70.4% .191 22.216);--color-red-500:oklch(63.7% .237 25.331);--color-yellow-400:oklch(85.2% .199 91.936);--color-yellow-500:oklch(79.5% .184 86.047);--color-green-400:oklch(79.2% .209 151.711);--color-green-500:oklch(72.3% .219 149.579);--color-blue-400:oklch(70.7% .165 254.624);--color-blue-500:oklch(62.3% .214 259.815);--color-blue-600:oklch(54.6% .245 262.881);--color-blue-700:oklch(48.8% .243 264.376);--color-purple-400:oklch(71.4% .203 305.504);--color-purple-500:oklch(62.7% .265 303.9);--color-pink-400:oklch(71.8% .202 349.761);--color-pink-500:oklch(65.6% .241 354.308);--color-gray-300:oklch(87.2% .01 258.338);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-md:28rem;--container-2xl:42rem;--container-3xl:48rem;--container-4xl:56rem;--container-5xl:64rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height: 1.5 ;--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height: 1.2 ;--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--text-6xl:3.75rem;--text-6xl--line-height:1;--tracking-tight:-.025em;--tracking-wider:.05em;--tracking-widest:.1em;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--animate-ping:ping 1s cubic-bezier(0, 0, .2, 1) infinite;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--blur-sm:8px;--blur-md:12px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-surface-900:#0a0a0f;--color-surface-800:#12121a;--color-surface-700:#1a1a25;--color-surface-600:#24243a;--color-accent:#ff66ab;--color-accent-hover:#ff85be;--color-accent-dim:#ff66ab33;--color-text-primary:#eeeef0;--color-text-secondary:#8888a0;--color-border:#2a2a3d;--font-body:"Geist", system-ui, sans-serif}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing) * 0)}.start{inset-inline-start:var(--spacing)}.top-0{top:calc(var(--spacing) * 0)}.left-0{left:calc(var(--spacing) * 0)}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.col-span-2{grid-column:span 2/span 2}.mx-auto{margin-inline:auto}.my-4{margin-block:calc(var(--spacing) * 4)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.ml-56{margin-left:calc(var(--spacing) * 56)}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline-block{display:inline-block}.table{display:table}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-2{height:calc(var(--spacing) * 2)}.h-3{height:calc(var(--spacing) * 3)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-10{height:calc(var(--spacing) * 10)}.h-12{height:calc(var(--spacing) * 12)}.h-14{height:calc(var(--spacing) * 14)}.h-16{height:calc(var(--spacing) * 16)}.h-full{height:100%}.max-h-\[80vh\]{max-height:80vh}.min-h-\[70vh\]{min-height:70vh}.min-h-dvh{min-height:100dvh}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-2{width:calc(var(--spacing) * 2)}.w-3{width:calc(var(--spacing) * 3)}.w-6{width:calc(var(--spacing) * 6)}.w-7{width:calc(var(--spacing) * 7)}.w-8{width:calc(var(--spacing) * 8)}.w-10{width:calc(var(--spacing) * 10)}.w-16{width:calc(var(--spacing) * 16)}.w-20{width:calc(var(--spacing) * 20)}.w-24{width:calc(var(--spacing) * 24)}.w-56{width:calc(var(--spacing) * 56)}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-3xl{max-width:var(--container-3xl)}.max-w-4xl{max-width:var(--container-4xl)}.max-w-5xl{max-width:var(--container-5xl)}.max-w-md{max-width:var(--container-md)}.min-w-0{min-width:calc(var(--spacing) * 0)}.flex-1{flex:1}.rotate-90{rotate:90deg}.animate-ping{animation:var(--animate-ping)}.animate-pulse{animation:var(--animate-pulse)}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-\[auto_1fr_auto_auto_auto\]{grid-template-columns:auto 1fr auto auto auto}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-6{gap:calc(var(--spacing) * 6)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-accent\/20{border-color:#ff66ab33}@supports (color:color-mix(in lab,red,red)){.border-accent\/20{border-color:color-mix(in oklab,var(--color-accent) 20%,transparent)}}.border-accent\/30{border-color:#ff66ab4d}@supports (color:color-mix(in lab,red,red)){.border-accent\/30{border-color:color-mix(in oklab,var(--color-accent) 30%,transparent)}}.border-blue-500\/30{border-color:#3080ff4d}@supports (color:color-mix(in lab,red,red)){.border-blue-500\/30{border-color:color-mix(in oklab,var(--color-blue-500) 30%,transparent)}}.border-border{border-color:var(--color-border)}.border-border\/50{border-color:#2a2a3d80}@supports (color:color-mix(in lab,red,red)){.border-border\/50{border-color:color-mix(in oklab,var(--color-border) 50%,transparent)}}.border-gray-300{border-color:var(--color-gray-300)}.border-green-500\/20{border-color:#00c75833}@supports (color:color-mix(in lab,red,red)){.border-green-500\/20{border-color:color-mix(in oklab,var(--color-green-500) 20%,transparent)}}.border-green-500\/30{border-color:#00c7584d}@supports (color:color-mix(in lab,red,red)){.border-green-500\/30{border-color:color-mix(in oklab,var(--color-green-500) 30%,transparent)}}.border-green-500\/40{border-color:#00c75866}@supports (color:color-mix(in lab,red,red)){.border-green-500\/40{border-color:color-mix(in oklab,var(--color-green-500) 40%,transparent)}}.border-pink-500\/30{border-color:#f6339a4d}@supports (color:color-mix(in lab,red,red)){.border-pink-500\/30{border-color:color-mix(in oklab,var(--color-pink-500) 30%,transparent)}}.border-purple-500\/30{border-color:#ac4bff4d}@supports (color:color-mix(in lab,red,red)){.border-purple-500\/30{border-color:color-mix(in oklab,var(--color-purple-500) 30%,transparent)}}.border-red-500\/30{border-color:#fb2c364d}@supports (color:color-mix(in lab,red,red)){.border-red-500\/30{border-color:color-mix(in oklab,var(--color-red-500) 30%,transparent)}}.border-yellow-500\/30{border-color:#edb2004d}@supports (color:color-mix(in lab,red,red)){.border-yellow-500\/30{border-color:color-mix(in oklab,var(--color-yellow-500) 30%,transparent)}}.bg-accent{background-color:var(--color-accent)}.bg-accent-dim{background-color:var(--color-accent-dim)}.bg-accent\/10{background-color:#ff66ab1a}@supports (color:color-mix(in lab,red,red)){.bg-accent\/10{background-color:color-mix(in oklab,var(--color-accent) 10%,transparent)}}.bg-black\/70{background-color:#000000b3}@supports (color:color-mix(in lab,red,red)){.bg-black\/70{background-color:color-mix(in oklab,var(--color-black) 70%,transparent)}}.bg-blue-400{background-color:var(--color-blue-400)}.bg-blue-500\/10{background-color:#3080ff1a}@supports (color:color-mix(in lab,red,red)){.bg-blue-500\/10{background-color:color-mix(in oklab,var(--color-blue-500) 10%,transparent)}}.bg-blue-500\/20{background-color:#3080ff33}@supports (color:color-mix(in lab,red,red)){.bg-blue-500\/20{background-color:color-mix(in oklab,var(--color-blue-500) 20%,transparent)}}.bg-blue-600{background-color:var(--color-blue-600)}.bg-green-400{background-color:var(--color-green-400)}.bg-green-500\/5{background-color:#00c7580d}@supports (color:color-mix(in lab,red,red)){.bg-green-500\/5{background-color:color-mix(in oklab,var(--color-green-500) 5%,transparent)}}.bg-green-500\/20{background-color:#00c75833}@supports (color:color-mix(in lab,red,red)){.bg-green-500\/20{background-color:color-mix(in oklab,var(--color-green-500) 20%,transparent)}}.bg-pink-500\/20{background-color:#f6339a33}@supports (color:color-mix(in lab,red,red)){.bg-pink-500\/20{background-color:color-mix(in oklab,var(--color-pink-500) 20%,transparent)}}.bg-purple-500\/10{background-color:#ac4bff1a}@supports (color:color-mix(in lab,red,red)){.bg-purple-500\/10{background-color:color-mix(in oklab,var(--color-purple-500) 10%,transparent)}}.bg-purple-500\/20{background-color:#ac4bff33}@supports (color:color-mix(in lab,red,red)){.bg-purple-500\/20{background-color:color-mix(in oklab,var(--color-purple-500) 20%,transparent)}}.bg-red-500\/5{background-color:#fb2c360d}@supports (color:color-mix(in lab,red,red)){.bg-red-500\/5{background-color:color-mix(in oklab,var(--color-red-500) 5%,transparent)}}.bg-red-500\/10{background-color:#fb2c361a}@supports (color:color-mix(in lab,red,red)){.bg-red-500\/10{background-color:color-mix(in oklab,var(--color-red-500) 10%,transparent)}}.bg-red-500\/20{background-color:#fb2c3633}@supports (color:color-mix(in lab,red,red)){.bg-red-500\/20{background-color:color-mix(in oklab,var(--color-red-500) 20%,transparent)}}.bg-surface-600{background-color:var(--color-surface-600)}.bg-surface-700{background-color:var(--color-surface-700)}.bg-surface-800{background-color:var(--color-surface-800)}.bg-surface-900{background-color:var(--color-surface-900)}.bg-surface-900\/80{background-color:#0a0a0fcc}@supports (color:color-mix(in lab,red,red)){.bg-surface-900\/80{background-color:color-mix(in oklab,var(--color-surface-900) 80%,transparent)}}.bg-transparent{background-color:#0000}.bg-white{background-color:var(--color-white)}.bg-yellow-400{background-color:var(--color-yellow-400)}.bg-yellow-500\/5{background-color:#edb2000d}@supports (color:color-mix(in lab,red,red)){.bg-yellow-500\/5{background-color:color-mix(in oklab,var(--color-yellow-500) 5%,transparent)}}.bg-yellow-500\/20{background-color:#edb20033}@supports (color:color-mix(in lab,red,red)){.bg-yellow-500\/20{background-color:color-mix(in oklab,var(--color-yellow-500) 20%,transparent)}}.object-cover{object-fit:cover}.p-1{padding:calc(var(--spacing) * 1)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-3\.5{padding-inline:calc(var(--spacing) * 3.5)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.px-8{padding-inline:calc(var(--spacing) * 8)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-5{padding-block:calc(var(--spacing) * 5)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-12{padding-block:calc(var(--spacing) * 12)}.pt-3{padding-top:calc(var(--spacing) * 3)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.text-accent{color:var(--color-accent)}.text-blue-400{color:var(--color-blue-400)}.text-green-400{color:var(--color-green-400)}.text-pink-400{color:var(--color-pink-400)}.text-purple-400{color:var(--color-purple-400)}.text-red-400{color:var(--color-red-400)}.text-red-500{color:var(--color-red-500)}.text-surface-900{color:var(--color-surface-900)}.text-text-primary{color:var(--color-text-primary)}.text-text-secondary{color:var(--color-text-secondary)}.text-text-secondary\/30{color:#8888a04d}@supports (color:color-mix(in lab,red,red)){.text-text-secondary\/30{color:color-mix(in oklab,var(--color-text-secondary) 30%,transparent)}}.text-white{color:var(--color-white)}.text-yellow-400{color:var(--color-yellow-400)}.uppercase{text-transform:uppercase}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.opacity-0{opacity:0}.opacity-30{opacity:.3}.opacity-50{opacity:.5}.opacity-75{opacity:.75}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.backdrop-blur-md{--tw-backdrop-blur:blur(var(--blur-md));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-blur-sm{--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media(hover:hover){.group-hover\:text-accent:is(:where(.group):hover *){color:var(--color-accent)}.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}.placeholder\:text-text-secondary\/50::placeholder{color:#8888a080}@supports (color:color-mix(in lab,red,red)){.placeholder\:text-text-secondary\/50::placeholder{color:color-mix(in oklab,var(--color-text-secondary) 50%,transparent)}}.last\:border-b-0:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}@media(hover:hover){.hover\:border-accent:hover{border-color:var(--color-accent)}.hover\:border-accent\/30:hover{border-color:#ff66ab4d}@supports (color:color-mix(in lab,red,red)){.hover\:border-accent\/30:hover{border-color:color-mix(in oklab,var(--color-accent) 30%,transparent)}}.hover\:border-accent\/40:hover{border-color:#ff66ab66}@supports (color:color-mix(in lab,red,red)){.hover\:border-accent\/40:hover{border-color:color-mix(in oklab,var(--color-accent) 40%,transparent)}}.hover\:border-green-500\/40:hover{border-color:#00c75866}@supports (color:color-mix(in lab,red,red)){.hover\:border-green-500\/40:hover{border-color:color-mix(in oklab,var(--color-green-500) 40%,transparent)}}.hover\:border-red-500\/30:hover{border-color:#fb2c364d}@supports (color:color-mix(in lab,red,red)){.hover\:border-red-500\/30:hover{border-color:color-mix(in oklab,var(--color-red-500) 30%,transparent)}}.hover\:bg-accent-hover:hover{background-color:var(--color-accent-hover)}.hover\:bg-blue-700:hover{background-color:var(--color-blue-700)}.hover\:bg-red-500\/10:hover{background-color:#fb2c361a}@supports (color:color-mix(in lab,red,red)){.hover\:bg-red-500\/10:hover{background-color:color-mix(in oklab,var(--color-red-500) 10%,transparent)}}.hover\:bg-surface-600:hover{background-color:var(--color-surface-600)}.hover\:bg-surface-700:hover{background-color:var(--color-surface-700)}.hover\:bg-yellow-500\/10:hover{background-color:#edb2001a}@supports (color:color-mix(in lab,red,red)){.hover\:bg-yellow-500\/10:hover{background-color:color-mix(in oklab,var(--color-yellow-500) 10%,transparent)}}.hover\:text-accent:hover{color:var(--color-accent)}.hover\:text-red-400:hover{color:var(--color-red-400)}.hover\:text-text-primary:hover{color:var(--color-text-primary)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}}.focus\:border-accent:focus{border-color:var(--color-accent)}.focus\:border-blue-500:focus{border-color:var(--color-blue-500)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-blue-500:focus{--tw-ring-color:var(--color-blue-500)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.disabled\:opacity-50:disabled{opacity:.5}@media(min-width:40rem){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}@media(min-width:64rem){.lg\:col-span-1{grid-column:span 1/span 1}.lg\:col-span-2{grid-column:span 2/span 2}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}}html{background-color:var(--color-surface-900);color:var(--color-text-primary);font-family:var(--font-body)}body{min-height:100dvh}::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:var(--color-surface-900)}::-webkit-scrollbar-thumb{background:var(--color-surface-600);border-radius:3px}::-webkit-scrollbar-thumb:hover{background:var(--color-accent)}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@keyframes ping{75%,to{opacity:0;transform:scale(2)}}@keyframes pulse{50%{opacity:.5}} diff --git a/.svelte-kit/output/server/chunks/api.js b/.svelte-kit/output/server/chunks/api.js deleted file mode 100644 index 5e6cc8c..0000000 --- a/.svelte-kit/output/server/chunks/api.js +++ /dev/null @@ -1,69 +0,0 @@ -import { b as private_env } from "./shared-server.js"; -import "./index2.js"; -const CACHE_TTL = 10 * 60 * 1e3; -const MAX_ENTRIES = 500; -const cache = /* @__PURE__ */ new Map(); -function getCached(key) { - const entry = cache.get(key); - if (!entry) return null; - if (Date.now() > entry.expiresAt) { - cache.delete(key); - return null; - } - return entry.data; -} -function setCache(key, data, ttl = CACHE_TTL) { - if (cache.size >= MAX_ENTRIES) { - const firstKey = cache.keys().next().value; - if (firstKey) cache.delete(firstKey); - } - cache.set(key, { data, expiresAt: Date.now() + ttl }); -} -let clientToken = null; -let clientTokenExpiresAt = 0; -async function getClientToken() { - if (clientToken && Date.now() < clientTokenExpiresAt - 6e4) { - return clientToken; - } - const res = await fetch("https://osu.ppy.sh/oauth/token", { - method: "POST", - headers: { - Accept: "application/json", - "Content-Type": "application/x-www-form-urlencoded" - }, - body: new URLSearchParams({ - client_id: private_env.OSU_CLIENT_ID, - client_secret: private_env.OSU_CLIENT_SECRET, - grant_type: "client_credentials", - scope: "identify public" - }) - }); - if (!res.ok) { - throw new Error(`Failed to get osu! client token: ${res.status} ${res.statusText}`); - } - const data = await res.json(); - clientToken = data.access_token; - clientTokenExpiresAt = Date.now() + data.expires_in * 1e3; - return clientToken; -} -async function osuFetch(path, token) { - const t = await getClientToken(); - const res = await fetch(`https://osu.ppy.sh/api/v2${path}`, { - headers: { Authorization: `Bearer ${t}` } - }); - if (!res.ok) { - throw new Error(`osu! API ${path}: ${res.status} ${res.statusText}`); - } - return res.json(); -} -async function getBeatmap(beatmapId) { - const cacheKey = `beatmap:${beatmapId}`; - const cached = getCached(cacheKey); - if (cached) return cached; - const data = await osuFetch(`/beatmaps/${beatmapId}`); - setCache(cacheKey, data); - return data; -} -export { - getBeatmap as g -}; diff --git a/.svelte-kit/output/server/chunks/auth.js b/.svelte-kit/output/server/chunks/auth.js deleted file mode 100644 index 588593c..0000000 --- a/.svelte-kit/output/server/chunks/auth.js +++ /dev/null @@ -1,7983 +0,0 @@ -import { env, isTest, isDevelopment, logger, createLogger, isProduction, shouldPublishLog } from "@better-auth/core/env"; -import { BetterAuthError, BASE_ERROR_CODES } from "@better-auth/core/error"; -import { isValidIP, normalizeIP, deprecate, normalizePathname, createRateLimitKey, safeJSONParse, generateId, filterOutputFields, defineErrorCodes } from "@better-auth/core/utils"; -import { defineRequestState, getCurrentAuthContext, getCurrentAdapter, runWithTransaction, hasRequestState, runWithRequestState, runWithEndpointContext, runWithAdapter, getBetterAuthVersion } from "@better-auth/core/context"; -import { APIError, toResponse, createRouter } from "better-call"; -import { createAuthMiddleware, createAuthEndpoint } from "@better-auth/core/api"; -import * as import___better_auth_core_db from "@better-auth/core/db"; -import { getAuthTables } from "@better-auth/core/db"; -import * as z from "zod"; -import { Kysely, SqliteDialect, MysqlDialect, PostgresDialect, MssqlDialect, sql } from "kysely"; -import { initGetModelName, initGetFieldName, createAdapterFactory } from "@better-auth/core/db/adapter"; -import { hkdf } from "@noble/hashes/hkdf.js"; -import { sha256 } from "@noble/hashes/sha2.js"; -import { jwtDecrypt, calculateJwkThumbprint, base64url, jwtVerify, EncryptJWT, SignJWT, decodeJwt } from "jose"; -import { hex } from "@better-auth/utils/hex"; -import { createRandomStringGenerator } from "@better-auth/utils/random"; -import "@better-auth/utils"; -import { createHash } from "@better-auth/utils/hash"; -import { base64Url } from "@better-auth/utils/base64"; -import { binary } from "@better-auth/utils/binary"; -import { createHMAC } from "@better-auth/utils/hmac"; -import { xchacha20poly1305 } from "@noble/ciphers/chacha.js"; -import { hexToBytes as hexToBytes$1, managedNonce, utf8ToBytes, bytesToHex } from "@noble/ciphers/utils.js"; -import { SocialProviderListEnum, socialProviders } from "@better-auth/core/social-providers"; -import { JWTExpired } from "jose/errors"; -import defu$1, { createDefu, defu } from "defu"; -import { scryptAsync } from "@noble/hashes/scrypt.js"; -import { hexToBytes } from "@noble/hashes/utils.js"; -import { createTelemetry } from "@better-auth/telemetry"; -import { count, desc, asc, inArray, notInArray, like, lt, lte, ne, gt, gte, eq, and, or, sql as sql$1 } from "drizzle-orm"; -import { b as private_env } from "./shared-server.js"; -import "./url.js"; -import { getRequestEvent } from "@sveltejs/kit/internal/server"; -import "./root.js"; -import "./utils.js"; -import "@sveltejs/kit"; -import "@sveltejs/kit/internal"; -import "./query.js"; -import { d as db, c as team, t as teamMember } from "./index2.js"; -import { betterFetch } from "@better-fetch/fetch"; -import { createAuthorizationURL, validateAuthorizationCode, refreshAccessToken } from "@better-auth/core/oauth2"; -import "@better-auth/utils/otp"; -function checkHasPath(url) { - try { - return (new URL(url).pathname.replace(/\/+$/, "") || "/") !== "/"; - } catch { - throw new BetterAuthError(`Invalid base URL: ${url}. Please provide a valid base URL.`); - } -} -function assertHasProtocol(url) { - try { - const parsedUrl = new URL(url); - if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") throw new BetterAuthError(`Invalid base URL: ${url}. URL must include 'http://' or 'https://'`); - } catch (error2) { - if (error2 instanceof BetterAuthError) throw error2; - throw new BetterAuthError(`Invalid base URL: ${url}. Please provide a valid base URL.`, { cause: error2 }); - } -} -function withPath(url, path = "/api/auth") { - assertHasProtocol(url); - if (checkHasPath(url)) return url; - const trimmedUrl = url.replace(/\/+$/, ""); - if (!path || path === "/") return trimmedUrl; - path = path.startsWith("/") ? path : `/${path}`; - return `${trimmedUrl}${path}`; -} -function validateProxyHeader(header, type) { - if (!header || header.trim() === "") return false; - if (type === "proto") return header === "http" || header === "https"; - if (type === "host") { - if ([ - /\.\./, - /\0/, - /[\s]/, - /^[.]/, - /[<>'"]/, - /javascript:/i, - /file:/i, - /data:/i - ].some((pattern) => pattern.test(header))) return false; - return /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*(:[0-9]{1,5})?$/.test(header) || /^(\d{1,3}\.){3}\d{1,3}(:[0-9]{1,5})?$/.test(header) || /^\[[0-9a-fA-F:]+\](:[0-9]{1,5})?$/.test(header) || /^localhost(:[0-9]{1,5})?$/i.test(header); - } - return false; -} -function getBaseURL(url, path, request, loadEnv, trustedProxyHeaders) { - if (url) return withPath(url, path); - { - const fromEnv = env.BETTER_AUTH_URL || env.NEXT_PUBLIC_BETTER_AUTH_URL || env.PUBLIC_BETTER_AUTH_URL || env.NUXT_PUBLIC_BETTER_AUTH_URL || env.NUXT_PUBLIC_AUTH_URL || (env.BASE_URL !== "/" ? env.BASE_URL : void 0); - if (fromEnv) return withPath(fromEnv, path); - } - const fromRequest = request?.headers.get("x-forwarded-host"); - const fromRequestProto = request?.headers.get("x-forwarded-proto"); - if (fromRequest && fromRequestProto && trustedProxyHeaders) { - if (validateProxyHeader(fromRequestProto, "proto") && validateProxyHeader(fromRequest, "host")) try { - return withPath(`${fromRequestProto}://${fromRequest}`, path); - } catch (_error) { - } - } - if (request) { - const url$1 = getOrigin(request.url); - if (!url$1) throw new BetterAuthError("Could not get origin from request. Please provide a valid base URL."); - return withPath(url$1, path); - } - if (typeof window !== "undefined" && window.location) return withPath(window.location.origin, path); -} -function getOrigin(url) { - try { - const parsedUrl = new URL(url); - return parsedUrl.origin === "null" ? null : parsedUrl.origin; - } catch { - return null; - } -} -function getProtocol(url) { - try { - return new URL(url).protocol; - } catch { - return null; - } -} -function getHost(url) { - try { - return new URL(url).host; - } catch { - return null; - } -} -const LOCALHOST_IP = "127.0.0.1"; -function getIp(req, options) { - if (options.advanced?.ipAddress?.disableIpTracking) return null; - const headers = "headers" in req ? req.headers : req; - const ipHeaders = options.advanced?.ipAddress?.ipAddressHeaders || ["x-forwarded-for"]; - for (const key of ipHeaders) { - const value = "get" in headers ? headers.get(key) : headers[key]; - if (typeof value === "string") { - const ip = value.split(",")[0].trim(); - if (isValidIP(ip)) return normalizeIP(ip, { ipv6Subnet: options.advanced?.ipAddress?.ipv6Subnet }); - } - } - if (isTest() || isDevelopment()) return LOCALHOST_IP; - return null; -} -const { get: getOAuthState, set: setOAuthState } = defineRequestState(() => null); -function escapeRegExpChar(char) { - if (char === "-" || char === "^" || char === "$" || char === "+" || char === "." || char === "(" || char === ")" || char === "|" || char === "[" || char === "]" || char === "{" || char === "}" || char === "*" || char === "?" || char === "\\") return `\\${char}`; - else return char; -} -function escapeRegExpString(str) { - let result = ""; - for (let i = 0; i < str.length; i++) result += escapeRegExpChar(str[i]); - return result; -} -function transform(pattern, separator = true) { - if (Array.isArray(pattern)) return `(?:${pattern.map((p) => `^${transform(p, separator)}$`).join("|")})`; - let separatorSplitter = ""; - let separatorMatcher = ""; - let wildcard = "."; - if (separator === true) { - separatorSplitter = "/"; - separatorMatcher = "[/\\\\]"; - wildcard = "[^/\\\\]"; - } else if (separator) { - separatorSplitter = separator; - separatorMatcher = escapeRegExpString(separatorSplitter); - if (separatorMatcher.length > 1) { - separatorMatcher = `(?:${separatorMatcher})`; - wildcard = `((?!${separatorMatcher}).)`; - } else wildcard = `[^${separatorMatcher}]`; - } - const requiredSeparator = separator ? `${separatorMatcher}+?` : ""; - const optionalSeparator = separator ? `${separatorMatcher}*?` : ""; - const segments = separator ? pattern.split(separatorSplitter) : [pattern]; - let result = ""; - for (let s = 0; s < segments.length; s++) { - const segment = segments[s]; - const nextSegment = segments[s + 1]; - let currentSeparator = ""; - if (!segment && s > 0) continue; - if (separator) if (s === segments.length - 1) currentSeparator = optionalSeparator; - else if (nextSegment !== "**") currentSeparator = requiredSeparator; - else currentSeparator = ""; - if (separator && segment === "**") { - if (currentSeparator) { - result += s === 0 ? "" : currentSeparator; - result += `(?:${wildcard}*?${currentSeparator})*?`; - } - continue; - } - for (let c = 0; c < segment.length; c++) { - const char = segment[c]; - if (char === "\\") { - if (c < segment.length - 1) { - result += escapeRegExpChar(segment[c + 1]); - c++; - } - } else if (char === "?") result += wildcard; - else if (char === "*") result += `${wildcard}*?`; - else result += escapeRegExpChar(char); - } - result += currentSeparator; - } - return result; -} -function isMatch(regexp, sample) { - if (typeof sample !== "string") throw new TypeError(`Sample must be a string, but ${typeof sample} given`); - return regexp.test(sample); -} -function wildcardMatch(pattern, options) { - if (typeof pattern !== "string" && !Array.isArray(pattern)) throw new TypeError(`The first argument must be a single pattern string or an array of patterns, but ${typeof pattern} given`); - if (typeof options === "string" || typeof options === "boolean") options = { separator: options }; - if (arguments.length === 2 && !(typeof options === "undefined" || typeof options === "object" && options !== null && !Array.isArray(options))) throw new TypeError(`The second argument must be an options object or a string/boolean separator, but ${typeof options} given`); - options = options || {}; - if (options.separator === "\\") throw new Error("\\ is not a valid separator because it is used for escaping. Try setting the separator to `true` instead"); - const regexpPattern = transform(pattern, options.separator); - const regexp = new RegExp(`^${regexpPattern}$`, options.flags); - const fn = isMatch.bind(null, regexp); - fn.options = options; - fn.pattern = pattern; - fn.regexp = regexp; - return fn; -} -const matchesOriginPattern = (url, pattern, settings) => { - if (url.startsWith("/")) { - if (settings?.allowRelativePaths) return url.startsWith("/") && /^\/(?!\/|\\|%2f|%5c)[\w\-.\+/@]*(?:\?[\w\-.\+/=&%@]*)?$/.test(url); - return false; - } - if (pattern.includes("*") || pattern.includes("?")) { - if (pattern.includes("://")) return wildcardMatch(pattern)(getOrigin(url) || url); - const host = getHost(url); - if (!host) return false; - return wildcardMatch(pattern)(host); - } - const protocol = getProtocol(url); - return protocol === "http:" || protocol === "https:" || !protocol ? pattern === getOrigin(url) : url.startsWith(pattern); -}; -function shouldSkipCSRFForBackwardCompat(ctx) { - return ctx.context.skipOriginCheck === true && ctx.context.options.advanced?.disableCSRFCheck === void 0; -} -const logBackwardCompatWarning = deprecate(function logBackwardCompatWarning$1() { -}, "disableOriginCheck: true currently also disables CSRF checks. In a future version, disableOriginCheck will ONLY disable URL validation. To keep CSRF disabled, add disableCSRFCheck: true to your config."); -const originCheckMiddleware = createAuthMiddleware(async (ctx) => { - if (ctx.request?.method === "GET" || ctx.request?.method === "OPTIONS" || ctx.request?.method === "HEAD" || !ctx.request) return; - await validateOrigin(ctx); - if (ctx.context.skipOriginCheck) return; - const { body, query } = ctx; - const callbackURL = body?.callbackURL || query?.callbackURL; - const redirectURL = body?.redirectTo; - const errorCallbackURL = body?.errorCallbackURL; - const newUserCallbackURL = body?.newUserCallbackURL; - const validateURL = (url, label) => { - if (!url) return; - if (!ctx.context.isTrustedOrigin(url, { allowRelativePaths: label !== "origin" })) { - ctx.context.logger.error(`Invalid ${label}: ${url}`); - ctx.context.logger.info(`If it's a valid URL, please add ${url} to trustedOrigins in your auth config -`, `Current list of trustedOrigins: ${ctx.context.trustedOrigins}`); - throw new APIError("FORBIDDEN", { message: `Invalid ${label}` }); - } - }; - callbackURL && validateURL(callbackURL, "callbackURL"); - redirectURL && validateURL(redirectURL, "redirectURL"); - errorCallbackURL && validateURL(errorCallbackURL, "errorCallbackURL"); - newUserCallbackURL && validateURL(newUserCallbackURL, "newUserCallbackURL"); -}); -const originCheck = (getValue) => createAuthMiddleware(async (ctx) => { - if (!ctx.request) return; - if (ctx.context.skipOriginCheck) return; - const callbackURL = getValue(ctx); - const validateURL = (url, label) => { - if (!url) return; - if (!ctx.context.isTrustedOrigin(url, { allowRelativePaths: label !== "origin" })) { - ctx.context.logger.error(`Invalid ${label}: ${url}`); - ctx.context.logger.info(`If it's a valid URL, please add ${url} to trustedOrigins in your auth config -`, `Current list of trustedOrigins: ${ctx.context.trustedOrigins}`); - throw new APIError("FORBIDDEN", { message: `Invalid ${label}` }); - } - }; - const callbacks = Array.isArray(callbackURL) ? callbackURL : [callbackURL]; - for (const url of callbacks) validateURL(url, "callbackURL"); -}); -async function validateOrigin(ctx, forceValidate = false) { - const headers = ctx.request?.headers; - if (!headers || !ctx.request) return; - const originHeader = headers.get("origin") || headers.get("referer") || ""; - const useCookies = headers.has("cookie"); - if (ctx.context.skipCSRFCheck) return; - if (shouldSkipCSRFForBackwardCompat(ctx)) { - ctx.context.options.advanced?.disableOriginCheck === true && logBackwardCompatWarning(); - return; - } - const skipOriginCheck = ctx.context.skipOriginCheck; - if (Array.isArray(skipOriginCheck)) try { - const basePath = new URL(ctx.context.baseURL).pathname; - const currentPath = normalizePathname(ctx.request.url, basePath); - if (skipOriginCheck.some((skipPath) => currentPath.startsWith(skipPath))) return; - } catch { - } - if (!(forceValidate || useCookies)) return; - if (!originHeader || originHeader === "null") throw new APIError("FORBIDDEN", { message: BASE_ERROR_CODES.MISSING_OR_NULL_ORIGIN }); - const trustedOrigins = Array.isArray(ctx.context.options.trustedOrigins) ? ctx.context.trustedOrigins : [...ctx.context.trustedOrigins, ...(await ctx.context.options.trustedOrigins?.(ctx.request))?.filter((v) => Boolean(v)) || []]; - if (!trustedOrigins.some((origin) => matchesOriginPattern(originHeader, origin))) { - ctx.context.logger.error(`Invalid origin: ${originHeader}`); - ctx.context.logger.info(`If it's a valid URL, please add ${originHeader} to trustedOrigins in your auth config -`, `Current list of trustedOrigins: ${trustedOrigins}`); - throw new APIError("FORBIDDEN", { message: "Invalid origin" }); - } -} -const formCsrfMiddleware = createAuthMiddleware(async (ctx) => { - if (!ctx.request) return; - await validateFormCsrf(ctx); -}); -async function validateFormCsrf(ctx) { - const req = ctx.request; - if (!req) return; - if (ctx.context.skipCSRFCheck) return; - if (shouldSkipCSRFForBackwardCompat(ctx)) return; - const headers = req.headers; - if (headers.has("cookie")) return await validateOrigin(ctx); - const site = headers.get("Sec-Fetch-Site"); - const mode = headers.get("Sec-Fetch-Mode"); - const dest = headers.get("Sec-Fetch-Dest"); - if (Boolean(site && site.trim() || mode && mode.trim() || dest && dest.trim())) { - if (site === "cross-site" && mode === "navigate") { - ctx.context.logger.error("Blocked cross-site navigation login attempt (CSRF protection)", { - secFetchSite: site, - secFetchMode: mode, - secFetchDest: dest - }); - throw new APIError("FORBIDDEN", { message: BASE_ERROR_CODES.CROSS_SITE_NAVIGATION_LOGIN_BLOCKED }); - } - return await validateOrigin(ctx, true); - } -} -const memory = /* @__PURE__ */ new Map(); -function shouldRateLimit(max, window2, rateLimitData) { - const now2 = Date.now(); - const windowInMs = window2 * 1e3; - return now2 - rateLimitData.lastRequest < windowInMs && rateLimitData.count >= max; -} -function rateLimitResponse(retryAfter) { - return new Response(JSON.stringify({ message: "Too many requests. Please try again later." }), { - status: 429, - statusText: "Too Many Requests", - headers: { "X-Retry-After": retryAfter.toString() } - }); -} -function getRetryAfter(lastRequest, window2) { - const now2 = Date.now(); - const windowInMs = window2 * 1e3; - return Math.ceil((lastRequest + windowInMs - now2) / 1e3); -} -function createDatabaseStorageWrapper(ctx) { - const model = "rateLimit"; - const db2 = ctx.adapter; - return { - get: async (key) => { - const data = (await db2.findMany({ - model, - where: [{ - field: "key", - value: key - }] - }))[0]; - if (typeof data?.lastRequest === "bigint") data.lastRequest = Number(data.lastRequest); - return data; - }, - set: async (key, value, _update) => { - try { - if (_update) await db2.updateMany({ - model, - where: [{ - field: "key", - value: key - }], - update: { - count: value.count, - lastRequest: value.lastRequest - } - }); - else await db2.create({ - model, - data: { - key, - count: value.count, - lastRequest: value.lastRequest - } - }); - } catch (e) { - ctx.logger.error("Error setting rate limit", e); - } - } - }; -} -function getRateLimitStorage(ctx, rateLimitSettings) { - if (ctx.options.rateLimit?.customStorage) return ctx.options.rateLimit.customStorage; - const storage = ctx.rateLimit.storage; - if (storage === "secondary-storage") return { - get: async (key) => { - const data = await ctx.options.secondaryStorage?.get(key); - return data ? safeJSONParse(data) : null; - }, - set: async (key, value, _update) => { - const ttl = rateLimitSettings?.window ?? ctx.options.rateLimit?.window ?? 10; - await ctx.options.secondaryStorage?.set?.(key, JSON.stringify(value), ttl); - } - }; - else if (storage === "memory") return { - async get(key) { - const entry = memory.get(key); - if (!entry) return null; - if (Date.now() >= entry.expiresAt) { - memory.delete(key); - return null; - } - return entry.data; - }, - async set(key, value, _update) { - const ttl = rateLimitSettings?.window ?? ctx.options.rateLimit?.window ?? 10; - const expiresAt = Date.now() + ttl * 1e3; - memory.set(key, { - data: value, - expiresAt - }); - } - }; - return createDatabaseStorageWrapper(ctx); -} -async function onRequestRateLimit(req, ctx) { - if (!ctx.rateLimit.enabled) return; - const basePath = new URL(ctx.baseURL).pathname; - const path = normalizePathname(req.url, basePath); - let currentWindow = ctx.rateLimit.window; - let currentMax = ctx.rateLimit.max; - const ip = getIp(req, ctx.options); - if (!ip) return; - const key = createRateLimitKey(ip, path); - const specialRule = getDefaultSpecialRules().find((rule) => rule.pathMatcher(path)); - if (specialRule) { - currentWindow = specialRule.window; - currentMax = specialRule.max; - } - for (const plugin of ctx.options.plugins || []) if (plugin.rateLimit) { - const matchedRule = plugin.rateLimit.find((rule) => rule.pathMatcher(path)); - if (matchedRule) { - currentWindow = matchedRule.window; - currentMax = matchedRule.max; - break; - } - } - if (ctx.rateLimit.customRules) { - const _path = Object.keys(ctx.rateLimit.customRules).find((p) => { - if (p.includes("*")) return wildcardMatch(p)(path); - return p === path; - }); - if (_path) { - const customRule = ctx.rateLimit.customRules[_path]; - const resolved = typeof customRule === "function" ? await customRule(req, { - window: currentWindow, - max: currentMax - }) : customRule; - if (resolved) { - currentWindow = resolved.window; - currentMax = resolved.max; - } - if (resolved === false) return; - } - } - const storage = getRateLimitStorage(ctx, { window: currentWindow }); - const data = await storage.get(key); - const now2 = Date.now(); - if (!data) await storage.set(key, { - key, - count: 1, - lastRequest: now2 - }); - else { - const timeSinceLastRequest = now2 - data.lastRequest; - if (shouldRateLimit(currentMax, currentWindow, data)) return rateLimitResponse(getRetryAfter(data.lastRequest, currentWindow)); - else if (timeSinceLastRequest > currentWindow * 1e3) await storage.set(key, { - ...data, - count: 1, - lastRequest: now2 - }, true); - else await storage.set(key, { - ...data, - count: data.count + 1, - lastRequest: now2 - }, true); - } -} -function getDefaultSpecialRules() { - return [{ - pathMatcher(path) { - return path.startsWith("/sign-in") || path.startsWith("/sign-up") || path.startsWith("/change-password") || path.startsWith("/change-email"); - }, - window: 10, - max: 3 - }]; -} -const getDate = (span, unit = "ms") => { - return new Date(Date.now() + (unit === "sec" ? span * 1e3 : span)); -}; -const cache = /* @__PURE__ */ new WeakMap(); -function parseOutputData(data, schema2) { - const fields = schema2.fields; - const parsedData = {}; - for (const key in data) { - const field = fields[key]; - if (!field) { - parsedData[key] = data[key]; - continue; - } - if (field.returned === false && key !== "id") continue; - parsedData[key] = data[key]; - } - return parsedData; -} -function getFields(options, table, mode) { - const cacheKey = `${table}:${mode}`; - if (!cache.has(options)) cache.set(options, /* @__PURE__ */ new Map()); - const tableCache = cache.get(options); - if (tableCache.has(cacheKey)) return tableCache.get(cacheKey); - const coreSchema = mode === "output" ? getAuthTables(options)[table]?.fields ?? {} : {}; - const additionalFields = table === "user" || table === "session" || table === "account" ? options[table]?.additionalFields : void 0; - let schema2 = { - ...coreSchema, - ...additionalFields ?? {} - }; - for (const plugin of options.plugins || []) if (plugin.schema && plugin.schema[table]) schema2 = { - ...schema2, - ...plugin.schema[table].fields - }; - tableCache.set(cacheKey, schema2); - return schema2; -} -function parseUserOutput(options, user) { - return parseOutputData(user, { fields: getFields(options, "user", "output") }); -} -function parseSessionOutput(options, session) { - return parseOutputData(session, { fields: getFields(options, "session", "output") }); -} -function parseAccountOutput(options, account) { - const { accessToken: _accessToken, refreshToken: _refreshToken, idToken: _idToken, accessTokenExpiresAt: _accessTokenExpiresAt, refreshTokenExpiresAt: _refreshTokenExpiresAt, password: _password, ...rest } = parseOutputData(account, { fields: getFields(options, "account", "output") }); - return rest; -} -function parseInputData(data, schema2) { - const action = schema2.action || "create"; - const fields = schema2.fields; - const parsedData = Object.assign(/* @__PURE__ */ Object.create(null), null); - for (const key in fields) { - if (key in data) { - if (fields[key].input === false) { - if (fields[key].defaultValue !== void 0) { - if (action !== "update") { - parsedData[key] = fields[key].defaultValue; - continue; - } - } - if (data[key]) throw new APIError("BAD_REQUEST", { message: `${key} is not allowed to be set` }); - continue; - } - if (fields[key].validator?.input && data[key] !== void 0) { - const result = fields[key].validator.input["~standard"].validate(data[key]); - if (result instanceof Promise) throw new APIError("INTERNAL_SERVER_ERROR", { message: "Async validation is not supported for additional fields" }); - if ("issues" in result && result.issues) throw new APIError("BAD_REQUEST", { message: result.issues[0]?.message || "Validation Error" }); - parsedData[key] = result.value; - continue; - } - if (fields[key].transform?.input && data[key] !== void 0) { - parsedData[key] = fields[key].transform?.input(data[key]); - continue; - } - parsedData[key] = data[key]; - continue; - } - if (fields[key].defaultValue !== void 0 && action === "create") { - if (typeof fields[key].defaultValue === "function") { - parsedData[key] = fields[key].defaultValue(); - continue; - } - parsedData[key] = fields[key].defaultValue; - continue; - } - if (fields[key].required && action === "create") throw new APIError("BAD_REQUEST", { message: `${key} is required` }); - } - return parsedData; -} -function parseUserInput(options, user = {}, action) { - return parseInputData(user, { - fields: getFields(options, "user", "input"), - action - }); -} -function parseAdditionalUserInput(options, user) { - const schema2 = getFields(options, "user", "input"); - return parseInputData(user || {}, { fields: schema2 }); -} -function parseAccountInput(options, account) { - return parseInputData(account, { fields: getFields(options, "account", "input") }); -} -function parseSessionInput(options, session) { - return parseInputData(session, { fields: getFields(options, "session", "input") }); -} -function mergeSchema(schema2, newSchema) { - if (!newSchema) return schema2; - for (const table in newSchema) { - const newModelName = newSchema[table]?.modelName; - if (newModelName) schema2[table].modelName = newModelName; - for (const field in schema2[table].fields) { - const newField = newSchema[table]?.fields?.[field]; - if (!newField) continue; - schema2[table].fields[field].fieldName = newField; - } - } - return schema2; -} -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (all, symbols) => { - let target = {}; - for (var name in all) { - __defProp(target, name, { - get: all[name], - enumerable: true - }); - } - return target; -}; -var __copyProps = (to, from, except, desc2) => { - if (from && typeof from === "object" || typeof from === "function") { - for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) { - key = keys[i]; - if (!__hasOwnProp.call(to, key) && key !== except) { - __defProp(to, key, { - get: ((k) => from[k]).bind(null, key), - enumerable: !(desc2 = __getOwnPropDesc(from, key)) || desc2.enumerable - }); - } - } - } - return to; -}; -var __reExport = (target, mod, secondTarget, symbols) => { - __copyProps(target, mod, "default"); -}; -async function getBaseAdapter(options, handleDirectDatabase) { - let adapter; - if (!options.database) { - const tables = getAuthTables(options); - const memoryDB = Object.keys(tables).reduce((acc, key) => { - acc[key] = []; - return acc; - }, {}); - const { memoryAdapter } = await import("./index5.js"); - adapter = memoryAdapter(memoryDB)(options); - } else if (typeof options.database === "function") adapter = options.database(options); - else adapter = await handleDirectDatabase(options); - if (!adapter.transaction) { - logger.warn("Adapter does not correctly implement transaction function, patching it automatically. Please update your adapter implementation."); - adapter.transaction = async (cb) => { - return cb(adapter); - }; - } - return adapter; -} -async function getAdapter(options) { - return getBaseAdapter(options, async (opts) => { - const { createKyselyAdapter: createKyselyAdapter2 } = await import("./index6.js"); - const { kysely, databaseType, transaction } = await createKyselyAdapter2(opts); - if (!kysely) throw new BetterAuthError("Failed to initialize database adapter"); - const { kyselyAdapter } = await import("./index6.js"); - return kyselyAdapter(kysely, { - type: databaseType || "sqlite", - debugLogs: opts.database && "debugLogs" in opts.database ? opts.database.debugLogs : false, - transaction - })(opts); - }); -} -const createFieldAttribute = (type, config2) => { - return { - type, - ...config2 - }; -}; -function convertToDB(fields, values) { - const result = values.id ? { id: values.id } : {}; - for (const key in fields) { - const field = fields[key]; - const value = values[key]; - if (value === void 0) continue; - result[field.fieldName || key] = value; - } - return result; -} -function convertFromDB(fields, values) { - if (!values) return null; - const result = { id: values.id }; - for (const [key, value] of Object.entries(fields)) result[key] = values[value.fieldName || key]; - return result; -} -function getWithHooks(adapter, ctx) { - const hooks = ctx.hooks; - async function createWithHooks(data, model, customCreateFn) { - const context = await getCurrentAuthContext().catch(() => null); - let actualData = data; - for (const hook of hooks || []) { - const toRun = hook[model]?.create?.before; - if (toRun) { - const result = await toRun(actualData, context); - if (result === false) return null; - if (typeof result === "object" && "data" in result) actualData = { - ...actualData, - ...result.data - }; - } - } - const customCreated = customCreateFn ? await customCreateFn.fn(actualData) : null; - const created = !customCreateFn || customCreateFn.executeMainFn ? await (await getCurrentAdapter(adapter)).create({ - model, - data: actualData, - forceAllowId: true - }) : customCreated; - for (const hook of hooks || []) { - const toRun = hook[model]?.create?.after; - if (toRun) await toRun(created, context); - } - return created; - } - async function updateWithHooks(data, where, model, customUpdateFn) { - const context = await getCurrentAuthContext().catch(() => null); - let actualData = data; - for (const hook of hooks || []) { - const toRun = hook[model]?.update?.before; - if (toRun) { - const result = await toRun(data, context); - if (result === false) return null; - if (typeof result === "object" && "data" in result) actualData = { - ...actualData, - ...result.data - }; - } - } - const customUpdated = customUpdateFn ? await customUpdateFn.fn(actualData) : null; - const updated = !customUpdateFn || customUpdateFn.executeMainFn ? await (await getCurrentAdapter(adapter)).update({ - model, - update: actualData, - where - }) : customUpdated; - for (const hook of hooks || []) { - const toRun = hook[model]?.update?.after; - if (toRun) await toRun(updated, context); - } - return updated; - } - async function updateManyWithHooks(data, where, model, customUpdateFn) { - const context = await getCurrentAuthContext().catch(() => null); - let actualData = data; - for (const hook of hooks || []) { - const toRun = hook[model]?.update?.before; - if (toRun) { - const result = await toRun(data, context); - if (result === false) return null; - if (typeof result === "object" && "data" in result) actualData = { - ...actualData, - ...result.data - }; - } - } - const customUpdated = customUpdateFn ? await customUpdateFn.fn(actualData) : null; - const updated = !customUpdateFn || customUpdateFn.executeMainFn ? await (await getCurrentAdapter(adapter)).updateMany({ - model, - update: actualData, - where - }) : customUpdated; - for (const hook of hooks || []) { - const toRun = hook[model]?.update?.after; - if (toRun) await toRun(updated, context); - } - return updated; - } - async function deleteWithHooks(where, model, customDeleteFn) { - const context = await getCurrentAuthContext().catch(() => null); - let entityToDelete = null; - try { - entityToDelete = (await (await getCurrentAdapter(adapter)).findMany({ - model, - where, - limit: 1 - }))[0] || null; - } catch { - } - if (entityToDelete) for (const hook of hooks || []) { - const toRun = hook[model]?.delete?.before; - if (toRun) { - if (await toRun(entityToDelete, context) === false) return null; - } - } - const customDeleted = customDeleteFn ? await customDeleteFn.fn(where) : null; - const deleted = !customDeleteFn || customDeleteFn.executeMainFn ? await (await getCurrentAdapter(adapter)).delete({ - model, - where - }) : customDeleted; - if (entityToDelete) for (const hook of hooks || []) { - const toRun = hook[model]?.delete?.after; - if (toRun) await toRun(entityToDelete, context); - } - return deleted; - } - async function deleteManyWithHooks(where, model, customDeleteFn) { - const context = await getCurrentAuthContext().catch(() => null); - let entitiesToDelete = []; - try { - entitiesToDelete = await (await getCurrentAdapter(adapter)).findMany({ - model, - where - }); - } catch { - } - for (const entity of entitiesToDelete) for (const hook of hooks || []) { - const toRun = hook[model]?.delete?.before; - if (toRun) { - if (await toRun(entity, context) === false) return null; - } - } - const customDeleted = customDeleteFn ? await customDeleteFn.fn(where) : null; - const deleted = !customDeleteFn || customDeleteFn.executeMainFn ? await (await getCurrentAdapter(adapter)).deleteMany({ - model, - where - }) : customDeleted; - for (const entity of entitiesToDelete) for (const hook of hooks || []) { - const toRun = hook[model]?.delete?.after; - if (toRun) await toRun(entity, context); - } - return deleted; - } - return { - createWithHooks, - updateWithHooks, - updateManyWithHooks, - deleteWithHooks, - deleteManyWithHooks - }; -} -const createInternalAdapter = (adapter, ctx) => { - const logger2 = ctx.logger; - const options = ctx.options; - const secondaryStorage = options.secondaryStorage; - const sessionExpiration = options.session?.expiresIn || 3600 * 24 * 7; - const { createWithHooks, updateWithHooks, updateManyWithHooks, deleteWithHooks, deleteManyWithHooks } = getWithHooks(adapter, ctx); - async function refreshUserSessions(user) { - if (!secondaryStorage) return; - const listRaw = await secondaryStorage.get(`active-sessions-${user.id}`); - if (!listRaw) return; - const now2 = Date.now(); - const validSessions = (safeJSONParse(listRaw) || []).filter((s) => s.expiresAt > now2); - await Promise.all(validSessions.map(async ({ token }) => { - const cached = await secondaryStorage.get(token); - if (!cached) return; - const parsed = safeJSONParse(cached); - if (!parsed) return; - const sessionTTL = Math.max(Math.floor(new Date(parsed.session.expiresAt).getTime() - now2) / 1e3, 0); - await secondaryStorage.set(token, JSON.stringify({ - session: parsed.session, - user - }), Math.floor(sessionTTL)); - })); - } - return { - createOAuthUser: async (user, account) => { - return runWithTransaction(adapter, async () => { - const createdUser = await createWithHooks({ - createdAt: /* @__PURE__ */ new Date(), - updatedAt: /* @__PURE__ */ new Date(), - ...user - }, "user", void 0); - return { - user: createdUser, - account: await createWithHooks({ - ...account, - userId: createdUser.id, - createdAt: /* @__PURE__ */ new Date(), - updatedAt: /* @__PURE__ */ new Date() - }, "account", void 0) - }; - }); - }, - createUser: async (user) => { - return await createWithHooks({ - createdAt: /* @__PURE__ */ new Date(), - updatedAt: /* @__PURE__ */ new Date(), - ...user, - email: user.email?.toLowerCase() - }, "user", void 0); - }, - createAccount: async (account) => { - return await createWithHooks({ - createdAt: /* @__PURE__ */ new Date(), - updatedAt: /* @__PURE__ */ new Date(), - ...account - }, "account", void 0); - }, - listSessions: async (userId) => { - if (secondaryStorage) { - const currentList = await secondaryStorage.get(`active-sessions-${userId}`); - if (!currentList) return []; - const list = safeJSONParse(currentList) || []; - const now2 = Date.now(); - const seenTokens = /* @__PURE__ */ new Set(); - const sessions = []; - for (const { token, expiresAt } of list) { - if (expiresAt <= now2 || seenTokens.has(token)) continue; - seenTokens.add(token); - const data = await secondaryStorage.get(token); - if (!data) continue; - try { - const parsed = typeof data === "string" ? JSON.parse(data) : data; - if (!parsed?.session) continue; - sessions.push(parseSessionOutput(ctx.options, { - ...parsed.session, - expiresAt: new Date(parsed.session.expiresAt) - })); - } catch { - continue; - } - } - return sessions; - } - return await (await getCurrentAdapter(adapter)).findMany({ - model: "session", - where: [{ - field: "userId", - value: userId - }] - }); - }, - listUsers: async (limit, offset, sortBy, where) => { - return await (await getCurrentAdapter(adapter)).findMany({ - model: "user", - limit, - offset, - sortBy, - where - }); - }, - countTotalUsers: async (where) => { - const total = await (await getCurrentAdapter(adapter)).count({ - model: "user", - where - }); - if (typeof total === "string") return parseInt(total); - return total; - }, - deleteUser: async (userId) => { - if (!secondaryStorage || options.session?.storeSessionInDatabase) await deleteManyWithHooks([{ - field: "userId", - value: userId - }], "session", void 0); - await deleteManyWithHooks([{ - field: "userId", - value: userId - }], "account", void 0); - await deleteWithHooks([{ - field: "id", - value: userId - }], "user", void 0); - }, - createSession: async (userId, dontRememberMe, override, overrideAll) => { - const ctx$1 = await getCurrentAuthContext().catch(() => null); - const headers = ctx$1?.headers || ctx$1?.request?.headers; - const { id: _, ...rest } = override || {}; - const defaultAdditionalFields = parseSessionInput(ctx$1?.context.options ?? options, {}); - const data = { - ipAddress: ctx$1?.request || ctx$1?.headers ? getIp(ctx$1?.request || ctx$1?.headers, ctx$1?.context.options) || "" : "", - userAgent: headers?.get("user-agent") || "", - ...rest, - expiresAt: dontRememberMe ? getDate(3600 * 24, "sec") : getDate(sessionExpiration, "sec"), - userId, - token: generateId(32), - createdAt: /* @__PURE__ */ new Date(), - updatedAt: /* @__PURE__ */ new Date(), - ...defaultAdditionalFields, - ...overrideAll ? rest : {} - }; - return await createWithHooks(data, "session", secondaryStorage ? { - fn: async (sessionData) => { - const currentList = await secondaryStorage.get(`active-sessions-${userId}`); - let list = []; - const now2 = Date.now(); - if (currentList) { - list = safeJSONParse(currentList) || []; - list = list.filter((session) => session.expiresAt > now2 && session.token !== data.token); - } - const sorted = [...list, { - token: data.token, - expiresAt: data.expiresAt.getTime() - }].sort((a, b) => a.expiresAt - b.expiresAt); - const furthestSessionExp = sorted.at(-1)?.expiresAt ?? data.expiresAt.getTime(); - const furthestSessionTTL = Math.max(Math.floor((furthestSessionExp - now2) / 1e3), 0); - if (furthestSessionTTL > 0) await secondaryStorage.set(`active-sessions-${userId}`, JSON.stringify(sorted), furthestSessionTTL); - const user = await (await getCurrentAdapter(adapter)).findOne({ - model: "user", - where: [{ - field: "id", - value: userId - }] - }); - const sessionTTL = Math.max(Math.floor((data.expiresAt.getTime() - now2) / 1e3), 0); - if (sessionTTL > 0) await secondaryStorage.set(data.token, JSON.stringify({ - session: sessionData, - user - }), sessionTTL); - return sessionData; - }, - executeMainFn: options.session?.storeSessionInDatabase - } : void 0); - }, - findSession: async (token) => { - if (secondaryStorage) { - const sessionStringified = await secondaryStorage.get(token); - if (!sessionStringified && !options.session?.storeSessionInDatabase) return null; - if (sessionStringified) { - const s = safeJSONParse(sessionStringified); - if (!s) return null; - return { - session: parseSessionOutput(ctx.options, { - ...s.session, - expiresAt: new Date(s.session.expiresAt), - createdAt: new Date(s.session.createdAt), - updatedAt: new Date(s.session.updatedAt) - }), - user: parseUserOutput(ctx.options, { - ...s.user, - createdAt: new Date(s.user.createdAt), - updatedAt: new Date(s.user.updatedAt) - }) - }; - } - } - const result = await (await getCurrentAdapter(adapter)).findOne({ - model: "session", - where: [{ - value: token, - field: "token" - }], - join: { user: true } - }); - if (!result) return null; - const { user, ...session } = result; - if (!user) return null; - return { - session: parseSessionOutput(ctx.options, session), - user: parseUserOutput(ctx.options, user) - }; - }, - findSessions: async (sessionTokens) => { - if (secondaryStorage) { - const sessions$1 = []; - for (const sessionToken of sessionTokens) { - const sessionStringified = await secondaryStorage.get(sessionToken); - if (sessionStringified) try { - const s = typeof sessionStringified === "string" ? JSON.parse(sessionStringified) : sessionStringified; - if (!s?.session) continue; - const session = { - session: { - ...s.session, - expiresAt: new Date(s.session.expiresAt) - }, - user: { - ...s.user, - createdAt: new Date(s.user.createdAt), - updatedAt: new Date(s.user.updatedAt) - } - }; - sessions$1.push(session); - } catch { - continue; - } - } - return sessions$1; - } - const sessions = await (await getCurrentAdapter(adapter)).findMany({ - model: "session", - where: [{ - field: "token", - value: sessionTokens, - operator: "in" - }], - join: { user: true } - }); - if (!sessions.length) return []; - if (sessions.some((session) => !session.user)) return []; - return sessions.map((_session) => { - const { user, ...session } = _session; - return { - session, - user - }; - }); - }, - updateSession: async (sessionToken, session) => { - return await updateWithHooks(session, [{ - field: "token", - value: sessionToken - }], "session", secondaryStorage ? { - async fn(data) { - const currentSession = await secondaryStorage.get(sessionToken); - if (!currentSession) return null; - const parsedSession = safeJSONParse(currentSession); - if (!parsedSession) return null; - const mergedSession = { - ...parsedSession.session, - ...data, - expiresAt: new Date(data.expiresAt ?? parsedSession.session.expiresAt), - createdAt: new Date(parsedSession.session.createdAt), - updatedAt: new Date(data.updatedAt ?? parsedSession.session.updatedAt) - }; - const updatedSession = parseSessionOutput(ctx.options, mergedSession); - const now2 = Date.now(); - const expiresMs = new Date(updatedSession.expiresAt).getTime(); - const sessionTTL = Math.max(Math.floor((expiresMs - now2) / 1e3), 0); - if (sessionTTL > 0) { - await secondaryStorage.set(sessionToken, JSON.stringify({ - session: updatedSession, - user: parsedSession.user - }), sessionTTL); - const listKey = `active-sessions-${updatedSession.userId}`; - const listRaw = await secondaryStorage.get(listKey); - const sorted = (listRaw ? safeJSONParse(listRaw) || [] : []).filter((s) => s.token !== sessionToken && s.expiresAt > now2).concat([{ - token: sessionToken, - expiresAt: expiresMs - }]).sort((a, b) => a.expiresAt - b.expiresAt); - const furthestSessionExp = sorted.at(-1)?.expiresAt; - if (furthestSessionExp && furthestSessionExp > now2) await secondaryStorage.set(listKey, JSON.stringify(sorted), Math.floor((furthestSessionExp - now2) / 1e3)); - else await secondaryStorage.delete(listKey); - } - return updatedSession; - }, - executeMainFn: options.session?.storeSessionInDatabase - } : void 0); - }, - deleteSession: async (token) => { - if (secondaryStorage) { - const data = await secondaryStorage.get(token); - if (data) { - const { session } = safeJSONParse(data) ?? {}; - if (!session) { - logger2.error("Session not found in secondary storage"); - return; - } - const userId = session.userId; - const currentList = await secondaryStorage.get(`active-sessions-${userId}`); - if (currentList) { - const list = safeJSONParse(currentList) || []; - const now2 = Date.now(); - const filtered = list.filter((session$1) => session$1.expiresAt > now2 && session$1.token !== token); - const furthestSessionExp = filtered.sort((a, b) => a.expiresAt - b.expiresAt).at(-1)?.expiresAt; - if (filtered.length > 0 && furthestSessionExp && furthestSessionExp > Date.now()) await secondaryStorage.set(`active-sessions-${userId}`, JSON.stringify(filtered), Math.floor((furthestSessionExp - now2) / 1e3)); - else await secondaryStorage.delete(`active-sessions-${userId}`); - } else logger2.error("Active sessions list not found in secondary storage"); - } - await secondaryStorage.delete(token); - if (!options.session?.storeSessionInDatabase || ctx.options.session?.preserveSessionInDatabase) return; - } - await deleteWithHooks([{ - field: "token", - value: token - }], "session", void 0); - }, - deleteAccounts: async (userId) => { - await deleteManyWithHooks([{ - field: "userId", - value: userId - }], "account", void 0); - }, - deleteAccount: async (accountId) => { - await deleteWithHooks([{ - field: "id", - value: accountId - }], "account", void 0); - }, - deleteSessions: async (userIdOrSessionTokens) => { - if (secondaryStorage) { - if (typeof userIdOrSessionTokens === "string") { - const activeSession = await secondaryStorage.get(`active-sessions-${userIdOrSessionTokens}`); - const sessions = activeSession ? safeJSONParse(activeSession) : []; - if (!sessions) return; - for (const session of sessions) await secondaryStorage.delete(session.token); - await secondaryStorage.delete(`active-sessions-${userIdOrSessionTokens}`); - } else for (const sessionToken of userIdOrSessionTokens) if (await secondaryStorage.get(sessionToken)) await secondaryStorage.delete(sessionToken); - if (!options.session?.storeSessionInDatabase || ctx.options.session?.preserveSessionInDatabase) return; - } - await deleteManyWithHooks([{ - field: Array.isArray(userIdOrSessionTokens) ? "token" : "userId", - value: userIdOrSessionTokens, - operator: Array.isArray(userIdOrSessionTokens) ? "in" : void 0 - }], "session", void 0); - }, - findOAuthUser: async (email, accountId, providerId) => { - const account = await (await getCurrentAdapter(adapter)).findOne({ - model: "account", - where: [{ - value: accountId, - field: "accountId" - }, { - value: providerId, - field: "providerId" - }], - join: { user: true } - }); - if (account) if (account.user) return { - user: account.user, - linkedAccount: account, - accounts: [account] - }; - else { - const user = await (await getCurrentAdapter(adapter)).findOne({ - model: "user", - where: [{ - value: email.toLowerCase(), - field: "email" - }] - }); - if (user) return { - user, - linkedAccount: account, - accounts: [account] - }; - return null; - } - else { - const user = await (await getCurrentAdapter(adapter)).findOne({ - model: "user", - where: [{ - value: email.toLowerCase(), - field: "email" - }] - }); - if (user) return { - user, - linkedAccount: null, - accounts: await (await getCurrentAdapter(adapter)).findMany({ - model: "account", - where: [{ - value: user.id, - field: "userId" - }] - }) || [] - }; - else return null; - } - }, - findUserByEmail: async (email, options$1) => { - const result = await (await getCurrentAdapter(adapter)).findOne({ - model: "user", - where: [{ - value: email.toLowerCase(), - field: "email" - }], - join: { ...options$1?.includeAccounts ? { account: true } : {} } - }); - if (!result) return null; - const { account: accounts, ...user } = result; - return { - user, - accounts: accounts ?? [] - }; - }, - findUserById: async (userId) => { - if (!userId) return null; - return await (await getCurrentAdapter(adapter)).findOne({ - model: "user", - where: [{ - field: "id", - value: userId - }] - }); - }, - linkAccount: async (account) => { - return await createWithHooks({ - createdAt: /* @__PURE__ */ new Date(), - updatedAt: /* @__PURE__ */ new Date(), - ...account - }, "account", void 0); - }, - updateUser: async (userId, data) => { - const user = await updateWithHooks(data, [{ - field: "id", - value: userId - }], "user", void 0); - await refreshUserSessions(user); - return user; - }, - updateUserByEmail: async (email, data) => { - const user = await updateWithHooks(data, [{ - field: "email", - value: email.toLowerCase() - }], "user", void 0); - await refreshUserSessions(user); - return user; - }, - updatePassword: async (userId, password) => { - await updateManyWithHooks({ password }, [{ - field: "userId", - value: userId - }, { - field: "providerId", - value: "credential" - }], "account", void 0); - }, - findAccounts: async (userId) => { - return await (await getCurrentAdapter(adapter)).findMany({ - model: "account", - where: [{ - field: "userId", - value: userId - }] - }); - }, - findAccount: async (accountId) => { - return await (await getCurrentAdapter(adapter)).findOne({ - model: "account", - where: [{ - field: "accountId", - value: accountId - }] - }); - }, - findAccountByProviderId: async (accountId, providerId) => { - return await (await getCurrentAdapter(adapter)).findOne({ - model: "account", - where: [{ - field: "accountId", - value: accountId - }, { - field: "providerId", - value: providerId - }] - }); - }, - findAccountByUserId: async (userId) => { - return await (await getCurrentAdapter(adapter)).findMany({ - model: "account", - where: [{ - field: "userId", - value: userId - }] - }); - }, - updateAccount: async (id, data) => { - return await updateWithHooks(data, [{ - field: "id", - value: id - }], "account", void 0); - }, - createVerificationValue: async (data) => { - return await createWithHooks({ - createdAt: /* @__PURE__ */ new Date(), - updatedAt: /* @__PURE__ */ new Date(), - ...data - }, "verification", void 0); - }, - findVerificationValue: async (identifier) => { - const verification = await (await getCurrentAdapter(adapter)).findMany({ - model: "verification", - where: [{ - field: "identifier", - value: identifier - }], - sortBy: { - field: "createdAt", - direction: "desc" - }, - limit: 1 - }); - if (!options.verification?.disableCleanup) await deleteManyWithHooks([{ - field: "expiresAt", - value: /* @__PURE__ */ new Date(), - operator: "lt" - }], "verification", void 0); - return verification[0]; - }, - deleteVerificationValue: async (id) => { - await deleteWithHooks([{ - field: "id", - value: id - }], "verification", void 0); - }, - deleteVerificationByIdentifier: async (identifier) => { - await deleteWithHooks([{ - field: "identifier", - value: identifier - }], "verification", void 0); - }, - updateVerificationValue: async (id, data) => { - return await updateWithHooks(data, [{ - field: "id", - value: id - }], "verification", void 0); - } - }; -}; -function toZodSchema({ fields, isClientSide }) { - const zodFields = Object.keys(fields).reduce((acc, key) => { - const field = fields[key]; - if (!field) return acc; - if (isClientSide && field.input === false) return acc; - let schema2; - if (field.type === "json") schema2 = z.json ? z.json() : z.any(); - else if (field.type === "string[]" || field.type === "number[]") schema2 = z.array(field.type === "string[]" ? z.string() : z.number()); - else if (Array.isArray(field.type)) schema2 = z.any(); - else schema2 = z[field.type](); - if (field?.required === false) schema2 = schema2.optional(); - if (!isClientSide && field?.returned === false) return acc; - return { - ...acc, - [key]: schema2 - }; - }, {}); - return z.object(zodFields); -} -function getSchema(config2) { - const tables = (0, db_exports.getAuthTables)(config2); - const schema2 = {}; - for (const key in tables) { - const table = tables[key]; - const fields = table.fields; - const actualFields = {}; - Object.entries(fields).forEach(([key$1, field]) => { - actualFields[field.fieldName || key$1] = field; - if (field.references) { - const refTable = tables[field.references.model]; - if (refTable) actualFields[field.fieldName || key$1].references = { - ...field.references, - model: refTable.modelName, - field: field.references.field - }; - } - }); - if (schema2[table.modelName]) { - schema2[table.modelName].fields = { - ...schema2[table.modelName].fields, - ...actualFields - }; - continue; - } - schema2[table.modelName] = { - fields: actualFields, - order: table.order || Infinity - }; - } - return schema2; -} -function getKyselyDatabaseType(db2) { - if (!db2) return null; - if ("dialect" in db2) return getKyselyDatabaseType(db2.dialect); - if ("createDriver" in db2) { - if (db2 instanceof SqliteDialect) return "sqlite"; - if (db2 instanceof MysqlDialect) return "mysql"; - if (db2 instanceof PostgresDialect) return "postgres"; - if (db2 instanceof MssqlDialect) return "mssql"; - } - if ("aggregate" in db2) return "sqlite"; - if ("getConnection" in db2) return "mysql"; - if ("connect" in db2) return "postgres"; - if ("fileControl" in db2) return "sqlite"; - if ("open" in db2 && "close" in db2 && "prepare" in db2) return "sqlite"; - return null; -} -const createKyselyAdapter = async (config2) => { - const db2 = config2.database; - if (!db2) return { - kysely: null, - databaseType: null, - transaction: void 0 - }; - if ("db" in db2) return { - kysely: db2.db, - databaseType: db2.type, - transaction: db2.transaction - }; - if ("dialect" in db2) return { - kysely: new Kysely({ dialect: db2.dialect }), - databaseType: db2.type, - transaction: db2.transaction - }; - let dialect = void 0; - const databaseType = getKyselyDatabaseType(db2); - if ("createDriver" in db2) dialect = db2; - if ("aggregate" in db2 && !("createSession" in db2)) dialect = new SqliteDialect({ database: db2 }); - if ("getConnection" in db2) dialect = new MysqlDialect(db2); - if ("connect" in db2) dialect = new PostgresDialect({ pool: db2 }); - if ("fileControl" in db2) { - const { BunSqliteDialect } = await import("./bun-sqlite-dialect.js"); - dialect = new BunSqliteDialect({ database: db2 }); - } - if ("createSession" in db2) { - let DatabaseSync = void 0; - try { - const nodeSqlite = "node:sqlite"; - ({ DatabaseSync } = await import( - /* @vite-ignore */ - /* webpackIgnore: true */ - nodeSqlite - )); - } catch (error2) { - if (error2 !== null && typeof error2 === "object" && "code" in error2 && error2.code !== "ERR_UNKNOWN_BUILTIN_MODULE") throw error2; - } - if (DatabaseSync && db2 instanceof DatabaseSync) { - const { NodeSqliteDialect } = await import("./node-sqlite-dialect.js"); - dialect = new NodeSqliteDialect({ database: db2 }); - } - } - return { - kysely: dialect ? new Kysely({ dialect }) : null, - databaseType, - transaction: void 0 - }; -}; -const map = { - postgres: { - string: [ - "character varying", - "varchar", - "text", - "uuid" - ], - number: [ - "int4", - "integer", - "bigint", - "smallint", - "numeric", - "real", - "double precision" - ], - boolean: ["bool", "boolean"], - date: [ - "timestamptz", - "timestamp", - "date" - ], - json: ["json", "jsonb"] - }, - mysql: { - string: [ - "varchar", - "text", - "uuid" - ], - number: [ - "integer", - "int", - "bigint", - "smallint", - "decimal", - "float", - "double" - ], - boolean: ["boolean", "tinyint"], - date: [ - "timestamp", - "datetime", - "date" - ], - json: ["json"] - }, - sqlite: { - string: ["TEXT"], - number: ["INTEGER", "REAL"], - boolean: ["INTEGER", "BOOLEAN"], - date: ["DATE", "INTEGER"], - json: ["TEXT"] - }, - mssql: { - string: [ - "varchar", - "nvarchar", - "uniqueidentifier" - ], - number: [ - "int", - "bigint", - "smallint", - "decimal", - "float", - "double" - ], - boolean: ["bit", "smallint"], - date: [ - "datetime2", - "date", - "datetime" - ], - json: ["varchar", "nvarchar"] - } -}; -function matchType(columnDataType, fieldType, dbType) { - function normalize(type) { - return type.toLowerCase().split("(")[0].trim(); - } - if (fieldType === "string[]" || fieldType === "number[]") return columnDataType.toLowerCase().includes("json"); - const types2 = map[dbType]; - return (Array.isArray(fieldType) ? types2["string"].map((t) => t.toLowerCase()) : types2[fieldType].map((t) => t.toLowerCase())).includes(normalize(columnDataType)); -} -async function getPostgresSchema(db2) { - try { - const result = await sql`SHOW search_path`.execute(db2); - if (result.rows[0]?.search_path) return result.rows[0].search_path.split(",").map((s) => s.trim()).map((s) => s.replace(/^["']|["']$/g, "")).filter((s) => !s.startsWith("$"))[0] || "public"; - } catch { - } - return "public"; -} -async function getMigrations(config2) { - const betterAuthSchema = getSchema(config2); - const logger$1 = createLogger(config2.logger); - let { kysely: db2, databaseType: dbType } = await createKyselyAdapter(config2); - if (!dbType) { - logger$1.warn("Could not determine database type, defaulting to sqlite. Please provide a type in the database options to avoid this."); - dbType = "sqlite"; - } - if (!db2) { - logger$1.error("Only kysely adapter is supported for migrations. You can use `generate` command to generate the schema, if you're using a different adapter."); - process.exit(1); - } - let currentSchema = "public"; - if (dbType === "postgres") { - currentSchema = await getPostgresSchema(db2); - logger$1.debug(`PostgreSQL migration: Using schema '${currentSchema}' (from search_path)`); - try { - if (!(await sql` - SELECT schema_name - FROM information_schema.schemata - WHERE schema_name = ${currentSchema} - `.execute(db2)).rows[0]) logger$1.warn(`Schema '${currentSchema}' does not exist. Tables will be inspected from available schemas. Consider creating the schema first or checking your database configuration.`); - } catch (error2) { - logger$1.debug(`Could not verify schema existence: ${error2 instanceof Error ? error2.message : String(error2)}`); - } - } - const allTableMetadata = await db2.introspection.getTables(); - let tableMetadata = allTableMetadata; - if (dbType === "postgres") try { - const tablesInSchema = await sql` - SELECT table_name - FROM information_schema.tables - WHERE table_schema = ${currentSchema} - AND table_type = 'BASE TABLE' - `.execute(db2); - const tableNamesInSchema = new Set(tablesInSchema.rows.map((row) => row.table_name)); - tableMetadata = allTableMetadata.filter((table) => table.schema === currentSchema && tableNamesInSchema.has(table.name)); - logger$1.debug(`Found ${tableMetadata.length} table(s) in schema '${currentSchema}': ${tableMetadata.map((t) => t.name).join(", ") || "(none)"}`); - } catch (error2) { - logger$1.warn(`Could not filter tables by schema. Using all discovered tables. Error: ${error2 instanceof Error ? error2.message : String(error2)}`); - } - const toBeCreated = []; - const toBeAdded = []; - for (const [key, value] of Object.entries(betterAuthSchema)) { - const table = tableMetadata.find((t) => t.name === key); - if (!table) { - const tIndex = toBeCreated.findIndex((t) => t.table === key); - const tableData = { - table: key, - fields: value.fields, - order: value.order || Infinity - }; - const insertIndex = toBeCreated.findIndex((t) => (t.order || Infinity) > tableData.order); - if (insertIndex === -1) if (tIndex === -1) toBeCreated.push(tableData); - else toBeCreated[tIndex].fields = { - ...toBeCreated[tIndex].fields, - ...value.fields - }; - else toBeCreated.splice(insertIndex, 0, tableData); - continue; - } - const toBeAddedFields = {}; - for (const [fieldName, field] of Object.entries(value.fields)) { - const column = table.columns.find((c) => c.name === fieldName); - if (!column) { - toBeAddedFields[fieldName] = field; - continue; - } - if (matchType(column.dataType, field.type, dbType)) continue; - else logger$1.warn(`Field ${fieldName} in table ${key} has a different type in the database. Expected ${field.type} but got ${column.dataType}.`); - } - if (Object.keys(toBeAddedFields).length > 0) toBeAdded.push({ - table: key, - fields: toBeAddedFields, - order: value.order || Infinity - }); - } - const migrations = []; - const useUUIDs = config2.advanced?.database?.generateId === "uuid"; - const useNumberId = config2.advanced?.database?.useNumberId || config2.advanced?.database?.generateId === "serial"; - function getType(field, fieldName) { - const type = field.type; - const provider = dbType || "sqlite"; - const typeMap = { - string: { - sqlite: "text", - postgres: "text", - mysql: field.unique ? "varchar(255)" : field.references ? "varchar(36)" : field.sortable ? "varchar(255)" : field.index ? "varchar(255)" : "text", - mssql: field.unique || field.sortable ? "varchar(255)" : field.references ? "varchar(36)" : "varchar(8000)" - }, - boolean: { - sqlite: "integer", - postgres: "boolean", - mysql: "boolean", - mssql: "smallint" - }, - number: { - sqlite: field.bigint ? "bigint" : "integer", - postgres: field.bigint ? "bigint" : "integer", - mysql: field.bigint ? "bigint" : "integer", - mssql: field.bigint ? "bigint" : "integer" - }, - date: { - sqlite: "date", - postgres: "timestamptz", - mysql: "timestamp(3)", - mssql: sql`datetime2(3)` - }, - json: { - sqlite: "text", - postgres: "jsonb", - mysql: "json", - mssql: "varchar(8000)" - }, - id: { - postgres: useNumberId ? sql`integer GENERATED BY DEFAULT AS IDENTITY` : useUUIDs ? "uuid" : "text", - mysql: useNumberId ? "integer" : useUUIDs ? "varchar(36)" : "varchar(36)", - mssql: useNumberId ? "integer" : useUUIDs ? "varchar(36)" : "varchar(36)", - sqlite: useNumberId ? "integer" : "text" - }, - foreignKeyId: { - postgres: useNumberId ? "integer" : useUUIDs ? "uuid" : "text", - mysql: useNumberId ? "integer" : useUUIDs ? "varchar(36)" : "varchar(36)", - mssql: useNumberId ? "integer" : useUUIDs ? "varchar(36)" : "varchar(36)", - sqlite: useNumberId ? "integer" : "text" - }, - "string[]": { - sqlite: "text", - postgres: "jsonb", - mysql: "json", - mssql: "varchar(8000)" - }, - "number[]": { - sqlite: "text", - postgres: "jsonb", - mysql: "json", - mssql: "varchar(8000)" - } - }; - if (fieldName === "id" || field.references?.field === "id") { - if (fieldName === "id") return typeMap.id[provider]; - return typeMap.foreignKeyId[provider]; - } - if (Array.isArray(type)) return "text"; - if (!(type in typeMap)) throw new Error(`Unsupported field type '${String(type)}' for field '${fieldName}'. Allowed types are: string, number, boolean, date, string[], number[]. If you need to store structured data, store it as a JSON string (type: "string") or split it into primitive fields. See https://better-auth.com/docs/advanced/schema#additional-fields`); - return typeMap[type][provider]; - } - const getModelName = initGetModelName({ - schema: getAuthTables(config2), - usePlural: false - }); - const getFieldName = initGetFieldName({ - schema: getAuthTables(config2), - usePlural: false - }); - function getReferencePath(model, field) { - try { - return `${getModelName(model)}.${getFieldName({ - model, - field - })}`; - } catch { - return `${model}.${field}`; - } - } - if (toBeAdded.length) for (const table of toBeAdded) for (const [fieldName, field] of Object.entries(table.fields)) { - const type = getType(field, fieldName); - const builder = db2.schema.alterTable(table.table); - if (field.index) { - const index = db2.schema.alterTable(table.table).addIndex(`${table.table}_${fieldName}_idx`); - migrations.push(index); - } - const built = builder.addColumn(fieldName, type, (col) => { - col = field.required !== false ? col.notNull() : col; - if (field.references) col = col.references(getReferencePath(field.references.model, field.references.field)).onDelete(field.references.onDelete || "cascade"); - if (field.unique) col = col.unique(); - if (field.type === "date" && typeof field.defaultValue === "function" && (dbType === "postgres" || dbType === "mysql" || dbType === "mssql")) if (dbType === "mysql") col = col.defaultTo(sql`CURRENT_TIMESTAMP(3)`); - else col = col.defaultTo(sql`CURRENT_TIMESTAMP`); - return col; - }); - migrations.push(built); - } - const toBeIndexed = []; - if (config2.advanced?.database?.useNumberId) logger$1.warn("`useNumberId` is deprecated. Please use `generateId` with `serial` instead."); - if (toBeCreated.length) for (const table of toBeCreated) { - const idType = getType({ type: useNumberId ? "number" : "string" }, "id"); - let dbT = db2.schema.createTable(table.table).addColumn("id", idType, (col) => { - if (useNumberId) { - if (dbType === "postgres") return col.primaryKey().notNull(); - else if (dbType === "sqlite") return col.primaryKey().notNull(); - else if (dbType === "mssql") return col.identity().primaryKey().notNull(); - return col.autoIncrement().primaryKey().notNull(); - } - if (useUUIDs) { - if (dbType === "postgres") return col.primaryKey().defaultTo(sql`pg_catalog.gen_random_uuid()`).notNull(); - return col.primaryKey().notNull(); - } - return col.primaryKey().notNull(); - }); - for (const [fieldName, field] of Object.entries(table.fields)) { - const type = getType(field, fieldName); - dbT = dbT.addColumn(fieldName, type, (col) => { - col = field.required !== false ? col.notNull() : col; - if (field.references) col = col.references(getReferencePath(field.references.model, field.references.field)).onDelete(field.references.onDelete || "cascade"); - if (field.unique) col = col.unique(); - if (field.type === "date" && typeof field.defaultValue === "function" && (dbType === "postgres" || dbType === "mysql" || dbType === "mssql")) if (dbType === "mysql") col = col.defaultTo(sql`CURRENT_TIMESTAMP(3)`); - else col = col.defaultTo(sql`CURRENT_TIMESTAMP`); - return col; - }); - if (field.index) { - const builder = db2.schema.createIndex(`${table.table}_${fieldName}_${field.unique ? "uidx" : "idx"}`).on(table.table).columns([fieldName]); - toBeIndexed.push(field.unique ? builder.unique() : builder); - } - } - migrations.push(dbT); - } - if (toBeIndexed.length) for (const index of toBeIndexed) migrations.push(index); - async function runMigrations() { - for (const migration of migrations) await migration.execute(); - } - async function compileMigrations() { - return migrations.map((m) => m.compile().sql).join(";\n\n") + ";"; - } - return { - toBeCreated, - toBeAdded, - runMigrations, - compileMigrations - }; -} -var db_exports = /* @__PURE__ */ __export({ - convertFromDB: () => convertFromDB, - convertToDB: () => convertToDB, - createFieldAttribute: () => createFieldAttribute, - createInternalAdapter: () => createInternalAdapter, - getAdapter: () => getAdapter, - getBaseAdapter: () => getBaseAdapter, - getMigrations: () => getMigrations, - getSchema: () => getSchema, - getWithHooks: () => getWithHooks, - matchType: () => matchType, - mergeSchema: () => mergeSchema, - parseAccountInput: () => parseAccountInput, - parseAccountOutput: () => parseAccountOutput, - parseAdditionalUserInput: () => parseAdditionalUserInput, - parseInputData: () => parseInputData, - parseSessionInput: () => parseSessionInput, - parseSessionOutput: () => parseSessionOutput, - parseUserInput: () => parseUserInput, - parseUserOutput: () => parseUserOutput, - toZodSchema: () => toZodSchema -}); -__reExport(db_exports, import___better_auth_core_db); -async function signJWT(payload, secret, expiresIn = 3600) { - return await new SignJWT(payload).setProtectedHeader({ alg: "HS256" }).setIssuedAt().setExpirationTime(Math.floor(Date.now() / 1e3) + expiresIn).sign(new TextEncoder().encode(secret)); -} -async function verifyJWT(token, secret) { - try { - return (await jwtVerify(token, new TextEncoder().encode(secret))).payload; - } catch { - return null; - } -} -const info = new Uint8Array([ - 66, - 101, - 116, - 116, - 101, - 114, - 65, - 117, - 116, - 104, - 46, - 106, - 115, - 32, - 71, - 101, - 110, - 101, - 114, - 97, - 116, - 101, - 100, - 32, - 69, - 110, - 99, - 114, - 121, - 112, - 116, - 105, - 111, - 110, - 32, - 75, - 101, - 121 -]); -const now = () => Date.now() / 1e3 | 0; -const alg = "dir"; -const enc = "A256CBC-HS512"; -async function symmetricEncodeJWT(payload, secret, salt, expiresIn = 3600) { - const encryptionSecret = hkdf(sha256, new TextEncoder().encode(secret), new TextEncoder().encode(salt), info, 64); - const thumbprint = await calculateJwkThumbprint({ - kty: "oct", - k: base64url.encode(encryptionSecret) - }, "sha256"); - return await new EncryptJWT(payload).setProtectedHeader({ - alg, - enc, - kid: thumbprint - }).setIssuedAt().setExpirationTime(now() + expiresIn).setJti(crypto.randomUUID()).encrypt(encryptionSecret); -} -async function symmetricDecodeJWT(token, secret, salt) { - if (!token) return null; - try { - const { payload } = await jwtDecrypt(token, async ({ kid }) => { - const encryptionSecret = hkdf(sha256, new TextEncoder().encode(secret), new TextEncoder().encode(salt), info, 64); - if (kid === void 0) return encryptionSecret; - if (kid === await calculateJwkThumbprint({ - kty: "oct", - k: base64url.encode(encryptionSecret) - }, "sha256")) return encryptionSecret; - throw new Error("no matching decryption secret"); - }, { - clockTolerance: 15, - keyManagementAlgorithms: [alg], - contentEncryptionAlgorithms: [enc, "A256GCM"] - }); - return payload; - } catch { - return null; - } -} -function constantTimeEqual(a, b) { - if (typeof a === "string") a = new TextEncoder().encode(a); - if (typeof b === "string") b = new TextEncoder().encode(b); - const aBuffer = new Uint8Array(a); - const bBuffer = new Uint8Array(b); - let c = aBuffer.length ^ bBuffer.length; - const length = Math.max(aBuffer.length, bBuffer.length); - for (let i = 0; i < length; i++) c |= (i < aBuffer.length ? aBuffer[i] : 0) ^ (i < bBuffer.length ? bBuffer[i] : 0); - return c === 0; -} -const config = { - N: 16384, - r: 16, - p: 1, - dkLen: 64 -}; -async function generateKey(password, salt) { - return await scryptAsync(password.normalize("NFKC"), salt, { - N: config.N, - p: config.p, - r: config.r, - dkLen: config.dkLen, - maxmem: 128 * config.N * config.r * 2 - }); -} -const hashPassword = async (password) => { - const salt = hex.encode(crypto.getRandomValues(new Uint8Array(16))); - const key = await generateKey(password, salt); - return `${salt}:${hex.encode(key)}`; -}; -const verifyPassword$1 = async ({ hash, password }) => { - const [salt, key] = hash.split(":"); - if (!salt || !key) throw new BetterAuthError("Invalid password hash"); - return constantTimeEqual(await generateKey(password, salt), hexToBytes(key)); -}; -const generateRandomString = createRandomStringGenerator("a-z", "0-9", "A-Z", "-_"); -const symmetricEncrypt = async ({ key, data }) => { - const keyAsBytes = await createHash("SHA-256").digest(key); - const dataAsBytes = utf8ToBytes(data); - return bytesToHex(managedNonce(xchacha20poly1305)(new Uint8Array(keyAsBytes)).encrypt(dataAsBytes)); -}; -const symmetricDecrypt = async ({ key, data }) => { - const keyAsBytes = await createHash("SHA-256").digest(key); - const dataAsBytes = hexToBytes$1(data); - const chacha = managedNonce(xchacha20poly1305)(new Uint8Array(keyAsBytes)); - return new TextDecoder().decode(chacha.decrypt(dataAsBytes)); -}; -const ALLOWED_COOKIE_SIZE = 4096; -const ESTIMATED_EMPTY_COOKIE_SIZE = 200; -const CHUNK_SIZE = ALLOWED_COOKIE_SIZE - ESTIMATED_EMPTY_COOKIE_SIZE; -function parseCookiesFromContext(ctx) { - const cookieHeader = ctx.headers?.get("cookie"); - if (!cookieHeader) return {}; - const cookies = {}; - const pairs = cookieHeader.split("; "); - for (const pair of pairs) { - const [name, ...valueParts] = pair.split("="); - if (name && valueParts.length > 0) cookies[name] = valueParts.join("="); - } - return cookies; -} -function getChunkIndex(cookieName) { - const parts = cookieName.split("."); - const lastPart = parts[parts.length - 1]; - const index = parseInt(lastPart || "0", 10); - return isNaN(index) ? 0 : index; -} -function readExistingChunks(cookieName, ctx) { - const chunks = {}; - const cookies = parseCookiesFromContext(ctx); - for (const [name, value] of Object.entries(cookies)) if (name.startsWith(cookieName)) chunks[name] = value; - return chunks; -} -function joinChunks(chunks) { - return Object.keys(chunks).sort((a, b) => { - return getChunkIndex(a) - getChunkIndex(b); - }).map((key) => chunks[key]).join(""); -} -function chunkCookie(storeName, cookie, chunks, logger2) { - const chunkCount = Math.ceil(cookie.value.length / CHUNK_SIZE); - if (chunkCount === 1) { - chunks[cookie.name] = cookie.value; - return [cookie]; - } - const cookies = []; - for (let i = 0; i < chunkCount; i++) { - const name = `${cookie.name}.${i}`; - const start = i * CHUNK_SIZE; - const value = cookie.value.substring(start, start + CHUNK_SIZE); - cookies.push({ - ...cookie, - name, - value - }); - chunks[name] = value; - } - logger2.debug(`CHUNKING_${storeName.toUpperCase()}_COOKIE`, { - message: `${storeName} cookie exceeds allowed ${ALLOWED_COOKIE_SIZE} bytes.`, - emptyCookieSize: ESTIMATED_EMPTY_COOKIE_SIZE, - valueSize: cookie.value.length, - chunkCount, - chunks: cookies.map((c) => c.value.length + ESTIMATED_EMPTY_COOKIE_SIZE) - }); - return cookies; -} -function getCleanCookies(chunks, cookieOptions) { - const cleanedChunks = {}; - for (const name in chunks) cleanedChunks[name] = { - name, - value: "", - attributes: { - ...cookieOptions, - maxAge: 0 - } - }; - return cleanedChunks; -} -const storeFactory = (storeName) => (cookieName, cookieOptions, ctx) => { - const chunks = readExistingChunks(cookieName, ctx); - const logger2 = ctx.context.logger; - return { - getValue() { - return joinChunks(chunks); - }, - hasChunks() { - return Object.keys(chunks).length > 0; - }, - chunk(value, options) { - const cleanedChunks = getCleanCookies(chunks, cookieOptions); - for (const name in chunks) delete chunks[name]; - const cookies = cleanedChunks; - const chunked = chunkCookie(storeName, { - name: cookieName, - value, - attributes: { - ...cookieOptions, - ...options - } - }, chunks, logger2); - for (const chunk of chunked) cookies[chunk.name] = chunk; - return Object.values(cookies); - }, - clean() { - const cleanedChunks = getCleanCookies(chunks, cookieOptions); - for (const name in chunks) delete chunks[name]; - return Object.values(cleanedChunks); - }, - setCookies(cookies) { - for (const cookie of cookies) ctx.setCookie(cookie.name, cookie.value, cookie.attributes); - } - }; -}; -const createSessionStore = storeFactory("Session"); -const createAccountStore = storeFactory("Account"); -function getChunkedCookie(ctx, cookieName) { - const value = ctx.getCookie(cookieName); - if (value) return value; - const chunks = []; - const cookieHeader = ctx.headers?.get("cookie"); - if (!cookieHeader) return null; - const cookies = {}; - const pairs = cookieHeader.split("; "); - for (const pair of pairs) { - const [name, ...valueParts] = pair.split("="); - if (name && valueParts.length > 0) cookies[name] = valueParts.join("="); - } - for (const [name, val] of Object.entries(cookies)) if (name.startsWith(cookieName + ".")) { - const indexStr = name.split(".").at(-1); - const index = parseInt(indexStr || "0", 10); - if (!isNaN(index)) chunks.push({ - index, - value: val - }); - } - if (chunks.length > 0) { - chunks.sort((a, b) => a.index - b.index); - return chunks.map((c) => c.value).join(""); - } - return null; -} -async function setAccountCookie(c, accountData) { - const accountDataCookie = c.context.authCookies.accountData; - const options = { - maxAge: 300, - ...accountDataCookie.attributes - }; - const data = await symmetricEncodeJWT(accountData, c.context.secret, "better-auth-account", options.maxAge); - if (data.length > ALLOWED_COOKIE_SIZE) { - const accountStore = createAccountStore(accountDataCookie.name, options, c); - const cookies = accountStore.chunk(data, options); - accountStore.setCookies(cookies); - } else { - const accountStore = createAccountStore(accountDataCookie.name, options, c); - if (accountStore.hasChunks()) { - const cleanCookies = accountStore.clean(); - accountStore.setCookies(cleanCookies); - } - c.setCookie(accountDataCookie.name, data, options); - } -} -async function getAccountCookie(c) { - const accountCookie = getChunkedCookie(c, c.context.authCookies.accountData.name); - if (accountCookie) { - const accountData = safeJSONParse(await symmetricDecodeJWT(accountCookie, c.context.secret, "better-auth-account")); - if (accountData) return accountData; - } - return null; -} -const getSessionQuerySchema = z.optional(z.object({ - disableCookieCache: z.coerce.boolean().meta({ description: "Disable cookie cache and fetch session from database" }).optional(), - disableRefresh: z.coerce.boolean().meta({ description: "Disable session refresh. Useful for checking session status, without updating the session" }).optional() -})); -function isPromise(obj) { - return !!obj && (typeof obj === "object" || typeof obj === "function") && typeof obj.then === "function"; -} -const SEC = 1e3; -const MIN = SEC * 60; -const HOUR = MIN * 60; -const DAY = HOUR * 24; -const WEEK = DAY * 7; -const MONTH = DAY * 30; -const YEAR = DAY * 365.25; -const REGEX = /^(\+|\-)? ?(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|months?|mo|years?|yrs?|y)(?: (ago|from now))?$/i; -function parse(value) { - const match = REGEX.exec(value); - if (!match || match[4] && match[1]) throw new TypeError(`Invalid time string format: "${value}". Use formats like "7d", "30m", "1 hour", etc.`); - const n = parseFloat(match[2]); - const unit = match[3].toLowerCase(); - let result; - switch (unit) { - case "years": - case "year": - case "yrs": - case "yr": - case "y": - result = n * YEAR; - break; - case "months": - case "month": - case "mo": - result = n * MONTH; - break; - case "weeks": - case "week": - case "w": - result = n * WEEK; - break; - case "days": - case "day": - case "d": - result = n * DAY; - break; - case "hours": - case "hour": - case "hrs": - case "hr": - case "h": - result = n * HOUR; - break; - case "minutes": - case "minute": - case "mins": - case "min": - case "m": - result = n * MIN; - break; - case "seconds": - case "second": - case "secs": - case "sec": - case "s": - result = n * SEC; - break; - default: - throw new TypeError(`Unknown time unit: "${unit}"`); - } - if (match[1] === "-" || match[4] === "ago") return -result; - return result; -} -function ms(value) { - return parse(value); -} -function sec(value) { - return Math.round(parse(value) / 1e3); -} -const SECURE_COOKIE_PREFIX = "__Secure-"; -function splitSetCookieHeader(setCookie) { - if (!setCookie) return []; - const result = []; - let current = ""; - let i = 0; - while (i < setCookie.length) { - const c = setCookie[i]; - if (c === ",") { - const lower = current.toLowerCase(); - if (lower.includes("expires=") && !lower.includes("gmt")) { - current += c; - i++; - } else { - const trimmed$1 = current.trim(); - if (trimmed$1) result.push(trimmed$1); - current = ""; - i++; - if (i < setCookie.length && setCookie[i] === " ") i++; - } - continue; - } - current += c; - i++; - } - const trimmed = current.trim(); - if (trimmed) result.push(trimmed); - return result; -} -function parseSetCookieHeader(setCookie) { - const cookies = /* @__PURE__ */ new Map(); - splitSetCookieHeader(setCookie).forEach((cookieString) => { - const [nameValue, ...attributes] = cookieString.split(";").map((part) => part.trim()); - const [name, ...valueParts] = (nameValue || "").split("="); - const value = valueParts.join("="); - if (!name || value === void 0) return; - const attrObj = { value }; - attributes.forEach((attribute) => { - const [attrName, ...attrValueParts] = attribute.split("="); - const attrValue = attrValueParts.join("="); - const normalizedAttrName = attrName.trim().toLowerCase(); - switch (normalizedAttrName) { - case "max-age": - attrObj["max-age"] = attrValue ? parseInt(attrValue.trim(), 10) : void 0; - break; - case "expires": - attrObj.expires = attrValue ? new Date(attrValue.trim()) : void 0; - break; - case "domain": - attrObj.domain = attrValue ? attrValue.trim() : void 0; - break; - case "path": - attrObj.path = attrValue ? attrValue.trim() : void 0; - break; - case "secure": - attrObj.secure = true; - break; - case "httponly": - attrObj.httponly = true; - break; - case "samesite": - attrObj.samesite = attrValue ? attrValue.trim().toLowerCase() : void 0; - break; - default: - attrObj[normalizedAttrName] = attrValue ? attrValue.trim() : true; - break; - } - }); - cookies.set(name, attrObj); - }); - return cookies; -} -function createCookieGetter(options) { - const secureCookiePrefix = (options.advanced?.useSecureCookies !== void 0 ? options.advanced?.useSecureCookies : options.baseURL ? options.baseURL.startsWith("https://") ? true : false : isProduction) ? SECURE_COOKIE_PREFIX : ""; - const crossSubdomainEnabled = !!options.advanced?.crossSubDomainCookies?.enabled; - const domain = crossSubdomainEnabled ? options.advanced?.crossSubDomainCookies?.domain || (options.baseURL ? new URL(options.baseURL).hostname : void 0) : void 0; - if (crossSubdomainEnabled && !domain) throw new BetterAuthError("baseURL is required when crossSubdomainCookies are enabled"); - function createCookie(cookieName, overrideAttributes = {}) { - const prefix = options.advanced?.cookiePrefix || "better-auth"; - const name = options.advanced?.cookies?.[cookieName]?.name || `${prefix}.${cookieName}`; - const attributes = options.advanced?.cookies?.[cookieName]?.attributes; - return { - name: `${secureCookiePrefix}${name}`, - attributes: { - secure: !!secureCookiePrefix, - sameSite: "lax", - path: "/", - httpOnly: true, - ...crossSubdomainEnabled ? { domain } : {}, - ...options.advanced?.defaultCookieAttributes, - ...overrideAttributes, - ...attributes - } - }; - } - return createCookie; -} -function getCookies(options) { - const createCookie = createCookieGetter(options); - const sessionToken = createCookie("session_token", { maxAge: options.session?.expiresIn || sec("7d") }); - const sessionData = createCookie("session_data", { maxAge: options.session?.cookieCache?.maxAge || 300 }); - const accountData = createCookie("account_data", { maxAge: options.session?.cookieCache?.maxAge || 300 }); - const dontRememberToken = createCookie("dont_remember"); - return { - sessionToken: { - name: sessionToken.name, - attributes: sessionToken.attributes - }, - sessionData: { - name: sessionData.name, - attributes: sessionData.attributes - }, - dontRememberToken: { - name: dontRememberToken.name, - attributes: dontRememberToken.attributes - }, - accountData: { - name: accountData.name, - attributes: accountData.attributes - } - }; -} -async function setCookieCache(ctx, session, dontRememberMe) { - if (!ctx.context.options.session?.cookieCache?.enabled) return; - const filteredSession = filterOutputFields(session.session, ctx.context.options.session?.additionalFields); - const filteredUser = parseUserOutput(ctx.context.options, session.user); - const versionConfig = ctx.context.options.session?.cookieCache?.version; - let version = "1"; - if (versionConfig) { - if (typeof versionConfig === "string") version = versionConfig; - else if (typeof versionConfig === "function") { - const result = versionConfig(session.session, session.user); - version = isPromise(result) ? await result : result; - } - } - const sessionData = { - session: filteredSession, - user: filteredUser, - updatedAt: Date.now(), - version - }; - const options = { - ...ctx.context.authCookies.sessionData.attributes, - maxAge: dontRememberMe ? void 0 : ctx.context.authCookies.sessionData.attributes.maxAge - }; - const expiresAtDate = getDate(options.maxAge || 60, "sec").getTime(); - const strategy = ctx.context.options.session?.cookieCache?.strategy || "compact"; - let data; - if (strategy === "jwe") data = await symmetricEncodeJWT(sessionData, ctx.context.secret, "better-auth-session", options.maxAge || 300); - else if (strategy === "jwt") data = await signJWT(sessionData, ctx.context.secret, options.maxAge || 300); - else data = base64Url.encode(JSON.stringify({ - session: sessionData, - expiresAt: expiresAtDate, - signature: await createHMAC("SHA-256", "base64urlnopad").sign(ctx.context.secret, JSON.stringify({ - ...sessionData, - expiresAt: expiresAtDate - })) - }), { padding: false }); - if (data.length > 4093) { - const sessionStore = createSessionStore(ctx.context.authCookies.sessionData.name, options, ctx); - const cookies = sessionStore.chunk(data, options); - sessionStore.setCookies(cookies); - } else { - const sessionStore = createSessionStore(ctx.context.authCookies.sessionData.name, options, ctx); - if (sessionStore.hasChunks()) { - const cleanCookies = sessionStore.clean(); - sessionStore.setCookies(cleanCookies); - } - ctx.setCookie(ctx.context.authCookies.sessionData.name, data, options); - } - if (ctx.context.options.account?.storeAccountCookie) { - const accountData = await getAccountCookie(ctx); - if (accountData) await setAccountCookie(ctx, accountData); - } -} -async function setSessionCookie(ctx, session, dontRememberMe, overrides) { - const dontRememberMeCookie = await ctx.getSignedCookie(ctx.context.authCookies.dontRememberToken.name, ctx.context.secret); - dontRememberMe = dontRememberMe !== void 0 ? dontRememberMe : !!dontRememberMeCookie; - const options = ctx.context.authCookies.sessionToken.attributes; - const maxAge = dontRememberMe ? void 0 : ctx.context.sessionConfig.expiresIn; - await ctx.setSignedCookie(ctx.context.authCookies.sessionToken.name, session.session.token, ctx.context.secret, { - ...options, - maxAge, - ...overrides - }); - if (dontRememberMe) await ctx.setSignedCookie(ctx.context.authCookies.dontRememberToken.name, "true", ctx.context.secret, ctx.context.authCookies.dontRememberToken.attributes); - await setCookieCache(ctx, session, dontRememberMe); - ctx.context.setNewSession(session); -} -function expireCookie(ctx, cookie) { - ctx.setCookie(cookie.name, "", { - ...cookie.attributes, - maxAge: 0 - }); -} -function deleteSessionCookie(ctx, skipDontRememberMe) { - expireCookie(ctx, ctx.context.authCookies.sessionToken); - expireCookie(ctx, ctx.context.authCookies.sessionData); - if (ctx.context.options.account?.storeAccountCookie) { - expireCookie(ctx, ctx.context.authCookies.accountData); - const accountStore = createAccountStore(ctx.context.authCookies.accountData.name, ctx.context.authCookies.accountData.attributes, ctx); - const cleanCookies$1 = accountStore.clean(); - accountStore.setCookies(cleanCookies$1); - } - if (ctx.context.oauthConfig.storeStateStrategy === "cookie") expireCookie(ctx, ctx.context.createAuthCookie("oauth_state")); - const sessionStore = createSessionStore(ctx.context.authCookies.sessionData.name, ctx.context.authCookies.sessionData.attributes, ctx); - const cleanCookies = sessionStore.clean(); - sessionStore.setCookies(cleanCookies); - expireCookie(ctx, ctx.context.authCookies.dontRememberToken); -} -const getSession = () => createAuthEndpoint("/get-session", { - method: "GET", - operationId: "getSession", - query: getSessionQuerySchema, - requireHeaders: true, - metadata: { openapi: { - operationId: "getSession", - description: "Get the current session", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - nullable: true, - properties: { - session: { $ref: "#/components/schemas/Session" }, - user: { $ref: "#/components/schemas/User" } - }, - required: ["session", "user"] - } } } - } } - } } -}, async (ctx) => { - try { - const sessionCookieToken = await ctx.getSignedCookie(ctx.context.authCookies.sessionToken.name, ctx.context.secret); - if (!sessionCookieToken) return null; - const sessionDataCookie = getChunkedCookie(ctx, ctx.context.authCookies.sessionData.name); - let sessionDataPayload = null; - if (sessionDataCookie) { - const strategy = ctx.context.options.session?.cookieCache?.strategy || "compact"; - if (strategy === "jwe") { - const payload = await symmetricDecodeJWT(sessionDataCookie, ctx.context.secret, "better-auth-session"); - if (payload && payload.session && payload.user) sessionDataPayload = { - session: { - session: payload.session, - user: payload.user, - updatedAt: payload.updatedAt, - version: payload.version - }, - expiresAt: payload.exp ? payload.exp * 1e3 : Date.now() - }; - else { - expireCookie(ctx, ctx.context.authCookies.sessionData); - return ctx.json(null); - } - } else if (strategy === "jwt") { - const payload = await verifyJWT(sessionDataCookie, ctx.context.secret); - if (payload && payload.session && payload.user) sessionDataPayload = { - session: { - session: payload.session, - user: payload.user, - updatedAt: payload.updatedAt, - version: payload.version - }, - expiresAt: payload.exp ? payload.exp * 1e3 : Date.now() - }; - else { - expireCookie(ctx, ctx.context.authCookies.sessionData); - return ctx.json(null); - } - } else { - const parsed = safeJSONParse(binary.decode(base64Url.decode(sessionDataCookie))); - if (parsed) if (await createHMAC("SHA-256", "base64urlnopad").verify(ctx.context.secret, JSON.stringify({ - ...parsed.session, - expiresAt: parsed.expiresAt - }), parsed.signature)) sessionDataPayload = parsed; - else { - expireCookie(ctx, ctx.context.authCookies.sessionData); - return ctx.json(null); - } - } - } - const dontRememberMe = await ctx.getSignedCookie(ctx.context.authCookies.dontRememberToken.name, ctx.context.secret); - if (sessionDataPayload?.session && ctx.context.options.session?.cookieCache?.enabled && !ctx.query?.disableCookieCache) { - const session$1 = sessionDataPayload.session; - const versionConfig = ctx.context.options.session?.cookieCache?.version; - let expectedVersion = "1"; - if (versionConfig) { - if (typeof versionConfig === "string") expectedVersion = versionConfig; - else if (typeof versionConfig === "function") { - const result = versionConfig(session$1.session, session$1.user); - expectedVersion = result instanceof Promise ? await result : result; - } - } - if ((session$1.version || "1") !== expectedVersion) expireCookie(ctx, ctx.context.authCookies.sessionData); - else { - const cachedSessionExpiresAt = new Date(session$1.session.expiresAt); - if (sessionDataPayload.expiresAt < Date.now() || cachedSessionExpiresAt < /* @__PURE__ */ new Date()) expireCookie(ctx, ctx.context.authCookies.sessionData); - else { - const cookieRefreshCache = ctx.context.sessionConfig.cookieRefreshCache; - if (cookieRefreshCache === false) { - ctx.context.session = session$1; - const parsedSession$2 = parseSessionOutput(ctx.context.options, { - ...session$1.session, - expiresAt: new Date(session$1.session.expiresAt), - createdAt: new Date(session$1.session.createdAt), - updatedAt: new Date(session$1.session.updatedAt) - }); - const parsedUser$2 = parseUserOutput(ctx.context.options, { - ...session$1.user, - createdAt: new Date(session$1.user.createdAt), - updatedAt: new Date(session$1.user.updatedAt) - }); - return ctx.json({ - session: parsedSession$2, - user: parsedUser$2 - }); - } - if (sessionDataPayload.expiresAt - Date.now() < cookieRefreshCache.updateAge * 1e3) { - const newExpiresAt = getDate(ctx.context.options.session?.cookieCache?.maxAge || 300, "sec"); - const refreshedSession = { - session: { - ...session$1.session, - expiresAt: newExpiresAt - }, - user: session$1.user, - updatedAt: Date.now() - }; - await setCookieCache(ctx, refreshedSession, false); - const parsedRefreshedSession = parseSessionOutput(ctx.context.options, { - ...refreshedSession.session, - expiresAt: new Date(refreshedSession.session.expiresAt), - createdAt: new Date(refreshedSession.session.createdAt), - updatedAt: new Date(refreshedSession.session.updatedAt) - }); - const parsedRefreshedUser = parseUserOutput(ctx.context.options, { - ...refreshedSession.user, - createdAt: new Date(refreshedSession.user.createdAt), - updatedAt: new Date(refreshedSession.user.updatedAt) - }); - ctx.context.session = { - session: parsedRefreshedSession, - user: parsedRefreshedUser - }; - return ctx.json({ - session: parsedRefreshedSession, - user: parsedRefreshedUser - }); - } - const parsedSession$1 = parseSessionOutput(ctx.context.options, { - ...session$1.session, - expiresAt: new Date(session$1.session.expiresAt), - createdAt: new Date(session$1.session.createdAt), - updatedAt: new Date(session$1.session.updatedAt) - }); - const parsedUser$1 = parseUserOutput(ctx.context.options, { - ...session$1.user, - createdAt: new Date(session$1.user.createdAt), - updatedAt: new Date(session$1.user.updatedAt) - }); - ctx.context.session = { - session: parsedSession$1, - user: parsedUser$1 - }; - return ctx.json({ - session: parsedSession$1, - user: parsedUser$1 - }); - } - } - } - const session = await ctx.context.internalAdapter.findSession(sessionCookieToken); - ctx.context.session = session; - if (!session || session.session.expiresAt < /* @__PURE__ */ new Date()) { - deleteSessionCookie(ctx); - if (session) - await ctx.context.internalAdapter.deleteSession(session.session.token); - return ctx.json(null); - } - if (dontRememberMe || ctx.query?.disableRefresh) { - const parsedSession$1 = parseSessionOutput(ctx.context.options, session.session); - const parsedUser$1 = parseUserOutput(ctx.context.options, session.user); - return ctx.json({ - session: parsedSession$1, - user: parsedUser$1 - }); - } - const expiresIn = ctx.context.sessionConfig.expiresIn; - const updateAge = ctx.context.sessionConfig.updateAge; - if (session.session.expiresAt.valueOf() - expiresIn * 1e3 + updateAge * 1e3 <= Date.now() && (!ctx.query?.disableRefresh || !ctx.context.options.session?.disableSessionRefresh)) { - const updatedSession = await ctx.context.internalAdapter.updateSession(session.session.token, { - expiresAt: getDate(ctx.context.sessionConfig.expiresIn, "sec"), - updatedAt: /* @__PURE__ */ new Date() - }); - if (!updatedSession) { - deleteSessionCookie(ctx); - return ctx.json(null, { status: 401 }); - } - const maxAge = (updatedSession.expiresAt.valueOf() - Date.now()) / 1e3; - await setSessionCookie(ctx, { - session: updatedSession, - user: session.user - }, false, { maxAge }); - const parsedUpdatedSession = parseSessionOutput(ctx.context.options, updatedSession); - const parsedUser$1 = parseUserOutput(ctx.context.options, session.user); - return ctx.json({ - session: parsedUpdatedSession, - user: parsedUser$1 - }); - } - await setCookieCache(ctx, session, !!dontRememberMe); - const parsedSession = parseSessionOutput(ctx.context.options, session.session); - const parsedUser = parseUserOutput(ctx.context.options, session.user); - return ctx.json({ - session: parsedSession, - user: parsedUser - }); - } catch (error2) { - ctx.context.logger.error("INTERNAL_SERVER_ERROR", error2); - throw new APIError("INTERNAL_SERVER_ERROR", { message: BASE_ERROR_CODES.FAILED_TO_GET_SESSION }); - } -}); -const getSessionFromCtx = async (ctx, config2) => { - if (ctx.context.session) return ctx.context.session; - const session = await getSession()({ - ...ctx, - asResponse: false, - headers: ctx.headers, - returnHeaders: false, - returnStatus: false, - query: { - ...config2, - ...ctx.query - } - }).catch((e) => { - return null; - }); - ctx.context.session = session; - return session; -}; -const sessionMiddleware = createAuthMiddleware(async (ctx) => { - const session = await getSessionFromCtx(ctx); - if (!session?.session) throw new APIError("UNAUTHORIZED"); - return { session }; -}); -const sensitiveSessionMiddleware = createAuthMiddleware(async (ctx) => { - const session = await getSessionFromCtx(ctx, { disableCookieCache: true }); - if (!session?.session) throw new APIError("UNAUTHORIZED"); - return { session }; -}); -createAuthMiddleware(async (ctx) => { - const session = await getSessionFromCtx(ctx); - if (!session?.session && (ctx.request || ctx.headers)) throw new APIError("UNAUTHORIZED"); - return { session }; -}); -const freshSessionMiddleware = createAuthMiddleware(async (ctx) => { - const session = await getSessionFromCtx(ctx); - if (!session?.session) throw new APIError("UNAUTHORIZED"); - if (ctx.context.sessionConfig.freshAge === 0) return { session }; - const freshAge = ctx.context.sessionConfig.freshAge; - const lastUpdated = new Date(session.session.updatedAt || session.session.createdAt).getTime(); - if (!(Date.now() - lastUpdated < freshAge * 1e3)) throw new APIError("FORBIDDEN", { message: "Session is not fresh" }); - return { session }; -}); -const listSessions = () => createAuthEndpoint("/list-sessions", { - method: "GET", - operationId: "listUserSessions", - use: [sessionMiddleware], - requireHeaders: true, - metadata: { openapi: { - operationId: "listUserSessions", - description: "List all active sessions for the user", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "array", - items: { $ref: "#/components/schemas/Session" } - } } } - } } - } } -}, async (ctx) => { - try { - const activeSessions = (await ctx.context.internalAdapter.listSessions(ctx.context.session.user.id)).filter((session) => { - return session.expiresAt > /* @__PURE__ */ new Date(); - }); - return ctx.json(activeSessions.map((session) => parseSessionOutput(ctx.context.options, session))); - } catch (e) { - ctx.context.logger.error(e); - throw ctx.error("INTERNAL_SERVER_ERROR"); - } -}); -const revokeSession = createAuthEndpoint("/revoke-session", { - method: "POST", - body: z.object({ token: z.string().meta({ description: "The token to revoke" }) }), - use: [sensitiveSessionMiddleware], - requireHeaders: true, - metadata: { openapi: { - description: "Revoke a single session", - requestBody: { content: { "application/json": { schema: { - type: "object", - properties: { token: { - type: "string", - description: "The token to revoke" - } }, - required: ["token"] - } } } }, - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { status: { - type: "boolean", - description: "Indicates if the session was revoked successfully" - } }, - required: ["status"] - } } } - } } - } } -}, async (ctx) => { - const token = ctx.body.token; - if ((await ctx.context.internalAdapter.findSession(token))?.session.userId === ctx.context.session.user.id) try { - await ctx.context.internalAdapter.deleteSession(token); - } catch (error2) { - ctx.context.logger.error(error2 && typeof error2 === "object" && "name" in error2 ? error2.name : "", error2); - throw new APIError("INTERNAL_SERVER_ERROR"); - } - return ctx.json({ status: true }); -}); -const revokeSessions = createAuthEndpoint("/revoke-sessions", { - method: "POST", - use: [sensitiveSessionMiddleware], - requireHeaders: true, - metadata: { openapi: { - description: "Revoke all sessions for the user", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { status: { - type: "boolean", - description: "Indicates if all sessions were revoked successfully" - } }, - required: ["status"] - } } } - } } - } } -}, async (ctx) => { - try { - await ctx.context.internalAdapter.deleteSessions(ctx.context.session.user.id); - } catch (error2) { - ctx.context.logger.error(error2 && typeof error2 === "object" && "name" in error2 ? error2.name : "", error2); - throw new APIError("INTERNAL_SERVER_ERROR"); - } - return ctx.json({ status: true }); -}); -const revokeOtherSessions = createAuthEndpoint("/revoke-other-sessions", { - method: "POST", - requireHeaders: true, - use: [sensitiveSessionMiddleware], - metadata: { openapi: { - description: "Revoke all other sessions for the user except the current one", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { status: { - type: "boolean", - description: "Indicates if all other sessions were revoked successfully" - } }, - required: ["status"] - } } } - } } - } } -}, async (ctx) => { - const session = ctx.context.session; - if (!session.user) throw new APIError("UNAUTHORIZED"); - const otherSessions = (await ctx.context.internalAdapter.listSessions(session.user.id)).filter((session$1) => { - return session$1.expiresAt > /* @__PURE__ */ new Date(); - }).filter((session$1) => session$1.token !== ctx.context.session.session.token); - await Promise.all(otherSessions.map((session$1) => ctx.context.internalAdapter.deleteSession(session$1.token))); - return ctx.json({ status: true }); -}); -const stateDataSchema = z.looseObject({ - callbackURL: z.string(), - codeVerifier: z.string(), - errorURL: z.string().optional(), - newUserURL: z.string().optional(), - expiresAt: z.number(), - link: z.object({ - email: z.string(), - userId: z.coerce.string() - }).optional(), - requestSignUp: z.boolean().optional() -}); -var StateError = class extends BetterAuthError { - code; - details; - constructor(message, options) { - super(message, options); - this.code = options.code; - this.details = options.details; - } -}; -async function generateGenericState(c, stateData, settings) { - const state = generateRandomString(32); - if (c.context.oauthConfig.storeStateStrategy === "cookie") { - const encryptedData = await symmetricEncrypt({ - key: c.context.secret, - data: JSON.stringify(stateData) - }); - const stateCookie$1 = c.context.createAuthCookie("oauth_state", { maxAge: 600 }); - c.setCookie(stateCookie$1.name, encryptedData, stateCookie$1.attributes); - return { - state, - codeVerifier: stateData.codeVerifier - }; - } - const stateCookie = c.context.createAuthCookie("state", { maxAge: 300 }); - await c.setSignedCookie(stateCookie.name, state, c.context.secret, stateCookie.attributes); - const expiresAt = /* @__PURE__ */ new Date(); - expiresAt.setMinutes(expiresAt.getMinutes() + 10); - const verification = await c.context.internalAdapter.createVerificationValue({ - value: JSON.stringify(stateData), - identifier: state, - expiresAt - }); - if (!verification) throw new StateError("Unable to create verification. Make sure the database adapter is properly working and there is a verification table in the database", { code: "state_generation_error" }); - return { - state: verification.identifier, - codeVerifier: stateData.codeVerifier - }; -} -async function parseGenericState(c, state, settings) { - const storeStateStrategy = c.context.oauthConfig.storeStateStrategy; - let parsedData; - if (storeStateStrategy === "cookie") { - const stateCookie = c.context.createAuthCookie("oauth_state"); - const encryptedData = c.getCookie(stateCookie.name); - if (!encryptedData) throw new StateError("State mismatch: auth state cookie not found", { - code: "state_mismatch", - details: { state } - }); - try { - const decryptedData = await symmetricDecrypt({ - key: c.context.secret, - data: encryptedData - }); - parsedData = stateDataSchema.parse(JSON.parse(decryptedData)); - } catch (error2) { - throw new StateError("State invalid: Failed to decrypt or parse auth state", { - code: "state_invalid", - details: { state }, - cause: error2 - }); - } - expireCookie(c, stateCookie); - } else { - const data = await c.context.internalAdapter.findVerificationValue(state); - if (!data) throw new StateError("State mismatch: verification not found", { - code: "state_mismatch", - details: { state } - }); - parsedData = stateDataSchema.parse(JSON.parse(data.value)); - const stateCookie = c.context.createAuthCookie("state"); - const stateCookieValue = await c.getSignedCookie(stateCookie.name, c.context.secret); - if (!c.context.oauthConfig.skipStateCookieCheck && (!stateCookieValue || stateCookieValue !== state)) throw new StateError("State mismatch: State not persisted correctly", { - code: "state_security_mismatch", - details: { state } - }); - expireCookie(c, stateCookie); - await c.context.internalAdapter.deleteVerificationValue(data.id); - } - if (parsedData.expiresAt < Date.now()) throw new StateError("Invalid state: request expired", { - code: "state_mismatch", - details: { expiresAt: parsedData.expiresAt } - }); - return parsedData; -} -async function generateState(c, link, additionalData) { - const callbackURL = c.body?.callbackURL || c.context.options.baseURL; - if (!callbackURL) throw new APIError("BAD_REQUEST", { message: "callbackURL is required" }); - const codeVerifier = generateRandomString(128); - const stateData = { - ...additionalData ? additionalData : {}, - callbackURL, - codeVerifier, - errorURL: c.body?.errorCallbackURL, - newUserURL: c.body?.newUserCallbackURL, - link, - expiresAt: Date.now() + 600 * 1e3, - requestSignUp: c.body?.requestSignUp - }; - await setOAuthState(stateData); - try { - return generateGenericState(c, stateData); - } catch (error2) { - c.context.logger.error("Failed to create verification", error2); - throw new APIError("INTERNAL_SERVER_ERROR", { - message: "Unable to create verification", - cause: error2 - }); - } -} -async function parseState(c) { - const state = c.query.state || c.body.state; - const errorURL = c.context.options.onAPIError?.errorURL || `${c.context.baseURL}/error`; - let parsedData; - try { - parsedData = await parseGenericState(c, state); - } catch (error2) { - c.context.logger.error("Failed to parse state", error2); - if (error2 instanceof StateError && error2.code === "state_security_mismatch") throw c.redirect(`${errorURL}?error=state_mismatch`); - throw c.redirect(`${errorURL}?error=please_restart_the_process`); - } - if (!parsedData.errorURL) parsedData.errorURL = errorURL; - if (parsedData) await setOAuthState(parsedData); - return parsedData; -} -function decryptOAuthToken(token, ctx) { - if (!token) return token; - if (ctx.options.account?.encryptOAuthTokens) return symmetricDecrypt({ - key: ctx.secret, - data: token - }); - return token; -} -function setTokenUtil(token, ctx) { - if (ctx.options.account?.encryptOAuthTokens && token) return symmetricEncrypt({ - key: ctx.secret, - data: token - }); - return token; -} -const listUserAccounts = createAuthEndpoint("/list-accounts", { - method: "GET", - use: [sessionMiddleware], - metadata: { openapi: { - operationId: "listUserAccounts", - description: "List all accounts linked to the user", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "array", - items: { - type: "object", - properties: { - id: { type: "string" }, - providerId: { type: "string" }, - createdAt: { - type: "string", - format: "date-time" - }, - updatedAt: { - type: "string", - format: "date-time" - }, - accountId: { type: "string" }, - userId: { type: "string" }, - scopes: { - type: "array", - items: { type: "string" } - } - }, - required: [ - "id", - "providerId", - "createdAt", - "updatedAt", - "accountId", - "userId", - "scopes" - ] - } - } } } - } } - } } -}, async (c) => { - const session = c.context.session; - const accounts = await c.context.internalAdapter.findAccounts(session.user.id); - return c.json(accounts.map((a) => { - const { scope, ...parsed } = parseAccountOutput(c.context.options, a); - return { - ...parsed, - scopes: scope?.split(",") || [] - }; - })); -}); -const linkSocialAccount = createAuthEndpoint("/link-social", { - method: "POST", - requireHeaders: true, - body: z.object({ - callbackURL: z.string().meta({ description: "The URL to redirect to after the user has signed in" }).optional(), - provider: SocialProviderListEnum, - idToken: z.object({ - token: z.string(), - nonce: z.string().optional(), - accessToken: z.string().optional(), - refreshToken: z.string().optional(), - scopes: z.array(z.string()).optional() - }).optional(), - requestSignUp: z.boolean().optional(), - scopes: z.array(z.string()).meta({ description: "Additional scopes to request from the provider" }).optional(), - errorCallbackURL: z.string().meta({ description: "The URL to redirect to if there is an error during the link process" }).optional(), - disableRedirect: z.boolean().meta({ description: "Disable automatic redirection to the provider. Useful for handling the redirection yourself" }).optional(), - additionalData: z.record(z.string(), z.any()).optional() - }), - use: [sessionMiddleware], - metadata: { openapi: { - description: "Link a social account to the user", - operationId: "linkSocialAccount", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { - url: { - type: "string", - description: "The authorization URL to redirect the user to" - }, - redirect: { - type: "boolean", - description: "Indicates if the user should be redirected to the authorization URL" - }, - status: { type: "boolean" } - }, - required: ["redirect"] - } } } - } } - } } -}, async (c) => { - const session = c.context.session; - const provider = c.context.socialProviders.find((p) => p.id === c.body.provider); - if (!provider) { - c.context.logger.error("Provider not found. Make sure to add the provider in your auth config", { provider: c.body.provider }); - throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.PROVIDER_NOT_FOUND }); - } - if (c.body.idToken) { - if (!provider.verifyIdToken) { - c.context.logger.error("Provider does not support id token verification", { provider: c.body.provider }); - throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.ID_TOKEN_NOT_SUPPORTED }); - } - const { token, nonce } = c.body.idToken; - if (!await provider.verifyIdToken(token, nonce)) { - c.context.logger.error("Invalid id token", { provider: c.body.provider }); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.INVALID_TOKEN }); - } - const linkingUserInfo = await provider.getUserInfo({ - idToken: token, - accessToken: c.body.idToken.accessToken, - refreshToken: c.body.idToken.refreshToken - }); - if (!linkingUserInfo || !linkingUserInfo?.user) { - c.context.logger.error("Failed to get user info", { provider: c.body.provider }); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.FAILED_TO_GET_USER_INFO }); - } - const linkingUserId = String(linkingUserInfo.user.id); - if (!linkingUserInfo.user.email) { - c.context.logger.error("User email not found", { provider: c.body.provider }); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.USER_EMAIL_NOT_FOUND }); - } - if ((await c.context.internalAdapter.findAccounts(session.user.id)).find((a) => a.providerId === provider.id && a.accountId === linkingUserId)) return c.json({ - url: "", - status: true, - redirect: false - }); - if (!c.context.options.account?.accountLinking?.trustedProviders?.includes(provider.id) && !linkingUserInfo.user.emailVerified || c.context.options.account?.accountLinking?.enabled === false) throw new APIError("UNAUTHORIZED", { message: "Account not linked - linking not allowed" }); - if (linkingUserInfo.user.email?.toLowerCase() !== session.user.email.toLowerCase() && c.context.options.account?.accountLinking?.allowDifferentEmails !== true) throw new APIError("UNAUTHORIZED", { message: "Account not linked - different emails not allowed" }); - try { - await c.context.internalAdapter.createAccount({ - userId: session.user.id, - providerId: provider.id, - accountId: linkingUserId, - accessToken: c.body.idToken.accessToken, - idToken: token, - refreshToken: c.body.idToken.refreshToken, - scope: c.body.idToken.scopes?.join(",") - }); - } catch { - throw new APIError("EXPECTATION_FAILED", { message: "Account not linked - unable to create account" }); - } - if (c.context.options.account?.accountLinking?.updateUserInfoOnLink === true) try { - await c.context.internalAdapter.updateUser(session.user.id, { - name: linkingUserInfo.user?.name, - image: linkingUserInfo.user?.image - }); - } catch (e) { - console.warn("Could not update user - " + e.toString()); - } - return c.json({ - url: "", - status: true, - redirect: false - }); - } - const state = await generateState(c, { - userId: session.user.id, - email: session.user.email - }, c.body.additionalData); - const url = await provider.createAuthorizationURL({ - state: state.state, - codeVerifier: state.codeVerifier, - redirectURI: `${c.context.baseURL}/callback/${provider.id}`, - scopes: c.body.scopes - }); - if (!c.body.disableRedirect) c.setHeader("Location", url.toString()); - return c.json({ - url: url.toString(), - redirect: !c.body.disableRedirect - }); -}); -const unlinkAccount = createAuthEndpoint("/unlink-account", { - method: "POST", - body: z.object({ - providerId: z.string(), - accountId: z.string().optional() - }), - use: [freshSessionMiddleware], - metadata: { openapi: { - description: "Unlink an account", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { status: { type: "boolean" } } - } } } - } } - } } -}, async (ctx) => { - const { providerId, accountId } = ctx.body; - const accounts = await ctx.context.internalAdapter.findAccounts(ctx.context.session.user.id); - if (accounts.length === 1 && !ctx.context.options.account?.accountLinking?.allowUnlinkingAll) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.FAILED_TO_UNLINK_LAST_ACCOUNT }); - const accountExist = accounts.find((account) => accountId ? account.accountId === accountId && account.providerId === providerId : account.providerId === providerId); - if (!accountExist) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.ACCOUNT_NOT_FOUND }); - await ctx.context.internalAdapter.deleteAccount(accountExist.id); - return ctx.json({ status: true }); -}); -const getAccessToken = createAuthEndpoint("/get-access-token", { - method: "POST", - body: z.object({ - providerId: z.string().meta({ description: "The provider ID for the OAuth provider" }), - accountId: z.string().meta({ description: "The account ID associated with the refresh token" }).optional(), - userId: z.string().meta({ description: "The user ID associated with the account" }).optional() - }), - metadata: { openapi: { - description: "Get a valid access token, doing a refresh if needed", - responses: { - 200: { - description: "A Valid access token", - content: { "application/json": { schema: { - type: "object", - properties: { - tokenType: { type: "string" }, - idToken: { type: "string" }, - accessToken: { type: "string" }, - accessTokenExpiresAt: { - type: "string", - format: "date-time" - } - } - } } } - }, - 400: { description: "Invalid refresh token or provider configuration" } - } - } } -}, async (ctx) => { - const { providerId, accountId, userId } = ctx.body || {}; - const req = ctx.request; - const session = await getSessionFromCtx(ctx); - if (req && !session) throw ctx.error("UNAUTHORIZED"); - const resolvedUserId = session?.user?.id || userId; - if (!resolvedUserId) throw ctx.error("UNAUTHORIZED"); - if (!ctx.context.socialProviders.find((p) => p.id === providerId)) throw new APIError("BAD_REQUEST", { message: `Provider ${providerId} is not supported.` }); - const accountData = await getAccountCookie(ctx); - let account = void 0; - if (accountData && providerId === accountData.providerId && (!accountId || accountData.id === accountId)) account = accountData; - else account = (await ctx.context.internalAdapter.findAccounts(resolvedUserId)).find((acc) => accountId ? acc.id === accountId && acc.providerId === providerId : acc.providerId === providerId); - if (!account) throw new APIError("BAD_REQUEST", { message: "Account not found" }); - const provider = ctx.context.socialProviders.find((p) => p.id === providerId); - if (!provider) throw new APIError("BAD_REQUEST", { message: `Provider ${providerId} not found.` }); - try { - let newTokens = null; - const accessTokenExpired = account.accessTokenExpiresAt && new Date(account.accessTokenExpiresAt).getTime() - Date.now() < 5e3; - if (account.refreshToken && accessTokenExpired && provider.refreshAccessToken) { - const refreshToken$1 = await decryptOAuthToken(account.refreshToken, ctx.context); - newTokens = await provider.refreshAccessToken(refreshToken$1); - const updatedData = { - accessToken: await setTokenUtil(newTokens.accessToken, ctx.context), - accessTokenExpiresAt: newTokens.accessTokenExpiresAt, - refreshToken: await setTokenUtil(newTokens.refreshToken, ctx.context), - refreshTokenExpiresAt: newTokens.refreshTokenExpiresAt - }; - let updatedAccount = null; - if (account.id) updatedAccount = await ctx.context.internalAdapter.updateAccount(account.id, updatedData); - if (ctx.context.options.account?.storeAccountCookie) await setAccountCookie(ctx, { - ...account, - ...updatedAccount ?? updatedData - }); - } - const accessTokenExpiresAt = (() => { - if (newTokens?.accessTokenExpiresAt) { - if (typeof newTokens.accessTokenExpiresAt === "string") return new Date(newTokens.accessTokenExpiresAt); - return newTokens.accessTokenExpiresAt; - } - if (account.accessTokenExpiresAt) { - if (typeof account.accessTokenExpiresAt === "string") return new Date(account.accessTokenExpiresAt); - return account.accessTokenExpiresAt; - } - })(); - const tokens = { - accessToken: newTokens?.accessToken ?? await decryptOAuthToken(account.accessToken ?? "", ctx.context), - accessTokenExpiresAt, - scopes: account.scope?.split(",") ?? [], - idToken: newTokens?.idToken ?? account.idToken ?? void 0 - }; - return ctx.json(tokens); - } catch (error2) { - throw new APIError("BAD_REQUEST", { - message: "Failed to get a valid access token", - cause: error2 - }); - } -}); -const refreshToken = createAuthEndpoint("/refresh-token", { - method: "POST", - body: z.object({ - providerId: z.string().meta({ description: "The provider ID for the OAuth provider" }), - accountId: z.string().meta({ description: "The account ID associated with the refresh token" }).optional(), - userId: z.string().meta({ description: "The user ID associated with the account" }).optional() - }), - metadata: { openapi: { - description: "Refresh the access token using a refresh token", - responses: { - 200: { - description: "Access token refreshed successfully", - content: { "application/json": { schema: { - type: "object", - properties: { - tokenType: { type: "string" }, - idToken: { type: "string" }, - accessToken: { type: "string" }, - refreshToken: { type: "string" }, - accessTokenExpiresAt: { - type: "string", - format: "date-time" - }, - refreshTokenExpiresAt: { - type: "string", - format: "date-time" - } - } - } } } - }, - 400: { description: "Invalid refresh token or provider configuration" } - } - } } -}, async (ctx) => { - const { providerId, accountId, userId } = ctx.body; - const req = ctx.request; - const session = await getSessionFromCtx(ctx); - if (req && !session) throw ctx.error("UNAUTHORIZED"); - const resolvedUserId = session?.user?.id || userId; - if (!resolvedUserId) throw new APIError("BAD_REQUEST", { message: `Either userId or session is required` }); - const provider = ctx.context.socialProviders.find((p) => p.id === providerId); - if (!provider) throw new APIError("BAD_REQUEST", { message: `Provider ${providerId} not found.` }); - if (!provider.refreshAccessToken) throw new APIError("BAD_REQUEST", { message: `Provider ${providerId} does not support token refreshing.` }); - let account = void 0; - const accountData = await getAccountCookie(ctx); - if (accountData && (!providerId || providerId === accountData?.providerId)) account = accountData; - else account = (await ctx.context.internalAdapter.findAccounts(resolvedUserId)).find((acc) => accountId ? acc.id === accountId && acc.providerId === providerId : acc.providerId === providerId); - if (!account) throw new APIError("BAD_REQUEST", { message: "Account not found" }); - let refreshToken$1 = void 0; - if (accountData && providerId === accountData.providerId) refreshToken$1 = accountData.refreshToken ?? void 0; - else refreshToken$1 = account.refreshToken ?? void 0; - if (!refreshToken$1) throw new APIError("BAD_REQUEST", { message: "Refresh token not found" }); - try { - const decryptedRefreshToken = await decryptOAuthToken(refreshToken$1, ctx.context); - const tokens = await provider.refreshAccessToken(decryptedRefreshToken); - if (account.id) { - const updateData = { - ...account || {}, - accessToken: await setTokenUtil(tokens.accessToken, ctx.context), - refreshToken: await setTokenUtil(tokens.refreshToken, ctx.context), - accessTokenExpiresAt: tokens.accessTokenExpiresAt, - refreshTokenExpiresAt: tokens.refreshTokenExpiresAt, - scope: tokens.scopes?.join(",") || account.scope, - idToken: tokens.idToken || account.idToken - }; - await ctx.context.internalAdapter.updateAccount(account.id, updateData); - } - if (accountData && providerId === accountData.providerId && ctx.context.options.account?.storeAccountCookie) await setAccountCookie(ctx, { - ...accountData, - accessToken: await setTokenUtil(tokens.accessToken, ctx.context), - refreshToken: await setTokenUtil(tokens.refreshToken, ctx.context), - accessTokenExpiresAt: tokens.accessTokenExpiresAt, - refreshTokenExpiresAt: tokens.refreshTokenExpiresAt, - scope: tokens.scopes?.join(",") || accountData.scope, - idToken: tokens.idToken || accountData.idToken - }); - return ctx.json({ - accessToken: tokens.accessToken, - refreshToken: tokens.refreshToken, - accessTokenExpiresAt: tokens.accessTokenExpiresAt, - refreshTokenExpiresAt: tokens.refreshTokenExpiresAt, - scope: tokens.scopes?.join(",") || account.scope, - idToken: tokens.idToken || account.idToken, - providerId: account.providerId, - accountId: account.accountId - }); - } catch (error2) { - throw new APIError("BAD_REQUEST", { - message: "Failed to refresh access token", - cause: error2 - }); - } -}); -const accountInfoQuerySchema = z.optional(z.object({ accountId: z.string().meta({ description: "The provider given account id for which to get the account info" }).optional() })); -const accountInfo = createAuthEndpoint("/account-info", { - method: "GET", - use: [sessionMiddleware], - metadata: { openapi: { - description: "Get the account info provided by the provider", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { - user: { - type: "object", - properties: { - id: { type: "string" }, - name: { type: "string" }, - email: { type: "string" }, - image: { type: "string" }, - emailVerified: { type: "boolean" } - }, - required: ["id", "emailVerified"] - }, - data: { - type: "object", - properties: {}, - additionalProperties: true - } - }, - required: ["user", "data"], - additionalProperties: false - } } } - } } - } }, - query: accountInfoQuerySchema -}, async (ctx) => { - const providedAccountId = ctx.query?.accountId; - let account = void 0; - if (!providedAccountId) { - if (ctx.context.options.account?.storeAccountCookie) { - const accountData = await getAccountCookie(ctx); - if (accountData) account = accountData; - } - } else { - const accountData = await ctx.context.internalAdapter.findAccount(providedAccountId); - if (accountData) account = accountData; - } - if (!account || account.userId !== ctx.context.session.user.id) throw new APIError("BAD_REQUEST", { message: "Account not found" }); - const provider = ctx.context.socialProviders.find((p) => p.id === account.providerId); - if (!provider) throw new APIError("INTERNAL_SERVER_ERROR", { message: `Provider account provider is ${account.providerId} but it is not configured` }); - const tokens = await getAccessToken({ - ...ctx, - method: "POST", - body: { - accountId: account.id, - providerId: account.providerId - }, - returnHeaders: false, - returnStatus: false - }); - if (!tokens.accessToken) throw new APIError("BAD_REQUEST", { message: "Access token not found" }); - const info2 = await provider.getUserInfo({ - ...tokens, - accessToken: tokens.accessToken - }); - return ctx.json(info2); -}); -async function createEmailVerificationToken(secret, email, updateTo, expiresIn = 3600, extraPayload) { - return await signJWT({ - email: email.toLowerCase(), - updateTo, - ...extraPayload - }, secret, expiresIn); -} -async function sendVerificationEmailFn(ctx, user) { - if (!ctx.context.options.emailVerification?.sendVerificationEmail) { - ctx.context.logger.error("Verification email isn't enabled."); - throw new APIError("BAD_REQUEST", { message: "Verification email isn't enabled" }); - } - const token = await createEmailVerificationToken(ctx.context.secret, user.email, void 0, ctx.context.options.emailVerification?.expiresIn); - const callbackURL = ctx.body.callbackURL ? encodeURIComponent(ctx.body.callbackURL) : encodeURIComponent("/"); - const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${callbackURL}`; - await ctx.context.runInBackgroundOrAwait(ctx.context.options.emailVerification.sendVerificationEmail({ - user, - url, - token - }, ctx.request)); -} -const sendVerificationEmail = createAuthEndpoint("/send-verification-email", { - method: "POST", - operationId: "sendVerificationEmail", - body: z.object({ - email: z.email().meta({ description: "The email to send the verification email to" }), - callbackURL: z.string().meta({ description: "The URL to use for email verification callback" }).optional() - }), - metadata: { openapi: { - operationId: "sendVerificationEmail", - description: "Send a verification email to the user", - requestBody: { content: { "application/json": { schema: { - type: "object", - properties: { - email: { - type: "string", - description: "The email to send the verification email to", - example: "user@example.com" - }, - callbackURL: { - type: "string", - description: "The URL to use for email verification callback", - example: "https://example.com/callback", - nullable: true - } - }, - required: ["email"] - } } } }, - responses: { - "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { status: { - type: "boolean", - description: "Indicates if the email was sent successfully", - example: true - } } - } } } - }, - "400": { - description: "Bad Request", - content: { "application/json": { schema: { - type: "object", - properties: { message: { - type: "string", - description: "Error message", - example: "Verification email isn't enabled" - } } - } } } - } - } - } } -}, async (ctx) => { - if (!ctx.context.options.emailVerification?.sendVerificationEmail) { - ctx.context.logger.error("Verification email isn't enabled."); - throw new APIError("BAD_REQUEST", { message: "Verification email isn't enabled" }); - } - const { email } = ctx.body; - const session = await getSessionFromCtx(ctx); - if (!session) { - const user = await ctx.context.internalAdapter.findUserByEmail(email); - if (!user || user.user.emailVerified) { - await createEmailVerificationToken(ctx.context.secret, email, void 0, ctx.context.options.emailVerification?.expiresIn); - return ctx.json({ status: true }); - } - await sendVerificationEmailFn(ctx, user.user); - return ctx.json({ status: true }); - } - if (session?.user.email !== email) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.EMAIL_MISMATCH }); - if (session?.user.emailVerified) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.EMAIL_ALREADY_VERIFIED }); - await sendVerificationEmailFn(ctx, session.user); - return ctx.json({ status: true }); -}); -const verifyEmail = createAuthEndpoint("/verify-email", { - method: "GET", - operationId: "verifyEmail", - query: z.object({ - token: z.string().meta({ description: "The token to verify the email" }), - callbackURL: z.string().meta({ description: "The URL to redirect to after email verification" }).optional() - }), - use: [originCheck((ctx) => ctx.query.callbackURL)], - metadata: { openapi: { - description: "Verify the email of the user", - parameters: [{ - name: "token", - in: "query", - description: "The token to verify the email", - required: true, - schema: { type: "string" } - }, { - name: "callbackURL", - in: "query", - description: "The URL to redirect to after email verification", - required: false, - schema: { type: "string" } - }], - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { - user: { - type: "object", - $ref: "#/components/schemas/User" - }, - status: { - type: "boolean", - description: "Indicates if the email was verified successfully" - } - }, - required: ["user", "status"] - } } } - } } - } } -}, async (ctx) => { - function redirectOnError(error2) { - if (ctx.query.callbackURL) { - if (ctx.query.callbackURL.includes("?")) throw ctx.redirect(`${ctx.query.callbackURL}&error=${error2}`); - throw ctx.redirect(`${ctx.query.callbackURL}?error=${error2}`); - } - throw new APIError("UNAUTHORIZED", { message: error2 }); - } - const { token } = ctx.query; - let jwt; - try { - jwt = await jwtVerify(token, new TextEncoder().encode(ctx.context.secret), { algorithms: ["HS256"] }); - } catch (e) { - if (e instanceof JWTExpired) return redirectOnError("token_expired"); - return redirectOnError("invalid_token"); - } - const parsed = z.object({ - email: z.email(), - updateTo: z.string().optional(), - requestType: z.string().optional() - }).parse(jwt.payload); - const user = await ctx.context.internalAdapter.findUserByEmail(parsed.email); - if (!user) return redirectOnError("user_not_found"); - if (parsed.updateTo) { - const session = await getSessionFromCtx(ctx); - if (session && session.user.email !== parsed.email) return redirectOnError("unauthorized"); - switch (parsed.requestType) { - case "change-email-confirmation": { - const newToken = await createEmailVerificationToken(ctx.context.secret, parsed.email, parsed.updateTo, ctx.context.options.emailVerification?.expiresIn, { requestType: "change-email-verification" }); - const updateCallbackURL = ctx.query.callbackURL ? encodeURIComponent(ctx.query.callbackURL) : encodeURIComponent("/"); - const url = `${ctx.context.baseURL}/verify-email?token=${newToken}&callbackURL=${updateCallbackURL}`; - if (ctx.context.options.emailVerification?.sendVerificationEmail) await ctx.context.runInBackgroundOrAwait(ctx.context.options.emailVerification.sendVerificationEmail({ - user: { - ...user.user, - email: parsed.updateTo - }, - url, - token: newToken - }, ctx.request)); - if (ctx.query.callbackURL) throw ctx.redirect(ctx.query.callbackURL); - return ctx.json({ status: true }); - } - case "change-email-verification": { - let activeSession = session; - if (!activeSession) { - const newSession = await ctx.context.internalAdapter.createSession(user.user.id); - if (!newSession) throw new APIError("INTERNAL_SERVER_ERROR", { message: BASE_ERROR_CODES.FAILED_TO_CREATE_SESSION }); - activeSession = { - session: newSession, - user: user.user - }; - } - if (ctx.context.options.emailVerification?.onEmailVerification) await ctx.context.options.emailVerification.onEmailVerification(user.user, ctx.request); - const updatedUser$1 = await ctx.context.internalAdapter.updateUserByEmail(parsed.email, { - email: parsed.updateTo, - emailVerified: true - }); - if (ctx.context.options.emailVerification?.afterEmailVerification) await ctx.context.options.emailVerification.afterEmailVerification(updatedUser$1, ctx.request); - await setSessionCookie(ctx, { - session: activeSession.session, - user: { - ...activeSession.user, - email: parsed.updateTo, - emailVerified: true - } - }); - if (ctx.query.callbackURL) throw ctx.redirect(ctx.query.callbackURL); - return ctx.json({ - status: true, - user: parseUserOutput(ctx.context.options, updatedUser$1) - }); - } - default: { - let activeSession = session; - if (!activeSession) { - const newSession = await ctx.context.internalAdapter.createSession(user.user.id); - if (!newSession) throw new APIError("INTERNAL_SERVER_ERROR", { message: BASE_ERROR_CODES.FAILED_TO_CREATE_SESSION }); - activeSession = { - session: newSession, - user: user.user - }; - } - const updatedUser$1 = await ctx.context.internalAdapter.updateUserByEmail(parsed.email, { - email: parsed.updateTo, - emailVerified: false - }); - const newToken = await createEmailVerificationToken(ctx.context.secret, parsed.updateTo); - const updateCallbackURL = ctx.query.callbackURL ? encodeURIComponent(ctx.query.callbackURL) : encodeURIComponent("/"); - if (ctx.context.options.emailVerification?.sendVerificationEmail) await ctx.context.runInBackgroundOrAwait(ctx.context.options.emailVerification.sendVerificationEmail({ - user: updatedUser$1, - url: `${ctx.context.baseURL}/verify-email?token=${newToken}&callbackURL=${updateCallbackURL}`, - token: newToken - }, ctx.request)); - await setSessionCookie(ctx, { - session: activeSession.session, - user: { - ...activeSession.user, - email: parsed.updateTo, - emailVerified: false - } - }); - if (ctx.query.callbackURL) throw ctx.redirect(ctx.query.callbackURL); - return ctx.json({ - status: true, - user: parseUserOutput(ctx.context.options, updatedUser$1) - }); - } - } - } - if (user.user.emailVerified) { - if (ctx.query.callbackURL) throw ctx.redirect(ctx.query.callbackURL); - return ctx.json({ - status: true, - user: null - }); - } - if (ctx.context.options.emailVerification?.beforeEmailVerification) await ctx.context.options.emailVerification.beforeEmailVerification(user.user, ctx.request); - if (ctx.context.options.emailVerification?.onEmailVerification) await ctx.context.options.emailVerification.onEmailVerification(user.user, ctx.request); - const updatedUser = await ctx.context.internalAdapter.updateUserByEmail(parsed.email, { emailVerified: true }); - if (ctx.context.options.emailVerification?.afterEmailVerification) await ctx.context.options.emailVerification.afterEmailVerification(updatedUser, ctx.request); - if (ctx.context.options.emailVerification?.autoSignInAfterVerification) { - const currentSession = await getSessionFromCtx(ctx); - if (!currentSession || currentSession.user.email !== parsed.email) { - const session = await ctx.context.internalAdapter.createSession(user.user.id); - if (!session) throw new APIError("INTERNAL_SERVER_ERROR", { message: "Failed to create session" }); - await setSessionCookie(ctx, { - session, - user: { - ...user.user, - emailVerified: true - } - }); - } else await setSessionCookie(ctx, { - session: currentSession.session, - user: { - ...currentSession.user, - emailVerified: true - } - }); - } - if (ctx.query.callbackURL) throw ctx.redirect(ctx.query.callbackURL); - return ctx.json({ - status: true, - user: null - }); -}); -async function handleOAuthUserInfo(c, opts) { - const { userInfo, account, callbackURL, disableSignUp, overrideUserInfo } = opts; - const dbUser = await c.context.internalAdapter.findOAuthUser(userInfo.email.toLowerCase(), account.accountId, account.providerId).catch((e) => { - logger.error("Better auth was unable to query your database.\nError: ", e); - const errorURL = c.context.options.onAPIError?.errorURL || `${c.context.baseURL}/error`; - throw c.redirect(`${errorURL}?error=internal_server_error`); - }); - let user = dbUser?.user; - const isRegister = !user; - if (dbUser) { - const linkedAccount = dbUser.linkedAccount ?? dbUser.accounts.find((acc) => acc.providerId === account.providerId && acc.accountId === account.accountId); - if (!linkedAccount) { - const accountLinking = c.context.options.account?.accountLinking; - const trustedProviders = c.context.options.account?.accountLinking?.trustedProviders; - if (!(opts.isTrustedProvider || trustedProviders?.includes(account.providerId)) && !userInfo.emailVerified || accountLinking?.enabled === false || accountLinking?.disableImplicitLinking === true) { - if (isDevelopment()) logger.warn(`User already exist but account isn't linked to ${account.providerId}. To read more about how account linking works in Better Auth see https://www.better-auth.com/docs/concepts/users-accounts#account-linking.`); - return { - error: "account not linked", - data: null - }; - } - try { - await c.context.internalAdapter.linkAccount({ - providerId: account.providerId, - accountId: userInfo.id.toString(), - userId: dbUser.user.id, - accessToken: await setTokenUtil(account.accessToken, c.context), - refreshToken: await setTokenUtil(account.refreshToken, c.context), - idToken: account.idToken, - accessTokenExpiresAt: account.accessTokenExpiresAt, - refreshTokenExpiresAt: account.refreshTokenExpiresAt, - scope: account.scope - }); - } catch (e) { - logger.error("Unable to link account", e); - return { - error: "unable to link account", - data: null - }; - } - if (userInfo.emailVerified && !dbUser.user.emailVerified && userInfo.email.toLowerCase() === dbUser.user.email) await c.context.internalAdapter.updateUser(dbUser.user.id, { emailVerified: true }); - } else { - const freshTokens = c.context.options.account?.updateAccountOnSignIn !== false ? Object.fromEntries(Object.entries({ - idToken: account.idToken, - accessToken: await setTokenUtil(account.accessToken, c.context), - refreshToken: await setTokenUtil(account.refreshToken, c.context), - accessTokenExpiresAt: account.accessTokenExpiresAt, - refreshTokenExpiresAt: account.refreshTokenExpiresAt, - scope: account.scope - }).filter(([_, value]) => value !== void 0)) : {}; - if (c.context.options.account?.storeAccountCookie) await setAccountCookie(c, { - ...linkedAccount, - ...freshTokens - }); - if (Object.keys(freshTokens).length > 0) await c.context.internalAdapter.updateAccount(linkedAccount.id, freshTokens); - if (userInfo.emailVerified && !dbUser.user.emailVerified && userInfo.email.toLowerCase() === dbUser.user.email) await c.context.internalAdapter.updateUser(dbUser.user.id, { emailVerified: true }); - } - if (overrideUserInfo) { - const { id: _, ...restUserInfo } = userInfo; - user = await c.context.internalAdapter.updateUser(dbUser.user.id, { - ...restUserInfo, - email: userInfo.email.toLowerCase(), - emailVerified: userInfo.email.toLowerCase() === dbUser.user.email ? dbUser.user.emailVerified || userInfo.emailVerified : userInfo.emailVerified - }); - } - } else { - if (disableSignUp) return { - error: "signup disabled", - data: null, - isRegister: false - }; - try { - const { id: _, ...restUserInfo } = userInfo; - const accountData = { - accessToken: await setTokenUtil(account.accessToken, c.context), - refreshToken: await setTokenUtil(account.refreshToken, c.context), - idToken: account.idToken, - accessTokenExpiresAt: account.accessTokenExpiresAt, - refreshTokenExpiresAt: account.refreshTokenExpiresAt, - scope: account.scope, - providerId: account.providerId, - accountId: userInfo.id.toString() - }; - const { user: createdUser, account: createdAccount } = await c.context.internalAdapter.createOAuthUser({ - ...restUserInfo, - email: userInfo.email.toLowerCase() - }, accountData); - user = createdUser; - if (c.context.options.account?.storeAccountCookie) await setAccountCookie(c, createdAccount); - if (!userInfo.emailVerified && user && c.context.options.emailVerification?.sendOnSignUp && c.context.options.emailVerification?.sendVerificationEmail) { - const token = await createEmailVerificationToken(c.context.secret, user.email, void 0, c.context.options.emailVerification?.expiresIn); - const url = `${c.context.baseURL}/verify-email?token=${token}&callbackURL=${callbackURL}`; - await c.context.runInBackgroundOrAwait(c.context.options.emailVerification.sendVerificationEmail({ - user, - url, - token - }, c.request)); - } - } catch (e) { - logger.error(e); - if (e instanceof APIError) return { - error: e.message, - data: null, - isRegister: false - }; - return { - error: "unable to create user", - data: null, - isRegister: false - }; - } - } - if (!user) return { - error: "unable to create user", - data: null, - isRegister: false - }; - const session = await c.context.internalAdapter.createSession(user.id); - if (!session) return { - error: "unable to create session", - data: null, - isRegister: false - }; - return { - data: { - session, - user - }, - error: null, - isRegister - }; -} -const HIDE_METADATA = { scope: "server" }; -const schema = z.object({ - code: z.string().optional(), - error: z.string().optional(), - device_id: z.string().optional(), - error_description: z.string().optional(), - state: z.string().optional(), - user: z.string().optional() -}); -const callbackOAuth = createAuthEndpoint("/callback/:id", { - method: ["GET", "POST"], - operationId: "handleOAuthCallback", - body: schema.optional(), - query: schema.optional(), - metadata: { - ...HIDE_METADATA, - allowedMediaTypes: ["application/x-www-form-urlencoded", "application/json"] - } -}, async (c) => { - let queryOrBody; - const defaultErrorURL = c.context.options.onAPIError?.errorURL || `${c.context.baseURL}/error`; - if (c.method === "POST") { - const postData = c.body ? schema.parse(c.body) : {}; - const queryData = c.query ? schema.parse(c.query) : {}; - const mergedData = schema.parse({ - ...postData, - ...queryData - }); - const params = new URLSearchParams(); - for (const [key, value] of Object.entries(mergedData)) if (value !== void 0 && value !== null) params.set(key, String(value)); - const redirectURL = `${c.context.baseURL}/callback/${c.params.id}?${params.toString()}`; - throw c.redirect(redirectURL); - } - try { - if (c.method === "GET") queryOrBody = schema.parse(c.query); - else if (c.method === "POST") queryOrBody = schema.parse(c.body); - else throw new Error("Unsupported method"); - } catch (e) { - c.context.logger.error("INVALID_CALLBACK_REQUEST", e); - throw c.redirect(`${defaultErrorURL}?error=invalid_callback_request`); - } - const { code, error: error2, state, error_description, device_id, user: userData } = queryOrBody; - if (!state) { - c.context.logger.error("State not found", error2); - const url = `${defaultErrorURL}${defaultErrorURL.includes("?") ? "&" : "?"}state=state_not_found`; - throw c.redirect(url); - } - const { codeVerifier, callbackURL, link, errorURL, newUserURL, requestSignUp } = await parseState(c); - function redirectOnError(error$1, description) { - const baseURL = errorURL ?? defaultErrorURL; - const params = new URLSearchParams({ error: error$1 }); - if (description) params.set("error_description", description); - const url = `${baseURL}${baseURL.includes("?") ? "&" : "?"}${params.toString()}`; - throw c.redirect(url); - } - if (error2) redirectOnError(error2, error_description); - if (!code) { - c.context.logger.error("Code not found"); - throw redirectOnError("no_code"); - } - const provider = c.context.socialProviders.find((p) => p.id === c.params.id); - if (!provider) { - c.context.logger.error("Oauth provider with id", c.params.id, "not found"); - throw redirectOnError("oauth_provider_not_found"); - } - let tokens; - try { - tokens = await provider.validateAuthorizationCode({ - code, - codeVerifier, - deviceId: device_id, - redirectURI: `${c.context.baseURL}/callback/${provider.id}` - }); - } catch (e) { - c.context.logger.error("", e); - throw redirectOnError("invalid_code"); - } - if (!tokens) throw redirectOnError("invalid_code"); - const parsedUserData = userData ? safeJSONParse(userData) : null; - const userInfo = await provider.getUserInfo({ - ...tokens, - user: parsedUserData ?? void 0 - }).then((res) => res?.user); - if (!userInfo) { - c.context.logger.error("Unable to get user info"); - return redirectOnError("unable_to_get_user_info"); - } - if (!callbackURL) { - c.context.logger.error("No callback URL found"); - throw redirectOnError("no_callback_url"); - } - if (link) { - if (!c.context.options.account?.accountLinking?.trustedProviders?.includes(provider.id) && !userInfo.emailVerified || c.context.options.account?.accountLinking?.enabled === false) { - c.context.logger.error("Unable to link account - untrusted provider"); - return redirectOnError("unable_to_link_account"); - } - if (userInfo.email?.toLowerCase() !== link.email.toLowerCase() && c.context.options.account?.accountLinking?.allowDifferentEmails !== true) return redirectOnError("email_doesn't_match"); - const existingAccount = await c.context.internalAdapter.findAccount(String(userInfo.id)); - if (existingAccount) { - if (existingAccount.userId.toString() !== link.userId.toString()) return redirectOnError("account_already_linked_to_different_user"); - const updateData = Object.fromEntries(Object.entries({ - accessToken: await setTokenUtil(tokens.accessToken, c.context), - refreshToken: await setTokenUtil(tokens.refreshToken, c.context), - idToken: tokens.idToken, - accessTokenExpiresAt: tokens.accessTokenExpiresAt, - refreshTokenExpiresAt: tokens.refreshTokenExpiresAt, - scope: tokens.scopes?.join(",") - }).filter(([_, value]) => value !== void 0)); - await c.context.internalAdapter.updateAccount(existingAccount.id, updateData); - } else if (!await c.context.internalAdapter.createAccount({ - userId: link.userId, - providerId: provider.id, - accountId: String(userInfo.id), - ...tokens, - accessToken: await setTokenUtil(tokens.accessToken, c.context), - refreshToken: await setTokenUtil(tokens.refreshToken, c.context), - scope: tokens.scopes?.join(",") - })) return redirectOnError("unable_to_link_account"); - let toRedirectTo$1; - try { - toRedirectTo$1 = callbackURL.toString(); - } catch { - toRedirectTo$1 = callbackURL; - } - throw c.redirect(toRedirectTo$1); - } - if (!userInfo.email) { - c.context.logger.error("Provider did not return email. This could be due to misconfiguration in the provider settings."); - return redirectOnError("email_not_found"); - } - const accountData = { - providerId: provider.id, - accountId: String(userInfo.id), - ...tokens, - scope: tokens.scopes?.join(",") - }; - const result = await handleOAuthUserInfo(c, { - userInfo: { - ...userInfo, - id: String(userInfo.id), - email: userInfo.email, - name: userInfo.name || userInfo.email - }, - account: accountData, - callbackURL, - disableSignUp: provider.disableImplicitSignUp && !requestSignUp || provider.options?.disableSignUp, - overrideUserInfo: provider.options?.overrideUserInfoOnSignIn - }); - if (result.error) { - c.context.logger.error(result.error.split(" ").join("_")); - return redirectOnError(result.error.split(" ").join("_")); - } - const { session, user } = result.data; - await setSessionCookie(c, { - session, - user - }); - let toRedirectTo; - try { - toRedirectTo = (result.isRegister ? newUserURL || callbackURL : callbackURL).toString(); - } catch { - toRedirectTo = result.isRegister ? newUserURL || callbackURL : callbackURL; - } - throw c.redirect(toRedirectTo); -}); -function sanitize(input) { - return input.replace(//g, ">").replace(/"/g, """).replace(/'/g, "'").replace(/&(?!amp;|lt;|gt;|quot;|#39;|#x[0-9a-fA-F]+;|#[0-9]+;)/g, "&"); -} -const html = (options, code = "Unknown", description = null) => { - const custom = options.onAPIError?.customizeDefaultErrorPage; - return ` - - - - - Error - - - -
-${custom?.disableBackgroundGrid ? "" : ` -
-
-`} - -
- ${custom?.disableCornerDecorations ? "" : ` - -
-
- -
-
`} - -
-
-
-

- ERROR -

-
-
-
- -

- Something went wrong -

- -
- - CODE: - - - ${sanitize(code)} - -
- -

- ${!description ? `We encountered an unexpected error. Please try again or return to the home page. If you're a developer, you can find more information about the error here.` : description} -

-
- - -
-
- -`; -}; -const error = createAuthEndpoint("/error", { - method: "GET", - metadata: { - ...HIDE_METADATA, - openapi: { - description: "Displays an error page", - responses: { "200": { - description: "Success", - content: { "text/html": { schema: { - type: "string", - description: "The HTML content of the error page" - } } } - } } - } - } -}, async (c) => { - const url = new URL(c.request?.url || ""); - const unsanitizedCode = url.searchParams.get("error") || "UNKNOWN"; - const unsanitizedDescription = url.searchParams.get("error_description") || null; - const safeCode = /^[\'A-Za-z0-9_-]+$/.test(unsanitizedCode) ? unsanitizedCode : "UNKNOWN"; - const safeDescription = unsanitizedDescription ? sanitize(unsanitizedDescription) : null; - const queryParams = new URLSearchParams(); - queryParams.set("error", safeCode); - if (unsanitizedDescription) queryParams.set("error_description", unsanitizedDescription); - const options = c.context.options; - const errorURL = options.onAPIError?.errorURL; - if (errorURL) return new Response(null, { - status: 302, - headers: { Location: `${errorURL}${errorURL.includes("?") ? "&" : "?"}${queryParams.toString()}` } - }); - if (isProduction && !options.onAPIError?.customizeDefaultErrorPage) return new Response(null, { - status: 302, - headers: { Location: `/?${queryParams.toString()}` } - }); - return new Response(html(c.context.options, safeCode, safeDescription), { headers: { "Content-Type": "text/html" } }); -}); -const ok = createAuthEndpoint("/ok", { - method: "GET", - metadata: { - ...HIDE_METADATA, - openapi: { - description: "Check if the API is working", - responses: { "200": { - description: "API is working", - content: { "application/json": { schema: { - type: "object", - properties: { ok: { - type: "boolean", - description: "Indicates if the API is working" - } }, - required: ["ok"] - } } } - } } - } - } -}, async (ctx) => { - return ctx.json({ ok: true }); -}); -async function validatePassword(ctx, data) { - const credentialAccount = (await ctx.context.internalAdapter.findAccounts(data.userId))?.find((account) => account.providerId === "credential"); - const currentPassword = credentialAccount?.password; - if (!credentialAccount || !currentPassword) return false; - return await ctx.context.password.verify({ - hash: currentPassword, - password: data.password - }); -} -async function checkPassword(userId, c) { - const credentialAccount = (await c.context.internalAdapter.findAccounts(userId))?.find((account) => account.providerId === "credential"); - const currentPassword = credentialAccount?.password; - if (!credentialAccount || !currentPassword || !c.body.password) throw new APIError("BAD_REQUEST", { message: "No password credential found" }); - if (!await c.context.password.verify({ - hash: currentPassword, - password: c.body.password - })) throw new APIError("BAD_REQUEST", { message: "Invalid password" }); - return true; -} -function redirectError(ctx, callbackURL, query) { - const url = callbackURL ? new URL(callbackURL, ctx.baseURL) : new URL(`${ctx.baseURL}/error`); - if (query) Object.entries(query).forEach(([k, v]) => url.searchParams.set(k, v)); - return url.href; -} -function redirectCallback(ctx, callbackURL, query) { - const url = new URL(callbackURL, ctx.baseURL); - if (query) Object.entries(query).forEach(([k, v]) => url.searchParams.set(k, v)); - return url.href; -} -const requestPasswordReset = createAuthEndpoint("/request-password-reset", { - method: "POST", - body: z.object({ - email: z.email().meta({ description: "The email address of the user to send a password reset email to" }), - redirectTo: z.string().meta({ description: "The URL to redirect the user to reset their password. If the token isn't valid or expired, it'll be redirected with a query parameter `?error=INVALID_TOKEN`. If the token is valid, it'll be redirected with a query parameter `?token=VALID_TOKEN" }).optional() - }), - metadata: { openapi: { - operationId: "requestPasswordReset", - description: "Send a password reset email to the user", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { - status: { type: "boolean" }, - message: { type: "string" } - } - } } } - } } - } } -}, async (ctx) => { - if (!ctx.context.options.emailAndPassword?.sendResetPassword) { - ctx.context.logger.error("Reset password isn't enabled.Please pass an emailAndPassword.sendResetPassword function in your auth config!"); - throw new APIError("BAD_REQUEST", { message: "Reset password isn't enabled" }); - } - const { email, redirectTo } = ctx.body; - const user = await ctx.context.internalAdapter.findUserByEmail(email, { includeAccounts: true }); - if (!user) { - generateId(24); - await ctx.context.internalAdapter.findVerificationValue("dummy-verification-token"); - ctx.context.logger.error("Reset Password: User not found", { email }); - return ctx.json({ - status: true, - message: "If this email exists in our system, check your email for the reset link" - }); - } - const expiresAt = getDate(ctx.context.options.emailAndPassword.resetPasswordTokenExpiresIn || 3600 * 1, "sec"); - const verificationToken = generateId(24); - await ctx.context.internalAdapter.createVerificationValue({ - value: user.user.id, - identifier: `reset-password:${verificationToken}`, - expiresAt - }); - const callbackURL = redirectTo ? encodeURIComponent(redirectTo) : ""; - const url = `${ctx.context.baseURL}/reset-password/${verificationToken}?callbackURL=${callbackURL}`; - await ctx.context.runInBackgroundOrAwait(ctx.context.options.emailAndPassword.sendResetPassword({ - user: user.user, - url, - token: verificationToken - }, ctx.request)); - return ctx.json({ - status: true, - message: "If this email exists in our system, check your email for the reset link" - }); -}); -const requestPasswordResetCallback = createAuthEndpoint("/reset-password/:token", { - method: "GET", - operationId: "forgetPasswordCallback", - query: z.object({ callbackURL: z.string().meta({ description: "The URL to redirect the user to reset their password" }) }), - use: [originCheck((ctx) => ctx.query.callbackURL)], - metadata: { openapi: { - operationId: "resetPasswordCallback", - description: "Redirects the user to the callback URL with the token", - parameters: [{ - name: "token", - in: "path", - required: true, - description: "The token to reset the password", - schema: { type: "string" } - }, { - name: "callbackURL", - in: "query", - required: true, - description: "The URL to redirect the user to reset their password", - schema: { type: "string" } - }], - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { token: { type: "string" } } - } } } - } } - } } -}, async (ctx) => { - const { token } = ctx.params; - const { callbackURL } = ctx.query; - if (!token || !callbackURL) throw ctx.redirect(redirectError(ctx.context, callbackURL, { error: "INVALID_TOKEN" })); - const verification = await ctx.context.internalAdapter.findVerificationValue(`reset-password:${token}`); - if (!verification || verification.expiresAt < /* @__PURE__ */ new Date()) throw ctx.redirect(redirectError(ctx.context, callbackURL, { error: "INVALID_TOKEN" })); - throw ctx.redirect(redirectCallback(ctx.context, callbackURL, { token })); -}); -const resetPassword = createAuthEndpoint("/reset-password", { - method: "POST", - operationId: "resetPassword", - query: z.object({ token: z.string().optional() }).optional(), - body: z.object({ - newPassword: z.string().meta({ description: "The new password to set" }), - token: z.string().meta({ description: "The token to reset the password" }).optional() - }), - metadata: { openapi: { - operationId: "resetPassword", - description: "Reset the password for a user", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { status: { type: "boolean" } } - } } } - } } - } } -}, async (ctx) => { - const token = ctx.body.token || ctx.query?.token; - if (!token) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_TOKEN }); - const { newPassword } = ctx.body; - const minLength = ctx.context.password?.config.minPasswordLength; - const maxLength = ctx.context.password?.config.maxPasswordLength; - if (newPassword.length < minLength) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_SHORT }); - if (newPassword.length > maxLength) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_LONG }); - const id = `reset-password:${token}`; - const verification = await ctx.context.internalAdapter.findVerificationValue(id); - if (!verification || verification.expiresAt < /* @__PURE__ */ new Date()) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_TOKEN }); - const userId = verification.value; - const hashedPassword = await ctx.context.password.hash(newPassword); - if (!(await ctx.context.internalAdapter.findAccounts(userId)).find((ac) => ac.providerId === "credential")) await ctx.context.internalAdapter.createAccount({ - userId, - providerId: "credential", - password: hashedPassword, - accountId: userId - }); - else await ctx.context.internalAdapter.updatePassword(userId, hashedPassword); - await ctx.context.internalAdapter.deleteVerificationValue(verification.id); - if (ctx.context.options.emailAndPassword?.onPasswordReset) { - const user = await ctx.context.internalAdapter.findUserById(userId); - if (user) await ctx.context.options.emailAndPassword.onPasswordReset({ user }, ctx.request); - } - if (ctx.context.options.emailAndPassword?.revokeSessionsOnPasswordReset) await ctx.context.internalAdapter.deleteSessions(userId); - return ctx.json({ status: true }); -}); -const verifyPassword = createAuthEndpoint("/verify-password", { - method: "POST", - body: z.object({ password: z.string().meta({ description: "The password to verify" }) }), - metadata: { - scope: "server", - openapi: { - operationId: "verifyPassword", - description: "Verify the current user's password", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { status: { type: "boolean" } } - } } } - } } - } - }, - use: [sensitiveSessionMiddleware] -}, async (ctx) => { - const { password } = ctx.body; - const session = ctx.context.session; - if (!await validatePassword(ctx, { - password, - userId: session.user.id - })) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_PASSWORD }); - return ctx.json({ status: true }); -}); -const socialSignInBodySchema = z.object({ - callbackURL: z.string().meta({ description: "Callback URL to redirect to after the user has signed in" }).optional(), - newUserCallbackURL: z.string().optional(), - errorCallbackURL: z.string().meta({ description: "Callback URL to redirect to if an error happens" }).optional(), - provider: SocialProviderListEnum, - disableRedirect: z.boolean().meta({ description: "Disable automatic redirection to the provider. Useful for handling the redirection yourself" }).optional(), - idToken: z.optional(z.object({ - token: z.string().meta({ description: "ID token from the provider" }), - nonce: z.string().meta({ description: "Nonce used to generate the token" }).optional(), - accessToken: z.string().meta({ description: "Access token from the provider" }).optional(), - refreshToken: z.string().meta({ description: "Refresh token from the provider" }).optional(), - expiresAt: z.number().meta({ description: "Expiry date of the token" }).optional() - })), - scopes: z.array(z.string()).meta({ description: "Array of scopes to request from the provider. This will override the default scopes passed." }).optional(), - requestSignUp: z.boolean().meta({ description: "Explicitly request sign-up. Useful when disableImplicitSignUp is true for this provider" }).optional(), - loginHint: z.string().meta({ description: "The login hint to use for the authorization code request" }).optional(), - additionalData: z.record(z.string(), z.any()).optional().meta({ description: "Additional data to be passed through the OAuth flow" }) -}); -const signInSocial = () => createAuthEndpoint("/sign-in/social", { - method: "POST", - operationId: "socialSignIn", - body: socialSignInBodySchema, - metadata: { - $Infer: { - body: {}, - returned: {} - }, - openapi: { - description: "Sign in with a social provider", - operationId: "socialSignIn", - responses: { "200": { - description: "Success - Returns either session details or redirect URL", - content: { "application/json": { schema: { - type: "object", - description: "Session response when idToken is provided", - properties: { - token: { type: "string" }, - user: { - type: "object", - $ref: "#/components/schemas/User" - }, - url: { type: "string" }, - redirect: { - type: "boolean", - enum: [false] - } - }, - required: [ - "redirect", - "token", - "user" - ] - } } } - } } - } - } -}, async (c) => { - const provider = c.context.socialProviders.find((p) => p.id === c.body.provider); - if (!provider) { - c.context.logger.error("Provider not found. Make sure to add the provider in your auth config", { provider: c.body.provider }); - throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.PROVIDER_NOT_FOUND }); - } - if (c.body.idToken) { - if (!provider.verifyIdToken) { - c.context.logger.error("Provider does not support id token verification", { provider: c.body.provider }); - throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.ID_TOKEN_NOT_SUPPORTED }); - } - const { token, nonce } = c.body.idToken; - if (!await provider.verifyIdToken(token, nonce)) { - c.context.logger.error("Invalid id token", { provider: c.body.provider }); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.INVALID_TOKEN }); - } - const userInfo = await provider.getUserInfo({ - idToken: token, - accessToken: c.body.idToken.accessToken, - refreshToken: c.body.idToken.refreshToken - }); - if (!userInfo || !userInfo?.user) { - c.context.logger.error("Failed to get user info", { provider: c.body.provider }); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.FAILED_TO_GET_USER_INFO }); - } - if (!userInfo.user.email) { - c.context.logger.error("User email not found", { provider: c.body.provider }); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.USER_EMAIL_NOT_FOUND }); - } - const data = await handleOAuthUserInfo(c, { - userInfo: { - ...userInfo.user, - email: userInfo.user.email, - id: String(userInfo.user.id), - name: userInfo.user.name || "", - image: userInfo.user.image, - emailVerified: userInfo.user.emailVerified || false - }, - account: { - providerId: provider.id, - accountId: String(userInfo.user.id), - accessToken: c.body.idToken.accessToken - }, - callbackURL: c.body.callbackURL, - disableSignUp: provider.disableImplicitSignUp && !c.body.requestSignUp || provider.disableSignUp - }); - if (data.error) throw new APIError("UNAUTHORIZED", { message: data.error }); - await setSessionCookie(c, data.data); - return c.json({ - redirect: false, - token: data.data.session.token, - url: void 0, - user: parseUserOutput(c.context.options, data.data.user) - }); - } - const { codeVerifier, state } = await generateState(c, void 0, c.body.additionalData); - const url = await provider.createAuthorizationURL({ - state, - codeVerifier, - redirectURI: `${c.context.baseURL}/callback/${provider.id}`, - scopes: c.body.scopes, - loginHint: c.body.loginHint - }); - if (!c.body.disableRedirect) c.setHeader("Location", url.toString()); - return c.json({ - url: url.toString(), - redirect: !c.body.disableRedirect - }); -}); -const signInEmail = () => createAuthEndpoint("/sign-in/email", { - method: "POST", - operationId: "signInEmail", - use: [formCsrfMiddleware], - body: z.object({ - email: z.string().meta({ description: "Email of the user" }), - password: z.string().meta({ description: "Password of the user" }), - callbackURL: z.string().meta({ description: "Callback URL to use as a redirect for email verification" }).optional(), - rememberMe: z.boolean().meta({ description: "If this is false, the session will not be remembered. Default is `true`." }).default(true).optional() - }), - metadata: { - allowedMediaTypes: ["application/x-www-form-urlencoded", "application/json"], - $Infer: { - body: {}, - returned: {} - }, - openapi: { - operationId: "signInEmail", - description: "Sign in with email and password", - responses: { "200": { - description: "Success - Returns either session details or redirect URL", - content: { "application/json": { schema: { - type: "object", - description: "Session response when idToken is provided", - properties: { - redirect: { - type: "boolean", - enum: [false] - }, - token: { - type: "string", - description: "Session token" - }, - url: { - type: "string", - nullable: true - }, - user: { - type: "object", - $ref: "#/components/schemas/User" - } - }, - required: [ - "redirect", - "token", - "user" - ] - } } } - } } - } - } -}, async (ctx) => { - if (!ctx.context.options?.emailAndPassword?.enabled) { - ctx.context.logger.error("Email and password is not enabled. Make sure to enable it in the options on you `auth.ts` file. Check `https://better-auth.com/docs/authentication/email-password` for more!"); - throw new APIError("BAD_REQUEST", { message: "Email and password is not enabled" }); - } - const { email, password } = ctx.body; - if (!z.email().safeParse(email).success) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_EMAIL }); - const user = await ctx.context.internalAdapter.findUserByEmail(email, { includeAccounts: true }); - if (!user) { - await ctx.context.password.hash(password); - ctx.context.logger.error("User not found", { email }); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD }); - } - const credentialAccount = user.accounts.find((a) => a.providerId === "credential"); - if (!credentialAccount) { - await ctx.context.password.hash(password); - ctx.context.logger.error("Credential account not found", { email }); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD }); - } - const currentPassword = credentialAccount?.password; - if (!currentPassword) { - await ctx.context.password.hash(password); - ctx.context.logger.error("Password not found", { email }); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD }); - } - if (!await ctx.context.password.verify({ - hash: currentPassword, - password - })) { - ctx.context.logger.error("Invalid password"); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD }); - } - if (ctx.context.options?.emailAndPassword?.requireEmailVerification && !user.user.emailVerified) { - if (!ctx.context.options?.emailVerification?.sendVerificationEmail) throw new APIError("FORBIDDEN", { message: BASE_ERROR_CODES.EMAIL_NOT_VERIFIED }); - if (ctx.context.options?.emailVerification?.sendOnSignIn) { - const token = await createEmailVerificationToken(ctx.context.secret, user.user.email, void 0, ctx.context.options.emailVerification?.expiresIn); - const callbackURL = ctx.body.callbackURL ? encodeURIComponent(ctx.body.callbackURL) : encodeURIComponent("/"); - const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${callbackURL}`; - await ctx.context.runInBackgroundOrAwait(ctx.context.options.emailVerification.sendVerificationEmail({ - user: user.user, - url, - token - }, ctx.request)); - } - throw new APIError("FORBIDDEN", { message: BASE_ERROR_CODES.EMAIL_NOT_VERIFIED }); - } - const session = await ctx.context.internalAdapter.createSession(user.user.id, ctx.body.rememberMe === false); - if (!session) { - ctx.context.logger.error("Failed to create session"); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.FAILED_TO_CREATE_SESSION }); - } - await setSessionCookie(ctx, { - session, - user: user.user - }, ctx.body.rememberMe === false); - if (ctx.body.callbackURL) ctx.setHeader("Location", ctx.body.callbackURL); - return ctx.json({ - redirect: !!ctx.body.callbackURL, - token: session.token, - url: ctx.body.callbackURL, - user: parseUserOutput(ctx.context.options, user.user) - }); -}); -const signOut = createAuthEndpoint("/sign-out", { - method: "POST", - operationId: "signOut", - requireHeaders: true, - metadata: { openapi: { - operationId: "signOut", - description: "Sign out the current user", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { success: { type: "boolean" } } - } } } - } } - } } -}, async (ctx) => { - const sessionCookieToken = await ctx.getSignedCookie(ctx.context.authCookies.sessionToken.name, ctx.context.secret); - if (sessionCookieToken) try { - await ctx.context.internalAdapter.deleteSession(sessionCookieToken); - } catch (e) { - ctx.context.logger.error("Failed to delete session from database", e); - } - deleteSessionCookie(ctx); - return ctx.json({ success: true }); -}); -const signUpEmailBodySchema = z.object({ - name: z.string(), - email: z.email(), - password: z.string().nonempty(), - image: z.string().optional(), - callbackURL: z.string().optional(), - rememberMe: z.boolean().optional() -}).and(z.record(z.string(), z.any())); -const signUpEmail = () => createAuthEndpoint("/sign-up/email", { - method: "POST", - operationId: "signUpWithEmailAndPassword", - use: [formCsrfMiddleware], - body: signUpEmailBodySchema, - metadata: { - allowedMediaTypes: ["application/x-www-form-urlencoded", "application/json"], - $Infer: { - body: {}, - returned: {} - }, - openapi: { - operationId: "signUpWithEmailAndPassword", - description: "Sign up a user using email and password", - requestBody: { content: { "application/json": { schema: { - type: "object", - properties: { - name: { - type: "string", - description: "The name of the user" - }, - email: { - type: "string", - description: "The email of the user" - }, - password: { - type: "string", - description: "The password of the user" - }, - image: { - type: "string", - description: "The profile image URL of the user" - }, - callbackURL: { - type: "string", - description: "The URL to use for email verification callback" - }, - rememberMe: { - type: "boolean", - description: "If this is false, the session will not be remembered. Default is `true`." - } - }, - required: [ - "name", - "email", - "password" - ] - } } } }, - responses: { - "200": { - description: "Successfully created user", - content: { "application/json": { schema: { - type: "object", - properties: { - token: { - type: "string", - nullable: true, - description: "Authentication token for the session" - }, - user: { - type: "object", - properties: { - id: { - type: "string", - description: "The unique identifier of the user" - }, - email: { - type: "string", - format: "email", - description: "The email address of the user" - }, - name: { - type: "string", - description: "The name of the user" - }, - image: { - type: "string", - format: "uri", - nullable: true, - description: "The profile image URL of the user" - }, - emailVerified: { - type: "boolean", - description: "Whether the email has been verified" - }, - createdAt: { - type: "string", - format: "date-time", - description: "When the user was created" - }, - updatedAt: { - type: "string", - format: "date-time", - description: "When the user was last updated" - } - }, - required: [ - "id", - "email", - "name", - "emailVerified", - "createdAt", - "updatedAt" - ] - } - }, - required: ["user"] - } } } - }, - "422": { - description: "Unprocessable Entity. User already exists or failed to create user.", - content: { "application/json": { schema: { - type: "object", - properties: { message: { type: "string" } } - } } } - } - } - } - } -}, async (ctx) => { - return runWithTransaction(ctx.context.adapter, async () => { - if (!ctx.context.options.emailAndPassword?.enabled || ctx.context.options.emailAndPassword?.disableSignUp) throw new APIError("BAD_REQUEST", { message: "Email and password sign up is not enabled" }); - const body = ctx.body; - const { name, email, password, image, callbackURL: _callbackURL, rememberMe, ...rest } = body; - if (!z.email().safeParse(email).success) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_EMAIL }); - if (!password || typeof password !== "string") throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_PASSWORD }); - const minPasswordLength = ctx.context.password.config.minPasswordLength; - if (password.length < minPasswordLength) { - ctx.context.logger.error("Password is too short"); - throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_SHORT }); - } - const maxPasswordLength = ctx.context.password.config.maxPasswordLength; - if (password.length > maxPasswordLength) { - ctx.context.logger.error("Password is too long"); - throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_LONG }); - } - if ((await ctx.context.internalAdapter.findUserByEmail(email))?.user) { - ctx.context.logger.info(`Sign-up attempt for existing email: ${email}`); - throw new APIError("UNPROCESSABLE_ENTITY", { message: BASE_ERROR_CODES.USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL }); - } - const hash = await ctx.context.password.hash(password); - let createdUser; - try { - const data = parseUserInput(ctx.context.options, rest, "create"); - createdUser = await ctx.context.internalAdapter.createUser({ - email: email.toLowerCase(), - name, - image, - ...data, - emailVerified: false - }); - if (!createdUser) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.FAILED_TO_CREATE_USER }); - } catch (e) { - if (isDevelopment()) ctx.context.logger.error("Failed to create user", e); - if (e instanceof APIError) throw e; - ctx.context.logger?.error("Failed to create user", e); - throw new APIError("UNPROCESSABLE_ENTITY", { message: BASE_ERROR_CODES.FAILED_TO_CREATE_USER }); - } - if (!createdUser) throw new APIError("UNPROCESSABLE_ENTITY", { message: BASE_ERROR_CODES.FAILED_TO_CREATE_USER }); - await ctx.context.internalAdapter.linkAccount({ - userId: createdUser.id, - providerId: "credential", - accountId: createdUser.id, - password: hash - }); - if (ctx.context.options.emailVerification?.sendOnSignUp ?? ctx.context.options.emailAndPassword.requireEmailVerification) { - const token = await createEmailVerificationToken(ctx.context.secret, createdUser.email, void 0, ctx.context.options.emailVerification?.expiresIn); - const callbackURL = body.callbackURL ? encodeURIComponent(body.callbackURL) : encodeURIComponent("/"); - const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${callbackURL}`; - if (ctx.context.options.emailVerification?.sendVerificationEmail) await ctx.context.runInBackgroundOrAwait(ctx.context.options.emailVerification.sendVerificationEmail({ - user: createdUser, - url, - token - }, ctx.request)); - } - if (ctx.context.options.emailAndPassword.autoSignIn === false || ctx.context.options.emailAndPassword.requireEmailVerification) return ctx.json({ - token: null, - user: parseUserOutput(ctx.context.options, createdUser) - }); - const session = await ctx.context.internalAdapter.createSession(createdUser.id, rememberMe === false); - if (!session) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.FAILED_TO_CREATE_SESSION }); - await setSessionCookie(ctx, { - session, - user: createdUser - }, rememberMe === false); - return ctx.json({ - token: session.token, - user: parseUserOutput(ctx.context.options, createdUser) - }); - }); -}); -const updateUserBodySchema = z.record(z.string().meta({ description: "Field name must be a string" }), z.any()); -const updateUser = () => createAuthEndpoint("/update-user", { - method: "POST", - operationId: "updateUser", - body: updateUserBodySchema, - use: [sessionMiddleware], - metadata: { - $Infer: { body: {} }, - openapi: { - operationId: "updateUser", - description: "Update the current user", - requestBody: { content: { "application/json": { schema: { - type: "object", - properties: { - name: { - type: "string", - description: "The name of the user" - }, - image: { - type: "string", - description: "The image of the user", - nullable: true - } - } - } } } }, - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { user: { - type: "object", - $ref: "#/components/schemas/User" - } } - } } } - } } - } - } -}, async (ctx) => { - const body = ctx.body; - if (typeof body !== "object" || Array.isArray(body)) throw new APIError("BAD_REQUEST", { message: "Body must be an object" }); - if (body.email) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.EMAIL_CAN_NOT_BE_UPDATED }); - const { name, image, ...rest } = body; - const session = ctx.context.session; - const additionalFields = parseUserInput(ctx.context.options, rest, "update"); - if (image === void 0 && name === void 0 && Object.keys(additionalFields).length === 0) throw new APIError("BAD_REQUEST", { message: "No fields to update" }); - const updatedUser = await ctx.context.internalAdapter.updateUser(session.user.id, { - name, - image, - ...additionalFields - }) ?? { - ...session.user, - ...name !== void 0 && { name }, - ...image !== void 0 && { image }, - ...additionalFields - }; - await setSessionCookie(ctx, { - session: session.session, - user: updatedUser - }); - return ctx.json({ status: true }); -}); -const changePassword = createAuthEndpoint("/change-password", { - method: "POST", - operationId: "changePassword", - body: z.object({ - newPassword: z.string().meta({ description: "The new password to set" }), - currentPassword: z.string().meta({ description: "The current password is required" }), - revokeOtherSessions: z.boolean().meta({ description: "Must be a boolean value" }).optional() - }), - use: [sensitiveSessionMiddleware], - metadata: { openapi: { - operationId: "changePassword", - description: "Change the password of the user", - responses: { "200": { - description: "Password successfully changed", - content: { "application/json": { schema: { - type: "object", - properties: { - token: { - type: "string", - nullable: true, - description: "New session token if other sessions were revoked" - }, - user: { - type: "object", - properties: { - id: { - type: "string", - description: "The unique identifier of the user" - }, - email: { - type: "string", - format: "email", - description: "The email address of the user" - }, - name: { - type: "string", - description: "The name of the user" - }, - image: { - type: "string", - format: "uri", - nullable: true, - description: "The profile image URL of the user" - }, - emailVerified: { - type: "boolean", - description: "Whether the email has been verified" - }, - createdAt: { - type: "string", - format: "date-time", - description: "When the user was created" - }, - updatedAt: { - type: "string", - format: "date-time", - description: "When the user was last updated" - } - }, - required: [ - "id", - "email", - "name", - "emailVerified", - "createdAt", - "updatedAt" - ] - } - }, - required: ["user"] - } } } - } } - } } -}, async (ctx) => { - const { newPassword, currentPassword, revokeOtherSessions: revokeOtherSessions2 } = ctx.body; - const session = ctx.context.session; - const minPasswordLength = ctx.context.password.config.minPasswordLength; - if (newPassword.length < minPasswordLength) { - ctx.context.logger.error("Password is too short"); - throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_SHORT }); - } - const maxPasswordLength = ctx.context.password.config.maxPasswordLength; - if (newPassword.length > maxPasswordLength) { - ctx.context.logger.error("Password is too long"); - throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_LONG }); - } - const account = (await ctx.context.internalAdapter.findAccounts(session.user.id)).find((account$1) => account$1.providerId === "credential" && account$1.password); - if (!account || !account.password) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.CREDENTIAL_ACCOUNT_NOT_FOUND }); - const passwordHash = await ctx.context.password.hash(newPassword); - if (!await ctx.context.password.verify({ - hash: account.password, - password: currentPassword - })) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_PASSWORD }); - await ctx.context.internalAdapter.updateAccount(account.id, { password: passwordHash }); - let token = null; - if (revokeOtherSessions2) { - await ctx.context.internalAdapter.deleteSessions(session.user.id); - const newSession = await ctx.context.internalAdapter.createSession(session.user.id); - if (!newSession) throw new APIError("INTERNAL_SERVER_ERROR", { message: BASE_ERROR_CODES.FAILED_TO_GET_SESSION }); - await setSessionCookie(ctx, { - session: newSession, - user: session.user - }); - token = newSession.token; - } - return ctx.json({ - token, - user: parseUserOutput(ctx.context.options, session.user) - }); -}); -const setPassword = createAuthEndpoint({ - method: "POST", - body: z.object({ newPassword: z.string().meta({ description: "The new password to set is required" }) }), - use: [sensitiveSessionMiddleware] -}, async (ctx) => { - const { newPassword } = ctx.body; - const session = ctx.context.session; - const minPasswordLength = ctx.context.password.config.minPasswordLength; - if (newPassword.length < minPasswordLength) { - ctx.context.logger.error("Password is too short"); - throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_SHORT }); - } - const maxPasswordLength = ctx.context.password.config.maxPasswordLength; - if (newPassword.length > maxPasswordLength) { - ctx.context.logger.error("Password is too long"); - throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_LONG }); - } - const account = (await ctx.context.internalAdapter.findAccounts(session.user.id)).find((account$1) => account$1.providerId === "credential" && account$1.password); - const passwordHash = await ctx.context.password.hash(newPassword); - if (!account) { - await ctx.context.internalAdapter.linkAccount({ - userId: session.user.id, - providerId: "credential", - accountId: session.user.id, - password: passwordHash - }); - return ctx.json({ status: true }); - } - throw new APIError("BAD_REQUEST", { message: "user already has a password" }); -}); -const deleteUser = createAuthEndpoint("/delete-user", { - method: "POST", - use: [sensitiveSessionMiddleware], - body: z.object({ - callbackURL: z.string().meta({ description: "The callback URL to redirect to after the user is deleted" }).optional(), - password: z.string().meta({ description: "The password of the user is required to delete the user" }).optional(), - token: z.string().meta({ description: "The token to delete the user is required" }).optional() - }), - metadata: { openapi: { - operationId: "deleteUser", - description: "Delete the user", - requestBody: { content: { "application/json": { schema: { - type: "object", - properties: { - callbackURL: { - type: "string", - description: "The callback URL to redirect to after the user is deleted" - }, - password: { - type: "string", - description: "The user's password. Required if session is not fresh" - }, - token: { - type: "string", - description: "The deletion verification token" - } - } - } } } }, - responses: { "200": { - description: "User deletion processed successfully", - content: { "application/json": { schema: { - type: "object", - properties: { - success: { - type: "boolean", - description: "Indicates if the operation was successful" - }, - message: { - type: "string", - enum: ["User deleted", "Verification email sent"], - description: "Status message of the deletion process" - } - }, - required: ["success", "message"] - } } } - } } - } } -}, async (ctx) => { - if (!ctx.context.options.user?.deleteUser?.enabled) { - ctx.context.logger.error("Delete user is disabled. Enable it in the options"); - throw new APIError("NOT_FOUND"); - } - const session = ctx.context.session; - if (ctx.body.password) { - const account = (await ctx.context.internalAdapter.findAccounts(session.user.id)).find((account$1) => account$1.providerId === "credential" && account$1.password); - if (!account || !account.password) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.CREDENTIAL_ACCOUNT_NOT_FOUND }); - if (!await ctx.context.password.verify({ - hash: account.password, - password: ctx.body.password - })) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_PASSWORD }); - } - if (ctx.body.token) { - await deleteUserCallback({ - ...ctx, - query: { token: ctx.body.token } - }); - return ctx.json({ - success: true, - message: "User deleted" - }); - } - if (ctx.context.options.user.deleteUser?.sendDeleteAccountVerification) { - const token = generateRandomString(32, "0-9", "a-z"); - await ctx.context.internalAdapter.createVerificationValue({ - value: session.user.id, - identifier: `delete-account-${token}`, - expiresAt: new Date(Date.now() + (ctx.context.options.user.deleteUser?.deleteTokenExpiresIn || 3600 * 24) * 1e3) - }); - const url = `${ctx.context.baseURL}/delete-user/callback?token=${token}&callbackURL=${encodeURIComponent(ctx.body.callbackURL || "/")}`; - await ctx.context.runInBackgroundOrAwait(ctx.context.options.user.deleteUser.sendDeleteAccountVerification({ - user: session.user, - url, - token - }, ctx.request)); - return ctx.json({ - success: true, - message: "Verification email sent" - }); - } - if (!ctx.body.password && ctx.context.sessionConfig.freshAge !== 0) { - const currentAge = new Date(session.session.createdAt).getTime(); - const freshAge = ctx.context.sessionConfig.freshAge * 1e3; - if (Date.now() - currentAge > freshAge * 1e3) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.SESSION_EXPIRED }); - } - const beforeDelete = ctx.context.options.user.deleteUser?.beforeDelete; - if (beforeDelete) await beforeDelete(session.user, ctx.request); - await ctx.context.internalAdapter.deleteUser(session.user.id); - await ctx.context.internalAdapter.deleteSessions(session.user.id); - deleteSessionCookie(ctx); - const afterDelete = ctx.context.options.user.deleteUser?.afterDelete; - if (afterDelete) await afterDelete(session.user, ctx.request); - return ctx.json({ - success: true, - message: "User deleted" - }); -}); -const deleteUserCallback = createAuthEndpoint("/delete-user/callback", { - method: "GET", - query: z.object({ - token: z.string().meta({ description: "The token to verify the deletion request" }), - callbackURL: z.string().meta({ description: "The URL to redirect to after deletion" }).optional() - }), - use: [originCheck((ctx) => ctx.query.callbackURL)], - metadata: { openapi: { - description: "Callback to complete user deletion with verification token", - responses: { "200": { - description: "User successfully deleted", - content: { "application/json": { schema: { - type: "object", - properties: { - success: { - type: "boolean", - description: "Indicates if the deletion was successful" - }, - message: { - type: "string", - enum: ["User deleted"], - description: "Confirmation message" - } - }, - required: ["success", "message"] - } } } - } } - } } -}, async (ctx) => { - if (!ctx.context.options.user?.deleteUser?.enabled) { - ctx.context.logger.error("Delete user is disabled. Enable it in the options"); - throw new APIError("NOT_FOUND"); - } - const session = await getSessionFromCtx(ctx); - if (!session) throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.FAILED_TO_GET_USER_INFO }); - const token = await ctx.context.internalAdapter.findVerificationValue(`delete-account-${ctx.query.token}`); - if (!token || token.expiresAt < /* @__PURE__ */ new Date()) throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.INVALID_TOKEN }); - if (token.value !== session.user.id) throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.INVALID_TOKEN }); - const beforeDelete = ctx.context.options.user.deleteUser?.beforeDelete; - if (beforeDelete) await beforeDelete(session.user, ctx.request); - await ctx.context.internalAdapter.deleteUser(session.user.id); - await ctx.context.internalAdapter.deleteSessions(session.user.id); - await ctx.context.internalAdapter.deleteAccounts(session.user.id); - await ctx.context.internalAdapter.deleteVerificationValue(token.id); - deleteSessionCookie(ctx); - const afterDelete = ctx.context.options.user.deleteUser?.afterDelete; - if (afterDelete) await afterDelete(session.user, ctx.request); - if (ctx.query.callbackURL) throw ctx.redirect(ctx.query.callbackURL || "/"); - return ctx.json({ - success: true, - message: "User deleted" - }); -}); -const changeEmail = createAuthEndpoint("/change-email", { - method: "POST", - body: z.object({ - newEmail: z.email().meta({ description: "The new email address to set must be a valid email address" }), - callbackURL: z.string().meta({ description: "The URL to redirect to after email verification" }).optional() - }), - use: [sensitiveSessionMiddleware], - metadata: { openapi: { - operationId: "changeEmail", - responses: { - "200": { - description: "Email change request processed successfully", - content: { "application/json": { schema: { - type: "object", - properties: { - user: { - type: "object", - $ref: "#/components/schemas/User" - }, - status: { - type: "boolean", - description: "Indicates if the request was successful" - }, - message: { - type: "string", - enum: ["Email updated", "Verification email sent"], - description: "Status message of the email change process", - nullable: true - } - }, - required: ["status"] - } } } - }, - "422": { - description: "Unprocessable Entity. Email already exists", - content: { "application/json": { schema: { - type: "object", - properties: { message: { type: "string" } } - } } } - } - } - } } -}, async (ctx) => { - if (!ctx.context.options.user?.changeEmail?.enabled) { - ctx.context.logger.error("Change email is disabled."); - throw new APIError("BAD_REQUEST", { message: "Change email is disabled" }); - } - const newEmail = ctx.body.newEmail.toLowerCase(); - if (newEmail === ctx.context.session.user.email) { - ctx.context.logger.error("Email is the same"); - throw new APIError("BAD_REQUEST", { message: "Email is the same" }); - } - if (await ctx.context.internalAdapter.findUserByEmail(newEmail)) { - ctx.context.logger.error("Email already exists"); - throw new APIError("UNPROCESSABLE_ENTITY", { message: BASE_ERROR_CODES.USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL }); - } - if (ctx.context.session.user.emailVerified !== true && ctx.context.options.user.changeEmail.updateEmailWithoutVerification) { - await ctx.context.internalAdapter.updateUserByEmail(ctx.context.session.user.email, { email: newEmail }); - await setSessionCookie(ctx, { - session: ctx.context.session.session, - user: { - ...ctx.context.session.user, - email: newEmail - } - }); - if (ctx.context.options.emailVerification?.sendVerificationEmail) { - const token$1 = await createEmailVerificationToken(ctx.context.secret, newEmail, void 0, ctx.context.options.emailVerification?.expiresIn); - const url$1 = `${ctx.context.baseURL}/verify-email?token=${token$1}&callbackURL=${ctx.body.callbackURL || "/"}`; - await ctx.context.runInBackgroundOrAwait(ctx.context.options.emailVerification.sendVerificationEmail({ - user: { - ...ctx.context.session.user, - email: newEmail - }, - url: url$1, - token: token$1 - }, ctx.request)); - } - return ctx.json({ status: true }); - } - if (ctx.context.session.user.emailVerified && (ctx.context.options.user.changeEmail.sendChangeEmailConfirmation || ctx.context.options.user.changeEmail.sendChangeEmailVerification)) { - const token$1 = await createEmailVerificationToken(ctx.context.secret, ctx.context.session.user.email, newEmail, ctx.context.options.emailVerification?.expiresIn, { requestType: "change-email-confirmation" }); - const url$1 = `${ctx.context.baseURL}/verify-email?token=${token$1}&callbackURL=${ctx.body.callbackURL || "/"}`; - const sendFn = ctx.context.options.user.changeEmail.sendChangeEmailConfirmation || ctx.context.options.user.changeEmail.sendChangeEmailVerification; - if (sendFn) await ctx.context.runInBackgroundOrAwait(sendFn({ - user: ctx.context.session.user, - newEmail, - url: url$1, - token: token$1 - }, ctx.request)); - return ctx.json({ status: true }); - } - if (!ctx.context.options.emailVerification?.sendVerificationEmail) { - ctx.context.logger.error("Verification email isn't enabled."); - throw new APIError("BAD_REQUEST", { message: "Verification email isn't enabled" }); - } - const token = await createEmailVerificationToken(ctx.context.secret, ctx.context.session.user.email, newEmail, ctx.context.options.emailVerification?.expiresIn, { requestType: "change-email-verification" }); - const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${ctx.body.callbackURL || "/"}`; - await ctx.context.runInBackgroundOrAwait(ctx.context.options.emailVerification.sendVerificationEmail({ - user: { - ...ctx.context.session.user, - email: newEmail - }, - url, - token - }, ctx.request)); - return ctx.json({ status: true }); -}); -const defuReplaceArrays = createDefu((obj, key, value) => { - if (Array.isArray(obj[key]) && Array.isArray(value)) { - obj[key] = value; - return true; - } -}); -const hooksSourceWeakMap = /* @__PURE__ */ new WeakMap(); -function toAuthEndpoints(endpoints, ctx) { - const api = {}; - for (const [key, endpoint] of Object.entries(endpoints)) { - api[key] = async (context) => { - const run = async () => { - const authContext = await ctx; - let internalContext = { - ...context, - context: { - ...authContext, - returned: void 0, - responseHeaders: void 0, - session: null - }, - path: endpoint.path, - headers: context?.headers ? new Headers(context?.headers) : void 0 - }; - return runWithEndpointContext(internalContext, async () => { - const { beforeHooks, afterHooks } = getHooks(authContext); - const before = await runBeforeHooks(internalContext, beforeHooks); - if ("context" in before && before.context && typeof before.context === "object") { - const { headers, ...rest } = before.context; - if (headers) headers.forEach((value, key$1) => { - internalContext.headers.set(key$1, value); - }); - internalContext = defuReplaceArrays(rest, internalContext); - } else if (before) return context?.asResponse ? toResponse(before, { headers: context?.headers }) : context?.returnHeaders ? { - headers: context?.headers, - response: before - } : before; - internalContext.asResponse = false; - internalContext.returnHeaders = true; - internalContext.returnStatus = true; - const result = await runWithEndpointContext(internalContext, () => endpoint(internalContext)).catch((e) => { - if (e instanceof APIError) - return { - response: e, - status: e.statusCode, - headers: e.headers ? new Headers(e.headers) : null - }; - throw e; - }); - if (result && result instanceof Response) return result; - internalContext.context.returned = result.response; - internalContext.context.responseHeaders = result.headers; - const after = await runAfterHooks(internalContext, afterHooks); - if (after.response) result.response = after.response; - if (result.response instanceof APIError && shouldPublishLog(authContext.logger.level, "debug")) result.response.stack = result.response.errorStack; - if (result.response instanceof APIError && !context?.asResponse) throw result.response; - return context?.asResponse ? toResponse(result.response, { - headers: result.headers, - status: result.status - }) : context?.returnHeaders ? context?.returnStatus ? { - headers: result.headers, - response: result.response, - status: result.status - } : { - headers: result.headers, - response: result.response - } : context?.returnStatus ? { - response: result.response, - status: result.status - } : result.response; - }); - }; - if (await hasRequestState()) return run(); - else return runWithRequestState(/* @__PURE__ */ new WeakMap(), run); - }; - api[key].path = endpoint.path; - api[key].options = endpoint.options; - } - return api; -} -async function runBeforeHooks(context, hooks) { - let modifiedContext = {}; - for (const hook of hooks) { - let matched = false; - try { - matched = hook.matcher(context); - } catch (error2) { - const hookSource = hooksSourceWeakMap.get(hook.handler) ?? "unknown"; - context.context.logger.error(`An error occurred during ${hookSource} hook matcher execution:`, error2); - throw new APIError("INTERNAL_SERVER_ERROR", { message: `An error occurred during hook matcher execution. Check the logs for more details.` }); - } - if (matched) { - const result = await hook.handler({ - ...context, - returnHeaders: false - }).catch((e) => { - if (e instanceof APIError && shouldPublishLog(context.context.logger.level, "debug")) e.stack = e.errorStack; - throw e; - }); - if (result && typeof result === "object") { - if ("context" in result && typeof result.context === "object") { - const { headers, ...rest } = result.context; - if (headers instanceof Headers) if (modifiedContext.headers) headers.forEach((value, key) => { - modifiedContext.headers?.set(key, value); - }); - else modifiedContext.headers = headers; - modifiedContext = defuReplaceArrays(rest, modifiedContext); - continue; - } - return result; - } - } - } - return { context: modifiedContext }; -} -async function runAfterHooks(context, hooks) { - for (const hook of hooks) if (hook.matcher(context)) { - const result = await hook.handler(context).catch((e) => { - if (e instanceof APIError) { - if (shouldPublishLog(context.context.logger.level, "debug")) e.stack = e.errorStack; - return { - response: e, - headers: e.headers ? new Headers(e.headers) : null - }; - } - throw e; - }); - if (result.headers) result.headers.forEach((value, key) => { - if (!context.context.responseHeaders) context.context.responseHeaders = new Headers({ [key]: value }); - else if (key.toLowerCase() === "set-cookie") context.context.responseHeaders.append(key, value); - else context.context.responseHeaders.set(key, value); - }); - if (result.response) context.context.returned = result.response; - } - return { - response: context.context.returned, - headers: context.context.responseHeaders - }; -} -function getHooks(authContext) { - const plugins = authContext.options.plugins || []; - const beforeHooks = []; - const afterHooks = []; - const beforeHookHandler = authContext.options.hooks?.before; - if (beforeHookHandler) { - hooksSourceWeakMap.set(beforeHookHandler, "user"); - beforeHooks.push({ - matcher: () => true, - handler: beforeHookHandler - }); - } - const afterHookHandler = authContext.options.hooks?.after; - if (afterHookHandler) { - hooksSourceWeakMap.set(afterHookHandler, "user"); - afterHooks.push({ - matcher: () => true, - handler: afterHookHandler - }); - } - const pluginBeforeHooks = plugins.filter((plugin) => plugin.hooks?.before).map((plugin) => plugin.hooks?.before).flat(); - const pluginAfterHooks = plugins.filter((plugin) => plugin.hooks?.after).map((plugin) => plugin.hooks?.after).flat(); - if (pluginBeforeHooks.length) beforeHooks.push(...pluginBeforeHooks); - if (pluginAfterHooks.length) afterHooks.push(...pluginAfterHooks); - return { - beforeHooks, - afterHooks - }; -} -function checkEndpointConflicts(options, logger$1) { - const endpointRegistry = /* @__PURE__ */ new Map(); - options.plugins?.forEach((plugin) => { - if (plugin.endpoints) { - for (const [key, endpoint] of Object.entries(plugin.endpoints)) if (endpoint && "path" in endpoint && typeof endpoint.path === "string") { - const path = endpoint.path; - let methods = []; - if (endpoint.options && "method" in endpoint.options) { - if (Array.isArray(endpoint.options.method)) methods = endpoint.options.method; - else if (typeof endpoint.options.method === "string") methods = [endpoint.options.method]; - } - if (methods.length === 0) methods = ["*"]; - if (!endpointRegistry.has(path)) endpointRegistry.set(path, []); - endpointRegistry.get(path).push({ - pluginId: plugin.id, - endpointKey: key, - methods - }); - } - } - }); - const conflicts = []; - for (const [path, entries] of endpointRegistry.entries()) if (entries.length > 1) { - const methodMap = /* @__PURE__ */ new Map(); - let hasConflict = false; - for (const entry of entries) for (const method of entry.methods) { - if (!methodMap.has(method)) methodMap.set(method, []); - methodMap.get(method).push(entry.pluginId); - if (methodMap.get(method).length > 1) hasConflict = true; - if (method === "*" && entries.length > 1) hasConflict = true; - else if (method !== "*" && methodMap.has("*")) hasConflict = true; - } - if (hasConflict) { - const uniquePlugins = [...new Set(entries.map((e) => e.pluginId))]; - const conflictingMethods = []; - for (const [method, plugins] of methodMap.entries()) if (plugins.length > 1 || method === "*" && entries.length > 1 || method !== "*" && methodMap.has("*")) conflictingMethods.push(method); - conflicts.push({ - path, - plugins: uniquePlugins, - conflictingMethods - }); - } - } - if (conflicts.length > 0) { - const conflictMessages = conflicts.map((conflict) => ` - "${conflict.path}" [${conflict.conflictingMethods.join(", ")}] used by plugins: ${conflict.plugins.join(", ")}`).join("\n"); - logger$1.error(`Endpoint path conflicts detected! Multiple plugins are trying to use the same endpoint paths with conflicting HTTP methods: -${conflictMessages} - -To resolve this, you can: - 1. Use only one of the conflicting plugins - 2. Configure the plugins to use different paths (if supported) - 3. Ensure plugins use different HTTP methods for the same path -`); - } -} -function getEndpoints(ctx, options) { - const pluginEndpoints = options.plugins?.reduce((acc, plugin) => { - return { - ...acc, - ...plugin.endpoints - }; - }, {}) ?? {}; - const middlewares = options.plugins?.map((plugin) => plugin.middlewares?.map((m) => { - const middleware = (async (context) => { - const authContext = await ctx; - return m.middleware({ - ...context, - context: { - ...authContext, - ...context.context - } - }); - }); - middleware.options = m.middleware.options; - return { - path: m.path, - middleware - }; - })).filter((plugin) => plugin !== void 0).flat() || []; - return { - api: toAuthEndpoints({ - signInSocial: signInSocial(), - callbackOAuth, - getSession: getSession(), - signOut, - signUpEmail: signUpEmail(), - signInEmail: signInEmail(), - resetPassword, - verifyPassword, - verifyEmail, - sendVerificationEmail, - changeEmail, - changePassword, - setPassword, - updateUser: updateUser(), - deleteUser, - requestPasswordReset, - requestPasswordResetCallback, - listSessions: listSessions(), - revokeSession, - revokeSessions, - revokeOtherSessions, - linkSocialAccount, - listUserAccounts, - deleteUserCallback, - unlinkAccount, - refreshToken, - getAccessToken, - accountInfo, - ...pluginEndpoints, - ok, - error - }, ctx), - middlewares - }; -} -const router = (ctx, options) => { - const { api, middlewares } = getEndpoints(ctx, options); - const basePath = new URL(ctx.baseURL).pathname; - return createRouter(api, { - routerContext: ctx, - openapi: { disabled: true }, - basePath, - routerMiddleware: [{ - path: "/**", - middleware: originCheckMiddleware - }, ...middlewares], - allowedMediaTypes: ["application/json"], - skipTrailingSlashes: options.advanced?.skipTrailingSlashes ?? false, - async onRequest(req) { - const disabledPaths = ctx.options.disabledPaths || []; - const normalizedPath = normalizePathname(req.url, basePath); - if (disabledPaths.includes(normalizedPath)) return new Response("Not Found", { status: 404 }); - let currentRequest = req; - for (const plugin of ctx.options.plugins || []) if (plugin.onRequest) { - const response = await plugin.onRequest(currentRequest, ctx); - if (response && "response" in response) return response.response; - if (response && "request" in response) currentRequest = response.request; - } - const rateLimitResponse2 = await onRequestRateLimit(currentRequest, ctx); - if (rateLimitResponse2) return rateLimitResponse2; - return currentRequest; - }, - async onResponse(res) { - for (const plugin of ctx.options.plugins || []) if (plugin.onResponse) { - const response = await plugin.onResponse(res, ctx); - if (response) return response.response; - } - return res; - }, - onError(e) { - if (e instanceof APIError && e.status === "FOUND") return; - if (options.onAPIError?.throw) throw e; - if (options.onAPIError?.onError) { - options.onAPIError.onError(e, ctx); - return; - } - const optLogLevel = options.logger?.level; - const log = optLogLevel === "error" || optLogLevel === "warn" || optLogLevel === "debug" ? logger : void 0; - if (options.logger?.disabled !== true) { - if (e && typeof e === "object" && "message" in e && typeof e.message === "string") { - if (e.message.includes("no column") || e.message.includes("column") || e.message.includes("relation") || e.message.includes("table") || e.message.includes("does not exist")) { - ctx.logger?.error(e.message); - return; - } - } - if (e instanceof APIError) { - if (e.status === "INTERNAL_SERVER_ERROR") ctx.logger.error(e.status, e); - log?.error(e.message); - } else ctx.logger?.error(e && typeof e === "object" && "name" in e ? e.name : "", e); - } - } - }); -}; -async function runPluginInit(ctx) { - let options = ctx.options; - const plugins = options.plugins || []; - let context = ctx; - const dbHooks = []; - for (const plugin of plugins) if (plugin.init) { - const initPromise = plugin.init(context); - let result; - if (isPromise(initPromise)) result = await initPromise; - else result = initPromise; - if (typeof result === "object") { - if (result.options) { - const { databaseHooks, ...restOpts } = result.options; - if (databaseHooks) dbHooks.push(databaseHooks); - options = defu(options, restOpts); - } - if (result.context) context = { - ...context, - ...result.context - }; - } - } - dbHooks.push(options.databaseHooks); - context.internalAdapter = createInternalAdapter(context.adapter, { - options, - logger: context.logger, - hooks: dbHooks.filter((u) => u !== void 0), - generateId: context.generateId - }); - context.options = options; - return { context }; -} -function getInternalPlugins(options) { - const plugins = []; - if (options.advanced?.crossSubDomainCookies?.enabled) ; - return plugins; -} -async function getTrustedOrigins(options, request) { - const baseURL = getBaseURL(options.baseURL, options.basePath, request); - const trustedOrigins = baseURL ? [new URL(baseURL).origin] : []; - if (options.trustedOrigins) { - if (Array.isArray(options.trustedOrigins)) trustedOrigins.push(...options.trustedOrigins); - if (typeof options.trustedOrigins === "function") { - const validOrigins = await options.trustedOrigins(request); - trustedOrigins.push(...validOrigins); - } - } - const envTrustedOrigins = env.BETTER_AUTH_TRUSTED_ORIGINS; - if (envTrustedOrigins) trustedOrigins.push(...envTrustedOrigins.split(",")); - return trustedOrigins.filter((v) => Boolean(v)); -} -const createBetterAuth = (options, initFn) => { - const authContext = initFn(options); - const { api } = getEndpoints(authContext, options); - return { - handler: async (request) => { - const ctx = await authContext; - const basePath = ctx.options.basePath || "/api/auth"; - if (!ctx.options.baseURL) { - const baseURL = getBaseURL(void 0, basePath, request, void 0, ctx.options.advanced?.trustedProxyHeaders); - if (baseURL) { - ctx.baseURL = baseURL; - ctx.options.baseURL = getOrigin(ctx.baseURL) || void 0; - } else throw new BetterAuthError("Could not get base URL from request. Please provide a valid base URL."); - } - ctx.trustedOrigins = await getTrustedOrigins(ctx.options, request); - const { handler } = router(ctx, options); - return runWithAdapter(ctx.adapter, () => handler(request)); - }, - api, - options, - $context: authContext, - $ERROR_CODES: { - ...options.plugins?.reduce((acc, plugin) => { - if (plugin.$ERROR_CODES) return { - ...acc, - ...plugin.$ERROR_CODES - }; - return acc; - }, {}), - ...BASE_ERROR_CODES - } - }; -}; -const DEFAULT_SECRET = "better-auth-secret-12345678901234567890"; -function estimateEntropy(str) { - const unique = new Set(str).size; - if (unique === 0) return 0; - return Math.log2(Math.pow(unique, str.length)); -} -function validateSecret(secret, logger$1) { - const isDefaultSecret = secret === DEFAULT_SECRET; - if (isTest()) return; - if (isDefaultSecret && isProduction) throw new BetterAuthError("You are using the default secret. Please set `BETTER_AUTH_SECRET` in your environment variables or pass `secret` in your auth config."); - if (secret.length < 32) logger$1.warn(`[better-auth] Warning: your BETTER_AUTH_SECRET should be at least 32 characters long for adequate security. Generate one with \`npx @better-auth/cli secret\` or \`openssl rand -base64 32\`.`); - if (estimateEntropy(secret) < 120) logger$1.warn("[better-auth] Warning: your BETTER_AUTH_SECRET appears low-entropy. Use a randomly generated secret for production."); -} -async function createAuthContext(adapter, options, getDatabaseType) { - if (!options.database) options = defu$1(options, { - session: { cookieCache: { - enabled: true, - strategy: "jwe", - refreshCache: true - } }, - account: { - storeStateStrategy: "cookie", - storeAccountCookie: true - } - }); - const plugins = options.plugins || []; - const internalPlugins = getInternalPlugins(options); - const logger$1 = createLogger(options.logger); - const baseURL = getBaseURL(options.baseURL, options.basePath); - if (!baseURL) logger$1.warn(`[better-auth] Base URL could not be determined. Please set a valid base URL using the baseURL config option or the BETTER_AUTH_URL environment variable. Without this, callbacks and redirects may not work correctly.`); - if (adapter.id === "memory" && options.advanced?.database?.generateId === false) logger$1.error(`[better-auth] Misconfiguration detected. -You are using the memory DB with generateId: false. -This will cause no id to be generated for any model. -Most of the features of Better Auth will not work correctly.`); - const secret = options.secret || env.BETTER_AUTH_SECRET || env.AUTH_SECRET || DEFAULT_SECRET; - validateSecret(secret, logger$1); - options = { - ...options, - secret, - baseURL: baseURL ? new URL(baseURL).origin : "", - basePath: options.basePath || "/api/auth", - plugins: plugins.concat(internalPlugins) - }; - checkEndpointConflicts(options, logger$1); - const cookies = getCookies(options); - const tables = getAuthTables(options); - const providers = Object.entries(options.socialProviders || {}).map(([key, config2]) => { - if (config2 == null) return null; - if (config2.enabled === false) return null; - if (!config2.clientId) logger$1.warn(`Social provider ${key} is missing clientId or clientSecret`); - const provider = socialProviders[key](config2); - provider.disableImplicitSignUp = config2.disableImplicitSignUp; - return provider; - }).filter((x) => x !== null); - const generateIdFunc = ({ model, size }) => { - if (typeof options.advanced?.generateId === "function") return options.advanced.generateId({ - model, - size - }); - const dbGenerateId = options?.advanced?.database?.generateId; - if (typeof dbGenerateId === "function") return dbGenerateId({ - model, - size - }); - if (dbGenerateId === "uuid") return crypto.randomUUID(); - if (dbGenerateId === "serial" || dbGenerateId === false) return false; - return generateId(size); - }; - const { publish } = await createTelemetry(options, { - adapter: adapter.id, - database: typeof options.database === "function" ? "adapter" : getDatabaseType(options.database) - }); - const trustedOrigins = await getTrustedOrigins(options); - const initOrPromise = runPluginInit({ - appName: options.appName || "Better Auth", - baseURL: baseURL || "", - version: getBetterAuthVersion(), - socialProviders: providers, - options, - oauthConfig: { - storeStateStrategy: options.account?.storeStateStrategy || (options.database ? "database" : "cookie"), - skipStateCookieCheck: !!options.account?.skipStateCookieCheck - }, - tables, - trustedOrigins, - isTrustedOrigin(url, settings) { - return this.trustedOrigins.some((origin) => matchesOriginPattern(url, origin, settings)); - }, - sessionConfig: { - updateAge: options.session?.updateAge !== void 0 ? options.session.updateAge : 1440 * 60, - expiresIn: options.session?.expiresIn || 3600 * 24 * 7, - freshAge: options.session?.freshAge === void 0 ? 3600 * 24 : options.session.freshAge, - cookieRefreshCache: (() => { - const refreshCache = options.session?.cookieCache?.refreshCache; - const maxAge = options.session?.cookieCache?.maxAge || 300; - if ((!!options.database || !!options.secondaryStorage) && refreshCache) { - logger$1.warn("[better-auth] `session.cookieCache.refreshCache` is enabled while `database` or `secondaryStorage` is configured. `refreshCache` is meant for stateless (DB-less) setups. Disabling `refreshCache` — remove it from your config to silence this warning."); - return false; - } - if (refreshCache === false || refreshCache === void 0) return false; - if (refreshCache === true) return { - enabled: true, - updateAge: Math.floor(maxAge * 0.2) - }; - return { - enabled: true, - updateAge: refreshCache.updateAge !== void 0 ? refreshCache.updateAge : Math.floor(maxAge * 0.2) - }; - })() - }, - secret, - rateLimit: { - ...options.rateLimit, - enabled: options.rateLimit?.enabled ?? isProduction, - window: options.rateLimit?.window || 10, - max: options.rateLimit?.max || 100, - storage: options.rateLimit?.storage || (options.secondaryStorage ? "secondary-storage" : "memory") - }, - authCookies: cookies, - logger: logger$1, - generateId: generateIdFunc, - session: null, - secondaryStorage: options.secondaryStorage, - password: { - hash: options.emailAndPassword?.password?.hash || hashPassword, - verify: options.emailAndPassword?.password?.verify || verifyPassword$1, - config: { - minPasswordLength: options.emailAndPassword?.minPasswordLength || 8, - maxPasswordLength: options.emailAndPassword?.maxPasswordLength || 128 - }, - checkPassword - }, - setNewSession(session) { - this.newSession = session; - }, - newSession: null, - adapter, - internalAdapter: createInternalAdapter(adapter, { - options, - logger: logger$1, - hooks: options.databaseHooks ? [options.databaseHooks] : [], - generateId: generateIdFunc - }), - createAuthCookie: createCookieGetter(options), - async runMigrations() { - throw new BetterAuthError("runMigrations will be set by the specific init implementation"); - }, - publishTelemetry: publish, - skipCSRFCheck: !!options.advanced?.disableCSRFCheck, - skipOriginCheck: options.advanced?.disableOriginCheck !== void 0 ? options.advanced.disableOriginCheck : isTest() ? true : false, - runInBackground: options.advanced?.backgroundTasks?.handler ?? ((p) => { - p.catch(() => { - }); - }), - async runInBackgroundOrAwait(promise) { - try { - if (options.advanced?.backgroundTasks?.handler) { - if (promise instanceof Promise) options.advanced.backgroundTasks.handler(promise.catch((e) => { - logger$1.error("Failed to run background task:", e); - })); - } else await promise; - } catch (e) { - logger$1.error("Failed to run background task:", e); - } - }, - getPlugin: (id) => options.plugins.find((p) => p.id === id) ?? null - }); - let context; - if (isPromise(initOrPromise)) ({ context } = await initOrPromise); - else ({ context } = initOrPromise); - if (typeof context.options.emailVerification?.onEmailVerification === "function") context.options.emailVerification.onEmailVerification = deprecate(context.options.emailVerification.onEmailVerification, "Use `afterEmailVerification` instead. This will be removed in 1.5", context.logger); - return context; -} -const initMinimal = async (options) => { - const adapter = await getBaseAdapter(options, async () => { - throw new BetterAuthError("Direct database connection requires Kysely. Please use `better-auth` instead of `better-auth/minimal`, or provide an adapter (drizzleAdapter, prismaAdapter, etc.)"); - }); - const getDatabaseType = (_database) => "unknown"; - const ctx = await createAuthContext(adapter, options, getDatabaseType); - ctx.runMigrations = async function() { - throw new BetterAuthError("Migrations are not supported in 'better-auth/minimal'. Please use 'better-auth' for migration support."); - }; - return ctx; -}; -const betterAuth = (options) => { - return createBetterAuth(options, initMinimal); -}; -const drizzleAdapter = (db2, config2) => { - let lazyOptions = null; - const createCustomAdapter = (db$1) => ({ getFieldName, getDefaultFieldName, options }) => { - function getSchema2(model) { - const schema2 = config2.schema || db$1._.fullSchema; - if (!schema2) throw new BetterAuthError("Drizzle adapter failed to initialize. Schema not found. Please provide a schema object in the adapter options object."); - const schemaModel = schema2[model]; - if (!schemaModel) throw new BetterAuthError(`[# Drizzle Adapter]: The model "${model}" was not found in the schema object. Please pass the schema directly to the adapter options.`); - return schemaModel; - } - const withReturning = async (model, builder, data, where) => { - if (config2.provider !== "mysql") return (await builder.returning())[0]; - await builder.execute(); - const schemaModel = getSchema2(model); - const builderVal = builder.config?.values; - if (where?.length) { - const clause = convertWhereClause(where.map((w) => { - if (data[w.field] !== void 0) return { - ...w, - value: data[w.field] - }; - return w; - }), model); - return (await db$1.select().from(schemaModel).where(...clause))[0]; - } else if (builderVal && builderVal[0]?.id?.value) { - let tId = builderVal[0]?.id?.value; - if (!tId) tId = (await db$1.select({ id: sql$1`LAST_INSERT_ID()` }).from(schemaModel).orderBy(desc(schemaModel.id)).limit(1))[0].id; - return (await db$1.select().from(schemaModel).where(eq(schemaModel.id, tId)).limit(1).execute())[0]; - } else if (data.id) return (await db$1.select().from(schemaModel).where(eq(schemaModel.id, data.id)).limit(1).execute())[0]; - else { - if (!("id" in schemaModel)) throw new BetterAuthError(`The model "${model}" does not have an "id" field. Please use the "id" field as your primary key.`); - return (await db$1.select().from(schemaModel).orderBy(desc(schemaModel.id)).limit(1).execute())[0]; - } - }; - function convertWhereClause(where, model) { - const schemaModel = getSchema2(model); - if (!where) return []; - if (where.length === 1) { - const w = where[0]; - if (!w) return []; - const field = getFieldName({ - model, - field: w.field - }); - if (!schemaModel[field]) throw new BetterAuthError(`The field "${w.field}" does not exist in the schema for the model "${model}". Please update your schema.`); - if (w.operator === "in") { - if (!Array.isArray(w.value)) throw new BetterAuthError(`The value for the field "${w.field}" must be an array when using the "in" operator.`); - return [inArray(schemaModel[field], w.value)]; - } - if (w.operator === "not_in") { - if (!Array.isArray(w.value)) throw new BetterAuthError(`The value for the field "${w.field}" must be an array when using the "not_in" operator.`); - return [notInArray(schemaModel[field], w.value)]; - } - if (w.operator === "contains") return [like(schemaModel[field], `%${w.value}%`)]; - if (w.operator === "starts_with") return [like(schemaModel[field], `${w.value}%`)]; - if (w.operator === "ends_with") return [like(schemaModel[field], `%${w.value}`)]; - if (w.operator === "lt") return [lt(schemaModel[field], w.value)]; - if (w.operator === "lte") return [lte(schemaModel[field], w.value)]; - if (w.operator === "ne") return [ne(schemaModel[field], w.value)]; - if (w.operator === "gt") return [gt(schemaModel[field], w.value)]; - if (w.operator === "gte") return [gte(schemaModel[field], w.value)]; - return [eq(schemaModel[field], w.value)]; - } - const andGroup = where.filter((w) => w.connector === "AND" || !w.connector); - const orGroup = where.filter((w) => w.connector === "OR"); - const andClause = and(...andGroup.map((w) => { - const field = getFieldName({ - model, - field: w.field - }); - if (w.operator === "in") { - if (!Array.isArray(w.value)) throw new BetterAuthError(`The value for the field "${w.field}" must be an array when using the "in" operator.`); - return inArray(schemaModel[field], w.value); - } - if (w.operator === "not_in") { - if (!Array.isArray(w.value)) throw new BetterAuthError(`The value for the field "${w.field}" must be an array when using the "not_in" operator.`); - return notInArray(schemaModel[field], w.value); - } - if (w.operator === "contains") return like(schemaModel[field], `%${w.value}%`); - if (w.operator === "starts_with") return like(schemaModel[field], `${w.value}%`); - if (w.operator === "ends_with") return like(schemaModel[field], `%${w.value}`); - if (w.operator === "lt") return lt(schemaModel[field], w.value); - if (w.operator === "lte") return lte(schemaModel[field], w.value); - if (w.operator === "gt") return gt(schemaModel[field], w.value); - if (w.operator === "gte") return gte(schemaModel[field], w.value); - if (w.operator === "ne") return ne(schemaModel[field], w.value); - return eq(schemaModel[field], w.value); - })); - const orClause = or(...orGroup.map((w) => { - const field = getFieldName({ - model, - field: w.field - }); - if (w.operator === "in") { - if (!Array.isArray(w.value)) throw new BetterAuthError(`The value for the field "${w.field}" must be an array when using the "in" operator.`); - return inArray(schemaModel[field], w.value); - } - if (w.operator === "not_in") { - if (!Array.isArray(w.value)) throw new BetterAuthError(`The value for the field "${w.field}" must be an array when using the "not_in" operator.`); - return notInArray(schemaModel[field], w.value); - } - if (w.operator === "contains") return like(schemaModel[field], `%${w.value}%`); - if (w.operator === "starts_with") return like(schemaModel[field], `${w.value}%`); - if (w.operator === "ends_with") return like(schemaModel[field], `%${w.value}`); - if (w.operator === "lt") return lt(schemaModel[field], w.value); - if (w.operator === "lte") return lte(schemaModel[field], w.value); - if (w.operator === "gt") return gt(schemaModel[field], w.value); - if (w.operator === "gte") return gte(schemaModel[field], w.value); - if (w.operator === "ne") return ne(schemaModel[field], w.value); - return eq(schemaModel[field], w.value); - })); - const clause = []; - if (andGroup.length) clause.push(andClause); - if (orGroup.length) clause.push(orClause); - return clause; - } - function checkMissingFields(schema2, model, values) { - if (!schema2) throw new BetterAuthError("Drizzle adapter failed to initialize. Drizzle Schema not found. Please provide a schema object in the adapter options object."); - for (const key in values) if (!schema2[key]) throw new BetterAuthError(`The field "${key}" does not exist in the "${model}" Drizzle schema. Please update your drizzle schema or re-generate using "npx @better-auth/cli@latest generate".`); - } - return { - async create({ model, data: values }) { - const schemaModel = getSchema2(model); - checkMissingFields(schemaModel, model, values); - return await withReturning(model, db$1.insert(schemaModel).values(values), values); - }, - async findOne({ model, where, select, join }) { - const schemaModel = getSchema2(model); - const clause = convertWhereClause(where, model); - if (options.experimental?.joins) if (!db$1.query || !db$1.query[model]) { - logger.error(`[# Drizzle Adapter]: The model "${model}" was not found in the query object. Please update your Drizzle schema to include relations or re-generate using "npx @better-auth/cli@latest generate".`); - logger.info("Falling back to regular query"); - } else { - let includes; - const pluralJoinResults = []; - if (join) { - includes = {}; - const joinEntries = Object.entries(join); - for (const [model$1, joinAttr] of joinEntries) { - const limit = joinAttr.limit ?? options.advanced?.database?.defaultFindManyLimit ?? 100; - const isUnique = joinAttr.relation === "one-to-one"; - const pluralSuffix = isUnique || config2.usePlural ? "" : "s"; - includes[`${model$1}${pluralSuffix}`] = isUnique ? true : { limit }; - if (!isUnique) pluralJoinResults.push(`${model$1}${pluralSuffix}`); - } - } - const res$1 = await db$1.query[model].findFirst({ - where: clause[0], - columns: select?.length && select.length > 0 ? select.reduce((acc, field) => { - acc[getFieldName({ - model, - field - })] = true; - return acc; - }, {}) : void 0, - with: includes - }); - if (res$1) for (const pluralJoinResult of pluralJoinResults) { - const singularKey = !config2.usePlural ? pluralJoinResult.slice(0, -1) : pluralJoinResult; - res$1[singularKey] = res$1[pluralJoinResult]; - if (pluralJoinResult !== singularKey) delete res$1[pluralJoinResult]; - } - return res$1; - } - const res = await db$1.select(select?.length && select.length > 0 ? select.reduce((acc, field) => { - const fieldName = getFieldName({ - model, - field - }); - return { - ...acc, - [fieldName]: schemaModel[fieldName] - }; - }, {}) : void 0).from(schemaModel).where(...clause); - if (!res.length) return null; - return res[0]; - }, - async findMany({ model, where, sortBy, limit, select, offset, join }) { - const schemaModel = getSchema2(model); - const clause = where ? convertWhereClause(where, model) : []; - const sortFn = sortBy?.direction === "desc" ? desc : asc; - if (options.experimental?.joins) if (!db$1.query[model]) { - logger.error(`[# Drizzle Adapter]: The model "${model}" was not found in the query object. Please update your Drizzle schema to include relations or re-generate using "npx @better-auth/cli@latest generate".`); - logger.info("Falling back to regular query"); - } else { - let includes; - const pluralJoinResults = []; - if (join) { - includes = {}; - const joinEntries = Object.entries(join); - for (const [model$1, joinAttr] of joinEntries) { - const isUnique = joinAttr.relation === "one-to-one"; - const limit$1 = joinAttr.limit ?? options.advanced?.database?.defaultFindManyLimit ?? 100; - const pluralSuffix = isUnique || config2.usePlural ? "" : "s"; - includes[`${model$1}${pluralSuffix}`] = isUnique ? true : { limit: limit$1 }; - if (!isUnique) pluralJoinResults.push(`${model$1}${pluralSuffix}`); - } - } - let orderBy = void 0; - if (sortBy?.field) orderBy = [sortFn(schemaModel[getFieldName({ - model, - field: sortBy?.field - })])]; - const res = await db$1.query[model].findMany({ - where: clause[0], - with: includes, - columns: select?.length && select.length > 0 ? select.reduce((acc, field) => { - acc[getFieldName({ - model, - field - })] = true; - return acc; - }, {}) : void 0, - limit: limit ?? 100, - offset: offset ?? 0, - orderBy - }); - if (res) for (const item of res) for (const pluralJoinResult of pluralJoinResults) { - const singularKey = !config2.usePlural ? pluralJoinResult.slice(0, -1) : pluralJoinResult; - if (singularKey === pluralJoinResult) continue; - item[singularKey] = item[pluralJoinResult]; - delete item[pluralJoinResult]; - } - return res; - } - let builder = db$1.select(select?.length && select.length > 0 ? select.reduce((acc, field) => { - const fieldName = getFieldName({ - model, - field - }); - return { - ...acc, - [fieldName]: schemaModel[fieldName] - }; - }, {}) : void 0).from(schemaModel); - const effectiveLimit = limit; - const effectiveOffset = offset; - if (typeof effectiveLimit !== "undefined") builder = builder.limit(effectiveLimit); - if (typeof effectiveOffset !== "undefined") builder = builder.offset(effectiveOffset); - if (sortBy?.field) builder = builder.orderBy(sortFn(schemaModel[getFieldName({ - model, - field: sortBy?.field - })])); - return await builder.where(...clause); - }, - async count({ model, where }) { - const schemaModel = getSchema2(model); - const clause = where ? convertWhereClause(where, model) : []; - return (await db$1.select({ count: count() }).from(schemaModel).where(...clause))[0].count; - }, - async update({ model, where, update: values }) { - const schemaModel = getSchema2(model); - const clause = convertWhereClause(where, model); - return await withReturning(model, db$1.update(schemaModel).set(values).where(...clause), values, where); - }, - async updateMany({ model, where, update: values }) { - const schemaModel = getSchema2(model); - const clause = convertWhereClause(where, model); - return await db$1.update(schemaModel).set(values).where(...clause); - }, - async delete({ model, where }) { - const schemaModel = getSchema2(model); - const clause = convertWhereClause(where, model); - return await db$1.delete(schemaModel).where(...clause); - }, - async deleteMany({ model, where }) { - const schemaModel = getSchema2(model); - const clause = convertWhereClause(where, model); - const res = await db$1.delete(schemaModel).where(...clause); - let count$1 = 0; - if (res && "rowCount" in res) count$1 = res.rowCount; - else if (Array.isArray(res)) count$1 = res.length; - else if (res && ("affectedRows" in res || "rowsAffected" in res || "changes" in res)) count$1 = res.affectedRows ?? res.rowsAffected ?? res.changes; - if (typeof count$1 !== "number") logger.error("[Drizzle Adapter] The result of the deleteMany operation is not a number. This is likely a bug in the adapter. Please report this issue to the Better Auth team.", { - res, - model, - where - }); - return count$1; - }, - options: config2 - }; - }; - let adapterOptions = null; - adapterOptions = { - config: { - adapterId: "drizzle", - adapterName: "Drizzle Adapter", - usePlural: config2.usePlural ?? false, - debugLogs: config2.debugLogs ?? false, - supportsUUIDs: config2.provider === "pg" ? true : false, - supportsJSON: config2.provider === "pg" ? true : false, - supportsArrays: config2.provider === "pg" ? true : false, - transaction: config2.transaction ?? false ? (cb) => db2.transaction((tx) => { - return cb(createAdapterFactory({ - config: adapterOptions.config, - adapter: createCustomAdapter(tx) - })(lazyOptions)); - }) : false - }, - adapter: createCustomAdapter(db2) - }; - const adapter = createAdapterFactory(adapterOptions); - return (options) => { - lazyOptions = options; - return adapter(options); - }; -}; -const svelteKitHandler = async ({ auth: auth2, event, resolve, building }) => { - if (building) return resolve(event); - const { request, url } = event; - if (isAuthPath(url.toString(), auth2.options)) return auth2.handler(request); - return resolve(event); -}; -function isAuthPath(url, options) { - const _url = new URL(url); - const baseURL = new URL(`${options.baseURL || _url.origin}${options.basePath || "/api/auth"}`); - if (_url.origin !== baseURL.origin) return false; - if (!_url.pathname.startsWith(baseURL.pathname.endsWith("/") ? baseURL.pathname : `${baseURL.pathname}/`)) return false; - return true; -} -const sveltekitCookies = (getRequestEvent2) => { - return { - id: "sveltekit-cookies", - hooks: { after: [{ - matcher() { - return true; - }, - handler: createAuthMiddleware(async (ctx) => { - const returned = ctx.context.responseHeaders; - if ("_flag" in ctx && ctx._flag === "router") return; - if (returned instanceof Headers) { - const setCookies = returned?.get("set-cookie"); - if (!setCookies) return; - const event = getRequestEvent2(); - if (!event) return; - const parsed = parseSetCookieHeader(setCookies); - for (const [name, { value, ...ops }] of parsed) try { - event.cookies.set(name, decodeURIComponent(value), { - sameSite: ops.samesite, - path: ops.path || "/", - expires: ops.expires, - secure: ops.secure, - httpOnly: ops.httponly, - domain: ops.domain, - maxAge: ops["max-age"] - }); - } catch { - } - } - }) - }] } - }; -}; -defineErrorCodes({ - FAILED_TO_CREATE_USER: "Failed to create user", - USER_ALREADY_EXISTS: "User already exists.", - USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL: "User already exists. Use another email.", - YOU_CANNOT_BAN_YOURSELF: "You cannot ban yourself", - YOU_ARE_NOT_ALLOWED_TO_CHANGE_USERS_ROLE: "You are not allowed to change users role", - YOU_ARE_NOT_ALLOWED_TO_CREATE_USERS: "You are not allowed to create users", - YOU_ARE_NOT_ALLOWED_TO_LIST_USERS: "You are not allowed to list users", - YOU_ARE_NOT_ALLOWED_TO_LIST_USERS_SESSIONS: "You are not allowed to list users sessions", - YOU_ARE_NOT_ALLOWED_TO_BAN_USERS: "You are not allowed to ban users", - YOU_ARE_NOT_ALLOWED_TO_IMPERSONATE_USERS: "You are not allowed to impersonate users", - YOU_ARE_NOT_ALLOWED_TO_REVOKE_USERS_SESSIONS: "You are not allowed to revoke users sessions", - YOU_ARE_NOT_ALLOWED_TO_DELETE_USERS: "You are not allowed to delete users", - YOU_ARE_NOT_ALLOWED_TO_SET_USERS_PASSWORD: "You are not allowed to set users password", - BANNED_USER: "You have been banned from this application", - YOU_ARE_NOT_ALLOWED_TO_GET_USER: "You are not allowed to get user", - NO_DATA_TO_UPDATE: "No data to update", - YOU_ARE_NOT_ALLOWED_TO_UPDATE_USERS: "You are not allowed to update users", - YOU_CANNOT_REMOVE_YOURSELF: "You cannot remove yourself", - YOU_ARE_NOT_ALLOWED_TO_SET_NON_EXISTENT_VALUE: "You are not allowed to set a non-existent role value", - YOU_CANNOT_IMPERSONATE_ADMINS: "You cannot impersonate admins", - INVALID_ROLE_TYPE: "Invalid role type" -}); -createAuthMiddleware(async (ctx) => { - const session = await getSessionFromCtx(ctx); - if (!session) throw new APIError("UNAUTHORIZED"); - return { session }; -}); -z.object({ - userId: z.coerce.string().meta({ description: "The user id" }), - role: z.union([z.string().meta({ description: "The role to set. `admin` or `user` by default" }), z.array(z.string().meta({ description: "The roles to set. `admin` or `user` by default" }))]).meta({ description: "The role to set, this can be a string or an array of strings. Eg: `admin` or `[admin, user]`" }) -}); -z.object({ id: z.string().meta({ description: "The id of the User" }) }); -z.object({ - email: z.string().meta({ description: "The email of the user" }), - password: z.string().optional().meta({ description: "The password of the user. If not provided, the user will be created without a credential account (useful for magic link or social login only users)." }), - name: z.string().meta({ description: "The name of the user" }), - role: z.union([z.string().meta({ description: "The role of the user" }), z.array(z.string().meta({ description: "The roles of user" }))]).optional().meta({ description: `A string or array of strings representing the roles to apply to the new user. Eg: "user"` }), - data: z.record(z.string(), z.any()).optional().meta({ description: "Extra fields for the user. Including custom additional fields." }) -}); -z.object({ - userId: z.coerce.string().meta({ description: "The user id" }), - data: z.record(z.any(), z.any()).meta({ description: "The user data to update" }) -}); -z.object({ - searchValue: z.string().optional().meta({ description: 'The value to search for. Eg: "some name"' }), - searchField: z.enum(["email", "name"]).meta({ description: 'The field to search in, defaults to email. Can be `email` or `name`. Eg: "name"' }).optional(), - searchOperator: z.enum([ - "contains", - "starts_with", - "ends_with" - ]).meta({ description: 'The operator to use for the search. Can be `contains`, `starts_with` or `ends_with`. Eg: "contains"' }).optional(), - limit: z.string().meta({ description: "The number of users to return" }).or(z.number()).optional(), - offset: z.string().meta({ description: "The offset to start from" }).or(z.number()).optional(), - sortBy: z.string().meta({ description: "The field to sort by" }).optional(), - sortDirection: z.enum(["asc", "desc"]).meta({ description: "The direction to sort by" }).optional(), - filterField: z.string().meta({ description: "The field to filter by" }).optional(), - filterValue: z.string().meta({ description: "The value to filter by" }).or(z.number()).or(z.boolean()).optional(), - filterOperator: z.enum([ - "eq", - "ne", - "lt", - "lte", - "gt", - "gte", - "contains" - ]).meta({ description: "The operator to use for the filter" }).optional() -}); -z.object({ userId: z.coerce.string().meta({ description: "The user id" }) }); -z.object({ userId: z.coerce.string().meta({ description: "The user id" }) }); -z.object({ - userId: z.coerce.string().meta({ description: "The user id" }), - banReason: z.string().meta({ description: "The reason for the ban" }).optional(), - banExpiresIn: z.number().meta({ description: "The number of seconds until the ban expires" }).optional() -}); -z.object({ userId: z.coerce.string().meta({ description: "The user id" }) }); -z.object({ sessionToken: z.string().meta({ description: "The session token" }) }); -z.object({ userId: z.coerce.string().meta({ description: "The user id" }) }); -z.object({ userId: z.coerce.string().meta({ description: "The user id" }) }); -z.object({ - newPassword: z.string().nonempty("newPassword cannot be empty").meta({ description: "The new password" }), - userId: z.coerce.string().nonempty("userId cannot be empty").meta({ description: "The user id" }) -}); -z.object({ - userId: z.coerce.string().optional().meta({ description: `The user id. Eg: "user-id"` }), - role: z.string().optional().meta({ description: `The role to check permission for. Eg: "admin"` }) -}).and(z.union([z.object({ - permission: z.record(z.string(), z.array(z.string())), - permissions: z.undefined() -}), z.object({ - permission: z.undefined(), - permissions: z.record(z.string(), z.array(z.string())) -})])); -defineErrorCodes({ - INVALID_EMAIL_FORMAT: "Email was not generated in a valid format", - FAILED_TO_CREATE_USER: "Failed to create user", - COULD_NOT_CREATE_SESSION: "Could not create session", - ANONYMOUS_USERS_CANNOT_SIGN_IN_AGAIN_ANONYMOUSLY: "Anonymous users cannot sign in again anonymously", - FAILED_TO_DELETE_ANONYMOUS_USER: "Failed to delete anonymous user", - USER_IS_NOT_ANONYMOUS: "User is not anonymous", - DELETE_ANONYMOUS_USER_DISABLED: "Deleting anonymous users is disabled" -}); -z.object({ - key: z.string().meta({ description: "The key to verify" }), - permissions: z.record(z.string(), z.array(z.string())).meta({ description: "The permissions to verify." }).optional() -}); -z.object({ - name: z.string().meta({ description: "Name of the Api Key" }).optional(), - expiresIn: z.number().meta({ description: "Expiration time of the Api Key in seconds" }).min(1).optional().nullable().default(null), - userId: z.coerce.string().meta({ description: 'User Id of the user that the Api Key belongs to. server-only. Eg: "user-id"' }).optional(), - prefix: z.string().meta({ description: "Prefix of the Api Key" }).regex(/^[a-zA-Z0-9_-]+$/, { message: "Invalid prefix format, must be alphanumeric and contain only underscores and hyphens." }).optional(), - remaining: z.number().meta({ description: "Remaining number of requests. Server side only" }).min(0).optional().nullable().default(null), - metadata: z.any().optional(), - refillAmount: z.number().meta({ description: "Amount to refill the remaining count of the Api Key. server-only. Eg: 100" }).min(1).optional(), - refillInterval: z.number().meta({ description: "Interval to refill the Api Key in milliseconds. server-only. Eg: 1000" }).optional(), - rateLimitTimeWindow: z.number().meta({ description: "The duration in milliseconds where each request is counted. Once the `maxRequests` is reached, the request will be rejected until the `timeWindow` has passed, at which point the `timeWindow` will be reset. server-only. Eg: 1000" }).optional(), - rateLimitMax: z.number().meta({ description: "Maximum amount of requests allowed within a window. Once the `maxRequests` is reached, the request will be rejected until the `timeWindow` has passed, at which point the `timeWindow` will be reset. server-only. Eg: 100" }).optional(), - rateLimitEnabled: z.boolean().meta({ description: "Whether the key has rate limiting enabled. server-only. Eg: true" }).optional(), - permissions: z.record(z.string(), z.array(z.string())).meta({ description: "Permissions of the Api Key." }).optional() -}); -z.object({ keyId: z.string().meta({ description: "The id of the Api Key" }) }); -z.object({ id: z.string().meta({ description: "The id of the Api Key" }) }); -z.object({ - keyId: z.string().meta({ description: "The id of the Api Key" }), - userId: z.coerce.string().meta({ description: 'The id of the user which the api key belongs to. server-only. Eg: "some-user-id"' }).optional(), - name: z.string().meta({ description: "The name of the key" }).optional(), - enabled: z.boolean().meta({ description: "Whether the Api Key is enabled or not" }).optional(), - remaining: z.number().meta({ description: "The number of remaining requests" }).min(1).optional(), - refillAmount: z.number().meta({ description: "The refill amount" }).optional(), - refillInterval: z.number().meta({ description: "The refill interval" }).optional(), - metadata: z.any().optional(), - expiresIn: z.number().meta({ description: "Expiration time of the Api Key in seconds" }).min(1).optional().nullable(), - rateLimitEnabled: z.boolean().meta({ description: "Whether the key has rate limiting enabled." }).optional(), - rateLimitTimeWindow: z.number().meta({ description: "The duration in milliseconds where each request is counted. server-only. Eg: 1000" }).optional(), - rateLimitMax: z.number().meta({ description: "Maximum amount of requests allowed within a window. Once the `maxRequests` is reached, the request will be rejected until the `timeWindow` has passed, at which point the `timeWindow` will be reset. server-only. Eg: 100" }).optional(), - permissions: z.record(z.string(), z.array(z.string())).meta({ description: "Update the permissions on the API Key. server-only." }).optional().nullable() -}); -defineErrorCodes({ - INVALID_METADATA_TYPE: "metadata must be an object or undefined", - REFILL_AMOUNT_AND_INTERVAL_REQUIRED: "refillAmount is required when refillInterval is provided", - REFILL_INTERVAL_AND_AMOUNT_REQUIRED: "refillInterval is required when refillAmount is provided", - USER_BANNED: "User is banned", - UNAUTHORIZED_SESSION: "Unauthorized or invalid session", - KEY_NOT_FOUND: "API Key not found", - KEY_DISABLED: "API Key is disabled", - KEY_EXPIRED: "API Key has expired", - USAGE_EXCEEDED: "API Key has reached its usage limit", - KEY_NOT_RECOVERABLE: "API Key is not recoverable", - EXPIRES_IN_IS_TOO_SMALL: "The expiresIn is smaller than the predefined minimum value.", - EXPIRES_IN_IS_TOO_LARGE: "The expiresIn is larger than the predefined maximum value.", - INVALID_REMAINING: "The remaining count is either too large or too small.", - INVALID_PREFIX_LENGTH: "The prefix length is either too large or too small.", - INVALID_NAME_LENGTH: "The name length is either too large or too small.", - METADATA_DISABLED: "Metadata is disabled.", - RATE_LIMIT_EXCEEDED: "Rate limit exceeded.", - NO_VALUES_TO_UPDATE: "No values to update.", - KEY_DISABLED_EXPIRATION: "Custom key expiration values are disabled.", - INVALID_API_KEY: "Invalid API key.", - INVALID_USER_ID_FROM_API_KEY: "The user id from the API key is invalid.", - INVALID_API_KEY_GETTER_RETURN_TYPE: "API Key getter returned an invalid key type. Expected string.", - SERVER_ONLY_PROPERTY: "The property you're trying to set can only be set from the server auth instance only.", - FAILED_TO_UPDATE_API_KEY: "Failed to update API key", - NAME_REQUIRED: "API Key name is required." -}); -defineErrorCodes({ - VERIFICATION_FAILED: "Captcha verification failed", - MISSING_RESPONSE: "Missing CAPTCHA response", - UNKNOWN_ERROR: "Something went wrong" -}); -defineErrorCodes({ - MISSING_SECRET_KEY: "Missing secret key", - SERVICE_UNAVAILABLE: "CAPTCHA service unavailable" -}); -z.optional(z.object({ - disableCookieCache: z.boolean().meta({ description: "Disable cookie cache and fetch session from database" }).or(z.string().transform((v) => v === "true")).optional(), - disableRefresh: z.boolean().meta({ description: "Disable session refresh. Useful for checking session status, without updating the session" }).optional() -})); -const DEVICE_AUTHORIZATION_ERROR_CODES = defineErrorCodes({ - INVALID_DEVICE_CODE: "Invalid device code", - EXPIRED_DEVICE_CODE: "Device code has expired", - EXPIRED_USER_CODE: "User code has expired", - AUTHORIZATION_PENDING: "Authorization pending", - ACCESS_DENIED: "Access denied", - INVALID_USER_CODE: "Invalid user code", - DEVICE_CODE_ALREADY_PROCESSED: "Device code already processed", - POLLING_TOO_FREQUENTLY: "Polling too frequently", - USER_NOT_FOUND: "User not found", - FAILED_TO_CREATE_SESSION: "Failed to create session", - INVALID_DEVICE_CODE_STATUS: "Invalid device code status", - AUTHENTICATION_REQUIRED: "Authentication required" -}); -z.object({ - client_id: z.string().meta({ description: "The client ID of the application" }), - scope: z.string().meta({ description: "Space-separated list of scopes" }).optional() -}); -z.object({ - error: z.enum(["invalid_request", "invalid_client"]).meta({ description: "Error code" }), - error_description: z.string().meta({ description: "Detailed error description" }) -}); -z.object({ - grant_type: z.literal("urn:ietf:params:oauth:grant-type:device_code").meta({ description: "The grant type for device flow" }), - device_code: z.string().meta({ description: "The device verification code" }), - client_id: z.string().meta({ description: "The client ID of the application" }) -}); -z.object({ - error: z.enum([ - "authorization_pending", - "slow_down", - "expired_token", - "access_denied", - "invalid_request", - "invalid_grant" - ]).meta({ description: "Error code" }), - error_description: z.string().meta({ description: "Detailed error description" }) -}); -createAuthEndpoint("/device", { - method: "GET", - query: z.object({ user_code: z.string().meta({ description: "The user code to verify" }) }), - error: z.object({ - error: z.enum(["invalid_request"]).meta({ description: "Error code" }), - error_description: z.string().meta({ description: "Detailed error description" }) - }), - metadata: { openapi: { - description: "Verify user code and get device authorization status", - responses: { 200: { - description: "Device authorization status", - content: { "application/json": { schema: { - type: "object", - properties: { - user_code: { - type: "string", - description: "The user code to verify" - }, - status: { - type: "string", - enum: [ - "pending", - "approved", - "denied" - ], - description: "Current status of the device authorization" - } - } - } } } - } } - } } -}, async (ctx) => { - const { user_code } = ctx.query; - const cleanUserCode = user_code.replace(/-/g, ""); - const deviceCodeRecord = await ctx.context.adapter.findOne({ - model: "deviceCode", - where: [{ - field: "userCode", - value: cleanUserCode - }] - }); - if (!deviceCodeRecord) throw new APIError("BAD_REQUEST", { - error: "invalid_request", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.INVALID_USER_CODE - }); - if (deviceCodeRecord.expiresAt < /* @__PURE__ */ new Date()) throw new APIError("BAD_REQUEST", { - error: "expired_token", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.EXPIRED_USER_CODE - }); - return ctx.json({ - user_code, - status: deviceCodeRecord.status - }); -}); -createAuthEndpoint("/device/approve", { - method: "POST", - body: z.object({ userCode: z.string().meta({ description: "The user code to approve" }) }), - error: z.object({ - error: z.enum([ - "invalid_request", - "expired_token", - "device_code_already_processed", - "unauthorized", - "access_denied" - ]).meta({ description: "Error code" }), - error_description: z.string().meta({ description: "Detailed error description" }) - }), - requireHeaders: true, - metadata: { openapi: { - description: "Approve device authorization", - responses: { 200: { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { success: { type: "boolean" } } - } } } - } } - } } -}, async (ctx) => { - const session = await getSessionFromCtx(ctx); - if (!session) throw new APIError("UNAUTHORIZED", { - error: "unauthorized", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.AUTHENTICATION_REQUIRED - }); - const { userCode } = ctx.body; - const cleanUserCode = userCode.replace(/-/g, ""); - const deviceCodeRecord = await ctx.context.adapter.findOne({ - model: "deviceCode", - where: [{ - field: "userCode", - value: cleanUserCode - }] - }); - if (!deviceCodeRecord) throw new APIError("BAD_REQUEST", { - error: "invalid_request", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.INVALID_USER_CODE - }); - if (deviceCodeRecord.expiresAt < /* @__PURE__ */ new Date()) throw new APIError("BAD_REQUEST", { - error: "expired_token", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.EXPIRED_USER_CODE - }); - if (deviceCodeRecord.status !== "pending") throw new APIError("BAD_REQUEST", { - error: "invalid_request", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.DEVICE_CODE_ALREADY_PROCESSED - }); - if (deviceCodeRecord.userId && deviceCodeRecord.userId !== session.user.id) throw new APIError("FORBIDDEN", { - error: "access_denied", - error_description: "You are not authorized to approve this device authorization" - }); - await ctx.context.adapter.update({ - model: "deviceCode", - where: [{ - field: "id", - value: deviceCodeRecord.id - }], - update: { - status: "approved", - userId: session.user.id - } - }); - return ctx.json({ success: true }); -}); -createAuthEndpoint("/device/deny", { - method: "POST", - body: z.object({ userCode: z.string().meta({ description: "The user code to deny" }) }), - error: z.object({ - error: z.enum([ - "invalid_request", - "expired_token", - "unauthorized", - "access_denied" - ]).meta({ description: "Error code" }), - error_description: z.string().meta({ description: "Detailed error description" }) - }), - requireHeaders: true, - metadata: { openapi: { - description: "Deny device authorization", - responses: { 200: { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { success: { type: "boolean" } } - } } } - } } - } } -}, async (ctx) => { - const session = await getSessionFromCtx(ctx); - if (!session) throw new APIError("UNAUTHORIZED", { - error: "unauthorized", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.AUTHENTICATION_REQUIRED - }); - const { userCode } = ctx.body; - const cleanUserCode = userCode.replace(/-/g, ""); - const deviceCodeRecord = await ctx.context.adapter.findOne({ - model: "deviceCode", - where: [{ - field: "userCode", - value: cleanUserCode - }] - }); - if (!deviceCodeRecord) throw new APIError("BAD_REQUEST", { - error: "invalid_request", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.INVALID_USER_CODE - }); - if (deviceCodeRecord.expiresAt < /* @__PURE__ */ new Date()) throw new APIError("BAD_REQUEST", { - error: "expired_token", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.EXPIRED_USER_CODE - }); - if (deviceCodeRecord.status !== "pending") throw new APIError("BAD_REQUEST", { - error: "invalid_request", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.DEVICE_CODE_ALREADY_PROCESSED - }); - if (deviceCodeRecord.userId && deviceCodeRecord.userId !== session.user.id) throw new APIError("FORBIDDEN", { - error: "access_denied", - error_description: "You are not authorized to deny this device authorization" - }); - await ctx.context.adapter.update({ - model: "deviceCode", - where: [{ - field: "id", - value: deviceCodeRecord.id - }], - update: { - status: "denied", - userId: deviceCodeRecord.userId || session.user.id - } - }); - return ctx.json({ success: true }); -}); -z.object({ - id: z.string(), - deviceCode: z.string(), - userCode: z.string(), - userId: z.string().optional(), - expiresAt: z.date(), - status: z.string(), - lastPolledAt: z.date().optional(), - pollingInterval: z.number().optional(), - clientId: z.string().optional(), - scope: z.string().optional() -}); -const timeStringSchema = z.custom((val) => { - if (typeof val !== "string") return false; - try { - ms(val); - return true; - } catch { - return false; - } -}, { message: "Invalid time string format. Use formats like '30m', '5s', '1h', etc." }); -z.object({ - expiresIn: timeStringSchema.default("30m").describe("Time in seconds until the device code expires. Use formats like '30m', '5s', '1h', etc."), - interval: timeStringSchema.default("5s").describe("Time in seconds between polling attempts. Use formats like '30m', '5s', '1h', etc."), - deviceCodeLength: z.number().int().positive().default(40).describe("Length of the device code to be generated. Default is 40 characters."), - userCodeLength: z.number().int().positive().default(8).describe("Length of the user code to be generated. Default is 8 characters."), - generateDeviceCode: z.custom((val) => typeof val === "function", { message: "generateDeviceCode must be a function that returns a string or a promise that resolves to a string." }).optional().describe("Function to generate a device code. If not provided, a default random string generator will be used."), - generateUserCode: z.custom((val) => typeof val === "function", { message: "generateUserCode must be a function that returns a string or a promise that resolves to a string." }).optional().describe("Function to generate a user code. If not provided, a default random string generator will be used."), - validateClient: z.custom((val) => typeof val === "function", { message: "validateClient must be a function that returns a boolean or a promise that resolves to a boolean." }).optional().describe("Function to validate the client ID. If not provided, no validation will be performed."), - onDeviceAuthRequest: z.custom((val) => typeof val === "function", { message: "onDeviceAuthRequest must be a function that returns void or a promise that resolves to void." }).optional().describe("Function to handle device authorization requests. If not provided, no additional actions will be taken."), - verificationUri: z.string().optional().describe("The URI where users verify their device code. Can be an absolute URL (https://example.com/device) or relative path (/custom-path). This will be returned as verification_uri in the device code response. If not provided, defaults to /device."), - schema: z.custom(() => true) -}); -const types = [ - "email-verification", - "sign-in", - "forget-password" -]; -defineErrorCodes({ - OTP_EXPIRED: "OTP expired", - INVALID_OTP: "Invalid OTP", - TOO_MANY_ATTEMPTS: "Too many attempts" -}); -z.object({ - email: z.string({}).meta({ description: "Email address to send the OTP" }), - type: z.enum(types).meta({ description: "Type of the OTP" }) -}); -z.object({ - email: z.string({}).meta({ description: "Email address to send the OTP" }), - type: z.enum(types).meta({ - required: true, - description: "Type of the OTP" - }) -}); -z.object({ - email: z.string({}).meta({ description: "Email address the OTP was sent to" }), - type: z.enum(types).meta({ - required: true, - description: "Type of the OTP" - }) -}); -z.object({ - email: z.string().meta({ description: "Email address the OTP was sent to" }), - type: z.enum(types).meta({ - required: true, - description: "Type of the OTP" - }), - otp: z.string().meta({ - required: true, - description: "OTP to verify" - }) -}); -z.object({ - email: z.string({}).meta({ description: "Email address to verify" }), - otp: z.string().meta({ - required: true, - description: "OTP to verify" - }) -}); -z.object({ - email: z.string({}).meta({ description: "Email address to sign in" }), - otp: z.string().meta({ - required: true, - description: "OTP sent to the email" - }) -}); -z.object({ email: z.string().meta({ description: "Email address to send the OTP" }) }); -z.object({ email: z.string().meta({ description: "Email address to send the OTP" }) }); -z.object({ - email: z.string().meta({ description: "Email address to reset the password" }), - otp: z.string().meta({ description: "OTP sent to the email" }), - password: z.string().meta({ description: "New password" }) -}); -const GENERIC_OAUTH_ERROR_CODES = defineErrorCodes({ - INVALID_OAUTH_CONFIGURATION: "Invalid OAuth configuration", - TOKEN_URL_NOT_FOUND: "Invalid OAuth configuration. Token URL not found.", - PROVIDER_CONFIG_NOT_FOUND: "No config found for provider", - PROVIDER_ID_REQUIRED: "Provider ID is required", - INVALID_OAUTH_CONFIG: "Invalid OAuth configuration.", - SESSION_REQUIRED: "Session is required", - ISSUER_MISMATCH: "OAuth issuer mismatch. The authorization server issuer does not match the expected value (RFC 9207).", - ISSUER_MISSING: "OAuth issuer parameter missing. The authorization server did not include the required iss parameter (RFC 9207)." -}); -const signInWithOAuth2BodySchema = z.object({ - providerId: z.string().meta({ description: "The provider ID for the OAuth provider" }), - callbackURL: z.string().meta({ description: "The URL to redirect to after sign in" }).optional(), - errorCallbackURL: z.string().meta({ description: "The URL to redirect to if an error occurs" }).optional(), - newUserCallbackURL: z.string().meta({ description: 'The URL to redirect to after login if the user is new. Eg: "/welcome"' }).optional(), - disableRedirect: z.boolean().meta({ description: "Disable redirect" }).optional(), - scopes: z.array(z.string()).meta({ description: "Scopes to be passed to the provider authorization request." }).optional(), - requestSignUp: z.boolean().meta({ description: "Explicitly request sign-up. Useful when disableImplicitSignUp is true for this provider. Eg: false" }).optional(), - additionalData: z.record(z.string(), z.any()).optional() -}); -const signInWithOAuth2 = (options) => createAuthEndpoint("/sign-in/oauth2", { - method: "POST", - body: signInWithOAuth2BodySchema, - metadata: { openapi: { - description: "Sign in with OAuth2", - responses: { 200: { - description: "Sign in with OAuth2", - content: { "application/json": { schema: { - type: "object", - properties: { - url: { type: "string" }, - redirect: { type: "boolean" } - } - } } } - } } - } } -}, async (ctx) => { - const { providerId } = ctx.body; - const config2 = options.config.find((c) => c.providerId === providerId); - if (!config2) throw new APIError("BAD_REQUEST", { message: `${GENERIC_OAUTH_ERROR_CODES.PROVIDER_CONFIG_NOT_FOUND} ${providerId}` }); - const { discoveryUrl, authorizationUrl, tokenUrl, clientId, clientSecret, scopes, redirectURI, responseType, pkce, prompt, accessType, authorizationUrlParams, responseMode } = config2; - let finalAuthUrl = authorizationUrl; - let finalTokenUrl = tokenUrl; - if (discoveryUrl) { - const discovery = await betterFetch(discoveryUrl, { - method: "GET", - headers: config2.discoveryHeaders, - onError(context) { - ctx.context.logger.error(context.error.message, context.error, { discoveryUrl }); - } - }); - if (discovery.data) { - finalAuthUrl = discovery.data.authorization_endpoint; - finalTokenUrl = discovery.data.token_endpoint; - } - } - if (!finalAuthUrl || !finalTokenUrl) throw new APIError("BAD_REQUEST", { message: GENERIC_OAUTH_ERROR_CODES.INVALID_OAUTH_CONFIGURATION }); - if (authorizationUrlParams) { - const withAdditionalParams = new URL(finalAuthUrl); - for (const [paramName, paramValue] of Object.entries(authorizationUrlParams)) withAdditionalParams.searchParams.set(paramName, paramValue); - finalAuthUrl = withAdditionalParams.toString(); - } - const additionalParams = typeof authorizationUrlParams === "function" ? authorizationUrlParams(ctx) : authorizationUrlParams; - const { state, codeVerifier } = await generateState(ctx, void 0, ctx.body.additionalData); - const authUrl = await createAuthorizationURL({ - id: providerId, - options: { - clientId, - clientSecret, - redirectURI - }, - authorizationEndpoint: finalAuthUrl, - state, - codeVerifier: pkce ? codeVerifier : void 0, - scopes: ctx.body.scopes ? [...ctx.body.scopes, ...scopes || []] : scopes || [], - redirectURI: `${ctx.context.baseURL}/oauth2/callback/${providerId}`, - prompt, - accessType, - responseType, - responseMode, - additionalParams - }); - return ctx.json({ - url: authUrl.toString(), - redirect: !ctx.body.disableRedirect - }); -}); -const OAuth2CallbackQuerySchema = z.object({ - code: z.string().meta({ description: "The OAuth2 code" }).optional(), - error: z.string().meta({ description: "The error message, if any" }).optional(), - error_description: z.string().meta({ description: "The error description, if any" }).optional(), - state: z.string().meta({ description: "The state parameter from the OAuth2 request" }).optional(), - iss: z.string().meta({ description: "The issuer identifier" }).optional() -}); -const oAuth2Callback = (options) => createAuthEndpoint("/oauth2/callback/:providerId", { - method: "GET", - query: OAuth2CallbackQuerySchema, - metadata: { - ...HIDE_METADATA, - allowedMediaTypes: ["application/x-www-form-urlencoded", "application/json"], - openapi: { - description: "OAuth2 callback", - responses: { 200: { - description: "OAuth2 callback", - content: { "application/json": { schema: { - type: "object", - properties: { url: { type: "string" } } - } } } - } } - } - } -}, async (ctx) => { - const defaultErrorURL = ctx.context.options.onAPIError?.errorURL || `${ctx.context.baseURL}/error`; - if (ctx.query.error || !ctx.query.code) throw ctx.redirect(`${defaultErrorURL}?error=${ctx.query.error || "oAuth_code_missing"}&error_description=${ctx.query.error_description}`); - const providerId = ctx.params?.providerId; - if (!providerId) throw new APIError("BAD_REQUEST", { message: GENERIC_OAUTH_ERROR_CODES.PROVIDER_ID_REQUIRED }); - const providerConfig = options.config.find((p) => p.providerId === providerId); - if (!providerConfig) throw new APIError("BAD_REQUEST", { message: `${GENERIC_OAUTH_ERROR_CODES.PROVIDER_CONFIG_NOT_FOUND} ${providerId}` }); - let tokens = void 0; - const { callbackURL, codeVerifier, errorURL, requestSignUp, newUserURL, link } = await parseState(ctx); - const code = ctx.query.code; - function redirectOnError(error2) { - const defaultErrorURL$1 = ctx.context.options.onAPIError?.errorURL || `${ctx.context.baseURL}/error`; - let url = errorURL || defaultErrorURL$1; - if (url.includes("?")) url = `${url}&error=${error2}`; - else url = `${url}?error=${error2}`; - throw ctx.redirect(url); - } - let finalTokenUrl = providerConfig.tokenUrl; - let finalUserInfoUrl = providerConfig.userInfoUrl; - let expectedIssuer = providerConfig.issuer; - if (providerConfig.discoveryUrl) { - const discovery = await betterFetch(providerConfig.discoveryUrl, { - method: "GET", - headers: providerConfig.discoveryHeaders - }); - if (discovery.data) { - finalTokenUrl = discovery.data.token_endpoint; - finalUserInfoUrl = discovery.data.userinfo_endpoint; - if (!expectedIssuer && discovery.data.issuer) expectedIssuer = discovery.data.issuer; - } - } - if (expectedIssuer) { - if (ctx.query.iss) { - if (ctx.query.iss !== expectedIssuer) { - ctx.context.logger.error("OAuth issuer mismatch", { - expected: expectedIssuer, - received: ctx.query.iss - }); - return redirectOnError("issuer_mismatch"); - } - } else if (providerConfig.requireIssuerValidation) { - ctx.context.logger.error("OAuth issuer parameter missing", { expected: expectedIssuer }); - return redirectOnError("issuer_missing"); - } - } - try { - if (providerConfig.getToken) tokens = await providerConfig.getToken({ - code, - redirectURI: `${ctx.context.baseURL}/oauth2/callback/${providerConfig.providerId}`, - codeVerifier: providerConfig.pkce ? codeVerifier : void 0 - }); - else { - if (!finalTokenUrl) throw new APIError("BAD_REQUEST", { message: GENERIC_OAUTH_ERROR_CODES.INVALID_OAUTH_CONFIG }); - const additionalParams = typeof providerConfig.tokenUrlParams === "function" ? providerConfig.tokenUrlParams(ctx) : providerConfig.tokenUrlParams; - tokens = await validateAuthorizationCode({ - headers: providerConfig.authorizationHeaders, - code, - codeVerifier: providerConfig.pkce ? codeVerifier : void 0, - redirectURI: `${ctx.context.baseURL}/oauth2/callback/${providerConfig.providerId}`, - options: { - clientId: providerConfig.clientId, - clientSecret: providerConfig.clientSecret, - redirectURI: providerConfig.redirectURI - }, - tokenEndpoint: finalTokenUrl, - authentication: providerConfig.authentication, - additionalParams - }); - } - } catch (e) { - ctx.context.logger.error(e && typeof e === "object" && "name" in e ? e.name : "", e); - throw redirectOnError("oauth_code_verification_failed"); - } - if (!tokens) throw new APIError("BAD_REQUEST", { message: GENERIC_OAUTH_ERROR_CODES.INVALID_OAUTH_CONFIG }); - const userInfo = await (async function handleUserInfo() { - const userInfo$1 = providerConfig.getUserInfo ? await providerConfig.getUserInfo(tokens) : await getUserInfo(tokens, finalUserInfoUrl); - if (!userInfo$1) throw redirectOnError("user_info_is_missing"); - const mapUser = providerConfig.mapProfileToUser ? await providerConfig.mapProfileToUser(userInfo$1) : userInfo$1; - const email = mapUser.email ? mapUser.email.toLowerCase() : userInfo$1.email?.toLowerCase(); - if (!email) { - ctx.context.logger.error("Unable to get user info", userInfo$1); - throw redirectOnError("email_is_missing"); - } - const id = mapUser.id ? String(mapUser.id) : String(userInfo$1.id); - const name = mapUser.name ? mapUser.name : userInfo$1.name; - if (!name) { - ctx.context.logger.error("Unable to get user info", userInfo$1); - throw redirectOnError("name_is_missing"); - } - return { - ...userInfo$1, - ...mapUser, - email, - id, - name - }; - })(); - if (link) { - if (ctx.context.options.account?.accountLinking?.allowDifferentEmails !== true && link.email.toLowerCase() !== userInfo.email.toLowerCase()) return redirectOnError("email_doesn't_match"); - const existingAccount = await ctx.context.internalAdapter.findAccountByProviderId(String(userInfo.id), providerConfig.providerId); - if (existingAccount) { - if (existingAccount.userId !== link.userId) return redirectOnError("account_already_linked_to_different_user"); - const updateData = Object.fromEntries(Object.entries({ - accessToken: await setTokenUtil(tokens.accessToken, ctx.context), - idToken: tokens.idToken, - refreshToken: await setTokenUtil(tokens.refreshToken, ctx.context), - accessTokenExpiresAt: tokens.accessTokenExpiresAt, - refreshTokenExpiresAt: tokens.refreshTokenExpiresAt, - scope: tokens.scopes?.join(",") - }).filter(([_, value]) => value !== void 0)); - await ctx.context.internalAdapter.updateAccount(existingAccount.id, updateData); - } else if (!await ctx.context.internalAdapter.createAccount({ - userId: link.userId, - providerId: providerConfig.providerId, - accountId: userInfo.id, - accessToken: await setTokenUtil(tokens.accessToken, ctx.context), - accessTokenExpiresAt: tokens.accessTokenExpiresAt, - refreshTokenExpiresAt: tokens.refreshTokenExpiresAt, - scope: tokens.scopes?.join(","), - refreshToken: await setTokenUtil(tokens.refreshToken, ctx.context), - idToken: tokens.idToken - })) return redirectOnError("unable_to_link_account"); - let toRedirectTo$1; - try { - toRedirectTo$1 = callbackURL.toString(); - } catch { - toRedirectTo$1 = callbackURL; - } - throw ctx.redirect(toRedirectTo$1); - } - const result = await handleOAuthUserInfo(ctx, { - userInfo, - account: { - providerId: providerConfig.providerId, - accountId: userInfo.id, - ...tokens, - scope: tokens.scopes?.join(",") - }, - callbackURL, - disableSignUp: providerConfig.disableImplicitSignUp && !requestSignUp || providerConfig.disableSignUp, - overrideUserInfo: providerConfig.overrideUserInfo - }); - if (result.error) return redirectOnError(result.error.split(" ").join("_")); - const { session, user } = result.data; - await setSessionCookie(ctx, { - session, - user - }); - let toRedirectTo; - try { - toRedirectTo = (result.isRegister ? newUserURL || callbackURL : callbackURL).toString(); - } catch { - toRedirectTo = result.isRegister ? newUserURL || callbackURL : callbackURL; - } - throw ctx.redirect(toRedirectTo); -}); -const OAuth2LinkAccountBodySchema = z.object({ - providerId: z.string(), - callbackURL: z.string(), - scopes: z.array(z.string()).meta({ description: "Additional scopes to request when linking the account" }).optional(), - errorCallbackURL: z.string().meta({ description: "The URL to redirect to if there is an error during the link process" }).optional() -}); -const oAuth2LinkAccount = (options) => createAuthEndpoint("/oauth2/link", { - method: "POST", - body: OAuth2LinkAccountBodySchema, - use: [sessionMiddleware], - metadata: { openapi: { - description: "Link an OAuth2 account to the current user session", - responses: { "200": { - description: "Authorization URL generated successfully for linking an OAuth2 account", - content: { "application/json": { schema: { - type: "object", - properties: { - url: { - type: "string", - format: "uri", - description: "The authorization URL to redirect the user to for linking the OAuth2 account" - }, - redirect: { - type: "boolean", - description: "Indicates that the client should redirect to the provided URL", - enum: [true] - } - }, - required: ["url", "redirect"] - } } } - } } - } } -}, async (c) => { - const session = c.context.session; - if (!session) throw new APIError("UNAUTHORIZED", { message: GENERIC_OAUTH_ERROR_CODES.SESSION_REQUIRED }); - const provider = options.config.find((p) => p.providerId === c.body.providerId); - if (!provider) throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.PROVIDER_NOT_FOUND }); - const { providerId, clientId, clientSecret, redirectURI, authorizationUrl, discoveryUrl, pkce, scopes, prompt, accessType, authorizationUrlParams } = provider; - let finalAuthUrl = authorizationUrl; - if (!finalAuthUrl) { - if (!discoveryUrl) throw new APIError("BAD_REQUEST", { message: GENERIC_OAUTH_ERROR_CODES.INVALID_OAUTH_CONFIGURATION }); - const discovery = await betterFetch(discoveryUrl, { - method: "GET", - headers: provider.discoveryHeaders, - onError(context) { - c.context.logger.error(context.error.message, context.error, { discoveryUrl }); - } - }); - if (discovery.data) finalAuthUrl = discovery.data.authorization_endpoint; - } - if (!finalAuthUrl) throw new APIError("BAD_REQUEST", { message: GENERIC_OAUTH_ERROR_CODES.INVALID_OAUTH_CONFIGURATION }); - const state = await generateState(c, { - userId: session.user.id, - email: session.user.email - }, void 0); - const additionalParams = typeof authorizationUrlParams === "function" ? authorizationUrlParams(c) : authorizationUrlParams; - const url = await createAuthorizationURL({ - id: providerId, - options: { - clientId, - clientSecret, - redirectURI: redirectURI || `${c.context.baseURL}/oauth2/callback/${providerId}` - }, - authorizationEndpoint: finalAuthUrl, - state: state.state, - codeVerifier: pkce ? state.codeVerifier : void 0, - scopes: c.body.scopes || scopes || [], - redirectURI: redirectURI || `${c.context.baseURL}/oauth2/callback/${providerId}`, - prompt, - accessType, - additionalParams - }); - return c.json({ - url: url.toString(), - redirect: true - }); -}); -async function getUserInfo(tokens, finalUserInfoUrl) { - if (tokens.idToken) { - const decoded = decodeJwt(tokens.idToken); - if (decoded) { - if (decoded.sub && decoded.email) return { - id: decoded.sub, - emailVerified: decoded.email_verified, - image: decoded.picture, - ...decoded - }; - } - } - if (!finalUserInfoUrl) return null; - const userInfo = await betterFetch(finalUserInfoUrl, { - method: "GET", - headers: { Authorization: `Bearer ${tokens.accessToken}` } - }); - return { - id: userInfo.data?.sub ?? "", - emailVerified: userInfo.data?.email_verified ?? false, - email: userInfo.data?.email, - image: userInfo.data?.picture, - name: userInfo.data?.name, - ...userInfo.data - }; -} -const genericOAuth = (options) => { - const seenIds = /* @__PURE__ */ new Set(); - const nonUniqueIds = /* @__PURE__ */ new Set(); - for (const config2 of options.config) { - const id = config2.providerId; - if (seenIds.has(id)) nonUniqueIds.add(id); - seenIds.add(id); - } - if (nonUniqueIds.size > 0) console.warn(`Duplicate provider IDs found: ${Array.from(nonUniqueIds).join(", ")}`); - return { - id: "generic-oauth", - init: (ctx) => { - return { context: { socialProviders: options.config.map((c) => { - let finalUserInfoUrl = c.userInfoUrl; - return { - id: c.providerId, - name: c.providerId, - async createAuthorizationURL(data) { - let finalAuthUrl = c.authorizationUrl; - if (!finalAuthUrl && c.discoveryUrl) { - const discovery = await betterFetch(c.discoveryUrl, { - method: "GET", - headers: c.discoveryHeaders - }); - if (discovery.data) { - finalAuthUrl = discovery.data.authorization_endpoint; - finalUserInfoUrl = finalUserInfoUrl ?? discovery.data.userinfo_endpoint; - } - } - if (!finalAuthUrl) throw new APIError("BAD_REQUEST", { message: GENERIC_OAUTH_ERROR_CODES.INVALID_OAUTH_CONFIGURATION }); - return createAuthorizationURL({ - id: c.providerId, - options: { - clientId: c.clientId, - clientSecret: c.clientSecret, - redirectURI: c.redirectURI - }, - authorizationEndpoint: finalAuthUrl, - state: data.state, - codeVerifier: c.pkce ? data.codeVerifier : void 0, - scopes: c.scopes || [], - redirectURI: `${ctx.baseURL}/oauth2/callback/${c.providerId}` - }); - }, - async validateAuthorizationCode(data) { - if (c.getToken) return c.getToken(data); - let finalTokenUrl = c.tokenUrl; - if (c.discoveryUrl) { - const discovery = await betterFetch(c.discoveryUrl, { - method: "GET", - headers: c.discoveryHeaders - }); - if (discovery.data) { - finalTokenUrl = discovery.data.token_endpoint; - finalUserInfoUrl = discovery.data.userinfo_endpoint; - } - } - if (!finalTokenUrl) throw new APIError("BAD_REQUEST", { message: GENERIC_OAUTH_ERROR_CODES.TOKEN_URL_NOT_FOUND }); - return validateAuthorizationCode({ - headers: c.authorizationHeaders, - code: data.code, - codeVerifier: data.codeVerifier, - redirectURI: data.redirectURI, - options: { - clientId: c.clientId, - clientSecret: c.clientSecret, - redirectURI: c.redirectURI - }, - tokenEndpoint: finalTokenUrl, - authentication: c.authentication - }); - }, - async refreshAccessToken(refreshToken2) { - let finalTokenUrl = c.tokenUrl; - if (c.discoveryUrl) { - const discovery = await betterFetch(c.discoveryUrl, { - method: "GET", - headers: c.discoveryHeaders - }); - if (discovery.data) finalTokenUrl = discovery.data.token_endpoint; - } - if (!finalTokenUrl) throw new APIError("BAD_REQUEST", { message: GENERIC_OAUTH_ERROR_CODES.TOKEN_URL_NOT_FOUND }); - return refreshAccessToken({ - refreshToken: refreshToken2, - options: { - clientId: c.clientId, - clientSecret: c.clientSecret - }, - authentication: c.authentication, - tokenEndpoint: finalTokenUrl - }); - }, - async getUserInfo(tokens) { - const userInfo = c.getUserInfo ? await c.getUserInfo(tokens) : await getUserInfo(tokens, finalUserInfoUrl); - if (!userInfo) return null; - const userMap = await c.mapProfileToUser?.(userInfo); - return { - user: { - id: userInfo?.id, - email: userInfo?.email, - emailVerified: userInfo?.emailVerified, - image: userInfo?.image, - name: userInfo?.name, - ...userMap - }, - data: userInfo - }; - }, - options: { overrideUserInfoOnSignIn: c.overrideUserInfo } - }; - }).concat(ctx.socialProviders) } }; - }, - endpoints: { - signInWithOAuth2: signInWithOAuth2(options), - oAuth2Callback: oAuth2Callback(options), - oAuth2LinkAccount: oAuth2LinkAccount(options) - }, - options, - $ERROR_CODES: GENERIC_OAUTH_ERROR_CODES - }; -}; -defineErrorCodes({ PASSWORD_COMPROMISED: "The password you entered has been compromised. Please choose a different password." }); -z.object({ - payload: z.record(z.string(), z.any()), - overrideOptions: z.record(z.string(), z.any()).optional() -}); -z.object({ - token: z.string(), - issuer: z.string().optional() -}); -z.object({ - email: z.email().meta({ description: "Email address to send the magic link" }), - name: z.string().meta({ description: 'User display name. Only used if the user is registering for the first time. Eg: "my-name"' }).optional(), - callbackURL: z.string().meta({ description: "URL to redirect after magic link verification" }).optional(), - newUserCallbackURL: z.string().meta({ description: "URL to redirect after new user signup. Only used if the user is registering for the first time." }).optional(), - errorCallbackURL: z.string().meta({ description: "URL to redirect after error." }).optional() -}); -z.object({ - token: z.string().meta({ description: "Verification token" }), - callbackURL: z.string().meta({ description: 'URL to redirect after magic link verification, if not provided the user will be redirected to the root URL. Eg: "/dashboard"' }).optional(), - errorCallbackURL: z.string().meta({ description: "URL to redirect after error." }).optional(), - newUserCallbackURL: z.string().meta({ description: "URL to redirect after new user signup. Only used if the user is registering for the first time." }).optional() -}); -z.object({ - clientId: z.string(), - clientSecret: z.string().optional(), - type: z.enum([ - "web", - "native", - "user-agent-based", - "public" - ]), - name: z.string(), - icon: z.string().optional(), - metadata: z.string().optional(), - disabled: z.boolean().optional().default(false), - redirectUrls: z.string(), - userId: z.string().optional(), - createdAt: z.date(), - updatedAt: z.date() -}); -z.object({ - accept: z.boolean(), - consent_code: z.string().optional().nullish() -}); -z.record(z.any(), z.any()); -z.object({ - redirect_uris: z.array(z.string()).meta({ description: 'A list of redirect URIs. Eg: ["https://client.example.com/callback"]' }), - token_endpoint_auth_method: z.enum([ - "none", - "client_secret_basic", - "client_secret_post" - ]).meta({ description: 'The authentication method for the token endpoint. Eg: "client_secret_basic"' }).default("client_secret_basic").optional(), - grant_types: z.array(z.enum([ - "authorization_code", - "implicit", - "password", - "client_credentials", - "refresh_token", - "urn:ietf:params:oauth:grant-type:jwt-bearer", - "urn:ietf:params:oauth:grant-type:saml2-bearer" - ])).meta({ description: 'The grant types supported by the application. Eg: ["authorization_code"]' }).default(["authorization_code"]).optional(), - response_types: z.array(z.enum(["code", "token"])).meta({ description: 'The response types supported by the application. Eg: ["code"]' }).default(["code"]).optional(), - client_name: z.string().meta({ description: 'The name of the application. Eg: "My App"' }).optional(), - client_uri: z.string().meta({ description: 'The URI of the application. Eg: "https://client.example.com"' }).optional(), - logo_uri: z.string().meta({ description: 'The URI of the application logo. Eg: "https://client.example.com/logo.png"' }).optional(), - scope: z.string().meta({ description: 'The scopes supported by the application. Separated by spaces. Eg: "profile email"' }).optional(), - contacts: z.array(z.string()).meta({ description: 'The contact information for the application. Eg: ["admin@example.com"]' }).optional(), - tos_uri: z.string().meta({ description: 'The URI of the application terms of service. Eg: "https://client.example.com/tos"' }).optional(), - policy_uri: z.string().meta({ description: 'The URI of the application privacy policy. Eg: "https://client.example.com/policy"' }).optional(), - jwks_uri: z.string().meta({ description: 'The URI of the application JWKS. Eg: "https://client.example.com/jwks"' }).optional(), - jwks: z.record(z.any(), z.any()).meta({ description: 'The JWKS of the application. Eg: {"keys": [{"kty": "RSA", "alg": "RS256", "use": "sig", "n": "...", "e": "..."}]}' }).optional(), - metadata: z.record(z.any(), z.any()).meta({ description: 'The metadata of the application. Eg: {"key": "value"}' }).optional(), - software_id: z.string().meta({ description: 'The software ID of the application. Eg: "my-software"' }).optional(), - software_version: z.string().meta({ description: 'The software version of the application. Eg: "1.0.0"' }).optional(), - software_statement: z.string().meta({ description: "The software statement of the application." }).optional() -}); -z.object({ - redirect_uris: z.array(z.string()), - token_endpoint_auth_method: z.enum([ - "none", - "client_secret_basic", - "client_secret_post" - ]).default("client_secret_basic").optional(), - grant_types: z.array(z.enum([ - "authorization_code", - "implicit", - "password", - "client_credentials", - "refresh_token", - "urn:ietf:params:oauth:grant-type:jwt-bearer", - "urn:ietf:params:oauth:grant-type:saml2-bearer" - ])).default(["authorization_code"]).optional(), - response_types: z.array(z.enum(["code", "token"])).default(["code"]).optional(), - client_name: z.string().optional(), - client_uri: z.string().optional(), - logo_uri: z.string().optional(), - scope: z.string().optional(), - contacts: z.array(z.string()).optional(), - tos_uri: z.string().optional(), - policy_uri: z.string().optional(), - jwks_uri: z.string().optional(), - jwks: z.record(z.string(), z.any()).optional(), - metadata: z.record(z.any(), z.any()).optional(), - software_id: z.string().optional(), - software_version: z.string().optional(), - software_statement: z.string().optional() -}); -z.record(z.any(), z.any()); -defineErrorCodes({ INVALID_SESSION_TOKEN: "Invalid session token" }); -z.object({ sessionToken: z.string().meta({ description: "The session token to set as active" }) }); -z.object({ sessionToken: z.string().meta({ description: "The session token to revoke" }) }); -z.object({ - callbackURL: z.string().meta({ description: "The URL to redirect to after the proxy" }), - cookies: z.string().meta({ description: "The cookies to set after the proxy" }) -}); -z.object({ idToken: z.string().meta({ description: "Google ID token, which the client obtains from the One Tap API" }) }); -z.object({ token: z.string().meta({ description: 'The token to verify. Eg: "some-token"' }) }); -createAuthMiddleware(async () => { - return {}; -}); -createAuthMiddleware({ use: [sessionMiddleware] }, async (ctx) => { - return { session: ctx.context.session }; -}); -defineErrorCodes({ - YOU_ARE_NOT_ALLOWED_TO_CREATE_A_NEW_ORGANIZATION: "You are not allowed to create a new organization", - YOU_HAVE_REACHED_THE_MAXIMUM_NUMBER_OF_ORGANIZATIONS: "You have reached the maximum number of organizations", - ORGANIZATION_ALREADY_EXISTS: "Organization already exists", - ORGANIZATION_SLUG_ALREADY_TAKEN: "Organization slug already taken", - ORGANIZATION_NOT_FOUND: "Organization not found", - USER_IS_NOT_A_MEMBER_OF_THE_ORGANIZATION: "User is not a member of the organization", - YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_ORGANIZATION: "You are not allowed to update this organization", - YOU_ARE_NOT_ALLOWED_TO_DELETE_THIS_ORGANIZATION: "You are not allowed to delete this organization", - NO_ACTIVE_ORGANIZATION: "No active organization", - USER_IS_ALREADY_A_MEMBER_OF_THIS_ORGANIZATION: "User is already a member of this organization", - MEMBER_NOT_FOUND: "Member not found", - ROLE_NOT_FOUND: "Role not found", - YOU_ARE_NOT_ALLOWED_TO_CREATE_A_NEW_TEAM: "You are not allowed to create a new team", - TEAM_ALREADY_EXISTS: "Team already exists", - TEAM_NOT_FOUND: "Team not found", - YOU_CANNOT_LEAVE_THE_ORGANIZATION_AS_THE_ONLY_OWNER: "You cannot leave the organization as the only owner", - YOU_CANNOT_LEAVE_THE_ORGANIZATION_WITHOUT_AN_OWNER: "You cannot leave the organization without an owner", - YOU_ARE_NOT_ALLOWED_TO_DELETE_THIS_MEMBER: "You are not allowed to delete this member", - YOU_ARE_NOT_ALLOWED_TO_INVITE_USERS_TO_THIS_ORGANIZATION: "You are not allowed to invite users to this organization", - USER_IS_ALREADY_INVITED_TO_THIS_ORGANIZATION: "User is already invited to this organization", - INVITATION_NOT_FOUND: "Invitation not found", - YOU_ARE_NOT_THE_RECIPIENT_OF_THE_INVITATION: "You are not the recipient of the invitation", - EMAIL_VERIFICATION_REQUIRED_BEFORE_ACCEPTING_OR_REJECTING_INVITATION: "Email verification required before accepting or rejecting invitation", - YOU_ARE_NOT_ALLOWED_TO_CANCEL_THIS_INVITATION: "You are not allowed to cancel this invitation", - INVITER_IS_NO_LONGER_A_MEMBER_OF_THE_ORGANIZATION: "Inviter is no longer a member of the organization", - YOU_ARE_NOT_ALLOWED_TO_INVITE_USER_WITH_THIS_ROLE: "You are not allowed to invite a user with this role", - FAILED_TO_RETRIEVE_INVITATION: "Failed to retrieve invitation", - YOU_HAVE_REACHED_THE_MAXIMUM_NUMBER_OF_TEAMS: "You have reached the maximum number of teams", - UNABLE_TO_REMOVE_LAST_TEAM: "Unable to remove last team", - YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_MEMBER: "You are not allowed to update this member", - ORGANIZATION_MEMBERSHIP_LIMIT_REACHED: "Organization membership limit reached", - YOU_ARE_NOT_ALLOWED_TO_CREATE_TEAMS_IN_THIS_ORGANIZATION: "You are not allowed to create teams in this organization", - YOU_ARE_NOT_ALLOWED_TO_DELETE_TEAMS_IN_THIS_ORGANIZATION: "You are not allowed to delete teams in this organization", - YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_TEAM: "You are not allowed to update this team", - YOU_ARE_NOT_ALLOWED_TO_DELETE_THIS_TEAM: "You are not allowed to delete this team", - INVITATION_LIMIT_REACHED: "Invitation limit reached", - TEAM_MEMBER_LIMIT_REACHED: "Team member limit reached", - USER_IS_NOT_A_MEMBER_OF_THE_TEAM: "User is not a member of the team", - YOU_CAN_NOT_ACCESS_THE_MEMBERS_OF_THIS_TEAM: "You are not allowed to list the members of this team", - YOU_DO_NOT_HAVE_AN_ACTIVE_TEAM: "You do not have an active team", - YOU_ARE_NOT_ALLOWED_TO_CREATE_A_NEW_TEAM_MEMBER: "You are not allowed to create a new member", - YOU_ARE_NOT_ALLOWED_TO_REMOVE_A_TEAM_MEMBER: "You are not allowed to remove a team member", - YOU_ARE_NOT_ALLOWED_TO_ACCESS_THIS_ORGANIZATION: "You are not allowed to access this organization as an owner", - YOU_ARE_NOT_A_MEMBER_OF_THIS_ORGANIZATION: "You are not a member of this organization", - MISSING_AC_INSTANCE: "Dynamic Access Control requires a pre-defined ac instance on the server auth plugin. Read server logs for more information", - YOU_MUST_BE_IN_AN_ORGANIZATION_TO_CREATE_A_ROLE: "You must be in an organization to create a role", - YOU_ARE_NOT_ALLOWED_TO_CREATE_A_ROLE: "You are not allowed to create a role", - YOU_ARE_NOT_ALLOWED_TO_UPDATE_A_ROLE: "You are not allowed to update a role", - YOU_ARE_NOT_ALLOWED_TO_DELETE_A_ROLE: "You are not allowed to delete a role", - YOU_ARE_NOT_ALLOWED_TO_READ_A_ROLE: "You are not allowed to read a role", - YOU_ARE_NOT_ALLOWED_TO_LIST_A_ROLE: "You are not allowed to list a role", - YOU_ARE_NOT_ALLOWED_TO_GET_A_ROLE: "You are not allowed to get a role", - TOO_MANY_ROLES: "This organization has too many roles", - INVALID_RESOURCE: "The provided permission includes an invalid resource", - ROLE_NAME_IS_ALREADY_TAKEN: "That role name is already taken", - CANNOT_DELETE_A_PRE_DEFINED_ROLE: "Cannot delete a pre-defined role", - ROLE_IS_ASSIGNED_TO_MEMBERS: "Cannot delete a role that is assigned to members. Please reassign the members to a different role first" -}); -z.object({ - organizationId: z.string().optional().meta({ description: "The id of the organization to create the role in. If not provided, the user's active organization will be used." }), - role: z.string().meta({ description: "The name of the role to create" }), - permission: z.record(z.string(), z.array(z.string())).meta({ description: "The permission to assign to the role" }) -}); -z.object({ organizationId: z.string().optional().meta({ description: "The id of the organization to create the role in. If not provided, the user's active organization will be used." }) }).and(z.union([z.object({ roleName: z.string().nonempty().meta({ description: "The name of the role to delete" }) }), z.object({ roleId: z.string().nonempty().meta({ description: "The id of the role to delete" }) })])); -z.object({ organizationId: z.string().optional().meta({ description: "The id of the organization to list roles for. If not provided, the user's active organization will be used." }) }).optional(); -z.object({ organizationId: z.string().optional().meta({ description: "The id of the organization to read a role for. If not provided, the user's active organization will be used." }) }).and(z.union([z.object({ roleName: z.string().nonempty().meta({ description: "The name of the role to read" }) }), z.object({ roleId: z.string().nonempty().meta({ description: "The id of the role to read" }) })])).optional(); -z.union([z.object({ roleName: z.string().nonempty().meta({ description: "The name of the role to update" }) }), z.object({ roleId: z.string().nonempty().meta({ description: "The id of the role to update" }) })]); -z.object({ - email: z.string().meta({ description: "The email address of the user to invite" }), - role: z.union([z.string().meta({ description: "The role to assign to the user" }), z.array(z.string().meta({ description: "The roles to assign to the user" }))]).meta({ description: 'The role(s) to assign to the user. It can be `admin`, `member`, owner. Eg: "member"' }), - organizationId: z.string().meta({ description: "The organization ID to invite the user to" }).optional(), - resend: z.boolean().meta({ description: "Resend the invitation email, if the user is already invited. Eg: true" }).optional(), - teamId: z.union([z.string().meta({ description: "The team ID to invite the user to" }).optional(), z.array(z.string()).meta({ description: "The team IDs to invite the user to" }).optional()]) -}); -z.object({ invitationId: z.string().meta({ description: "The ID of the invitation to accept" }) }); -z.object({ invitationId: z.string().meta({ description: "The ID of the invitation to reject" }) }); -z.object({ invitationId: z.string().meta({ description: "The ID of the invitation to cancel" }) }); -z.object({ id: z.string().meta({ description: "The ID of the invitation to get" }) }); -z.object({ organizationId: z.string().meta({ description: "The ID of the organization to list invitations for" }).optional() }).optional(); -z.object({ - userId: z.coerce.string().meta({ description: 'The user Id which represents the user to be added as a member. If `null` is provided, then it\'s expected to provide session headers. Eg: "user-id"' }), - role: z.union([z.string(), z.array(z.string())]).meta({ description: 'The role(s) to assign to the new member. Eg: ["admin", "sale"]' }), - organizationId: z.string().meta({ description: `An optional organization ID to pass. If not provided, will default to the user's active organization. Eg: "org-id"` }).optional(), - teamId: z.string().meta({ description: 'An optional team ID to add the member to. Eg: "team-id"' }).optional() -}); -z.object({ - memberIdOrEmail: z.string().meta({ description: "The ID or email of the member to remove" }), - organizationId: z.string().meta({ description: 'The ID of the organization to remove the member from. If not provided, the active organization will be used. Eg: "org-id"' }).optional() -}); -z.object({ - role: z.union([z.string(), z.array(z.string())]).meta({ description: 'The new role to be applied. This can be a string or array of strings representing the roles. Eg: ["admin", "sale"]' }), - memberId: z.string().meta({ description: 'The member id to apply the role update to. Eg: "member-id"' }), - organizationId: z.string().meta({ description: 'An optional organization ID which the member is a part of to apply the role update. If not provided, you must provide session headers to get the active organization. Eg: "organization-id"' }).optional() -}); -z.object({ organizationId: z.string().meta({ description: 'The organization Id for the member to leave. Eg: "organization-id"' }) }); -z.object({ - userId: z.string().meta({ description: "The user ID to get the role for. If not provided, will default to the current user's" }).optional(), - organizationId: z.string().meta({ description: `The organization ID to list members for. If not provided, will default to the user's active organization. Eg: "organization-id"` }).optional(), - organizationSlug: z.string().meta({ description: `The organization slug to list members for. If not provided, will default to the user's active organization. Eg: "organization-slug"` }).optional() -}).optional(); -z.object({ - name: z.string().min(1).meta({ description: "The name of the organization" }), - slug: z.string().min(1).meta({ description: "The slug of the organization" }), - userId: z.coerce.string().meta({ description: 'The user id of the organization creator. If not provided, the current user will be used. Should only be used by admins or when called by the server. server-only. Eg: "user-id"' }).optional(), - logo: z.string().meta({ description: "The logo of the organization" }).optional(), - metadata: z.record(z.string(), z.any()).meta({ description: "The metadata of the organization" }).optional(), - keepCurrentActiveOrganization: z.boolean().meta({ description: "Whether to keep the current active organization active after creating a new one. Eg: true" }).optional() -}); -z.object({ slug: z.string().meta({ description: 'The organization slug to check. Eg: "my-org"' }) }); -z.object({ - name: z.string().min(1).meta({ description: "The name of the organization" }).optional(), - slug: z.string().min(1).meta({ description: "The slug of the organization" }).optional(), - logo: z.string().meta({ description: "The logo of the organization" }).optional(), - metadata: z.record(z.string(), z.any()).meta({ description: "The metadata of the organization" }).optional() -}); -z.object({ organizationId: z.string().meta({ description: "The organization id to delete" }) }); -z.optional(z.object({ - organizationId: z.string().meta({ description: "The organization id to get" }).optional(), - organizationSlug: z.string().meta({ description: "The organization slug to get" }).optional(), - membersLimit: z.number().or(z.string().transform((val) => parseInt(val))).meta({ description: "The limit of members to get. By default, it uses the membershipLimit option which defaults to 100." }).optional() -})); -z.object({ - organizationId: z.string().meta({ description: 'The organization id to set as active. It can be null to unset the active organization. Eg: "org-id"' }).nullable().optional(), - organizationSlug: z.string().meta({ description: 'The organization slug to set as active. It can be null to unset the active organization if organizationId is not provided. Eg: "org-slug"' }).optional() -}); -const roleSchema = z.string(); -const invitationStatus = z.enum([ - "pending", - "accepted", - "rejected", - "canceled" -]).default("pending"); -z.object({ - id: z.string().default(generateId), - name: z.string(), - slug: z.string(), - logo: z.string().nullish().optional(), - metadata: z.record(z.string(), z.unknown()).or(z.string().transform((v) => JSON.parse(v))).optional(), - createdAt: z.date() -}); -z.object({ - id: z.string().default(generateId), - organizationId: z.string(), - userId: z.coerce.string(), - role: roleSchema, - createdAt: z.date().default(() => /* @__PURE__ */ new Date()) -}); -z.object({ - id: z.string().default(generateId), - organizationId: z.string(), - email: z.string(), - role: roleSchema, - status: invitationStatus, - teamId: z.string().nullish(), - inviterId: z.string(), - expiresAt: z.date(), - createdAt: z.date().default(() => /* @__PURE__ */ new Date()) -}); -z.object({ - id: z.string().default(generateId), - name: z.string().min(1), - organizationId: z.string(), - createdAt: z.date(), - updatedAt: z.date().optional() -}); -z.object({ - id: z.string().default(generateId), - teamId: z.string(), - userId: z.string(), - createdAt: z.date().default(() => /* @__PURE__ */ new Date()) -}); -z.object({ - id: z.string().default(generateId), - organizationId: z.string(), - role: z.string(), - permission: z.record(z.string(), z.array(z.string())), - createdAt: z.date().default(() => /* @__PURE__ */ new Date()), - updatedAt: z.date().optional() -}); -const defaultRoles = [ - "admin", - "member", - "owner" -]; -z.union([z.enum(defaultRoles), z.array(z.enum(defaultRoles))]); -z.object({ - name: z.string().meta({ description: 'The name of the team. Eg: "my-team"' }), - organizationId: z.string().meta({ description: 'The organization ID which the team will be created in. Defaults to the active organization. Eg: "organization-id"' }).optional() -}); -z.object({ - teamId: z.string().meta({ description: `The team ID of the team to remove. Eg: "team-id"` }), - organizationId: z.string().meta({ description: `The organization ID which the team falls under. If not provided, it will default to the user's active organization. Eg: "organization-id"` }).optional() -}); -z.optional(z.object({ organizationId: z.string().meta({ description: `The organization ID which the teams are under to list. Defaults to the users active organization. Eg: "organization-id"` }).optional() })); -z.object({ teamId: z.string().meta({ description: "The team id to set as active. It can be null to unset the active team" }).nullable().optional() }); -z.optional(z.object({ teamId: z.string().optional().meta({ description: "The team whose members we should return. If this is not provided the members of the current active team get returned." }) })); -z.object({ - teamId: z.string().meta({ description: "The team the user should be a member of." }), - userId: z.coerce.string().meta({ description: "The user Id which represents the user to be added as a member." }) -}); -z.object({ - teamId: z.string().meta({ description: "The team the user should be removed from." }), - userId: z.coerce.string().meta({ description: "The user which should be removed from the team." }) -}); -z.object({ organizationId: z.string().optional() }).and(z.union([z.object({ - permission: z.record(z.string(), z.array(z.string())), - permissions: z.undefined() -}), z.object({ - permission: z.undefined(), - permissions: z.record(z.string(), z.array(z.string())) -})])); -defineErrorCodes({ - INVALID_PHONE_NUMBER: "Invalid phone number", - PHONE_NUMBER_EXIST: "Phone number already exists", - PHONE_NUMBER_NOT_EXIST: "phone number isn't registered", - INVALID_PHONE_NUMBER_OR_PASSWORD: "Invalid phone number or password", - UNEXPECTED_ERROR: "Unexpected error", - OTP_NOT_FOUND: "OTP not found", - OTP_EXPIRED: "OTP expired", - INVALID_OTP: "Invalid OTP", - PHONE_NUMBER_NOT_VERIFIED: "Phone number not verified", - PHONE_NUMBER_CANNOT_BE_UPDATED: "Phone number cannot be updated", - SEND_OTP_NOT_IMPLEMENTED: "sendOTP not implemented", - TOO_MANY_ATTEMPTS: "Too many attempts" -}); -z.object({ - phoneNumber: z.string().meta({ description: 'Phone number to sign in. Eg: "+1234567890"' }), - password: z.string().meta({ description: "Password to use for sign in." }), - rememberMe: z.boolean().meta({ description: "Remember the session. Eg: true" }).optional() -}); -z.object({ phoneNumber: z.string().meta({ description: 'Phone number to send OTP. Eg: "+1234567890"' }) }); -z.object({ - phoneNumber: z.string().meta({ description: 'Phone number to verify. Eg: "+1234567890"' }), - code: z.string().meta({ description: 'OTP code. Eg: "123456"' }), - disableSession: z.boolean().meta({ description: "Disable session creation after verification. Eg: false" }).optional(), - updatePhoneNumber: z.boolean().meta({ description: "Check if there is a session and update the phone number. Eg: true" }).optional() -}).and(z.record(z.string(), z.any())); -z.object({ phoneNumber: z.string() }); -z.object({ - otp: z.string().meta({ description: 'The one time password to reset the password. Eg: "123456"' }), - phoneNumber: z.string().meta({ description: 'The phone number to the account which intends to reset the password for. Eg: "+1234567890"' }), - newPassword: z.string().meta({ description: `The new password. Eg: "new-and-secure-password"` }) -}); -z.object({ - walletAddress: z.string().regex(/^0[xX][a-fA-F0-9]{40}$/i).length(42), - chainId: z.number().int().positive().max(2147483647).optional().default(1) -}); -defineErrorCodes({ - OTP_NOT_ENABLED: "OTP not enabled", - OTP_HAS_EXPIRED: "OTP has expired", - TOTP_NOT_ENABLED: "TOTP not enabled", - TWO_FACTOR_NOT_ENABLED: "Two factor isn't enabled", - BACKUP_CODES_NOT_ENABLED: "Backup codes aren't enabled", - INVALID_BACKUP_CODE: "Invalid backup code", - INVALID_CODE: "Invalid code", - TOO_MANY_ATTEMPTS_REQUEST_NEW_CODE: "Too many attempts. Please request a new code.", - INVALID_TWO_FACTOR_COOKIE: "Invalid two factor cookie" -}); -z.object({ - code: z.string().meta({ description: `A backup code to verify. Eg: "123456"` }), - disableSession: z.boolean().meta({ description: "If true, the session cookie will not be set." }).optional(), - trustDevice: z.boolean().meta({ description: "If true, the device will be trusted for 30 days. It'll be refreshed on every sign in request within this time. Eg: true" }).optional() -}); -z.object({ userId: z.coerce.string().meta({ description: `The user ID to view all backup codes. Eg: "user-id"` }) }); -z.object({ password: z.string().meta({ description: "The users password." }) }); -z.object({ - code: z.string().meta({ description: 'The otp code to verify. Eg: "012345"' }), - trustDevice: z.boolean().optional().meta({ description: "If true, the device will be trusted for 30 days. It'll be refreshed on every sign in request within this time. Eg: true" }) -}); -z.object({ trustDevice: z.boolean().optional().meta({ description: "If true, the device will be trusted for 30 days. It'll be refreshed on every sign in request within this time. Eg: true" }) }).optional(); -z.object({ secret: z.string().meta({ description: "The secret to generate the TOTP code" }) }); -z.object({ password: z.string().meta({ description: "User password" }) }); -z.object({ - code: z.string().meta({ description: 'The otp code to verify. Eg: "012345"' }), - trustDevice: z.boolean().meta({ description: "If true, the device will be trusted for 30 days. It'll be refreshed on every sign in request within this time. Eg: true" }).optional() -}); -z.object({ - password: z.string().meta({ description: "User password" }), - issuer: z.string().meta({ description: "Custom issuer for the TOTP URI" }).optional() -}); -z.object({ password: z.string().meta({ description: "User password" }) }); -defineErrorCodes({ - INVALID_USERNAME_OR_PASSWORD: "Invalid username or password", - EMAIL_NOT_VERIFIED: "Email not verified", - UNEXPECTED_ERROR: "Unexpected error", - USERNAME_IS_ALREADY_TAKEN: "Username is already taken. Please try another.", - USERNAME_TOO_SHORT: "Username is too short", - USERNAME_TOO_LONG: "Username is too long", - INVALID_USERNAME: "Username is invalid", - INVALID_DISPLAY_USERNAME: "Display username is invalid" -}); -z.object({ - username: z.string().meta({ description: "The username of the user" }), - password: z.string().meta({ description: "The password of the user" }), - rememberMe: z.boolean().meta({ description: "Remember the user session" }).optional(), - callbackURL: z.string().meta({ description: "The URL to redirect to after email verification" }).optional() -}); -z.object({ username: z.string().meta({ description: "The username to check" }) }); -const auth = betterAuth({ - baseURL: private_env.ORIGIN, - secret: private_env.BETTER_AUTH_SECRET, - database: drizzleAdapter(db, { provider: "pg" }), - emailAndPassword: { enabled: true }, - databaseHooks: { - user: { - create: { - after: async (user) => { - const [personalTeam] = await db.insert(team).values({ - name: user.name, - isPersonal: true, - ownerId: user.id, - avatarUrl: user.image - }).returning(); - await db.insert(teamMember).values({ - teamId: personalTeam.id, - userId: user.id, - role: "owner" - }); - } - } - } - }, - plugins: [ - genericOAuth({ - config: [ - { - providerId: "osu", - clientId: private_env.OSU_CLIENT_ID, - clientSecret: private_env.OSU_CLIENT_SECRET, - authorizationUrl: "https://osu.ppy.sh/oauth/authorize", - tokenUrl: "https://osu.ppy.sh/oauth/token", - userInfoUrl: "https://osu.ppy.sh/api/v2/me", - scopes: ["identify", "public"], - pkce: false, - authentication: "post", - // ── FIX: Use ORIGIN env var instead of hardcoded localhost ── - redirectURI: `${private_env.ORIGIN}/api/auth/oauth2/callback/osu`, - getToken: async ({ code, redirectURI }) => { - const res = await fetch("https://osu.ppy.sh/oauth/token", { - method: "POST", - headers: { - Accept: "application/json", - "Content-Type": "application/x-www-form-urlencoded" - }, - body: new URLSearchParams({ - client_id: private_env.OSU_CLIENT_ID, - client_secret: private_env.OSU_CLIENT_SECRET, - code, - grant_type: "authorization_code", - redirect_uri: redirectURI - }) - }); - const data = await res.json(); - if (!res.ok) { - console.error("osu! token exchange failed:", data); - throw new Error("Token exchange failed"); - } - return { - accessToken: data.access_token, - refreshToken: data.refresh_token, - accessTokenExpiresAt: new Date(Date.now() + data.expires_in * 1e3), - scopes: ["identify", "public"], - raw: data - }; - }, - mapProfileToUser(profile) { - return { - name: profile.username, - image: profile.avatar_url, - email: `${profile.id}@osu.local` - }; - } - } - ] - }), - sveltekitCookies(getRequestEvent) - // must be last - ] -}); -export { - auth as a, - createKyselyAdapter as c, - getKyselyDatabaseType as g, - svelteKitHandler as s -}; diff --git a/.svelte-kit/output/server/chunks/bun-sqlite-dialect.js b/.svelte-kit/output/server/chunks/bun-sqlite-dialect.js deleted file mode 100644 index 6fe94c6..0000000 --- a/.svelte-kit/output/server/chunks/bun-sqlite-dialect.js +++ /dev/null @@ -1,155 +0,0 @@ -import { CompiledQuery, DefaultQueryCompiler, DEFAULT_MIGRATION_TABLE, DEFAULT_MIGRATION_LOCK_TABLE, sql } from "kysely"; -var BunSqliteAdapter = class { - get supportsCreateIfNotExists() { - return true; - } - get supportsTransactionalDdl() { - return false; - } - get supportsReturning() { - return true; - } - async acquireMigrationLock() { - } - async releaseMigrationLock() { - } - get supportsOutput() { - return true; - } -}; -var BunSqliteDriver = class { - #config; - #connectionMutex = new ConnectionMutex(); - #db; - #connection; - constructor(config) { - this.#config = { ...config }; - } - async init() { - this.#db = this.#config.database; - this.#connection = new BunSqliteConnection(this.#db); - if (this.#config.onCreateConnection) await this.#config.onCreateConnection(this.#connection); - } - async acquireConnection() { - await this.#connectionMutex.lock(); - return this.#connection; - } - async beginTransaction(connection) { - await connection.executeQuery(CompiledQuery.raw("begin")); - } - async commitTransaction(connection) { - await connection.executeQuery(CompiledQuery.raw("commit")); - } - async rollbackTransaction(connection) { - await connection.executeQuery(CompiledQuery.raw("rollback")); - } - async releaseConnection() { - this.#connectionMutex.unlock(); - } - async destroy() { - this.#db?.close(); - } -}; -var BunSqliteConnection = class { - #db; - constructor(db) { - this.#db = db; - } - executeQuery(compiledQuery) { - const { sql: sql$1, parameters } = compiledQuery; - const stmt = this.#db.prepare(sql$1); - return Promise.resolve({ rows: stmt.all(parameters) }); - } - async *streamQuery() { - throw new Error("Streaming query is not supported by SQLite driver."); - } -}; -var ConnectionMutex = class { - #promise; - #resolve; - async lock() { - while (await this.#promise) await this.#promise; - this.#promise = new Promise((resolve) => { - this.#resolve = resolve; - }); - } - unlock() { - const resolve = this.#resolve; - this.#promise = void 0; - this.#resolve = void 0; - resolve?.(); - } -}; -var BunSqliteIntrospector = class { - #db; - constructor(db) { - this.#db = db; - } - async getSchemas() { - return []; - } - async getTables(options = { withInternalKyselyTables: false }) { - let query = this.#db.selectFrom("sqlite_schema").where("type", "=", "table").where("name", "not like", "sqlite_%").select("name").$castTo(); - if (!options.withInternalKyselyTables) query = query.where("name", "!=", DEFAULT_MIGRATION_TABLE).where("name", "!=", DEFAULT_MIGRATION_LOCK_TABLE); - const tables = await query.execute(); - return Promise.all(tables.map(({ name }) => this.#getTableMetadata(name))); - } - async getMetadata(options) { - return { tables: await this.getTables(options) }; - } - async #getTableMetadata(table) { - const db = this.#db; - const autoIncrementCol = (await db.selectFrom("sqlite_master").where("name", "=", table).select("sql").$castTo().execute())[0]?.sql?.split(/[\(\),]/)?.find((it) => it.toLowerCase().includes("autoincrement"))?.split(/\s+/)?.[0]?.replace(/["`]/g, ""); - return { - name: table, - columns: (await db.selectFrom(sql`pragma_table_info(${table})`.as("table_info")).select([ - "name", - "type", - "notnull", - "dflt_value" - ]).execute()).map((col) => ({ - name: col.name, - dataType: col.type, - isNullable: !col.notnull, - isAutoIncrementing: col.name === autoIncrementCol, - hasDefaultValue: col.dflt_value != null - })), - isView: true - }; - } -}; -var BunSqliteQueryCompiler = class extends DefaultQueryCompiler { - getCurrentParameterPlaceholder() { - return "?"; - } - getLeftIdentifierWrapper() { - return '"'; - } - getRightIdentifierWrapper() { - return '"'; - } - getAutoIncrement() { - return "autoincrement"; - } -}; -var BunSqliteDialect = class { - #config; - constructor(config) { - this.#config = { ...config }; - } - createDriver() { - return new BunSqliteDriver(this.#config); - } - createQueryCompiler() { - return new BunSqliteQueryCompiler(); - } - createAdapter() { - return new BunSqliteAdapter(); - } - createIntrospector(db) { - return new BunSqliteIntrospector(db); - } -}; -export { - BunSqliteDialect -}; diff --git a/.svelte-kit/output/server/chunks/engine.js b/.svelte-kit/output/server/chunks/engine.js deleted file mode 100644 index f6bafe4..0000000 --- a/.svelte-kit/output/server/chunks/engine.js +++ /dev/null @@ -1,350 +0,0 @@ -import { d as db, b as match, e as matchParticipant, t as teamMember, f as matchParticipantPlayer, g as matchGame, h as matchGameScore, i as matchQueue, p as playerRating } from "./index2.js"; -import { eq, sql, asc } from "drizzle-orm"; -const MATCH_STATES = { - CREATED: "CREATED", - LOBBY: "LOBBY", - ROLLING: "ROLLING", - PICKING: "PICKING", - PLAYING: "PLAYING", - FINISHED: "FINISHED", - CANCELLED: "CANCELLED" -}; -const GAME_STATES = { - PLAYING: "PLAYING", - FINISHED: "FINISHED" -}; -async function joinQueue(userId, teamId) { - let rating = await db.query.playerRating.findFirst({ - where: eq(playerRating.userId, userId) - }); - if (!rating) { - [rating] = await db.insert(playerRating).values({ userId, elo: 1e3 }).returning(); - } - const existing = await db.query.matchQueue.findFirst({ - where: eq(matchQueue.userId, userId) - }); - if (existing) throw new Error("Already in queue"); - await db.insert(matchQueue).values({ - userId, - teamId, - elo: rating.elo - }); - return tryMatchFromQueue(); -} -async function leaveQueue(userId) { - await db.delete(matchQueue).where(eq(matchQueue.userId, userId)); -} -async function getQueueStatus(userId) { - const entry = await db.query.matchQueue.findFirst({ - where: eq(matchQueue.userId, userId) - }); - const count = await db.select({ count: sql`count(*)` }).from(matchQueue); - return { - inQueue: !!entry, - queueSize: Number(count[0].count), - joinedAt: entry?.joinedAt ?? null - }; -} -async function tryMatchFromQueue() { - const queue = await db.query.matchQueue.findMany({ - orderBy: asc(matchQueue.elo) - }); - if (queue.length < 2) return null; - let bestPair = null; - let smallestGap = Infinity; - for (let i = 0; i < queue.length - 1; i++) { - const gap = Math.abs(queue[i].elo - queue[i + 1].elo); - if (gap < smallestGap) { - smallestGap = gap; - bestPair = [queue[i], queue[i + 1]]; - } - } - if (!bestPair) return null; - const avgElo = (bestPair[0].elo + bestPair[1].elo) / 2; - const selectedPool = await selectMappoolForRating(avgElo); - if (!selectedPool) throw new Error("No mappools available"); - await db.delete(matchQueue).where(eq(matchQueue.userId, bestPair[0].userId)); - await db.delete(matchQueue).where(eq(matchQueue.userId, bestPair[1].userId)); - const created = await createMatch({ - name: "Ranked Match", - config: { bestOf: 7, teamSize: 1, scoringType: "score" }, - mappoolId: selectedPool.id, - teams: [bestPair[0].teamId, bestPair[1].teamId], - createdBy: "system" - }); - return created; -} -async function selectMappoolForRating(avgElo) { - const pools = await db.query.mappool.findMany({ - with: { slots: true } - }); - if (pools.length === 0) return null; - const targetStars = 3 + (avgElo - 800) / 400 * 4; - const clampedTarget = Math.max(2, Math.min(8, targetStars)); - let bestPool = pools[0]; - let bestDiff = Infinity; - for (const pool of pools) { - if (pool.slots.length === 0) continue; - const avgStars = pool.slots.reduce((sum, s) => sum + (s.starRating ?? 0), 0) / pool.slots.length; - const diff = Math.abs(avgStars - clampedTarget); - if (diff < bestDiff) { - bestDiff = diff; - bestPool = pool; - } - } - return bestPool; -} -async function createMatch(opts) { - const { name, config, mappoolId, teams, createdBy } = opts; - const [created] = await db.insert(match).values({ - name, - config, - mappoolId, - createdBy, - state: MATCH_STATES.CREATED - }).returning(); - for (let i = 0; i < teams.length; i++) { - const [participant] = await db.insert(matchParticipant).values({ - matchId: created.id, - teamId: teams[i], - slot: i + 1 - }).returning(); - const members = await db.query.teamMember.findMany({ - where: eq(teamMember.teamId, teams[i]) - }); - for (const member of members) { - await db.insert(matchParticipantPlayer).values({ - participantId: participant.id, - userId: member.userId - }); - } - } - return getMatchFull(created.id); -} -async function moveToLobby(matchId, osuLobbyId) { - const m = await getMatchOrThrow(matchId); - assertState(m.state, MATCH_STATES.CREATED); - await db.update(match).set({ - state: MATCH_STATES.LOBBY, - osuLobbyId: osuLobbyId ?? null, - startedAt: /* @__PURE__ */ new Date() - }).where(eq(match.id, matchId)); - return getMatchFull(matchId); -} -async function moveToRolling(matchId) { - const m = await getMatchOrThrow(matchId); - assertState(m.state, MATCH_STATES.LOBBY); - await db.update(match).set({ state: MATCH_STATES.ROLLING }).where(eq(match.id, matchId)); - return getMatchFull(matchId); -} -async function submitRoll(matchId, participantId, value) { - const m = await getMatchOrThrow(matchId); - assertState(m.state, MATCH_STATES.ROLLING); - await db.update(matchParticipant).set({ rollValue: value }).where(eq(matchParticipant.id, participantId)); - const participants = await db.query.matchParticipant.findMany({ - where: eq(matchParticipant.matchId, matchId) - }); - const allRolled = participants.every( - (p) => p.id === participantId ? true : p.rollValue !== null - ); - if (allRolled) { - const sorted = [...participants].map((p) => ({ - ...p, - rollValue: p.id === participantId ? value : p.rollValue - })).sort((a, b) => b.rollValue - a.rollValue); - for (let i = 0; i < sorted.length; i++) { - await db.update(matchParticipant).set({ pickOrder: i + 1 }).where(eq(matchParticipant.id, sorted[i].id)); - } - await db.update(match).set({ state: MATCH_STATES.PICKING }).where(eq(match.id, matchId)); - } - return getMatchFull(matchId); -} -async function pickMap(matchId, participantId, mappoolSlotId) { - const m = await getMatchOrThrow(matchId); - assertState(m.state, MATCH_STATES.PICKING); - const participants = await db.query.matchParticipant.findMany({ - where: eq(matchParticipant.matchId, matchId) - }); - const totalGames = await db.query.matchGame.findMany({ - where: eq(matchGame.matchId, matchId) - }); - const expectedPicker = getExpectedPicker(participants, totalGames.length); - if (expectedPicker.id !== participantId) { - throw new Error("Not your turn to pick"); - } - const alreadyPlayed = totalGames.some((g) => g.mappoolSlotId === mappoolSlotId); - if (alreadyPlayed) { - throw new Error("This map has already been played"); - } - const [game] = await db.insert(matchGame).values({ - matchId, - gameNumber: totalGames.length + 1, - mappoolSlotId, - pickedByParticipantId: participantId, - state: GAME_STATES.PLAYING, - startedAt: /* @__PURE__ */ new Date() - }).returning(); - await db.update(match).set({ state: MATCH_STATES.PLAYING }).where(eq(match.id, matchId)); - return game; -} -async function submitGameScores(matchGameId, scores) { - const game = await db.query.matchGame.findFirst({ - where: eq(matchGame.id, matchGameId) - }); - if (!game) throw new Error("Game not found"); - if (game.state !== GAME_STATES.PLAYING) throw new Error(`Game is ${game.state}, not PLAYING`); - for (const s of scores) { - await db.insert(matchGameScore).values({ - matchGameId, - playerId: s.playerId, - score: s.score, - accuracy: s.accuracy ?? 0, - maxCombo: s.maxCombo ?? 0, - count300: s.count300 ?? 0, - count100: s.count100 ?? 0, - count50: s.count50 ?? 0, - countMiss: s.countMiss ?? 0, - mods: s.mods ?? [], - passed: s.passed ?? true - }); - } - const allScores = await db.query.matchGameScore.findMany({ - where: eq(matchGameScore.matchGameId, matchGameId), - with: { player: true } - }); - const participantScores = /* @__PURE__ */ new Map(); - for (const s of allScores) { - const pid = s.player.participantId; - participantScores.set(pid, (participantScores.get(pid) ?? 0) + s.score); - } - let winnerId = null; - let highScore = -1; - for (const [pid, total] of participantScores) { - if (total > highScore) { - highScore = total; - winnerId = pid; - } - } - await db.update(matchGame).set({ - state: GAME_STATES.FINISHED, - winnerParticipantId: winnerId, - finishedAt: /* @__PURE__ */ new Date() - }).where(eq(matchGame.id, matchGameId)); - if (winnerId) { - const participant = await db.query.matchParticipant.findFirst({ - where: eq(matchParticipant.id, winnerId) - }); - if (participant) { - await db.update(matchParticipant).set({ score: participant.score + 1 }).where(eq(matchParticipant.id, winnerId)); - } - } - const m = await getMatchOrThrow(game.matchId); - const config = m.config; - const winsNeeded = Math.ceil(config.bestOf / 2); - const participants = await db.query.matchParticipant.findMany({ - where: eq(matchParticipant.matchId, game.matchId) - }); - const matchWinner = participants.find((p) => p.score >= winsNeeded); - if (matchWinner) { - await db.update(match).set({ - state: MATCH_STATES.FINISHED, - winnerId: matchWinner.teamId, - finishedAt: /* @__PURE__ */ new Date() - }).where(eq(match.id, game.matchId)); - await updateElo(participants, matchWinner.id); - } else { - await db.update(match).set({ state: MATCH_STATES.PICKING }).where(eq(match.id, game.matchId)); - } - return getMatchFull(game.matchId); -} -async function updateElo(participants, winnerId) { - for (const p of participants) { - const players = await db.query.matchParticipantPlayer.findMany({ - where: eq(matchParticipantPlayer.participantId, p.id) - }); - const isWinner = p.id === winnerId; - for (const player of players) { - let rating = await db.query.playerRating.findFirst({ - where: eq(playerRating.userId, player.userId) - }); - if (!rating) { - [rating] = await db.insert(playerRating).values({ userId: player.userId, elo: 1e3 }).returning(); - } - const K = 32; - const expected = 0.5; - const actual = isWinner ? 1 : 0; - const newElo = Math.round(rating.elo + K * (actual - expected)); - await db.update(playerRating).set({ - elo: newElo, - wins: isWinner ? rating.wins + 1 : rating.wins, - losses: isWinner ? rating.losses : rating.losses + 1, - updatedAt: /* @__PURE__ */ new Date() - }).where(eq(playerRating.userId, player.userId)); - } - } -} -async function cancelMatch(matchId) { - await db.update(match).set({ - state: MATCH_STATES.CANCELLED, - finishedAt: /* @__PURE__ */ new Date() - }).where(eq(match.id, matchId)); - return getMatchFull(matchId); -} -function getExpectedPicker(participants, gameCount) { - const sorted = [...participants].sort((a, b) => (a.pickOrder ?? 99) - (b.pickOrder ?? 99)); - const pickerIndex = gameCount % sorted.length; - return sorted[pickerIndex]; -} -async function getMatchFull(matchId) { - const m = await db.query.match.findFirst({ - where: eq(match.id, matchId), - with: { - mappool: { - with: { slots: true } - }, - participants: { - with: { - team: true, - players: true - } - }, - games: { - with: { - slot: true, - scores: { - with: { player: true } - } - }, - orderBy: (g, { asc: asc2 }) => [asc2(g.gameNumber)] - } - } - }); - if (!m) throw new Error("Match not found"); - return m; -} -async function getMatchOrThrow(matchId) { - const m = await db.query.match.findFirst({ - where: eq(match.id, matchId) - }); - if (!m) throw new Error("Match not found"); - return m; -} -function assertState(current, expected) { - if (current !== expected) { - throw new Error(`Match is ${current}, expected ${expected}`); - } -} -export { - MATCH_STATES as M, - cancelMatch as a, - moveToRolling as b, - createMatch as c, - submitGameScores as d, - getQueueStatus as e, - getMatchFull as g, - joinQueue as j, - leaveQueue as l, - moveToLobby as m, - pickMap as p, - submitRoll as s -}; diff --git a/.svelte-kit/output/server/chunks/environment.js b/.svelte-kit/output/server/chunks/environment.js deleted file mode 100644 index d81356b..0000000 --- a/.svelte-kit/output/server/chunks/environment.js +++ /dev/null @@ -1,14 +0,0 @@ -let building = false; -let prerendering = false; -function set_building() { - building = true; -} -function set_prerendering() { - prerendering = true; -} -export { - set_prerendering as a, - building as b, - prerendering as p, - set_building as s -}; diff --git a/.svelte-kit/output/server/chunks/exports.js b/.svelte-kit/output/server/chunks/exports.js deleted file mode 100644 index 441ec91..0000000 --- a/.svelte-kit/output/server/chunks/exports.js +++ /dev/null @@ -1,70 +0,0 @@ -function validator(expected) { - function validate(module, file) { - if (!module) return; - for (const key in module) { - if (key[0] === "_" || expected.has(key)) continue; - const values = [...expected.values()]; - const hint = hint_for_supported_files(key, file?.slice(file.lastIndexOf("."))) ?? `valid exports are ${values.join(", ")}, or anything with a '_' prefix`; - throw new Error(`Invalid export '${key}'${file ? ` in ${file}` : ""} (${hint})`); - } - } - return validate; -} -function hint_for_supported_files(key, ext = ".js") { - const supported_files = []; - if (valid_layout_exports.has(key)) { - supported_files.push(`+layout${ext}`); - } - if (valid_page_exports.has(key)) { - supported_files.push(`+page${ext}`); - } - if (valid_layout_server_exports.has(key)) { - supported_files.push(`+layout.server${ext}`); - } - if (valid_page_server_exports.has(key)) { - supported_files.push(`+page.server${ext}`); - } - if (valid_server_exports.has(key)) { - supported_files.push(`+server${ext}`); - } - if (supported_files.length > 0) { - return `'${key}' is a valid export in ${supported_files.slice(0, -1).join(", ")}${supported_files.length > 1 ? " or " : ""}${supported_files.at(-1)}`; - } -} -const valid_layout_exports = /* @__PURE__ */ new Set([ - "load", - "prerender", - "csr", - "ssr", - "trailingSlash", - "config" -]); -const valid_page_exports = /* @__PURE__ */ new Set([...valid_layout_exports, "entries"]); -const valid_layout_server_exports = /* @__PURE__ */ new Set([...valid_layout_exports]); -const valid_page_server_exports = /* @__PURE__ */ new Set([...valid_layout_server_exports, "actions", "entries"]); -const valid_server_exports = /* @__PURE__ */ new Set([ - "GET", - "POST", - "PATCH", - "PUT", - "DELETE", - "OPTIONS", - "HEAD", - "fallback", - "prerender", - "trailingSlash", - "config", - "entries" -]); -const validate_layout_exports = validator(valid_layout_exports); -const validate_page_exports = validator(valid_page_exports); -const validate_layout_server_exports = validator(valid_layout_server_exports); -const validate_page_server_exports = validator(valid_page_server_exports); -const validate_server_exports = validator(valid_server_exports); -export { - validate_layout_exports as a, - validate_page_server_exports as b, - validate_page_exports as c, - validate_server_exports as d, - validate_layout_server_exports as v -}; diff --git a/.svelte-kit/output/server/chunks/false.js b/.svelte-kit/output/server/chunks/false.js deleted file mode 100644 index f3effd6..0000000 --- a/.svelte-kit/output/server/chunks/false.js +++ /dev/null @@ -1,4 +0,0 @@ -const DEV = false; -export { - DEV as D -}; diff --git a/.svelte-kit/output/server/chunks/index.js b/.svelte-kit/output/server/chunks/index.js deleted file mode 100644 index 14b637b..0000000 --- a/.svelte-kit/output/server/chunks/index.js +++ /dev/null @@ -1,60 +0,0 @@ -import { n as noop } from "./index3.js"; -import { s as safe_not_equal } from "./root.js"; -import "clsx"; -const subscriber_queue = []; -function readable(value, start) { - return { - subscribe: writable(value, start).subscribe - }; -} -function writable(value, start = noop) { - let stop = null; - const subscribers = /* @__PURE__ */ new Set(); - function set(new_value) { - if (safe_not_equal(value, new_value)) { - value = new_value; - if (stop) { - const run_queue = !subscriber_queue.length; - for (const subscriber of subscribers) { - subscriber[1](); - subscriber_queue.push(subscriber, value); - } - if (run_queue) { - for (let i = 0; i < subscriber_queue.length; i += 2) { - subscriber_queue[i][0](subscriber_queue[i + 1]); - } - subscriber_queue.length = 0; - } - } - } - } - function update(fn) { - set(fn( - /** @type {T} */ - value - )); - } - function subscribe(run, invalidate = noop) { - const subscriber = [run, invalidate]; - subscribers.add(subscriber); - if (subscribers.size === 1) { - stop = start(set, update) || noop; - } - run( - /** @type {T} */ - value - ); - return () => { - subscribers.delete(subscriber); - if (subscribers.size === 0 && stop) { - stop(); - stop = null; - } - }; - } - return { set, update, subscribe }; -} -export { - readable as r, - writable as w -}; diff --git a/.svelte-kit/output/server/chunks/index2.js b/.svelte-kit/output/server/chunks/index2.js deleted file mode 100644 index 2c507a6..0000000 --- a/.svelte-kit/output/server/chunks/index2.js +++ /dev/null @@ -1,302 +0,0 @@ -import { drizzle } from "drizzle-orm/postgres-js"; -import postgres from "postgres"; -import { pgTable, timestamp, text, boolean, index, uuid, real, integer, jsonb, uniqueIndex } from "drizzle-orm/pg-core"; -import { relations } from "drizzle-orm"; -import { b as private_env } from "./shared-server.js"; -const user = pgTable("user", { - id: text("id").primaryKey(), - name: text("name").notNull(), - email: text("email").notNull().unique(), - emailVerified: boolean("email_verified").default(false).notNull(), - image: text("image"), - // ── Staff role: 'player' | 'referee' | 'admin' ── - role: text("role").default("player").notNull(), - createdAt: timestamp("created_at").defaultNow().notNull(), - updatedAt: timestamp("updated_at").defaultNow().$onUpdate(() => /* @__PURE__ */ new Date()).notNull() -}); -const session = pgTable( - "session", - { - id: text("id").primaryKey(), - expiresAt: timestamp("expires_at").notNull(), - token: text("token").notNull().unique(), - createdAt: timestamp("created_at").defaultNow().notNull(), - updatedAt: timestamp("updated_at").$onUpdate(() => /* @__PURE__ */ new Date()).notNull(), - ipAddress: text("ip_address"), - userAgent: text("user_agent"), - userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }) - }, - (table) => [index("session_userId_idx").on(table.userId)] -); -const account = pgTable( - "account", - { - id: text("id").primaryKey(), - accountId: text("account_id").notNull(), - providerId: text("provider_id").notNull(), - userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }), - accessToken: text("access_token"), - refreshToken: text("refresh_token"), - idToken: text("id_token"), - accessTokenExpiresAt: timestamp("access_token_expires_at"), - refreshTokenExpiresAt: timestamp("refresh_token_expires_at"), - scope: text("scope"), - password: text("password"), - createdAt: timestamp("created_at").defaultNow().notNull(), - updatedAt: timestamp("updated_at").$onUpdate(() => /* @__PURE__ */ new Date()).notNull() - }, - (table) => [index("account_userId_idx").on(table.userId)] -); -const verification = pgTable( - "verification", - { - id: text("id").primaryKey(), - identifier: text("identifier").notNull(), - value: text("value").notNull(), - expiresAt: timestamp("expires_at").notNull(), - createdAt: timestamp("created_at").defaultNow().notNull(), - updatedAt: timestamp("updated_at").defaultNow().$onUpdate(() => /* @__PURE__ */ new Date()).notNull() - }, - (table) => [index("verification_identifier_idx").on(table.identifier)] -); -const userRelations = relations(user, ({ many }) => ({ - sessions: many(session), - accounts: many(account) -})); -const sessionRelations = relations(session, ({ one }) => ({ - user: one(user, { - fields: [session.userId], - references: [user.id] - }) -})); -const accountRelations = relations(account, ({ one }) => ({ - user: one(user, { - fields: [account.userId], - references: [user.id] - }) -})); -const team = pgTable("team", { - id: uuid("id").primaryKey().defaultRandom(), - name: text("name").notNull(), - isPersonal: boolean("is_personal").default(false).notNull(), - ownerId: text("owner_id"), - avatarUrl: text("avatar_url"), - createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull() -}); -const teamMember = pgTable("team_member", { - id: uuid("id").primaryKey().defaultRandom(), - teamId: uuid("team_id").notNull().references(() => team.id, { onDelete: "cascade" }), - userId: text("user_id").notNull(), - role: text("role").default("member"), - joinedAt: timestamp("joined_at", { withTimezone: true }).defaultNow() -}); -const mappool = pgTable("mappool", { - id: uuid("id").primaryKey().defaultRandom(), - name: text("name").notNull(), - createdBy: text("created_by"), - createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull() -}); -const mappoolSlot = pgTable("mappool_slot", { - id: uuid("id").primaryKey().defaultRandom(), - mappoolId: uuid("mappool_id").notNull().references(() => mappool.id, { onDelete: "cascade" }), - category: text("category").notNull(), - orderInCategory: integer("order_in_category").notNull(), - beatmapId: text("beatmap_id").notNull(), - starRating: real("star_rating"), - mods: text("mods").array().default([]).notNull() -}); -const match = pgTable( - "match", - { - id: uuid("id").primaryKey().defaultRandom(), - name: text("name"), - state: text("state").default("CREATED").notNull(), - config: jsonb("config").notNull(), - mappoolId: uuid("mappool_id").references(() => mappool.id), - osuLobbyId: integer("osu_lobby_id"), - scheduledAt: timestamp("scheduled_at", { withTimezone: true }), - startedAt: timestamp("started_at", { withTimezone: true }), - finishedAt: timestamp("finished_at", { withTimezone: true }), - winnerId: uuid("winner_id").references(() => team.id), - createdBy: text("created_by"), - createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull() - }, - (t) => [index("idx_match_state").on(t.state)] -); -const matchParticipant = pgTable( - "match_participant", - { - id: uuid("id").primaryKey().defaultRandom(), - matchId: uuid("match_id").notNull().references(() => match.id, { onDelete: "cascade" }), - teamId: uuid("team_id").notNull().references(() => team.id), - slot: integer("slot").notNull(), - score: integer("score").default(0).notNull(), - rollValue: integer("roll_value"), - pickOrder: integer("pick_order") - }, - (t) => [ - index("idx_mp_match_team").on(t.matchId, t.teamId), - uniqueIndex("idx_mp_match_slot").on(t.matchId, t.slot), - index("idx_mp_match").on(t.matchId) - ] -); -const matchParticipantPlayer = pgTable( - "match_participant_player", - { - id: uuid("id").primaryKey().defaultRandom(), - participantId: uuid("participant_id").notNull().references(() => matchParticipant.id, { onDelete: "cascade" }), - userId: text("user_id").notNull() - }, - (t) => [ - uniqueIndex("idx_mpp_participant_user").on(t.participantId, t.userId), - index("idx_mpp_participant").on(t.participantId) - ] -); -const matchGame = pgTable( - "match_game", - { - id: uuid("id").primaryKey().defaultRandom(), - matchId: uuid("match_id").notNull().references(() => match.id, { onDelete: "cascade" }), - gameNumber: integer("game_number").notNull(), - mappoolSlotId: uuid("mappool_slot_id").notNull().references(() => mappoolSlot.id), - pickedByParticipantId: uuid("picked_by_participant_id").references(() => matchParticipant.id), - winnerParticipantId: uuid("winner_participant_id").references(() => matchParticipant.id), - state: text("state").default("PENDING").notNull(), - startedAt: timestamp("started_at", { withTimezone: true }), - finishedAt: timestamp("finished_at", { withTimezone: true }) - }, - (t) => [index("idx_match_game_match").on(t.matchId)] -); -const matchGameScore = pgTable( - "match_game_score", - { - id: uuid("id").primaryKey().defaultRandom(), - matchGameId: uuid("match_game_id").notNull().references(() => matchGame.id, { onDelete: "cascade" }), - playerId: uuid("player_id").notNull().references(() => matchParticipantPlayer.id), - score: integer("score").default(0).notNull(), - accuracy: real("accuracy").default(0).notNull(), - maxCombo: integer("max_combo").default(0).notNull(), - count300: integer("count_300").default(0).notNull(), - count100: integer("count_100").default(0).notNull(), - count50: integer("count_50").default(0).notNull(), - countMiss: integer("count_miss").default(0).notNull(), - mods: text("mods").array().default([]).notNull(), - passed: boolean("passed").default(false).notNull() - }, - (t) => [index("idx_mgs_game").on(t.matchGameId)] -); -const matchQueue = pgTable( - "match_queue", - { - id: uuid("id").primaryKey().defaultRandom(), - userId: text("user_id").notNull(), - teamId: uuid("team_id").notNull().references(() => team.id), - elo: integer("elo").default(1e3).notNull(), - joinedAt: timestamp("joined_at", { withTimezone: true }).defaultNow().notNull() - }, - (t) => [ - uniqueIndex("idx_queue_user").on(t.userId), - index("idx_queue_elo").on(t.elo) - ] -); -const playerRating = pgTable("player_rating", { - id: uuid("id").primaryKey().defaultRandom(), - userId: text("user_id").notNull().unique(), - elo: integer("elo").default(1e3).notNull(), - wins: integer("wins").default(0).notNull(), - losses: integer("losses").default(0).notNull(), - updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull() -}); -const teamRelations = relations(team, ({ many }) => ({ - members: many(teamMember) -})); -const teamMemberRelations = relations(teamMember, ({ one }) => ({ - team: one(team, { fields: [teamMember.teamId], references: [team.id] }) -})); -const mappoolRelations = relations(mappool, ({ many }) => ({ - slots: many(mappoolSlot) -})); -const mappoolSlotRelations = relations(mappoolSlot, ({ one }) => ({ - mappool: one(mappool, { fields: [mappoolSlot.mappoolId], references: [mappool.id] }) -})); -const matchRelations = relations(match, ({ one, many }) => ({ - mappool: one(mappool, { fields: [match.mappoolId], references: [mappool.id] }), - participants: many(matchParticipant), - games: many(matchGame) -})); -const matchParticipantRelations = relations(matchParticipant, ({ one, many }) => ({ - match: one(match, { fields: [matchParticipant.matchId], references: [match.id] }), - team: one(team, { fields: [matchParticipant.teamId], references: [team.id] }), - players: many(matchParticipantPlayer) -})); -const matchParticipantPlayerRelations = relations(matchParticipantPlayer, ({ one }) => ({ - participant: one(matchParticipant, { - fields: [matchParticipantPlayer.participantId], - references: [matchParticipant.id] - }) -})); -const matchGameRelations = relations(matchGame, ({ one, many }) => ({ - match: one(match, { fields: [matchGame.matchId], references: [match.id] }), - slot: one(mappoolSlot, { fields: [matchGame.mappoolSlotId], references: [mappoolSlot.id] }), - scores: many(matchGameScore) -})); -const matchGameScoreRelations = relations(matchGameScore, ({ one }) => ({ - game: one(matchGame, { fields: [matchGameScore.matchGameId], references: [matchGame.id] }), - player: one(matchParticipantPlayer, { - fields: [matchGameScore.playerId], - references: [matchParticipantPlayer.id] - }) -})); -const matchQueueRelations = relations(matchQueue, ({ one }) => ({ - team: one(team, { fields: [matchQueue.teamId], references: [team.id] }) -})); -const schema = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({ - __proto__: null, - account, - accountRelations, - mappool, - mappoolRelations, - mappoolSlot, - mappoolSlotRelations, - match, - matchGame, - matchGameRelations, - matchGameScore, - matchGameScoreRelations, - matchParticipant, - matchParticipantPlayer, - matchParticipantPlayerRelations, - matchParticipantRelations, - matchQueue, - matchQueueRelations, - matchRelations, - playerRating, - session, - sessionRelations, - team, - teamMember, - teamMemberRelations, - teamRelations, - user, - userRelations, - verification -}, Symbol.toStringTag, { value: "Module" })); -if (!private_env.DATABASE_URL) throw new Error("DATABASE_URL is not set"); -const client = postgres(private_env.DATABASE_URL); -const db = drizzle(client, { schema }); -export { - mappoolSlot as a, - match as b, - team as c, - db as d, - matchParticipant as e, - matchParticipantPlayer as f, - matchGame as g, - matchGameScore as h, - matchQueue as i, - account as j, - mappool as m, - playerRating as p, - teamMember as t, - user as u -}; diff --git a/.svelte-kit/output/server/chunks/index3.js b/.svelte-kit/output/server/chunks/index3.js deleted file mode 100644 index 20b173b..0000000 --- a/.svelte-kit/output/server/chunks/index3.js +++ /dev/null @@ -1,1249 +0,0 @@ -import { clsx as clsx$1 } from "clsx"; -import * as devalue from "devalue"; -var is_array = Array.isArray; -var index_of = Array.prototype.indexOf; -var includes = Array.prototype.includes; -var array_from = Array.from; -var define_property = Object.defineProperty; -var get_descriptor = Object.getOwnPropertyDescriptor; -var object_prototype = Object.prototype; -var array_prototype = Array.prototype; -var get_prototype_of = Object.getPrototypeOf; -var is_extensible = Object.isExtensible; -var has_own_property = Object.prototype.hasOwnProperty; -const noop = () => { -}; -function run_all(arr) { - for (var i = 0; i < arr.length; i++) { - arr[i](); - } -} -function deferred() { - var resolve; - var reject; - var promise = new Promise((res, rej) => { - resolve = res; - reject = rej; - }); - return { promise, resolve, reject }; -} -const DERIVED = 1 << 1; -const EFFECT = 1 << 2; -const RENDER_EFFECT = 1 << 3; -const MANAGED_EFFECT = 1 << 24; -const BLOCK_EFFECT = 1 << 4; -const BRANCH_EFFECT = 1 << 5; -const ROOT_EFFECT = 1 << 6; -const BOUNDARY_EFFECT = 1 << 7; -const CONNECTED = 1 << 9; -const CLEAN = 1 << 10; -const DIRTY = 1 << 11; -const MAYBE_DIRTY = 1 << 12; -const INERT = 1 << 13; -const DESTROYED = 1 << 14; -const REACTION_RAN = 1 << 15; -const EFFECT_TRANSPARENT = 1 << 16; -const EAGER_EFFECT = 1 << 17; -const HEAD_EFFECT = 1 << 18; -const EFFECT_PRESERVED = 1 << 19; -const USER_EFFECT = 1 << 20; -const WAS_MARKED = 1 << 16; -const REACTION_IS_UPDATING = 1 << 21; -const ASYNC = 1 << 22; -const ERROR_VALUE = 1 << 23; -const STATE_SYMBOL = /* @__PURE__ */ Symbol("$state"); -const LEGACY_PROPS = /* @__PURE__ */ Symbol("legacy props"); -const STALE_REACTION = new class StaleReactionError extends Error { - name = "StaleReactionError"; - message = "The reaction that called `getAbortSignal()` was re-run or destroyed"; -}(); -const COMMENT_NODE = 8; -function lifecycle_outside_component(name) { - { - throw new Error(`https://svelte.dev/e/lifecycle_outside_component`); - } -} -const HYDRATION_START = "["; -const HYDRATION_START_ELSE = "[!"; -const HYDRATION_START_FAILED = "[?"; -const HYDRATION_END = "]"; -const HYDRATION_ERROR = {}; -const ELEMENT_IS_NAMESPACED = 1; -const ELEMENT_PRESERVE_ATTRIBUTE_CASE = 1 << 1; -const ELEMENT_IS_INPUT = 1 << 2; -const UNINITIALIZED = /* @__PURE__ */ Symbol(); -const DOM_BOOLEAN_ATTRIBUTES = [ - "allowfullscreen", - "async", - "autofocus", - "autoplay", - "checked", - "controls", - "default", - "disabled", - "formnovalidate", - "indeterminate", - "inert", - "ismap", - "loop", - "multiple", - "muted", - "nomodule", - "novalidate", - "open", - "playsinline", - "readonly", - "required", - "reversed", - "seamless", - "selected", - "webkitdirectory", - "defer", - "disablepictureinpicture", - "disableremoteplayback" -]; -function is_boolean_attribute(name) { - return DOM_BOOLEAN_ATTRIBUTES.includes(name); -} -const PASSIVE_EVENTS = ["touchstart", "touchmove"]; -function is_passive_event(name) { - return PASSIVE_EVENTS.includes(name); -} -const ATTR_REGEX = /[&"<]/g; -const CONTENT_REGEX = /[&<]/g; -function escape_html(value, is_attr) { - const str = String(value ?? ""); - const pattern = is_attr ? ATTR_REGEX : CONTENT_REGEX; - pattern.lastIndex = 0; - let escaped = ""; - let last = 0; - while (pattern.test(str)) { - const i = pattern.lastIndex - 1; - const ch = str[i]; - escaped += str.substring(last, i) + (ch === "&" ? "&" : ch === '"' ? """ : "<"); - last = i + 1; - } - return escaped + str.substring(last); -} -const replacements = { - translate: /* @__PURE__ */ new Map([ - [true, "yes"], - [false, "no"] - ]) -}; -function attr(name, value, is_boolean = false) { - if (name === "hidden" && value !== "until-found") { - is_boolean = true; - } - if (value == null || !value && is_boolean) return ""; - const normalized = has_own_property.call(replacements, name) && replacements[name].get(value) || value; - const assignment = is_boolean ? `=""` : `="${escape_html(normalized, true)}"`; - return ` ${name}${assignment}`; -} -function clsx(value) { - if (typeof value === "object") { - return clsx$1(value); - } else { - return value ?? ""; - } -} -const whitespace = [..." \n\r\f \v\uFEFF"]; -function to_class(value, hash, directives) { - var classname = value == null ? "" : "" + value; - if (hash) { - classname = classname ? classname + " " + hash : hash; - } - if (directives) { - for (var key of Object.keys(directives)) { - if (directives[key]) { - classname = classname ? classname + " " + key : key; - } else if (classname.length) { - var len = key.length; - var a = 0; - while ((a = classname.indexOf(key, a)) >= 0) { - var b = a + len; - if ((a === 0 || whitespace.includes(classname[a - 1])) && (b === classname.length || whitespace.includes(classname[b]))) { - classname = (a === 0 ? "" : classname.substring(0, a)) + classname.substring(b + 1); - } else { - a = b; - } - } - } - } - } - return classname === "" ? null : classname; -} -function append_styles(styles, important = false) { - var separator = important ? " !important;" : ";"; - var css = ""; - for (var key of Object.keys(styles)) { - var value = styles[key]; - if (value != null && value !== "") { - css += " " + key + ": " + value + separator; - } - } - return css; -} -function to_css_name(name) { - if (name[0] !== "-" || name[1] !== "-") { - return name.toLowerCase(); - } - return name; -} -function to_style(value, styles) { - if (styles) { - var new_style = ""; - var normal_styles; - var important_styles; - if (Array.isArray(styles)) { - normal_styles = styles[0]; - important_styles = styles[1]; - } else { - normal_styles = styles; - } - if (value) { - value = String(value).replaceAll(/\s*\/\*.*?\*\/\s*/g, "").trim(); - var in_str = false; - var in_apo = 0; - var in_comment = false; - var reserved_names = []; - if (normal_styles) { - reserved_names.push(...Object.keys(normal_styles).map(to_css_name)); - } - if (important_styles) { - reserved_names.push(...Object.keys(important_styles).map(to_css_name)); - } - var start_index = 0; - var name_index = -1; - const len = value.length; - for (var i = 0; i < len; i++) { - var c = value[i]; - if (in_comment) { - if (c === "/" && value[i - 1] === "*") { - in_comment = false; - } - } else if (in_str) { - if (in_str === c) { - in_str = false; - } - } else if (c === "/" && value[i + 1] === "*") { - in_comment = true; - } else if (c === '"' || c === "'") { - in_str = c; - } else if (c === "(") { - in_apo++; - } else if (c === ")") { - in_apo--; - } - if (!in_comment && in_str === false && in_apo === 0) { - if (c === ":" && name_index === -1) { - name_index = i; - } else if (c === ";" || i === len - 1) { - if (name_index !== -1) { - var name = to_css_name(value.substring(start_index, name_index).trim()); - if (!reserved_names.includes(name)) { - if (c !== ";") { - i++; - } - var property = value.substring(start_index, i).trim(); - new_style += " " + property + ";"; - } - } - start_index = i + 1; - name_index = -1; - } - } - } - } - if (normal_styles) { - new_style += append_styles(normal_styles); - } - if (important_styles) { - new_style += append_styles(important_styles, true); - } - new_style = new_style.trim(); - return new_style === "" ? null : new_style; - } - return value == null ? null : String(value); -} -const BLOCK_OPEN = ``; -const BLOCK_CLOSE = ``; -let controller = null; -function abort() { - controller?.abort(STALE_REACTION); - controller = null; -} -function await_invalid() { - const error = new Error(`await_invalid -Encountered asynchronous work while rendering synchronously. -https://svelte.dev/e/await_invalid`); - error.name = "Svelte error"; - throw error; -} -function invalid_csp() { - const error = new Error(`invalid_csp -\`csp.nonce\` was set while \`csp.hash\` was \`true\`. These options cannot be used simultaneously. -https://svelte.dev/e/invalid_csp`); - error.name = "Svelte error"; - throw error; -} -function server_context_required() { - const error = new Error(`server_context_required -Could not resolve \`render\` context. -https://svelte.dev/e/server_context_required`); - error.name = "Svelte error"; - throw error; -} -var ssr_context = null; -function set_ssr_context(v) { - ssr_context = v; -} -function getContext(key) { - const context_map = get_or_init_context_map(); - const result = ( - /** @type {T} */ - context_map.get(key) - ); - return result; -} -function setContext(key, context) { - get_or_init_context_map().set(key, context); - return context; -} -function get_or_init_context_map(name) { - if (ssr_context === null) { - lifecycle_outside_component(); - } - return ssr_context.c ??= new Map(get_parent_context(ssr_context) || void 0); -} -function push(fn) { - ssr_context = { p: ssr_context, c: null, r: null }; -} -function pop() { - ssr_context = /** @type {SSRContext} */ - ssr_context.p; -} -function get_parent_context(ssr_context2) { - let parent = ssr_context2.p; - while (parent !== null) { - const context_map = parent.c; - if (context_map !== null) { - return context_map; - } - parent = parent.p; - } - return null; -} -function unresolved_hydratable(key, stack) { - { - console.warn(`https://svelte.dev/e/unresolved_hydratable`); - } -} -function get_render_context() { - const store = als?.getStore(); - { - server_context_required(); - } - return store; -} -let als = null; -let text_encoder; -let crypto; -const obfuscated_import = (module_name) => import( - /* @vite-ignore */ - module_name -); -async function sha256(data) { - text_encoder ??= new TextEncoder(); - crypto ??= globalThis.crypto?.subtle?.digest ? globalThis.crypto : ( - // @ts-ignore - we don't install node types in the prod build - // don't use import('node:crypto') directly because static analysers will think we rely on node when we don't - (await obfuscated_import("node:crypto")).webcrypto - ); - const hash_buffer = await crypto.subtle.digest("SHA-256", text_encoder.encode(data)); - return base64_encode(hash_buffer); -} -function base64_encode(bytes) { - if (globalThis.Buffer) { - return globalThis.Buffer.from(bytes).toString("base64"); - } - let binary = ""; - for (let i = 0; i < bytes.length; i++) { - binary += String.fromCharCode(bytes[i]); - } - return btoa(binary); -} -class Renderer { - /** - * The contents of the renderer. - * @type {RendererItem[]} - */ - #out = []; - /** - * Any `onDestroy` callbacks registered during execution of this renderer. - * @type {(() => void)[] | undefined} - */ - #on_destroy = void 0; - /** - * Whether this renderer is a component body. - * @type {boolean} - */ - #is_component_body = false; - /** - * If set, this renderer is an error boundary. When async collection - * of the children fails, the failed snippet is rendered instead. - * @type {{ - * failed: (renderer: Renderer, error: unknown, reset: () => void) => void; - * transformError: (error: unknown) => unknown; - * context: SSRContext | null; - * } | null} - */ - #boundary = null; - /** - * The type of string content that this renderer is accumulating. - * @type {RendererType} - */ - type; - /** @type {Renderer | undefined} */ - #parent; - /** - * Asynchronous work associated with this renderer - * @type {Promise | undefined} - */ - promise = void 0; - /** - * State which is associated with the content tree as a whole. - * It will be re-exposed, uncopied, on all children. - * @type {SSRState} - * @readonly - */ - global; - /** - * State that is local to the branch it is declared in. - * It will be shallow-copied to all children. - * - * @type {{ select_value: string | undefined }} - */ - local; - /** - * @param {SSRState} global - * @param {Renderer | undefined} [parent] - */ - constructor(global, parent) { - this.#parent = parent; - this.global = global; - this.local = parent ? { ...parent.local } : { select_value: void 0 }; - this.type = parent ? parent.type : "body"; - } - /** - * @param {(renderer: Renderer) => void} fn - */ - head(fn) { - const head = new Renderer(this.global, this); - head.type = "head"; - this.#out.push(head); - head.child(fn); - } - /** - * @param {Array>} blockers - * @param {(renderer: Renderer) => void} fn - */ - async_block(blockers, fn) { - this.#out.push(BLOCK_OPEN); - this.async(blockers, fn); - this.#out.push(BLOCK_CLOSE); - } - /** - * @param {Array>} blockers - * @param {(renderer: Renderer) => void} fn - */ - async(blockers, fn) { - let callback = fn; - if (blockers.length > 0) { - const context = ssr_context; - callback = (renderer) => { - return Promise.all(blockers).then(() => { - const previous_context = ssr_context; - try { - set_ssr_context(context); - return fn(renderer); - } finally { - set_ssr_context(previous_context); - } - }); - }; - } - this.child(callback); - } - /** - * @param {Array<() => void>} thunks - */ - run(thunks) { - const context = ssr_context; - let promise = Promise.resolve(thunks[0]()); - const promises = [promise]; - for (const fn of thunks.slice(1)) { - promise = promise.then(() => { - const previous_context = ssr_context; - set_ssr_context(context); - try { - return fn(); - } finally { - set_ssr_context(previous_context); - } - }); - promises.push(promise); - } - promise.catch(noop); - this.promise = promise; - return promises; - } - /** - * @param {(renderer: Renderer) => MaybePromise} fn - */ - child_block(fn) { - this.#out.push(BLOCK_OPEN); - this.child(fn); - this.#out.push(BLOCK_CLOSE); - } - /** - * Create a child renderer. The child renderer inherits the state from the parent, - * but has its own content. - * @param {(renderer: Renderer) => MaybePromise} fn - */ - child(fn) { - const child = new Renderer(this.global, this); - this.#out.push(child); - const parent = ssr_context; - set_ssr_context({ - ...ssr_context, - p: parent, - c: null, - r: child - }); - const result = fn(child); - set_ssr_context(parent); - if (result instanceof Promise) { - result.catch(noop); - result.finally(() => set_ssr_context(null)).catch(noop); - if (child.global.mode === "sync") { - await_invalid(); - } - child.promise = result; - } - return child; - } - /** - * Render children inside an error boundary. If the children throw and the API-level - * `transformError` transform handles the error (doesn't re-throw), the `failed` snippet is - * rendered instead. Otherwise the error propagates. - * - * @param {{ failed?: (renderer: Renderer, error: unknown, reset: () => void) => void }} props - * @param {(renderer: Renderer) => MaybePromise} children_fn - */ - boundary(props, children_fn) { - const child = new Renderer(this.global, this); - this.#out.push(child); - const parent_context = ssr_context; - if (props.failed) { - child.#boundary = { - failed: props.failed, - transformError: this.global.transformError, - context: parent_context - }; - } - set_ssr_context({ - ...ssr_context, - p: parent_context, - c: null, - r: child - }); - try { - const result = children_fn(child); - set_ssr_context(parent_context); - if (result instanceof Promise) { - if (child.global.mode === "sync") { - await_invalid(); - } - result.catch(noop); - child.promise = result; - } - } catch (error) { - set_ssr_context(parent_context); - const failed_snippet = props.failed; - if (!failed_snippet) throw error; - const result = this.global.transformError(error); - child.#out.length = 0; - child.#boundary = null; - if (result instanceof Promise) { - if (this.global.mode === "sync") { - await_invalid(); - } - child.promise = /** @type {Promise} */ - result.then((transformed) => { - set_ssr_context(parent_context); - child.#out.push(Renderer.#serialize_failed_boundary(transformed)); - failed_snippet(child, transformed, noop); - child.#out.push(BLOCK_CLOSE); - }); - child.promise.catch(noop); - } else { - child.#out.push(Renderer.#serialize_failed_boundary(result)); - failed_snippet(child, result, noop); - child.#out.push(BLOCK_CLOSE); - } - } - } - /** - * Create a component renderer. The component renderer inherits the state from the parent, - * but has its own content. It is treated as an ordering boundary for ondestroy callbacks. - * @param {(renderer: Renderer) => MaybePromise} fn - * @param {Function} [component_fn] - * @returns {void} - */ - component(fn, component_fn) { - push(); - const child = this.child(fn); - child.#is_component_body = true; - pop(); - } - /** - * @param {Record} attrs - * @param {(renderer: Renderer) => void} fn - * @param {string | undefined} [css_hash] - * @param {Record | undefined} [classes] - * @param {Record | undefined} [styles] - * @param {number | undefined} [flags] - * @param {boolean | undefined} [is_rich] - * @returns {void} - */ - select(attrs, fn, css_hash, classes, styles, flags, is_rich) { - const { value, ...select_attrs } = attrs; - this.push(``); - this.child((renderer) => { - renderer.local.select_value = value; - fn(renderer); - }); - this.push(`${is_rich ? "" : ""}`); - } - /** - * @param {Record} attrs - * @param {string | number | boolean | ((renderer: Renderer) => void)} body - * @param {string | undefined} [css_hash] - * @param {Record | undefined} [classes] - * @param {Record | undefined} [styles] - * @param {number | undefined} [flags] - * @param {boolean | undefined} [is_rich] - */ - option(attrs, body, css_hash, classes, styles, flags, is_rich) { - this.#out.push(` { - if (has_own_property.call(attrs, "value")) { - value = attrs.value; - } - if (value === this.local.select_value) { - renderer.#out.push(' selected=""'); - } - renderer.#out.push(`>${body2}${is_rich ? "" : ""}`); - if (head) { - renderer.head((child) => child.push(head)); - } - }; - if (typeof body === "function") { - this.child((renderer) => { - const r = new Renderer(this.global, this); - body(r); - if (this.global.mode === "async") { - return r.#collect_content_async().then((content) => { - close(renderer, content.body.replaceAll("", ""), content); - }); - } else { - const content = r.#collect_content(); - close(renderer, content.body.replaceAll("", ""), content); - } - }); - } else { - close(this, body, { body: escape_html(body) }); - } - } - /** - * @param {(renderer: Renderer) => void} fn - */ - title(fn) { - const path = this.get_path(); - const close = (head) => { - this.global.set_title(head, path); - }; - this.child((renderer) => { - const r = new Renderer(renderer.global, renderer); - fn(r); - if (renderer.global.mode === "async") { - return r.#collect_content_async().then((content) => { - close(content.head); - }); - } else { - const content = r.#collect_content(); - close(content.head); - } - }); - } - /** - * @param {string | (() => Promise)} content - */ - push(content) { - if (typeof content === "function") { - this.child(async (renderer) => renderer.push(await content())); - } else { - this.#out.push(content); - } - } - /** - * @param {() => void} fn - */ - on_destroy(fn) { - (this.#on_destroy ??= []).push(fn); - } - /** - * @returns {number[]} - */ - get_path() { - return this.#parent ? [...this.#parent.get_path(), this.#parent.#out.indexOf(this)] : []; - } - /** - * @deprecated this is needed for legacy component bindings - */ - copy() { - const copy = new Renderer(this.global, this.#parent); - copy.#out = this.#out.map((item) => item instanceof Renderer ? item.copy() : item); - copy.promise = this.promise; - return copy; - } - /** - * @param {Renderer} other - * @deprecated this is needed for legacy component bindings - */ - subsume(other) { - if (this.global.mode !== other.global.mode) { - throw new Error( - "invariant: A renderer cannot switch modes. If you're seeing this, there's a compiler bug. File an issue!" - ); - } - this.local = other.local; - this.#out = other.#out.map((item) => { - if (item instanceof Renderer) { - item.subsume(item); - } - return item; - }); - this.promise = other.promise; - this.type = other.type; - } - get length() { - return this.#out.length; - } - /** - * Creates the hydration comment that marks the start of a failed boundary. - * The error is JSON-serialized and embedded inside an HTML comment for the client - * to parse during hydration. The JSON is escaped to prevent `-->` or ``; - } - /** - * Only available on the server and when compiling with the `server` option. - * Takes a component and returns an object with `body` and `head` properties on it, which you can use to populate the HTML when server-rendering your app. - * @template {Record} Props - * @param {Component} component - * @param {{ props?: Omit; context?: Map; idPrefix?: string; csp?: Csp }} [options] - * @returns {RenderOutput} - */ - static render(component, options = {}) { - let sync; - const result = ( - /** @type {RenderOutput} */ - {} - ); - Object.defineProperties(result, { - html: { - get: () => { - return (sync ??= Renderer.#render(component, options)).body; - } - }, - head: { - get: () => { - return (sync ??= Renderer.#render(component, options)).head; - } - }, - body: { - get: () => { - return (sync ??= Renderer.#render(component, options)).body; - } - }, - hashes: { - value: { - script: "" - } - }, - then: { - value: ( - /** - * this is not type-safe, but honestly it's the best I can do right now, and it's a straightforward function. - * - * @template TResult1 - * @template [TResult2=never] - * @param { (value: SyncRenderOutput) => TResult1 } onfulfilled - * @param { (reason: unknown) => TResult2 } onrejected - */ - (onfulfilled, onrejected) => { - { - const result2 = sync ??= Renderer.#render(component, options); - const user_result = onfulfilled({ - head: result2.head, - body: result2.body, - html: result2.body, - hashes: { script: [] } - }); - return Promise.resolve(user_result); - } - } - ) - } - }); - return result; - } - /** - * Collect all of the `onDestroy` callbacks registered during rendering. In an async context, this is only safe to call - * after awaiting `collect_async`. - * - * Child renderers are "porous" and don't affect execution order, but component body renderers - * create ordering boundaries. Within a renderer, callbacks run in order until hitting a component boundary. - * @returns {Iterable<() => void>} - */ - *#collect_on_destroy() { - for (const component of this.#traverse_components()) { - yield* component.#collect_ondestroy(); - } - } - /** - * Performs a depth-first search of renderers, yielding the deepest components first, then additional components as we backtrack up the tree. - * @returns {Iterable} - */ - *#traverse_components() { - for (const child of this.#out) { - if (typeof child !== "string") { - yield* child.#traverse_components(); - } - } - if (this.#is_component_body) { - yield this; - } - } - /** - * @returns {Iterable<() => void>} - */ - *#collect_ondestroy() { - if (this.#on_destroy) { - for (const fn of this.#on_destroy) { - yield fn; - } - } - for (const child of this.#out) { - if (child instanceof Renderer && !child.#is_component_body) { - yield* child.#collect_ondestroy(); - } - } - } - /** - * Render a component. Throws if any of the children are performing asynchronous work. - * - * @template {Record} Props - * @param {Component} component - * @param {{ props?: Omit; context?: Map; idPrefix?: string }} options - * @returns {AccumulatedContent} - */ - static #render(component, options) { - var previous_context = ssr_context; - try { - const renderer = Renderer.#open_render("sync", component, options); - const content = renderer.#collect_content(); - return Renderer.#close_render(content, renderer); - } finally { - abort(); - set_ssr_context(previous_context); - } - } - /** - * Render a component. - * - * @template {Record} Props - * @param {Component} component - * @param {{ props?: Omit; context?: Map; idPrefix?: string; csp?: Csp }} options - * @returns {Promise} - */ - static async #render_async(component, options) { - const previous_context = ssr_context; - try { - const renderer = Renderer.#open_render("async", component, options); - const content = await renderer.#collect_content_async(); - const hydratables = await renderer.#collect_hydratables(); - if (hydratables !== null) { - content.head = hydratables + content.head; - } - return Renderer.#close_render(content, renderer); - } finally { - set_ssr_context(previous_context); - abort(); - } - } - /** - * Collect all of the code from the `out` array and return it as a string, or a promise resolving to a string. - * @param {AccumulatedContent} content - * @returns {AccumulatedContent} - */ - #collect_content(content = { head: "", body: "" }) { - for (const item of this.#out) { - if (typeof item === "string") { - content[this.type] += item; - } else if (item instanceof Renderer) { - item.#collect_content(content); - } - } - return content; - } - /** - * Collect all of the code from the `out` array and return it as a string. - * @param {AccumulatedContent} content - * @returns {Promise} - */ - async #collect_content_async(content = { head: "", body: "" }) { - await this.promise; - for (const item of this.#out) { - if (typeof item === "string") { - content[this.type] += item; - } else if (item instanceof Renderer) { - if (item.#boundary) { - const boundary_content = { head: "", body: "" }; - try { - await item.#collect_content_async(boundary_content); - content.head += boundary_content.head; - content.body += boundary_content.body; - } catch (error) { - const { context, failed, transformError } = item.#boundary; - set_ssr_context(context); - let transformed = await transformError(error); - const failed_renderer = new Renderer(item.global, item); - failed_renderer.type = item.type; - failed_renderer.#out.push(Renderer.#serialize_failed_boundary(transformed)); - failed(failed_renderer, transformed, noop); - failed_renderer.#out.push(BLOCK_CLOSE); - await failed_renderer.#collect_content_async(content); - } - } else { - await item.#collect_content_async(content); - } - } - } - return content; - } - async #collect_hydratables() { - const ctx = get_render_context().hydratable; - for (const [_, key] of ctx.unresolved_promises) { - unresolved_hydratable(key, ctx.lookup.get(key)?.stack ?? ""); - } - for (const comparison of ctx.comparisons) { - await comparison; - } - return await this.#hydratable_block(ctx); - } - /** - * @template {Record} Props - * @param {'sync' | 'async'} mode - * @param {import('svelte').Component} component - * @param {{ props?: Omit; context?: Map; idPrefix?: string; csp?: Csp; transformError?: (error: unknown) => unknown }} options - * @returns {Renderer} - */ - static #open_render(mode, component, options) { - var previous_context = ssr_context; - try { - const renderer = new Renderer( - new SSRState( - mode, - options.idPrefix ? options.idPrefix + "-" : "", - options.csp, - options.transformError - ) - ); - const context = { p: null, c: options.context ?? null, r: renderer }; - set_ssr_context(context); - renderer.push(BLOCK_OPEN); - component(renderer, options.props ?? {}); - renderer.push(BLOCK_CLOSE); - return renderer; - } finally { - set_ssr_context(previous_context); - } - } - /** - * @param {AccumulatedContent} content - * @param {Renderer} renderer - * @returns {AccumulatedContent & { hashes: { script: Sha256Source[] } }} - */ - static #close_render(content, renderer) { - for (const cleanup of renderer.#collect_on_destroy()) { - cleanup(); - } - let head = content.head + renderer.global.get_title(); - let body = content.body; - for (const { hash, code } of renderer.global.css) { - head += ``; - } - return { - head, - body, - hashes: { - script: renderer.global.csp.script_hashes - } - }; - } - /** - * @param {HydratableContext} ctx - */ - async #hydratable_block(ctx) { - if (ctx.lookup.size === 0) { - return null; - } - let entries = []; - let has_promises = false; - for (const [k, v] of ctx.lookup) { - if (v.promises) { - has_promises = true; - for (const p of v.promises) await p; - } - entries.push(`[${devalue.uneval(k)},${v.serialized}]`); - } - let prelude = `const h = (window.__svelte ??= {}).h ??= new Map();`; - if (has_promises) { - prelude = `const r = (v) => Promise.resolve(v); - ${prelude}`; - } - const body = ` - { - ${prelude} - - for (const [k, v] of [ - ${entries.join(",\n ")} - ]) { - h.set(k, v); - } - } - `; - let csp_attr = ""; - if (this.global.csp.nonce) { - csp_attr = ` nonce="${this.global.csp.nonce}"`; - } else if (this.global.csp.hash) { - const hash = await sha256(body); - this.global.csp.script_hashes.push(`sha256-${hash}`); - } - return ` - ${body}<\/script>`; - } -} -class SSRState { - /** @readonly @type {Csp & { script_hashes: Sha256Source[] }} */ - csp; - /** @readonly @type {'sync' | 'async'} */ - mode; - /** @readonly @type {() => string} */ - uid; - /** @readonly @type {Set<{ hash: string; code: string }>} */ - css = /* @__PURE__ */ new Set(); - /** - * `transformError` passed to `render`. Called when an error boundary catches an error. - * Throws by default if unset in `render`. - * @type {(error: unknown) => unknown} - */ - transformError; - /** @type {{ path: number[], value: string }} */ - #title = { path: [], value: "" }; - /** - * @param {'sync' | 'async'} mode - * @param {string} id_prefix - * @param {Csp} csp - * @param {((error: unknown) => unknown) | undefined} [transformError] - */ - constructor(mode, id_prefix = "", csp = { hash: false }, transformError) { - this.mode = mode; - this.csp = { ...csp, script_hashes: [] }; - this.transformError = transformError ?? ((error) => { - throw error; - }); - let uid = 1; - this.uid = () => `${id_prefix}s${uid++}`; - } - get_title() { - return this.#title.value; - } - /** - * Performs a depth-first (lexicographic) comparison using the path. Rejects sets - * from earlier than or equal to the current value. - * @param {string} value - * @param {number[]} path - */ - set_title(value, path) { - const current = this.#title.path; - let i = 0; - let l = Math.min(path.length, current.length); - while (i < l && path[i] === current[i]) i += 1; - if (path[i] === void 0) return; - if (current[i] === void 0 || path[i] > current[i]) { - this.#title.path = path; - this.#title.value = value; - } - } -} -const INVALID_ATTR_NAME_CHAR_REGEX = /[\s'">/=\u{FDD0}-\u{FDEF}\u{FFFE}\u{FFFF}\u{1FFFE}\u{1FFFF}\u{2FFFE}\u{2FFFF}\u{3FFFE}\u{3FFFF}\u{4FFFE}\u{4FFFF}\u{5FFFE}\u{5FFFF}\u{6FFFE}\u{6FFFF}\u{7FFFE}\u{7FFFF}\u{8FFFE}\u{8FFFF}\u{9FFFE}\u{9FFFF}\u{AFFFE}\u{AFFFF}\u{BFFFE}\u{BFFFF}\u{CFFFE}\u{CFFFF}\u{DFFFE}\u{DFFFF}\u{EFFFE}\u{EFFFF}\u{FFFFE}\u{FFFFF}\u{10FFFE}\u{10FFFF}]/u; -function render(component, options = {}) { - if (options.csp?.hash && options.csp.nonce) { - invalid_csp(); - } - return Renderer.render( - /** @type {Component} */ - component, - options - ); -} -function attributes(attrs, css_hash, classes, styles, flags = 0) { - if (styles) { - attrs.style = to_style(attrs.style, styles); - } - if (attrs.class) { - attrs.class = clsx(attrs.class); - } - if (css_hash || classes) { - attrs.class = to_class(attrs.class, css_hash, classes); - } - let attr_str = ""; - let name; - const is_html = (flags & ELEMENT_IS_NAMESPACED) === 0; - const lowercase = (flags & ELEMENT_PRESERVE_ATTRIBUTE_CASE) === 0; - const is_input = (flags & ELEMENT_IS_INPUT) !== 0; - for (name of Object.keys(attrs)) { - if (typeof attrs[name] === "function") continue; - if (name[0] === "$" && name[1] === "$") continue; - if (INVALID_ATTR_NAME_CHAR_REGEX.test(name)) continue; - var value = attrs[name]; - if (lowercase) { - name = name.toLowerCase(); - } - if (name.length > 2 && name.startsWith("on")) continue; - if (is_input) { - if (name === "defaultvalue" || name === "defaultchecked") { - name = name === "defaultvalue" ? "value" : "checked"; - if (attrs[name]) continue; - } - } - attr_str += attr(name, value, is_html && is_boolean_attribute(name)); - } - return attr_str; -} -function stringify(value) { - return typeof value === "string" ? value : value == null ? "" : value + ""; -} -function attr_class(value, hash, directives) { - var result = to_class(value, hash, directives); - return result ? ` class="${escape_html(result, true)}"` : ""; -} -function ensure_array_like(array_like_or_iterator) { - if (array_like_or_iterator) { - return array_like_or_iterator.length !== void 0 ? array_like_or_iterator : Array.from(array_like_or_iterator); - } - return []; -} -function once(get_value) { - let value = ( - /** @type {V} */ - UNINITIALIZED - ); - return () => { - if (value === UNINITIALIZED) { - value = get_value(); - } - return value; - }; -} -function derived(fn) { - const get_value = ssr_context === null ? fn : once(fn); - let updated_value; - return function(new_value) { - if (arguments.length === 0) { - return updated_value ?? get_value(); - } - updated_value = new_value; - return updated_value; - }; -} -export { - is_passive_event as $, - ASYNC as A, - BOUNDARY_EFFECT as B, - COMMENT_NODE as C, - DIRTY as D, - ERROR_VALUE as E, - EFFECT_TRANSPARENT as F, - EFFECT_PRESERVED as G, - HYDRATION_ERROR as H, - INERT as I, - EAGER_EFFECT as J, - STATE_SYMBOL as K, - object_prototype as L, - MAYBE_DIRTY as M, - array_prototype as N, - get_descriptor as O, - get_prototype_of as P, - is_array as Q, - REACTION_RAN as R, - STALE_REACTION as S, - is_extensible as T, - UNINITIALIZED as U, - USER_EFFECT as V, - WAS_MARKED as W, - REACTION_IS_UPDATING as X, - index_of as Y, - define_property as Z, - array_from as _, - ensure_array_like as a, - LEGACY_PROPS as a0, - render as a1, - setContext as a2, - attr as b, - attr_class as c, - derived as d, - escape_html as e, - HYDRATION_END as f, - getContext as g, - HYDRATION_START as h, - HYDRATION_START_ELSE as i, - EFFECT as j, - CONNECTED as k, - CLEAN as l, - DERIVED as m, - noop as n, - BLOCK_EFFECT as o, - deferred as p, - BRANCH_EFFECT as q, - run_all as r, - stringify as s, - ROOT_EFFECT as t, - RENDER_EFFECT as u, - MANAGED_EFFECT as v, - HEAD_EFFECT as w, - DESTROYED as x, - includes as y, - HYDRATION_START_FAILED as z -}; diff --git a/.svelte-kit/output/server/chunks/index4.js b/.svelte-kit/output/server/chunks/index4.js deleted file mode 100644 index 2ae44a6..0000000 --- a/.svelte-kit/output/server/chunks/index4.js +++ /dev/null @@ -1,47 +0,0 @@ -import "./state.svelte.js"; -import "clsx"; -import "@sveltejs/kit/internal"; -import "./url.js"; -import "./utils.js"; -import { w as writable } from "./index.js"; -import "@sveltejs/kit/internal/server"; -import "./root.js"; -import "./exports.js"; -import { g as getContext } from "./index3.js"; -function create_updated_store() { - const { set, subscribe } = writable(false); - { - return { - subscribe, - // eslint-disable-next-line @typescript-eslint/require-await - check: async () => false - }; - } -} -const stores = { - updated: /* @__PURE__ */ create_updated_store() -}; -({ - check: stores.updated.check -}); -function context() { - return getContext("__request__"); -} -const page$1 = { - get data() { - return context().page.data; - }, - get error() { - return context().page.error; - }, - get status() { - return context().page.status; - }, - get url() { - return context().page.url; - } -}; -const page = page$1; -export { - page as p -}; diff --git a/.svelte-kit/output/server/chunks/index5.js b/.svelte-kit/output/server/chunks/index5.js deleted file mode 100644 index 5a5bcdc..0000000 --- a/.svelte-kit/output/server/chunks/index5.js +++ /dev/null @@ -1,224 +0,0 @@ -import { logger } from "@better-auth/core/env"; -import { createAdapterFactory } from "@better-auth/core/db/adapter"; -const memoryAdapter = (db, config) => { - let lazyOptions = null; - const adapterCreator = createAdapterFactory({ - config: { - adapterId: "memory", - adapterName: "Memory Adapter", - usePlural: false, - debugLogs: config?.debugLogs || false, - supportsArrays: true, - customTransformInput(props) { - if ((props.options.advanced?.database?.useNumberId || props.options.advanced?.database?.generateId === "serial") && props.field === "id" && props.action === "create") return db[props.model].length + 1; - return props.data; - }, - transaction: async (cb) => { - const clone = structuredClone(db); - try { - return await cb(adapterCreator(lazyOptions)); - } catch (error) { - Object.keys(db).forEach((key) => { - db[key] = clone[key]; - }); - throw error; - } - } - }, - adapter: ({ getFieldName, getDefaultFieldName, options, getModelName }) => { - const applySortToRecords = (records, sortBy, model) => { - if (!sortBy) return records; - return records.sort((a, b) => { - const field = getFieldName({ - model, - field: sortBy.field - }); - const aValue = a[field]; - const bValue = b[field]; - let comparison = 0; - if (aValue == null && bValue == null) comparison = 0; - else if (aValue == null) comparison = -1; - else if (bValue == null) comparison = 1; - else if (typeof aValue === "string" && typeof bValue === "string") comparison = aValue.localeCompare(bValue); - else if (aValue instanceof Date && bValue instanceof Date) comparison = aValue.getTime() - bValue.getTime(); - else if (typeof aValue === "number" && typeof bValue === "number") comparison = aValue - bValue; - else if (typeof aValue === "boolean" && typeof bValue === "boolean") comparison = aValue === bValue ? 0 : aValue ? 1 : -1; - else comparison = String(aValue).localeCompare(String(bValue)); - return sortBy.direction === "asc" ? comparison : -comparison; - }); - }; - function convertWhereClause(where, model, join, select) { - const baseRecords = (() => { - const table = db[model]; - if (!table) { - logger.error(`[MemoryAdapter] Model ${model} not found in the DB`, Object.keys(db)); - throw new Error(`Model ${model} not found`); - } - const evalClause = (record, clause) => { - const { field, value, operator } = clause; - switch (operator) { - case "in": - if (!Array.isArray(value)) throw new Error("Value must be an array"); - return value.includes(record[field]); - case "not_in": - if (!Array.isArray(value)) throw new Error("Value must be an array"); - return !value.includes(record[field]); - case "contains": - return record[field].includes(value); - case "starts_with": - return record[field].startsWith(value); - case "ends_with": - return record[field].endsWith(value); - case "ne": - return record[field] !== value; - case "gt": - return value != null && Boolean(record[field] > value); - case "gte": - return value != null && Boolean(record[field] >= value); - case "lt": - return value != null && Boolean(record[field] < value); - case "lte": - return value != null && Boolean(record[field] <= value); - default: - return record[field] === value; - } - }; - let records = table.filter((record) => { - if (!where.length || where.length === 0) return true; - let result = evalClause(record, where[0]); - for (const clause of where) { - const clauseResult = evalClause(record, clause); - if (clause.connector === "OR") result = result || clauseResult; - else result = result && clauseResult; - } - return result; - }); - if (select?.length && select.length > 0) records = records.map((record) => Object.fromEntries(Object.entries(record).filter(([key]) => select.includes(getDefaultFieldName({ - model, - field: key - }))))); - return records; - })(); - if (!join) return baseRecords; - const grouped = /* @__PURE__ */ new Map(); - const seenIds = /* @__PURE__ */ new Map(); - for (const baseRecord of baseRecords) { - const baseId = String(baseRecord.id); - if (!grouped.has(baseId)) { - const nested = { ...baseRecord }; - for (const [joinModel, joinAttr] of Object.entries(join)) { - const joinModelName = getModelName(joinModel); - if (joinAttr.relation === "one-to-one") nested[joinModelName] = null; - else { - nested[joinModelName] = []; - seenIds.set(`${baseId}-${joinModel}`, /* @__PURE__ */ new Set()); - } - } - grouped.set(baseId, nested); - } - const nestedEntry = grouped.get(baseId); - for (const [joinModel, joinAttr] of Object.entries(join)) { - const joinModelName = getModelName(joinModel); - const joinTable = db[joinModelName]; - if (!joinTable) { - logger.error(`[MemoryAdapter] JoinOption model ${joinModelName} not found in the DB`, Object.keys(db)); - throw new Error(`JoinOption model ${joinModelName} not found`); - } - const matchingRecords = joinTable.filter((joinRecord) => joinRecord[joinAttr.on.to] === baseRecord[joinAttr.on.from]); - if (joinAttr.relation === "one-to-one") nestedEntry[joinModelName] = matchingRecords[0] || null; - else { - const seenSet = seenIds.get(`${baseId}-${joinModel}`); - const limit = joinAttr.limit ?? 100; - let count = 0; - for (const matchingRecord of matchingRecords) { - if (count >= limit) break; - if (!seenSet.has(matchingRecord.id)) { - nestedEntry[joinModelName].push(matchingRecord); - seenSet.add(matchingRecord.id); - count++; - } - } - } - } - } - return Array.from(grouped.values()); - } - return { - create: async ({ model, data }) => { - if (options.advanced?.database?.useNumberId || options.advanced?.database?.generateId === "serial") data.id = db[getModelName(model)].length + 1; - if (!db[model]) db[model] = []; - db[model].push(data); - return data; - }, - findOne: async ({ model, where, select, join }) => { - const res = convertWhereClause(where, model, join, select); - if (join) { - const resArray = res; - if (!resArray.length) return null; - return resArray[0]; - } - return res[0] || null; - }, - findMany: async ({ model, where, sortBy, limit, select, offset, join }) => { - const res = convertWhereClause(where || [], model, join, select); - if (join) { - const resArray = res; - if (!resArray.length) return []; - applySortToRecords(resArray, sortBy, model); - let paginatedRecords = resArray; - if (offset !== void 0) paginatedRecords = paginatedRecords.slice(offset); - if (limit !== void 0) paginatedRecords = paginatedRecords.slice(0, limit); - return paginatedRecords; - } - let table = applySortToRecords(res, sortBy, model); - if (offset !== void 0) table = table.slice(offset); - if (limit !== void 0) table = table.slice(0, limit); - return table || []; - }, - count: async ({ model, where }) => { - if (where) return convertWhereClause(where, model).length; - return db[model].length; - }, - update: async ({ model, where, update }) => { - const res = convertWhereClause(where, model); - res.forEach((record) => { - Object.assign(record, update); - }); - return res[0] || null; - }, - delete: async ({ model, where }) => { - const table = db[model]; - const res = convertWhereClause(where, model); - db[model] = table.filter((record) => !res.includes(record)); - }, - deleteMany: async ({ model, where }) => { - const table = db[model]; - const res = convertWhereClause(where, model); - let count = 0; - db[model] = table.filter((record) => { - if (res.includes(record)) { - count++; - return false; - } - return !res.includes(record); - }); - return count; - }, - updateMany({ model, where, update }) { - const res = convertWhereClause(where, model); - res.forEach((record) => { - Object.assign(record, update); - }); - return res[0] || null; - } - }; - } - }); - return (options) => { - lazyOptions = options; - return adapterCreator(options); - }; -}; -export { - memoryAdapter -}; diff --git a/.svelte-kit/output/server/chunks/index6.js b/.svelte-kit/output/server/chunks/index6.js deleted file mode 100644 index f55374c..0000000 --- a/.svelte-kit/output/server/chunks/index6.js +++ /dev/null @@ -1,307 +0,0 @@ -import { c as createKyselyAdapter } from "./auth.js"; -import { g } from "./auth.js"; -import { sql } from "kysely"; -import { createAdapterFactory } from "@better-auth/core/db/adapter"; -const kyselyAdapter = (db, config) => { - let lazyOptions = null; - const createCustomAdapter = (db$1) => { - return ({ getFieldName, schema, getDefaultFieldName, getDefaultModelName, getFieldAttributes, getModelName }) => { - const selectAllJoins = (join) => { - const allSelects = []; - const allSelectsStr = []; - if (join) for (const [joinModel, _] of Object.entries(join)) { - const fields = schema[getDefaultModelName(joinModel)]?.fields; - const [_joinModelSchema, joinModelName] = joinModel.includes(".") ? joinModel.split(".") : [void 0, joinModel]; - if (!fields) continue; - fields.id = { type: "string" }; - for (const [field, fieldAttr] of Object.entries(fields)) { - allSelects.push(sql`${sql.ref(`join_${joinModelName}`)}.${sql.ref(fieldAttr.fieldName || field)} as ${sql.ref(`_joined_${joinModelName}_${fieldAttr.fieldName || field}`)}`); - allSelectsStr.push({ - joinModel, - joinModelRef: joinModelName, - fieldName: fieldAttr.fieldName || field - }); - } - } - return { - allSelectsStr, - allSelects - }; - }; - const withReturning = async (values, builder, model, where) => { - let res; - if (config?.type === "mysql") { - await builder.execute(); - const field = values.id ? "id" : where.length > 0 && where[0]?.field ? where[0].field : "id"; - if (!values.id && where.length === 0) { - res = await db$1.selectFrom(model).selectAll().orderBy(getFieldName({ - model, - field - }), "desc").limit(1).executeTakeFirst(); - return res; - } - const value = values[field] || where[0]?.value; - res = await db$1.selectFrom(model).selectAll().orderBy(getFieldName({ - model, - field - }), "desc").where(getFieldName({ - model, - field - }), "=", value).limit(1).executeTakeFirst(); - return res; - } - if (config?.type === "mssql") { - res = await builder.outputAll("inserted").executeTakeFirst(); - return res; - } - res = await builder.returningAll().executeTakeFirst(); - return res; - }; - function convertWhereClause(model, w) { - if (!w) return { - and: null, - or: null - }; - const conditions = { - and: [], - or: [] - }; - w.forEach((condition) => { - const { field: _field, value: _value, operator = "=", connector = "AND" } = condition; - const value = _value; - const field = getFieldName({ - model, - field: _field - }); - const expr = (eb) => { - const f = `${model}.${field}`; - if (operator.toLowerCase() === "in") return eb(f, "in", Array.isArray(value) ? value : [value]); - if (operator.toLowerCase() === "not_in") return eb(f, "not in", Array.isArray(value) ? value : [value]); - if (operator === "contains") return eb(f, "like", `%${value}%`); - if (operator === "starts_with") return eb(f, "like", `${value}%`); - if (operator === "ends_with") return eb(f, "like", `%${value}`); - if (operator === "eq") return eb(f, "=", value); - if (operator === "ne") return eb(f, "<>", value); - if (operator === "gt") return eb(f, ">", value); - if (operator === "gte") return eb(f, ">=", value); - if (operator === "lt") return eb(f, "<", value); - if (operator === "lte") return eb(f, "<=", value); - return eb(f, operator, value); - }; - if (connector === "OR") conditions.or.push(expr); - else conditions.and.push(expr); - }); - return { - and: conditions.and.length ? conditions.and : null, - or: conditions.or.length ? conditions.or : null - }; - } - function processJoinedResults(rows, joinConfig, allSelectsStr) { - if (!joinConfig || !rows.length) return rows; - const groupedByMainId = /* @__PURE__ */ new Map(); - for (const currentRow of rows) { - const mainModelFields = {}; - const joinedModelFields = {}; - for (const [joinModel] of Object.entries(joinConfig)) joinedModelFields[getModelName(joinModel)] = {}; - for (const [key, value] of Object.entries(currentRow)) { - const keyStr = String(key); - let assigned = false; - for (const { joinModel, fieldName, joinModelRef } of allSelectsStr) if (keyStr === `_joined_${joinModelRef}_${fieldName}`) { - joinedModelFields[getModelName(joinModel)][getFieldName({ - model: joinModel, - field: fieldName - })] = value; - assigned = true; - break; - } - if (!assigned) mainModelFields[key] = value; - } - const mainId = mainModelFields.id; - if (!mainId) continue; - if (!groupedByMainId.has(mainId)) { - const entry$1 = { ...mainModelFields }; - for (const [joinModel, joinAttr] of Object.entries(joinConfig)) entry$1[getModelName(joinModel)] = joinAttr.relation === "one-to-one" ? null : []; - groupedByMainId.set(mainId, entry$1); - } - const entry = groupedByMainId.get(mainId); - for (const [joinModel, joinAttr] of Object.entries(joinConfig)) { - const isUnique = joinAttr.relation === "one-to-one"; - const limit = joinAttr.limit ?? 100; - const joinedObj = joinedModelFields[getModelName(joinModel)]; - const hasData = joinedObj && Object.keys(joinedObj).length > 0 && Object.values(joinedObj).some((value) => value !== null && value !== void 0); - if (isUnique) entry[getModelName(joinModel)] = hasData ? joinedObj : null; - else { - const joinModelName = getModelName(joinModel); - if (Array.isArray(entry[joinModelName]) && hasData) { - if (entry[joinModelName].length >= limit) continue; - const idFieldName = getFieldName({ - model: joinModel, - field: "id" - }); - const joinedId = joinedObj[idFieldName]; - if (joinedId) { - if (!entry[joinModelName].some((item) => item[idFieldName] === joinedId) && entry[joinModelName].length < limit) entry[joinModelName].push(joinedObj); - } else if (entry[joinModelName].length < limit) entry[joinModelName].push(joinedObj); - } - } - } - } - const result = Array.from(groupedByMainId.values()); - for (const entry of result) for (const [joinModel, joinAttr] of Object.entries(joinConfig)) if (joinAttr.relation !== "one-to-one") { - const joinModelName = getModelName(joinModel); - if (Array.isArray(entry[joinModelName])) { - const limit = joinAttr.limit ?? 100; - if (entry[joinModelName].length > limit) entry[joinModelName] = entry[joinModelName].slice(0, limit); - } - } - return result; - } - return { - async create({ data, model }) { - return await withReturning(data, db$1.insertInto(model).values(data), model, []); - }, - async findOne({ model, where, select, join }) { - const { and, or } = convertWhereClause(model, where); - let query = db$1.selectFrom((eb) => { - let b = eb.selectFrom(model); - if (and) b = b.where((eb$1) => eb$1.and(and.map((expr) => expr(eb$1)))); - if (or) b = b.where((eb$1) => eb$1.or(or.map((expr) => expr(eb$1)))); - if (select?.length && select.length > 0) b = b.select(select.map((field) => getFieldName({ - model, - field - }))); - else b = b.selectAll(); - return b.as("primary"); - }).selectAll("primary"); - if (join) for (const [joinModel, joinAttr] of Object.entries(join)) { - const [_joinModelSchema, joinModelName] = joinModel.includes(".") ? joinModel.split(".") : [void 0, joinModel]; - query = query.leftJoin(`${joinModel} as join_${joinModelName}`, (join$1) => join$1.onRef(`join_${joinModelName}.${joinAttr.on.to}`, "=", `primary.${joinAttr.on.from}`)); - } - const { allSelectsStr, allSelects } = selectAllJoins(join); - query = query.select(allSelects); - const res = await query.execute(); - if (!res || !Array.isArray(res) || res.length === 0) return null; - const row = res[0]; - if (join) return processJoinedResults(res, join, allSelectsStr)[0]; - return row; - }, - async findMany({ model, where, limit, select, offset, sortBy, join }) { - const { and, or } = convertWhereClause(model, where); - let query = db$1.selectFrom((eb) => { - let b = eb.selectFrom(model); - if (config?.type === "mssql") { - if (offset !== void 0) { - if (!sortBy) b = b.orderBy(getFieldName({ - model, - field: "id" - })); - b = b.offset(offset).fetch(limit || 100); - } else if (limit !== void 0) b = b.top(limit); - } else { - if (limit !== void 0) b = b.limit(limit); - if (offset !== void 0) b = b.offset(offset); - } - if (sortBy?.field) b = b.orderBy(`${getFieldName({ - model, - field: sortBy.field - })}`, sortBy.direction); - if (and) b = b.where((eb$1) => eb$1.and(and.map((expr) => expr(eb$1)))); - if (or) b = b.where((eb$1) => eb$1.or(or.map((expr) => expr(eb$1)))); - if (select?.length && select.length > 0) b = b.select(select.map((field) => getFieldName({ - model, - field - }))); - else b = b.selectAll(); - return b.as("primary"); - }).selectAll("primary"); - if (join) for (const [joinModel, joinAttr] of Object.entries(join)) { - const [_joinModelSchema, joinModelName] = joinModel.includes(".") ? joinModel.split(".") : [void 0, joinModel]; - query = query.leftJoin(`${joinModel} as join_${joinModelName}`, (join$1) => join$1.onRef(`join_${joinModelName}.${joinAttr.on.to}`, "=", `primary.${joinAttr.on.from}`)); - } - const { allSelectsStr, allSelects } = selectAllJoins(join); - query = query.select(allSelects); - if (sortBy?.field) query = query.orderBy(`${getFieldName({ - model, - field: sortBy.field - })}`, sortBy.direction); - const res = await query.execute(); - if (!res) return []; - if (join) return processJoinedResults(res, join, allSelectsStr); - return res; - }, - async update({ model, where, update: values }) { - const { and, or } = convertWhereClause(model, where); - let query = db$1.updateTable(model).set(values); - if (and) query = query.where((eb) => eb.and(and.map((expr) => expr(eb)))); - if (or) query = query.where((eb) => eb.or(or.map((expr) => expr(eb)))); - return await withReturning(values, query, model, where); - }, - async updateMany({ model, where, update: values }) { - const { and, or } = convertWhereClause(model, where); - let query = db$1.updateTable(model).set(values); - if (and) query = query.where((eb) => eb.and(and.map((expr) => expr(eb)))); - if (or) query = query.where((eb) => eb.or(or.map((expr) => expr(eb)))); - const res = (await query.executeTakeFirst()).numUpdatedRows; - return res > Number.MAX_SAFE_INTEGER ? Number.MAX_SAFE_INTEGER : Number(res); - }, - async count({ model, where }) { - const { and, or } = convertWhereClause(model, where); - let query = db$1.selectFrom(model).select(db$1.fn.count("id").as("count")); - if (and) query = query.where((eb) => eb.and(and.map((expr) => expr(eb)))); - if (or) query = query.where((eb) => eb.or(or.map((expr) => expr(eb)))); - const res = await query.execute(); - if (typeof res[0].count === "number") return res[0].count; - if (typeof res[0].count === "bigint") return Number(res[0].count); - return parseInt(res[0].count); - }, - async delete({ model, where }) { - const { and, or } = convertWhereClause(model, where); - let query = db$1.deleteFrom(model); - if (and) query = query.where((eb) => eb.and(and.map((expr) => expr(eb)))); - if (or) query = query.where((eb) => eb.or(or.map((expr) => expr(eb)))); - await query.execute(); - }, - async deleteMany({ model, where }) { - const { and, or } = convertWhereClause(model, where); - let query = db$1.deleteFrom(model); - if (and) query = query.where((eb) => eb.and(and.map((expr) => expr(eb)))); - if (or) query = query.where((eb) => eb.or(or.map((expr) => expr(eb)))); - const res = (await query.executeTakeFirst()).numDeletedRows; - return res > Number.MAX_SAFE_INTEGER ? Number.MAX_SAFE_INTEGER : Number(res); - }, - options: config - }; - }; - }; - let adapterOptions = null; - adapterOptions = { - config: { - adapterId: "kysely", - adapterName: "Kysely Adapter", - usePlural: config?.usePlural, - debugLogs: config?.debugLogs, - supportsBooleans: config?.type === "sqlite" || config?.type === "mssql" || config?.type === "mysql" || !config?.type ? false : true, - supportsDates: config?.type === "sqlite" || config?.type === "mssql" || !config?.type ? false : true, - supportsJSON: config?.type === "postgres" ? true : false, - supportsArrays: false, - supportsUUIDs: config?.type === "postgres" ? true : false, - transaction: config?.transaction ? (cb) => db.transaction().execute((trx) => { - return cb(createAdapterFactory({ - config: adapterOptions.config, - adapter: createCustomAdapter(trx) - })(lazyOptions)); - }) : false - }, - adapter: createCustomAdapter(db) - }; - const adapter = createAdapterFactory(adapterOptions); - return (options) => { - lazyOptions = options; - return adapter(options); - }; -}; -export { - createKyselyAdapter, - g as getKyselyDatabaseType, - kyselyAdapter -}; diff --git a/.svelte-kit/output/server/chunks/internal.js b/.svelte-kit/output/server/chunks/internal.js deleted file mode 100644 index 55b3eeb..0000000 --- a/.svelte-kit/output/server/chunks/internal.js +++ /dev/null @@ -1,127 +0,0 @@ -import { r as root } from "./root.js"; -import "./environment.js"; -import "./server.js"; -import "./shared-server.js"; -let read_implementation = null; -function set_read_implementation(fn) { - read_implementation = fn; -} -function set_manifest(_) { -} -const options = { - app_template_contains_nonce: false, - async: false, - csp: { "mode": "auto", "directives": { "upgrade-insecure-requests": false, "block-all-mixed-content": false }, "reportOnly": { "upgrade-insecure-requests": false, "block-all-mixed-content": false } }, - csrf_check_origin: true, - csrf_trusted_origins: [], - embedded: false, - env_public_prefix: "PUBLIC_", - env_private_prefix: "", - hash_routing: false, - hooks: null, - // added lazily, via `get_hooks` - preload_strategy: "modulepreload", - root, - service_worker: false, - service_worker_options: void 0, - templates: { - app: ({ head, body, assets, nonce, env }) => '\n\n \n \n \n \n \n \n Vash Esports\n ' + head + '\n \n \n
' + body + "
\n \n\n", - error: ({ status, message }) => '\n\n \n \n ' + message + ` - - - - -
- ` + status + '\n
\n

' + message + "

\n
\n
\n \n\n" - }, - version_hash: "12t8tv8" -}; -async function get_hooks() { - let handle; - let handleFetch; - let handleError; - let handleValidationError; - let init; - ({ handle, handleFetch, handleError, handleValidationError, init } = await import("../entries/hooks.server.js")); - let reroute; - let transport; - return { - handle, - handleFetch, - handleError, - handleValidationError, - init, - reroute, - transport - }; -} -export { - set_manifest as a, - get_hooks as g, - options as o, - read_implementation as r, - set_read_implementation as s -}; diff --git a/.svelte-kit/output/server/chunks/node-sqlite-dialect.js b/.svelte-kit/output/server/chunks/node-sqlite-dialect.js deleted file mode 100644 index 68f03bc..0000000 --- a/.svelte-kit/output/server/chunks/node-sqlite-dialect.js +++ /dev/null @@ -1,155 +0,0 @@ -import { CompiledQuery, DefaultQueryCompiler, DEFAULT_MIGRATION_TABLE, DEFAULT_MIGRATION_LOCK_TABLE, sql } from "kysely"; -var NodeSqliteAdapter = class { - get supportsCreateIfNotExists() { - return true; - } - get supportsTransactionalDdl() { - return false; - } - get supportsReturning() { - return true; - } - async acquireMigrationLock() { - } - async releaseMigrationLock() { - } - get supportsOutput() { - return true; - } -}; -var NodeSqliteDriver = class { - #config; - #connectionMutex = new ConnectionMutex(); - #db; - #connection; - constructor(config) { - this.#config = { ...config }; - } - async init() { - this.#db = this.#config.database; - this.#connection = new NodeSqliteConnection(this.#db); - if (this.#config.onCreateConnection) await this.#config.onCreateConnection(this.#connection); - } - async acquireConnection() { - await this.#connectionMutex.lock(); - return this.#connection; - } - async beginTransaction(connection) { - await connection.executeQuery(CompiledQuery.raw("begin")); - } - async commitTransaction(connection) { - await connection.executeQuery(CompiledQuery.raw("commit")); - } - async rollbackTransaction(connection) { - await connection.executeQuery(CompiledQuery.raw("rollback")); - } - async releaseConnection() { - this.#connectionMutex.unlock(); - } - async destroy() { - this.#db?.close(); - } -}; -var NodeSqliteConnection = class { - #db; - constructor(db) { - this.#db = db; - } - executeQuery(compiledQuery) { - const { sql: sql$1, parameters } = compiledQuery; - const rows = this.#db.prepare(sql$1).all(...parameters); - return Promise.resolve({ rows }); - } - async *streamQuery() { - throw new Error("Streaming query is not supported by SQLite driver."); - } -}; -var ConnectionMutex = class { - #promise; - #resolve; - async lock() { - while (await this.#promise) await this.#promise; - this.#promise = new Promise((resolve) => { - this.#resolve = resolve; - }); - } - unlock() { - const resolve = this.#resolve; - this.#promise = void 0; - this.#resolve = void 0; - resolve?.(); - } -}; -var NodeSqliteIntrospector = class { - #db; - constructor(db) { - this.#db = db; - } - async getSchemas() { - return []; - } - async getTables(options = { withInternalKyselyTables: false }) { - let query = this.#db.selectFrom("sqlite_schema").where("type", "=", "table").where("name", "not like", "sqlite_%").select("name").$castTo(); - if (!options.withInternalKyselyTables) query = query.where("name", "!=", DEFAULT_MIGRATION_TABLE).where("name", "!=", DEFAULT_MIGRATION_LOCK_TABLE); - const tables = await query.execute(); - return Promise.all(tables.map(({ name }) => this.#getTableMetadata(name))); - } - async getMetadata(options) { - return { tables: await this.getTables(options) }; - } - async #getTableMetadata(table) { - const db = this.#db; - const autoIncrementCol = (await db.selectFrom("sqlite_master").where("name", "=", table).select("sql").$castTo().execute())[0]?.sql?.split(/[\(\),]/)?.find((it) => it.toLowerCase().includes("autoincrement"))?.split(/\s+/)?.[0]?.replace(/["`]/g, ""); - return { - name: table, - columns: (await db.selectFrom(sql`pragma_table_info(${table})`.as("table_info")).select([ - "name", - "type", - "notnull", - "dflt_value" - ]).execute()).map((col) => ({ - name: col.name, - dataType: col.type, - isNullable: !col.notnull, - isAutoIncrementing: col.name === autoIncrementCol, - hasDefaultValue: col.dflt_value != null - })), - isView: true - }; - } -}; -var NodeSqliteQueryCompiler = class extends DefaultQueryCompiler { - getCurrentParameterPlaceholder() { - return "?"; - } - getLeftIdentifierWrapper() { - return '"'; - } - getRightIdentifierWrapper() { - return '"'; - } - getAutoIncrement() { - return "autoincrement"; - } -}; -var NodeSqliteDialect = class { - #config; - constructor(config) { - this.#config = { ...config }; - } - createDriver() { - return new NodeSqliteDriver(this.#config); - } - createQueryCompiler() { - return new NodeSqliteQueryCompiler(); - } - createAdapter() { - return new NodeSqliteAdapter(); - } - createIntrospector(db) { - return new NodeSqliteIntrospector(db); - } -}; -export { - NodeSqliteDialect -}; diff --git a/.svelte-kit/output/server/chunks/orchestrator.js b/.svelte-kit/output/server/chunks/orchestrator.js deleted file mode 100644 index da259e9..0000000 --- a/.svelte-kit/output/server/chunks/orchestrator.js +++ /dev/null @@ -1,448 +0,0 @@ -import { d as db, b as match, u as user, g as matchGame } from "./index2.js"; -import { eq } from "drizzle-orm"; -import { g as getMatchFull, M as MATCH_STATES, s as submitRoll, p as pickMap, d as submitGameScores } from "./engine.js"; -import { b as private_env } from "./shared-server.js"; -let client = null; -let connecting = null; -async function getClient() { - if (client?.isConnected?.()) return client; - if (connecting) { - await connecting; - return client; - } - if (!private_env.OSU_IRC_USERNAME || !private_env.OSU_IRC_PASSWORD) { - throw new Error("OSU_IRC_USERNAME and OSU_IRC_PASSWORD must be set in .env"); - } - const banchoModule = await import("bancho.js"); - const BanchoClient = banchoModule.BanchoClient ?? banchoModule.default?.BanchoClient ?? banchoModule.default; - client = new BanchoClient({ - username: private_env.OSU_IRC_USERNAME, - password: private_env.OSU_IRC_PASSWORD - }); - connecting = client.connect().then(() => { - console.log("[Bancho] Connected as", private_env.OSU_IRC_USERNAME); - connecting = null; - }); - await connecting; - return client; -} -class TournamentLobby { - channel = null; - channelName = ""; - osuMatchId = 0; - // Score collection - collectedScores = []; - matchFinishedResolve = null; - // Ready tracking - allReadyResolve = null; - // Event callbacks (set by orchestrator) - onRollResult = null; - onPickCommand = null; - /** - * Create a new multiplayer lobby via !mp make. - */ - async create(name) { - const c = await getClient(); - return new Promise((resolve, reject) => { - const timeout = setTimeout( - () => reject(new Error("Lobby creation timed out")), - 15e3 - ); - const banchoBot = c.getUser("BanchoBot"); - const onPM = (msg) => { - const text = msg.message ?? String(msg); - const m = text.match(/https:\/\/osu\.ppy\.sh\/mp\/(\d+)/); - if (m) { - clearTimeout(timeout); - banchoBot.removeListener("message", onPM); - this.osuMatchId = parseInt(m[1]); - this.channelName = `#mp_${this.osuMatchId}`; - this.joinChannel(c).then( - () => resolve({ matchId: this.osuMatchId, channel: this.channelName }) - ); - } - }; - banchoBot.on("message", onPM); - banchoBot.sendMessage(`!mp make ${name}`); - }); - } - async joinChannel(c) { - this.channel = c.getChannel(this.channelName); - await this.channel.join(); - this.channel.on("message", (msg) => { - const text = msg.message ?? String(msg); - const sender = msg.user?.ircUsername ?? ""; - if (sender === "BanchoBot") { - this.parseBanchoMessage(text); - } else if (sender) { - this.parsePlayerMessage(sender, text); - } - }); - } - // ── Message Parsing ───────────────────────────────────────────────── - parseBanchoMessage(text) { - const scoreMatch = text.match( - /^(.+?) finished playing \(Score: ([\d,]+).*?(PASSED|FAILED)\)/i - ); - if (scoreMatch) { - this.collectedScores.push({ - username: scoreMatch[1].trim(), - score: parseInt(scoreMatch[2].replace(/,/g, "")), - passed: scoreMatch[3] === "PASSED" - }); - console.log(`[Bancho] Score: ${scoreMatch[1].trim()} = ${scoreMatch[2]}`); - return; - } - if (text.includes("The match has finished!")) { - console.log("[Bancho] Game finished. Scores:", this.collectedScores); - if (this.matchFinishedResolve) { - this.matchFinishedResolve([...this.collectedScores]); - this.matchFinishedResolve = null; - } - this.collectedScores = []; - return; - } - const rollMatch = text.match(/^(.+?) rolls (\d+) point\(s\)/); - if (rollMatch) { - const username = rollMatch[1].trim(); - const value = parseInt(rollMatch[2]); - console.log(`[Bancho] Roll: ${username} = ${value}`); - if (this.onRollResult) { - this.onRollResult(username, value); - } - return; - } - if (text.includes("All players are ready")) { - console.log("[Bancho] All players ready"); - if (this.allReadyResolve) { - this.allReadyResolve(); - this.allReadyResolve = null; - } - return; - } - } - parsePlayerMessage(sender, text) { - const pickMatch = text.match(/^!pick\s+([A-Z]{2})(\d*)/i); - if (pickMatch) { - const category = pickMatch[1].toUpperCase(); - const num = pickMatch[2] ? parseInt(pickMatch[2]) : 1; - const label = `${category}${num}`; - console.log(`[Bancho] Pick command from ${sender}: ${label}`); - if (this.onPickCommand) { - this.onPickCommand(sender, label); - } - return; - } - } - // ── IRC Commands ──────────────────────────────────────────────────── - async send(cmd) { - if (!this.channel) throw new Error("Lobby not created"); - console.log(`[Bancho] ${this.channelName} > ${cmd}`); - await this.channel.sendMessage(cmd); - } - async invite(username) { - await this.send(`!mp invite ${username.replace(/ /g, "_")}`); - } - async setProperties(teamMode, scoreMode, size) { - await this.send(`!mp set ${teamMode} ${scoreMode} ${size}`); - } - async setMap(beatmapId, playmode = 0) { - await this.send(`!mp map ${beatmapId} ${playmode}`); - } - async setMods(mods) { - const filtered = mods.filter((m) => !["NM", "TB", "None", "NF"].includes(m)); - if (mods.includes("FM") || mods.includes("Freemod")) { - await this.send("!mp mods Freemod NF"); - } else if (filtered.length > 0) { - await this.send(`!mp mods NF ${filtered.join(" ")}`); - } else { - await this.send("!mp mods NF"); - } - } - async startGame(delaySec = 5) { - await this.send(`!mp start ${delaySec}`); - } - async close() { - try { - await this.send("!mp close"); - } catch { - } - } - async chat(message) { - await this.send(message); - } - // ── Async Waiters ─────────────────────────────────────────────────── - /** - * Wait for all players to click "Ready" in osu! client. - * BanchoBot sends "All players are ready" when they do. - */ - waitForReady(timeoutMs = 18e4) { - return new Promise((resolve, reject) => { - const t = setTimeout(() => { - this.allReadyResolve = null; - reject(new Error("Timed out waiting for players to ready")); - }, timeoutMs); - this.allReadyResolve = () => { - clearTimeout(t); - resolve(); - }; - }); - } - /** - * Wait for "The match has finished!" and return all player scores. - */ - waitForScores(timeoutMs = 6e5) { - this.collectedScores = []; - return new Promise((resolve, reject) => { - const t = setTimeout(() => { - this.matchFinishedResolve = null; - reject(new Error("Timed out waiting for match scores")); - }, timeoutMs); - this.matchFinishedResolve = (scores) => { - clearTimeout(t); - resolve(scores); - }; - }); - } -} -const lobbies = /* @__PURE__ */ new Map(); -function getLobby(matchId) { - return lobbies.get(matchId); -} -function setLobby(matchId, lobby) { - lobbies.set(matchId, lobby); -} -function removeLobby(matchId) { - lobbies.delete(matchId); -} -function sleep(ms) { - return new Promise((r) => setTimeout(r, ms)); -} -async function initMatchLobby(matchId) { - const m = await getMatchFull(matchId); - const config = m.config; - const lobby = new TournamentLobby(); - const lobbyName = `VASH: (${m.participants[0]?.team.name}) vs (${m.participants[1]?.team.name})`; - console.log(`[Orchestrator] Creating lobby: ${lobbyName}`); - const { matchId: osuId, channel } = await lobby.create(lobbyName); - console.log(`[Orchestrator] Created ${channel} (osu mp/${osuId})`); - setLobby(matchId, lobby); - await db.update(match).set({ state: MATCH_STATES.LOBBY, osuLobbyId: osuId, startedAt: /* @__PURE__ */ new Date() }).where(eq(match.id, matchId)); - const scoreMode = config.scoringType === "score_v2" ? 3 : config.scoringType === "accuracy" ? 1 : config.scoringType === "combo" ? 2 : 0; - await lobby.setProperties(0, scoreMode, config.teamSize * 2); - await lobby.send("!mp password"); - await sleep(500); - const invited = /* @__PURE__ */ new Set(); - for (const p of m.participants) { - for (const pl of p.players) { - const u = await db.query.user.findFirst({ where: eq(user.id, pl.userId) }); - if (u?.name && !invited.has(u.name.toLowerCase())) { - await lobby.invite(u.name); - invited.add(u.name.toLowerCase()); - console.log(`[Orchestrator] Invited ${u.name}`); - await sleep(300); - } - } - } - setupChatHandlers(matchId, lobby); - await lobby.chat( - `Welcome! BO${config.bestOf}. Type !roll to decide pick order, or use the web UI.` - ); - await db.update(match).set({ state: MATCH_STATES.ROLLING }).where(eq(match.id, matchId)); - return { osuMatchId: osuId, channel }; -} -function setupChatHandlers(matchId, lobby) { - lobby.onRollResult = async (username, value) => { - try { - const m = await getMatchFull(matchId); - if (m.state !== MATCH_STATES.ROLLING) { - await lobby.chat(`Rolls are not active right now.`); - return; - } - let targetParticipant = null; - for (const p of m.participants) { - for (const pl of p.players) { - const u = await db.query.user.findFirst({ where: eq(user.id, pl.userId) }); - if (u?.name?.toLowerCase() === username.toLowerCase().replace(/_/g, " ")) { - if (p.rollValue === null) { - targetParticipant = p; - break; - } else if (!targetParticipant) { - const unrolled = m.participants.find((pp) => pp.rollValue === null); - if (unrolled) targetParticipant = unrolled; - } - } - } - if (targetParticipant?.rollValue === null) break; - } - if (!targetParticipant || targetParticipant.rollValue !== null) { - await lobby.chat(`${username}: already rolled or not in this match.`); - return; - } - await submitRoll(matchId, targetParticipant.id, value); - console.log(`[Orchestrator] IRC roll: ${username} = ${value}`); - const updated = await getMatchFull(matchId); - if (updated.state === MATCH_STATES.PICKING) { - const sorted = [...updated.participants].sort( - (a, b) => (a.pickOrder ?? 99) - (b.pickOrder ?? 99) - ); - await lobby.chat( - `Rolls complete! ${sorted[0]?.team.name} picks first. Use !pick (e.g. !pick NM1) or pick in web UI.` - ); - } - } catch (err) { - console.error("[Orchestrator] IRC roll error:", err.message); - } - }; - lobby.onPickCommand = async (username, slotLabel) => { - try { - const m = await getMatchFull(matchId); - if (m.state !== MATCH_STATES.PICKING) { - await lobby.chat(`Picks are not active right now.`); - return; - } - const labelMatch = slotLabel.match(/^([A-Z]{2})(\d+)$/); - if (!labelMatch) { - await lobby.chat(`${username}: Invalid slot. Use format like NM1, HD2, DT1.`); - return; - } - const category = labelMatch[1]; - const order = parseInt(labelMatch[2]); - const sorted = [...m.participants].sort( - (a, b) => (a.pickOrder ?? 99) - (b.pickOrder ?? 99) - ); - const expectedIdx = m.games.length % sorted.length; - const expectedPicker = sorted[expectedIdx]; - let isPickerTurn = false; - if (expectedPicker) { - for (const pl of expectedPicker.players) { - const u = await db.query.user.findFirst({ where: eq(user.id, pl.userId) }); - if (u?.name?.toLowerCase() === username.toLowerCase().replace(/_/g, " ")) { - isPickerTurn = true; - break; - } - } - } - if (!isPickerTurn && m.participants[0]?.teamId === m.participants[1]?.teamId) { - isPickerTurn = true; - } - if (!isPickerTurn) { - await lobby.chat(`${username}: It's not your turn to pick.`); - return; - } - const slot = m.mappool?.slots?.find( - (s) => s.category === category && s.orderInCategory === order - ); - if (!slot) { - await lobby.chat(`${username}: Slot ${slotLabel} not found in this mappool.`); - return; - } - const alreadyPlayed = m.games.some((g) => g.mappoolSlotId === slot.id); - if (alreadyPlayed) { - await lobby.chat(`${username}: ${slotLabel} has already been played.`); - return; - } - const game = await pickMap(matchId, expectedPicker.id, slot.id); - console.log(`[Orchestrator] IRC pick: ${username} picked ${slotLabel}`); - playPickedMap(matchId, game.id).catch( - (err) => console.error("[Orchestrator] IRC play failed:", err.message) - ); - } catch (err) { - console.error("[Orchestrator] IRC pick error:", err.message); - await lobby.chat(`Error: ${err.message}`).catch(() => { - }); - } - }; -} -async function playPickedMap(matchId, matchGameId) { - const lobby = getLobby(matchId); - if (!lobby) { - console.warn("[Orchestrator] No IRC lobby for", matchId, "— skipping IRC"); - return; - } - const game = await db.query.matchGame.findFirst({ - where: eq(matchGame.id, matchGameId), - with: { slot: true } - }); - if (!game) throw new Error("Game not found"); - const slot = game.slot; - await lobby.setMap(slot.beatmapId); - await sleep(1e3); - await lobby.setMods(slot.mods); - await sleep(500); - await lobby.chat( - `Playing ${slot.category}${slot.orderInCategory}. Ready up! (Game starts when all players are ready)` - ); - try { - await lobby.waitForReady(); - await lobby.chat("All ready — starting in 5s!"); - await lobby.startGame(5); - } catch (err) { - console.warn("[Orchestrator] Ready timeout:", err.message); - await lobby.chat("Ready timed out. Use the web UI to force start, or ready up!"); - return; - } - collectScores(matchId, matchGameId, lobby).catch( - (err) => console.error("[Orchestrator] Score collection failed:", err) - ); -} -async function forceStartGame(matchId) { - const lobby = getLobby(matchId); - if (!lobby) return; - await lobby.chat("Force starting in 10s!"); - await lobby.startGame(10); -} -async function collectScores(matchId, matchGameId, lobby) { - const ircScores = await lobby.waitForScores(); - console.log(`[Orchestrator] Scores for game ${matchGameId}:`, ircScores); - const m = await getMatchFull(matchId); - const scores = []; - for (const irc of ircScores) { - for (const participant of m.participants) { - for (const player of participant.players) { - const u = await db.query.user.findFirst({ where: eq(user.id, player.userId) }); - const ircName = irc.username.toLowerCase().replace(/_/g, " "); - const dbName = u?.name?.toLowerCase(); - if (dbName && (dbName === ircName || dbName === irc.username.toLowerCase())) { - scores.push({ playerId: player.id, score: irc.score, passed: irc.passed }); - } - } - } - } - if (scores.length === 0) { - console.warn("[Orchestrator] No scores matched any IRC usernames"); - return; - } - await submitGameScores(matchGameId, scores); - const updated = await getMatchFull(matchId); - if (updated.state === MATCH_STATES.FINISHED) { - const winner = updated.participants.find((p) => p.teamId === updated.winnerId); - await lobby.chat(`GG! ${winner?.team.name ?? "?"} wins the match!`); - await sleep(5e3); - await lobby.close(); - removeLobby(matchId); - } else { - const sorted = [...updated.participants].sort( - (a, b) => (a.pickOrder ?? 99) - (b.pickOrder ?? 99) - ); - const nextIdx = updated.games.length % sorted.length; - const nextPicker = sorted[nextIdx]; - await lobby.chat( - `${nextPicker?.team.name}'s turn to pick. Use !pick (e.g. !pick HD1) or pick in web UI.` - ); - } -} -async function closeLobby(matchId) { - const lobby = getLobby(matchId); - if (lobby) { - await lobby.close(); - removeLobby(matchId); - } -} -export { - closeLobby as c, - forceStartGame as f, - getLobby as g, - initMatchLobby as i, - playPickedMap as p -}; diff --git a/.svelte-kit/output/server/chunks/query.js b/.svelte-kit/output/server/chunks/query.js deleted file mode 100644 index a14a6fa..0000000 --- a/.svelte-kit/output/server/chunks/query.js +++ /dev/null @@ -1,258 +0,0 @@ -import { get_request_store, with_request_store } from "@sveltejs/kit/internal/server"; -import { z as stringify_remote_arg, f as create_remote_key, h as handle_error_and_jsonify } from "./shared.js"; -import { p as prerendering } from "./environment.js"; -import { parse } from "devalue"; -import { error } from "@sveltejs/kit"; -import { HttpError, SvelteKitError } from "@sveltejs/kit/internal"; -function create_validator(validate_or_fn, maybe_fn) { - if (!maybe_fn) { - return (arg) => { - if (arg !== void 0) { - error(400, "Bad Request"); - } - }; - } - if (validate_or_fn === "unchecked") { - return (arg) => arg; - } - if ("~standard" in validate_or_fn) { - return async (arg) => { - const { event, state } = get_request_store(); - const result = await validate_or_fn["~standard"].validate(arg); - if (result.issues) { - error( - 400, - await state.handleValidationError({ - issues: result.issues, - event - }) - ); - } - return result.value; - }; - } - throw new Error( - 'Invalid validator passed to remote function. Expected "unchecked" or a Standard Schema (https://standardschema.dev)' - ); -} -async function get_response(info, arg, state, get_result) { - await 0; - const cache = get_cache(info, state); - return cache[stringify_remote_arg(arg, state.transport)] ??= get_result(); -} -function parse_remote_response(data, transport) { - const revivers = {}; - for (const key in transport) { - revivers[key] = transport[key].decode; - } - return parse(data, revivers); -} -async function run_remote_function(event, state, allow_cookies, get_input, fn) { - const store = { - event: { - ...event, - setHeaders: () => { - throw new Error("setHeaders is not allowed in remote functions"); - }, - cookies: { - ...event.cookies, - set: (name, value, opts) => { - if (!allow_cookies) { - throw new Error("Cannot set cookies in `query` or `prerender` functions"); - } - if (opts.path && !opts.path.startsWith("/")) { - throw new Error("Cookies set in remote functions must have an absolute path"); - } - return event.cookies.set(name, value, opts); - }, - delete: (name, opts) => { - if (!allow_cookies) { - throw new Error("Cannot delete cookies in `query` or `prerender` functions"); - } - if (opts.path && !opts.path.startsWith("/")) { - throw new Error("Cookies deleted in remote functions must have an absolute path"); - } - return event.cookies.delete(name, opts); - } - } - }, - state: { - ...state, - is_in_remote_function: true - } - }; - const input = await with_request_store(store, get_input); - return with_request_store(store, () => fn(input)); -} -function get_cache(info, state = get_request_store().state) { - let cache = state.remote_data?.get(info); - if (cache === void 0) { - cache = {}; - (state.remote_data ??= /* @__PURE__ */ new Map()).set(info, cache); - } - return cache; -} -// @__NO_SIDE_EFFECTS__ -function query(validate_or_fn, maybe_fn) { - const fn = maybe_fn ?? validate_or_fn; - const validate = create_validator(validate_or_fn, maybe_fn); - const __ = { type: "query", id: "", name: "" }; - const wrapper = (arg) => { - if (prerendering) { - throw new Error( - `Cannot call query '${__.name}' while prerendering, as prerendered pages need static data. Use 'prerender' from $app/server instead` - ); - } - const { event, state } = get_request_store(); - const get_remote_function_result = () => run_remote_function(event, state, false, () => validate(arg), fn); - const promise = get_response(__, arg, state, get_remote_function_result); - promise.catch(() => { - }); - promise.set = (value) => update_refresh_value(get_refresh_context(__, "set", arg), value); - promise.refresh = () => { - const refresh_context = get_refresh_context(__, "refresh", arg); - const is_immediate_refresh = !refresh_context.cache[refresh_context.cache_key]; - const value = is_immediate_refresh ? promise : get_remote_function_result(); - return update_refresh_value(refresh_context, value, is_immediate_refresh); - }; - promise.withOverride = () => { - throw new Error(`Cannot call '${__.name}.withOverride()' on the server`); - }; - return ( - /** @type {RemoteQuery} */ - promise - ); - }; - Object.defineProperty(wrapper, "__", { value: __ }); - return wrapper; -} -// @__NO_SIDE_EFFECTS__ -function batch(validate_or_fn, maybe_fn) { - const fn = maybe_fn ?? validate_or_fn; - const validate = create_validator(validate_or_fn, maybe_fn); - const __ = { - type: "query_batch", - id: "", - name: "", - run: async (args, options) => { - const { event, state } = get_request_store(); - return run_remote_function( - event, - state, - false, - async () => Promise.all(args.map(validate)), - async (input) => { - const get_result = await fn(input); - return Promise.all( - input.map(async (arg, i) => { - try { - return { type: "result", data: get_result(arg, i) }; - } catch (error2) { - return { - type: "error", - error: await handle_error_and_jsonify(event, state, options, error2), - status: error2 instanceof HttpError || error2 instanceof SvelteKitError ? error2.status : 500 - }; - } - }) - ); - } - ); - } - }; - let batching = { args: [], resolvers: [] }; - const wrapper = (arg) => { - if (prerendering) { - throw new Error( - `Cannot call query.batch '${__.name}' while prerendering, as prerendered pages need static data. Use 'prerender' from $app/server instead` - ); - } - const { event, state } = get_request_store(); - const get_remote_function_result = () => { - return new Promise((resolve, reject) => { - batching.args.push(arg); - batching.resolvers.push({ resolve, reject }); - if (batching.args.length > 1) return; - setTimeout(async () => { - const batched = batching; - batching = { args: [], resolvers: [] }; - try { - return await run_remote_function( - event, - state, - false, - async () => Promise.all(batched.args.map(validate)), - async (input) => { - const get_result = await fn(input); - for (let i = 0; i < batched.resolvers.length; i++) { - try { - batched.resolvers[i].resolve(get_result(input[i], i)); - } catch (error2) { - batched.resolvers[i].reject(error2); - } - } - } - ); - } catch (error2) { - for (const resolver of batched.resolvers) { - resolver.reject(error2); - } - } - }, 0); - }); - }; - const promise = get_response(__, arg, state, get_remote_function_result); - promise.catch(() => { - }); - promise.set = (value) => update_refresh_value(get_refresh_context(__, "set", arg), value); - promise.refresh = () => { - const refresh_context = get_refresh_context(__, "refresh", arg); - const is_immediate_refresh = !refresh_context.cache[refresh_context.cache_key]; - const value = is_immediate_refresh ? promise : get_remote_function_result(); - return update_refresh_value(refresh_context, value, is_immediate_refresh); - }; - promise.withOverride = () => { - throw new Error(`Cannot call '${__.name}.withOverride()' on the server`); - }; - return ( - /** @type {RemoteQuery} */ - promise - ); - }; - Object.defineProperty(wrapper, "__", { value: __ }); - return wrapper; -} -Object.defineProperty(query, "batch", { value: batch, enumerable: true }); -function get_refresh_context(__, action, arg) { - const { state } = get_request_store(); - const { refreshes } = state; - if (!refreshes) { - const name = __.type === "query_batch" ? `query.batch '${__.name}'` : `query '${__.name}'`; - throw new Error( - `Cannot call ${action} on ${name} because it is not executed in the context of a command/form remote function` - ); - } - const cache = get_cache(__, state); - const cache_key = stringify_remote_arg(arg, state.transport); - const refreshes_key = create_remote_key(__.id, cache_key); - return { __, state, refreshes, refreshes_key, cache, cache_key }; -} -function update_refresh_value({ __, refreshes, refreshes_key, cache, cache_key }, value, is_immediate_refresh = false) { - const promise = Promise.resolve(value); - if (!is_immediate_refresh) { - cache[cache_key] = promise; - } - if (__.id) { - refreshes[refreshes_key] = promise; - } - return promise.then(() => { - }); -} -export { - get_response as a, - create_validator as c, - get_cache as g, - parse_remote_response as p, - query as q, - run_remote_function as r -}; diff --git a/.svelte-kit/output/server/chunks/root.js b/.svelte-kit/output/server/chunks/root.js deleted file mode 100644 index c678a5c..0000000 --- a/.svelte-kit/output/server/chunks/root.js +++ /dev/null @@ -1,2713 +0,0 @@ -import { H as HYDRATION_ERROR, C as COMMENT_NODE, f as HYDRATION_END, h as HYDRATION_START, i as HYDRATION_START_ELSE, r as run_all, B as BOUNDARY_EFFECT, R as REACTION_RAN, E as ERROR_VALUE, j as EFFECT, k as CONNECTED, l as CLEAN, M as MAYBE_DIRTY, D as DIRTY, m as DERIVED, W as WAS_MARKED, I as INERT, o as BLOCK_EFFECT, U as UNINITIALIZED, p as deferred, q as BRANCH_EFFECT, t as ROOT_EFFECT, u as RENDER_EFFECT, v as MANAGED_EFFECT, w as HEAD_EFFECT, x as DESTROYED, A as ASYNC, y as includes, z as HYDRATION_START_FAILED, F as EFFECT_TRANSPARENT, G as EFFECT_PRESERVED, S as STALE_REACTION, n as noop, J as EAGER_EFFECT, K as STATE_SYMBOL, L as object_prototype, N as array_prototype, O as get_descriptor, P as get_prototype_of, Q as is_array, T as is_extensible, V as USER_EFFECT, X as REACTION_IS_UPDATING, Y as index_of, Z as define_property, _ as array_from, $ as is_passive_event, a0 as LEGACY_PROPS, a1 as render, a2 as setContext, d as derived } from "./index3.js"; -import { D as DEV } from "./false.js"; -function equals(value) { - return value === this.v; -} -function safe_not_equal(a, b) { - return a != a ? b == b : a !== b || a !== null && typeof a === "object" || typeof a === "function"; -} -function safe_equals(value) { - return !safe_not_equal(value, this.v); -} -function effect_update_depth_exceeded() { - { - throw new Error(`https://svelte.dev/e/effect_update_depth_exceeded`); - } -} -function hydration_failed() { - { - throw new Error(`https://svelte.dev/e/hydration_failed`); - } -} -function state_descriptors_fixed() { - { - throw new Error(`https://svelte.dev/e/state_descriptors_fixed`); - } -} -function state_prototype_fixed() { - { - throw new Error(`https://svelte.dev/e/state_prototype_fixed`); - } -} -function state_unsafe_mutation() { - { - throw new Error(`https://svelte.dev/e/state_unsafe_mutation`); - } -} -function svelte_boundary_reset_onerror() { - { - throw new Error(`https://svelte.dev/e/svelte_boundary_reset_onerror`); - } -} -function hydration_mismatch(location) { - { - console.warn(`https://svelte.dev/e/hydration_mismatch`); - } -} -function svelte_boundary_reset_noop() { - { - console.warn(`https://svelte.dev/e/svelte_boundary_reset_noop`); - } -} -let hydrating = false; -function set_hydrating(value) { - hydrating = value; -} -let hydrate_node; -function set_hydrate_node(node) { - if (node === null) { - hydration_mismatch(); - throw HYDRATION_ERROR; - } - return hydrate_node = node; -} -function hydrate_next() { - return set_hydrate_node(/* @__PURE__ */ get_next_sibling(hydrate_node)); -} -function next(count = 1) { - if (hydrating) { - var i = count; - var node = hydrate_node; - while (i--) { - node = /** @type {TemplateNode} */ - /* @__PURE__ */ get_next_sibling(node); - } - hydrate_node = node; - } -} -function skip_nodes(remove = true) { - var depth = 0; - var node = hydrate_node; - while (true) { - if (node.nodeType === COMMENT_NODE) { - var data = ( - /** @type {Comment} */ - node.data - ); - if (data === HYDRATION_END) { - if (depth === 0) return node; - depth -= 1; - } else if (data === HYDRATION_START || data === HYDRATION_START_ELSE || // "[1", "[2", etc. for if blocks - data[0] === "[" && !isNaN(Number(data.slice(1)))) { - depth += 1; - } - } - var next2 = ( - /** @type {TemplateNode} */ - /* @__PURE__ */ get_next_sibling(node) - ); - if (remove) node.remove(); - node = next2; - } -} -let tracing_mode_flag = false; -let component_context = null; -function set_component_context(context) { - component_context = context; -} -function push(props, runes = false, fn) { - component_context = { - p: component_context, - i: false, - c: null, - e: null, - s: props, - x: null, - l: null - }; -} -function pop(component) { - var context = ( - /** @type {ComponentContext} */ - component_context - ); - var effects = context.e; - if (effects !== null) { - context.e = null; - for (var fn of effects) { - create_user_effect(fn); - } - } - context.i = true; - component_context = context.p; - return ( - /** @type {T} */ - {} - ); -} -function is_runes() { - return true; -} -let micro_tasks = []; -function run_micro_tasks() { - var tasks = micro_tasks; - micro_tasks = []; - run_all(tasks); -} -function queue_micro_task(fn) { - if (micro_tasks.length === 0 && !is_flushing_sync) { - var tasks = micro_tasks; - queueMicrotask(() => { - if (tasks === micro_tasks) run_micro_tasks(); - }); - } - micro_tasks.push(fn); -} -function flush_tasks() { - while (micro_tasks.length > 0) { - run_micro_tasks(); - } -} -function handle_error(error) { - var effect = active_effect; - if (effect === null) { - active_reaction.f |= ERROR_VALUE; - return error; - } - if ((effect.f & REACTION_RAN) === 0 && (effect.f & EFFECT) === 0) { - throw error; - } - invoke_error_boundary(error, effect); -} -function invoke_error_boundary(error, effect) { - while (effect !== null) { - if ((effect.f & BOUNDARY_EFFECT) !== 0) { - if ((effect.f & REACTION_RAN) === 0) { - throw error; - } - try { - effect.b.error(error); - return; - } catch (e) { - error = e; - } - } - effect = effect.parent; - } - throw error; -} -const STATUS_MASK = -7169; -function set_signal_status(signal, status) { - signal.f = signal.f & STATUS_MASK | status; -} -function update_derived_status(derived2) { - if ((derived2.f & CONNECTED) !== 0 || derived2.deps === null) { - set_signal_status(derived2, CLEAN); - } else { - set_signal_status(derived2, MAYBE_DIRTY); - } -} -function clear_marked(deps) { - if (deps === null) return; - for (const dep of deps) { - if ((dep.f & DERIVED) === 0 || (dep.f & WAS_MARKED) === 0) { - continue; - } - dep.f ^= WAS_MARKED; - clear_marked( - /** @type {Derived} */ - dep.deps - ); - } -} -function defer_effect(effect, dirty_effects, maybe_dirty_effects) { - if ((effect.f & DIRTY) !== 0) { - dirty_effects.add(effect); - } else if ((effect.f & MAYBE_DIRTY) !== 0) { - maybe_dirty_effects.add(effect); - } - clear_marked(effect.deps); - set_signal_status(effect, CLEAN); -} -const batches = /* @__PURE__ */ new Set(); -let current_batch = null; -let batch_values = null; -let queued_root_effects = []; -let last_scheduled_effect = null; -let is_flushing = false; -let is_flushing_sync = false; -class Batch { - /** - * The current values of any sources that are updated in this batch - * They keys of this map are identical to `this.#previous` - * @type {Map} - */ - current = /* @__PURE__ */ new Map(); - /** - * The values of any sources that are updated in this batch _before_ those updates took place. - * They keys of this map are identical to `this.#current` - * @type {Map} - */ - previous = /* @__PURE__ */ new Map(); - /** - * When the batch is committed (and the DOM is updated), we need to remove old branches - * and append new ones by calling the functions added inside (if/each/key/etc) blocks - * @type {Set<() => void>} - */ - #commit_callbacks = /* @__PURE__ */ new Set(); - /** - * If a fork is discarded, we need to destroy any effects that are no longer needed - * @type {Set<(batch: Batch) => void>} - */ - #discard_callbacks = /* @__PURE__ */ new Set(); - /** - * The number of async effects that are currently in flight - */ - #pending = 0; - /** - * The number of async effects that are currently in flight, _not_ inside a pending boundary - */ - #blocking_pending = 0; - /** - * A deferred that resolves when the batch is committed, used with `settled()` - * TODO replace with Promise.withResolvers once supported widely enough - * @type {{ promise: Promise, resolve: (value?: any) => void, reject: (reason: unknown) => void } | null} - */ - #deferred = null; - /** - * Deferred effects (which run after async work has completed) that are DIRTY - * @type {Set} - */ - #dirty_effects = /* @__PURE__ */ new Set(); - /** - * Deferred effects that are MAYBE_DIRTY - * @type {Set} - */ - #maybe_dirty_effects = /* @__PURE__ */ new Set(); - /** - * A map of branches that still exist, but will be destroyed when this batch - * is committed — we skip over these during `process`. - * The value contains child effects that were dirty/maybe_dirty before being reset, - * so they can be rescheduled if the branch survives. - * @type {Map} - */ - #skipped_branches = /* @__PURE__ */ new Map(); - is_fork = false; - #decrement_queued = false; - #is_deferred() { - return this.is_fork || this.#blocking_pending > 0; - } - /** - * Add an effect to the #skipped_branches map and reset its children - * @param {Effect} effect - */ - skip_effect(effect) { - if (!this.#skipped_branches.has(effect)) { - this.#skipped_branches.set(effect, { d: [], m: [] }); - } - } - /** - * Remove an effect from the #skipped_branches map and reschedule - * any tracked dirty/maybe_dirty child effects - * @param {Effect} effect - */ - unskip_effect(effect) { - var tracked = this.#skipped_branches.get(effect); - if (tracked) { - this.#skipped_branches.delete(effect); - for (var e of tracked.d) { - set_signal_status(e, DIRTY); - schedule_effect(e); - } - for (e of tracked.m) { - set_signal_status(e, MAYBE_DIRTY); - schedule_effect(e); - } - } - } - /** - * - * @param {Effect[]} root_effects - */ - process(root_effects) { - queued_root_effects = []; - this.apply(); - var effects = []; - var render_effects = []; - for (const root2 of root_effects) { - this.#traverse_effect_tree(root2, effects, render_effects); - } - if (this.#is_deferred()) { - this.#defer_effects(render_effects); - this.#defer_effects(effects); - for (const [e, t] of this.#skipped_branches) { - reset_branch(e, t); - } - } else { - for (const fn of this.#commit_callbacks) fn(); - this.#commit_callbacks.clear(); - if (this.#pending === 0) { - this.#commit(); - } - current_batch = null; - flush_queued_effects(render_effects); - flush_queued_effects(effects); - this.#dirty_effects.clear(); - this.#maybe_dirty_effects.clear(); - this.#deferred?.resolve(); - } - batch_values = null; - } - /** - * Traverse the effect tree, executing effects or stashing - * them for later execution as appropriate - * @param {Effect} root - * @param {Effect[]} effects - * @param {Effect[]} render_effects - */ - #traverse_effect_tree(root2, effects, render_effects) { - root2.f ^= CLEAN; - var effect = root2.first; - while (effect !== null) { - var flags2 = effect.f; - var is_branch = (flags2 & (BRANCH_EFFECT | ROOT_EFFECT)) !== 0; - var is_skippable_branch = is_branch && (flags2 & CLEAN) !== 0; - var skip = is_skippable_branch || (flags2 & INERT) !== 0 || this.#skipped_branches.has(effect); - if (!skip && effect.fn !== null) { - if (is_branch) { - effect.f ^= CLEAN; - } else if ((flags2 & EFFECT) !== 0) { - effects.push(effect); - } else if (is_dirty(effect)) { - if ((flags2 & BLOCK_EFFECT) !== 0) this.#maybe_dirty_effects.add(effect); - update_effect(effect); - } - var child = effect.first; - if (child !== null) { - effect = child; - continue; - } - } - while (effect !== null) { - var next2 = effect.next; - if (next2 !== null) { - effect = next2; - break; - } - effect = effect.parent; - } - } - } - /** - * @param {Effect[]} effects - */ - #defer_effects(effects) { - for (var i = 0; i < effects.length; i += 1) { - defer_effect(effects[i], this.#dirty_effects, this.#maybe_dirty_effects); - } - } - /** - * Associate a change to a given source with the current - * batch, noting its previous and current values - * @param {Source} source - * @param {any} value - */ - capture(source2, value) { - if (value !== UNINITIALIZED && !this.previous.has(source2)) { - this.previous.set(source2, value); - } - if ((source2.f & ERROR_VALUE) === 0) { - this.current.set(source2, source2.v); - batch_values?.set(source2, source2.v); - } - } - activate() { - current_batch = this; - this.apply(); - } - deactivate() { - if (current_batch !== this) return; - current_batch = null; - batch_values = null; - } - flush() { - this.activate(); - if (queued_root_effects.length > 0) { - flush_effects(); - if (current_batch !== null && current_batch !== this) { - return; - } - } else if (this.#pending === 0) { - this.process([]); - } - this.deactivate(); - } - discard() { - for (const fn of this.#discard_callbacks) fn(this); - this.#discard_callbacks.clear(); - } - #commit() { - if (batches.size > 1) { - this.previous.clear(); - var previous_batch_values = batch_values; - var is_earlier = true; - for (const batch of batches) { - if (batch === this) { - is_earlier = false; - continue; - } - const sources = []; - for (const [source2, value] of this.current) { - if (batch.current.has(source2)) { - if (is_earlier && value !== batch.current.get(source2)) { - batch.current.set(source2, value); - } else { - continue; - } - } - sources.push(source2); - } - if (sources.length === 0) { - continue; - } - const others = [...batch.current.keys()].filter((s) => !this.current.has(s)); - if (others.length > 0) { - var prev_queued_root_effects = queued_root_effects; - queued_root_effects = []; - const marked = /* @__PURE__ */ new Set(); - const checked = /* @__PURE__ */ new Map(); - for (const source2 of sources) { - mark_effects(source2, others, marked, checked); - } - if (queued_root_effects.length > 0) { - current_batch = batch; - batch.apply(); - for (const root2 of queued_root_effects) { - batch.#traverse_effect_tree(root2, [], []); - } - batch.deactivate(); - } - queued_root_effects = prev_queued_root_effects; - } - } - current_batch = null; - batch_values = previous_batch_values; - } - this.#skipped_branches.clear(); - batches.delete(this); - } - /** - * - * @param {boolean} blocking - */ - increment(blocking) { - this.#pending += 1; - if (blocking) this.#blocking_pending += 1; - } - /** - * - * @param {boolean} blocking - */ - decrement(blocking) { - this.#pending -= 1; - if (blocking) this.#blocking_pending -= 1; - if (this.#decrement_queued) return; - this.#decrement_queued = true; - queue_micro_task(() => { - this.#decrement_queued = false; - if (!this.#is_deferred()) { - this.revive(); - } else if (queued_root_effects.length > 0) { - this.flush(); - } - }); - } - revive() { - for (const e of this.#dirty_effects) { - this.#maybe_dirty_effects.delete(e); - set_signal_status(e, DIRTY); - schedule_effect(e); - } - for (const e of this.#maybe_dirty_effects) { - set_signal_status(e, MAYBE_DIRTY); - schedule_effect(e); - } - this.flush(); - } - /** @param {() => void} fn */ - oncommit(fn) { - this.#commit_callbacks.add(fn); - } - /** @param {(batch: Batch) => void} fn */ - ondiscard(fn) { - this.#discard_callbacks.add(fn); - } - settled() { - return (this.#deferred ??= deferred()).promise; - } - static ensure() { - if (current_batch === null) { - const batch = current_batch = new Batch(); - batches.add(current_batch); - if (!is_flushing_sync) { - queue_micro_task(() => { - if (current_batch !== batch) { - return; - } - batch.flush(); - }); - } - } - return current_batch; - } - apply() { - return; - } -} -function flushSync(fn) { - var was_flushing_sync = is_flushing_sync; - is_flushing_sync = true; - try { - var result; - if (fn) ; - while (true) { - flush_tasks(); - if (queued_root_effects.length === 0) { - current_batch?.flush(); - if (queued_root_effects.length === 0) { - last_scheduled_effect = null; - return ( - /** @type {T} */ - result - ); - } - } - flush_effects(); - } - } finally { - is_flushing_sync = was_flushing_sync; - } -} -function flush_effects() { - is_flushing = true; - var source_stacks = null; - try { - var flush_count = 0; - while (queued_root_effects.length > 0) { - var batch = Batch.ensure(); - if (flush_count++ > 1e3) { - var updates, entry; - if (DEV) ; - infinite_loop_guard(); - } - batch.process(queued_root_effects); - old_values.clear(); - if (DEV) ; - } - } finally { - queued_root_effects = []; - is_flushing = false; - last_scheduled_effect = null; - } -} -function infinite_loop_guard() { - try { - effect_update_depth_exceeded(); - } catch (error) { - invoke_error_boundary(error, last_scheduled_effect); - } -} -let eager_block_effects = null; -function flush_queued_effects(effects) { - var length = effects.length; - if (length === 0) return; - var i = 0; - while (i < length) { - var effect = effects[i++]; - if ((effect.f & (DESTROYED | INERT)) === 0 && is_dirty(effect)) { - eager_block_effects = /* @__PURE__ */ new Set(); - update_effect(effect); - if (effect.deps === null && effect.first === null && effect.nodes === null && effect.teardown === null && effect.ac === null) { - unlink_effect(effect); - } - if (eager_block_effects?.size > 0) { - old_values.clear(); - for (const e of eager_block_effects) { - if ((e.f & (DESTROYED | INERT)) !== 0) continue; - const ordered_effects = [e]; - let ancestor = e.parent; - while (ancestor !== null) { - if (eager_block_effects.has(ancestor)) { - eager_block_effects.delete(ancestor); - ordered_effects.push(ancestor); - } - ancestor = ancestor.parent; - } - for (let j = ordered_effects.length - 1; j >= 0; j--) { - const e2 = ordered_effects[j]; - if ((e2.f & (DESTROYED | INERT)) !== 0) continue; - update_effect(e2); - } - } - eager_block_effects.clear(); - } - } - } - eager_block_effects = null; -} -function mark_effects(value, sources, marked, checked) { - if (marked.has(value)) return; - marked.add(value); - if (value.reactions !== null) { - for (const reaction of value.reactions) { - const flags2 = reaction.f; - if ((flags2 & DERIVED) !== 0) { - mark_effects( - /** @type {Derived} */ - reaction, - sources, - marked, - checked - ); - } else if ((flags2 & (ASYNC | BLOCK_EFFECT)) !== 0 && (flags2 & DIRTY) === 0 && depends_on(reaction, sources, checked)) { - set_signal_status(reaction, DIRTY); - schedule_effect( - /** @type {Effect} */ - reaction - ); - } - } - } -} -function depends_on(reaction, sources, checked) { - const depends = checked.get(reaction); - if (depends !== void 0) return depends; - if (reaction.deps !== null) { - for (const dep of reaction.deps) { - if (includes.call(sources, dep)) { - return true; - } - if ((dep.f & DERIVED) !== 0 && depends_on( - /** @type {Derived} */ - dep, - sources, - checked - )) { - checked.set( - /** @type {Derived} */ - dep, - true - ); - return true; - } - } - } - checked.set(reaction, false); - return false; -} -function schedule_effect(signal) { - var effect = last_scheduled_effect = signal; - var boundary2 = effect.b; - if (boundary2?.is_pending && (signal.f & (EFFECT | RENDER_EFFECT | MANAGED_EFFECT)) !== 0 && (signal.f & REACTION_RAN) === 0) { - boundary2.defer_effect(signal); - return; - } - while (effect.parent !== null) { - effect = effect.parent; - var flags2 = effect.f; - if (is_flushing && effect === active_effect && (flags2 & BLOCK_EFFECT) !== 0 && (flags2 & HEAD_EFFECT) === 0 && (flags2 & REACTION_RAN) !== 0) { - return; - } - if ((flags2 & (ROOT_EFFECT | BRANCH_EFFECT)) !== 0) { - if ((flags2 & CLEAN) === 0) { - return; - } - effect.f ^= CLEAN; - } - } - queued_root_effects.push(effect); -} -function reset_branch(effect, tracked) { - if ((effect.f & BRANCH_EFFECT) !== 0 && (effect.f & CLEAN) !== 0) { - return; - } - if ((effect.f & DIRTY) !== 0) { - tracked.d.push(effect); - } else if ((effect.f & MAYBE_DIRTY) !== 0) { - tracked.m.push(effect); - } - set_signal_status(effect, CLEAN); - var e = effect.first; - while (e !== null) { - reset_branch(e, tracked); - e = e.next; - } -} -function createSubscriber(start) { - let subscribers = 0; - let version = source(0); - let stop; - return () => { - if (effect_tracking()) { - get(version); - render_effect(() => { - if (subscribers === 0) { - stop = untrack(() => start(() => increment(version))); - } - subscribers += 1; - return () => { - queue_micro_task(() => { - subscribers -= 1; - if (subscribers === 0) { - stop?.(); - stop = void 0; - increment(version); - } - }); - }; - }); - } - }; -} -var flags = EFFECT_TRANSPARENT | EFFECT_PRESERVED; -function boundary(node, props, children, transform_error) { - new Boundary(node, props, children, transform_error); -} -class Boundary { - /** @type {Boundary | null} */ - parent; - is_pending = false; - /** - * API-level transformError transform function. Transforms errors before they reach the `failed` snippet. - * Inherited from parent boundary, or defaults to identity. - * @type {(error: unknown) => unknown} - */ - transform_error; - /** @type {TemplateNode} */ - #anchor; - /** @type {TemplateNode | null} */ - #hydrate_open = hydrating ? hydrate_node : null; - /** @type {BoundaryProps} */ - #props; - /** @type {((anchor: Node) => void)} */ - #children; - /** @type {Effect} */ - #effect; - /** @type {Effect | null} */ - #main_effect = null; - /** @type {Effect | null} */ - #pending_effect = null; - /** @type {Effect | null} */ - #failed_effect = null; - /** @type {DocumentFragment | null} */ - #offscreen_fragment = null; - #local_pending_count = 0; - #pending_count = 0; - #pending_count_update_queued = false; - /** @type {Set} */ - #dirty_effects = /* @__PURE__ */ new Set(); - /** @type {Set} */ - #maybe_dirty_effects = /* @__PURE__ */ new Set(); - /** - * A source containing the number of pending async deriveds/expressions. - * Only created if `$effect.pending()` is used inside the boundary, - * otherwise updating the source results in needless `Batch.ensure()` - * calls followed by no-op flushes - * @type {Source | null} - */ - #effect_pending = null; - #effect_pending_subscriber = createSubscriber(() => { - this.#effect_pending = source(this.#local_pending_count); - return () => { - this.#effect_pending = null; - }; - }); - /** - * @param {TemplateNode} node - * @param {BoundaryProps} props - * @param {((anchor: Node) => void)} children - * @param {((error: unknown) => unknown) | undefined} [transform_error] - */ - constructor(node, props, children, transform_error) { - this.#anchor = node; - this.#props = props; - this.#children = (anchor) => { - var effect = ( - /** @type {Effect} */ - active_effect - ); - effect.b = this; - effect.f |= BOUNDARY_EFFECT; - children(anchor); - }; - this.parent = /** @type {Effect} */ - active_effect.b; - this.transform_error = transform_error ?? this.parent?.transform_error ?? ((e) => e); - this.#effect = block(() => { - if (hydrating) { - const comment = ( - /** @type {Comment} */ - this.#hydrate_open - ); - hydrate_next(); - const server_rendered_pending = comment.data === HYDRATION_START_ELSE; - const server_rendered_failed = comment.data.startsWith(HYDRATION_START_FAILED); - if (server_rendered_failed) { - const serialized_error = JSON.parse(comment.data.slice(HYDRATION_START_FAILED.length)); - this.#hydrate_failed_content(serialized_error); - } else if (server_rendered_pending) { - this.#hydrate_pending_content(); - } else { - this.#hydrate_resolved_content(); - } - } else { - this.#render(); - } - }, flags); - if (hydrating) { - this.#anchor = hydrate_node; - } - } - #hydrate_resolved_content() { - try { - this.#main_effect = branch(() => this.#children(this.#anchor)); - } catch (error) { - this.error(error); - } - } - /** - * @param {unknown} error The deserialized error from the server's hydration comment - */ - #hydrate_failed_content(error) { - const failed = this.#props.failed; - if (!failed) return; - this.#failed_effect = branch(() => { - failed( - this.#anchor, - () => error, - () => () => { - } - ); - }); - } - #hydrate_pending_content() { - const pending = this.#props.pending; - if (!pending) return; - this.is_pending = true; - this.#pending_effect = branch(() => pending(this.#anchor)); - queue_micro_task(() => { - var fragment = this.#offscreen_fragment = document.createDocumentFragment(); - var anchor = create_text(); - fragment.append(anchor); - this.#main_effect = this.#run(() => { - Batch.ensure(); - return branch(() => this.#children(anchor)); - }); - if (this.#pending_count === 0) { - this.#anchor.before(fragment); - this.#offscreen_fragment = null; - pause_effect( - /** @type {Effect} */ - this.#pending_effect, - () => { - this.#pending_effect = null; - } - ); - this.#resolve(); - } - }); - } - #render() { - try { - this.is_pending = this.has_pending_snippet(); - this.#pending_count = 0; - this.#local_pending_count = 0; - this.#main_effect = branch(() => { - this.#children(this.#anchor); - }); - if (this.#pending_count > 0) { - var fragment = this.#offscreen_fragment = document.createDocumentFragment(); - move_effect(this.#main_effect, fragment); - const pending = ( - /** @type {(anchor: Node) => void} */ - this.#props.pending - ); - this.#pending_effect = branch(() => pending(this.#anchor)); - } else { - this.#resolve(); - } - } catch (error) { - this.error(error); - } - } - #resolve() { - this.is_pending = false; - for (const e of this.#dirty_effects) { - set_signal_status(e, DIRTY); - schedule_effect(e); - } - for (const e of this.#maybe_dirty_effects) { - set_signal_status(e, MAYBE_DIRTY); - schedule_effect(e); - } - this.#dirty_effects.clear(); - this.#maybe_dirty_effects.clear(); - } - /** - * Defer an effect inside a pending boundary until the boundary resolves - * @param {Effect} effect - */ - defer_effect(effect) { - defer_effect(effect, this.#dirty_effects, this.#maybe_dirty_effects); - } - /** - * Returns `false` if the effect exists inside a boundary whose pending snippet is shown - * @returns {boolean} - */ - is_rendered() { - return !this.is_pending && (!this.parent || this.parent.is_rendered()); - } - has_pending_snippet() { - return !!this.#props.pending; - } - /** - * @template T - * @param {() => T} fn - */ - #run(fn) { - var previous_effect = active_effect; - var previous_reaction = active_reaction; - var previous_ctx = component_context; - set_active_effect(this.#effect); - set_active_reaction(this.#effect); - set_component_context(this.#effect.ctx); - try { - return fn(); - } catch (e) { - handle_error(e); - return null; - } finally { - set_active_effect(previous_effect); - set_active_reaction(previous_reaction); - set_component_context(previous_ctx); - } - } - /** - * Updates the pending count associated with the currently visible pending snippet, - * if any, such that we can replace the snippet with content once work is done - * @param {1 | -1} d - */ - #update_pending_count(d) { - if (!this.has_pending_snippet()) { - if (this.parent) { - this.parent.#update_pending_count(d); - } - return; - } - this.#pending_count += d; - if (this.#pending_count === 0) { - this.#resolve(); - if (this.#pending_effect) { - pause_effect(this.#pending_effect, () => { - this.#pending_effect = null; - }); - } - if (this.#offscreen_fragment) { - this.#anchor.before(this.#offscreen_fragment); - this.#offscreen_fragment = null; - } - } - } - /** - * Update the source that powers `$effect.pending()` inside this boundary, - * and controls when the current `pending` snippet (if any) is removed. - * Do not call from inside the class - * @param {1 | -1} d - */ - update_pending_count(d) { - this.#update_pending_count(d); - this.#local_pending_count += d; - if (!this.#effect_pending || this.#pending_count_update_queued) return; - this.#pending_count_update_queued = true; - queue_micro_task(() => { - this.#pending_count_update_queued = false; - if (this.#effect_pending) { - internal_set(this.#effect_pending, this.#local_pending_count); - } - }); - } - get_effect_pending() { - this.#effect_pending_subscriber(); - return get( - /** @type {Source} */ - this.#effect_pending - ); - } - /** @param {unknown} error */ - error(error) { - var onerror = this.#props.onerror; - let failed = this.#props.failed; - if (!onerror && !failed) { - throw error; - } - if (this.#main_effect) { - destroy_effect(this.#main_effect); - this.#main_effect = null; - } - if (this.#pending_effect) { - destroy_effect(this.#pending_effect); - this.#pending_effect = null; - } - if (this.#failed_effect) { - destroy_effect(this.#failed_effect); - this.#failed_effect = null; - } - if (hydrating) { - set_hydrate_node( - /** @type {TemplateNode} */ - this.#hydrate_open - ); - next(); - set_hydrate_node(skip_nodes()); - } - var did_reset = false; - var calling_on_error = false; - const reset = () => { - if (did_reset) { - svelte_boundary_reset_noop(); - return; - } - did_reset = true; - if (calling_on_error) { - svelte_boundary_reset_onerror(); - } - if (this.#failed_effect !== null) { - pause_effect(this.#failed_effect, () => { - this.#failed_effect = null; - }); - } - this.#run(() => { - Batch.ensure(); - this.#render(); - }); - }; - const handle_error_result = (transformed_error) => { - try { - calling_on_error = true; - onerror?.(transformed_error, reset); - calling_on_error = false; - } catch (error2) { - invoke_error_boundary(error2, this.#effect && this.#effect.parent); - } - if (failed) { - this.#failed_effect = this.#run(() => { - Batch.ensure(); - try { - return branch(() => { - var effect = ( - /** @type {Effect} */ - active_effect - ); - effect.b = this; - effect.f |= BOUNDARY_EFFECT; - failed( - this.#anchor, - () => transformed_error, - () => reset - ); - }); - } catch (error2) { - invoke_error_boundary( - error2, - /** @type {Effect} */ - this.#effect.parent - ); - return null; - } - }); - } - }; - queue_micro_task(() => { - var result; - try { - result = this.transform_error(error); - } catch (e) { - invoke_error_boundary(e, this.#effect && this.#effect.parent); - return; - } - if (result !== null && typeof result === "object" && typeof /** @type {any} */ - result.then === "function") { - result.then( - handle_error_result, - /** @param {unknown} e */ - (e) => invoke_error_boundary(e, this.#effect && this.#effect.parent) - ); - } else { - handle_error_result(result); - } - }); - } -} -function destroy_derived_effects(derived2) { - var effects = derived2.effects; - if (effects !== null) { - derived2.effects = null; - for (var i = 0; i < effects.length; i += 1) { - destroy_effect( - /** @type {Effect} */ - effects[i] - ); - } - } -} -function get_derived_parent_effect(derived2) { - var parent = derived2.parent; - while (parent !== null) { - if ((parent.f & DERIVED) === 0) { - return (parent.f & DESTROYED) === 0 ? ( - /** @type {Effect} */ - parent - ) : null; - } - parent = parent.parent; - } - return null; -} -function execute_derived(derived2) { - var value; - var prev_active_effect = active_effect; - set_active_effect(get_derived_parent_effect(derived2)); - { - try { - derived2.f &= ~WAS_MARKED; - destroy_derived_effects(derived2); - value = update_reaction(derived2); - } finally { - set_active_effect(prev_active_effect); - } - } - return value; -} -function update_derived(derived2) { - var value = execute_derived(derived2); - if (!derived2.equals(value)) { - derived2.wv = increment_write_version(); - if (!current_batch?.is_fork || derived2.deps === null) { - derived2.v = value; - if (derived2.deps === null) { - set_signal_status(derived2, CLEAN); - return; - } - } - } - if (is_destroying_effect) { - return; - } - if (batch_values !== null) { - if (effect_tracking() || current_batch?.is_fork) { - batch_values.set(derived2, value); - } - } else { - update_derived_status(derived2); - } -} -function freeze_derived_effects(derived2) { - if (derived2.effects === null) return; - for (const e of derived2.effects) { - if (e.teardown || e.ac) { - e.teardown?.(); - e.ac?.abort(STALE_REACTION); - e.teardown = noop; - e.ac = null; - remove_reactions(e, 0); - destroy_effect_children(e); - } - } -} -function unfreeze_derived_effects(derived2) { - if (derived2.effects === null) return; - for (const e of derived2.effects) { - if (e.teardown) { - update_effect(e); - } - } -} -let eager_effects = /* @__PURE__ */ new Set(); -const old_values = /* @__PURE__ */ new Map(); -let eager_effects_deferred = false; -function source(v, stack) { - var signal = { - f: 0, - // TODO ideally we could skip this altogether, but it causes type errors - v, - reactions: null, - equals, - rv: 0, - wv: 0 - }; - return signal; -} -// @__NO_SIDE_EFFECTS__ -function state(v, stack) { - const s = source(v); - push_reaction_value(s); - return s; -} -// @__NO_SIDE_EFFECTS__ -function mutable_source(initial_value, immutable = false, trackable = true) { - const s = source(initial_value); - if (!immutable) { - s.equals = safe_equals; - } - return s; -} -function set(source2, value, should_proxy = false) { - if (active_reaction !== null && // since we are untracking the function inside `$inspect.with` we need to add this check - // to ensure we error if state is set inside an inspect effect - (!untracking || (active_reaction.f & EAGER_EFFECT) !== 0) && is_runes() && (active_reaction.f & (DERIVED | BLOCK_EFFECT | ASYNC | EAGER_EFFECT)) !== 0 && (current_sources === null || !includes.call(current_sources, source2))) { - state_unsafe_mutation(); - } - let new_value = should_proxy ? proxy(value) : value; - return internal_set(source2, new_value); -} -function internal_set(source2, value) { - if (!source2.equals(value)) { - var old_value = source2.v; - if (is_destroying_effect) { - old_values.set(source2, value); - } else { - old_values.set(source2, old_value); - } - source2.v = value; - var batch = Batch.ensure(); - batch.capture(source2, old_value); - if ((source2.f & DERIVED) !== 0) { - const derived2 = ( - /** @type {Derived} */ - source2 - ); - if ((source2.f & DIRTY) !== 0) { - execute_derived(derived2); - } - update_derived_status(derived2); - } - source2.wv = increment_write_version(); - mark_reactions(source2, DIRTY); - if (active_effect !== null && (active_effect.f & CLEAN) !== 0 && (active_effect.f & (BRANCH_EFFECT | ROOT_EFFECT)) === 0) { - if (untracked_writes === null) { - set_untracked_writes([source2]); - } else { - untracked_writes.push(source2); - } - } - if (!batch.is_fork && eager_effects.size > 0 && !eager_effects_deferred) { - flush_eager_effects(); - } - } - return value; -} -function flush_eager_effects() { - eager_effects_deferred = false; - for (const effect of eager_effects) { - if ((effect.f & CLEAN) !== 0) { - set_signal_status(effect, MAYBE_DIRTY); - } - if (is_dirty(effect)) { - update_effect(effect); - } - } - eager_effects.clear(); -} -function increment(source2) { - set(source2, source2.v + 1); -} -function mark_reactions(signal, status) { - var reactions = signal.reactions; - if (reactions === null) return; - var length = reactions.length; - for (var i = 0; i < length; i++) { - var reaction = reactions[i]; - var flags2 = reaction.f; - var not_dirty = (flags2 & DIRTY) === 0; - if (not_dirty) { - set_signal_status(reaction, status); - } - if ((flags2 & DERIVED) !== 0) { - var derived2 = ( - /** @type {Derived} */ - reaction - ); - batch_values?.delete(derived2); - if ((flags2 & WAS_MARKED) === 0) { - if (flags2 & CONNECTED) { - reaction.f |= WAS_MARKED; - } - mark_reactions(derived2, MAYBE_DIRTY); - } - } else if (not_dirty) { - if ((flags2 & BLOCK_EFFECT) !== 0 && eager_block_effects !== null) { - eager_block_effects.add( - /** @type {Effect} */ - reaction - ); - } - schedule_effect( - /** @type {Effect} */ - reaction - ); - } - } -} -function proxy(value) { - if (typeof value !== "object" || value === null || STATE_SYMBOL in value) { - return value; - } - const prototype = get_prototype_of(value); - if (prototype !== object_prototype && prototype !== array_prototype) { - return value; - } - var sources = /* @__PURE__ */ new Map(); - var is_proxied_array = is_array(value); - var version = /* @__PURE__ */ state(0); - var parent_version = update_version; - var with_parent = (fn) => { - if (update_version === parent_version) { - return fn(); - } - var reaction = active_reaction; - var version2 = update_version; - set_active_reaction(null); - set_update_version(parent_version); - var result = fn(); - set_active_reaction(reaction); - set_update_version(version2); - return result; - }; - if (is_proxied_array) { - sources.set("length", /* @__PURE__ */ state( - /** @type {any[]} */ - value.length - )); - } - return new Proxy( - /** @type {any} */ - value, - { - defineProperty(_, prop, descriptor) { - if (!("value" in descriptor) || descriptor.configurable === false || descriptor.enumerable === false || descriptor.writable === false) { - state_descriptors_fixed(); - } - var s = sources.get(prop); - if (s === void 0) { - with_parent(() => { - var s2 = /* @__PURE__ */ state(descriptor.value); - sources.set(prop, s2); - return s2; - }); - } else { - set(s, descriptor.value, true); - } - return true; - }, - deleteProperty(target, prop) { - var s = sources.get(prop); - if (s === void 0) { - if (prop in target) { - const s2 = with_parent(() => /* @__PURE__ */ state(UNINITIALIZED)); - sources.set(prop, s2); - increment(version); - } - } else { - set(s, UNINITIALIZED); - increment(version); - } - return true; - }, - get(target, prop, receiver) { - if (prop === STATE_SYMBOL) { - return value; - } - var s = sources.get(prop); - var exists = prop in target; - if (s === void 0 && (!exists || get_descriptor(target, prop)?.writable)) { - s = with_parent(() => { - var p = proxy(exists ? target[prop] : UNINITIALIZED); - var s2 = /* @__PURE__ */ state(p); - return s2; - }); - sources.set(prop, s); - } - if (s !== void 0) { - var v = get(s); - return v === UNINITIALIZED ? void 0 : v; - } - return Reflect.get(target, prop, receiver); - }, - getOwnPropertyDescriptor(target, prop) { - var descriptor = Reflect.getOwnPropertyDescriptor(target, prop); - if (descriptor && "value" in descriptor) { - var s = sources.get(prop); - if (s) descriptor.value = get(s); - } else if (descriptor === void 0) { - var source2 = sources.get(prop); - var value2 = source2?.v; - if (source2 !== void 0 && value2 !== UNINITIALIZED) { - return { - enumerable: true, - configurable: true, - value: value2, - writable: true - }; - } - } - return descriptor; - }, - has(target, prop) { - if (prop === STATE_SYMBOL) { - return true; - } - var s = sources.get(prop); - var has = s !== void 0 && s.v !== UNINITIALIZED || Reflect.has(target, prop); - if (s !== void 0 || active_effect !== null && (!has || get_descriptor(target, prop)?.writable)) { - if (s === void 0) { - s = with_parent(() => { - var p = has ? proxy(target[prop]) : UNINITIALIZED; - var s2 = /* @__PURE__ */ state(p); - return s2; - }); - sources.set(prop, s); - } - var value2 = get(s); - if (value2 === UNINITIALIZED) { - return false; - } - } - return has; - }, - set(target, prop, value2, receiver) { - var s = sources.get(prop); - var has = prop in target; - if (is_proxied_array && prop === "length") { - for (var i = value2; i < /** @type {Source} */ - s.v; i += 1) { - var other_s = sources.get(i + ""); - if (other_s !== void 0) { - set(other_s, UNINITIALIZED); - } else if (i in target) { - other_s = with_parent(() => /* @__PURE__ */ state(UNINITIALIZED)); - sources.set(i + "", other_s); - } - } - } - if (s === void 0) { - if (!has || get_descriptor(target, prop)?.writable) { - s = with_parent(() => /* @__PURE__ */ state(void 0)); - set(s, proxy(value2)); - sources.set(prop, s); - } - } else { - has = s.v !== UNINITIALIZED; - var p = with_parent(() => proxy(value2)); - set(s, p); - } - var descriptor = Reflect.getOwnPropertyDescriptor(target, prop); - if (descriptor?.set) { - descriptor.set.call(receiver, value2); - } - if (!has) { - if (is_proxied_array && typeof prop === "string") { - var ls = ( - /** @type {Source} */ - sources.get("length") - ); - var n = Number(prop); - if (Number.isInteger(n) && n >= ls.v) { - set(ls, n + 1); - } - } - increment(version); - } - return true; - }, - ownKeys(target) { - get(version); - var own_keys = Reflect.ownKeys(target).filter((key2) => { - var source3 = sources.get(key2); - return source3 === void 0 || source3.v !== UNINITIALIZED; - }); - for (var [key, source2] of sources) { - if (source2.v !== UNINITIALIZED && !(key in target)) { - own_keys.push(key); - } - } - return own_keys; - }, - setPrototypeOf() { - state_prototype_fixed(); - } - } - ); -} -var $window; -var first_child_getter; -var next_sibling_getter; -function init_operations() { - if ($window !== void 0) { - return; - } - $window = window; - var element_prototype = Element.prototype; - var node_prototype = Node.prototype; - var text_prototype = Text.prototype; - first_child_getter = get_descriptor(node_prototype, "firstChild").get; - next_sibling_getter = get_descriptor(node_prototype, "nextSibling").get; - if (is_extensible(element_prototype)) { - element_prototype.__click = void 0; - element_prototype.__className = void 0; - element_prototype.__attributes = null; - element_prototype.__style = void 0; - element_prototype.__e = void 0; - } - if (is_extensible(text_prototype)) { - text_prototype.__t = void 0; - } -} -function create_text(value = "") { - return document.createTextNode(value); -} -// @__NO_SIDE_EFFECTS__ -function get_first_child(node) { - return ( - /** @type {TemplateNode | null} */ - first_child_getter.call(node) - ); -} -// @__NO_SIDE_EFFECTS__ -function get_next_sibling(node) { - return ( - /** @type {TemplateNode | null} */ - next_sibling_getter.call(node) - ); -} -function clear_text_content(node) { - node.textContent = ""; -} -function without_reactive_context(fn) { - var previous_reaction = active_reaction; - var previous_effect = active_effect; - set_active_reaction(null); - set_active_effect(null); - try { - return fn(); - } finally { - set_active_reaction(previous_reaction); - set_active_effect(previous_effect); - } -} -function push_effect(effect, parent_effect) { - var parent_last = parent_effect.last; - if (parent_last === null) { - parent_effect.last = parent_effect.first = effect; - } else { - parent_last.next = effect; - effect.prev = parent_last; - parent_effect.last = effect; - } -} -function create_effect(type, fn, sync) { - var parent = active_effect; - if (parent !== null && (parent.f & INERT) !== 0) { - type |= INERT; - } - var effect = { - ctx: component_context, - deps: null, - nodes: null, - f: type | DIRTY | CONNECTED, - first: null, - fn, - last: null, - next: null, - parent, - b: parent && parent.b, - prev: null, - teardown: null, - wv: 0, - ac: null - }; - if (sync) { - try { - update_effect(effect); - } catch (e2) { - destroy_effect(effect); - throw e2; - } - } else if (fn !== null) { - schedule_effect(effect); - } - var e = effect; - if (sync && e.deps === null && e.teardown === null && e.nodes === null && e.first === e.last && // either `null`, or a singular child - (e.f & EFFECT_PRESERVED) === 0) { - e = e.first; - if ((type & BLOCK_EFFECT) !== 0 && (type & EFFECT_TRANSPARENT) !== 0 && e !== null) { - e.f |= EFFECT_TRANSPARENT; - } - } - if (e !== null) { - e.parent = parent; - if (parent !== null) { - push_effect(e, parent); - } - if (active_reaction !== null && (active_reaction.f & DERIVED) !== 0 && (type & ROOT_EFFECT) === 0) { - var derived2 = ( - /** @type {Derived} */ - active_reaction - ); - (derived2.effects ??= []).push(e); - } - } - return effect; -} -function effect_tracking() { - return active_reaction !== null && !untracking; -} -function create_user_effect(fn) { - return create_effect(EFFECT | USER_EFFECT, fn, false); -} -function component_root(fn) { - Batch.ensure(); - const effect = create_effect(ROOT_EFFECT | EFFECT_PRESERVED, fn, true); - return (options = {}) => { - return new Promise((fulfil) => { - if (options.outro) { - pause_effect(effect, () => { - destroy_effect(effect); - fulfil(void 0); - }); - } else { - destroy_effect(effect); - fulfil(void 0); - } - }); - }; -} -function render_effect(fn, flags2 = 0) { - return create_effect(RENDER_EFFECT | flags2, fn, true); -} -function block(fn, flags2 = 0) { - var effect = create_effect(BLOCK_EFFECT | flags2, fn, true); - return effect; -} -function branch(fn) { - return create_effect(BRANCH_EFFECT | EFFECT_PRESERVED, fn, true); -} -function execute_effect_teardown(effect) { - var teardown = effect.teardown; - if (teardown !== null) { - const previously_destroying_effect = is_destroying_effect; - const previous_reaction = active_reaction; - set_is_destroying_effect(true); - set_active_reaction(null); - try { - teardown.call(null); - } finally { - set_is_destroying_effect(previously_destroying_effect); - set_active_reaction(previous_reaction); - } - } -} -function destroy_effect_children(signal, remove_dom = false) { - var effect = signal.first; - signal.first = signal.last = null; - while (effect !== null) { - const controller = effect.ac; - if (controller !== null) { - without_reactive_context(() => { - controller.abort(STALE_REACTION); - }); - } - var next2 = effect.next; - if ((effect.f & ROOT_EFFECT) !== 0) { - effect.parent = null; - } else { - destroy_effect(effect, remove_dom); - } - effect = next2; - } -} -function destroy_block_effect_children(signal) { - var effect = signal.first; - while (effect !== null) { - var next2 = effect.next; - if ((effect.f & BRANCH_EFFECT) === 0) { - destroy_effect(effect); - } - effect = next2; - } -} -function destroy_effect(effect, remove_dom = true) { - var removed = false; - if ((remove_dom || (effect.f & HEAD_EFFECT) !== 0) && effect.nodes !== null && effect.nodes.end !== null) { - remove_effect_dom( - effect.nodes.start, - /** @type {TemplateNode} */ - effect.nodes.end - ); - removed = true; - } - destroy_effect_children(effect, remove_dom && !removed); - remove_reactions(effect, 0); - set_signal_status(effect, DESTROYED); - var transitions = effect.nodes && effect.nodes.t; - if (transitions !== null) { - for (const transition of transitions) { - transition.stop(); - } - } - execute_effect_teardown(effect); - var parent = effect.parent; - if (parent !== null && parent.first !== null) { - unlink_effect(effect); - } - effect.next = effect.prev = effect.teardown = effect.ctx = effect.deps = effect.fn = effect.nodes = effect.ac = null; -} -function remove_effect_dom(node, end) { - while (node !== null) { - var next2 = node === end ? null : /* @__PURE__ */ get_next_sibling(node); - node.remove(); - node = next2; - } -} -function unlink_effect(effect) { - var parent = effect.parent; - var prev = effect.prev; - var next2 = effect.next; - if (prev !== null) prev.next = next2; - if (next2 !== null) next2.prev = prev; - if (parent !== null) { - if (parent.first === effect) parent.first = next2; - if (parent.last === effect) parent.last = prev; - } -} -function pause_effect(effect, callback, destroy = true) { - var transitions = []; - pause_children(effect, transitions, true); - var fn = () => { - if (destroy) destroy_effect(effect); - if (callback) callback(); - }; - var remaining = transitions.length; - if (remaining > 0) { - var check = () => --remaining || fn(); - for (var transition of transitions) { - transition.out(check); - } - } else { - fn(); - } -} -function pause_children(effect, transitions, local) { - if ((effect.f & INERT) !== 0) return; - effect.f ^= INERT; - var t = effect.nodes && effect.nodes.t; - if (t !== null) { - for (const transition of t) { - if (transition.is_global || local) { - transitions.push(transition); - } - } - } - var child = effect.first; - while (child !== null) { - var sibling = child.next; - var transparent = (child.f & EFFECT_TRANSPARENT) !== 0 || // If this is a branch effect without a block effect parent, - // it means the parent block effect was pruned. In that case, - // transparency information was transferred to the branch effect. - (child.f & BRANCH_EFFECT) !== 0 && (effect.f & BLOCK_EFFECT) !== 0; - pause_children(child, transitions, transparent ? local : false); - child = sibling; - } -} -function move_effect(effect, fragment) { - if (!effect.nodes) return; - var node = effect.nodes.start; - var end = effect.nodes.end; - while (node !== null) { - var next2 = node === end ? null : /* @__PURE__ */ get_next_sibling(node); - fragment.append(node); - node = next2; - } -} -let is_updating_effect = false; -let is_destroying_effect = false; -function set_is_destroying_effect(value) { - is_destroying_effect = value; -} -let active_reaction = null; -let untracking = false; -function set_active_reaction(reaction) { - active_reaction = reaction; -} -let active_effect = null; -function set_active_effect(effect) { - active_effect = effect; -} -let current_sources = null; -function push_reaction_value(value) { - if (active_reaction !== null && true) { - if (current_sources === null) { - current_sources = [value]; - } else { - current_sources.push(value); - } - } -} -let new_deps = null; -let skipped_deps = 0; -let untracked_writes = null; -function set_untracked_writes(value) { - untracked_writes = value; -} -let write_version = 1; -let read_version = 0; -let update_version = read_version; -function set_update_version(value) { - update_version = value; -} -function increment_write_version() { - return ++write_version; -} -function is_dirty(reaction) { - var flags2 = reaction.f; - if ((flags2 & DIRTY) !== 0) { - return true; - } - if (flags2 & DERIVED) { - reaction.f &= ~WAS_MARKED; - } - if ((flags2 & MAYBE_DIRTY) !== 0) { - var dependencies = ( - /** @type {Value[]} */ - reaction.deps - ); - var length = dependencies.length; - for (var i = 0; i < length; i++) { - var dependency = dependencies[i]; - if (is_dirty( - /** @type {Derived} */ - dependency - )) { - update_derived( - /** @type {Derived} */ - dependency - ); - } - if (dependency.wv > reaction.wv) { - return true; - } - } - if ((flags2 & CONNECTED) !== 0 && // During time traveling we don't want to reset the status so that - // traversal of the graph in the other batches still happens - batch_values === null) { - set_signal_status(reaction, CLEAN); - } - } - return false; -} -function schedule_possible_effect_self_invalidation(signal, effect, root2 = true) { - var reactions = signal.reactions; - if (reactions === null) return; - if (current_sources !== null && includes.call(current_sources, signal)) { - return; - } - for (var i = 0; i < reactions.length; i++) { - var reaction = reactions[i]; - if ((reaction.f & DERIVED) !== 0) { - schedule_possible_effect_self_invalidation( - /** @type {Derived} */ - reaction, - effect, - false - ); - } else if (effect === reaction) { - if (root2) { - set_signal_status(reaction, DIRTY); - } else if ((reaction.f & CLEAN) !== 0) { - set_signal_status(reaction, MAYBE_DIRTY); - } - schedule_effect( - /** @type {Effect} */ - reaction - ); - } - } -} -function update_reaction(reaction) { - var previous_deps = new_deps; - var previous_skipped_deps = skipped_deps; - var previous_untracked_writes = untracked_writes; - var previous_reaction = active_reaction; - var previous_sources = current_sources; - var previous_component_context = component_context; - var previous_untracking = untracking; - var previous_update_version = update_version; - var flags2 = reaction.f; - new_deps = /** @type {null | Value[]} */ - null; - skipped_deps = 0; - untracked_writes = null; - active_reaction = (flags2 & (BRANCH_EFFECT | ROOT_EFFECT)) === 0 ? reaction : null; - current_sources = null; - set_component_context(reaction.ctx); - untracking = false; - update_version = ++read_version; - if (reaction.ac !== null) { - without_reactive_context(() => { - reaction.ac.abort(STALE_REACTION); - }); - reaction.ac = null; - } - try { - reaction.f |= REACTION_IS_UPDATING; - var fn = ( - /** @type {Function} */ - reaction.fn - ); - var result = fn(); - reaction.f |= REACTION_RAN; - var deps = reaction.deps; - var is_fork = current_batch?.is_fork; - if (new_deps !== null) { - var i; - if (!is_fork) { - remove_reactions(reaction, skipped_deps); - } - if (deps !== null && skipped_deps > 0) { - deps.length = skipped_deps + new_deps.length; - for (i = 0; i < new_deps.length; i++) { - deps[skipped_deps + i] = new_deps[i]; - } - } else { - reaction.deps = deps = new_deps; - } - if (effect_tracking() && (reaction.f & CONNECTED) !== 0) { - for (i = skipped_deps; i < deps.length; i++) { - (deps[i].reactions ??= []).push(reaction); - } - } - } else if (!is_fork && deps !== null && skipped_deps < deps.length) { - remove_reactions(reaction, skipped_deps); - deps.length = skipped_deps; - } - if (is_runes() && untracked_writes !== null && !untracking && deps !== null && (reaction.f & (DERIVED | MAYBE_DIRTY | DIRTY)) === 0) { - for (i = 0; i < /** @type {Source[]} */ - untracked_writes.length; i++) { - schedule_possible_effect_self_invalidation( - untracked_writes[i], - /** @type {Effect} */ - reaction - ); - } - } - if (previous_reaction !== null && previous_reaction !== reaction) { - read_version++; - if (previous_reaction.deps !== null) { - for (let i2 = 0; i2 < previous_skipped_deps; i2 += 1) { - previous_reaction.deps[i2].rv = read_version; - } - } - if (previous_deps !== null) { - for (const dep of previous_deps) { - dep.rv = read_version; - } - } - if (untracked_writes !== null) { - if (previous_untracked_writes === null) { - previous_untracked_writes = untracked_writes; - } else { - previous_untracked_writes.push(.../** @type {Source[]} */ - untracked_writes); - } - } - } - if ((reaction.f & ERROR_VALUE) !== 0) { - reaction.f ^= ERROR_VALUE; - } - return result; - } catch (error) { - return handle_error(error); - } finally { - reaction.f ^= REACTION_IS_UPDATING; - new_deps = previous_deps; - skipped_deps = previous_skipped_deps; - untracked_writes = previous_untracked_writes; - active_reaction = previous_reaction; - current_sources = previous_sources; - set_component_context(previous_component_context); - untracking = previous_untracking; - update_version = previous_update_version; - } -} -function remove_reaction(signal, dependency) { - let reactions = dependency.reactions; - if (reactions !== null) { - var index = index_of.call(reactions, signal); - if (index !== -1) { - var new_length = reactions.length - 1; - if (new_length === 0) { - reactions = dependency.reactions = null; - } else { - reactions[index] = reactions[new_length]; - reactions.pop(); - } - } - } - if (reactions === null && (dependency.f & DERIVED) !== 0 && // Destroying a child effect while updating a parent effect can cause a dependency to appear - // to be unused, when in fact it is used by the currently-updating parent. Checking `new_deps` - // allows us to skip the expensive work of disconnecting and immediately reconnecting it - (new_deps === null || !includes.call(new_deps, dependency))) { - var derived2 = ( - /** @type {Derived} */ - dependency - ); - if ((derived2.f & CONNECTED) !== 0) { - derived2.f ^= CONNECTED; - derived2.f &= ~WAS_MARKED; - } - update_derived_status(derived2); - freeze_derived_effects(derived2); - remove_reactions(derived2, 0); - } -} -function remove_reactions(signal, start_index) { - var dependencies = signal.deps; - if (dependencies === null) return; - for (var i = start_index; i < dependencies.length; i++) { - remove_reaction(signal, dependencies[i]); - } -} -function update_effect(effect) { - var flags2 = effect.f; - if ((flags2 & DESTROYED) !== 0) { - return; - } - set_signal_status(effect, CLEAN); - var previous_effect = active_effect; - var was_updating_effect = is_updating_effect; - active_effect = effect; - is_updating_effect = true; - try { - if ((flags2 & (BLOCK_EFFECT | MANAGED_EFFECT)) !== 0) { - destroy_block_effect_children(effect); - } else { - destroy_effect_children(effect); - } - execute_effect_teardown(effect); - var teardown = update_reaction(effect); - effect.teardown = typeof teardown === "function" ? teardown : null; - effect.wv = write_version; - var dep; - if (DEV && tracing_mode_flag && (effect.f & DIRTY) !== 0 && effect.deps !== null) ; - } finally { - is_updating_effect = was_updating_effect; - active_effect = previous_effect; - } -} -function get(signal) { - var flags2 = signal.f; - var is_derived = (flags2 & DERIVED) !== 0; - if (active_reaction !== null && !untracking) { - var destroyed = active_effect !== null && (active_effect.f & DESTROYED) !== 0; - if (!destroyed && (current_sources === null || !includes.call(current_sources, signal))) { - var deps = active_reaction.deps; - if ((active_reaction.f & REACTION_IS_UPDATING) !== 0) { - if (signal.rv < read_version) { - signal.rv = read_version; - if (new_deps === null && deps !== null && deps[skipped_deps] === signal) { - skipped_deps++; - } else if (new_deps === null) { - new_deps = [signal]; - } else { - new_deps.push(signal); - } - } - } else { - (active_reaction.deps ??= []).push(signal); - var reactions = signal.reactions; - if (reactions === null) { - signal.reactions = [active_reaction]; - } else if (!includes.call(reactions, active_reaction)) { - reactions.push(active_reaction); - } - } - } - } - if (is_destroying_effect && old_values.has(signal)) { - return old_values.get(signal); - } - if (is_derived) { - var derived2 = ( - /** @type {Derived} */ - signal - ); - if (is_destroying_effect) { - var value = derived2.v; - if ((derived2.f & CLEAN) === 0 && derived2.reactions !== null || depends_on_old_values(derived2)) { - value = execute_derived(derived2); - } - old_values.set(derived2, value); - return value; - } - var should_connect = (derived2.f & CONNECTED) === 0 && !untracking && active_reaction !== null && (is_updating_effect || (active_reaction.f & CONNECTED) !== 0); - var is_new = (derived2.f & REACTION_RAN) === 0; - if (is_dirty(derived2)) { - if (should_connect) { - derived2.f |= CONNECTED; - } - update_derived(derived2); - } - if (should_connect && !is_new) { - unfreeze_derived_effects(derived2); - reconnect(derived2); - } - } - if (batch_values?.has(signal)) { - return batch_values.get(signal); - } - if ((signal.f & ERROR_VALUE) !== 0) { - throw signal.v; - } - return signal.v; -} -function reconnect(derived2) { - derived2.f |= CONNECTED; - if (derived2.deps === null) return; - for (const dep of derived2.deps) { - (dep.reactions ??= []).push(derived2); - if ((dep.f & DERIVED) !== 0 && (dep.f & CONNECTED) === 0) { - unfreeze_derived_effects( - /** @type {Derived} */ - dep - ); - reconnect( - /** @type {Derived} */ - dep - ); - } - } -} -function depends_on_old_values(derived2) { - if (derived2.v === UNINITIALIZED) return true; - if (derived2.deps === null) return false; - for (const dep of derived2.deps) { - if (old_values.has(dep)) { - return true; - } - if ((dep.f & DERIVED) !== 0 && depends_on_old_values( - /** @type {Derived} */ - dep - )) { - return true; - } - } - return false; -} -function untrack(fn) { - var previous_untracking = untracking; - try { - untracking = true; - return fn(); - } finally { - untracking = previous_untracking; - } -} -const event_symbol = /* @__PURE__ */ Symbol("events"); -const all_registered_events = /* @__PURE__ */ new Set(); -const root_event_handles = /* @__PURE__ */ new Set(); -let last_propagated_event = null; -function handle_event_propagation(event) { - var handler_element = this; - var owner_document = ( - /** @type {Node} */ - handler_element.ownerDocument - ); - var event_name = event.type; - var path = event.composedPath?.() || []; - var current_target = ( - /** @type {null | Element} */ - path[0] || event.target - ); - last_propagated_event = event; - var path_idx = 0; - var handled_at = last_propagated_event === event && event[event_symbol]; - if (handled_at) { - var at_idx = path.indexOf(handled_at); - if (at_idx !== -1 && (handler_element === document || handler_element === /** @type {any} */ - window)) { - event[event_symbol] = handler_element; - return; - } - var handler_idx = path.indexOf(handler_element); - if (handler_idx === -1) { - return; - } - if (at_idx <= handler_idx) { - path_idx = at_idx; - } - } - current_target = /** @type {Element} */ - path[path_idx] || event.target; - if (current_target === handler_element) return; - define_property(event, "currentTarget", { - configurable: true, - get() { - return current_target || owner_document; - } - }); - var previous_reaction = active_reaction; - var previous_effect = active_effect; - set_active_reaction(null); - set_active_effect(null); - try { - var throw_error; - var other_errors = []; - while (current_target !== null) { - var parent_element = current_target.assignedSlot || current_target.parentNode || /** @type {any} */ - current_target.host || null; - try { - var delegated = current_target[event_symbol]?.[event_name]; - if (delegated != null && (!/** @type {any} */ - current_target.disabled || // DOM could've been updated already by the time this is reached, so we check this as well - // -> the target could not have been disabled because it emits the event in the first place - event.target === current_target)) { - delegated.call(current_target, event); - } - } catch (error) { - if (throw_error) { - other_errors.push(error); - } else { - throw_error = error; - } - } - if (event.cancelBubble || parent_element === handler_element || parent_element === null) { - break; - } - current_target = parent_element; - } - if (throw_error) { - for (let error of other_errors) { - queueMicrotask(() => { - throw error; - }); - } - throw throw_error; - } - } finally { - event[event_symbol] = handler_element; - delete event.currentTarget; - set_active_reaction(previous_reaction); - set_active_effect(previous_effect); - } -} -function assign_nodes(start, end) { - var effect = ( - /** @type {Effect} */ - active_effect - ); - if (effect.nodes === null) { - effect.nodes = { start, end, a: null, t: null }; - } -} -function mount(component, options) { - return _mount(component, options); -} -function hydrate(component, options) { - init_operations(); - options.intro = options.intro ?? false; - const target = options.target; - const was_hydrating = hydrating; - const previous_hydrate_node = hydrate_node; - try { - var anchor = /* @__PURE__ */ get_first_child(target); - while (anchor && (anchor.nodeType !== COMMENT_NODE || /** @type {Comment} */ - anchor.data !== HYDRATION_START)) { - anchor = /* @__PURE__ */ get_next_sibling(anchor); - } - if (!anchor) { - throw HYDRATION_ERROR; - } - set_hydrating(true); - set_hydrate_node( - /** @type {Comment} */ - anchor - ); - const instance = _mount(component, { ...options, anchor }); - set_hydrating(false); - return ( - /** @type {Exports} */ - instance - ); - } catch (error) { - if (error instanceof Error && error.message.split("\n").some((line) => line.startsWith("https://svelte.dev/e/"))) { - throw error; - } - if (error !== HYDRATION_ERROR) { - console.warn("Failed to hydrate: ", error); - } - if (options.recover === false) { - hydration_failed(); - } - init_operations(); - clear_text_content(target); - set_hydrating(false); - return mount(component, options); - } finally { - set_hydrating(was_hydrating); - set_hydrate_node(previous_hydrate_node); - } -} -const listeners = /* @__PURE__ */ new Map(); -function _mount(Component, { target, anchor, props = {}, events, context, intro = true, transformError }) { - init_operations(); - var component = void 0; - var unmount2 = component_root(() => { - var anchor_node = anchor ?? target.appendChild(create_text()); - boundary( - /** @type {TemplateNode} */ - anchor_node, - { - pending: () => { - } - }, - (anchor_node2) => { - push({}); - var ctx = ( - /** @type {ComponentContext} */ - component_context - ); - if (context) ctx.c = context; - if (events) { - props.$$events = events; - } - if (hydrating) { - assign_nodes( - /** @type {TemplateNode} */ - anchor_node2, - null - ); - } - component = Component(anchor_node2, props) || {}; - if (hydrating) { - active_effect.nodes.end = hydrate_node; - if (hydrate_node === null || hydrate_node.nodeType !== COMMENT_NODE || /** @type {Comment} */ - hydrate_node.data !== HYDRATION_END) { - hydration_mismatch(); - throw HYDRATION_ERROR; - } - } - pop(); - }, - transformError - ); - var registered_events = /* @__PURE__ */ new Set(); - var event_handle = (events2) => { - for (var i = 0; i < events2.length; i++) { - var event_name = events2[i]; - if (registered_events.has(event_name)) continue; - registered_events.add(event_name); - var passive = is_passive_event(event_name); - for (const node of [target, document]) { - var counts = listeners.get(node); - if (counts === void 0) { - counts = /* @__PURE__ */ new Map(); - listeners.set(node, counts); - } - var count = counts.get(event_name); - if (count === void 0) { - node.addEventListener(event_name, handle_event_propagation, { passive }); - counts.set(event_name, 1); - } else { - counts.set(event_name, count + 1); - } - } - } - }; - event_handle(array_from(all_registered_events)); - root_event_handles.add(event_handle); - return () => { - for (var event_name of registered_events) { - for (const node of [target, document]) { - var counts = ( - /** @type {Map} */ - listeners.get(node) - ); - var count = ( - /** @type {number} */ - counts.get(event_name) - ); - if (--count == 0) { - node.removeEventListener(event_name, handle_event_propagation); - counts.delete(event_name); - if (counts.size === 0) { - listeners.delete(node); - } - } else { - counts.set(event_name, count); - } - } - } - root_event_handles.delete(event_handle); - if (anchor_node !== anchor) { - anchor_node.parentNode?.removeChild(anchor_node); - } - }; - }); - mounted_components.set(component, unmount2); - return component; -} -let mounted_components = /* @__PURE__ */ new WeakMap(); -function unmount(component, options) { - const fn = mounted_components.get(component); - if (fn) { - mounted_components.delete(component); - return fn(options); - } - return Promise.resolve(); -} -function asClassComponent$1(component) { - return class extends Svelte4Component { - /** @param {any} options */ - constructor(options) { - super({ - component, - ...options - }); - } - }; -} -class Svelte4Component { - /** @type {any} */ - #events; - /** @type {Record} */ - #instance; - /** - * @param {ComponentConstructorOptions & { - * component: any; - * }} options - */ - constructor(options) { - var sources = /* @__PURE__ */ new Map(); - var add_source = (key, value) => { - var s = /* @__PURE__ */ mutable_source(value, false, false); - sources.set(key, s); - return s; - }; - const props = new Proxy( - { ...options.props || {}, $$events: {} }, - { - get(target, prop) { - return get(sources.get(prop) ?? add_source(prop, Reflect.get(target, prop))); - }, - has(target, prop) { - if (prop === LEGACY_PROPS) return true; - get(sources.get(prop) ?? add_source(prop, Reflect.get(target, prop))); - return Reflect.has(target, prop); - }, - set(target, prop, value) { - set(sources.get(prop) ?? add_source(prop, value), value); - return Reflect.set(target, prop, value); - } - } - ); - this.#instance = (options.hydrate ? hydrate : mount)(options.component, { - target: options.target, - anchor: options.anchor, - props, - context: options.context, - intro: options.intro ?? false, - recover: options.recover, - transformError: options.transformError - }); - if (!options?.props?.$$host || options.sync === false) { - flushSync(); - } - this.#events = props.$$events; - for (const key of Object.keys(this.#instance)) { - if (key === "$set" || key === "$destroy" || key === "$on") continue; - define_property(this, key, { - get() { - return this.#instance[key]; - }, - /** @param {any} value */ - set(value) { - this.#instance[key] = value; - }, - enumerable: true - }); - } - this.#instance.$set = /** @param {Record} next */ - (next2) => { - Object.assign(props, next2); - }; - this.#instance.$destroy = () => { - unmount(this.#instance); - }; - } - /** @param {Record} props */ - $set(props) { - this.#instance.$set(props); - } - /** - * @param {string} event - * @param {(...args: any[]) => any} callback - * @returns {any} - */ - $on(event, callback) { - this.#events[event] = this.#events[event] || []; - const cb = (...args) => callback.call(this, ...args); - this.#events[event].push(cb); - return () => { - this.#events[event] = this.#events[event].filter( - /** @param {any} fn */ - (fn) => fn !== cb - ); - }; - } - $destroy() { - this.#instance.$destroy(); - } -} -function asClassComponent(component) { - const component_constructor = asClassComponent$1(component); - const _render = (props, { context, csp, transformError } = {}) => { - const result = render(component, { props, context, csp, transformError }); - const munged = Object.defineProperties( - /** @type {LegacyRenderResult & PromiseLike} */ - {}, - { - css: { - value: { code: "", map: null } - }, - head: { - get: () => result.head - }, - html: { - get: () => result.body - }, - then: { - /** - * this is not type-safe, but honestly it's the best I can do right now, and it's a straightforward function. - * - * @template TResult1 - * @template [TResult2=never] - * @param { (value: LegacyRenderResult) => TResult1 } onfulfilled - * @param { (reason: unknown) => TResult2 } onrejected - */ - value: (onfulfilled, onrejected) => { - { - const user_result = onfulfilled({ - css: munged.css, - head: munged.head, - html: munged.html - }); - return Promise.resolve(user_result); - } - } - } - } - ); - return munged; - }; - component_constructor.render = _render; - return component_constructor; -} -function Root($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - let { - stores, - page, - constructors, - components = [], - form, - data_0 = null, - data_1 = null, - data_2 = null - } = $$props; - { - setContext("__svelte__", stores); - } - { - stores.page.set(page); - } - const Pyramid_2 = derived(() => constructors[2]); - if (constructors[1]) { - $$renderer2.push(""); - const Pyramid_0 = constructors[0]; - if (Pyramid_0) { - $$renderer2.push(""); - Pyramid_0($$renderer2, { - data: data_0, - form, - params: page.params, - children: ($$renderer3) => { - if (constructors[2]) { - $$renderer3.push(""); - const Pyramid_1 = constructors[1]; - if (Pyramid_1) { - $$renderer3.push(""); - Pyramid_1($$renderer3, { - data: data_1, - form, - params: page.params, - children: ($$renderer4) => { - if (Pyramid_2()) { - $$renderer4.push(""); - Pyramid_2()($$renderer4, { data: data_2, form, params: page.params }); - $$renderer4.push(""); - } else { - $$renderer4.push(""); - $$renderer4.push(""); - } - }, - $$slots: { default: true } - }); - $$renderer3.push(""); - } else { - $$renderer3.push(""); - $$renderer3.push(""); - } - } else { - $$renderer3.push(""); - const Pyramid_1 = constructors[1]; - if (Pyramid_1) { - $$renderer3.push(""); - Pyramid_1($$renderer3, { data: data_1, form, params: page.params }); - $$renderer3.push(""); - } else { - $$renderer3.push(""); - $$renderer3.push(""); - } - } - $$renderer3.push(``); - }, - $$slots: { default: true } - }); - $$renderer2.push(""); - } else { - $$renderer2.push(""); - $$renderer2.push(""); - } - } else { - $$renderer2.push(""); - const Pyramid_0 = constructors[0]; - if (Pyramid_0) { - $$renderer2.push(""); - Pyramid_0($$renderer2, { data: data_0, form, params: page.params }); - $$renderer2.push(""); - } else { - $$renderer2.push(""); - $$renderer2.push(""); - } - } - $$renderer2.push(` `); - { - $$renderer2.push(""); - } - $$renderer2.push(``); - }); -} -const root = asClassComponent(Root); -export { - root as r, - safe_not_equal as s -}; diff --git a/.svelte-kit/output/server/chunks/routing.js b/.svelte-kit/output/server/chunks/routing.js deleted file mode 100644 index 11c0ffa..0000000 --- a/.svelte-kit/output/server/chunks/routing.js +++ /dev/null @@ -1,85 +0,0 @@ -import { b as decode_params } from "./url.js"; -function affects_path(segment) { - return segment !== "" && !/^\([^)]+\)$/.test(segment); -} -function get_route_segments(route) { - return route.slice(1).split("/").filter(affects_path); -} -function exec(match, params, matchers) { - const result = {}; - const values = match.slice(1); - const values_needing_match = values.filter((value) => value !== void 0); - let buffered = 0; - for (let i = 0; i < params.length; i += 1) { - const param = params[i]; - let value = values[i - buffered]; - if (param.chained && param.rest && buffered) { - value = values.slice(i - buffered, i + 1).filter((s) => s).join("/"); - buffered = 0; - } - if (value === void 0) { - if (param.rest) { - value = ""; - } else { - continue; - } - } - if (!param.matcher || matchers[param.matcher](value)) { - result[param.name] = value; - const next_param = params[i + 1]; - const next_value = values[i + 1]; - if (next_param && !next_param.rest && next_param.optional && next_value && param.chained) { - buffered = 0; - } - if (!next_param && !next_value && Object.keys(result).length === values_needing_match.length) { - buffered = 0; - } - continue; - } - if (param.optional && param.chained) { - buffered++; - continue; - } - return; - } - if (buffered) return; - return result; -} -const basic_param_pattern = /\[(\[)?(\.\.\.)?(\w+?)(?:=(\w+))?\]\]?/g; -function resolve_route(id, params) { - const segments = get_route_segments(id); - const has_id_trailing_slash = id.endsWith("/"); - return "/" + segments.map( - (segment) => segment.replace(basic_param_pattern, (_, optional, rest, name) => { - const param_value = params[name]; - if (!param_value) { - if (optional) return ""; - if (rest && param_value !== void 0) return ""; - throw new Error(`Missing parameter '${name}' in route ${id}`); - } - if (param_value.startsWith("/") || param_value.endsWith("/")) - throw new Error( - `Parameter '${name}' in route ${id} cannot start or end with a slash -- this would cause an invalid route like foo//bar` - ); - return param_value; - }) - ).filter(Boolean).join("/") + (has_id_trailing_slash ? "/" : ""); -} -function find_route(path, routes, matchers) { - for (const route of routes) { - const match = route.pattern.exec(path); - if (!match) continue; - const matched = exec(match, route.params, matchers); - if (matched) { - return { - route, - params: decode_params(matched) - }; - } - } - return null; -} -export { - find_route as f, - resolve_route as r -}; diff --git a/.svelte-kit/output/server/chunks/server.js b/.svelte-kit/output/server/chunks/server.js deleted file mode 100644 index bf7eaa6..0000000 --- a/.svelte-kit/output/server/chunks/server.js +++ /dev/null @@ -1,27 +0,0 @@ -let base = ""; -let assets = base; -const app_dir = "_app"; -const relative = true; -const initial = { base, assets }; -const initial_base = initial.base; -function override(paths) { - base = paths.base; - assets = paths.assets; -} -function reset() { - base = initial.base; - assets = initial.assets; -} -function set_assets(path) { - assets = initial.assets = path; -} -export { - assets as a, - base as b, - app_dir as c, - reset as d, - initial_base as i, - override as o, - relative as r, - set_assets as s -}; diff --git a/.svelte-kit/output/server/chunks/shared-server.js b/.svelte-kit/output/server/chunks/shared-server.js deleted file mode 100644 index 4fa13e6..0000000 --- a/.svelte-kit/output/server/chunks/shared-server.js +++ /dev/null @@ -1,14 +0,0 @@ -let private_env = {}; -let public_env = {}; -function set_private_env(environment) { - private_env = environment; -} -function set_public_env(environment) { - public_env = environment; -} -export { - set_public_env as a, - private_env as b, - public_env as p, - set_private_env as s -}; diff --git a/.svelte-kit/output/server/chunks/shared.js b/.svelte-kit/output/server/chunks/shared.js deleted file mode 100644 index 9162124..0000000 --- a/.svelte-kit/output/server/chunks/shared.js +++ /dev/null @@ -1,789 +0,0 @@ -import { json, text } from "@sveltejs/kit"; -import { SvelteKitError, HttpError } from "@sveltejs/kit/internal"; -import { with_request_store } from "@sveltejs/kit/internal/server"; -import * as devalue from "devalue"; -import { t as text_decoder, b as base64_encode, c as base64_decode } from "./utils.js"; -const SVELTE_KIT_ASSETS = "/_svelte_kit_assets"; -const ENDPOINT_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"]; -const MUTATIVE_METHODS = ["POST", "PUT", "PATCH", "DELETE"]; -const PAGE_METHODS = ["GET", "POST", "HEAD"]; -function set_nested_value(object, path_string, value) { - if (path_string.startsWith("n:")) { - path_string = path_string.slice(2); - value = value === "" ? void 0 : parseFloat(value); - } else if (path_string.startsWith("b:")) { - path_string = path_string.slice(2); - value = value === "on"; - } - deep_set(object, split_path(path_string), value); -} -function convert_formdata(data) { - const result = {}; - for (let key of data.keys()) { - const is_array = key.endsWith("[]"); - let values = data.getAll(key); - if (is_array) key = key.slice(0, -2); - if (values.length > 1 && !is_array) { - throw new Error(`Form cannot contain duplicated keys — "${key}" has ${values.length} values`); - } - values = values.filter( - (entry) => typeof entry === "string" || entry.name !== "" || entry.size > 0 - ); - if (key.startsWith("n:")) { - key = key.slice(2); - values = values.map((v) => v === "" ? void 0 : parseFloat( - /** @type {string} */ - v - )); - } else if (key.startsWith("b:")) { - key = key.slice(2); - values = values.map((v) => v === "on"); - } - set_nested_value(result, key, is_array ? values : values[0]); - } - return result; -} -const BINARY_FORM_CONTENT_TYPE = "application/x-sveltekit-formdata"; -const BINARY_FORM_VERSION = 0; -const HEADER_BYTES = 1 + 4 + 2; -async function deserialize_binary_form(request) { - if (request.headers.get("content-type") !== BINARY_FORM_CONTENT_TYPE) { - const form_data = await request.formData(); - return { data: convert_formdata(form_data), meta: {}, form_data }; - } - if (!request.body) { - throw deserialize_error("no body"); - } - const content_length = parseInt(request.headers.get("content-length") ?? ""); - if (Number.isNaN(content_length)) { - throw deserialize_error("invalid Content-Length header"); - } - const reader = request.body.getReader(); - const chunks = []; - function get_chunk(index) { - if (index in chunks) return chunks[index]; - let i = chunks.length; - while (i <= index) { - chunks[i] = reader.read().then((chunk) => chunk.value); - i++; - } - return chunks[index]; - } - async function get_buffer(offset, length) { - let start_chunk; - let chunk_start = 0; - let chunk_index; - for (chunk_index = 0; ; chunk_index++) { - const chunk = await get_chunk(chunk_index); - if (!chunk) return null; - const chunk_end = chunk_start + chunk.byteLength; - if (offset >= chunk_start && offset < chunk_end) { - start_chunk = chunk; - break; - } - chunk_start = chunk_end; - } - if (offset + length <= chunk_start + start_chunk.byteLength) { - return start_chunk.subarray(offset - chunk_start, offset + length - chunk_start); - } - const chunks2 = [start_chunk.subarray(offset - chunk_start)]; - let cursor = start_chunk.byteLength - offset + chunk_start; - while (cursor < length) { - chunk_index++; - let chunk = await get_chunk(chunk_index); - if (!chunk) return null; - if (chunk.byteLength > length - cursor) { - chunk = chunk.subarray(0, length - cursor); - } - chunks2.push(chunk); - cursor += chunk.byteLength; - } - const buffer = new Uint8Array(length); - cursor = 0; - for (const chunk of chunks2) { - buffer.set(chunk, cursor); - cursor += chunk.byteLength; - } - return buffer; - } - const header = await get_buffer(0, HEADER_BYTES); - if (!header) throw deserialize_error("too short"); - if (header[0] !== BINARY_FORM_VERSION) { - throw deserialize_error(`got version ${header[0]}, expected version ${BINARY_FORM_VERSION}`); - } - const header_view = new DataView(header.buffer, header.byteOffset, header.byteLength); - const data_length = header_view.getUint32(1, true); - if (HEADER_BYTES + data_length > content_length) { - throw deserialize_error("data overflow"); - } - const file_offsets_length = header_view.getUint16(5, true); - if (HEADER_BYTES + data_length + file_offsets_length > content_length) { - throw deserialize_error("file offset table overflow"); - } - const data_buffer = await get_buffer(HEADER_BYTES, data_length); - if (!data_buffer) throw deserialize_error("data too short"); - let file_offsets; - let files_start_offset; - if (file_offsets_length > 0) { - const file_offsets_buffer = await get_buffer(HEADER_BYTES + data_length, file_offsets_length); - if (!file_offsets_buffer) throw deserialize_error("file offset table too short"); - const parsed_offsets = JSON.parse(text_decoder.decode(file_offsets_buffer)); - if (!Array.isArray(parsed_offsets) || parsed_offsets.some((n) => typeof n !== "number" || !Number.isInteger(n) || n < 0)) { - throw deserialize_error("invalid file offset table"); - } - file_offsets = /** @type {Array} */ - parsed_offsets; - files_start_offset = HEADER_BYTES + data_length + file_offsets_length; - } - const file_spans = []; - const [data, meta] = devalue.parse(text_decoder.decode(data_buffer), { - File: ([name, type, size, last_modified, index]) => { - if (typeof name !== "string" || typeof type !== "string" || typeof size !== "number" || typeof last_modified !== "number" || typeof index !== "number") { - throw deserialize_error("invalid file metadata"); - } - let offset = file_offsets[index]; - if (offset === void 0) { - throw deserialize_error("duplicate file offset table index"); - } - file_offsets[index] = void 0; - offset += files_start_offset; - if (offset + size > content_length) { - throw deserialize_error("file data overflow"); - } - file_spans.push({ offset, size }); - return new Proxy(new LazyFile(name, type, size, last_modified, get_chunk, offset), { - getPrototypeOf() { - return File.prototype; - } - }); - } - }); - file_spans.sort((a, b) => a.offset - b.offset || a.size - b.size); - for (let i = 1; i < file_spans.length; i++) { - const previous = file_spans[i - 1]; - const current = file_spans[i]; - const previous_end = previous.offset + previous.size; - if (previous_end < current.offset) { - throw deserialize_error("gaps in file data"); - } - if (previous_end > current.offset) { - throw deserialize_error("overlapping file data"); - } - } - void (async () => { - let has_more = true; - while (has_more) { - const chunk = await get_chunk(chunks.length); - has_more = !!chunk; - } - })(); - return { data, meta, form_data: null }; -} -function deserialize_error(message) { - return new SvelteKitError(400, "Bad Request", `Could not deserialize binary form: ${message}`); -} -class LazyFile { - /** @type {(index: number) => Promise | undefined>} */ - #get_chunk; - /** @type {number} */ - #offset; - /** - * @param {string} name - * @param {string} type - * @param {number} size - * @param {number} last_modified - * @param {(index: number) => Promise | undefined>} get_chunk - * @param {number} offset - */ - constructor(name, type, size, last_modified, get_chunk, offset) { - this.name = name; - this.type = type; - this.size = size; - this.lastModified = last_modified; - this.webkitRelativePath = ""; - this.#get_chunk = get_chunk; - this.#offset = offset; - this.arrayBuffer = this.arrayBuffer.bind(this); - this.bytes = this.bytes.bind(this); - this.slice = this.slice.bind(this); - this.stream = this.stream.bind(this); - this.text = this.text.bind(this); - } - /** @type {ArrayBuffer | undefined} */ - #buffer; - async arrayBuffer() { - this.#buffer ??= await new Response(this.stream()).arrayBuffer(); - return this.#buffer; - } - async bytes() { - return new Uint8Array(await this.arrayBuffer()); - } - /** - * @param {number=} start - * @param {number=} end - * @param {string=} contentType - */ - slice(start = 0, end = this.size, contentType = this.type) { - if (start < 0) { - start = Math.max(this.size + start, 0); - } else { - start = Math.min(start, this.size); - } - if (end < 0) { - end = Math.max(this.size + end, 0); - } else { - end = Math.min(end, this.size); - } - const size = Math.max(end - start, 0); - const file = new LazyFile( - this.name, - contentType, - size, - this.lastModified, - this.#get_chunk, - this.#offset + start - ); - return file; - } - stream() { - let cursor = 0; - let chunk_index = 0; - return new ReadableStream({ - start: async (controller) => { - let chunk_start = 0; - let start_chunk; - for (chunk_index = 0; ; chunk_index++) { - const chunk = await this.#get_chunk(chunk_index); - if (!chunk) return null; - const chunk_end = chunk_start + chunk.byteLength; - if (this.#offset >= chunk_start && this.#offset < chunk_end) { - start_chunk = chunk; - break; - } - chunk_start = chunk_end; - } - if (this.#offset + this.size <= chunk_start + start_chunk.byteLength) { - controller.enqueue( - start_chunk.subarray(this.#offset - chunk_start, this.#offset + this.size - chunk_start) - ); - controller.close(); - } else { - controller.enqueue(start_chunk.subarray(this.#offset - chunk_start)); - cursor = start_chunk.byteLength - this.#offset + chunk_start; - } - }, - pull: async (controller) => { - chunk_index++; - let chunk = await this.#get_chunk(chunk_index); - if (!chunk) { - controller.error("incomplete file data"); - controller.close(); - return; - } - if (chunk.byteLength > this.size - cursor) { - chunk = chunk.subarray(0, this.size - cursor); - } - controller.enqueue(chunk); - cursor += chunk.byteLength; - if (cursor >= this.size) { - controller.close(); - } - } - }); - } - async text() { - return text_decoder.decode(await this.arrayBuffer()); - } -} -const path_regex = /^[a-zA-Z_$]\w*(\.[a-zA-Z_$]\w*|\[\d+\])*$/; -function split_path(path) { - if (!path_regex.test(path)) { - throw new Error(`Invalid path ${path}`); - } - return path.split(/\.|\[|\]/).filter(Boolean); -} -function check_prototype_pollution(key) { - if (key === "__proto__" || key === "constructor" || key === "prototype") { - throw new Error( - `Invalid key "${key}"` - ); - } -} -function deep_set(object, keys, value) { - let current = object; - for (let i = 0; i < keys.length - 1; i += 1) { - const key = keys[i]; - check_prototype_pollution(key); - const is_array = /^\d+$/.test(keys[i + 1]); - const exists = Object.hasOwn(current, key); - const inner = current[key]; - if (exists && is_array !== Array.isArray(inner)) { - throw new Error(`Invalid array key ${keys[i + 1]}`); - } - if (!exists) { - current[key] = is_array ? [] : {}; - } - current = current[key]; - } - const final_key = keys[keys.length - 1]; - check_prototype_pollution(final_key); - current[final_key] = value; -} -function normalize_issue(issue, server = false) { - const normalized = { name: "", path: [], message: issue.message, server }; - if (issue.path !== void 0) { - let name = ""; - for (const segment of issue.path) { - const key = ( - /** @type {string | number} */ - typeof segment === "object" ? segment.key : segment - ); - normalized.path.push(key); - if (typeof key === "number") { - name += `[${key}]`; - } else if (typeof key === "string") { - name += name === "" ? key : "." + key; - } - } - normalized.name = name; - } - return normalized; -} -function flatten_issues(issues) { - const result = {}; - for (const issue of issues) { - (result.$ ??= []).push(issue); - let name = ""; - if (issue.path !== void 0) { - for (const key of issue.path) { - if (typeof key === "number") { - name += `[${key}]`; - } else if (typeof key === "string") { - name += name === "" ? key : "." + key; - } - (result[name] ??= []).push(issue); - } - } - } - return result; -} -function deep_get(object, path) { - let current = object; - for (const key of path) { - if (current == null || typeof current !== "object") { - return current; - } - current = current[key]; - } - return current; -} -function create_field_proxy(target, get_input, set_input, get_issues, path = []) { - const get_value = () => { - return deep_get(get_input(), path); - }; - return new Proxy(target, { - get(target2, prop) { - if (typeof prop === "symbol") return target2[prop]; - if (/^\d+$/.test(prop)) { - return create_field_proxy({}, get_input, set_input, get_issues, [ - ...path, - parseInt(prop, 10) - ]); - } - const key = build_path_string(path); - if (prop === "set") { - const set_func = function(newValue) { - set_input(path, newValue); - return newValue; - }; - return create_field_proxy(set_func, get_input, set_input, get_issues, [...path, prop]); - } - if (prop === "value") { - return create_field_proxy(get_value, get_input, set_input, get_issues, [...path, prop]); - } - if (prop === "issues" || prop === "allIssues") { - const issues_func = () => { - const all_issues = get_issues()[key === "" ? "$" : key]; - if (prop === "allIssues") { - return all_issues?.map((issue) => ({ - path: issue.path, - message: issue.message - })); - } - return all_issues?.filter((issue) => issue.name === key)?.map((issue) => ({ - path: issue.path, - message: issue.message - })); - }; - return create_field_proxy(issues_func, get_input, set_input, get_issues, [...path, prop]); - } - if (prop === "as") { - const as_func = (type, input_value) => { - const is_array = type === "file multiple" || type === "select multiple" || type === "checkbox" && typeof input_value === "string"; - const prefix = type === "number" || type === "range" ? "n:" : type === "checkbox" && !is_array ? "b:" : ""; - const base_props = { - name: prefix + key + (is_array ? "[]" : ""), - get "aria-invalid"() { - const issues = get_issues(); - return key in issues ? "true" : void 0; - } - }; - if (type !== "text" && type !== "select" && type !== "select multiple") { - base_props.type = type === "file multiple" ? "file" : type; - } - if (type === "submit" || type === "hidden") { - return Object.defineProperties(base_props, { - value: { value: input_value, enumerable: true } - }); - } - if (type === "select" || type === "select multiple") { - return Object.defineProperties(base_props, { - multiple: { value: is_array, enumerable: true }, - value: { - enumerable: true, - get() { - return get_value(); - } - } - }); - } - if (type === "checkbox" || type === "radio") { - return Object.defineProperties(base_props, { - value: { value: input_value ?? "on", enumerable: true }, - checked: { - enumerable: true, - get() { - const value = get_value(); - if (type === "radio") { - return value === input_value; - } - if (is_array) { - return (value ?? []).includes(input_value); - } - return value; - } - } - }); - } - if (type === "file" || type === "file multiple") { - return Object.defineProperties(base_props, { - multiple: { value: is_array, enumerable: true }, - files: { - enumerable: true, - get() { - const value = get_value(); - if (value instanceof File) { - if (typeof DataTransfer !== "undefined") { - const fileList = new DataTransfer(); - fileList.items.add(value); - return fileList.files; - } - return { 0: value, length: 1 }; - } - if (Array.isArray(value) && value.every((f) => f instanceof File)) { - if (typeof DataTransfer !== "undefined") { - const fileList = new DataTransfer(); - value.forEach((file) => fileList.items.add(file)); - return fileList.files; - } - const fileListLike = { length: value.length }; - value.forEach((file, index) => { - fileListLike[index] = file; - }); - return fileListLike; - } - return null; - } - } - }); - } - return Object.defineProperties(base_props, { - value: { - enumerable: true, - get() { - const value = get_value(); - return value != null ? String(value) : ""; - } - } - }); - }; - return create_field_proxy(as_func, get_input, set_input, get_issues, [...path, "as"]); - } - return create_field_proxy({}, get_input, set_input, get_issues, [...path, prop]); - } - }); -} -function build_path_string(path) { - let result = ""; - for (const segment of path) { - if (typeof segment === "number") { - result += `[${segment}]`; - } else { - result += result === "" ? segment : "." + segment; - } - } - return result; -} -function negotiate(accept, types) { - const parts = []; - accept.split(",").forEach((str, i) => { - const match = /([^/ \t]+)\/([^; \t]+)[ \t]*(?:;[ \t]*q=([0-9.]+))?/.exec(str); - if (match) { - const [, type, subtype, q = "1"] = match; - parts.push({ type, subtype, q: +q, i }); - } - }); - parts.sort((a, b) => { - if (a.q !== b.q) { - return b.q - a.q; - } - if (a.subtype === "*" !== (b.subtype === "*")) { - return a.subtype === "*" ? 1 : -1; - } - if (a.type === "*" !== (b.type === "*")) { - return a.type === "*" ? 1 : -1; - } - return a.i - b.i; - }); - let accepted; - let min_priority = Infinity; - for (const mimetype of types) { - const [type, subtype] = mimetype.split("/"); - const priority = parts.findIndex( - (part) => (part.type === type || part.type === "*") && (part.subtype === subtype || part.subtype === "*") - ); - if (priority !== -1 && priority < min_priority) { - accepted = mimetype; - min_priority = priority; - } - } - return accepted; -} -function is_content_type(request, ...types) { - const type = request.headers.get("content-type")?.split(";", 1)[0].trim() ?? ""; - return types.includes(type.toLowerCase()); -} -function is_form_content_type(request) { - return is_content_type( - request, - "application/x-www-form-urlencoded", - "multipart/form-data", - "text/plain", - BINARY_FORM_CONTENT_TYPE - ); -} -function coalesce_to_error(err) { - return err instanceof Error || err && /** @type {any} */ - err.name && /** @type {any} */ - err.message ? ( - /** @type {Error} */ - err - ) : new Error(JSON.stringify(err)); -} -function normalize_error(error) { - return ( - /** @type {import('../exports/internal/index.js').Redirect | HttpError | SvelteKitError | Error} */ - error - ); -} -function get_status(error) { - return error instanceof HttpError || error instanceof SvelteKitError ? error.status : 500; -} -function get_message(error) { - return error instanceof SvelteKitError ? error.text : "Internal Error"; -} -const escape_html_attr_dict = { - "&": "&", - '"': """ - // Svelte also escapes < because the escape function could be called inside a `noscript` there - // https://github.com/sveltejs/svelte/security/advisories/GHSA-8266-84wp-wv5c - // However, that doesn't apply in SvelteKit -}; -const escape_html_dict = { - "&": "&", - "<": "<" -}; -const surrogates = ( - // high surrogate without paired low surrogate - "[\\ud800-\\udbff](?![\\udc00-\\udfff])|[\\ud800-\\udbff][\\udc00-\\udfff]|[\\udc00-\\udfff]" -); -const escape_html_attr_regex = new RegExp( - `[${Object.keys(escape_html_attr_dict).join("")}]|` + surrogates, - "g" -); -const escape_html_regex = new RegExp( - `[${Object.keys(escape_html_dict).join("")}]|` + surrogates, - "g" -); -function escape_html(str, is_attr) { - const dict = is_attr ? escape_html_attr_dict : escape_html_dict; - const escaped_str = str.replace(is_attr ? escape_html_attr_regex : escape_html_regex, (match) => { - if (match.length === 2) { - return match; - } - return dict[match] ?? `&#${match.charCodeAt(0)};`; - }); - return escaped_str; -} -function method_not_allowed(mod, method) { - return text(`${method} method not allowed`, { - status: 405, - headers: { - // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/405 - // "The server must generate an Allow header field in a 405 status code response" - allow: allowed_methods(mod).join(", ") - } - }); -} -function allowed_methods(mod) { - const allowed = ENDPOINT_METHODS.filter((method) => method in mod); - if ("GET" in mod && !("HEAD" in mod)) { - allowed.push("HEAD"); - } - return allowed; -} -function get_global_name(options) { - return `__sveltekit_${options.version_hash}`; -} -function static_error_page(options, status, message) { - let page = options.templates.error({ status, message: escape_html(message) }); - return text(page, { - headers: { "content-type": "text/html; charset=utf-8" }, - status - }); -} -async function handle_fatal_error(event, state, options, error) { - error = error instanceof HttpError ? error : coalesce_to_error(error); - const status = get_status(error); - const body = await handle_error_and_jsonify(event, state, options, error); - const type = negotiate(event.request.headers.get("accept") || "text/html", [ - "application/json", - "text/html" - ]); - if (event.isDataRequest || type === "application/json") { - return json(body, { - status - }); - } - return static_error_page(options, status, body.message); -} -async function handle_error_and_jsonify(event, state, options, error) { - if (error instanceof HttpError) { - return { message: "Unknown Error", ...error.body }; - } - const status = get_status(error); - const message = get_message(error); - return await with_request_store( - { event, state }, - () => options.hooks.handleError({ error, event, status, message }) - ) ?? { message }; -} -function redirect_response(status, location) { - const response = new Response(void 0, { - status, - headers: { location } - }); - return response; -} -function clarify_devalue_error(event, error) { - if (error.path) { - return `Data returned from \`load\` while rendering ${event.route.id} is not serializable: ${error.message} (${error.path}). If you need to serialize/deserialize custom types, use transport hooks: https://svelte.dev/docs/kit/hooks#Universal-hooks-transport.`; - } - if (error.path === "") { - return `Data returned from \`load\` while rendering ${event.route.id} is not a plain object`; - } - return error.message; -} -function serialize_uses(node) { - const uses = {}; - if (node.uses && node.uses.dependencies.size > 0) { - uses.dependencies = Array.from(node.uses.dependencies); - } - if (node.uses && node.uses.search_params.size > 0) { - uses.search_params = Array.from(node.uses.search_params); - } - if (node.uses && node.uses.params.size > 0) { - uses.params = Array.from(node.uses.params); - } - if (node.uses?.parent) uses.parent = 1; - if (node.uses?.route) uses.route = 1; - if (node.uses?.url) uses.url = 1; - return uses; -} -function has_prerendered_path(manifest, pathname) { - return manifest._.prerendered_routes.has(pathname) || pathname.at(-1) === "/" && manifest._.prerendered_routes.has(pathname.slice(0, -1)); -} -function format_server_error(status, error, event) { - const formatted_text = ` -\x1B[1;31m[${status}] ${event.request.method} ${event.url.pathname}\x1B[0m`; - if (status === 404) { - return formatted_text; - } - return `${formatted_text} -${error.stack}`; -} -function get_node_type(node_id) { - const parts = node_id?.split("/"); - const filename = parts?.at(-1); - if (!filename) return "unknown"; - const dot_parts = filename.split("."); - return dot_parts.slice(0, -1).join("."); -} -const INVALIDATED_PARAM = "x-sveltekit-invalidated"; -const TRAILING_SLASH_PARAM = "x-sveltekit-trailing-slash"; -function stringify(data, transport) { - const encoders = Object.fromEntries(Object.entries(transport).map(([k, v]) => [k, v.encode])); - return devalue.stringify(data, encoders); -} -function stringify_remote_arg(value, transport) { - if (value === void 0) return ""; - const json_string = stringify(value, transport); - const bytes = new TextEncoder().encode(json_string); - return base64_encode(bytes).replaceAll("=", "").replaceAll("+", "-").replaceAll("/", "_"); -} -function parse_remote_arg(string, transport) { - if (!string) return void 0; - const json_string = text_decoder.decode( - // no need to add back `=` characters, atob can handle it - base64_decode(string.replaceAll("-", "+").replaceAll("_", "/")) - ); - const decoders = Object.fromEntries(Object.entries(transport).map(([k, v]) => [k, v.decode])); - return devalue.parse(json_string, decoders); -} -function create_remote_key(id, payload) { - return id + "/" + payload; -} -export { - ENDPOINT_METHODS as E, - INVALIDATED_PARAM as I, - MUTATIVE_METHODS as M, - PAGE_METHODS as P, - SVELTE_KIT_ASSETS as S, - TRAILING_SLASH_PARAM as T, - normalize_error as a, - get_global_name as b, - clarify_devalue_error as c, - get_node_type as d, - escape_html as e, - create_remote_key as f, - get_status as g, - handle_error_and_jsonify as h, - is_form_content_type as i, - static_error_page as j, - stringify as k, - deserialize_binary_form as l, - method_not_allowed as m, - negotiate as n, - has_prerendered_path as o, - parse_remote_arg as p, - handle_fatal_error as q, - redirect_response as r, - serialize_uses as s, - format_server_error as t, - create_field_proxy as u, - normalize_issue as v, - set_nested_value as w, - flatten_issues as x, - deep_set as y, - stringify_remote_arg as z -}; diff --git a/.svelte-kit/output/server/chunks/state.svelte.js b/.svelte-kit/output/server/chunks/state.svelte.js deleted file mode 100644 index 9cd4558..0000000 --- a/.svelte-kit/output/server/chunks/state.svelte.js +++ /dev/null @@ -1,18 +0,0 @@ -import "clsx"; -import { n as noop } from "./index3.js"; -import "./url.js"; -import "@sveltejs/kit/internal/server"; -import "./root.js"; -const is_legacy = noop.toString().includes("$$") || /function \w+\(\) \{\}/.test(noop.toString()); -if (is_legacy) { - ({ - data: {}, - form: null, - error: null, - params: {}, - route: { id: null }, - state: {}, - status: -1, - url: new URL("https://example.com") - }); -} diff --git a/.svelte-kit/output/server/chunks/url.js b/.svelte-kit/output/server/chunks/url.js deleted file mode 100644 index 2ba2c18..0000000 --- a/.svelte-kit/output/server/chunks/url.js +++ /dev/null @@ -1,106 +0,0 @@ -const SCHEME = /^[a-z][a-z\d+\-.]+:/i; -const internal = new URL("sveltekit-internal://"); -function resolve(base, path) { - if (path[0] === "/" && path[1] === "/") return path; - let url = new URL(base, internal); - url = new URL(path, url); - return url.protocol === internal.protocol ? url.pathname + url.search + url.hash : url.href; -} -function normalize_path(path, trailing_slash) { - if (path === "/" || trailing_slash === "ignore") return path; - if (trailing_slash === "never") { - return path.endsWith("/") ? path.slice(0, -1) : path; - } else if (trailing_slash === "always" && !path.endsWith("/")) { - return path + "/"; - } - return path; -} -function decode_pathname(pathname) { - return pathname.split("%25").map(decodeURI).join("%25"); -} -function decode_params(params) { - for (const key in params) { - params[key] = decodeURIComponent(params[key]); - } - return params; -} -function make_trackable(url, callback, search_params_callback, allow_hash = false) { - const tracked = new URL(url); - Object.defineProperty(tracked, "searchParams", { - value: new Proxy(tracked.searchParams, { - get(obj, key) { - if (key === "get" || key === "getAll" || key === "has") { - return (param, ...rest) => { - search_params_callback(param); - return obj[key](param, ...rest); - }; - } - callback(); - const value = Reflect.get(obj, key); - return typeof value === "function" ? value.bind(obj) : value; - } - }), - enumerable: true, - configurable: true - }); - const tracked_url_properties = ["href", "pathname", "search", "toString", "toJSON"]; - if (allow_hash) tracked_url_properties.push("hash"); - for (const property of tracked_url_properties) { - Object.defineProperty(tracked, property, { - get() { - callback(); - return url[property]; - }, - enumerable: true, - configurable: true - }); - } - { - tracked[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")] = (depth, opts, inspect) => { - return inspect(url, opts); - }; - tracked.searchParams[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")] = (depth, opts, inspect) => { - return inspect(url.searchParams, opts); - }; - } - if (!allow_hash) { - disable_hash(tracked); - } - return tracked; -} -function disable_hash(url) { - allow_nodejs_console_log(url); - Object.defineProperty(url, "hash", { - get() { - throw new Error( - "Cannot access event.url.hash. Consider using `page.url.hash` inside a component instead" - ); - } - }); -} -function disable_search(url) { - allow_nodejs_console_log(url); - for (const property of ["search", "searchParams"]) { - Object.defineProperty(url, property, { - get() { - throw new Error(`Cannot access url.${property} on a page with prerendering enabled`); - } - }); - } -} -function allow_nodejs_console_log(url) { - { - url[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")] = (depth, opts, inspect) => { - return inspect(new URL(url), opts); - }; - } -} -export { - SCHEME as S, - decode_pathname as a, - decode_params as b, - disable_search as d, - make_trackable as m, - normalize_path as n, - resolve as r -}; diff --git a/.svelte-kit/output/server/chunks/utils.js b/.svelte-kit/output/server/chunks/utils.js deleted file mode 100644 index 78e5bde..0000000 --- a/.svelte-kit/output/server/chunks/utils.js +++ /dev/null @@ -1,43 +0,0 @@ -const text_encoder = new TextEncoder(); -const text_decoder = new TextDecoder(); -function get_relative_path(from, to) { - const from_parts = from.split(/[/\\]/); - const to_parts = to.split(/[/\\]/); - from_parts.pop(); - while (from_parts[0] === to_parts[0]) { - from_parts.shift(); - to_parts.shift(); - } - let i = from_parts.length; - while (i--) from_parts[i] = ".."; - return from_parts.concat(to_parts).join("/"); -} -function base64_encode(bytes) { - if (globalThis.Buffer) { - return globalThis.Buffer.from(bytes).toString("base64"); - } - let binary = ""; - for (let i = 0; i < bytes.length; i++) { - binary += String.fromCharCode(bytes[i]); - } - return btoa(binary); -} -function base64_decode(encoded) { - if (globalThis.Buffer) { - const buffer = globalThis.Buffer.from(encoded, "base64"); - return new Uint8Array(buffer); - } - const binary = atob(encoded); - const bytes = new Uint8Array(binary.length); - for (let i = 0; i < binary.length; i++) { - bytes[i] = binary.charCodeAt(i); - } - return bytes; -} -export { - text_encoder as a, - base64_encode as b, - base64_decode as c, - get_relative_path as g, - text_decoder as t -}; diff --git a/.svelte-kit/output/server/entries/endpoints/api/health/_server.ts.js b/.svelte-kit/output/server/entries/endpoints/api/health/_server.ts.js deleted file mode 100644 index 203529d..0000000 --- a/.svelte-kit/output/server/entries/endpoints/api/health/_server.ts.js +++ /dev/null @@ -1,25 +0,0 @@ -import { json } from "@sveltejs/kit"; -import { d as db } from "../../../../chunks/index2.js"; -import { sql } from "drizzle-orm"; -const GET = async () => { - try { - await db.execute(sql`SELECT 1`); - return json({ - status: "ok", - timestamp: (/* @__PURE__ */ new Date()).toISOString(), - uptime: process.uptime() - }); - } catch (e) { - return json( - { - status: "error", - error: "Database connection failed", - timestamp: (/* @__PURE__ */ new Date()).toISOString() - }, - { status: 503 } - ); - } -}; -export { - GET -}; diff --git a/.svelte-kit/output/server/entries/endpoints/api/mappools/_id_/_server.ts.js b/.svelte-kit/output/server/entries/endpoints/api/mappools/_id_/_server.ts.js deleted file mode 100644 index 4d6b270..0000000 --- a/.svelte-kit/output/server/entries/endpoints/api/mappools/_id_/_server.ts.js +++ /dev/null @@ -1,24 +0,0 @@ -import { error, json } from "@sveltejs/kit"; -import { d as db, m as mappool, a as mappoolSlot } from "../../../../../chunks/index2.js"; -import { eq } from "drizzle-orm"; -const GET = async ({ params, locals }) => { - if (!locals.user) error(401, "Not logged in"); - const pool = await db.query.mappool.findFirst({ - where: eq(mappool.id, params.id) - }); - if (!pool) error(404, "Mappool not found"); - const slots = await db.query.mappoolSlot.findMany({ - where: eq(mappoolSlot.mappoolId, params.id), - orderBy: (s, { asc }) => [asc(s.category), asc(s.orderInCategory)] - }); - return json({ ...pool, slots }); -}; -const DELETE = async ({ params, locals }) => { - if (!locals.user) error(401, "Not logged in"); - await db.delete(mappool).where(eq(mappool.id, params.id)); - return json({ ok: true }); -}; -export { - DELETE, - GET -}; diff --git a/.svelte-kit/output/server/entries/endpoints/api/mappools/_id_/slots/_server.ts.js b/.svelte-kit/output/server/entries/endpoints/api/mappools/_id_/slots/_server.ts.js deleted file mode 100644 index b61da5c..0000000 --- a/.svelte-kit/output/server/entries/endpoints/api/mappools/_id_/slots/_server.ts.js +++ /dev/null @@ -1,27 +0,0 @@ -import { error, json } from "@sveltejs/kit"; -import { d as db, a as mappoolSlot } from "../../../../../../chunks/index2.js"; -import { and, eq } from "drizzle-orm"; -const POST = async ({ params, request, locals }) => { - if (!locals.user) error(401, "Not logged in"); - const { beatmapId, category, mods } = await request.json(); - if (!beatmapId || !category) { - error(400, "beatmapId and category are required"); - } - const existing = await db.query.mappoolSlot.findMany({ - where: and( - eq(mappoolSlot.mappoolId, params.id), - eq(mappoolSlot.category, category.toUpperCase()) - ) - }); - const [created] = await db.insert(mappoolSlot).values({ - mappoolId: params.id, - beatmapId: String(beatmapId), - category: category.toUpperCase(), - orderInCategory: existing.length + 1, - mods: mods ?? [] - }).returning(); - return json(created, { status: 201 }); -}; -export { - POST -}; diff --git a/.svelte-kit/output/server/entries/endpoints/api/mappools/_id_/slots/_slotId_/_server.ts.js b/.svelte-kit/output/server/entries/endpoints/api/mappools/_id_/slots/_slotId_/_server.ts.js deleted file mode 100644 index c77f59a..0000000 --- a/.svelte-kit/output/server/entries/endpoints/api/mappools/_id_/slots/_slotId_/_server.ts.js +++ /dev/null @@ -1,11 +0,0 @@ -import { error, json } from "@sveltejs/kit"; -import { d as db, a as mappoolSlot } from "../../../../../../../chunks/index2.js"; -import { eq } from "drizzle-orm"; -const DELETE = async ({ params, locals }) => { - if (!locals.user) error(401, "Not logged in"); - await db.delete(mappoolSlot).where(eq(mappoolSlot.id, params.slotId)); - return json({ ok: true }); -}; -export { - DELETE -}; diff --git a/.svelte-kit/output/server/entries/endpoints/api/mappools/_server.ts.js b/.svelte-kit/output/server/entries/endpoints/api/mappools/_server.ts.js deleted file mode 100644 index bf904be..0000000 --- a/.svelte-kit/output/server/entries/endpoints/api/mappools/_server.ts.js +++ /dev/null @@ -1,23 +0,0 @@ -import { error, json } from "@sveltejs/kit"; -import { d as db, m as mappool } from "../../../../chunks/index2.js"; -const GET = async ({ locals }) => { - if (!locals.user) error(401, "Not logged in"); - const mappools = await db.query.mappool.findMany({ - orderBy: (m, { desc }) => [desc(m.createdAt)] - }); - return json(mappools); -}; -const POST = async ({ request, locals }) => { - if (!locals.user) error(401, "Not logged in"); - const { name } = await request.json(); - if (!name?.trim()) error(400, "Name is required"); - const [created] = await db.insert(mappool).values({ - name: name.trim(), - createdBy: locals.user.id - }).returning(); - return json(created, { status: 201 }); -}; -export { - GET, - POST -}; diff --git a/.svelte-kit/output/server/entries/endpoints/api/matches/_id_/_server.ts.js b/.svelte-kit/output/server/entries/endpoints/api/matches/_id_/_server.ts.js deleted file mode 100644 index b383e98..0000000 --- a/.svelte-kit/output/server/entries/endpoints/api/matches/_id_/_server.ts.js +++ /dev/null @@ -1,24 +0,0 @@ -import { error, json } from "@sveltejs/kit"; -import { a as cancelMatch, g as getMatchFull } from "../../../../../chunks/engine.js"; -const GET = async ({ params, locals }) => { - if (!locals.user) error(401, "Not logged in"); - try { - const m = await getMatchFull(params.id); - return json(m); - } catch (e) { - error(404, e.message); - } -}; -const DELETE = async ({ params, locals }) => { - if (!locals.user) error(401, "Not logged in"); - try { - const m = await cancelMatch(params.id); - return json(m); - } catch (e) { - error(400, e.message); - } -}; -export { - DELETE, - GET -}; diff --git a/.svelte-kit/output/server/entries/endpoints/api/matches/_id_/lobby/_server.ts.js b/.svelte-kit/output/server/entries/endpoints/api/matches/_id_/lobby/_server.ts.js deleted file mode 100644 index 35ed7aa..0000000 --- a/.svelte-kit/output/server/entries/endpoints/api/matches/_id_/lobby/_server.ts.js +++ /dev/null @@ -1,15 +0,0 @@ -import { error, json } from "@sveltejs/kit"; -import { m as moveToLobby } from "../../../../../../chunks/engine.js"; -const POST = async ({ params, request, locals }) => { - if (!locals.user) error(401, "Not logged in"); - const body = await request.json().catch(() => ({})); - try { - const m = await moveToLobby(params.id, body.osuLobbyId); - return json(m); - } catch (e) { - error(400, e.message); - } -}; -export { - POST -}; diff --git a/.svelte-kit/output/server/entries/endpoints/api/matches/_id_/pick/_server.ts.js b/.svelte-kit/output/server/entries/endpoints/api/matches/_id_/pick/_server.ts.js deleted file mode 100644 index a655c49..0000000 --- a/.svelte-kit/output/server/entries/endpoints/api/matches/_id_/pick/_server.ts.js +++ /dev/null @@ -1,18 +0,0 @@ -import { error, json } from "@sveltejs/kit"; -import { p as pickMap } from "../../../../../../chunks/engine.js"; -const POST = async ({ params, request, locals }) => { - if (!locals.user) error(401, "Not logged in"); - const { participantId, mappoolSlotId } = await request.json(); - if (!participantId || !mappoolSlotId) { - error(400, "participantId and mappoolSlotId required"); - } - try { - const game = await pickMap(params.id, participantId, mappoolSlotId); - return json(game); - } catch (e) { - error(400, e.message); - } -}; -export { - POST -}; diff --git a/.svelte-kit/output/server/entries/endpoints/api/matches/_id_/roll/_server.ts.js b/.svelte-kit/output/server/entries/endpoints/api/matches/_id_/roll/_server.ts.js deleted file mode 100644 index 21f102e..0000000 --- a/.svelte-kit/output/server/entries/endpoints/api/matches/_id_/roll/_server.ts.js +++ /dev/null @@ -1,18 +0,0 @@ -import { error, json } from "@sveltejs/kit"; -import { s as submitRoll } from "../../../../../../chunks/engine.js"; -const POST = async ({ params, request, locals }) => { - if (!locals.user) error(401, "Not logged in"); - const { participantId, value } = await request.json(); - if (!participantId || value == null) { - error(400, "participantId and value required"); - } - try { - const m = await submitRoll(params.id, participantId, value); - return json(m); - } catch (e) { - error(400, e.message); - } -}; -export { - POST -}; diff --git a/.svelte-kit/output/server/entries/endpoints/api/matches/_id_/rolling/_server.ts.js b/.svelte-kit/output/server/entries/endpoints/api/matches/_id_/rolling/_server.ts.js deleted file mode 100644 index e5cc1e3..0000000 --- a/.svelte-kit/output/server/entries/endpoints/api/matches/_id_/rolling/_server.ts.js +++ /dev/null @@ -1,14 +0,0 @@ -import { error, json } from "@sveltejs/kit"; -import { b as moveToRolling } from "../../../../../../chunks/engine.js"; -const POST = async ({ params, locals }) => { - if (!locals.user) error(401, "Not logged in"); - try { - const m = await moveToRolling(params.id); - return json(m); - } catch (e) { - error(400, e.message); - } -}; -export { - POST -}; diff --git a/.svelte-kit/output/server/entries/endpoints/api/matches/_id_/score/_server.ts.js b/.svelte-kit/output/server/entries/endpoints/api/matches/_id_/score/_server.ts.js deleted file mode 100644 index cd031cb..0000000 --- a/.svelte-kit/output/server/entries/endpoints/api/matches/_id_/score/_server.ts.js +++ /dev/null @@ -1,18 +0,0 @@ -import { error, json } from "@sveltejs/kit"; -import { d as submitGameScores } from "../../../../../../chunks/engine.js"; -const POST = async ({ request, locals }) => { - if (!locals.user) error(401, "Not logged in"); - const { matchGameId, scores } = await request.json(); - if (!matchGameId || !scores?.length) { - error(400, "matchGameId and scores required"); - } - try { - const m = await submitGameScores(matchGameId, scores); - return json(m); - } catch (e) { - error(400, e.message); - } -}; -export { - POST -}; diff --git a/.svelte-kit/output/server/entries/endpoints/api/matches/_server.ts.js b/.svelte-kit/output/server/entries/endpoints/api/matches/_server.ts.js deleted file mode 100644 index 3732a25..0000000 --- a/.svelte-kit/output/server/entries/endpoints/api/matches/_server.ts.js +++ /dev/null @@ -1,37 +0,0 @@ -import { error, json } from "@sveltejs/kit"; -import { d as db } from "../../../../chunks/index2.js"; -import { c as createMatch } from "../../../../chunks/engine.js"; -const GET = async ({ locals }) => { - if (!locals.user) error(401, "Not logged in"); - const matches = await db.query.match.findMany({ - with: { - participants: { with: { team: true } } - }, - orderBy: (m, { desc }) => [desc(m.createdAt)] - }); - return json(matches); -}; -const POST = async ({ request, locals }) => { - if (!locals.user) error(401, "Not logged in"); - const body = await request.json(); - const { name, config, mappoolId, teams } = body; - if (!name || !config || !mappoolId || !teams?.length) { - error(400, "Missing required fields"); - } - try { - const result = await createMatch({ - name, - config, - mappoolId, - teams, - createdBy: locals.user.id - }); - return json(result, { status: 201 }); - } catch (e) { - error(400, e.message); - } -}; -export { - GET, - POST -}; diff --git a/.svelte-kit/output/server/entries/endpoints/api/osu/beatmap/_id_/_server.ts.js b/.svelte-kit/output/server/entries/endpoints/api/osu/beatmap/_id_/_server.ts.js deleted file mode 100644 index c258470..0000000 --- a/.svelte-kit/output/server/entries/endpoints/api/osu/beatmap/_id_/_server.ts.js +++ /dev/null @@ -1,14 +0,0 @@ -import { error, json } from "@sveltejs/kit"; -import { g as getBeatmap } from "../../../../../../chunks/api.js"; -const GET = async ({ params, locals }) => { - if (!locals.user) error(401, "Not logged in"); - try { - const beatmap = await getBeatmap(params.id); - return json(beatmap); - } catch { - error(404, "Beatmap not found"); - } -}; -export { - GET -}; diff --git a/.svelte-kit/output/server/entries/endpoints/api/queue/_server.ts.js b/.svelte-kit/output/server/entries/endpoints/api/queue/_server.ts.js deleted file mode 100644 index d6b0508..0000000 --- a/.svelte-kit/output/server/entries/endpoints/api/queue/_server.ts.js +++ /dev/null @@ -1,36 +0,0 @@ -import { error, json } from "@sveltejs/kit"; -import { l as leaveQueue, e as getQueueStatus, j as joinQueue } from "../../../../chunks/engine.js"; -import { d as db, t as teamMember } from "../../../../chunks/index2.js"; -import { eq } from "drizzle-orm"; -const GET = async ({ locals }) => { - if (!locals.user) error(401, "Not logged in"); - const status = await getQueueStatus(locals.user.id); - return json(status); -}; -const POST = async ({ locals }) => { - if (!locals.user) error(401, "Not logged in"); - const membership = await db.query.teamMember.findFirst({ - where: eq(teamMember.userId, locals.user.id), - with: { team: true } - }); - const personalTeam = membership?.team; - if (!personalTeam?.isPersonal) { - error(400, "No personal team found"); - } - try { - const result = await joinQueue(locals.user.id, personalTeam.id); - return json({ matched: !!result, match: result }); - } catch (e) { - error(400, e.message); - } -}; -const DELETE = async ({ locals }) => { - if (!locals.user) error(401, "Not logged in"); - await leaveQueue(locals.user.id); - return json({ ok: true }); -}; -export { - DELETE, - GET, - POST -}; diff --git a/.svelte-kit/output/server/entries/fallbacks/layout.svelte.js b/.svelte-kit/output/server/entries/fallbacks/layout.svelte.js deleted file mode 100644 index c3792df..0000000 --- a/.svelte-kit/output/server/entries/fallbacks/layout.svelte.js +++ /dev/null @@ -1,9 +0,0 @@ -import "clsx"; -function Layout($$renderer, $$props) { - let { children } = $$props; - children($$renderer); - $$renderer.push(``); -} -export { - Layout as default -}; diff --git a/.svelte-kit/output/server/entries/hooks.server.js b/.svelte-kit/output/server/entries/hooks.server.js deleted file mode 100644 index 35278f0..0000000 --- a/.svelte-kit/output/server/entries/hooks.server.js +++ /dev/null @@ -1,22 +0,0 @@ -import { b as building } from "../chunks/environment.js"; -import { a as auth, s as svelteKitHandler } from "../chunks/auth.js"; -import { d as db, u as user } from "../chunks/index2.js"; -import { eq } from "drizzle-orm"; -const handleBetterAuth = async ({ event, resolve }) => { - const session = await auth.api.getSession({ headers: event.request.headers }); - if (session) { - event.locals.session = session.session; - const dbUser = await db.query.user.findFirst({ - where: eq(user.id, session.user.id) - }); - event.locals.user = { - ...session.user, - role: dbUser?.role ?? "player" - }; - } - return svelteKitHandler({ event, resolve, auth, building }); -}; -const handle = handleBetterAuth; -export { - handle -}; diff --git a/.svelte-kit/output/server/entries/pages/(app)/_layout.server.ts.js b/.svelte-kit/output/server/entries/pages/(app)/_layout.server.ts.js deleted file mode 100644 index 18d72d1..0000000 --- a/.svelte-kit/output/server/entries/pages/(app)/_layout.server.ts.js +++ /dev/null @@ -1,14 +0,0 @@ -const load = async ({ locals }) => { - return { - user: locals.user ? { - id: locals.user.id, - name: locals.user.name, - email: locals.user.email, - image: locals.user.image, - role: locals.user.role ?? "player" - } : null - }; -}; -export { - load -}; diff --git a/.svelte-kit/output/server/entries/pages/(app)/_layout.svelte.js b/.svelte-kit/output/server/entries/pages/(app)/_layout.svelte.js deleted file mode 100644 index 068b523..0000000 --- a/.svelte-kit/output/server/entries/pages/(app)/_layout.svelte.js +++ /dev/null @@ -1,97 +0,0 @@ -import { a as ensure_array_like, b as attr, c as attr_class, s as stringify, e as escape_html, d as derived } from "../../../chunks/index3.js"; -import { p as page } from "../../../chunks/index4.js"; -import "@sveltejs/kit/internal"; -import "../../../chunks/url.js"; -import "../../../chunks/utils.js"; -import "@sveltejs/kit/internal/server"; -import "../../../chunks/root.js"; -import "../../../chunks/exports.js"; -import "../../../chunks/state.svelte.js"; -function Sidebar($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - const user = derived(() => page.data?.user); - const nav = [ - { href: "/", label: "Dashboard", icon: "⌂" }, - { href: "/matches", label: "Matches", icon: "⚔" }, - { href: "/mappools", label: "Mappools", icon: "♫" }, - { href: "/teams", label: "Teams", icon: "⚑" } - ]; - function isActive(href) { - if (href === "/") return page.url.pathname === "/"; - return page.url.pathname.startsWith(href); - } - const isAdmin = derived(() => user()?.role === "admin"); - $$renderer2.push(``); - }); -} -function Header($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - const user = derived(() => page.data?.user); - const roleBadge = { - referee: { label: "REF", color: "bg-yellow-500/20 text-yellow-400" }, - admin: { label: "ADMIN", color: "bg-red-500/20 text-red-400" } - }; - const badge = derived(() => user()?.role ? roleBadge[user().role] : null); - $$renderer2.push(`
`); - if (user()) { - $$renderer2.push(""); - $$renderer2.push(`
`); - if (badge()) { - $$renderer2.push(""); - $$renderer2.push(`${escape_html(badge().label)}`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (user().image) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` ${escape_html(user().name)}
`); - } else { - $$renderer2.push(""); - $$renderer2.push(`Sign in with osu!`); - } - $$renderer2.push(`
`); - }); -} -function _layout($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - let { children } = $$props; - const user = derived(() => page.data?.user); - if (user()) { - $$renderer2.push(""); - $$renderer2.push(`
`); - Sidebar($$renderer2); - $$renderer2.push(`
`); - Header($$renderer2); - $$renderer2.push(`
`); - children($$renderer2); - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - $$renderer2.push(`
V
Vash Esports
Sign in with osu!
`); - children($$renderer2); - $$renderer2.push(`
`); - } - $$renderer2.push(``); - }); -} -export { - _layout as default -}; diff --git a/.svelte-kit/output/server/entries/pages/(app)/_page.server.ts.js b/.svelte-kit/output/server/entries/pages/(app)/_page.server.ts.js deleted file mode 100644 index e04978c..0000000 --- a/.svelte-kit/output/server/entries/pages/(app)/_page.server.ts.js +++ /dev/null @@ -1,39 +0,0 @@ -import { d as db, b as match, c as team, m as mappool } from "../../../chunks/index2.js"; -import { desc, inArray, count, eq } from "drizzle-orm"; -const load = async ({ locals }) => { - if (!locals.user) { - return { - authenticated: false, - recentMatches: [], - liveMatches: [], - stats: { matches: 0, finished: 0, teams: 0, mappools: 0 } - }; - } - const recentMatches = await db.query.match.findMany({ - with: { participants: { with: { team: true } } }, - orderBy: desc(match.createdAt), - limit: 5 - }); - const liveMatches = await db.query.match.findMany({ - with: { participants: { with: { team: true } } }, - where: inArray(match.state, ["LOBBY", "ROLLING", "PICKING", "PLAYING"]) - }); - const [matchCount] = await db.select({ count: count() }).from(match); - const [teamCount] = await db.select({ count: count() }).from(team); - const [poolCount] = await db.select({ count: count() }).from(mappool); - const [finishedCount] = await db.select({ count: count() }).from(match).where(eq(match.state, "FINISHED")); - return { - authenticated: true, - recentMatches, - liveMatches, - stats: { - matches: matchCount.count, - finished: finishedCount.count, - teams: teamCount.count, - mappools: poolCount.count - } - }; -}; -export { - load -}; diff --git a/.svelte-kit/output/server/entries/pages/(app)/_page.svelte.js b/.svelte-kit/output/server/entries/pages/(app)/_page.svelte.js deleted file mode 100644 index 6f98657..0000000 --- a/.svelte-kit/output/server/entries/pages/(app)/_page.svelte.js +++ /dev/null @@ -1,118 +0,0 @@ -import { e as escape_html, a as ensure_array_like, b as attr, s as stringify, c as attr_class } from "../../../chunks/index3.js"; -function _page($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - let { data } = $$props; - const stateConfig = { - CREATED: { label: "Created", color: "text-text-secondary" }, - LOBBY: { label: "In Lobby", color: "text-yellow-400" }, - ROLLING: { - label: "Rolling", - color: "text-yellow-400", - dot: "bg-yellow-400" - }, - PICKING: { label: "Picking", color: "text-blue-400", dot: "bg-blue-400" }, - PLAYING: { label: "Live", color: "text-green-400", dot: "bg-green-400" }, - FINISHED: { label: "Finished", color: "text-text-secondary" }, - CANCELLED: { label: "Cancelled", color: "text-red-400" } - }; - let queueLoading = false; - function timeAgo(date) { - const d = new Date(date); - const diff = Date.now() - d.getTime(); - const mins = Math.floor(diff / 6e4); - if (mins < 1) return "just now"; - if (mins < 60) return `${mins}m ago`; - const hours = Math.floor(mins / 60); - if (hours < 24) return `${hours}h ago`; - const days = Math.floor(hours / 24); - return `${days}d ago`; - } - if (!data.user) { - $$renderer2.push(""); - $$renderer2.push(`
V

Welcome to Vash Esports

Automated tournament match management for osu! — lobbies, mappools, picks, bans, and - ELO tracking all in one place.

Sign in with osu!

Uses your osu! account. No extra registration needed.

`); - } else { - $$renderer2.push(""); - $$renderer2.push(`

Welcome back, ${escape_html(data.user.name)}

Automated esports match management for osu!

${escape_html(data.stats.matches)}

Total Matches

${escape_html(data.stats.finished)}

Completed

${escape_html(data.stats.teams)}

Teams

${escape_html(data.stats.mappools)}

Mappools

`); - if (data.liveMatches.length > 0) { - $$renderer2.push(""); - $$renderer2.push(`

Live Now

`); - const each_array = ensure_array_like(data.liveMatches); - for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) { - let m = each_array[$$index]; - const p1 = m.participants[0]; - const p2 = m.participants[1]; - const sc = stateConfig[m.state]; - $$renderer2.push(`
`); - if (p1?.team.avatarUrl) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` ${escape_html(p1?.team.name ?? "?")}
${escape_html(p1?.score ?? 0)} vs ${escape_html(p2?.score ?? 0)}
${escape_html(p2?.team.name ?? "?")} `); - if (p2?.team.avatarUrl) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - if (sc?.dot) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` ${escape_html(sc?.label)}`); - } - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`

Ranked Queue

Find a match at your skill level

`); - { - $$renderer2.push(""); - $$renderer2.push(`${escape_html("Find Match")}`); - } - $$renderer2.push(`

Recent Matches

`); - const each_array_1 = ensure_array_like(data.recentMatches); - if (each_array_1.length !== 0) { - $$renderer2.push(""); - for (let $$index_1 = 0, $$length = each_array_1.length; $$index_1 < $$length; $$index_1++) { - let m = each_array_1[$$index_1]; - const p1 = m.participants[0]; - const p2 = m.participants[1]; - const config = m.config; - const sc = stateConfig[m.state]; - $$renderer2.push(`
${escape_html(p1?.team.name ?? "?")} `); - if (m.state === "FINISHED") { - $$renderer2.push(""); - $$renderer2.push(` (p2?.score ?? 0) ? "text-green-400" : "text-text-secondary")}`)}>${escape_html(p1?.score ?? 0)} - (p1?.score ?? 0) ? "text-green-400" : "text-text-secondary")}`)}>${escape_html(p2?.score ?? 0)}`); - } else { - $$renderer2.push(""); - $$renderer2.push(`vs`); - } - $$renderer2.push(` ${escape_html(p2?.team.name ?? "?")}

${escape_html(m.name ? `${m.name} · ` : "")}BO${escape_html(config.bestOf)} - · ${escape_html(timeAgo(m.finishedAt ?? m.createdAt))}

`); - if (m.state === "FINISHED" && m.winnerId) { - $$renderer2.push(""); - const winner = m.participants.find((p) => p.teamId === m.winnerId); - $$renderer2.push(`🏆 ${escape_html(winner?.team.name)}`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` ${escape_html(sc?.label)}`); - } - } else { - $$renderer2.push(""); - $$renderer2.push(`

No matches yet. Create one

`); - } - $$renderer2.push(`
`); - } - $$renderer2.push(``); - }); -} -export { - _page as default -}; diff --git a/.svelte-kit/output/server/entries/pages/(app)/admin/_page.server.ts.js b/.svelte-kit/output/server/entries/pages/(app)/admin/_page.server.ts.js deleted file mode 100644 index 7f5e1cf..0000000 --- a/.svelte-kit/output/server/entries/pages/(app)/admin/_page.server.ts.js +++ /dev/null @@ -1,70 +0,0 @@ -import { d as db, u as user, p as playerRating } from "../../../../chunks/index2.js"; -import { eq, desc } from "drizzle-orm"; -import { error } from "@sveltejs/kit"; -const ROLE_HIERARCHY = { - player: 0, - referee: 1, - admin: 2 -}; -function hasRole(userRole, minRole) { - const level = ROLE_HIERARCHY[userRole] ?? 0; - const required = ROLE_HIERARCHY[minRole]; - return level >= required; -} -function requireRole(locals, minRole, message = "Insufficient permissions") { - if (!locals.user) { - error(401, "Not logged in"); - } - if (!hasRole(locals.user.role, minRole)) { - error(403, message); - } -} -async function setUserRole(userId, role) { - await db.update(user).set({ role }).where(eq(user.id, userId)); -} -const load = async ({ locals }) => { - requireRole(locals, "admin"); - const users = await db.query.user.findMany({ - orderBy: desc(user.createdAt) - }); - const usersWithRatings = await Promise.all( - users.map(async (u) => { - const rating = await db.query.playerRating.findFirst({ - where: eq(playerRating.userId, u.id) - }); - return { - id: u.id, - name: u.name, - email: u.email, - image: u.image, - role: u.role ?? "player", - createdAt: u.createdAt, - elo: rating?.elo ?? 1e3, - wins: rating?.wins ?? 0, - losses: rating?.losses ?? 0 - }; - }) - ); - return { users: usersWithRatings }; -}; -const actions = { - setRole: async ({ request, locals }) => { - requireRole(locals, "admin"); - const form = await request.formData(); - const userId = form.get("userId")?.toString(); - const role = form.get("role")?.toString(); - if (!userId || !role) return { error: "User ID and role are required" }; - if (!["player", "referee", "admin"].includes(role)) { - return { error: "Invalid role" }; - } - if (userId === locals.user.id && role !== "admin") { - return { error: "You can't demote yourself" }; - } - await setUserRole(userId, role); - return { success: true }; - } -}; -export { - actions, - load -}; diff --git a/.svelte-kit/output/server/entries/pages/(app)/admin/_page.svelte.js b/.svelte-kit/output/server/entries/pages/(app)/admin/_page.svelte.js deleted file mode 100644 index 59b9970..0000000 --- a/.svelte-kit/output/server/entries/pages/(app)/admin/_page.svelte.js +++ /dev/null @@ -1,70 +0,0 @@ -import { e as escape_html, a as ensure_array_like, b as attr, s as stringify } from "../../../../chunks/index3.js"; -import "@sveltejs/kit/internal"; -import "../../../../chunks/url.js"; -import "../../../../chunks/utils.js"; -import "@sveltejs/kit/internal/server"; -import "../../../../chunks/root.js"; -import "../../../../chunks/exports.js"; -import "../../../../chunks/state.svelte.js"; -function _page($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - let { data } = $$props; - const roleBadge = { - player: { - label: "Player", - color: "bg-surface-600 text-text-secondary border-border" - }, - referee: { - label: "Referee", - color: "bg-yellow-500/20 text-yellow-400 border-yellow-500/30" - }, - admin: { - label: "Admin", - color: "bg-red-500/20 text-red-400 border-red-500/30" - } - }; - $$renderer2.push(`

Admin Panel

${escape_html(data.users.length)} registered user${escape_html(data.users.length !== 1 ? "s" : "")}

`); - { - $$renderer2.push(""); - } - $$renderer2.push(`
Avatar User ELO W/L Role
`); - const each_array = ensure_array_like(data.users); - for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) { - let u = each_array[$$index]; - const badge = roleBadge[u.role] ?? roleBadge.player; - $$renderer2.push(`
`); - if (u.image) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - $$renderer2.push(`
${escape_html(u.name.charAt(0).toUpperCase())}
`); - } - $$renderer2.push(`

${escape_html(u.name)}

${escape_html(u.email)}

${escape_html(u.elo)} ${escape_html(u.wins)}W / ${escape_html(u.losses)}L
`); - $$renderer2.select( - { - name: "role", - value: u.role, - onchange: (e) => e.currentTarget.form?.requestSubmit(), - class: `rounded-md border px-2 py-1 text-xs font-500 ${stringify(badge.color)} cursor-pointer bg-transparent focus:outline-none` - }, - ($$renderer3) => { - $$renderer3.option({ value: "player", class: "bg-surface-800 text-text-primary" }, ($$renderer4) => { - $$renderer4.push(`Player`); - }); - $$renderer3.option({ value: "referee", class: "bg-surface-800 text-text-primary" }, ($$renderer4) => { - $$renderer4.push(`Referee`); - }); - $$renderer3.option({ value: "admin", class: "bg-surface-800 text-text-primary" }, ($$renderer4) => { - $$renderer4.push(`Admin`); - }); - } - ); - $$renderer2.push(`
`); - } - $$renderer2.push(`
`); - }); -} -export { - _page as default -}; diff --git a/.svelte-kit/output/server/entries/pages/(app)/mappools/_id_/_page.server.ts.js b/.svelte-kit/output/server/entries/pages/(app)/mappools/_id_/_page.server.ts.js deleted file mode 100644 index cbdf47b..0000000 --- a/.svelte-kit/output/server/entries/pages/(app)/mappools/_id_/_page.server.ts.js +++ /dev/null @@ -1,100 +0,0 @@ -import { d as db, m as mappool, a as mappoolSlot } from "../../../../../chunks/index2.js"; -import { eq, and } from "drizzle-orm"; -import { redirect, error } from "@sveltejs/kit"; -import { g as getBeatmap } from "../../../../../chunks/api.js"; -const load = async ({ params, locals }) => { - if (!locals.user) redirect(302, "/"); - const pool = await db.query.mappool.findFirst({ - where: eq(mappool.id, params.id), - with: { - slots: { - orderBy: (s, { asc }) => [asc(s.category), asc(s.orderInCategory)] - } - } - }); - if (!pool) error(404, "Mappool not found"); - const slotsWithBeatmaps = await Promise.all( - pool.slots.map(async (slot) => { - try { - const beatmap = await getBeatmap(slot.beatmapId); - return { - ...slot, - beatmap: { - title: beatmap.beatmapset.title, - artist: beatmap.beatmapset.artist, - version: beatmap.version, - starRating: beatmap.difficulty_rating, - bpm: beatmap.bpm, - totalLength: beatmap.total_length, - coverUrl: beatmap.beatmapset.covers["card@2x"], - url: beatmap.url - } - }; - } catch { - return { - ...slot, - beatmap: null - }; - } - }) - ); - return { - pool: { ...pool, slots: slotsWithBeatmaps } - }; -}; -const actions = { - addSlot: async ({ params, request, locals }) => { - if (!locals.user) redirect(302, "/"); - const form = await request.formData(); - let beatmapId = form.get("beatmapId")?.toString()?.trim(); - const category = form.get("category")?.toString()?.trim()?.toUpperCase(); - if (!beatmapId || !category) { - return { error: "Beatmap ID and category are required" }; - } - const urlMatch = beatmapId.match(/beatmaps\/(\d+)/); - const setMatch = beatmapId.match(/beatmapsets\/\d+#\w+\/(\d+)/); - if (urlMatch) beatmapId = urlMatch[1]; - else if (setMatch) beatmapId = setMatch[1]; - if (!/^\d+$/.test(beatmapId)) { - return { error: "Invalid beatmap ID" }; - } - let beatmap; - try { - beatmap = await getBeatmap(beatmapId); - } catch { - return { error: "Beatmap not found on osu!" }; - } - const existing = await db.query.mappoolSlot.findMany({ - where: and( - eq(mappoolSlot.mappoolId, params.id), - eq(mappoolSlot.category, category) - ) - }); - await db.insert(mappoolSlot).values({ - mappoolId: params.id, - beatmapId, - category, - orderInCategory: existing.length + 1, - starRating: beatmap.difficulty_rating, - mods: category === "NM" || category === "TB" || category === "FM" ? [] : [category] - }); - return { success: true }; - }, - removeSlot: async ({ request, locals }) => { - if (!locals.user) redirect(302, "/"); - const form = await request.formData(); - const slotId = form.get("slotId")?.toString(); - if (!slotId) return { error: "Missing slot ID" }; - await db.delete(mappoolSlot).where(eq(mappoolSlot.id, slotId)); - return { success: true }; - }, - deletePool: async ({ params, locals }) => { - if (!locals.user) redirect(302, "/"); - await db.delete(mappool).where(eq(mappool.id, params.id)); - redirect(303, "/mappools"); - } -}; -export { - actions, - load -}; diff --git a/.svelte-kit/output/server/entries/pages/(app)/mappools/_id_/_page.svelte.js b/.svelte-kit/output/server/entries/pages/(app)/mappools/_id_/_page.svelte.js deleted file mode 100644 index 0a8825e..0000000 --- a/.svelte-kit/output/server/entries/pages/(app)/mappools/_id_/_page.svelte.js +++ /dev/null @@ -1,98 +0,0 @@ -import { e as escape_html, a as ensure_array_like, b as attr, c as attr_class, d as derived, s as stringify } from "../../../../../chunks/index3.js"; -import "@sveltejs/kit/internal"; -import "../../../../../chunks/url.js"; -import "../../../../../chunks/utils.js"; -import "@sveltejs/kit/internal/server"; -import "../../../../../chunks/root.js"; -import "../../../../../chunks/exports.js"; -import "../../../../../chunks/state.svelte.js"; -function _page($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - let { data } = $$props; - const categories = ["NM", "HD", "HR", "DT", "FM", "TB"]; - let addingCategory = "NM"; - let beatmapInput = ""; - const grouped = derived(() => () => { - const groups = {}; - for (const cat of categories) { - const slots = data.pool.slots.filter((s) => s.category === cat); - if (slots.length > 0) groups[cat] = slots; - } - return groups; - }); - function formatLength(seconds) { - const m = Math.floor(seconds / 60); - const s = seconds % 60; - return `${m}:${s.toString().padStart(2, "0")}`; - } - const categoryColors = { - NM: "bg-blue-500/20 text-blue-400 border-blue-500/30", - HD: "bg-yellow-500/20 text-yellow-400 border-yellow-500/30", - HR: "bg-red-500/20 text-red-400 border-red-500/30", - DT: "bg-purple-500/20 text-purple-400 border-purple-500/30", - FM: "bg-green-500/20 text-green-400 border-green-500/30", - TB: "bg-pink-500/20 text-pink-400 border-pink-500/30" - }; - $$renderer2.push(`
←

${escape_html(data.pool.name)}

${escape_html(data.pool.slots.length)} map${escape_html(data.pool.slots.length !== 1 ? "s" : "")}

Add Map

`); - $$renderer2.select( - { - name: "category", - value: addingCategory, - class: "rounded-md border border-border bg-surface-700 px-3 py-2 text-sm text-text-primary focus:border-accent focus:outline-none" - }, - ($$renderer3) => { - $$renderer3.push(``); - const each_array = ensure_array_like(categories); - for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) { - let cat = each_array[$$index]; - $$renderer3.option({ value: cat }, ($$renderer4) => { - $$renderer4.push(`${escape_html(cat)}`); - }); - } - $$renderer3.push(``); - } - ); - $$renderer2.push(`
`); - { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - const each_array_1 = ensure_array_like(Object.entries(grouped()())); - if (each_array_1.length !== 0) { - $$renderer2.push(""); - for (let $$index_2 = 0, $$length = each_array_1.length; $$index_2 < $$length; $$index_2++) { - let [category, slots] = each_array_1[$$index_2]; - $$renderer2.push(`
${escape_html(category)} ${escape_html(slots.length)} map${escape_html(slots.length !== 1 ? "s" : "")}
`); - const each_array_2 = ensure_array_like(slots); - for (let i = 0, $$length2 = each_array_2.length; i < $$length2; i++) { - let slot = each_array_2[i]; - $$renderer2.push(`
`); - if (slot.beatmap?.coverUrl) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - $$renderer2.push(`
No cover
`); - } - $$renderer2.push(`
`); - if (slot.beatmap) { - $$renderer2.push(""); - $$renderer2.push(`${escape_html(slot.beatmap.artist)} - ${escape_html(slot.beatmap.title)}
[${escape_html(slot.beatmap.version)}] ★ ${escape_html(slot.beatmap.starRating.toFixed(2))} ${escape_html(slot.beatmap.bpm)} BPM ${escape_html(formatLength(slot.beatmap.totalLength))}
`); - } else { - $$renderer2.push(""); - $$renderer2.push(`

Beatmap #${escape_html(slot.beatmapId)}

`); - } - $$renderer2.push(`
${escape_html(category)}${escape_html(i + 1)}
`); - } - $$renderer2.push(`
`); - } - } else { - $$renderer2.push(""); - $$renderer2.push(`

No maps yet. Add your first map above.

`); - } - $$renderer2.push(`
`); - }); -} -export { - _page as default -}; diff --git a/.svelte-kit/output/server/entries/pages/(app)/mappools/_page.server.ts.js b/.svelte-kit/output/server/entries/pages/(app)/mappools/_page.server.ts.js deleted file mode 100644 index 77c98ad..0000000 --- a/.svelte-kit/output/server/entries/pages/(app)/mappools/_page.server.ts.js +++ /dev/null @@ -1,24 +0,0 @@ -import { d as db, m as mappool } from "../../../../chunks/index2.js"; -import { redirect } from "@sveltejs/kit"; -const load = async ({ locals }) => { - if (!locals.user) redirect(302, "/"); - const mappools = await db.query.mappool.findMany({ - with: { slots: true }, - orderBy: (m, { desc }) => [desc(m.createdAt)] - }); - return { mappools }; -}; -const actions = { - create: async ({ request, locals }) => { - if (!locals.user) redirect(302, "/"); - const form = await request.formData(); - const name = form.get("name")?.toString()?.trim(); - if (!name) return { error: "Name is required" }; - const [created] = await db.insert(mappool).values({ name, createdBy: locals.user.id }).returning(); - redirect(303, `/mappools/${created.id}`); - } -}; -export { - actions, - load -}; diff --git a/.svelte-kit/output/server/entries/pages/(app)/mappools/_page.svelte.js b/.svelte-kit/output/server/entries/pages/(app)/mappools/_page.svelte.js deleted file mode 100644 index c122aec..0000000 --- a/.svelte-kit/output/server/entries/pages/(app)/mappools/_page.svelte.js +++ /dev/null @@ -1,34 +0,0 @@ -import { e as escape_html, a as ensure_array_like, b as attr, s as stringify } from "../../../../chunks/index3.js"; -import "@sveltejs/kit/internal"; -import "../../../../chunks/url.js"; -import "../../../../chunks/utils.js"; -import "@sveltejs/kit/internal/server"; -import "../../../../chunks/root.js"; -import "../../../../chunks/exports.js"; -import "../../../../chunks/state.svelte.js"; -function _page($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - let { data } = $$props; - $$renderer2.push(`

Mappools

Create and manage your beatmap pools

`); - { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - const each_array = ensure_array_like(data.mappools); - if (each_array.length !== 0) { - $$renderer2.push(""); - for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) { - let pool = each_array[$$index]; - $$renderer2.push(`

${escape_html(pool.name)}

${escape_html(pool.slots.length)} map${escape_html(pool.slots.length !== 1 ? "s" : "")} - · Created ${escape_html(new Date(pool.createdAt).toLocaleDateString())}

→`); - } - } else { - $$renderer2.push(""); - $$renderer2.push(`

No mappools yet. Create one to get started.

`); - } - $$renderer2.push(`
`); - }); -} -export { - _page as default -}; diff --git a/.svelte-kit/output/server/entries/pages/(app)/matches/_id_/_page.server.ts.js b/.svelte-kit/output/server/entries/pages/(app)/matches/_id_/_page.server.ts.js deleted file mode 100644 index 497a952..0000000 --- a/.svelte-kit/output/server/entries/pages/(app)/matches/_id_/_page.server.ts.js +++ /dev/null @@ -1,129 +0,0 @@ -import { d as db, u as user } from "../../../../../chunks/index2.js"; -import { a as cancelMatch, g as getMatchFull, p as pickMap, s as submitRoll } from "../../../../../chunks/engine.js"; -import { c as closeLobby, f as forceStartGame, p as playPickedMap, g as getLobby } from "../../../../../chunks/orchestrator.js"; -import { redirect, error } from "@sveltejs/kit"; -import { g as getBeatmap } from "../../../../../chunks/api.js"; -import { eq } from "drizzle-orm"; -const load = async ({ params, locals }) => { - if (!locals.user) redirect(302, "/"); - let m; - try { - m = await getMatchFull(params.id); - } catch { - error(404, "Match not found"); - } - const beatmapCache = {}; - if (m.mappool?.slots) { - await Promise.allSettled( - m.mappool.slots.map(async (slot) => { - try { - const bm = await getBeatmap(slot.beatmapId); - beatmapCache[slot.beatmapId] = { - title: bm.beatmapset.title, - artist: bm.beatmapset.artist, - version: bm.version, - starRating: bm.difficulty_rating, - bpm: bm.bpm, - totalLength: bm.total_length, - coverUrl: bm.beatmapset.covers["card@2x"], - listCoverUrl: bm.beatmapset.covers["list@2x"] - }; - } catch { - } - }) - ); - } - return { match: m, beatmapCache, userId: locals.user.id }; -}; -const actions = { - reinvite: async ({ params, locals }) => { - if (!locals.user) redirect(302, "/"); - const lobby = getLobby(params.id); - if (!lobby) return { error: "No active IRC lobby for this match" }; - const m = await getMatchFull(params.id); - const invited = []; - for (const p of m.participants) { - for (const pl of p.players) { - const u = await db.query.user.findFirst({ where: eq(user.id, pl.userId) }); - if (u?.name) { - await lobby.invite(u.name); - invited.push(u.name); - } - } - } - return { reinvited: invited }; - }, - roll: async ({ params, locals }) => { - if (!locals.user) redirect(302, "/"); - const m = await getMatchFull(params.id); - let myParticipant = m.participants.find( - (p) => p.players.some((pl) => pl.userId === locals.user.id) - ); - if (!myParticipant) { - return { error: "You are not in this match" }; - } - if (myParticipant.rollValue !== null) { - const unrolled = m.participants.find((p) => p.rollValue === null); - if (unrolled) { - myParticipant = unrolled; - } else { - return { error: "All participants have already rolled" }; - } - } - const value = Math.floor(Math.random() * 100) + 1; - await submitRoll(params.id, myParticipant.id, value); - const lobby = getLobby(params.id); - if (lobby) { - lobby.chat(`${myParticipant.team?.name ?? "Player"} rolled ${value} (via web)`).catch(() => { - }); - const updated = await getMatchFull(params.id); - if (updated.state === "PICKING") { - const sorted = [...updated.participants].sort( - (a, b) => (a.pickOrder ?? 99) - (b.pickOrder ?? 99) - ); - lobby.chat( - `Rolls complete! ${sorted[0]?.team.name} picks first. Use !pick (e.g. !pick NM1) or pick in web UI.` - ).catch(() => { - }); - } - } - return { rolled: value, participantId: myParticipant.id }; - }, - pick: async ({ params, request, locals }) => { - if (!locals.user) redirect(302, "/"); - const form = await request.formData(); - const slotId = form.get("slotId")?.toString(); - if (!slotId) return { error: "No map selected" }; - const m = await getMatchFull(params.id); - const sorted = [...m.participants].sort( - (a, b) => (a.pickOrder ?? 99) - (b.pickOrder ?? 99) - ); - const expectedIdx = m.games.length % sorted.length; - const expectedPicker = sorted[expectedIdx]; - if (!expectedPicker) return { error: "Cannot determine picker" }; - try { - const game = await pickMap(params.id, expectedPicker.id, slotId); - playPickedMap(params.id, game.id).catch( - (err) => console.error("[Match] IRC play failed:", err.message) - ); - return { picked: true, gameId: game.id }; - } catch (e) { - return { error: e.message }; - } - }, - forceStart: async ({ params, locals }) => { - if (!locals.user) redirect(302, "/"); - await forceStartGame(params.id); - return { started: true }; - }, - cancel: async ({ params, locals }) => { - if (!locals.user) redirect(302, "/"); - await cancelMatch(params.id); - await closeLobby(params.id); - redirect(303, "/matches"); - } -}; -export { - actions, - load -}; diff --git a/.svelte-kit/output/server/entries/pages/(app)/matches/_id_/_page.svelte.js b/.svelte-kit/output/server/entries/pages/(app)/matches/_id_/_page.svelte.js deleted file mode 100644 index e6b854f..0000000 --- a/.svelte-kit/output/server/entries/pages/(app)/matches/_id_/_page.svelte.js +++ /dev/null @@ -1,323 +0,0 @@ -import { e as escape_html, b as attr, s as stringify, c as attr_class, a as ensure_array_like, d as derived } from "../../../../../chunks/index3.js"; -import "@sveltejs/kit/internal"; -import "../../../../../chunks/url.js"; -import "../../../../../chunks/utils.js"; -import "@sveltejs/kit/internal/server"; -import "../../../../../chunks/root.js"; -import "../../../../../chunks/exports.js"; -import "../../../../../chunks/state.svelte.js"; -function _page($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - let { data } = $$props; - let m = derived(() => data.match); - let p1 = derived(() => m().participants[0]); - let p2 = derived(() => m().participants[1]); - const config = derived(() => m().config); - const winsNeeded = derived(() => Math.ceil(config().bestOf / 2)); - const playedSlotIds = derived(() => new Set(m().games.map((g) => g.mappoolSlotId))); - const sortedByPick = derived(() => [...m().participants].sort((a, b) => (a.pickOrder ?? 99) - (b.pickOrder ?? 99))); - const expectedPickerIdx = derived(() => m().games.length % sortedByPick().length); - const expectedPicker = derived(() => sortedByPick()[expectedPickerIdx()]); - const canRoll = derived(() => m().state === "ROLLING" && m().participants.some((p) => p.rollValue === null)); - const catColors = { - NM: "bg-blue-500/20 text-blue-400 border-blue-500/30", - HD: "bg-yellow-500/20 text-yellow-400 border-yellow-500/30", - HR: "bg-red-500/20 text-red-400 border-red-500/30", - DT: "bg-purple-500/20 text-purple-400 border-purple-500/30", - FM: "bg-green-500/20 text-green-400 border-green-500/30", - TB: "bg-pink-500/20 text-pink-400 border-pink-500/30" - }; - const groupedSlots = derived(() => () => { - if (!m().mappool?.slots) return {}; - const groups = {}; - for (const slot of m().mappool.slots) { - if (!groups[slot.category]) groups[slot.category] = []; - groups[slot.category].push(slot); - } - for (const cat of Object.keys(groups)) { - groups[cat].sort((a, b) => a.orderInCategory - b.orderInCategory); - } - return groups; - }); - let rolling = false; - let picking = false; - let forceStarting = false; - function formatLength(seconds) { - const mins = Math.floor(seconds / 60); - const secs = seconds % 60; - return `${mins}:${secs.toString().padStart(2, "0")}`; - } - function stateLabel(s) { - return { - CREATED: "Waiting", - LOBBY: "In Lobby", - ROLLING: "Rolling", - PICKING: "Pick Phase", - PLAYING: "Playing", - FINISHED: "Finished", - CANCELLED: "Cancelled" - }[s] ?? s; - } - function stateBorder(s) { - return { - ROLLING: "border-yellow-500/30", - PICKING: "border-blue-500/30", - PLAYING: "border-green-500/30", - FINISHED: "border-accent/30" - }[s] ?? "border-border"; - } - $$renderer2.push(`
←

${escape_html(m().name || "Match")}

Best of ${escape_html(config().bestOf)} · First to ${escape_html(winsNeeded())} `); - if (m().osuLobbyId) { - $$renderer2.push(""); - $$renderer2.push(`· osu! mp/${escape_html(m().osuLobbyId)}`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`

${escape_html(stateLabel(m().state))} `); - if (!["FINISHED", "CANCELLED"].includes(m().state)) { - $$renderer2.push(""); - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - if (p1() && p2()) { - $$renderer2.push(""); - $$renderer2.push(`
`); - if (p1().team.avatarUrl) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`

${escape_html(p1().team.name)}

`); - if (p1().rollValue != null) { - $$renderer2.push(""); - $$renderer2.push(`

Roll: ${escape_html(p1().rollValue)}${escape_html(p1().pickOrder === 1 ? " ★" : "")}

`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
= winsNeeded() ? "text-green-400" : "text-text-primary")}`)}>${escape_html(p1().score)}
vs = winsNeeded() ? "text-green-400" : "text-text-primary")}`)}>${escape_html(p2().score)}

${escape_html(p2().team.name)}

`); - if (p2().rollValue != null) { - $$renderer2.push(""); - $$renderer2.push(`

${escape_html(p2().pickOrder === 1 ? "★ " : "")}Roll: ${escape_html(p2().rollValue)}

`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - if (p2().team.avatarUrl) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (["LOBBY", "ROLLING", "PICKING", "PLAYING"].includes(m().state)) { - $$renderer2.push(""); - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (m().state === "ROLLING") { - $$renderer2.push(""); - $$renderer2.push(`

🎲 Roll Phase

Highest roll picks first

`); - const each_array = ensure_array_like(m().participants); - for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) { - let p = each_array[$$index]; - $$renderer2.push(`

${escape_html(p.team.name)}

`); - if (p.rollValue != null) { - $$renderer2.push(""); - $$renderer2.push(`

${escape_html(p.rollValue)}

`); - } else { - $$renderer2.push(""); - $$renderer2.push(`

—

`); - } - $$renderer2.push(`
`); - } - $$renderer2.push(`
`); - if (canRoll()) { - $$renderer2.push(""); - $$renderer2.push(`

or type !roll in osu! chat

`); - } else { - $$renderer2.push(""); - $$renderer2.push(`

Waiting for all rolls...

`); - } - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (m().state === "PICKING") { - $$renderer2.push(""); - $$renderer2.push(`

🎯 Pick a Map

${escape_html(expectedPicker()?.team.name)}'s turn to pick

or type !pick NM1 in osu! chat

`); - { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - const each_array_1 = ensure_array_like(Object.entries(groupedSlots()())); - for (let $$index_2 = 0, $$length = each_array_1.length; $$index_2 < $$length; $$index_2++) { - let [category, slots] = each_array_1[$$index_2]; - $$renderer2.push(`
${escape_html(category)}
`); - const each_array_2 = ensure_array_like(slots); - for (let i = 0, $$length2 = each_array_2.length; i < $$length2; i++) { - let slot = each_array_2[i]; - const bm = data.beatmapCache[slot.beatmapId]; - const isPlayed = playedSlotIds().has(slot.id); - $$renderer2.push(`
`); - } - $$renderer2.push(`
`); - } - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (m().state === "PLAYING") { - $$renderer2.push(""); - const currentGame = m().games[m().games.length - 1]; - const bm = currentGame ? data.beatmapCache[currentGame.slot?.beatmapId] : null; - $$renderer2.push(`
Now Playing
`); - if (bm) { - $$renderer2.push(""); - $$renderer2.push(`

${escape_html(bm.artist)} - ${escape_html(bm.title)} [${escape_html(bm.version)}]

★${escape_html(bm.starRating.toFixed(1))} · ${escape_html(bm.bpm)}bpm · ${escape_html(formatLength(bm.totalLength))}

`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`

Waiting for players to ready up & play in osu!...

`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (m().state === "FINISHED") { - $$renderer2.push(""); - const winner = m().participants.find((p) => p.teamId === m().winnerId); - $$renderer2.push(`
🏆

${escape_html(winner?.team.name)} wins!

${escape_html(p1()?.score)} – ${escape_html(p2()?.score)}

`); - const each_array_3 = ensure_array_like(m().games); - for (let $$index_3 = 0, $$length = each_array_3.length; $$index_3 < $$length; $$index_3++) { - let game = each_array_3[$$index_3]; - const bm = data.beatmapCache[game.slot?.beatmapId]; - const winnerP = m().participants.find((p) => p.id === game.winnerParticipantId); - $$renderer2.push(`
${escape_html(game.slot?.category)}${escape_html(game.slot?.orderInCategory)} ${escape_html(bm ? `${bm.artist} - ${bm.title}` : `#${game.slot?.beatmapId}`)} ${escape_html(winnerP?.team.name)}
`); - } - $$renderer2.push(`
Back to Dashboard
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (m().games.length > 0) { - $$renderer2.push(""); - $$renderer2.push(`

Games Played

`); - const each_array_4 = ensure_array_like(m().games); - for (let $$index_4 = 0, $$length = each_array_4.length; $$index_4 < $$length; $$index_4++) { - let game = each_array_4[$$index_4]; - const bm = data.beatmapCache[game.slot?.beatmapId]; - const pickerTeam = m().participants.find((p) => p.id === game.pickedByParticipantId)?.team; - const winnerTeam = m().participants.find((p) => p.id === game.winnerParticipantId)?.team; - $$renderer2.push(`
${escape_html(game.gameNumber)} `); - if (bm?.listCoverUrl) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - if (bm) { - $$renderer2.push(""); - $$renderer2.push(`

${escape_html(bm.artist)} - ${escape_html(bm.title)} [${escape_html(bm.version)}]

`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
${escape_html(game.slot?.category)}${escape_html(game.slot?.orderInCategory)} `); - if (pickerTeam) { - $$renderer2.push(""); - $$renderer2.push(`Picked by ${escape_html(pickerTeam.name)}`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - if (game.state === "FINISHED" && p1() && p2()) { - $$renderer2.push(""); - const p1Score = game.scores.filter((s) => s.player?.participantId === p1().id).reduce((sum, s) => sum + s.score, 0); - const p2Score = game.scores.filter((s) => s.player?.participantId === p2().id).reduce((sum, s) => sum + s.score, 0); - $$renderer2.push(`
p2Score ? "font-700 text-green-400" : "text-text-secondary")}>${escape_html(p1Score.toLocaleString())} - p1Score ? "font-700 text-green-400" : "text-text-secondary")}>${escape_html(p2Score.toLocaleString())}
`); - } else if (game.state === "PLAYING") { - $$renderer2.push(""); - $$renderer2.push(`Live`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (winnerTeam) { - $$renderer2.push(""); - $$renderer2.push(`✓ ${escape_html(winnerTeam.name)}`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - } - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (m().state === "CREATED") { - $$renderer2.push(""); - $$renderer2.push(`

Creating osu! lobby...

`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (m().state === "LOBBY") { - $$renderer2.push(""); - $$renderer2.push(`

Lobby created. Waiting for players to join...

`); - if (m().osuLobbyId) { - $$renderer2.push(""); - $$renderer2.push(`

osu! mp/${escape_html(m().osuLobbyId)}

`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (m().state === "CANCELLED") { - $$renderer2.push(""); - $$renderer2.push(`

This match was cancelled.

`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(``); - }); -} -export { - _page as default -}; diff --git a/.svelte-kit/output/server/entries/pages/(app)/matches/_page.server.ts.js b/.svelte-kit/output/server/entries/pages/(app)/matches/_page.server.ts.js deleted file mode 100644 index 2891ac2..0000000 --- a/.svelte-kit/output/server/entries/pages/(app)/matches/_page.server.ts.js +++ /dev/null @@ -1,58 +0,0 @@ -import { d as db, b as match } from "../../../../chunks/index2.js"; -import { redirect } from "@sveltejs/kit"; -import { desc } from "drizzle-orm"; -import { c as createMatch } from "../../../../chunks/engine.js"; -import { i as initMatchLobby } from "../../../../chunks/orchestrator.js"; -const load = async ({ locals }) => { - if (!locals.user) redirect(302, "/"); - const matches = await db.query.match.findMany({ - with: { participants: { with: { team: true } } }, - orderBy: desc(match.createdAt), - limit: 50 - }); - const teams = await db.query.team.findMany({ - orderBy: (t, { asc }) => [asc(t.name)] - }); - const mappools = await db.query.mappool.findMany({ - with: { slots: true }, - orderBy: (m, { desc: desc2 }) => [desc2(m.createdAt)] - }); - return { matches, teams, mappools }; -}; -const actions = { - createMatch: async ({ request, locals }) => { - if (!locals.user) redirect(302, "/"); - const form = await request.formData(); - const name = form.get("name")?.toString()?.trim() || "Custom Match"; - const team1Id = form.get("team1")?.toString(); - const team2Id = form.get("team2")?.toString(); - const mappoolId = form.get("mappool")?.toString(); - const bestOf = parseInt(form.get("bestOf")?.toString() ?? "7"); - console.log("[Matches] CREATE:", { name, team1Id, team2Id, mappoolId, bestOf }); - if (!team1Id || !team2Id || !mappoolId) { - return { error: "All fields are required" }; - } - let result; - try { - result = await createMatch({ - name, - config: { bestOf, teamSize: 1, scoringType: "score" }, - mappoolId, - teams: [team1Id, team2Id], - createdBy: locals.user.id - }); - console.log("[Matches] Created:", result.id); - } catch (e) { - console.error("[Matches] Error:", e); - return { error: e.message }; - } - initMatchLobby(result.id).catch((err) => { - console.error("[Matches] IRC lobby failed:", err.message); - }); - redirect(303, `/matches/${result.id}`); - } -}; -export { - actions, - load -}; diff --git a/.svelte-kit/output/server/entries/pages/(app)/matches/_page.svelte.js b/.svelte-kit/output/server/entries/pages/(app)/matches/_page.svelte.js deleted file mode 100644 index 9af67ae..0000000 --- a/.svelte-kit/output/server/entries/pages/(app)/matches/_page.svelte.js +++ /dev/null @@ -1,164 +0,0 @@ -import { e as escape_html, a as ensure_array_like, b as attr, s as stringify, c as attr_class, d as derived } from "../../../../chunks/index3.js"; -import "@sveltejs/kit/internal"; -import "../../../../chunks/url.js"; -import "../../../../chunks/utils.js"; -import "@sveltejs/kit/internal/server"; -import "../../../../chunks/root.js"; -import "../../../../chunks/exports.js"; -import "../../../../chunks/state.svelte.js"; -function _page($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - let { data } = $$props; - const stateConfig = { - CREATED: { label: "Created", color: "text-text-secondary border-border" }, - LOBBY: { - label: "In Lobby", - color: "text-yellow-400 border-yellow-500/30" - }, - ROLLING: { - label: "Rolling", - color: "text-yellow-400 border-yellow-500/30", - dot: "bg-yellow-400" - }, - PICKING: { - label: "Picking", - color: "text-blue-400 border-blue-500/30", - dot: "bg-blue-400" - }, - PLAYING: { - label: "Live", - color: "text-green-400 border-green-500/30", - dot: "bg-green-400" - }, - FINISHED: { - label: "Finished", - color: "text-text-secondary border-border" - }, - CANCELLED: { label: "Cancelled", color: "text-red-400 border-red-500/30" } - }; - const liveStates = ["LOBBY", "ROLLING", "PICKING", "PLAYING"]; - const liveMatches = derived(() => data.matches.filter((m) => liveStates.includes(m.state))); - const recentMatches = derived(() => data.matches.filter((m) => !liveStates.includes(m.state))); - function teamDisplay(m) { - const p1 = m.participants[0]; - const p2 = m.participants[1]; - return { p1, p2 }; - } - function timeAgo(date) { - const d = new Date(date); - const diff = Date.now() - d.getTime(); - const mins = Math.floor(diff / 6e4); - if (mins < 1) return "just now"; - if (mins < 60) return `${mins}m ago`; - const hours = Math.floor(mins / 60); - if (hours < 24) return `${hours}h ago`; - const days = Math.floor(hours / 24); - return `${days}d ago`; - } - $$renderer2.push(`

Matches

${escape_html(data.matches.length)} match${escape_html(data.matches.length !== 1 ? "es" : "")} `); - if (liveMatches().length > 0) { - $$renderer2.push(""); - $$renderer2.push(`· ${escape_html(liveMatches().length)} live`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`

`); - { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (liveMatches().length > 0) { - $$renderer2.push(""); - $$renderer2.push(`

Live Now

`); - const each_array_4 = ensure_array_like(liveMatches()); - for (let $$index_4 = 0, $$length = each_array_4.length; $$index_4 < $$length; $$index_4++) { - let m = each_array_4[$$index_4]; - const { p1, p2 } = teamDisplay(m); - const sc = stateConfig[m.state]; - $$renderer2.push(`
`); - if (p1?.team.avatarUrl) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` ${escape_html(p1?.team.name ?? "?")}
${escape_html(p1?.score ?? 0)} vs ${escape_html(p2?.score ?? 0)}
${escape_html(p2?.team.name ?? "?")} `); - if (p2?.team.avatarUrl) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - if (sc?.dot) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` ${escape_html(sc?.label ?? m.state)}`); - } - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - if (liveMatches().length > 0) { - $$renderer2.push(""); - $$renderer2.push(`

Past Matches

`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - const each_array_5 = ensure_array_like(recentMatches()); - if (each_array_5.length !== 0) { - $$renderer2.push(""); - for (let $$index_5 = 0, $$length = each_array_5.length; $$index_5 < $$length; $$index_5++) { - let m = each_array_5[$$index_5]; - const { p1, p2 } = teamDisplay(m); - const config = m.config; - const sc = stateConfig[m.state]; - $$renderer2.push(`
${escape_html(p1?.team.name ?? "?")} `); - if (m.state === "FINISHED") { - $$renderer2.push(""); - $$renderer2.push(` (p2?.score ?? 0) ? "text-green-400" : "text-text-secondary")}`)}>${escape_html(p1?.score ?? 0)} - (p1?.score ?? 0) ? "text-green-400" : "text-text-secondary")}`)}>${escape_html(p2?.score ?? 0)}`); - } else { - $$renderer2.push(""); - $$renderer2.push(`vs`); - } - $$renderer2.push(` ${escape_html(p2?.team.name ?? "?")}

${escape_html(m.name ? `${m.name} · ` : "")}BO${escape_html(config.bestOf)} `); - if (m.finishedAt) { - $$renderer2.push(""); - $$renderer2.push(`· ${escape_html(timeAgo(m.finishedAt))}`); - } else if (m.createdAt) { - $$renderer2.push(""); - $$renderer2.push(`· ${escape_html(timeAgo(m.createdAt))}`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`

`); - if (m.state === "FINISHED" && m.winnerId) { - $$renderer2.push(""); - const winner = m.participants.find((p) => p.teamId === m.winnerId); - $$renderer2.push(`🏆 ${escape_html(winner?.team.name)}`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` ${escape_html(sc?.label ?? m.state)}`); - } - } else { - $$renderer2.push(""); - if (liveMatches().length === 0) { - $$renderer2.push(""); - $$renderer2.push(`

No matches yet. Create one to get started.

`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(``); - } - $$renderer2.push(`
`); - }); -} -export { - _page as default -}; diff --git a/.svelte-kit/output/server/entries/pages/(app)/settings/_page.server.ts.js b/.svelte-kit/output/server/entries/pages/(app)/settings/_page.server.ts.js deleted file mode 100644 index 0198d65..0000000 --- a/.svelte-kit/output/server/entries/pages/(app)/settings/_page.server.ts.js +++ /dev/null @@ -1,37 +0,0 @@ -import { redirect } from "@sveltejs/kit"; -import { a as auth } from "../../../../chunks/auth.js"; -import { d as db, p as playerRating, j as account } from "../../../../chunks/index2.js"; -import { eq, and } from "drizzle-orm"; -const load = async ({ locals }) => { - if (!locals.user) redirect(302, "/"); - const rating = await db.query.playerRating.findFirst({ - where: eq(playerRating.userId, locals.user.id) - }); - const osuAccount = await db.query.account.findFirst({ - where: and(eq(account.userId, locals.user.id), eq(account.providerId, "osu")) - }); - return { - profile: { - id: locals.user.id, - name: locals.user.name, - email: locals.user.email, - image: locals.user.image, - role: locals.user.role ?? "player", - createdAt: locals.user.createdAt - }, - rating: rating ? { elo: rating.elo, wins: rating.wins, losses: rating.losses } : { elo: 1e3, wins: 0, losses: 0 }, - hasOsuLinked: !!osuAccount - }; -}; -const actions = { - logout: async (event) => { - await auth.api.signOut({ - headers: event.request.headers - }); - redirect(302, "/"); - } -}; -export { - actions, - load -}; diff --git a/.svelte-kit/output/server/entries/pages/(app)/settings/_page.svelte.js b/.svelte-kit/output/server/entries/pages/(app)/settings/_page.svelte.js deleted file mode 100644 index 3b24951..0000000 --- a/.svelte-kit/output/server/entries/pages/(app)/settings/_page.svelte.js +++ /dev/null @@ -1,48 +0,0 @@ -import { b as attr, e as escape_html, c as attr_class, s as stringify, d as derived } from "../../../../chunks/index3.js"; -import "@sveltejs/kit/internal"; -import "../../../../chunks/url.js"; -import "../../../../chunks/utils.js"; -import "@sveltejs/kit/internal/server"; -import "../../../../chunks/root.js"; -import "../../../../chunks/exports.js"; -import "../../../../chunks/state.svelte.js"; -function _page($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - let { data } = $$props; - const roleBadge = { - player: { label: "Player", color: "bg-surface-600 text-text-secondary" }, - referee: { label: "Referee", color: "bg-yellow-500/20 text-yellow-400" }, - admin: { label: "Admin", color: "bg-red-500/20 text-red-400" } - }; - const badge = derived(() => roleBadge[data.profile.role] ?? roleBadge.player); - const winRate = derived(() => data.rating.wins + data.rating.losses > 0 ? (data.rating.wins / (data.rating.wins + data.rating.losses) * 100).toFixed(1) : "—"); - $$renderer2.push(`

Settings

Your profile and account settings

`); - if (data.profile.image) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - $$renderer2.push(`
${escape_html(data.profile.name.charAt(0).toUpperCase())}
`); - } - $$renderer2.push(`

${escape_html(data.profile.name)}

${escape_html(badge().label)}

${escape_html(data.profile.email)}

Connected Accounts

🎮

osu!

`); - if (data.hasOsuLinked) { - $$renderer2.push(""); - $$renderer2.push(`Connected as ${escape_html(data.profile.name)}`); - } else { - $$renderer2.push(""); - $$renderer2.push(`Not connected`); - } - $$renderer2.push(`

`); - if (data.hasOsuLinked) { - $$renderer2.push(""); - $$renderer2.push(`Linked`); - } else { - $$renderer2.push(""); - $$renderer2.push(`Connect`); - } - $$renderer2.push(`

Ranked Stats

${escape_html(data.rating.elo)}

ELO Rating

${escape_html(data.rating.wins)}

Wins

${escape_html(data.rating.losses)}

Losses

${escape_html(winRate())}${escape_html(winRate() !== "—" ? "%" : "")}

Win Rate

Account

`); - }); -} -export { - _page as default -}; diff --git a/.svelte-kit/output/server/entries/pages/(app)/teams/_page.server.ts.js b/.svelte-kit/output/server/entries/pages/(app)/teams/_page.server.ts.js deleted file mode 100644 index dbeb11a..0000000 --- a/.svelte-kit/output/server/entries/pages/(app)/teams/_page.server.ts.js +++ /dev/null @@ -1,88 +0,0 @@ -import { d as db, c as team, t as teamMember, u as user } from "../../../../chunks/index2.js"; -import { eq } from "drizzle-orm"; -import { redirect } from "@sveltejs/kit"; -const load = async ({ locals }) => { - if (!locals.user) redirect(302, "/"); - const teams = await db.query.team.findMany({ - with: { - members: true - }, - orderBy: (t, { desc }) => [desc(t.createdAt)] - }); - const teamsWithUsers = await Promise.all( - teams.map(async (t) => { - const membersWithUsers = await Promise.all( - t.members.map(async (m) => { - const u = await db.query.user.findFirst({ - where: eq(user.id, m.userId) - }); - return { ...m, user: u ? { id: u.id, name: u.name, image: u.image } : null }; - }) - ); - return { ...t, members: membersWithUsers }; - }) - ); - return { teams: teamsWithUsers, userId: locals.user.id }; -}; -const actions = { - create: async ({ request, locals }) => { - if (!locals.user) redirect(302, "/"); - const form = await request.formData(); - const name = form.get("name")?.toString()?.trim(); - if (!name) return { error: "Team name is required" }; - const [created] = await db.insert(team).values({ - name, - ownerId: locals.user.id, - isPersonal: false - }).returning(); - await db.insert(teamMember).values({ - teamId: created.id, - userId: locals.user.id, - role: "captain" - }); - return { success: true }; - }, - addMember: async ({ request, locals }) => { - if (!locals.user) redirect(302, "/"); - const form = await request.formData(); - const teamId = form.get("teamId")?.toString(); - const username = form.get("username")?.toString()?.trim(); - if (!teamId || !username) return { error: "Team and username are required" }; - const u = await db.query.user.findFirst({ - where: eq(user.name, username) - }); - if (!u) return { error: `User "${username}" not found. They need to log in first.` }; - const existing = await db.query.teamMember.findFirst({ - where: (m, { and, eq: eq2 }) => and(eq2(m.teamId, teamId), eq2(m.userId, u.id)) - }); - if (existing) return { error: `${username} is already on this team` }; - await db.insert(teamMember).values({ - teamId, - userId: u.id, - role: "member" - }); - return { success: true }; - }, - removeMember: async ({ request, locals }) => { - if (!locals.user) redirect(302, "/"); - const form = await request.formData(); - const memberId = form.get("memberId")?.toString(); - if (!memberId) return { error: "Missing member ID" }; - await db.delete(teamMember).where(eq(teamMember.id, memberId)); - return { success: true }; - }, - deleteTeam: async ({ request, locals }) => { - if (!locals.user) redirect(302, "/"); - const form = await request.formData(); - const teamId = form.get("teamId")?.toString(); - if (!teamId) return { error: "Missing team ID" }; - const t = await db.query.team.findFirst({ where: eq(team.id, teamId) }); - if (!t || t.ownerId !== locals.user.id) return { error: "Not authorized" }; - await db.delete(team).where(eq(team.id, teamId)); - return { success: true }; - } -}; -export { - actions, - load -}; diff --git a/.svelte-kit/output/server/entries/pages/(app)/teams/_page.svelte.js b/.svelte-kit/output/server/entries/pages/(app)/teams/_page.svelte.js deleted file mode 100644 index e5203aa..0000000 --- a/.svelte-kit/output/server/entries/pages/(app)/teams/_page.svelte.js +++ /dev/null @@ -1,138 +0,0 @@ -import { e as escape_html, a as ensure_array_like, b as attr, c as attr_class, s as stringify, d as derived } from "../../../../chunks/index3.js"; -import "@sveltejs/kit/internal"; -import "../../../../chunks/url.js"; -import "../../../../chunks/utils.js"; -import "@sveltejs/kit/internal/server"; -import "../../../../chunks/root.js"; -import "../../../../chunks/exports.js"; -import "../../../../chunks/state.svelte.js"; -function _page($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - let { data } = $$props; - let expandedTeam = null; - let addingMemberTo = null; - let memberUsername = ""; - const myTeams = derived(() => data.teams.filter((t) => t.members.some((m) => m.userId === data.userId))); - const otherTeams = derived(() => data.teams.filter((t) => !t.members.some((m) => m.userId === data.userId))); - function isOwner(t) { - return t.ownerId === data.userId; - } - $$renderer2.push(`

Teams

${escape_html(data.teams.length)} team${escape_html(data.teams.length !== 1 ? "s" : "")}

`); - { - $$renderer2.push(""); - } - $$renderer2.push(` `); - { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (myTeams().length > 0) { - $$renderer2.push(""); - $$renderer2.push(`

My Teams

`); - const each_array = ensure_array_like(myTeams()); - for (let $$index_1 = 0, $$length = each_array.length; $$index_1 < $$length; $$index_1++) { - let t = each_array[$$index_1]; - $$renderer2.push(`
`); - if (expandedTeam === t.id) { - $$renderer2.push(""); - $$renderer2.push(`
`); - const each_array_1 = ensure_array_like(t.members); - for (let $$index = 0, $$length2 = each_array_1.length; $$index < $$length2; $$index++) { - let member = each_array_1[$$index]; - $$renderer2.push(`
`); - if (member.user?.image) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - $$renderer2.push(`
`); - } - $$renderer2.push(` ${escape_html(member.user?.name ?? "Unknown")} ${escape_html(member.role)} `); - if (isOwner(t) && member.userId !== data.userId) { - $$renderer2.push(""); - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - } - $$renderer2.push(`
`); - if (isOwner(t) && !t.isPersonal) { - $$renderer2.push(""); - if (addingMemberTo === t.id) { - $$renderer2.push(""); - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - $$renderer2.push(``); - } - $$renderer2.push(``); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (isOwner(t) && !t.isPersonal) { - $$renderer2.push(""); - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - } - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (otherTeams().length > 0) { - $$renderer2.push(""); - $$renderer2.push(`

Other Teams

`); - const each_array_2 = ensure_array_like(otherTeams()); - for (let $$index_2 = 0, $$length = each_array_2.length; $$index_2 < $$length; $$index_2++) { - let t = each_array_2[$$index_2]; - $$renderer2.push(`
`); - if (t.avatarUrl) { - $$renderer2.push(""); - $$renderer2.push(``); - } else { - $$renderer2.push(""); - $$renderer2.push(`
${escape_html(t.name.charAt(0).toUpperCase())}
`); - } - $$renderer2.push(`
${escape_html(t.name)}

${escape_html(t.members.length)} member${escape_html(t.members.length !== 1 ? "s" : "")}

`); - } - $$renderer2.push(`
`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(` `); - if (data.teams.length === 0) { - $$renderer2.push(""); - $$renderer2.push(`

No teams yet. Your personal team is created when you sign in.

`); - } else { - $$renderer2.push(""); - } - $$renderer2.push(`
`); - }); -} -export { - _page as default -}; diff --git a/.svelte-kit/output/server/entries/pages/_error.svelte.js b/.svelte-kit/output/server/entries/pages/_error.svelte.js deleted file mode 100644 index 85b4f7d..0000000 --- a/.svelte-kit/output/server/entries/pages/_error.svelte.js +++ /dev/null @@ -1,25 +0,0 @@ -import { e as escape_html } from "../../chunks/index3.js"; -import "clsx"; -import { p as page } from "../../chunks/index4.js"; -function _error($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - $$renderer2.push(`

${escape_html(page.status)}

`); - if (page.status === 404) { - $$renderer2.push(""); - $$renderer2.push(`Page not found`); - } else if (page.status === 403) { - $$renderer2.push(""); - $$renderer2.push(`Access denied`); - } else if (page.status === 401) { - $$renderer2.push(""); - $$renderer2.push(`Not logged in`); - } else { - $$renderer2.push(""); - $$renderer2.push(`Something went wrong`); - } - $$renderer2.push(`

${escape_html(page.error?.message ?? "An unexpected error occurred.")}

Back to Dashboard
`); - }); -} -export { - _error as default -}; diff --git a/.svelte-kit/output/server/entries/pages/demo/_page.svelte.js b/.svelte-kit/output/server/entries/pages/demo/_page.svelte.js deleted file mode 100644 index 1b9e0e2..0000000 --- a/.svelte-kit/output/server/entries/pages/demo/_page.svelte.js +++ /dev/null @@ -1,31 +0,0 @@ -import { b as attr } from "../../../chunks/index3.js"; -import { i as initial_base, b as base } from "../../../chunks/server.js"; -import { r as resolve_route } from "../../../chunks/routing.js"; -import "../../../chunks/url.js"; -import { try_get_request_store } from "@sveltejs/kit/internal/server"; -import "../../../chunks/root.js"; -function resolve(id, params) { - const resolved = resolve_route( - id, - /** @type {Record} */ - params - ); - { - const store = try_get_request_store(); - if (store && !store.state.prerendering?.fallback) { - const after_base = store.event.url.pathname.slice(initial_base.length); - const segments = after_base.split("/").slice(2); - const prefix = segments.map(() => "..").join("/") || "."; - return prefix + resolved; - } - } - return base + resolved; -} -function _page($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - $$renderer2.push(`better-auth`); - }); -} -export { - _page as default -}; diff --git a/.svelte-kit/output/server/entries/pages/demo/better-auth/_page.server.ts.js b/.svelte-kit/output/server/entries/pages/demo/better-auth/_page.server.ts.js deleted file mode 100644 index 8fa1822..0000000 --- a/.svelte-kit/output/server/entries/pages/demo/better-auth/_page.server.ts.js +++ /dev/null @@ -1,20 +0,0 @@ -import { redirect } from "@sveltejs/kit"; -import { a as auth } from "../../../../chunks/auth.js"; -const load = async (event) => { - if (!event.locals.user) { - return redirect(302, "/demo/better-auth/login"); - } - return { user: event.locals.user }; -}; -const actions = { - signOut: async (event) => { - await auth.api.signOut({ - headers: event.request.headers - }); - return redirect(302, "/demo/better-auth/login"); - } -}; -export { - actions, - load -}; diff --git a/.svelte-kit/output/server/entries/pages/demo/better-auth/_page.svelte.js b/.svelte-kit/output/server/entries/pages/demo/better-auth/_page.svelte.js deleted file mode 100644 index 42126b3..0000000 --- a/.svelte-kit/output/server/entries/pages/demo/better-auth/_page.svelte.js +++ /dev/null @@ -1,18 +0,0 @@ -import { e as escape_html } from "../../../../chunks/index3.js"; -import "clsx"; -import "@sveltejs/kit/internal"; -import "../../../../chunks/url.js"; -import "../../../../chunks/utils.js"; -import "@sveltejs/kit/internal/server"; -import "../../../../chunks/root.js"; -import "../../../../chunks/exports.js"; -import "../../../../chunks/state.svelte.js"; -function _page($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - let { data } = $$props; - $$renderer2.push(`

Hi, ${escape_html(data.user.name)}!

Your user ID is ${escape_html(data.user.id)}.

`); - }); -} -export { - _page as default -}; diff --git a/.svelte-kit/output/server/entries/pages/demo/better-auth/login/_page.server.ts.js b/.svelte-kit/output/server/entries/pages/demo/better-auth/login/_page.server.ts.js deleted file mode 100644 index 2e2ee65..0000000 --- a/.svelte-kit/output/server/entries/pages/demo/better-auth/login/_page.server.ts.js +++ /dev/null @@ -1,75 +0,0 @@ -import { redirect, fail } from "@sveltejs/kit"; -import { a as auth } from "../../../../../chunks/auth.js"; -import "@better-auth/core/env"; -import "@better-auth/core/utils"; -import { APIError } from "better-call"; -import "@better-auth/core/api"; -const load = async (event) => { - if (event.locals.user) { - return redirect(302, "/demo/better-auth"); - } - return {}; -}; -const actions = { - signInEmail: async (event) => { - const formData = await event.request.formData(); - const email = formData.get("email")?.toString() ?? ""; - const password = formData.get("password")?.toString() ?? ""; - try { - await auth.api.signInEmail({ - body: { - email, - password, - callbackURL: "/auth/verification-success" - } - }); - } catch (error) { - if (error instanceof APIError) { - return fail(400, { message: error.message || "Signin failed" }); - } - return fail(500, { message: "Unexpected error" }); - } - return redirect(302, "/demo/better-auth"); - }, - signUpEmail: async (event) => { - const formData = await event.request.formData(); - const email = formData.get("email")?.toString() ?? ""; - const password = formData.get("password")?.toString() ?? ""; - const name = formData.get("name")?.toString() ?? ""; - try { - await auth.api.signUpEmail({ - body: { - email, - password, - name, - callbackURL: "/auth/verification-success" - } - }); - } catch (error) { - if (error instanceof APIError) { - return fail(400, { message: error.message || "Registration failed" }); - } - return fail(500, { message: "Unexpected error" }); - } - return redirect(302, "/demo/better-auth"); - }, - signInSocial: async (event) => { - const formData = await event.request.formData(); - const provider = formData.get("provider")?.toString() ?? "osu"; - const callbackURL = formData.get("callbackURL")?.toString() ?? "/demo/better-auth"; - const result = await auth.api.signInSocial({ - body: { - provider, - callbackURL - } - }); - if (result.url) { - return redirect(302, result.url); - } - return fail(400, { message: "Social sign-in failed" }); - } -}; -export { - actions, - load -}; diff --git a/.svelte-kit/output/server/entries/pages/demo/better-auth/login/_page.svelte.js b/.svelte-kit/output/server/entries/pages/demo/better-auth/login/_page.svelte.js deleted file mode 100644 index c17dfef..0000000 --- a/.svelte-kit/output/server/entries/pages/demo/better-auth/login/_page.svelte.js +++ /dev/null @@ -1,18 +0,0 @@ -import { e as escape_html } from "../../../../../chunks/index3.js"; -import "clsx"; -import "@sveltejs/kit/internal"; -import "../../../../../chunks/url.js"; -import "../../../../../chunks/utils.js"; -import "@sveltejs/kit/internal/server"; -import "../../../../../chunks/root.js"; -import "../../../../../chunks/exports.js"; -import "../../../../../chunks/state.svelte.js"; -function _page($$renderer, $$props) { - $$renderer.component(($$renderer2) => { - let { form } = $$props; - $$renderer2.push(`

Login

${escape_html(form?.message ?? "")}


`); - }); -} -export { - _page as default -}; diff --git a/.svelte-kit/output/server/entries/pages/login/_page.server.ts.js b/.svelte-kit/output/server/entries/pages/login/_page.server.ts.js deleted file mode 100644 index a8c7c75..0000000 --- a/.svelte-kit/output/server/entries/pages/login/_page.server.ts.js +++ /dev/null @@ -1,16 +0,0 @@ -import { redirect } from "@sveltejs/kit"; -import { a as auth } from "../../../chunks/auth.js"; -const load = async (event) => { - if (event.locals.user) redirect(302, "/"); - const result = await auth.api.signInSocial({ - body: { - provider: "osu", - callbackURL: "/" - } - }); - if (result.url) redirect(302, result.url); - return {}; -}; -export { - load -}; diff --git a/.svelte-kit/output/server/index.js b/.svelte-kit/output/server/index.js deleted file mode 100644 index fb8a806..0000000 --- a/.svelte-kit/output/server/index.js +++ /dev/null @@ -1,3698 +0,0 @@ -import { D as DEV } from "./chunks/false.js"; -import { json, text, error } from "@sveltejs/kit"; -import { Redirect, SvelteKitError, ActionFailure, HttpError } from "@sveltejs/kit/internal"; -import { with_request_store, merge_tracing, try_get_request_store } from "@sveltejs/kit/internal/server"; -import { a as assets, b as base, c as app_dir, r as relative, o as override, d as reset } from "./chunks/server.js"; -import { E as ENDPOINT_METHODS, P as PAGE_METHODS, n as negotiate, m as method_not_allowed, h as handle_error_and_jsonify, g as get_status, i as is_form_content_type, a as normalize_error, b as get_global_name, s as serialize_uses, c as clarify_devalue_error, d as get_node_type, e as escape_html, S as SVELTE_KIT_ASSETS, f as create_remote_key, j as static_error_page, r as redirect_response, p as parse_remote_arg, k as stringify, l as deserialize_binary_form, o as has_prerendered_path, T as TRAILING_SLASH_PARAM, I as INVALIDATED_PARAM, q as handle_fatal_error, M as MUTATIVE_METHODS, t as format_server_error } from "./chunks/shared.js"; -import * as devalue from "devalue"; -import { m as make_trackable, d as disable_search, S as SCHEME, n as normalize_path, r as resolve, a as decode_pathname } from "./chunks/url.js"; -import { b as base64_encode, t as text_decoder, a as text_encoder, g as get_relative_path } from "./chunks/utils.js"; -import { w as writable, r as readable } from "./chunks/index.js"; -import { p as public_env, s as set_private_env, a as set_public_env } from "./chunks/shared-server.js"; -import { f as find_route } from "./chunks/routing.js"; -import { v as validate_layout_server_exports, a as validate_layout_exports, b as validate_page_server_exports, c as validate_page_exports, d as validate_server_exports } from "./chunks/exports.js"; -import { parse, serialize } from "cookie"; -import * as set_cookie_parser from "set-cookie-parser"; -import { r as read_implementation, o as options, g as get_hooks, s as set_read_implementation } from "./chunks/internal.js"; -function with_resolvers() { - let resolve2; - let reject; - const promise = new Promise((res, rej) => { - resolve2 = res; - reject = rej; - }); - return { promise, resolve: resolve2, reject }; -} -const NULL_BODY_STATUS = [101, 103, 204, 205, 304]; -const IN_WEBCONTAINER = !!globalThis.process?.versions?.webcontainer; -async function render_endpoint(event, event_state, mod, state) { - const method = ( - /** @type {import('types').HttpMethod} */ - event.request.method - ); - let handler = mod[method] || mod.fallback; - if (method === "HEAD" && !mod.HEAD && mod.GET) { - handler = mod.GET; - } - if (!handler) { - return method_not_allowed(mod, method); - } - const prerender = mod.prerender ?? state.prerender_default; - if (prerender && (mod.POST || mod.PATCH || mod.PUT || mod.DELETE)) { - throw new Error("Cannot prerender endpoints that have mutative methods"); - } - if (state.prerendering && !state.prerendering.inside_reroute && !prerender) { - if (state.depth > 0) { - throw new Error(`${event.route.id} is not prerenderable`); - } else { - return new Response(void 0, { status: 204 }); - } - } - try { - event_state.allows_commands = true; - const response = await with_request_store( - { event, state: event_state }, - () => handler( - /** @type {import('@sveltejs/kit').RequestEvent>} */ - event - ) - ); - if (!(response instanceof Response)) { - throw new Error( - `Invalid response from route ${event.url.pathname}: handler should return a Response object` - ); - } - if (state.prerendering && (!state.prerendering.inside_reroute || prerender)) { - const cloned = new Response(response.clone().body, { - status: response.status, - statusText: response.statusText, - headers: new Headers(response.headers) - }); - cloned.headers.set("x-sveltekit-prerender", String(prerender)); - if (state.prerendering.inside_reroute && prerender) { - cloned.headers.set( - "x-sveltekit-routeid", - encodeURI( - /** @type {string} */ - event.route.id - ) - ); - state.prerendering.dependencies.set(event.url.pathname, { response: cloned, body: null }); - } else { - return cloned; - } - } - return response; - } catch (e) { - if (e instanceof Redirect) { - return new Response(void 0, { - status: e.status, - headers: { location: e.location } - }); - } - throw e; - } -} -function is_endpoint_request(event) { - const { method, headers: headers2 } = event.request; - if (ENDPOINT_METHODS.includes(method) && !PAGE_METHODS.includes(method)) { - return true; - } - if (method === "POST" && headers2.get("x-sveltekit-action") === "true") return false; - const accept = event.request.headers.get("accept") ?? "*/*"; - return negotiate(accept, ["*", "text/html"]) !== "text/html"; -} -function compact(arr) { - return arr.filter( - /** @returns {val is NonNullable} */ - (val) => val != null - ); -} -const DATA_SUFFIX = "/__data.json"; -const HTML_DATA_SUFFIX = ".html__data.json"; -function has_data_suffix(pathname) { - return pathname.endsWith(DATA_SUFFIX) || pathname.endsWith(HTML_DATA_SUFFIX); -} -function add_data_suffix(pathname) { - if (pathname.endsWith(".html")) return pathname.replace(/\.html$/, HTML_DATA_SUFFIX); - return pathname.replace(/\/$/, "") + DATA_SUFFIX; -} -function strip_data_suffix(pathname) { - if (pathname.endsWith(HTML_DATA_SUFFIX)) { - return pathname.slice(0, -HTML_DATA_SUFFIX.length) + ".html"; - } - return pathname.slice(0, -DATA_SUFFIX.length); -} -const ROUTE_SUFFIX = "/__route.js"; -function has_resolution_suffix(pathname) { - return pathname.endsWith(ROUTE_SUFFIX); -} -function add_resolution_suffix(pathname) { - return pathname.replace(/\/$/, "") + ROUTE_SUFFIX; -} -function strip_resolution_suffix(pathname) { - return pathname.slice(0, -ROUTE_SUFFIX.length); -} -const noop_span = { - spanContext() { - return noop_span_context; - }, - setAttribute() { - return this; - }, - setAttributes() { - return this; - }, - addEvent() { - return this; - }, - setStatus() { - return this; - }, - updateName() { - return this; - }, - end() { - return this; - }, - isRecording() { - return false; - }, - recordException() { - return this; - }, - addLink() { - return this; - }, - addLinks() { - return this; - } -}; -const noop_span_context = { - traceId: "", - spanId: "", - traceFlags: 0 -}; -async function record_span({ name, attributes, fn }) { - { - return fn(noop_span); - } -} -function is_action_json_request(event) { - const accept = negotiate(event.request.headers.get("accept") ?? "*/*", [ - "application/json", - "text/html" - ]); - return accept === "application/json" && event.request.method === "POST"; -} -async function handle_action_json_request(event, event_state, options2, server) { - const actions = server?.actions; - if (!actions) { - const no_actions_error = new SvelteKitError( - 405, - "Method Not Allowed", - `POST method not allowed. No form actions exist for ${"this page"}` - ); - return action_json( - { - type: "error", - error: await handle_error_and_jsonify(event, event_state, options2, no_actions_error) - }, - { - status: no_actions_error.status, - headers: { - // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/405 - // "The server must generate an Allow header field in a 405 status code response" - allow: "GET" - } - } - ); - } - check_named_default_separate(actions); - try { - const data = await call_action(event, event_state, actions); - if (DEV) ; - if (data instanceof ActionFailure) { - return action_json({ - type: "failure", - status: data.status, - // @ts-expect-error we assign a string to what is supposed to be an object. That's ok - // because we don't use the object outside, and this way we have better code navigation - // through knowing where the related interface is used. - data: stringify_action_response( - data.data, - /** @type {string} */ - event.route.id, - options2.hooks.transport - ) - }); - } else { - return action_json({ - type: "success", - status: data ? 200 : 204, - // @ts-expect-error see comment above - data: stringify_action_response( - data, - /** @type {string} */ - event.route.id, - options2.hooks.transport - ) - }); - } - } catch (e) { - const err = normalize_error(e); - if (err instanceof Redirect) { - return action_json_redirect(err); - } - return action_json( - { - type: "error", - error: await handle_error_and_jsonify( - event, - event_state, - options2, - check_incorrect_fail_use(err) - ) - }, - { - status: get_status(err) - } - ); - } -} -function check_incorrect_fail_use(error2) { - return error2 instanceof ActionFailure ? new Error('Cannot "throw fail()". Use "return fail()"') : error2; -} -function action_json_redirect(redirect) { - return action_json({ - type: "redirect", - status: redirect.status, - location: redirect.location - }); -} -function action_json(data, init2) { - return json(data, init2); -} -function is_action_request(event) { - return event.request.method === "POST"; -} -async function handle_action_request(event, event_state, server) { - const actions = server?.actions; - if (!actions) { - event.setHeaders({ - // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/405 - // "The server must generate an Allow header field in a 405 status code response" - allow: "GET" - }); - return { - type: "error", - error: new SvelteKitError( - 405, - "Method Not Allowed", - `POST method not allowed. No form actions exist for ${"this page"}` - ) - }; - } - check_named_default_separate(actions); - try { - const data = await call_action(event, event_state, actions); - if (DEV) ; - if (data instanceof ActionFailure) { - return { - type: "failure", - status: data.status, - data: data.data - }; - } else { - return { - type: "success", - status: 200, - // @ts-expect-error this will be removed upon serialization, so `undefined` is the same as omission - data - }; - } - } catch (e) { - const err = normalize_error(e); - if (err instanceof Redirect) { - return { - type: "redirect", - status: err.status, - location: err.location - }; - } - return { - type: "error", - error: check_incorrect_fail_use(err) - }; - } -} -function check_named_default_separate(actions) { - if (actions.default && Object.keys(actions).length > 1) { - throw new Error( - "When using named actions, the default action cannot be used. See the docs for more info: https://svelte.dev/docs/kit/form-actions#named-actions" - ); - } -} -async function call_action(event, event_state, actions) { - const url = new URL(event.request.url); - let name = "default"; - for (const param of url.searchParams) { - if (param[0].startsWith("/")) { - name = param[0].slice(1); - if (name === "default") { - throw new Error('Cannot use reserved action name "default"'); - } - break; - } - } - const action = actions[name]; - if (!action) { - throw new SvelteKitError(404, "Not Found", `No action with name '${name}' found`); - } - if (!is_form_content_type(event.request)) { - throw new SvelteKitError( - 415, - "Unsupported Media Type", - `Form actions expect form-encoded data — received ${event.request.headers.get( - "content-type" - )}` - ); - } - return record_span({ - name: "sveltekit.form_action", - attributes: { - "http.route": event.route.id || "unknown" - }, - fn: async (current2) => { - const traced_event = merge_tracing(event, current2); - event_state.allows_commands = true; - const result = await with_request_store( - { event: traced_event, state: event_state }, - () => action(traced_event) - ); - if (result instanceof ActionFailure) { - current2.setAttributes({ - "sveltekit.form_action.result.type": "failure", - "sveltekit.form_action.result.status": result.status - }); - } - return result; - } - }); -} -function validate_action_return(data) { - if (data instanceof Redirect) { - throw new Error("Cannot `return redirect(...)` — use `redirect(...)` instead"); - } - if (data instanceof HttpError) { - throw new Error("Cannot `return error(...)` — use `error(...)` or `return fail(...)` instead"); - } -} -function uneval_action_response(data, route_id, transport) { - const replacer = (thing) => { - for (const key2 in transport) { - const encoded = transport[key2].encode(thing); - if (encoded) { - return `app.decode('${key2}', ${devalue.uneval(encoded, replacer)})`; - } - } - }; - return try_serialize(data, (value) => devalue.uneval(value, replacer), route_id); -} -function stringify_action_response(data, route_id, transport) { - const encoders = Object.fromEntries( - Object.entries(transport).map(([key2, value]) => [key2, value.encode]) - ); - return try_serialize(data, (value) => devalue.stringify(value, encoders), route_id); -} -function try_serialize(data, fn, route_id) { - try { - return fn(data); - } catch (e) { - const error2 = ( - /** @type {any} */ - e - ); - if (data instanceof Response) { - throw new Error( - `Data returned from action inside ${route_id} is not serializable. Form actions need to return plain objects or fail(). E.g. return { success: true } or return fail(400, { message: "invalid" });`, - { cause: e } - ); - } - if ("path" in error2) { - let message = `Data returned from action inside ${route_id} is not serializable: ${error2.message}`; - if (error2.path !== "") message += ` (data.${error2.path})`; - throw new Error(message, { cause: e }); - } - throw error2; - } -} -function create_async_iterator() { - let resolved = -1; - let returned = -1; - const deferred = []; - return { - iterate: (transform = (x) => x) => { - return { - [Symbol.asyncIterator]() { - return { - next: async () => { - const next = deferred[++returned]; - if (!next) return { value: null, done: true }; - const value = await next.promise; - return { value: transform(value), done: false }; - } - }; - } - }; - }, - add: (promise) => { - deferred.push(with_resolvers()); - void promise.then((value) => { - deferred[++resolved].resolve(value); - }); - } - }; -} -function server_data_serializer(event, event_state, options2) { - let promise_id = 1; - let max_nodes = -1; - const iterator = create_async_iterator(); - const global = get_global_name(options2); - function get_replacer(index) { - return function replacer(thing) { - if (typeof thing?.then === "function") { - const id = promise_id++; - const promise = thing.then( - /** @param {any} data */ - (data) => ({ data }) - ).catch( - /** @param {any} error */ - async (error2) => ({ - error: await handle_error_and_jsonify(event, event_state, options2, error2) - }) - ).then( - /** - * @param {{data: any; error: any}} result - */ - async ({ data, error: error2 }) => { - let str; - try { - str = devalue.uneval(error2 ? [, error2] : [data], replacer); - } catch { - error2 = await handle_error_and_jsonify( - event, - event_state, - options2, - new Error(`Failed to serialize promise while rendering ${event.route.id}`) - ); - str = devalue.uneval([, error2], replacer); - } - return { - index, - str: `${global}.resolve(${id}, ${str.includes("app.decode") ? `(app) => ${str}` : `() => ${str}`})` - }; - } - ); - iterator.add(promise); - return `${global}.defer(${id})`; - } else { - for (const key2 in options2.hooks.transport) { - const encoded = options2.hooks.transport[key2].encode(thing); - if (encoded) { - return `app.decode('${key2}', ${devalue.uneval(encoded, replacer)})`; - } - } - } - }; - } - const strings = ( - /** @type {string[]} */ - [] - ); - return { - set_max_nodes(i) { - max_nodes = i; - }, - add_node(i, node) { - try { - if (!node) { - strings[i] = "null"; - return; - } - const payload = { type: "data", data: node.data, uses: serialize_uses(node) }; - if (node.slash) payload.slash = node.slash; - strings[i] = devalue.uneval(payload, get_replacer(i)); - } catch (e) { - e.path = e.path.slice(1); - throw new Error(clarify_devalue_error( - event, - /** @type {any} */ - e - ), { cause: e }); - } - }, - get_data(csp) { - const open = ``; - const close = `<\/script> -`; - return { - data: `[${compact(max_nodes > -1 ? strings.slice(0, max_nodes) : strings).join(",")}]`, - chunks: promise_id > 1 ? iterator.iterate(({ index, str }) => { - if (max_nodes > -1 && index >= max_nodes) { - return ""; - } - return open + str + close; - }) : null - }; - } - }; -} -function server_data_serializer_json(event, event_state, options2) { - let promise_id = 1; - const iterator = create_async_iterator(); - const reducers = { - ...Object.fromEntries( - Object.entries(options2.hooks.transport).map(([key2, value]) => [key2, value.encode]) - ), - /** @param {any} thing */ - Promise: (thing) => { - if (typeof thing?.then !== "function") { - return; - } - const id = promise_id++; - let key2 = "data"; - const promise = thing.catch( - /** @param {any} e */ - async (e) => { - key2 = "error"; - return handle_error_and_jsonify( - event, - event_state, - options2, - /** @type {any} */ - e - ); - } - ).then( - /** @param {any} value */ - async (value) => { - let str; - try { - str = devalue.stringify(value, reducers); - } catch { - const error2 = await handle_error_and_jsonify( - event, - event_state, - options2, - new Error(`Failed to serialize promise while rendering ${event.route.id}`) - ); - key2 = "error"; - str = devalue.stringify(error2, reducers); - } - return `{"type":"chunk","id":${id},"${key2}":${str}} -`; - } - ); - iterator.add(promise); - return id; - } - }; - const strings = ( - /** @type {string[]} */ - [] - ); - return { - add_node(i, node) { - try { - if (!node) { - strings[i] = "null"; - return; - } - if (node.type === "error" || node.type === "skip") { - strings[i] = JSON.stringify(node); - return; - } - strings[i] = `{"type":"data","data":${devalue.stringify(node.data, reducers)},"uses":${JSON.stringify( - serialize_uses(node) - )}${node.slash ? `,"slash":${JSON.stringify(node.slash)}` : ""}}`; - } catch (e) { - e.path = "data" + e.path; - throw new Error(clarify_devalue_error( - event, - /** @type {any} */ - e - ), { cause: e }); - } - }, - get_data() { - return { - data: `{"type":"data","nodes":[${strings.join(",")}]} -`, - chunks: promise_id > 1 ? iterator.iterate() : null - }; - } - }; -} -async function load_server_data({ event, event_state, state, node, parent }) { - if (!node?.server) return null; - let is_tracking = true; - const uses = { - dependencies: /* @__PURE__ */ new Set(), - params: /* @__PURE__ */ new Set(), - parent: false, - route: false, - url: false, - search_params: /* @__PURE__ */ new Set() - }; - const load = node.server.load; - const slash = node.server.trailingSlash; - if (!load) { - return { type: "data", data: null, uses, slash }; - } - const url = make_trackable( - event.url, - () => { - if (is_tracking) { - uses.url = true; - } - }, - (param) => { - if (is_tracking) { - uses.search_params.add(param); - } - } - ); - if (state.prerendering) { - disable_search(url); - } - const result = await record_span({ - name: "sveltekit.load", - attributes: { - "sveltekit.load.node_id": node.server_id || "unknown", - "sveltekit.load.node_type": get_node_type(node.server_id), - "http.route": event.route.id || "unknown" - }, - fn: async (current2) => { - const traced_event = merge_tracing(event, current2); - const result2 = await with_request_store( - { event: traced_event, state: event_state }, - () => load.call(null, { - ...traced_event, - fetch: (info, init2) => { - new URL(info instanceof Request ? info.url : info, event.url); - return event.fetch(info, init2); - }, - /** @param {string[]} deps */ - depends: (...deps) => { - for (const dep of deps) { - const { href } = new URL(dep, event.url); - uses.dependencies.add(href); - } - }, - params: new Proxy(event.params, { - get: (target, key2) => { - if (is_tracking) { - uses.params.add(key2); - } - return target[ - /** @type {string} */ - key2 - ]; - } - }), - parent: async () => { - if (is_tracking) { - uses.parent = true; - } - return parent(); - }, - route: new Proxy(event.route, { - get: (target, key2) => { - if (is_tracking) { - uses.route = true; - } - return target[ - /** @type {'id'} */ - key2 - ]; - } - }), - url, - untrack(fn) { - is_tracking = false; - try { - return fn(); - } finally { - is_tracking = true; - } - } - }) - ); - return result2; - } - }); - return { - type: "data", - data: result ?? null, - uses, - slash - }; -} -async function load_data({ - event, - event_state, - fetched, - node, - parent, - server_data_promise, - state, - resolve_opts, - csr -}) { - const server_data_node = await server_data_promise; - const load = node?.universal?.load; - if (!load) { - return server_data_node?.data ?? null; - } - const result = await record_span({ - name: "sveltekit.load", - attributes: { - "sveltekit.load.node_id": node.universal_id || "unknown", - "sveltekit.load.node_type": get_node_type(node.universal_id), - "http.route": event.route.id || "unknown" - }, - fn: async (current2) => { - const traced_event = merge_tracing(event, current2); - return await with_request_store( - { event: traced_event, state: event_state }, - () => load.call(null, { - url: event.url, - params: event.params, - data: server_data_node?.data ?? null, - route: event.route, - fetch: create_universal_fetch(event, state, fetched, csr, resolve_opts), - setHeaders: event.setHeaders, - depends: () => { - }, - parent, - untrack: (fn) => fn(), - tracing: traced_event.tracing - }) - ); - } - }); - return result ?? null; -} -function create_universal_fetch(event, state, fetched, csr, resolve_opts) { - const universal_fetch = async (input, init2) => { - const cloned_body = input instanceof Request && input.body ? input.clone().body : null; - const cloned_headers = input instanceof Request && [...input.headers].length ? new Headers(input.headers) : init2?.headers; - let response = await event.fetch(input, init2); - const url = new URL(input instanceof Request ? input.url : input, event.url); - const same_origin = url.origin === event.url.origin; - let dependency; - if (same_origin) { - if (state.prerendering) { - dependency = { response, body: null }; - state.prerendering.dependencies.set(url.pathname, dependency); - } - } else if (url.protocol === "https:" || url.protocol === "http:") { - const mode = input instanceof Request ? input.mode : init2?.mode ?? "cors"; - if (mode === "no-cors") { - response = new Response("", { - status: response.status, - statusText: response.statusText, - headers: response.headers - }); - } else { - const acao = response.headers.get("access-control-allow-origin"); - if (!acao || acao !== event.url.origin && acao !== "*") { - throw new Error( - `CORS error: ${acao ? "Incorrect" : "No"} 'Access-Control-Allow-Origin' header is present on the requested resource` - ); - } - } - } - let teed_body; - const proxy = new Proxy(response, { - get(response2, key2, receiver) { - async function push_fetched(body2, is_b64) { - const status_number = Number(response2.status); - if (isNaN(status_number)) { - throw new Error( - `response.status is not a number. value: "${response2.status}" type: ${typeof response2.status}` - ); - } - fetched.push({ - url: same_origin ? url.href.slice(event.url.origin.length) : url.href, - method: event.request.method, - request_body: ( - /** @type {string | ArrayBufferView | undefined} */ - input instanceof Request && cloned_body ? await stream_to_string(cloned_body) : init2?.body - ), - request_headers: cloned_headers, - response_body: body2, - response: response2, - is_b64 - }); - } - if (key2 === "body") { - if (response2.body === null) { - return null; - } - if (teed_body) { - return teed_body; - } - const [a, b] = response2.body.tee(); - void (async () => { - let result = new Uint8Array(); - for await (const chunk of a) { - const combined = new Uint8Array(result.length + chunk.length); - combined.set(result, 0); - combined.set(chunk, result.length); - result = combined; - } - if (dependency) { - dependency.body = new Uint8Array(result); - } - void push_fetched(base64_encode(result), true); - })(); - return teed_body = b; - } - if (key2 === "arrayBuffer") { - return async () => { - const buffer = await response2.arrayBuffer(); - const bytes = new Uint8Array(buffer); - if (dependency) { - dependency.body = bytes; - } - if (buffer instanceof ArrayBuffer) { - await push_fetched(base64_encode(bytes), true); - } - return buffer; - }; - } - async function text2() { - const body2 = await response2.text(); - if (body2 === "" && NULL_BODY_STATUS.includes(response2.status)) { - await push_fetched(void 0, false); - return void 0; - } - if (!body2 || typeof body2 === "string") { - await push_fetched(body2, false); - } - if (dependency) { - dependency.body = body2; - } - return body2; - } - if (key2 === "text") { - return text2; - } - if (key2 === "json") { - return async () => { - const body2 = await text2(); - return body2 ? JSON.parse(body2) : void 0; - }; - } - const value = Reflect.get(response2, key2, response2); - if (value instanceof Function) { - return Object.defineProperties( - /** - * @this {any} - */ - function() { - return Reflect.apply(value, this === receiver ? response2 : this, arguments); - }, - { - name: { value: value.name }, - length: { value: value.length } - } - ); - } - return value; - } - }); - if (csr) { - const get = response.headers.get; - response.headers.get = (key2) => { - const lower = key2.toLowerCase(); - const value = get.call(response.headers, lower); - if (value && !lower.startsWith("x-sveltekit-")) { - const included = resolve_opts.filterSerializedResponseHeaders(lower, value); - if (!included) { - throw new Error( - `Failed to get response header "${lower}" — it must be included by the \`filterSerializedResponseHeaders\` option: https://svelte.dev/docs/kit/hooks#Server-hooks-handle (at ${event.route.id})` - ); - } - } - return value; - }; - } - return proxy; - }; - return (input, init2) => { - const response = universal_fetch(input, init2); - response.catch(() => { - }); - return response; - }; -} -async function stream_to_string(stream) { - let result = ""; - const reader = stream.getReader(); - while (true) { - const { done, value } = await reader.read(); - if (done) { - break; - } - result += text_decoder.decode(value); - } - return result; -} -function hash(...values) { - let hash2 = 5381; - for (const value of values) { - if (typeof value === "string") { - let i = value.length; - while (i) hash2 = hash2 * 33 ^ value.charCodeAt(--i); - } else if (ArrayBuffer.isView(value)) { - const buffer = new Uint8Array(value.buffer, value.byteOffset, value.byteLength); - let i = buffer.length; - while (i) hash2 = hash2 * 33 ^ buffer[--i]; - } else { - throw new TypeError("value must be a string or TypedArray"); - } - } - return (hash2 >>> 0).toString(36); -} -const replacements = { - "<": "\\u003C", - "\u2028": "\\u2028", - "\u2029": "\\u2029" -}; -const pattern = new RegExp(`[${Object.keys(replacements).join("")}]`, "g"); -function serialize_data(fetched, filter, prerendering = false) { - const headers2 = {}; - let cache_control = null; - let age = null; - let varyAny = false; - for (const [key2, value] of fetched.response.headers) { - if (filter(key2, value)) { - headers2[key2] = value; - } - if (key2 === "cache-control") cache_control = value; - else if (key2 === "age") age = value; - else if (key2 === "vary" && value.trim() === "*") varyAny = true; - } - const payload = { - status: fetched.response.status, - statusText: fetched.response.statusText, - headers: headers2, - body: fetched.response_body - }; - const safe_payload = JSON.stringify(payload).replace(pattern, (match) => replacements[match]); - const attrs = [ - 'type="application/json"', - "data-sveltekit-fetched", - `data-url="${escape_html(fetched.url, true)}"` - ]; - if (fetched.is_b64) { - attrs.push("data-b64"); - } - if (fetched.request_headers || fetched.request_body) { - const values = []; - if (fetched.request_headers) { - values.push([...new Headers(fetched.request_headers)].join(",")); - } - if (fetched.request_body) { - values.push(fetched.request_body); - } - attrs.push(`data-hash="${hash(...values)}"`); - } - if (!prerendering && fetched.method === "GET" && cache_control && !varyAny) { - const match = /s-maxage=(\d+)/g.exec(cache_control) ?? /max-age=(\d+)/g.exec(cache_control); - if (match) { - const ttl = +match[1] - +(age ?? "0"); - attrs.push(`data-ttl="${ttl}"`); - } - } - return `
@@ -20,6 +27,9 @@

Admin Panel

{data.users.length} registered user{data.users.length !== 1 ? 's' : ''} + {#if data.actorIsRootAdmin} + ROOT ADMIN + {/if}

@@ -39,6 +49,8 @@ {#each data.users as u} {@const badge = roleBadge[u.role] ?? roleBadge.player} + {@const isProtected = u.isRootAdmin} + {@const canChangeRole = !isProtected && (data.actorIsRootAdmin || u.role !== 'admin')}
@@ -55,7 +67,12 @@
-

{u.name}

+
+

{u.name}

+ {#if u.isRootAdmin} + ROOT + {/if} +

{u.email}

@@ -69,35 +86,68 @@ -
{ - actionError = ''; - return async ({ result }) => { - if ( - result.type === 'failure' || - (result.type === 'success' && (result.data as any)?.error) - ) { - actionError = (result.data as any)?.error ?? 'Failed to update role'; - } - }; - }} - class="flex items-center gap-2" - > - - -
+ + + + {:else} + + {badge.label} + + {/if}
{/each} + + +
+

Permission Levels

+
+
+ Player + Create account, join queue, create/manage own mappools and teams +
+
+ Referee + All player permissions + manage any match, force start games +
+
+ Admin + Full access + manage all mappools/teams + promote players to referee +
+ {#if data.actorIsRootAdmin} +
+ Root Admin + Can promote/demote admins. Set via ROOT_ADMIN_EMAIL env var. Cannot be demoted. +
+ {/if} +
+
diff --git a/src/routes/(app)/leaderboard/+page.server.ts b/src/routes/(app)/leaderboard/+page.server.ts new file mode 100644 index 0000000..9f889f1 --- /dev/null +++ b/src/routes/(app)/leaderboard/+page.server.ts @@ -0,0 +1,133 @@ +import { db } from '$lib/server/db'; +import { + playerRating, + team, + teamMember, + matchParticipant, + matchGameScore, + matchGame, + matchParticipantPlayer, + match +} from '$lib/server/db/schema'; +import { user } from '$lib/server/db/auth.schema'; +import { eq, desc, sql, and } from 'drizzle-orm'; +import type { PageServerLoad } from './$types'; + +export const load: PageServerLoad = async () => { + // ── Top players by ELO ── + const topPlayers = await db.query.playerRating.findMany({ + orderBy: desc(playerRating.elo), + limit: 25 + }); + + const playersWithUsers = await Promise.all( + topPlayers.map(async (r, i) => { + const u = await db.query.user.findFirst({ + where: eq(user.id, r.userId) + }); + return { + rank: i + 1, + userId: r.userId, + name: u?.name ?? 'Unknown', + image: u?.image ?? null, + elo: r.elo, + wins: r.wins, + losses: r.losses, + winRate: + r.wins + r.losses > 0 + ? ((r.wins / (r.wins + r.losses)) * 100).toFixed(1) + : '—' + }; + }) + ); + + // ── Top teams by match wins ── + // Count wins for each team from matchParticipant scores + const teamWins = await db + .select({ + teamId: match.winnerId, + wins: sql`count(*)`.as('wins') + }) + .from(match) + .where(and( + sql`${match.winnerId} IS NOT NULL`, + eq(match.state, 'FINISHED') + )) + .groupBy(match.winnerId) + .orderBy(sql`count(*) DESC`) + .limit(15); + + const teamsWithDetails = await Promise.all( + teamWins.map(async (tw, i) => { + if (!tw.teamId) return null; + const t = await db.query.team.findFirst({ + where: eq(team.id, tw.teamId), + with: { members: true } + }); + if (!t) return null; + + // Count total matches for this team + const totalMatches = await db + .select({ count: sql`count(DISTINCT ${matchParticipant.matchId})` }) + .from(matchParticipant) + .where(eq(matchParticipant.teamId, tw.teamId)); + + return { + rank: i + 1, + teamId: t.id, + name: t.name, + avatarUrl: t.avatarUrl, + isPersonal: t.isPersonal, + memberCount: t.members.length, + wins: Number(tw.wins), + totalMatches: Number(totalMatches[0]?.count ?? 0) + }; + }) + ); + + const topTeams = teamsWithDetails.filter(Boolean); + + // ── Recent high scores (individual map scores) ── + const recentHighScores = await db.query.matchGameScore.findMany({ + orderBy: desc(matchGameScore.score), + limit: 15, + with: { + player: true, + game: { + with: { + slot: true, + match: true + } + } + } + }); + + const highScoresWithNames = await Promise.all( + recentHighScores.map(async (s, i) => { + const u = await db.query.user.findFirst({ + where: eq(user.id, s.player.userId) + }); + return { + rank: i + 1, + playerName: u?.name ?? 'Unknown', + playerImage: u?.image ?? null, + score: s.score, + accuracy: s.accuracy, + maxCombo: s.maxCombo, + mods: s.mods, + passed: s.passed, + beatmapId: s.game.slot?.beatmapId ?? null, + mapCategory: s.game.slot?.category ?? '', + mapOrder: s.game.slot?.orderInCategory ?? 0, + matchName: s.game.match?.name ?? 'Match', + matchId: s.game.matchId + }; + }) + ); + + return { + topPlayers: playersWithUsers, + topTeams: topTeams, + highScores: highScoresWithNames + }; +}; diff --git a/src/routes/(app)/leaderboard/+page.svelte b/src/routes/(app)/leaderboard/+page.svelte new file mode 100644 index 0000000..58e5228 --- /dev/null +++ b/src/routes/(app)/leaderboard/+page.svelte @@ -0,0 +1,263 @@ + + +
+
+

Leaderboard

+

Rankings and top performances

+
+ + +
+ {#each tabs as tab} + + {/each} +
+ + + {#if activeTab === 'players'} +
+ {#if data.topPlayers.length === 0} +
+

No ranked players yet. Play some matches!

+
+ {:else} +
+ # + + Player + ELO + W/L + Win % +
+ + {#each data.topPlayers as p} + {@const medal = rankBadge(p.rank)} +
+ + + {medal ? medal.emoji : p.rank} + + + + {#if p.image} + + {:else} +
+ {p.name.charAt(0).toUpperCase()} +
+ {/if} + + + {p.name} + + + {p.elo} + + + + {p.wins}/{p.losses} + + + + + {p.winRate}{p.winRate !== '—' ? '%' : ''} + +
+ {/each} + {/if} +
+ {/if} + + + {#if activeTab === 'teams'} +
+ {#if data.topTeams.length === 0} +
+

No team results yet.

+
+ {:else} +
+ # + + Team + Wins + Matches +
+ + {#each data.topTeams as t} + {@const medal = rankBadge(t.rank)} +
+ + + {medal ? medal.emoji : t.rank} + + + + {#if t.avatarUrl} + + {:else} +
+ {t.name.charAt(0).toUpperCase()} +
+ {/if} + + +
+ {t.name} + {#if t.isPersonal} + (solo) + {/if} +

{t.memberCount} member{t.memberCount !== 1 ? 's' : ''}

+
+ + + {t.wins} + + + {t.totalMatches} +
+ {/each} + {/if} +
+ {/if} + + + {#if activeTab === 'scores'} +
+ {#if data.highScores.length === 0} +
+

No scores recorded yet.

+
+ {:else} +
+ # + + Player + Map + Score + Acc +
+ + {#each data.highScores as s} + {@const medal = rankBadge(s.rank)} +
+ + + {medal ? medal.emoji : s.rank} + + + + {#if s.playerImage} + + {:else} +
+ {s.playerName.charAt(0).toUpperCase()} +
+ {/if} + + +
+ {s.playerName} +

+ {s.matchName} +

+
+ + + + {s.mapCategory}{s.mapOrder} + + + + + {s.score.toLocaleString()} + + + + + {s.accuracy > 0 ? `${(s.accuracy * 100).toFixed(1)}%` : '—'} + +
+ {/each} + {/if} +
+ {/if} + + +
+

How ELO Works

+

+ Every player starts at 1000 ELO. Win a match to gain points, lose to drop. + The system uses K=32, so new players' ratings shift quickly. As you play more, + your rating stabilizes around your true skill level. Queue matchmaking pairs players + with similar ELO for fair matches. +

+
+
diff --git a/src/routes/(app)/mappools/[id]/+page.server.ts b/src/routes/(app)/mappools/[id]/+page.server.ts index 5eb2b71..f582417 100644 --- a/src/routes/(app)/mappools/[id]/+page.server.ts +++ b/src/routes/(app)/mappools/[id]/+page.server.ts @@ -3,10 +3,11 @@ import { mappool, mappoolSlot } from '$lib/server/db/schema'; import { eq, and } from 'drizzle-orm'; import { error, redirect } from '@sveltejs/kit'; import { getBeatmap } from '$lib/server/osu/api'; +import { requireAuth, requireOwnerOrAdmin } from '$lib/server/permissions'; import type { PageServerLoad, Actions } from './$types'; export const load: PageServerLoad = async ({ params, locals }) => { - if (!locals.user) redirect(302, '/'); + requireAuth(locals); const pool = await db.query.mappool.findFirst({ where: eq(mappool.id, params.id), @@ -38,68 +39,89 @@ export const load: PageServerLoad = async ({ params, locals }) => { } }; } catch { - return { - ...slot, - beatmap: null - }; + return { ...slot, beatmap: null }; } }) ); + const isOwner = pool.createdBy === locals.user!.id; + const isAdmin = locals.user!.role === 'admin'; + return { - pool: { ...pool, slots: slotsWithBeatmaps } + pool: { ...pool, slots: slotsWithBeatmaps }, + canEdit: isOwner || isAdmin }; }; export const actions: Actions = { + rename: async ({ params, request, locals }) => { + const pool = await db.query.mappool.findFirst({ + where: eq(mappool.id, params.id) + }); + if (!pool) error(404, 'Mappool not found'); + requireOwnerOrAdmin(locals, pool.createdBy); + + const form = await request.formData(); + const name = form.get('name')?.toString()?.trim(); + if (!name) return { error: 'Name is required' }; + + await db.update(mappool).set({ name }).where(eq(mappool.id, params.id)); + return { success: true }; + }, + addSlot: async ({ params, request, locals }) => { - if (!locals.user) redirect(302, '/'); + const pool = await db.query.mappool.findFirst({ + where: eq(mappool.id, params.id) + }); + if (!pool) error(404, 'Mappool not found'); + requireOwnerOrAdmin(locals, pool.createdBy); - const form = await request.formData(); - let beatmapId = form.get('beatmapId')?.toString()?.trim(); - const category = form.get('category')?.toString()?.trim()?.toUpperCase(); + const form = await request.formData(); + let beatmapId = form.get('beatmapId')?.toString()?.trim(); + const category = form.get('category')?.toString()?.trim()?.toUpperCase(); - if (!beatmapId || !category) { - return { error: 'Beatmap ID and category are required' }; - } + if (!beatmapId || !category) { + return { error: 'Beatmap ID and category are required' }; + } - const urlMatch = beatmapId.match(/beatmaps\/(\d+)/); - const setMatch = beatmapId.match(/beatmapsets\/\d+#\w+\/(\d+)/); - if (urlMatch) beatmapId = urlMatch[1]; - else if (setMatch) beatmapId = setMatch[1]; + const urlMatch = beatmapId.match(/beatmaps\/(\d+)/); + const setMatch = beatmapId.match(/beatmapsets\/\d+#\w+\/(\d+)/); + if (urlMatch) beatmapId = urlMatch[1]; + else if (setMatch) beatmapId = setMatch[1]; - if (!/^\d+$/.test(beatmapId)) { - return { error: 'Invalid beatmap ID' }; - } + if (!/^\d+$/.test(beatmapId)) { + return { error: 'Invalid beatmap ID' }; + } - let beatmap; - try { - beatmap = await getBeatmap(beatmapId); - } catch { - return { error: 'Beatmap not found on osu!' }; - } + let beatmap; + try { + beatmap = await getBeatmap(beatmapId); + } catch { + return { error: 'Beatmap not found on osu!' }; + } - const existing = await db.query.mappoolSlot.findMany({ - where: and( - eq(mappoolSlot.mappoolId, params.id), - eq(mappoolSlot.category, category) - ) - }); + const existing = await db.query.mappoolSlot.findMany({ + where: and(eq(mappoolSlot.mappoolId, params.id), eq(mappoolSlot.category, category)) + }); - await db.insert(mappoolSlot).values({ - mappoolId: params.id, - beatmapId, - category, - orderInCategory: existing.length + 1, - starRating: beatmap.difficulty_rating, - mods: category === 'NM' || category === 'TB' || category === 'FM' ? [] : [category] - }); + await db.insert(mappoolSlot).values({ + mappoolId: params.id, + beatmapId, + category, + orderInCategory: existing.length + 1, + starRating: beatmap.difficulty_rating, + mods: category === 'NM' || category === 'TB' || category === 'FM' ? [] : [category] + }); - return { success: true }; -}, + return { success: true }; + }, - removeSlot: async ({ request, locals }) => { - if (!locals.user) redirect(302, '/'); + removeSlot: async ({ params, request, locals }) => { + const pool = await db.query.mappool.findFirst({ + where: eq(mappool.id, params.id) + }); + if (!pool) error(404, 'Mappool not found'); + requireOwnerOrAdmin(locals, pool.createdBy); const form = await request.formData(); const slotId = form.get('slotId')?.toString(); @@ -110,7 +132,11 @@ export const actions: Actions = { }, deletePool: async ({ params, locals }) => { - if (!locals.user) redirect(302, '/'); + const pool = await db.query.mappool.findFirst({ + where: eq(mappool.id, params.id) + }); + if (!pool) error(404, 'Mappool not found'); + requireOwnerOrAdmin(locals, pool.createdBy); await db.delete(mappool).where(eq(mappool.id, params.id)); redirect(303, '/mappools'); diff --git a/src/routes/(app)/mappools/[id]/+page.svelte b/src/routes/(app)/mappools/[id]/+page.svelte index 9616476..a95bbff 100644 --- a/src/routes/(app)/mappools/[id]/+page.svelte +++ b/src/routes/(app)/mappools/[id]/+page.svelte @@ -11,6 +11,10 @@ let addError = $state(''); let searching = $state(false); + // Rename state + let editing = $state(false); + let editName = $state(data.pool.name); + // Group slots by category const grouped = $derived(() => { const groups: Record = {}; @@ -22,7 +26,6 @@ }); function parseBeatmapId(input: string): string | null { - // Accept raw ID or osu! URL const urlMatch = input.match(/beatmaps\/(\d+)/); if (urlMatch) return urlMatch[1]; const match = input.match(/^(\d+)$/); @@ -49,80 +52,138 @@
- ← + ←
-

{data.pool.name}

+ {#if editing && data.canEdit} +
{ + return async ({ result, update }) => { + if (result.type === 'success') { + editing = false; + await update(); + } + }; + }} + class="flex items-center gap-2" + > + + + +
+ {:else} +
+

{data.pool.name}

+ {#if data.canEdit} + + {/if} +
+ {/if}

{data.pool.slots.length} map{data.pool.slots.length !== 1 ? 's' : ''}

-
- -
+ {#if data.canEdit} +
+ +
+ {/if}
-
{ - searching = true; - addError = ''; - return async ({ result, update }) => { - searching = false; - if (result.type === 'success') { - beatmapInput = ''; - await update(); - } else if (result.type === 'failure') { - addError = (result.data as { error?: string })?.error ?? 'Failed to add map'; } - }; - }} - class="mt-6 rounded-lg border border-border bg-surface-800 p-4" - > -

Add Map

-
- + {#if data.canEdit} + { + searching = true; + addError = ''; + return async ({ result, update }) => { + searching = false; + if (result.type === 'success') { + beatmapInput = ''; + await update(); + } else if (result.type === 'failure') { + addError = (result.data as { error?: string })?.error ?? 'Failed to add map'; + } + }; + }} + class="mt-6 rounded-lg border border-border bg-surface-800 p-4" + > +

Add Map

+
+ - + - -
+ +
- {#if addError} -

{addError}

- {/if} -
+ {#if addError} +

{addError}

+ {/if} + + {/if}
@@ -134,7 +195,9 @@ > {category} - {slots.length} map{slots.length !== 1 ? 's' : ''} + {slots.length} map{slots.length !== 1 ? 's' : ''}
@@ -144,13 +207,11 @@ > {#if slot.beatmap?.coverUrl} - + {:else} -
+
No cover
{/if} @@ -158,7 +219,7 @@ {/each}
diff --git a/src/routes/(app)/matches/+page.server.ts b/src/routes/(app)/matches/+page.server.ts index 07f899d..5bd266a 100644 --- a/src/routes/(app)/matches/+page.server.ts +++ b/src/routes/(app)/matches/+page.server.ts @@ -4,10 +4,11 @@ import { redirect } from '@sveltejs/kit'; import { desc } from 'drizzle-orm'; import { createMatch } from '$lib/server/match/engine'; import { initMatchLobby } from '$lib/server/match/orchestrator'; +import { requireAuth, requireRole, hasRole } from '$lib/server/permissions'; import type { PageServerLoad, Actions } from './$types'; export const load: PageServerLoad = async ({ locals }) => { - if (!locals.user) redirect(302, '/'); + requireAuth(locals); const matches = await db.query.match.findMany({ with: { participants: { with: { team: true } } }, @@ -24,12 +25,18 @@ export const load: PageServerLoad = async ({ locals }) => { orderBy: (m, { desc }) => [desc(m.createdAt)] }); - return { matches, teams, mappools }; + return { + matches, + teams, + mappools, + canCreateMatch: hasRole(locals.user!.role, 'referee') + }; }; export const actions: Actions = { createMatch: async ({ request, locals }) => { - if (!locals.user) redirect(302, '/'); + // Only referees and admins can create matches manually + requireRole(locals, 'referee', 'Only referees and admins can create matches'); const form = await request.formData(); const name = form.get('name')?.toString()?.trim() || 'Custom Match'; @@ -44,8 +51,6 @@ export const actions: Actions = { return { error: 'All fields are required' }; } - // Same team is allowed for testing/dev - let result; try { result = await createMatch({ @@ -53,7 +58,7 @@ export const actions: Actions = { config: { bestOf, teamSize: 1, scoringType: 'score' }, mappoolId, teams: [team1Id, team2Id], - createdBy: locals.user.id + createdBy: locals.user!.id }); console.log('[Matches] Created:', result.id); } catch (e: any) { @@ -61,7 +66,7 @@ export const actions: Actions = { return { error: e.message }; } - // Create IRC lobby in background (don't block redirect) + // Create IRC lobby in background initMatchLobby(result.id).catch((err) => { console.error('[Matches] IRC lobby failed:', err.message); }); diff --git a/src/routes/(app)/matches/+page.svelte b/src/routes/(app)/matches/+page.svelte index f7212ad..f0383ab 100644 --- a/src/routes/(app)/matches/+page.svelte +++ b/src/routes/(app)/matches/+page.svelte @@ -9,9 +9,21 @@ const stateConfig: Record = { CREATED: { label: 'Created', color: 'text-text-secondary border-border' }, LOBBY: { label: 'In Lobby', color: 'text-yellow-400 border-yellow-500/30' }, - ROLLING: { label: 'Rolling', color: 'text-yellow-400 border-yellow-500/30', dot: 'bg-yellow-400' }, - PICKING: { label: 'Picking', color: 'text-blue-400 border-blue-500/30', dot: 'bg-blue-400' }, - PLAYING: { label: 'Live', color: 'text-green-400 border-green-500/30', dot: 'bg-green-400' }, + ROLLING: { + label: 'Rolling', + color: 'text-yellow-400 border-yellow-500/30', + dot: 'bg-yellow-400' + }, + PICKING: { + label: 'Picking', + color: 'text-blue-400 border-blue-500/30', + dot: 'bg-blue-400' + }, + PLAYING: { + label: 'Live', + color: 'text-green-400 border-green-500/30', + dot: 'bg-green-400' + }, FINISHED: { label: 'Finished', color: 'text-text-secondary border-border' }, CANCELLED: { label: 'Cancelled', color: 'text-red-400 border-red-500/30' } }; @@ -52,23 +64,28 @@ {/if}

- + {#if data.canCreateMatch} + + {/if} - {#if showCreate} + {#if showCreate && data.canCreateMatch}
{ createError = ''; return async ({ result, update }) => { - if (result.type === 'failure' || (result.type === 'success' && (result.data as any)?.error)) { + if ( + result.type === 'failure' || + (result.type === 'success' && (result.data as any)?.error) + ) { createError = (result.data as any)?.error ?? 'Failed to create match'; } else { await update(); @@ -166,7 +183,7 @@ {/if} -{#if liveMatches.length > 0} + {#if liveMatches.length > 0}

@@ -203,7 +220,10 @@ {/if}
- + {#if sc?.dot} {/if} @@ -234,9 +254,17 @@
{p1?.team.name ?? '?'} {#if m.state === 'FINISHED'} - {p1?.score ?? 0} + {p1?.score ?? 0} - - {p2?.score ?? 0} + {p2?.score ?? 0} {:else} vs {/if} @@ -259,14 +287,23 @@ {/if} - + {sc?.label ?? m.state} {:else} {#if liveMatches.length === 0}
-

No matches yet. Create one to get started.

+

+ No matches yet. + {#if data.canCreateMatch} + Create one to get started. + {:else} + Join the ranked queue from the dashboard! + {/if} +

{/if} {/each} diff --git a/src/routes/(app)/teams/+page.server.ts b/src/routes/(app)/teams/+page.server.ts index b6a8030..10247b6 100644 --- a/src/routes/(app)/teams/+page.server.ts +++ b/src/routes/(app)/teams/+page.server.ts @@ -2,10 +2,11 @@ import { db } from '$lib/server/db'; import { team, teamMember, user } from '$lib/server/db/schema'; import { eq } from 'drizzle-orm'; import { redirect } from '@sveltejs/kit'; +import { requireAuth, requireOwnerOrAdmin } from '$lib/server/permissions'; import type { PageServerLoad, Actions } from './$types'; export const load: PageServerLoad = async ({ locals }) => { - if (!locals.user) redirect(302, '/'); + const u = requireAuth(locals); const teams = await db.query.team.findMany({ with: { @@ -19,22 +20,22 @@ export const load: PageServerLoad = async ({ locals }) => { teams.map(async (t) => { const membersWithUsers = await Promise.all( t.members.map(async (m) => { - const u = await db.query.user.findFirst({ + const usr = await db.query.user.findFirst({ where: eq(user.id, m.userId) }); - return { ...m, user: u ? { id: u.id, name: u.name, image: u.image } : null }; + return { ...m, user: usr ? { id: usr.id, name: usr.name, image: usr.image } : null }; }) ); return { ...t, members: membersWithUsers }; }) ); - return { teams: teamsWithUsers, userId: locals.user.id }; + return { teams: teamsWithUsers, userId: u.id }; }; export const actions: Actions = { create: async ({ request, locals }) => { - if (!locals.user) redirect(302, '/'); + const u = requireAuth(locals); const form = await request.formData(); const name = form.get('name')?.toString()?.trim(); @@ -45,7 +46,7 @@ export const actions: Actions = { .insert(team) .values({ name, - ownerId: locals.user.id, + ownerId: u.id, isPersonal: false }) .returning(); @@ -53,15 +54,32 @@ export const actions: Actions = { // Add creator as captain await db.insert(teamMember).values({ teamId: created.id, - userId: locals.user.id, + userId: u.id, role: 'captain' }); return { success: true }; }, + rename: async ({ request, locals }) => { + const form = await request.formData(); + const teamId = form.get('teamId')?.toString(); + const name = form.get('name')?.toString()?.trim(); + + if (!teamId || !name) return { error: 'Team ID and name are required' }; + + const t = await db.query.team.findFirst({ where: eq(team.id, teamId) }); + if (!t) return { error: 'Team not found' }; + if (t.isPersonal) return { error: 'Cannot rename personal team' }; + + requireOwnerOrAdmin(locals, t.ownerId); + + await db.update(team).set({ name }).where(eq(team.id, teamId)); + return { success: true }; + }, + addMember: async ({ request, locals }) => { - if (!locals.user) redirect(302, '/'); + requireAuth(locals); const form = await request.formData(); const teamId = form.get('teamId')?.toString(); @@ -69,6 +87,11 @@ export const actions: Actions = { if (!teamId || !username) return { error: 'Team and username are required' }; + // Only owner or admin can add members + const t = await db.query.team.findFirst({ where: eq(team.id, teamId) }); + if (!t) return { error: 'Team not found' }; + requireOwnerOrAdmin(locals, t.ownerId); + // Find user by osu! username const u = await db.query.user.findFirst({ where: eq(user.name, username) @@ -93,26 +116,34 @@ export const actions: Actions = { }, removeMember: async ({ request, locals }) => { - if (!locals.user) redirect(302, '/'); + requireAuth(locals); const form = await request.formData(); const memberId = form.get('memberId')?.toString(); if (!memberId) return { error: 'Missing member ID' }; + // Look up the member to find the team, then check ownership + const member = await db.query.teamMember.findFirst({ + where: eq(teamMember.id, memberId), + with: { team: true } + }); + if (!member) return { error: 'Member not found' }; + requireOwnerOrAdmin(locals, member.team.ownerId); + await db.delete(teamMember).where(eq(teamMember.id, memberId)); return { success: true }; }, deleteTeam: async ({ request, locals }) => { - if (!locals.user) redirect(302, '/'); - const form = await request.formData(); const teamId = form.get('teamId')?.toString(); if (!teamId) return { error: 'Missing team ID' }; - // Only allow owner to delete const t = await db.query.team.findFirst({ where: eq(team.id, teamId) }); - if (!t || t.ownerId !== locals.user.id) return { error: 'Not authorized' }; + if (!t) return { error: 'Team not found' }; + if (t.isPersonal) return { error: 'Cannot delete personal team' }; + + requireOwnerOrAdmin(locals, t.ownerId); await db.delete(team).where(eq(team.id, teamId)); return { success: true }; diff --git a/src/routes/(app)/teams/+page.svelte b/src/routes/(app)/teams/+page.svelte index 3c87bef..a3d8c84 100644 --- a/src/routes/(app)/teams/+page.svelte +++ b/src/routes/(app)/teams/+page.svelte @@ -7,15 +7,17 @@ let creating = $state(false); let expandedTeam = $state(null); let addingMemberTo = $state(null); + let renamingTeam = $state(null); + let renameValue = $state(''); let memberUsername = $state(''); let actionError = $state(''); - const myTeams = $derived(data.teams.filter((t: any) => - t.members.some((m: any) => m.userId === data.userId) - )); - const otherTeams = $derived(data.teams.filter((t: any) => - !t.members.some((m: any) => m.userId === data.userId) - )); + const myTeams = $derived( + data.teams.filter((t: any) => t.members.some((m: any) => m.userId === data.userId)) + ); + const otherTeams = $derived( + data.teams.filter((t: any) => !t.members.some((m: any) => m.userId === data.userId)) + ); function isOwner(t: any) { return t.ownerId === data.userId; @@ -89,7 +91,9 @@ {#if t.avatarUrl} {:else} -
+
{t.name.charAt(0).toUpperCase()}
{/if} @@ -97,19 +101,81 @@
{t.name} {#if t.isPersonal} - solo + solo {/if}

{t.members.length} member{t.members.length !== 1 ? 's' : ''}

- › + › {#if expandedTeam === t.id}
+ + {#if isOwner(t) && !t.isPersonal} + {#if renamingTeam === t.id} + { + actionError = ''; + return async ({ result, update }) => { + if (result.type === 'success' && (result.data as any)?.success) { + renamingTeam = null; + await update(); + } else if ( + result.type === 'success' && + (result.data as any)?.error + ) { + actionError = (result.data as any).error; + } + }; + }} + class="mb-3 flex items-center gap-2" + > + + + + + + {:else} + + {/if} + {/if} +
{#each t.members as member} @@ -122,11 +188,21 @@ {member.user?.name ?? 'Unknown'} {member.role} {#if isOwner(t) && member.userId !== data.userId} -
{ - return async ({ update }) => { await update(); }; - }}> + { + return async ({ update }) => { + await update(); + }; + }} + > - +
{/if}
@@ -146,7 +222,10 @@ memberUsername = ''; addingMemberTo = null; await update(); - } else if (result.type === 'success' && (result.data as any)?.error) { + } else if ( + result.type === 'success' && + (result.data as any)?.error + ) { actionError = (result.data as any).error; } }; @@ -162,8 +241,17 @@ required class="flex-1 rounded-md border border-border bg-surface-600 px-3 py-1.5 text-sm text-text-primary placeholder:text-text-secondary/50 focus:border-accent focus:outline-none" /> - - + + {:else}