From fb9140a03fc4e45f4a2783d64817b52bd7cdbc7c Mon Sep 17 00:00:00 2001 From: Stan Runge Date: Sat, 28 Feb 2026 06:38:05 +0100 Subject: [PATCH] fix: update match configuration to bestOf 5 and scoringType to score_v2 --- .env | 14 + .svelte-kit/adapter-node/.vite/manifest.json | 661 + .../immutable/assets/_layout.Dv2no-8m.css | 1 + .svelte-kit/adapter-node/chunks/api.js | 69 + .svelte-kit/adapter-node/chunks/auth.js | 7983 +++ .../adapter-node/chunks/bun-sqlite-dialect.js | 155 + .svelte-kit/adapter-node/chunks/engine.js | 350 + .../adapter-node/chunks/environment.js | 14 + .svelte-kit/adapter-node/chunks/exports.js | 70 + .svelte-kit/adapter-node/chunks/false.js | 4 + .svelte-kit/adapter-node/chunks/index.js | 60 + .svelte-kit/adapter-node/chunks/index2.js | 302 + .svelte-kit/adapter-node/chunks/index3.js | 1249 + .svelte-kit/adapter-node/chunks/index4.js | 47 + .svelte-kit/adapter-node/chunks/index5.js | 224 + .svelte-kit/adapter-node/chunks/index6.js | 307 + .svelte-kit/adapter-node/chunks/internal.js | 127 + .../chunks/node-sqlite-dialect.js | 155 + .../adapter-node/chunks/orchestrator.js | 448 + .svelte-kit/adapter-node/chunks/query.js | 258 + .svelte-kit/adapter-node/chunks/root.js | 2713 + .svelte-kit/adapter-node/chunks/routing.js | 85 + .svelte-kit/adapter-node/chunks/server.js | 27 + .../adapter-node/chunks/shared-server.js | 14 + .svelte-kit/adapter-node/chunks/shared.js | 789 + .../adapter-node/chunks/state.svelte.js | 18 + .svelte-kit/adapter-node/chunks/url.js | 106 + .svelte-kit/adapter-node/chunks/utils.js | 43 + .../endpoints/api/health/_server.ts.js | 25 + .../endpoints/api/mappools/_id_/_server.ts.js | 24 + .../api/mappools/_id_/slots/_server.ts.js | 27 + .../_id_/slots/_slotId_/_server.ts.js | 11 + .../endpoints/api/mappools/_server.ts.js | 23 + .../endpoints/api/matches/_id_/_server.ts.js | 24 + .../api/matches/_id_/lobby/_server.ts.js | 15 + .../api/matches/_id_/pick/_server.ts.js | 18 + .../api/matches/_id_/roll/_server.ts.js | 18 + .../api/matches/_id_/rolling/_server.ts.js | 14 + .../api/matches/_id_/score/_server.ts.js | 18 + .../endpoints/api/matches/_server.ts.js | 37 + .../api/osu/beatmap/_id_/_server.ts.js | 14 + .../entries/endpoints/api/queue/_server.ts.js | 36 + .../entries/fallbacks/layout.svelte.js | 9 + .../adapter-node/entries/hooks.server.js | 22 + .../entries/pages/(app)/_layout.server.ts.js | 14 + .../entries/pages/(app)/_layout.svelte.js | 97 + .../entries/pages/(app)/_page.server.ts.js | 39 + .../entries/pages/(app)/_page.svelte.js | 118 + .../pages/(app)/admin/_page.server.ts.js | 70 + .../entries/pages/(app)/admin/_page.svelte.js | 70 + .../(app)/mappools/_id_/_page.server.ts.js | 100 + .../pages/(app)/mappools/_id_/_page.svelte.js | 98 + .../pages/(app)/mappools/_page.server.ts.js | 24 + .../pages/(app)/mappools/_page.svelte.js | 34 + .../(app)/matches/_id_/_page.server.ts.js | 129 + .../pages/(app)/matches/_id_/_page.svelte.js | 323 + .../pages/(app)/matches/_page.server.ts.js | 58 + .../pages/(app)/matches/_page.svelte.js | 164 + .../pages/(app)/settings/_page.server.ts.js | 37 + .../pages/(app)/settings/_page.svelte.js | 48 + .../pages/(app)/teams/_page.server.ts.js | 88 + .../entries/pages/(app)/teams/_page.svelte.js | 138 + .../entries/pages/_error.svelte.js | 25 + .../entries/pages/demo/_page.svelte.js | 31 + .../pages/demo/better-auth/_page.server.ts.js | 20 + .../pages/demo/better-auth/_page.svelte.js | 18 + .../demo/better-auth/login/_page.server.ts.js | 75 + .../demo/better-auth/login/_page.svelte.js | 18 + .../entries/pages/login/_page.server.ts.js | 16 + .svelte-kit/adapter-node/index.js | 3698 ++ .svelte-kit/adapter-node/internal.js | 16 + .svelte-kit/adapter-node/manifest-full.js | 226 + .svelte-kit/adapter-node/manifest.js | 230 + .svelte-kit/adapter-node/nodes/0.js | 8 + .svelte-kit/adapter-node/nodes/1.js | 8 + .svelte-kit/adapter-node/nodes/10.js | 10 + .svelte-kit/adapter-node/nodes/11.js | 8 + .svelte-kit/adapter-node/nodes/12.js | 10 + .svelte-kit/adapter-node/nodes/13.js | 10 + .svelte-kit/adapter-node/nodes/14.js | 8 + .svelte-kit/adapter-node/nodes/2.js | 10 + .svelte-kit/adapter-node/nodes/3.js | 10 + .svelte-kit/adapter-node/nodes/4.js | 10 + .svelte-kit/adapter-node/nodes/5.js | 10 + .svelte-kit/adapter-node/nodes/6.js | 10 + .svelte-kit/adapter-node/nodes/7.js | 10 + .svelte-kit/adapter-node/nodes/8.js | 10 + .svelte-kit/adapter-node/nodes/9.js | 10 + .svelte-kit/adapter-node/remote-entry.js | 314 + .svelte-kit/ambient.d.ts | 332 + .svelte-kit/generated/client-optimized/app.js | 52 + .../generated/client-optimized/matchers.js | 1 + .../generated/client-optimized/nodes/0.js | 1 + .../generated/client-optimized/nodes/1.js | 1 + .../generated/client-optimized/nodes/10.js | 1 + .../generated/client-optimized/nodes/11.js | 1 + .../generated/client-optimized/nodes/12.js | 1 + .../generated/client-optimized/nodes/13.js | 1 + .../generated/client-optimized/nodes/14.js | 0 .../generated/client-optimized/nodes/2.js | 1 + .../generated/client-optimized/nodes/3.js | 1 + .../generated/client-optimized/nodes/4.js | 1 + .../generated/client-optimized/nodes/5.js | 1 + .../generated/client-optimized/nodes/6.js | 1 + .../generated/client-optimized/nodes/7.js | 1 + .../generated/client-optimized/nodes/8.js | 1 + .../generated/client-optimized/nodes/9.js | 1 + .svelte-kit/generated/client/app.js | 52 + .svelte-kit/generated/client/matchers.js | 1 + .svelte-kit/generated/client/nodes/0.js | 1 + .svelte-kit/generated/client/nodes/1.js | 1 + .svelte-kit/generated/client/nodes/10.js | 1 + .svelte-kit/generated/client/nodes/11.js | 1 + .svelte-kit/generated/client/nodes/12.js | 1 + .svelte-kit/generated/client/nodes/13.js | 1 + .svelte-kit/generated/client/nodes/14.js | 0 .svelte-kit/generated/client/nodes/2.js | 1 + .svelte-kit/generated/client/nodes/3.js | 1 + .svelte-kit/generated/client/nodes/4.js | 1 + .svelte-kit/generated/client/nodes/5.js | 1 + .svelte-kit/generated/client/nodes/6.js | 1 + .svelte-kit/generated/client/nodes/7.js | 1 + .svelte-kit/generated/client/nodes/8.js | 1 + .svelte-kit/generated/client/nodes/9.js | 1 + .svelte-kit/generated/root.js | 3 + .svelte-kit/generated/root.svelte | 80 + .svelte-kit/generated/server/internal.js | 53 + .svelte-kit/non-ambient.d.ts | 81 + .svelte-kit/output/client/.vite/manifest.json | 394 + .../_app/immutable/assets/2.Dv2no-8m.css | 1 + .../client/_app/immutable/chunks/BAocuFgQ.js | 1 + .../client/_app/immutable/chunks/BLQQas77.js | 1 + .../client/_app/immutable/chunks/BQKoxf2Q.js | 1 + .../client/_app/immutable/chunks/BkIq08el.js | 3 + .../client/_app/immutable/chunks/BnX5ZnVA.js | 1 + .../client/_app/immutable/chunks/BqOsL1Vv.js | 1 + .../client/_app/immutable/chunks/BxEwC6Zc.js | 1 + .../client/_app/immutable/chunks/CAkKRSSs.js | 1 + .../client/_app/immutable/chunks/CvGSsBh3.js | 1 + .../client/_app/immutable/chunks/Cy2QBcXt.js | 1 + .../client/_app/immutable/chunks/CyUoLS3q.js | 1 + .../client/_app/immutable/chunks/D2SGgx9j.js | 1 + .../client/_app/immutable/chunks/DAtZQVjv.js | 1 + .../client/_app/immutable/chunks/DoLu9QLy.js | 2 + .../client/_app/immutable/chunks/DsnmJJEf.js | 1 + .../client/_app/immutable/chunks/TpZZa089.js | 1 + .../client/_app/immutable/chunks/kALFGdUG.js | 1 + .../_app/immutable/entry/app.DL20j9gb.js | 2 + .../_app/immutable/entry/start.Df1GVxyt.js | 1 + .../client/_app/immutable/nodes/0.9C686m9W.js | 1 + .../client/_app/immutable/nodes/1.RyK1bdTz.js | 1 + .../_app/immutable/nodes/10.BPlEN6_G.js | 1 + .../_app/immutable/nodes/11.DR1Vz7m0.js | 1 + .../_app/immutable/nodes/12.C9UZWAjJ.js | 1 + .../_app/immutable/nodes/13.CyZ4e6yK.js | 1 + .../client/_app/immutable/nodes/2.BsR2_q_w.js | 1 + .../client/_app/immutable/nodes/3.CMuy9Bx3.js | 3 + .../client/_app/immutable/nodes/4.BdC-uDW-.js | 1 + .../client/_app/immutable/nodes/5.CyqZcxti.js | 2 + .../client/_app/immutable/nodes/6.CEe0czaO.js | 1 + .../client/_app/immutable/nodes/7._nuD3LlN.js | 1 + .../client/_app/immutable/nodes/8.CkbqikZq.js | 1 + .../client/_app/immutable/nodes/9.BTBc_Eli.js | 1 + .svelte-kit/output/client/_app/version.json | 1 + .../output/client/android-chrome-192x192.png | Bin 0 -> 38272 bytes .../output/client/android-chrome-512x512.png | Bin 0 -> 159273 bytes .../output/client/apple-touch-icon.png | Bin 0 -> 36949 bytes .svelte-kit/output/client/favicon-16x16.png | Bin 0 -> 860 bytes .svelte-kit/output/client/favicon-32x32.png | Bin 0 -> 2419 bytes .svelte-kit/output/client/favicon.ico | Bin 0 -> 15406 bytes .svelte-kit/output/client/robots.txt | 3 + .svelte-kit/output/client/site.webmanifest | 1 + .svelte-kit/output/server/.vite/manifest.json | 661 + .../immutable/assets/_layout.Dv2no-8m.css | 1 + .svelte-kit/output/server/chunks/api.js | 69 + .svelte-kit/output/server/chunks/auth.js | 7983 +++ .../server/chunks/bun-sqlite-dialect.js | 155 + .svelte-kit/output/server/chunks/engine.js | 350 + .../output/server/chunks/environment.js | 14 + .svelte-kit/output/server/chunks/exports.js | 70 + .svelte-kit/output/server/chunks/false.js | 4 + .svelte-kit/output/server/chunks/index.js | 60 + .svelte-kit/output/server/chunks/index2.js | 302 + .svelte-kit/output/server/chunks/index3.js | 1249 + .svelte-kit/output/server/chunks/index4.js | 47 + .svelte-kit/output/server/chunks/index5.js | 224 + .svelte-kit/output/server/chunks/index6.js | 307 + .svelte-kit/output/server/chunks/internal.js | 127 + .../server/chunks/node-sqlite-dialect.js | 155 + .../output/server/chunks/orchestrator.js | 448 + .svelte-kit/output/server/chunks/query.js | 258 + .svelte-kit/output/server/chunks/root.js | 2713 + .svelte-kit/output/server/chunks/routing.js | 85 + .svelte-kit/output/server/chunks/server.js | 27 + .../output/server/chunks/shared-server.js | 14 + .svelte-kit/output/server/chunks/shared.js | 789 + .../output/server/chunks/state.svelte.js | 18 + .svelte-kit/output/server/chunks/url.js | 106 + .svelte-kit/output/server/chunks/utils.js | 43 + .../endpoints/api/health/_server.ts.js | 25 + .../endpoints/api/mappools/_id_/_server.ts.js | 24 + .../api/mappools/_id_/slots/_server.ts.js | 27 + .../_id_/slots/_slotId_/_server.ts.js | 11 + .../endpoints/api/mappools/_server.ts.js | 23 + .../endpoints/api/matches/_id_/_server.ts.js | 24 + .../api/matches/_id_/lobby/_server.ts.js | 15 + .../api/matches/_id_/pick/_server.ts.js | 18 + .../api/matches/_id_/roll/_server.ts.js | 18 + .../api/matches/_id_/rolling/_server.ts.js | 14 + .../api/matches/_id_/score/_server.ts.js | 18 + .../endpoints/api/matches/_server.ts.js | 37 + .../api/osu/beatmap/_id_/_server.ts.js | 14 + .../entries/endpoints/api/queue/_server.ts.js | 36 + .../server/entries/fallbacks/layout.svelte.js | 9 + .../output/server/entries/hooks.server.js | 22 + .../entries/pages/(app)/_layout.server.ts.js | 14 + .../entries/pages/(app)/_layout.svelte.js | 97 + .../entries/pages/(app)/_page.server.ts.js | 39 + .../entries/pages/(app)/_page.svelte.js | 118 + .../pages/(app)/admin/_page.server.ts.js | 70 + .../entries/pages/(app)/admin/_page.svelte.js | 70 + .../(app)/mappools/_id_/_page.server.ts.js | 100 + .../pages/(app)/mappools/_id_/_page.svelte.js | 98 + .../pages/(app)/mappools/_page.server.ts.js | 24 + .../pages/(app)/mappools/_page.svelte.js | 34 + .../(app)/matches/_id_/_page.server.ts.js | 129 + .../pages/(app)/matches/_id_/_page.svelte.js | 323 + .../pages/(app)/matches/_page.server.ts.js | 58 + .../pages/(app)/matches/_page.svelte.js | 164 + .../pages/(app)/settings/_page.server.ts.js | 37 + .../pages/(app)/settings/_page.svelte.js | 48 + .../pages/(app)/teams/_page.server.ts.js | 88 + .../entries/pages/(app)/teams/_page.svelte.js | 138 + .../server/entries/pages/_error.svelte.js | 25 + .../server/entries/pages/demo/_page.svelte.js | 31 + .../pages/demo/better-auth/_page.server.ts.js | 20 + .../pages/demo/better-auth/_page.svelte.js | 18 + .../demo/better-auth/login/_page.server.ts.js | 75 + .../demo/better-auth/login/_page.svelte.js | 18 + .../entries/pages/login/_page.server.ts.js | 16 + .svelte-kit/output/server/index.js | 3698 ++ .svelte-kit/output/server/internal.js | 16 + .svelte-kit/output/server/manifest-full.js | 226 + .svelte-kit/output/server/manifest.js | 226 + .svelte-kit/output/server/nodes/0.js | 8 + .svelte-kit/output/server/nodes/1.js | 8 + .svelte-kit/output/server/nodes/10.js | 10 + .svelte-kit/output/server/nodes/11.js | 8 + .svelte-kit/output/server/nodes/12.js | 10 + .svelte-kit/output/server/nodes/13.js | 10 + .svelte-kit/output/server/nodes/14.js | 8 + .svelte-kit/output/server/nodes/2.js | 10 + .svelte-kit/output/server/nodes/3.js | 10 + .svelte-kit/output/server/nodes/4.js | 10 + .svelte-kit/output/server/nodes/5.js | 10 + .svelte-kit/output/server/nodes/6.js | 10 + .svelte-kit/output/server/nodes/7.js | 10 + .svelte-kit/output/server/nodes/8.js | 10 + .svelte-kit/output/server/nodes/9.js | 10 + .svelte-kit/output/server/remote-entry.js | 314 + .svelte-kit/tsconfig.json | 55 + .svelte-kit/types/route_meta_data.json | 88 + .svelte-kit/types/src/routes/$types.d.ts | 20 + .../types/src/routes/(app)/$types.d.ts | 34 + .../types/src/routes/(app)/admin/$types.d.ts | 31 + .../routes/(app)/admin/proxy+page.server.ts | 63 + .../src/routes/(app)/mappools/$types.d.ts | 31 + .../routes/(app)/mappools/[id]/$types.d.ts | 32 + .../(app)/mappools/[id]/proxy+page.server.ts | 120 + .../(app)/mappools/proxy+page.server.ts | 34 + .../src/routes/(app)/matches/$types.d.ts | 31 + .../src/routes/(app)/matches/[id]/$types.d.ts | 32 + .../(app)/matches/[id]/proxy+page.server.ts | 164 + .../routes/(app)/matches/proxy+page.server.ts | 73 + .../src/routes/(app)/proxy+layout.server.ts | 17 + .../src/routes/(app)/proxy+page.server.ts | 50 + .../src/routes/(app)/settings/$types.d.ts | 31 + .../(app)/settings/proxy+page.server.ts | 48 + .../types/src/routes/(app)/teams/$types.d.ts | 31 + .../routes/(app)/teams/proxy+page.server.ts | 122 + .../types/src/routes/api/health/$types.d.ts | 10 + .../types/src/routes/api/mappools/$types.d.ts | 10 + .../src/routes/api/mappools/[id]/$types.d.ts | 11 + .../api/mappools/[id]/slots/$types.d.ts | 11 + .../mappools/[id]/slots/[slotId]/$types.d.ts | 11 + .../types/src/routes/api/matches/$types.d.ts | 10 + .../src/routes/api/matches/[id]/$types.d.ts | 11 + .../routes/api/matches/[id]/lobby/$types.d.ts | 11 + .../routes/api/matches/[id]/pick/$types.d.ts | 11 + .../routes/api/matches/[id]/roll/$types.d.ts | 11 + .../api/matches/[id]/rolling/$types.d.ts | 11 + .../routes/api/matches/[id]/score/$types.d.ts | 11 + .../routes/api/osu/beatmap/[id]/$types.d.ts | 11 + .../types/src/routes/api/queue/$types.d.ts | 10 + .svelte-kit/types/src/routes/demo/$types.d.ts | 18 + .../src/routes/demo/better-auth/$types.d.ts | 31 + .../routes/demo/better-auth/login/$types.d.ts | 31 + .../better-auth/login/proxy+page.server.ts | 80 + .../demo/better-auth/proxy+page.server.ts | 22 + .../types/src/routes/login/$types.d.ts | 25 + .../src/routes/login/proxy+page.server.ts | 19 + .../_app/immutable/assets/2.Dv2no-8m.css | 1 + .../_app/immutable/assets/2.Dv2no-8m.css.br | Bin 0 -> 4851 bytes .../_app/immutable/assets/2.Dv2no-8m.css.gz | Bin 0 -> 5654 bytes .../client/_app/immutable/chunks/BAocuFgQ.js | 1 + .../_app/immutable/chunks/BAocuFgQ.js.br | Bin 0 -> 878 bytes .../_app/immutable/chunks/BAocuFgQ.js.gz | Bin 0 -> 991 bytes .../client/_app/immutable/chunks/BLQQas77.js | 1 + .../_app/immutable/chunks/BLQQas77.js.br | Bin 0 -> 1712 bytes .../_app/immutable/chunks/BLQQas77.js.gz | Bin 0 -> 1858 bytes .../client/_app/immutable/chunks/BQKoxf2Q.js | 1 + .../_app/immutable/chunks/BQKoxf2Q.js.br | Bin 0 -> 344 bytes .../_app/immutable/chunks/BQKoxf2Q.js.gz | Bin 0 -> 396 bytes .../client/_app/immutable/chunks/BkIq08el.js | 3 + .../_app/immutable/chunks/BkIq08el.js.br | Bin 0 -> 8905 bytes .../_app/immutable/chunks/BkIq08el.js.gz | Bin 0 -> 9809 bytes .../client/_app/immutable/chunks/BnX5ZnVA.js | 1 + .../_app/immutable/chunks/BnX5ZnVA.js.br | Bin 0 -> 583 bytes .../_app/immutable/chunks/BnX5ZnVA.js.gz | Bin 0 -> 659 bytes .../client/_app/immutable/chunks/BqOsL1Vv.js | 1 + .../_app/immutable/chunks/BqOsL1Vv.js.br | Bin 0 -> 189 bytes .../_app/immutable/chunks/BqOsL1Vv.js.gz | Bin 0 -> 224 bytes .../client/_app/immutable/chunks/BxEwC6Zc.js | 1 + .../_app/immutable/chunks/BxEwC6Zc.js.br | Bin 0 -> 8486 bytes .../_app/immutable/chunks/BxEwC6Zc.js.gz | Bin 0 -> 9437 bytes .../client/_app/immutable/chunks/CAkKRSSs.js | 1 + .../_app/immutable/chunks/CAkKRSSs.js.br | Bin 0 -> 408 bytes .../_app/immutable/chunks/CAkKRSSs.js.gz | Bin 0 -> 457 bytes .../client/_app/immutable/chunks/CvGSsBh3.js | 1 + .../_app/immutable/chunks/CvGSsBh3.js.br | Bin 0 -> 344 bytes .../_app/immutable/chunks/CvGSsBh3.js.gz | Bin 0 -> 406 bytes .../client/_app/immutable/chunks/Cy2QBcXt.js | 1 + .../_app/immutable/chunks/Cy2QBcXt.js.br | Bin 0 -> 516 bytes .../_app/immutable/chunks/Cy2QBcXt.js.gz | Bin 0 -> 585 bytes .../client/_app/immutable/chunks/CyUoLS3q.js | 1 + .../_app/immutable/chunks/CyUoLS3q.js.br | Bin 0 -> 177 bytes .../_app/immutable/chunks/CyUoLS3q.js.gz | Bin 0 -> 170 bytes .../client/_app/immutable/chunks/D2SGgx9j.js | 1 + .../_app/immutable/chunks/D2SGgx9j.js.br | Bin 0 -> 141 bytes .../_app/immutable/chunks/D2SGgx9j.js.gz | Bin 0 -> 165 bytes .../client/_app/immutable/chunks/DAtZQVjv.js | 1 + .../_app/immutable/chunks/DAtZQVjv.js.br | Bin 0 -> 3369 bytes .../_app/immutable/chunks/DAtZQVjv.js.gz | Bin 0 -> 3782 bytes .../client/_app/immutable/chunks/DoLu9QLy.js | 2 + .../_app/immutable/chunks/DoLu9QLy.js.br | Bin 0 -> 2519 bytes .../_app/immutable/chunks/DoLu9QLy.js.gz | Bin 0 -> 2783 bytes .../client/_app/immutable/chunks/DsnmJJEf.js | 1 + .../_app/immutable/chunks/DsnmJJEf.js.br | 2 + .../_app/immutable/chunks/DsnmJJEf.js.gz | Bin 0 -> 81 bytes .../client/_app/immutable/chunks/TpZZa089.js | 1 + .../_app/immutable/chunks/TpZZa089.js.br | Bin 0 -> 315 bytes .../_app/immutable/chunks/TpZZa089.js.gz | Bin 0 -> 340 bytes .../client/_app/immutable/chunks/kALFGdUG.js | 1 + .../_app/immutable/chunks/kALFGdUG.js.br | Bin 0 -> 603 bytes .../_app/immutable/chunks/kALFGdUG.js.gz | Bin 0 -> 673 bytes .../_app/immutable/entry/app.DL20j9gb.js | 2 + .../_app/immutable/entry/app.DL20j9gb.js.br | Bin 0 -> 3459 bytes .../_app/immutable/entry/app.DL20j9gb.js.gz | Bin 0 -> 3846 bytes .../_app/immutable/entry/start.Df1GVxyt.js | 1 + .../_app/immutable/entry/start.Df1GVxyt.js.br | Bin 0 -> 107 bytes .../_app/immutable/entry/start.Df1GVxyt.js.gz | Bin 0 -> 107 bytes .../client/_app/immutable/nodes/0.9C686m9W.js | 1 + .../_app/immutable/nodes/0.9C686m9W.js.br | Bin 0 -> 157 bytes .../_app/immutable/nodes/0.9C686m9W.js.gz | Bin 0 -> 174 bytes .../client/_app/immutable/nodes/1.RyK1bdTz.js | 1 + .../_app/immutable/nodes/1.RyK1bdTz.js.br | Bin 0 -> 564 bytes .../_app/immutable/nodes/1.RyK1bdTz.js.gz | Bin 0 -> 688 bytes .../_app/immutable/nodes/10.BPlEN6_G.js | 1 + .../_app/immutable/nodes/10.BPlEN6_G.js.br | Bin 0 -> 2484 bytes .../_app/immutable/nodes/10.BPlEN6_G.js.gz | Bin 0 -> 2877 bytes .../_app/immutable/nodes/11.DR1Vz7m0.js | 1 + .../_app/immutable/nodes/11.DR1Vz7m0.js.br | Bin 0 -> 276 bytes .../_app/immutable/nodes/11.DR1Vz7m0.js.gz | Bin 0 -> 286 bytes .../_app/immutable/nodes/12.C9UZWAjJ.js | 1 + .../_app/immutable/nodes/12.C9UZWAjJ.js.br | Bin 0 -> 355 bytes .../_app/immutable/nodes/12.C9UZWAjJ.js.gz | Bin 0 -> 427 bytes .../_app/immutable/nodes/13.CyZ4e6yK.js | 1 + .../_app/immutable/nodes/13.CyZ4e6yK.js.br | Bin 0 -> 521 bytes .../_app/immutable/nodes/13.CyZ4e6yK.js.gz | Bin 0 -> 658 bytes .../client/_app/immutable/nodes/2.BsR2_q_w.js | 1 + .../_app/immutable/nodes/2.BsR2_q_w.js.br | Bin 0 -> 1662 bytes .../_app/immutable/nodes/2.BsR2_q_w.js.gz | Bin 0 -> 1962 bytes .../client/_app/immutable/nodes/3.CMuy9Bx3.js | 3 + .../_app/immutable/nodes/3.CMuy9Bx3.js.br | Bin 0 -> 3044 bytes .../_app/immutable/nodes/3.CMuy9Bx3.js.gz | Bin 0 -> 3553 bytes .../client/_app/immutable/nodes/4.BdC-uDW-.js | 1 + .../_app/immutable/nodes/4.BdC-uDW-.js.br | Bin 0 -> 1473 bytes .../_app/immutable/nodes/4.BdC-uDW-.js.gz | Bin 0 -> 1715 bytes .../client/_app/immutable/nodes/5.CyqZcxti.js | 2 + .../_app/immutable/nodes/5.CyqZcxti.js.br | Bin 0 -> 1010 bytes .../_app/immutable/nodes/5.CyqZcxti.js.gz | Bin 0 -> 1208 bytes .../client/_app/immutable/nodes/6.CEe0czaO.js | 1 + .../_app/immutable/nodes/6.CEe0czaO.js.br | Bin 0 -> 2399 bytes .../_app/immutable/nodes/6.CEe0czaO.js.gz | Bin 0 -> 2759 bytes .../client/_app/immutable/nodes/7._nuD3LlN.js | 1 + .../_app/immutable/nodes/7._nuD3LlN.js.br | Bin 0 -> 3095 bytes .../_app/immutable/nodes/7._nuD3LlN.js.gz | Bin 0 -> 3600 bytes .../client/_app/immutable/nodes/8.CkbqikZq.js | 1 + .../_app/immutable/nodes/8.CkbqikZq.js.br | Bin 0 -> 5147 bytes .../_app/immutable/nodes/8.CkbqikZq.js.gz | Bin 0 -> 6008 bytes .../client/_app/immutable/nodes/9.BTBc_Eli.js | 1 + .../_app/immutable/nodes/9.BTBc_Eli.js.br | Bin 0 -> 1490 bytes .../_app/immutable/nodes/9.BTBc_Eli.js.gz | Bin 0 -> 1728 bytes build/client/_app/version.json | 1 + build/client/_app/version.json.br | Bin 0 -> 30 bytes build/client/_app/version.json.gz | Bin 0 -> 47 bytes build/client/android-chrome-192x192.png | Bin 0 -> 38272 bytes build/client/android-chrome-512x512.png | Bin 0 -> 159273 bytes build/client/apple-touch-icon.png | Bin 0 -> 36949 bytes build/client/favicon-16x16.png | Bin 0 -> 860 bytes build/client/favicon-32x32.png | Bin 0 -> 2419 bytes build/client/favicon.ico | Bin 0 -> 15406 bytes build/client/robots.txt | 3 + build/client/robots.txt.br | Bin 0 -> 67 bytes build/client/robots.txt.gz | Bin 0 -> 77 bytes build/client/site.webmanifest | 1 + build/env.js | 94 + build/handler.js | 1494 + build/index.js | 345 + build/server/chunks/0-BWa0n_wG.js | 9 + build/server/chunks/0-BWa0n_wG.js.map | 1 + build/server/chunks/1-dOPiiXyK.js | 9 + build/server/chunks/1-dOPiiXyK.js.map | 1 + build/server/chunks/10-BGqcbnOp.js | 103 + build/server/chunks/10-BGqcbnOp.js.map | 1 + build/server/chunks/11-DB2oh-6z.js | 9 + build/server/chunks/11-DB2oh-6z.js.map | 1 + build/server/chunks/12-3YbOOB0i.js | 42 + build/server/chunks/12-3YbOOB0i.js.map | 1 + build/server/chunks/13-CyOLqwjC.js | 93 + build/server/chunks/13-CyOLqwjC.js.map | 1 + build/server/chunks/14-BMPOArNY.js | 36 + build/server/chunks/14-BMPOArNY.js.map | 1 + build/server/chunks/2-BiADR-CH.js | 27 + build/server/chunks/2-BiADR-CH.js.map | 1 + build/server/chunks/3-BPD8edaL.js | 55 + build/server/chunks/3-BPD8edaL.js.map | 1 + build/server/chunks/4-CQssXWUd.js | 85 + build/server/chunks/4-CQssXWUd.js.map | 1 + build/server/chunks/5-Dk6CJpPs.js | 40 + build/server/chunks/5-Dk6CJpPs.js.map | 1 + build/server/chunks/6-CW5Wcf44.js | 115 + build/server/chunks/6-CW5Wcf44.js.map | 1 + build/server/chunks/7-DLfylrWu.js | 73 + build/server/chunks/7-DLfylrWu.js.map | 1 + build/server/chunks/8-Cct4CuMl.js | 144 + build/server/chunks/8-Cct4CuMl.js.map | 1 + build/server/chunks/9-DztSgTEC.js | 57 + build/server/chunks/9-DztSgTEC.js.map | 1 + build/server/chunks/_error.svelte-Szt4-wKI.js | 30 + .../chunks/_error.svelte-Szt4-wKI.js.map | 1 + .../server/chunks/_layout.svelte-BV7ZtoED.js | 96 + .../chunks/_layout.svelte-BV7ZtoED.js.map | 1 + build/server/chunks/_page.svelte-6xWa24o9.js | 68 + .../chunks/_page.svelte-6xWa24o9.js.map | 1 + build/server/chunks/_page.svelte-B33-skqO.js | 136 + .../chunks/_page.svelte-B33-skqO.js.map | 1 + build/server/chunks/_page.svelte-Be6BiSzg.js | 96 + .../chunks/_page.svelte-Be6BiSzg.js.map | 1 + build/server/chunks/_page.svelte-Bj4oURhW.js | 162 + .../chunks/_page.svelte-Bj4oURhW.js.map | 1 + build/server/chunks/_page.svelte-C-71W7Xe.js | 119 + .../chunks/_page.svelte-C-71W7Xe.js.map | 1 + build/server/chunks/_page.svelte-C5eWfXqa.js | 29 + .../chunks/_page.svelte-C5eWfXqa.js.map | 1 + build/server/chunks/_page.svelte-Ctzd-tuM.js | 15 + .../chunks/_page.svelte-Ctzd-tuM.js.map | 1 + build/server/chunks/_page.svelte-D23V0tpa.js | 46 + .../chunks/_page.svelte-D23V0tpa.js.map | 1 + build/server/chunks/_page.svelte-G6sWOX7O.js | 321 + .../chunks/_page.svelte-G6sWOX7O.js.map | 1 + build/server/chunks/_page.svelte-ad4cZnqC.js | 15 + .../chunks/_page.svelte-ad4cZnqC.js.map | 1 + build/server/chunks/_page.svelte-ijSwFWFX.js | 32 + .../chunks/_page.svelte-ijSwFWFX.js.map | 1 + build/server/chunks/_server.ts-BEoJR5yQ.js | 39 + .../server/chunks/_server.ts-BEoJR5yQ.js.map | 1 + build/server/chunks/_server.ts-BKWDSPwT.js | 22 + .../server/chunks/_server.ts-BKWDSPwT.js.map | 1 + build/server/chunks/_server.ts-C5pGCspz.js | 22 + .../server/chunks/_server.ts-C5pGCspz.js.map | 1 + build/server/chunks/_server.ts-CYhG9EuN.js | 25 + .../server/chunks/_server.ts-CYhG9EuN.js.map | 1 + build/server/chunks/_server.ts-CgeuSTTA.js | 19 + .../server/chunks/_server.ts-CgeuSTTA.js.map | 1 + build/server/chunks/_server.ts-Chr3sGwY.js | 29 + .../server/chunks/_server.ts-Chr3sGwY.js.map | 1 + build/server/chunks/_server.ts-CknVZIWY.js | 25 + .../server/chunks/_server.ts-CknVZIWY.js.map | 1 + build/server/chunks/_server.ts-Cp6RS2Xl.js | 27 + .../server/chunks/_server.ts-Cp6RS2Xl.js.map | 1 + build/server/chunks/_server.ts-DLwKwHxp.js | 18 + .../server/chunks/_server.ts-DLwKwHxp.js.map | 1 + build/server/chunks/_server.ts-DRKvzZ51.js | 36 + .../server/chunks/_server.ts-DRKvzZ51.js.map | 1 + build/server/chunks/_server.ts-KSG0NbEr.js | 27 + .../server/chunks/_server.ts-KSG0NbEr.js.map | 1 + build/server/chunks/_server.ts-M_0oeLSe.js | 18 + .../server/chunks/_server.ts-M_0oeLSe.js.map | 1 + build/server/chunks/_server.ts-kIjYmsyw.js | 22 + .../server/chunks/_server.ts-kIjYmsyw.js.map | 1 + build/server/chunks/_server.ts-wwm7Wb6_.js | 13 + .../server/chunks/_server.ts-wwm7Wb6_.js.map | 1 + build/server/chunks/aggregate-CrXc04Dg.js | 8 + build/server/chunks/aggregate-CrXc04Dg.js.map | 1 + build/server/chunks/api-DYV1cRWY.js | 70 + build/server/chunks/api-DYV1cRWY.js.map | 1 + build/server/chunks/auth-CAP7sZek.js | 51503 ++++++++++++++++ build/server/chunks/auth-CAP7sZek.js.map | 1 + .../chunks/bun-sqlite-dialect-C-rWaXX0.js | 165 + .../chunks/bun-sqlite-dialect-C-rWaXX0.js.map | 1 + build/server/chunks/engine-DiCmv1C-.js | 339 + build/server/chunks/engine-DiCmv1C-.js.map | 1 + build/server/chunks/exports-B5ORJhfK.js | 65 + build/server/chunks/exports-B5ORJhfK.js.map | 1 + build/server/chunks/hooks.server-g13gcBbX.js | 31 + .../chunks/hooks.server-g13gcBbX.js.map | 1 + build/server/chunks/index-B2LGyy1l.js | 247 + build/server/chunks/index-B2LGyy1l.js.map | 1 + build/server/chunks/index-MqY7A75_.js | 59 + build/server/chunks/index-MqY7A75_.js.map | 1 + build/server/chunks/index2-B7hVh_Qf.js | 7045 +++ build/server/chunks/index2-B7hVh_Qf.js.map | 1 + build/server/chunks/index3-C4geC3K_.js | 1821 + build/server/chunks/index3-C4geC3K_.js.map | 1 + build/server/chunks/index4-B8FtU3M-.js | 44 + build/server/chunks/index4-B8FtU3M-.js.map | 1 + build/server/chunks/index5-f2WMNNiy.js | 233 + build/server/chunks/index5-f2WMNNiy.js.map | 1 + build/server/chunks/index6-aBT-vm5N.js | 313 + build/server/chunks/index6-aBT-vm5N.js.map | 1 + build/server/chunks/layout.svelte-UxsTmhKc.js | 8 + .../chunks/layout.svelte-UxsTmhKc.js.map | 1 + .../chunks/node-sqlite-dialect-CyfGAEpZ.js | 165 + .../node-sqlite-dialect-CyfGAEpZ.js.map | 1 + build/server/chunks/orchestrator-BMt7lT0G.js | 444 + .../chunks/orchestrator-BMt7lT0G.js.map | 1 + build/server/chunks/root-D12ma0No.js | 2880 + build/server/chunks/root-D12ma0No.js.map | 1 + build/server/chunks/routing-NqiTWnxU.js | 100 + build/server/chunks/routing-NqiTWnxU.js.map | 1 + build/server/chunks/shared-DWC9PG0H.js | 1242 + build/server/chunks/shared-DWC9PG0H.js.map | 1 + build/server/chunks/shared-server-DaWdgxVh.js | 11 + .../chunks/shared-server-DaWdgxVh.js.map | 1 + build/server/chunks/state.svelte-DvHRBIfo.js | 10 + .../chunks/state.svelte-DvHRBIfo.js.map | 1 + build/server/chunks/utils-D_bK1W85.js | 39 + build/server/chunks/utils-D_bK1W85.js.map | 1 + build/server/index.js | 4355 ++ build/server/index.js.map | 1 + build/server/manifest.js | 233 + build/server/manifest.js.map | 1 + build/shims.js | 32 + src/lib/server/match/engine.ts | 2 +- 555 files changed, 124715 insertions(+), 1 deletion(-) create mode 100644 .env create mode 100644 .svelte-kit/adapter-node/.vite/manifest.json create mode 100644 .svelte-kit/adapter-node/_app/immutable/assets/_layout.Dv2no-8m.css create mode 100644 .svelte-kit/adapter-node/chunks/api.js create mode 100644 .svelte-kit/adapter-node/chunks/auth.js create mode 100644 .svelte-kit/adapter-node/chunks/bun-sqlite-dialect.js create mode 100644 .svelte-kit/adapter-node/chunks/engine.js create mode 100644 .svelte-kit/adapter-node/chunks/environment.js create mode 100644 .svelte-kit/adapter-node/chunks/exports.js create mode 100644 .svelte-kit/adapter-node/chunks/false.js create mode 100644 .svelte-kit/adapter-node/chunks/index.js create mode 100644 .svelte-kit/adapter-node/chunks/index2.js create mode 100644 .svelte-kit/adapter-node/chunks/index3.js create mode 100644 .svelte-kit/adapter-node/chunks/index4.js create mode 100644 .svelte-kit/adapter-node/chunks/index5.js create mode 100644 .svelte-kit/adapter-node/chunks/index6.js create mode 100644 .svelte-kit/adapter-node/chunks/internal.js create mode 100644 .svelte-kit/adapter-node/chunks/node-sqlite-dialect.js create mode 100644 .svelte-kit/adapter-node/chunks/orchestrator.js create mode 100644 .svelte-kit/adapter-node/chunks/query.js create mode 100644 .svelte-kit/adapter-node/chunks/root.js create mode 100644 .svelte-kit/adapter-node/chunks/routing.js create mode 100644 .svelte-kit/adapter-node/chunks/server.js create mode 100644 .svelte-kit/adapter-node/chunks/shared-server.js create mode 100644 .svelte-kit/adapter-node/chunks/shared.js create mode 100644 .svelte-kit/adapter-node/chunks/state.svelte.js create mode 100644 .svelte-kit/adapter-node/chunks/url.js create mode 100644 .svelte-kit/adapter-node/chunks/utils.js create mode 100644 .svelte-kit/adapter-node/entries/endpoints/api/health/_server.ts.js create mode 100644 .svelte-kit/adapter-node/entries/endpoints/api/mappools/_id_/_server.ts.js create mode 100644 .svelte-kit/adapter-node/entries/endpoints/api/mappools/_id_/slots/_server.ts.js create mode 100644 .svelte-kit/adapter-node/entries/endpoints/api/mappools/_id_/slots/_slotId_/_server.ts.js create mode 100644 .svelte-kit/adapter-node/entries/endpoints/api/mappools/_server.ts.js create mode 100644 .svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/_server.ts.js create mode 100644 .svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/lobby/_server.ts.js create mode 100644 .svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/pick/_server.ts.js create mode 100644 .svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/roll/_server.ts.js create mode 100644 .svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/rolling/_server.ts.js create mode 100644 .svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/score/_server.ts.js create mode 100644 .svelte-kit/adapter-node/entries/endpoints/api/matches/_server.ts.js create mode 100644 .svelte-kit/adapter-node/entries/endpoints/api/osu/beatmap/_id_/_server.ts.js create mode 100644 .svelte-kit/adapter-node/entries/endpoints/api/queue/_server.ts.js create mode 100644 .svelte-kit/adapter-node/entries/fallbacks/layout.svelte.js create mode 100644 .svelte-kit/adapter-node/entries/hooks.server.js create mode 100644 .svelte-kit/adapter-node/entries/pages/(app)/_layout.server.ts.js create mode 100644 .svelte-kit/adapter-node/entries/pages/(app)/_layout.svelte.js create mode 100644 .svelte-kit/adapter-node/entries/pages/(app)/_page.server.ts.js create mode 100644 .svelte-kit/adapter-node/entries/pages/(app)/_page.svelte.js create mode 100644 .svelte-kit/adapter-node/entries/pages/(app)/admin/_page.server.ts.js create mode 100644 .svelte-kit/adapter-node/entries/pages/(app)/admin/_page.svelte.js create mode 100644 .svelte-kit/adapter-node/entries/pages/(app)/mappools/_id_/_page.server.ts.js create mode 100644 .svelte-kit/adapter-node/entries/pages/(app)/mappools/_id_/_page.svelte.js create mode 100644 .svelte-kit/adapter-node/entries/pages/(app)/mappools/_page.server.ts.js create mode 100644 .svelte-kit/adapter-node/entries/pages/(app)/mappools/_page.svelte.js create mode 100644 .svelte-kit/adapter-node/entries/pages/(app)/matches/_id_/_page.server.ts.js create mode 100644 .svelte-kit/adapter-node/entries/pages/(app)/matches/_id_/_page.svelte.js create mode 100644 .svelte-kit/adapter-node/entries/pages/(app)/matches/_page.server.ts.js create mode 100644 .svelte-kit/adapter-node/entries/pages/(app)/matches/_page.svelte.js create mode 100644 .svelte-kit/adapter-node/entries/pages/(app)/settings/_page.server.ts.js create mode 100644 .svelte-kit/adapter-node/entries/pages/(app)/settings/_page.svelte.js create mode 100644 .svelte-kit/adapter-node/entries/pages/(app)/teams/_page.server.ts.js create mode 100644 .svelte-kit/adapter-node/entries/pages/(app)/teams/_page.svelte.js create mode 100644 .svelte-kit/adapter-node/entries/pages/_error.svelte.js create mode 100644 .svelte-kit/adapter-node/entries/pages/demo/_page.svelte.js create mode 100644 .svelte-kit/adapter-node/entries/pages/demo/better-auth/_page.server.ts.js create mode 100644 .svelte-kit/adapter-node/entries/pages/demo/better-auth/_page.svelte.js create mode 100644 .svelte-kit/adapter-node/entries/pages/demo/better-auth/login/_page.server.ts.js create mode 100644 .svelte-kit/adapter-node/entries/pages/demo/better-auth/login/_page.svelte.js create mode 100644 .svelte-kit/adapter-node/entries/pages/login/_page.server.ts.js create mode 100644 .svelte-kit/adapter-node/index.js create mode 100644 .svelte-kit/adapter-node/internal.js create mode 100644 .svelte-kit/adapter-node/manifest-full.js create mode 100644 .svelte-kit/adapter-node/manifest.js create mode 100644 .svelte-kit/adapter-node/nodes/0.js create mode 100644 .svelte-kit/adapter-node/nodes/1.js create mode 100644 .svelte-kit/adapter-node/nodes/10.js create mode 100644 .svelte-kit/adapter-node/nodes/11.js create mode 100644 .svelte-kit/adapter-node/nodes/12.js create mode 100644 .svelte-kit/adapter-node/nodes/13.js create mode 100644 .svelte-kit/adapter-node/nodes/14.js create mode 100644 .svelte-kit/adapter-node/nodes/2.js create mode 100644 .svelte-kit/adapter-node/nodes/3.js create mode 100644 .svelte-kit/adapter-node/nodes/4.js create mode 100644 .svelte-kit/adapter-node/nodes/5.js create mode 100644 .svelte-kit/adapter-node/nodes/6.js create mode 100644 .svelte-kit/adapter-node/nodes/7.js create mode 100644 .svelte-kit/adapter-node/nodes/8.js create mode 100644 .svelte-kit/adapter-node/nodes/9.js create mode 100644 .svelte-kit/adapter-node/remote-entry.js create mode 100644 .svelte-kit/ambient.d.ts create mode 100644 .svelte-kit/generated/client-optimized/app.js create mode 100644 .svelte-kit/generated/client-optimized/matchers.js create mode 100644 .svelte-kit/generated/client-optimized/nodes/0.js create mode 100644 .svelte-kit/generated/client-optimized/nodes/1.js create mode 100644 .svelte-kit/generated/client-optimized/nodes/10.js create mode 100644 .svelte-kit/generated/client-optimized/nodes/11.js create mode 100644 .svelte-kit/generated/client-optimized/nodes/12.js create mode 100644 .svelte-kit/generated/client-optimized/nodes/13.js create mode 100644 .svelte-kit/generated/client-optimized/nodes/14.js create mode 100644 .svelte-kit/generated/client-optimized/nodes/2.js create mode 100644 .svelte-kit/generated/client-optimized/nodes/3.js create mode 100644 .svelte-kit/generated/client-optimized/nodes/4.js create mode 100644 .svelte-kit/generated/client-optimized/nodes/5.js create mode 100644 .svelte-kit/generated/client-optimized/nodes/6.js create mode 100644 .svelte-kit/generated/client-optimized/nodes/7.js create mode 100644 .svelte-kit/generated/client-optimized/nodes/8.js create mode 100644 .svelte-kit/generated/client-optimized/nodes/9.js create mode 100644 .svelte-kit/generated/client/app.js create mode 100644 .svelte-kit/generated/client/matchers.js create mode 100644 .svelte-kit/generated/client/nodes/0.js create mode 100644 .svelte-kit/generated/client/nodes/1.js create mode 100644 .svelte-kit/generated/client/nodes/10.js create mode 100644 .svelte-kit/generated/client/nodes/11.js create mode 100644 .svelte-kit/generated/client/nodes/12.js create mode 100644 .svelte-kit/generated/client/nodes/13.js create mode 100644 .svelte-kit/generated/client/nodes/14.js create mode 100644 .svelte-kit/generated/client/nodes/2.js create mode 100644 .svelte-kit/generated/client/nodes/3.js create mode 100644 .svelte-kit/generated/client/nodes/4.js create mode 100644 .svelte-kit/generated/client/nodes/5.js create mode 100644 .svelte-kit/generated/client/nodes/6.js create mode 100644 .svelte-kit/generated/client/nodes/7.js create mode 100644 .svelte-kit/generated/client/nodes/8.js create mode 100644 .svelte-kit/generated/client/nodes/9.js create mode 100644 .svelte-kit/generated/root.js create mode 100644 .svelte-kit/generated/root.svelte create mode 100644 .svelte-kit/generated/server/internal.js create mode 100644 .svelte-kit/non-ambient.d.ts create mode 100644 .svelte-kit/output/client/.vite/manifest.json create mode 100644 .svelte-kit/output/client/_app/immutable/assets/2.Dv2no-8m.css create mode 100644 .svelte-kit/output/client/_app/immutable/chunks/BAocuFgQ.js create mode 100644 .svelte-kit/output/client/_app/immutable/chunks/BLQQas77.js create mode 100644 .svelte-kit/output/client/_app/immutable/chunks/BQKoxf2Q.js create mode 100644 .svelte-kit/output/client/_app/immutable/chunks/BkIq08el.js create mode 100644 .svelte-kit/output/client/_app/immutable/chunks/BnX5ZnVA.js create mode 100644 .svelte-kit/output/client/_app/immutable/chunks/BqOsL1Vv.js create mode 100644 .svelte-kit/output/client/_app/immutable/chunks/BxEwC6Zc.js create mode 100644 .svelte-kit/output/client/_app/immutable/chunks/CAkKRSSs.js create mode 100644 .svelte-kit/output/client/_app/immutable/chunks/CvGSsBh3.js create mode 100644 .svelte-kit/output/client/_app/immutable/chunks/Cy2QBcXt.js create mode 100644 .svelte-kit/output/client/_app/immutable/chunks/CyUoLS3q.js create mode 100644 .svelte-kit/output/client/_app/immutable/chunks/D2SGgx9j.js create mode 100644 .svelte-kit/output/client/_app/immutable/chunks/DAtZQVjv.js create mode 100644 .svelte-kit/output/client/_app/immutable/chunks/DoLu9QLy.js create mode 100644 .svelte-kit/output/client/_app/immutable/chunks/DsnmJJEf.js create mode 100644 .svelte-kit/output/client/_app/immutable/chunks/TpZZa089.js create mode 100644 .svelte-kit/output/client/_app/immutable/chunks/kALFGdUG.js create mode 100644 .svelte-kit/output/client/_app/immutable/entry/app.DL20j9gb.js create mode 100644 .svelte-kit/output/client/_app/immutable/entry/start.Df1GVxyt.js create mode 100644 .svelte-kit/output/client/_app/immutable/nodes/0.9C686m9W.js create mode 100644 .svelte-kit/output/client/_app/immutable/nodes/1.RyK1bdTz.js create mode 100644 .svelte-kit/output/client/_app/immutable/nodes/10.BPlEN6_G.js create mode 100644 .svelte-kit/output/client/_app/immutable/nodes/11.DR1Vz7m0.js create mode 100644 .svelte-kit/output/client/_app/immutable/nodes/12.C9UZWAjJ.js create mode 100644 .svelte-kit/output/client/_app/immutable/nodes/13.CyZ4e6yK.js create mode 100644 .svelte-kit/output/client/_app/immutable/nodes/2.BsR2_q_w.js create mode 100644 .svelte-kit/output/client/_app/immutable/nodes/3.CMuy9Bx3.js create mode 100644 .svelte-kit/output/client/_app/immutable/nodes/4.BdC-uDW-.js create mode 100644 .svelte-kit/output/client/_app/immutable/nodes/5.CyqZcxti.js create mode 100644 .svelte-kit/output/client/_app/immutable/nodes/6.CEe0czaO.js create mode 100644 .svelte-kit/output/client/_app/immutable/nodes/7._nuD3LlN.js create mode 100644 .svelte-kit/output/client/_app/immutable/nodes/8.CkbqikZq.js create mode 100644 .svelte-kit/output/client/_app/immutable/nodes/9.BTBc_Eli.js create mode 100644 .svelte-kit/output/client/_app/version.json create mode 100644 .svelte-kit/output/client/android-chrome-192x192.png create mode 100644 .svelte-kit/output/client/android-chrome-512x512.png create mode 100644 .svelte-kit/output/client/apple-touch-icon.png create mode 100644 .svelte-kit/output/client/favicon-16x16.png create mode 100644 .svelte-kit/output/client/favicon-32x32.png create mode 100644 .svelte-kit/output/client/favicon.ico create mode 100644 .svelte-kit/output/client/robots.txt create mode 100644 .svelte-kit/output/client/site.webmanifest create mode 100644 .svelte-kit/output/server/.vite/manifest.json create mode 100644 .svelte-kit/output/server/_app/immutable/assets/_layout.Dv2no-8m.css create mode 100644 .svelte-kit/output/server/chunks/api.js create mode 100644 .svelte-kit/output/server/chunks/auth.js create mode 100644 .svelte-kit/output/server/chunks/bun-sqlite-dialect.js create mode 100644 .svelte-kit/output/server/chunks/engine.js create mode 100644 .svelte-kit/output/server/chunks/environment.js create mode 100644 .svelte-kit/output/server/chunks/exports.js create mode 100644 .svelte-kit/output/server/chunks/false.js create mode 100644 .svelte-kit/output/server/chunks/index.js create mode 100644 .svelte-kit/output/server/chunks/index2.js create mode 100644 .svelte-kit/output/server/chunks/index3.js create mode 100644 .svelte-kit/output/server/chunks/index4.js create mode 100644 .svelte-kit/output/server/chunks/index5.js create mode 100644 .svelte-kit/output/server/chunks/index6.js create mode 100644 .svelte-kit/output/server/chunks/internal.js create mode 100644 .svelte-kit/output/server/chunks/node-sqlite-dialect.js create mode 100644 .svelte-kit/output/server/chunks/orchestrator.js create mode 100644 .svelte-kit/output/server/chunks/query.js create mode 100644 .svelte-kit/output/server/chunks/root.js create mode 100644 .svelte-kit/output/server/chunks/routing.js create mode 100644 .svelte-kit/output/server/chunks/server.js create mode 100644 .svelte-kit/output/server/chunks/shared-server.js create mode 100644 .svelte-kit/output/server/chunks/shared.js create mode 100644 .svelte-kit/output/server/chunks/state.svelte.js create mode 100644 .svelte-kit/output/server/chunks/url.js create mode 100644 .svelte-kit/output/server/chunks/utils.js create mode 100644 .svelte-kit/output/server/entries/endpoints/api/health/_server.ts.js create mode 100644 .svelte-kit/output/server/entries/endpoints/api/mappools/_id_/_server.ts.js create mode 100644 .svelte-kit/output/server/entries/endpoints/api/mappools/_id_/slots/_server.ts.js create mode 100644 .svelte-kit/output/server/entries/endpoints/api/mappools/_id_/slots/_slotId_/_server.ts.js create mode 100644 .svelte-kit/output/server/entries/endpoints/api/mappools/_server.ts.js create mode 100644 .svelte-kit/output/server/entries/endpoints/api/matches/_id_/_server.ts.js create mode 100644 .svelte-kit/output/server/entries/endpoints/api/matches/_id_/lobby/_server.ts.js create mode 100644 .svelte-kit/output/server/entries/endpoints/api/matches/_id_/pick/_server.ts.js create mode 100644 .svelte-kit/output/server/entries/endpoints/api/matches/_id_/roll/_server.ts.js create mode 100644 .svelte-kit/output/server/entries/endpoints/api/matches/_id_/rolling/_server.ts.js create mode 100644 .svelte-kit/output/server/entries/endpoints/api/matches/_id_/score/_server.ts.js create mode 100644 .svelte-kit/output/server/entries/endpoints/api/matches/_server.ts.js create mode 100644 .svelte-kit/output/server/entries/endpoints/api/osu/beatmap/_id_/_server.ts.js create mode 100644 .svelte-kit/output/server/entries/endpoints/api/queue/_server.ts.js create mode 100644 .svelte-kit/output/server/entries/fallbacks/layout.svelte.js create mode 100644 .svelte-kit/output/server/entries/hooks.server.js create mode 100644 .svelte-kit/output/server/entries/pages/(app)/_layout.server.ts.js create mode 100644 .svelte-kit/output/server/entries/pages/(app)/_layout.svelte.js create mode 100644 .svelte-kit/output/server/entries/pages/(app)/_page.server.ts.js create mode 100644 .svelte-kit/output/server/entries/pages/(app)/_page.svelte.js create mode 100644 .svelte-kit/output/server/entries/pages/(app)/admin/_page.server.ts.js create mode 100644 .svelte-kit/output/server/entries/pages/(app)/admin/_page.svelte.js create mode 100644 .svelte-kit/output/server/entries/pages/(app)/mappools/_id_/_page.server.ts.js create mode 100644 .svelte-kit/output/server/entries/pages/(app)/mappools/_id_/_page.svelte.js create mode 100644 .svelte-kit/output/server/entries/pages/(app)/mappools/_page.server.ts.js create mode 100644 .svelte-kit/output/server/entries/pages/(app)/mappools/_page.svelte.js create mode 100644 .svelte-kit/output/server/entries/pages/(app)/matches/_id_/_page.server.ts.js create mode 100644 .svelte-kit/output/server/entries/pages/(app)/matches/_id_/_page.svelte.js create mode 100644 .svelte-kit/output/server/entries/pages/(app)/matches/_page.server.ts.js create mode 100644 .svelte-kit/output/server/entries/pages/(app)/matches/_page.svelte.js create mode 100644 .svelte-kit/output/server/entries/pages/(app)/settings/_page.server.ts.js create mode 100644 .svelte-kit/output/server/entries/pages/(app)/settings/_page.svelte.js create mode 100644 .svelte-kit/output/server/entries/pages/(app)/teams/_page.server.ts.js create mode 100644 .svelte-kit/output/server/entries/pages/(app)/teams/_page.svelte.js create mode 100644 .svelte-kit/output/server/entries/pages/_error.svelte.js create mode 100644 .svelte-kit/output/server/entries/pages/demo/_page.svelte.js create mode 100644 .svelte-kit/output/server/entries/pages/demo/better-auth/_page.server.ts.js create mode 100644 .svelte-kit/output/server/entries/pages/demo/better-auth/_page.svelte.js create mode 100644 .svelte-kit/output/server/entries/pages/demo/better-auth/login/_page.server.ts.js create mode 100644 .svelte-kit/output/server/entries/pages/demo/better-auth/login/_page.svelte.js create mode 100644 .svelte-kit/output/server/entries/pages/login/_page.server.ts.js create mode 100644 .svelte-kit/output/server/index.js create mode 100644 .svelte-kit/output/server/internal.js create mode 100644 .svelte-kit/output/server/manifest-full.js create mode 100644 .svelte-kit/output/server/manifest.js create mode 100644 .svelte-kit/output/server/nodes/0.js create mode 100644 .svelte-kit/output/server/nodes/1.js create mode 100644 .svelte-kit/output/server/nodes/10.js create mode 100644 .svelte-kit/output/server/nodes/11.js create mode 100644 .svelte-kit/output/server/nodes/12.js create mode 100644 .svelte-kit/output/server/nodes/13.js create mode 100644 .svelte-kit/output/server/nodes/14.js create mode 100644 .svelte-kit/output/server/nodes/2.js create mode 100644 .svelte-kit/output/server/nodes/3.js create mode 100644 .svelte-kit/output/server/nodes/4.js create mode 100644 .svelte-kit/output/server/nodes/5.js create mode 100644 .svelte-kit/output/server/nodes/6.js create mode 100644 .svelte-kit/output/server/nodes/7.js create mode 100644 .svelte-kit/output/server/nodes/8.js create mode 100644 .svelte-kit/output/server/nodes/9.js create mode 100644 .svelte-kit/output/server/remote-entry.js create mode 100644 .svelte-kit/tsconfig.json create mode 100644 .svelte-kit/types/route_meta_data.json create mode 100644 .svelte-kit/types/src/routes/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/(app)/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/(app)/admin/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/(app)/admin/proxy+page.server.ts create mode 100644 .svelte-kit/types/src/routes/(app)/mappools/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/(app)/mappools/[id]/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/(app)/mappools/[id]/proxy+page.server.ts create mode 100644 .svelte-kit/types/src/routes/(app)/mappools/proxy+page.server.ts create mode 100644 .svelte-kit/types/src/routes/(app)/matches/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/(app)/matches/[id]/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/(app)/matches/[id]/proxy+page.server.ts create mode 100644 .svelte-kit/types/src/routes/(app)/matches/proxy+page.server.ts create mode 100644 .svelte-kit/types/src/routes/(app)/proxy+layout.server.ts create mode 100644 .svelte-kit/types/src/routes/(app)/proxy+page.server.ts create mode 100644 .svelte-kit/types/src/routes/(app)/settings/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/(app)/settings/proxy+page.server.ts create mode 100644 .svelte-kit/types/src/routes/(app)/teams/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/(app)/teams/proxy+page.server.ts create mode 100644 .svelte-kit/types/src/routes/api/health/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/api/mappools/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/api/mappools/[id]/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/api/mappools/[id]/slots/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/api/mappools/[id]/slots/[slotId]/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/api/matches/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/api/matches/[id]/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/api/matches/[id]/lobby/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/api/matches/[id]/pick/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/api/matches/[id]/roll/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/api/matches/[id]/rolling/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/api/matches/[id]/score/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/api/osu/beatmap/[id]/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/api/queue/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/demo/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/demo/better-auth/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/demo/better-auth/login/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/demo/better-auth/login/proxy+page.server.ts create mode 100644 .svelte-kit/types/src/routes/demo/better-auth/proxy+page.server.ts create mode 100644 .svelte-kit/types/src/routes/login/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/login/proxy+page.server.ts create mode 100644 build/client/_app/immutable/assets/2.Dv2no-8m.css create mode 100644 build/client/_app/immutable/assets/2.Dv2no-8m.css.br create mode 100644 build/client/_app/immutable/assets/2.Dv2no-8m.css.gz create mode 100644 build/client/_app/immutable/chunks/BAocuFgQ.js create mode 100644 build/client/_app/immutable/chunks/BAocuFgQ.js.br create mode 100644 build/client/_app/immutable/chunks/BAocuFgQ.js.gz create mode 100644 build/client/_app/immutable/chunks/BLQQas77.js create mode 100644 build/client/_app/immutable/chunks/BLQQas77.js.br create mode 100644 build/client/_app/immutable/chunks/BLQQas77.js.gz create mode 100644 build/client/_app/immutable/chunks/BQKoxf2Q.js create mode 100644 build/client/_app/immutable/chunks/BQKoxf2Q.js.br create mode 100644 build/client/_app/immutable/chunks/BQKoxf2Q.js.gz create mode 100644 build/client/_app/immutable/chunks/BkIq08el.js create mode 100644 build/client/_app/immutable/chunks/BkIq08el.js.br create mode 100644 build/client/_app/immutable/chunks/BkIq08el.js.gz create mode 100644 build/client/_app/immutable/chunks/BnX5ZnVA.js create mode 100644 build/client/_app/immutable/chunks/BnX5ZnVA.js.br create mode 100644 build/client/_app/immutable/chunks/BnX5ZnVA.js.gz create mode 100644 build/client/_app/immutable/chunks/BqOsL1Vv.js create mode 100644 build/client/_app/immutable/chunks/BqOsL1Vv.js.br create mode 100644 build/client/_app/immutable/chunks/BqOsL1Vv.js.gz create mode 100644 build/client/_app/immutable/chunks/BxEwC6Zc.js create mode 100644 build/client/_app/immutable/chunks/BxEwC6Zc.js.br create mode 100644 build/client/_app/immutable/chunks/BxEwC6Zc.js.gz create mode 100644 build/client/_app/immutable/chunks/CAkKRSSs.js create mode 100644 build/client/_app/immutable/chunks/CAkKRSSs.js.br create mode 100644 build/client/_app/immutable/chunks/CAkKRSSs.js.gz create mode 100644 build/client/_app/immutable/chunks/CvGSsBh3.js create mode 100644 build/client/_app/immutable/chunks/CvGSsBh3.js.br create mode 100644 build/client/_app/immutable/chunks/CvGSsBh3.js.gz create mode 100644 build/client/_app/immutable/chunks/Cy2QBcXt.js create mode 100644 build/client/_app/immutable/chunks/Cy2QBcXt.js.br create mode 100644 build/client/_app/immutable/chunks/Cy2QBcXt.js.gz create mode 100644 build/client/_app/immutable/chunks/CyUoLS3q.js create mode 100644 build/client/_app/immutable/chunks/CyUoLS3q.js.br create mode 100644 build/client/_app/immutable/chunks/CyUoLS3q.js.gz create mode 100644 build/client/_app/immutable/chunks/D2SGgx9j.js create mode 100644 build/client/_app/immutable/chunks/D2SGgx9j.js.br create mode 100644 build/client/_app/immutable/chunks/D2SGgx9j.js.gz create mode 100644 build/client/_app/immutable/chunks/DAtZQVjv.js create mode 100644 build/client/_app/immutable/chunks/DAtZQVjv.js.br create mode 100644 build/client/_app/immutable/chunks/DAtZQVjv.js.gz create mode 100644 build/client/_app/immutable/chunks/DoLu9QLy.js create mode 100644 build/client/_app/immutable/chunks/DoLu9QLy.js.br create mode 100644 build/client/_app/immutable/chunks/DoLu9QLy.js.gz create mode 100644 build/client/_app/immutable/chunks/DsnmJJEf.js create mode 100644 build/client/_app/immutable/chunks/DsnmJJEf.js.br create mode 100644 build/client/_app/immutable/chunks/DsnmJJEf.js.gz create mode 100644 build/client/_app/immutable/chunks/TpZZa089.js create mode 100644 build/client/_app/immutable/chunks/TpZZa089.js.br create mode 100644 build/client/_app/immutable/chunks/TpZZa089.js.gz create mode 100644 build/client/_app/immutable/chunks/kALFGdUG.js create mode 100644 build/client/_app/immutable/chunks/kALFGdUG.js.br create mode 100644 build/client/_app/immutable/chunks/kALFGdUG.js.gz create mode 100644 build/client/_app/immutable/entry/app.DL20j9gb.js create mode 100644 build/client/_app/immutable/entry/app.DL20j9gb.js.br create mode 100644 build/client/_app/immutable/entry/app.DL20j9gb.js.gz create mode 100644 build/client/_app/immutable/entry/start.Df1GVxyt.js create mode 100644 build/client/_app/immutable/entry/start.Df1GVxyt.js.br create mode 100644 build/client/_app/immutable/entry/start.Df1GVxyt.js.gz create mode 100644 build/client/_app/immutable/nodes/0.9C686m9W.js create mode 100644 build/client/_app/immutable/nodes/0.9C686m9W.js.br create mode 100644 build/client/_app/immutable/nodes/0.9C686m9W.js.gz create mode 100644 build/client/_app/immutable/nodes/1.RyK1bdTz.js create mode 100644 build/client/_app/immutable/nodes/1.RyK1bdTz.js.br create mode 100644 build/client/_app/immutable/nodes/1.RyK1bdTz.js.gz create mode 100644 build/client/_app/immutable/nodes/10.BPlEN6_G.js create mode 100644 build/client/_app/immutable/nodes/10.BPlEN6_G.js.br create mode 100644 build/client/_app/immutable/nodes/10.BPlEN6_G.js.gz create mode 100644 build/client/_app/immutable/nodes/11.DR1Vz7m0.js create mode 100644 build/client/_app/immutable/nodes/11.DR1Vz7m0.js.br create mode 100644 build/client/_app/immutable/nodes/11.DR1Vz7m0.js.gz create mode 100644 build/client/_app/immutable/nodes/12.C9UZWAjJ.js create mode 100644 build/client/_app/immutable/nodes/12.C9UZWAjJ.js.br create mode 100644 build/client/_app/immutable/nodes/12.C9UZWAjJ.js.gz create mode 100644 build/client/_app/immutable/nodes/13.CyZ4e6yK.js create mode 100644 build/client/_app/immutable/nodes/13.CyZ4e6yK.js.br create mode 100644 build/client/_app/immutable/nodes/13.CyZ4e6yK.js.gz create mode 100644 build/client/_app/immutable/nodes/2.BsR2_q_w.js create mode 100644 build/client/_app/immutable/nodes/2.BsR2_q_w.js.br create mode 100644 build/client/_app/immutable/nodes/2.BsR2_q_w.js.gz create mode 100644 build/client/_app/immutable/nodes/3.CMuy9Bx3.js create mode 100644 build/client/_app/immutable/nodes/3.CMuy9Bx3.js.br create mode 100644 build/client/_app/immutable/nodes/3.CMuy9Bx3.js.gz create mode 100644 build/client/_app/immutable/nodes/4.BdC-uDW-.js create mode 100644 build/client/_app/immutable/nodes/4.BdC-uDW-.js.br create mode 100644 build/client/_app/immutable/nodes/4.BdC-uDW-.js.gz create mode 100644 build/client/_app/immutable/nodes/5.CyqZcxti.js create mode 100644 build/client/_app/immutable/nodes/5.CyqZcxti.js.br create mode 100644 build/client/_app/immutable/nodes/5.CyqZcxti.js.gz create mode 100644 build/client/_app/immutable/nodes/6.CEe0czaO.js create mode 100644 build/client/_app/immutable/nodes/6.CEe0czaO.js.br create mode 100644 build/client/_app/immutable/nodes/6.CEe0czaO.js.gz create mode 100644 build/client/_app/immutable/nodes/7._nuD3LlN.js create mode 100644 build/client/_app/immutable/nodes/7._nuD3LlN.js.br create mode 100644 build/client/_app/immutable/nodes/7._nuD3LlN.js.gz create mode 100644 build/client/_app/immutable/nodes/8.CkbqikZq.js create mode 100644 build/client/_app/immutable/nodes/8.CkbqikZq.js.br create mode 100644 build/client/_app/immutable/nodes/8.CkbqikZq.js.gz create mode 100644 build/client/_app/immutable/nodes/9.BTBc_Eli.js create mode 100644 build/client/_app/immutable/nodes/9.BTBc_Eli.js.br create mode 100644 build/client/_app/immutable/nodes/9.BTBc_Eli.js.gz create mode 100644 build/client/_app/version.json create mode 100644 build/client/_app/version.json.br create mode 100644 build/client/_app/version.json.gz create mode 100644 build/client/android-chrome-192x192.png create mode 100644 build/client/android-chrome-512x512.png create mode 100644 build/client/apple-touch-icon.png create mode 100644 build/client/favicon-16x16.png create mode 100644 build/client/favicon-32x32.png create mode 100644 build/client/favicon.ico create mode 100644 build/client/robots.txt create mode 100644 build/client/robots.txt.br create mode 100644 build/client/robots.txt.gz create mode 100644 build/client/site.webmanifest create mode 100644 build/env.js create mode 100644 build/handler.js create mode 100644 build/index.js create mode 100644 build/server/chunks/0-BWa0n_wG.js create mode 100644 build/server/chunks/0-BWa0n_wG.js.map create mode 100644 build/server/chunks/1-dOPiiXyK.js create mode 100644 build/server/chunks/1-dOPiiXyK.js.map create mode 100644 build/server/chunks/10-BGqcbnOp.js create mode 100644 build/server/chunks/10-BGqcbnOp.js.map create mode 100644 build/server/chunks/11-DB2oh-6z.js create mode 100644 build/server/chunks/11-DB2oh-6z.js.map create mode 100644 build/server/chunks/12-3YbOOB0i.js create mode 100644 build/server/chunks/12-3YbOOB0i.js.map create mode 100644 build/server/chunks/13-CyOLqwjC.js create mode 100644 build/server/chunks/13-CyOLqwjC.js.map create mode 100644 build/server/chunks/14-BMPOArNY.js create mode 100644 build/server/chunks/14-BMPOArNY.js.map create mode 100644 build/server/chunks/2-BiADR-CH.js create mode 100644 build/server/chunks/2-BiADR-CH.js.map create mode 100644 build/server/chunks/3-BPD8edaL.js create mode 100644 build/server/chunks/3-BPD8edaL.js.map create mode 100644 build/server/chunks/4-CQssXWUd.js create mode 100644 build/server/chunks/4-CQssXWUd.js.map create mode 100644 build/server/chunks/5-Dk6CJpPs.js create mode 100644 build/server/chunks/5-Dk6CJpPs.js.map create mode 100644 build/server/chunks/6-CW5Wcf44.js create mode 100644 build/server/chunks/6-CW5Wcf44.js.map create mode 100644 build/server/chunks/7-DLfylrWu.js create mode 100644 build/server/chunks/7-DLfylrWu.js.map create mode 100644 build/server/chunks/8-Cct4CuMl.js create mode 100644 build/server/chunks/8-Cct4CuMl.js.map create mode 100644 build/server/chunks/9-DztSgTEC.js create mode 100644 build/server/chunks/9-DztSgTEC.js.map create mode 100644 build/server/chunks/_error.svelte-Szt4-wKI.js create mode 100644 build/server/chunks/_error.svelte-Szt4-wKI.js.map create mode 100644 build/server/chunks/_layout.svelte-BV7ZtoED.js create mode 100644 build/server/chunks/_layout.svelte-BV7ZtoED.js.map create mode 100644 build/server/chunks/_page.svelte-6xWa24o9.js create mode 100644 build/server/chunks/_page.svelte-6xWa24o9.js.map create mode 100644 build/server/chunks/_page.svelte-B33-skqO.js create mode 100644 build/server/chunks/_page.svelte-B33-skqO.js.map create mode 100644 build/server/chunks/_page.svelte-Be6BiSzg.js create mode 100644 build/server/chunks/_page.svelte-Be6BiSzg.js.map create mode 100644 build/server/chunks/_page.svelte-Bj4oURhW.js create mode 100644 build/server/chunks/_page.svelte-Bj4oURhW.js.map create mode 100644 build/server/chunks/_page.svelte-C-71W7Xe.js create mode 100644 build/server/chunks/_page.svelte-C-71W7Xe.js.map create mode 100644 build/server/chunks/_page.svelte-C5eWfXqa.js create mode 100644 build/server/chunks/_page.svelte-C5eWfXqa.js.map create mode 100644 build/server/chunks/_page.svelte-Ctzd-tuM.js create mode 100644 build/server/chunks/_page.svelte-Ctzd-tuM.js.map create mode 100644 build/server/chunks/_page.svelte-D23V0tpa.js create mode 100644 build/server/chunks/_page.svelte-D23V0tpa.js.map create mode 100644 build/server/chunks/_page.svelte-G6sWOX7O.js create mode 100644 build/server/chunks/_page.svelte-G6sWOX7O.js.map create mode 100644 build/server/chunks/_page.svelte-ad4cZnqC.js create mode 100644 build/server/chunks/_page.svelte-ad4cZnqC.js.map create mode 100644 build/server/chunks/_page.svelte-ijSwFWFX.js create mode 100644 build/server/chunks/_page.svelte-ijSwFWFX.js.map create mode 100644 build/server/chunks/_server.ts-BEoJR5yQ.js create mode 100644 build/server/chunks/_server.ts-BEoJR5yQ.js.map create mode 100644 build/server/chunks/_server.ts-BKWDSPwT.js create mode 100644 build/server/chunks/_server.ts-BKWDSPwT.js.map create mode 100644 build/server/chunks/_server.ts-C5pGCspz.js create mode 100644 build/server/chunks/_server.ts-C5pGCspz.js.map create mode 100644 build/server/chunks/_server.ts-CYhG9EuN.js create mode 100644 build/server/chunks/_server.ts-CYhG9EuN.js.map create mode 100644 build/server/chunks/_server.ts-CgeuSTTA.js create mode 100644 build/server/chunks/_server.ts-CgeuSTTA.js.map create mode 100644 build/server/chunks/_server.ts-Chr3sGwY.js create mode 100644 build/server/chunks/_server.ts-Chr3sGwY.js.map create mode 100644 build/server/chunks/_server.ts-CknVZIWY.js create mode 100644 build/server/chunks/_server.ts-CknVZIWY.js.map create mode 100644 build/server/chunks/_server.ts-Cp6RS2Xl.js create mode 100644 build/server/chunks/_server.ts-Cp6RS2Xl.js.map create mode 100644 build/server/chunks/_server.ts-DLwKwHxp.js create mode 100644 build/server/chunks/_server.ts-DLwKwHxp.js.map create mode 100644 build/server/chunks/_server.ts-DRKvzZ51.js create mode 100644 build/server/chunks/_server.ts-DRKvzZ51.js.map create mode 100644 build/server/chunks/_server.ts-KSG0NbEr.js create mode 100644 build/server/chunks/_server.ts-KSG0NbEr.js.map create mode 100644 build/server/chunks/_server.ts-M_0oeLSe.js create mode 100644 build/server/chunks/_server.ts-M_0oeLSe.js.map create mode 100644 build/server/chunks/_server.ts-kIjYmsyw.js create mode 100644 build/server/chunks/_server.ts-kIjYmsyw.js.map create mode 100644 build/server/chunks/_server.ts-wwm7Wb6_.js create mode 100644 build/server/chunks/_server.ts-wwm7Wb6_.js.map create mode 100644 build/server/chunks/aggregate-CrXc04Dg.js create mode 100644 build/server/chunks/aggregate-CrXc04Dg.js.map create mode 100644 build/server/chunks/api-DYV1cRWY.js create mode 100644 build/server/chunks/api-DYV1cRWY.js.map create mode 100644 build/server/chunks/auth-CAP7sZek.js create mode 100644 build/server/chunks/auth-CAP7sZek.js.map create mode 100644 build/server/chunks/bun-sqlite-dialect-C-rWaXX0.js create mode 100644 build/server/chunks/bun-sqlite-dialect-C-rWaXX0.js.map create mode 100644 build/server/chunks/engine-DiCmv1C-.js create mode 100644 build/server/chunks/engine-DiCmv1C-.js.map create mode 100644 build/server/chunks/exports-B5ORJhfK.js create mode 100644 build/server/chunks/exports-B5ORJhfK.js.map create mode 100644 build/server/chunks/hooks.server-g13gcBbX.js create mode 100644 build/server/chunks/hooks.server-g13gcBbX.js.map create mode 100644 build/server/chunks/index-B2LGyy1l.js create mode 100644 build/server/chunks/index-B2LGyy1l.js.map create mode 100644 build/server/chunks/index-MqY7A75_.js create mode 100644 build/server/chunks/index-MqY7A75_.js.map create mode 100644 build/server/chunks/index2-B7hVh_Qf.js create mode 100644 build/server/chunks/index2-B7hVh_Qf.js.map create mode 100644 build/server/chunks/index3-C4geC3K_.js create mode 100644 build/server/chunks/index3-C4geC3K_.js.map create mode 100644 build/server/chunks/index4-B8FtU3M-.js create mode 100644 build/server/chunks/index4-B8FtU3M-.js.map create mode 100644 build/server/chunks/index5-f2WMNNiy.js create mode 100644 build/server/chunks/index5-f2WMNNiy.js.map create mode 100644 build/server/chunks/index6-aBT-vm5N.js create mode 100644 build/server/chunks/index6-aBT-vm5N.js.map create mode 100644 build/server/chunks/layout.svelte-UxsTmhKc.js create mode 100644 build/server/chunks/layout.svelte-UxsTmhKc.js.map create mode 100644 build/server/chunks/node-sqlite-dialect-CyfGAEpZ.js create mode 100644 build/server/chunks/node-sqlite-dialect-CyfGAEpZ.js.map create mode 100644 build/server/chunks/orchestrator-BMt7lT0G.js create mode 100644 build/server/chunks/orchestrator-BMt7lT0G.js.map create mode 100644 build/server/chunks/root-D12ma0No.js create mode 100644 build/server/chunks/root-D12ma0No.js.map create mode 100644 build/server/chunks/routing-NqiTWnxU.js create mode 100644 build/server/chunks/routing-NqiTWnxU.js.map create mode 100644 build/server/chunks/shared-DWC9PG0H.js create mode 100644 build/server/chunks/shared-DWC9PG0H.js.map create mode 100644 build/server/chunks/shared-server-DaWdgxVh.js create mode 100644 build/server/chunks/shared-server-DaWdgxVh.js.map create mode 100644 build/server/chunks/state.svelte-DvHRBIfo.js create mode 100644 build/server/chunks/state.svelte-DvHRBIfo.js.map create mode 100644 build/server/chunks/utils-D_bK1W85.js create mode 100644 build/server/chunks/utils-D_bK1W85.js.map create mode 100644 build/server/index.js create mode 100644 build/server/index.js.map create mode 100644 build/server/manifest.js create mode 100644 build/server/manifest.js.map create mode 100644 build/shims.js diff --git a/.env b/.env new file mode 100644 index 0000000..976b6b1 --- /dev/null +++ b/.env @@ -0,0 +1,14 @@ +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 new file mode 100644 index 0000000..36de7fb --- /dev/null +++ b/.svelte-kit/adapter-node/.vite/manifest.json @@ -0,0 +1,661 @@ +{ + ".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 new file mode 100644 index 0000000..d32e9ae --- /dev/null +++ b/.svelte-kit/adapter-node/_app/immutable/assets/_layout.Dv2no-8m.css @@ -0,0 +1 @@ +@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 new file mode 100644 index 0000000..5e6cc8c --- /dev/null +++ b/.svelte-kit/adapter-node/chunks/api.js @@ -0,0 +1,69 @@ +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 new file mode 100644 index 0000000..588593c --- /dev/null +++ b/.svelte-kit/adapter-node/chunks/auth.js @@ -0,0 +1,7983 @@ +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 new file mode 100644 index 0000000..6fe94c6 --- /dev/null +++ b/.svelte-kit/adapter-node/chunks/bun-sqlite-dialect.js @@ -0,0 +1,155 @@ +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 new file mode 100644 index 0000000..f6bafe4 --- /dev/null +++ b/.svelte-kit/adapter-node/chunks/engine.js @@ -0,0 +1,350 @@ +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 new file mode 100644 index 0000000..d81356b --- /dev/null +++ b/.svelte-kit/adapter-node/chunks/environment.js @@ -0,0 +1,14 @@ +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 new file mode 100644 index 0000000..441ec91 --- /dev/null +++ b/.svelte-kit/adapter-node/chunks/exports.js @@ -0,0 +1,70 @@ +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 new file mode 100644 index 0000000..f3effd6 --- /dev/null +++ b/.svelte-kit/adapter-node/chunks/false.js @@ -0,0 +1,4 @@ +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 new file mode 100644 index 0000000..14b637b --- /dev/null +++ b/.svelte-kit/adapter-node/chunks/index.js @@ -0,0 +1,60 @@ +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 new file mode 100644 index 0000000..2c507a6 --- /dev/null +++ b/.svelte-kit/adapter-node/chunks/index2.js @@ -0,0 +1,302 @@ +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 new file mode 100644 index 0000000..20b173b --- /dev/null +++ b/.svelte-kit/adapter-node/chunks/index3.js @@ -0,0 +1,1249 @@ +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 new file mode 100644 index 0000000..2ae44a6 --- /dev/null +++ b/.svelte-kit/adapter-node/chunks/index4.js @@ -0,0 +1,47 @@ +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 new file mode 100644 index 0000000..5a5bcdc --- /dev/null +++ b/.svelte-kit/adapter-node/chunks/index5.js @@ -0,0 +1,224 @@ +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 new file mode 100644 index 0000000..f55374c --- /dev/null +++ b/.svelte-kit/adapter-node/chunks/index6.js @@ -0,0 +1,307 @@ +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 new file mode 100644 index 0000000..55b3eeb --- /dev/null +++ b/.svelte-kit/adapter-node/chunks/internal.js @@ -0,0 +1,127 @@ +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 new file mode 100644 index 0000000..68f03bc --- /dev/null +++ b/.svelte-kit/adapter-node/chunks/node-sqlite-dialect.js @@ -0,0 +1,155 @@ +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 new file mode 100644 index 0000000..da259e9 --- /dev/null +++ b/.svelte-kit/adapter-node/chunks/orchestrator.js @@ -0,0 +1,448 @@ +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 new file mode 100644 index 0000000..a14a6fa --- /dev/null +++ b/.svelte-kit/adapter-node/chunks/query.js @@ -0,0 +1,258 @@ +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 new file mode 100644 index 0000000..c678a5c --- /dev/null +++ b/.svelte-kit/adapter-node/chunks/root.js @@ -0,0 +1,2713 @@ +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 new file mode 100644 index 0000000..11c0ffa --- /dev/null +++ b/.svelte-kit/adapter-node/chunks/routing.js @@ -0,0 +1,85 @@ +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 new file mode 100644 index 0000000..bf7eaa6 --- /dev/null +++ b/.svelte-kit/adapter-node/chunks/server.js @@ -0,0 +1,27 @@ +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 new file mode 100644 index 0000000..4fa13e6 --- /dev/null +++ b/.svelte-kit/adapter-node/chunks/shared-server.js @@ -0,0 +1,14 @@ +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 new file mode 100644 index 0000000..9162124 --- /dev/null +++ b/.svelte-kit/adapter-node/chunks/shared.js @@ -0,0 +1,789 @@ +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 new file mode 100644 index 0000000..9cd4558 --- /dev/null +++ b/.svelte-kit/adapter-node/chunks/state.svelte.js @@ -0,0 +1,18 @@ +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 new file mode 100644 index 0000000..2ba2c18 --- /dev/null +++ b/.svelte-kit/adapter-node/chunks/url.js @@ -0,0 +1,106 @@ +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 new file mode 100644 index 0000000..78e5bde --- /dev/null +++ b/.svelte-kit/adapter-node/chunks/utils.js @@ -0,0 +1,43 @@ +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 new file mode 100644 index 0000000..203529d --- /dev/null +++ b/.svelte-kit/adapter-node/entries/endpoints/api/health/_server.ts.js @@ -0,0 +1,25 @@ +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 new file mode 100644 index 0000000..4d6b270 --- /dev/null +++ b/.svelte-kit/adapter-node/entries/endpoints/api/mappools/_id_/_server.ts.js @@ -0,0 +1,24 @@ +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 new file mode 100644 index 0000000..b61da5c --- /dev/null +++ b/.svelte-kit/adapter-node/entries/endpoints/api/mappools/_id_/slots/_server.ts.js @@ -0,0 +1,27 @@ +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 new file mode 100644 index 0000000..c77f59a --- /dev/null +++ b/.svelte-kit/adapter-node/entries/endpoints/api/mappools/_id_/slots/_slotId_/_server.ts.js @@ -0,0 +1,11 @@ +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 new file mode 100644 index 0000000..bf904be --- /dev/null +++ b/.svelte-kit/adapter-node/entries/endpoints/api/mappools/_server.ts.js @@ -0,0 +1,23 @@ +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 new file mode 100644 index 0000000..b383e98 --- /dev/null +++ b/.svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/_server.ts.js @@ -0,0 +1,24 @@ +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 new file mode 100644 index 0000000..35ed7aa --- /dev/null +++ b/.svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/lobby/_server.ts.js @@ -0,0 +1,15 @@ +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 new file mode 100644 index 0000000..a655c49 --- /dev/null +++ b/.svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/pick/_server.ts.js @@ -0,0 +1,18 @@ +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 new file mode 100644 index 0000000..21f102e --- /dev/null +++ b/.svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/roll/_server.ts.js @@ -0,0 +1,18 @@ +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 new file mode 100644 index 0000000..e5cc1e3 --- /dev/null +++ b/.svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/rolling/_server.ts.js @@ -0,0 +1,14 @@ +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 new file mode 100644 index 0000000..cd031cb --- /dev/null +++ b/.svelte-kit/adapter-node/entries/endpoints/api/matches/_id_/score/_server.ts.js @@ -0,0 +1,18 @@ +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 new file mode 100644 index 0000000..3732a25 --- /dev/null +++ b/.svelte-kit/adapter-node/entries/endpoints/api/matches/_server.ts.js @@ -0,0 +1,37 @@ +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 new file mode 100644 index 0000000..c258470 --- /dev/null +++ b/.svelte-kit/adapter-node/entries/endpoints/api/osu/beatmap/_id_/_server.ts.js @@ -0,0 +1,14 @@ +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 new file mode 100644 index 0000000..d6b0508 --- /dev/null +++ b/.svelte-kit/adapter-node/entries/endpoints/api/queue/_server.ts.js @@ -0,0 +1,36 @@ +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 new file mode 100644 index 0000000..c3792df --- /dev/null +++ b/.svelte-kit/adapter-node/entries/fallbacks/layout.svelte.js @@ -0,0 +1,9 @@ +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 new file mode 100644 index 0000000..35278f0 --- /dev/null +++ b/.svelte-kit/adapter-node/entries/hooks.server.js @@ -0,0 +1,22 @@ +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 new file mode 100644 index 0000000..18d72d1 --- /dev/null +++ b/.svelte-kit/adapter-node/entries/pages/(app)/_layout.server.ts.js @@ -0,0 +1,14 @@ +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 new file mode 100644 index 0000000..068b523 --- /dev/null +++ b/.svelte-kit/adapter-node/entries/pages/(app)/_layout.svelte.js @@ -0,0 +1,97 @@ +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 new file mode 100644 index 0000000..e04978c --- /dev/null +++ b/.svelte-kit/adapter-node/entries/pages/(app)/_page.server.ts.js @@ -0,0 +1,39 @@ +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 new file mode 100644 index 0000000..6f98657 --- /dev/null +++ b/.svelte-kit/adapter-node/entries/pages/(app)/_page.svelte.js @@ -0,0 +1,118 @@ +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 new file mode 100644 index 0000000..7f5e1cf --- /dev/null +++ b/.svelte-kit/adapter-node/entries/pages/(app)/admin/_page.server.ts.js @@ -0,0 +1,70 @@ +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 new file mode 100644 index 0000000..59b9970 --- /dev/null +++ b/.svelte-kit/adapter-node/entries/pages/(app)/admin/_page.svelte.js @@ -0,0 +1,70 @@ +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 new file mode 100644 index 0000000..cbdf47b --- /dev/null +++ b/.svelte-kit/adapter-node/entries/pages/(app)/mappools/_id_/_page.server.ts.js @@ -0,0 +1,100 @@ +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 new file mode 100644 index 0000000..0a8825e --- /dev/null +++ b/.svelte-kit/adapter-node/entries/pages/(app)/mappools/_id_/_page.svelte.js @@ -0,0 +1,98 @@ +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 new file mode 100644 index 0000000..77c98ad --- /dev/null +++ b/.svelte-kit/adapter-node/entries/pages/(app)/mappools/_page.server.ts.js @@ -0,0 +1,24 @@ +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 new file mode 100644 index 0000000..c122aec --- /dev/null +++ b/.svelte-kit/adapter-node/entries/pages/(app)/mappools/_page.svelte.js @@ -0,0 +1,34 @@ +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 new file mode 100644 index 0000000..497a952 --- /dev/null +++ b/.svelte-kit/adapter-node/entries/pages/(app)/matches/_id_/_page.server.ts.js @@ -0,0 +1,129 @@ +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 new file mode 100644 index 0000000..e6b854f --- /dev/null +++ b/.svelte-kit/adapter-node/entries/pages/(app)/matches/_id_/_page.svelte.js @@ -0,0 +1,323 @@ +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 new file mode 100644 index 0000000..2891ac2 --- /dev/null +++ b/.svelte-kit/adapter-node/entries/pages/(app)/matches/_page.server.ts.js @@ -0,0 +1,58 @@ +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 new file mode 100644 index 0000000..9af67ae --- /dev/null +++ b/.svelte-kit/adapter-node/entries/pages/(app)/matches/_page.svelte.js @@ -0,0 +1,164 @@ +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 new file mode 100644 index 0000000..0198d65 --- /dev/null +++ b/.svelte-kit/adapter-node/entries/pages/(app)/settings/_page.server.ts.js @@ -0,0 +1,37 @@ +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 new file mode 100644 index 0000000..3b24951 --- /dev/null +++ b/.svelte-kit/adapter-node/entries/pages/(app)/settings/_page.svelte.js @@ -0,0 +1,48 @@ +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 new file mode 100644 index 0000000..dbeb11a --- /dev/null +++ b/.svelte-kit/adapter-node/entries/pages/(app)/teams/_page.server.ts.js @@ -0,0 +1,88 @@ +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 new file mode 100644 index 0000000..e5203aa --- /dev/null +++ b/.svelte-kit/adapter-node/entries/pages/(app)/teams/_page.svelte.js @@ -0,0 +1,138 @@ +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 new file mode 100644 index 0000000..85b4f7d --- /dev/null +++ b/.svelte-kit/adapter-node/entries/pages/_error.svelte.js @@ -0,0 +1,25 @@ +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 new file mode 100644 index 0000000..1b9e0e2 --- /dev/null +++ b/.svelte-kit/adapter-node/entries/pages/demo/_page.svelte.js @@ -0,0 +1,31 @@ +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 new file mode 100644 index 0000000..8fa1822 --- /dev/null +++ b/.svelte-kit/adapter-node/entries/pages/demo/better-auth/_page.server.ts.js @@ -0,0 +1,20 @@ +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 new file mode 100644 index 0000000..42126b3 --- /dev/null +++ b/.svelte-kit/adapter-node/entries/pages/demo/better-auth/_page.svelte.js @@ -0,0 +1,18 @@ +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 new file mode 100644 index 0000000..2e2ee65 --- /dev/null +++ b/.svelte-kit/adapter-node/entries/pages/demo/better-auth/login/_page.server.ts.js @@ -0,0 +1,75 @@ +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 new file mode 100644 index 0000000..c17dfef --- /dev/null +++ b/.svelte-kit/adapter-node/entries/pages/demo/better-auth/login/_page.svelte.js @@ -0,0 +1,18 @@ +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 new file mode 100644 index 0000000..a8c7c75 --- /dev/null +++ b/.svelte-kit/adapter-node/entries/pages/login/_page.server.ts.js @@ -0,0 +1,16 @@ +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 new file mode 100644 index 0000000..fb8a806 --- /dev/null +++ b/.svelte-kit/adapter-node/index.js @@ -0,0 +1,3698 @@ +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 new file mode 100644 index 0000000..db0dd6a --- /dev/null +++ b/.svelte-kit/generated/server/internal.js @@ -0,0 +1,53 @@ + +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 new file mode 100644 index 0000000..c14fd87 --- /dev/null +++ b/.svelte-kit/non-ambient.d.ts @@ -0,0 +1,81 @@ + +// 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 new file mode 100644 index 0000000..f1cdb44 --- /dev/null +++ b/.svelte-kit/output/client/.vite/manifest.json @@ -0,0 +1,394 @@ +{ + ".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 new file mode 100644 index 0000000..d32e9ae --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/assets/2.Dv2no-8m.css @@ -0,0 +1 @@ +@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 new file mode 100644 index 0000000..4fefbc4 --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/chunks/BAocuFgQ.js @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..a308712 --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/chunks/BLQQas77.js @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..1911957 --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/chunks/BQKoxf2Q.js @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..609fb01 --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/chunks/BkIq08el.js @@ -0,0 +1,3 @@ +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 new file mode 100644 index 0000000..af55481 --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/chunks/BnX5ZnVA.js @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..3f264a6 --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/chunks/BqOsL1Vv.js @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..7c1d4c2 --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/chunks/BxEwC6Zc.js @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..17691ab --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/chunks/CAkKRSSs.js @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..4c73729 --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/chunks/CvGSsBh3.js @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..4b54476 --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/chunks/Cy2QBcXt.js @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..80818c3 --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/chunks/CyUoLS3q.js @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..ddb898d --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/chunks/D2SGgx9j.js @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..8e3bd4b --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/chunks/DAtZQVjv.js @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..176717a --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/chunks/DoLu9QLy.js @@ -0,0 +1,2 @@ +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 new file mode 100644 index 0000000..ca27dc7 --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/chunks/DsnmJJEf.js @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..b7981bb --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/chunks/TpZZa089.js @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..886d5c7 --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/chunks/kALFGdUG.js @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..72ad082 --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/entry/app.DL20j9gb.js @@ -0,0 +1,2 @@ +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 new file mode 100644 index 0000000..93acd60 --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/entry/start.Df1GVxyt.js @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..0e2b0f5 --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/nodes/0.9C686m9W.js @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..f7b0d81 --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/nodes/1.RyK1bdTz.js @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..6e9e279 --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/nodes/10.BPlEN6_G.js @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..67e6c80 --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/nodes/11.DR1Vz7m0.js @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..0276207 --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/nodes/12.C9UZWAjJ.js @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..501abea --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/nodes/13.CyZ4e6yK.js @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..e79d7eb --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/nodes/2.BsR2_q_w.js @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..2ffae4c --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/nodes/3.CMuy9Bx3.js @@ -0,0 +1,3 @@ +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 new file mode 100644 index 0000000..52a5797 --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/nodes/4.BdC-uDW-.js @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..57e94eb --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/nodes/5.CyqZcxti.js @@ -0,0 +1,2 @@ +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 new file mode 100644 index 0000000..008b31b --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/nodes/6.CEe0czaO.js @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..025e27c --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/nodes/7._nuD3LlN.js @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..cc8ee6c --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/nodes/8.CkbqikZq.js @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..07cdc33 --- /dev/null +++ b/.svelte-kit/output/client/_app/immutable/nodes/9.BTBc_Eli.js @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..0e8f73c --- /dev/null +++ b/.svelte-kit/output/client/_app/version.json @@ -0,0 +1 @@ +{"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 new file mode 100644 index 0000000000000000000000000000000000000000..e15a9abf8b8deee63ec91128231a0d65918364c4 GIT binary patch literal 38272 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 z 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 UX#KGOX8-^I07*qoM6N<$g30ad4gdfE literal 0 HcmV?d00001 diff --git a/.svelte-kit/output/client/android-chrome-512x512.png b/.svelte-kit/output/client/android-chrome-512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..58bc4cbffcf157d3b847fa7971259fad0f40a210 GIT binary patch literal 159273 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 z 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 !D?Ru;}|)M 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 literal 0 HcmV?d00001 diff --git a/.svelte-kit/output/client/apple-touch-icon.png b/.svelte-kit/output/client/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..fb8b64b537048492de285f22519de261c0892b1f GIT binary patch literal 36949 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 QqcQ&f`~RPTf7J~9FZj=DC;$Ke literal 0 HcmV?d00001 diff --git a/.svelte-kit/output/client/robots.txt b/.svelte-kit/output/client/robots.txt new file mode 100644 index 0000000..b6dd667 --- /dev/null +++ b/.svelte-kit/output/client/robots.txt @@ -0,0 +1,3 @@ +# allow crawling everything by default +User-agent: * +Disallow: diff --git a/.svelte-kit/output/client/site.webmanifest b/.svelte-kit/output/client/site.webmanifest new file mode 100644 index 0000000..45dc8a2 --- /dev/null +++ b/.svelte-kit/output/client/site.webmanifest @@ -0,0 +1 @@ +{"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 new file mode 100644 index 0000000..36de7fb --- /dev/null +++ b/.svelte-kit/output/server/.vite/manifest.json @@ -0,0 +1,661 @@ +{ + ".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 new file mode 100644 index 0000000..d32e9ae --- /dev/null +++ b/.svelte-kit/output/server/_app/immutable/assets/_layout.Dv2no-8m.css @@ -0,0 +1 @@ +@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 new file mode 100644 index 0000000..5e6cc8c --- /dev/null +++ b/.svelte-kit/output/server/chunks/api.js @@ -0,0 +1,69 @@ +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 new file mode 100644 index 0000000..588593c --- /dev/null +++ b/.svelte-kit/output/server/chunks/auth.js @@ -0,0 +1,7983 @@ +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 + + + + + +`; +}; +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 new file mode 100644 index 0000000..6fe94c6 --- /dev/null +++ b/.svelte-kit/output/server/chunks/bun-sqlite-dialect.js @@ -0,0 +1,155 @@ +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 new file mode 100644 index 0000000..f6bafe4 --- /dev/null +++ b/.svelte-kit/output/server/chunks/engine.js @@ -0,0 +1,350 @@ +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 new file mode 100644 index 0000000..d81356b --- /dev/null +++ b/.svelte-kit/output/server/chunks/environment.js @@ -0,0 +1,14 @@ +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 new file mode 100644 index 0000000..441ec91 --- /dev/null +++ b/.svelte-kit/output/server/chunks/exports.js @@ -0,0 +1,70 @@ +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 new file mode 100644 index 0000000..f3effd6 --- /dev/null +++ b/.svelte-kit/output/server/chunks/false.js @@ -0,0 +1,4 @@ +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 new file mode 100644 index 0000000..14b637b --- /dev/null +++ b/.svelte-kit/output/server/chunks/index.js @@ -0,0 +1,60 @@ +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 new file mode 100644 index 0000000..2c507a6 --- /dev/null +++ b/.svelte-kit/output/server/chunks/index2.js @@ -0,0 +1,302 @@ +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 new file mode 100644 index 0000000..20b173b --- /dev/null +++ b/.svelte-kit/output/server/chunks/index3.js @@ -0,0 +1,1249 @@ +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 new file mode 100644 index 0000000..2ae44a6 --- /dev/null +++ b/.svelte-kit/output/server/chunks/index4.js @@ -0,0 +1,47 @@ +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 new file mode 100644 index 0000000..5a5bcdc --- /dev/null +++ b/.svelte-kit/output/server/chunks/index5.js @@ -0,0 +1,224 @@ +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 new file mode 100644 index 0000000..f55374c --- /dev/null +++ b/.svelte-kit/output/server/chunks/index6.js @@ -0,0 +1,307 @@ +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 new file mode 100644 index 0000000..55b3eeb --- /dev/null +++ b/.svelte-kit/output/server/chunks/internal.js @@ -0,0 +1,127 @@ +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 new file mode 100644 index 0000000..68f03bc --- /dev/null +++ b/.svelte-kit/output/server/chunks/node-sqlite-dialect.js @@ -0,0 +1,155 @@ +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 new file mode 100644 index 0000000..da259e9 --- /dev/null +++ b/.svelte-kit/output/server/chunks/orchestrator.js @@ -0,0 +1,448 @@ +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 new file mode 100644 index 0000000..a14a6fa --- /dev/null +++ b/.svelte-kit/output/server/chunks/query.js @@ -0,0 +1,258 @@ +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 new file mode 100644 index 0000000..c678a5c --- /dev/null +++ b/.svelte-kit/output/server/chunks/root.js @@ -0,0 +1,2713 @@ +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 new file mode 100644 index 0000000..11c0ffa --- /dev/null +++ b/.svelte-kit/output/server/chunks/routing.js @@ -0,0 +1,85 @@ +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 new file mode 100644 index 0000000..bf7eaa6 --- /dev/null +++ b/.svelte-kit/output/server/chunks/server.js @@ -0,0 +1,27 @@ +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 new file mode 100644 index 0000000..4fa13e6 --- /dev/null +++ b/.svelte-kit/output/server/chunks/shared-server.js @@ -0,0 +1,14 @@ +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 new file mode 100644 index 0000000..9162124 --- /dev/null +++ b/.svelte-kit/output/server/chunks/shared.js @@ -0,0 +1,789 @@ +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 new file mode 100644 index 0000000..9cd4558 --- /dev/null +++ b/.svelte-kit/output/server/chunks/state.svelte.js @@ -0,0 +1,18 @@ +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 new file mode 100644 index 0000000..2ba2c18 --- /dev/null +++ b/.svelte-kit/output/server/chunks/url.js @@ -0,0 +1,106 @@ +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 new file mode 100644 index 0000000..78e5bde --- /dev/null +++ b/.svelte-kit/output/server/chunks/utils.js @@ -0,0 +1,43 @@ +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 new file mode 100644 index 0000000..203529d --- /dev/null +++ b/.svelte-kit/output/server/entries/endpoints/api/health/_server.ts.js @@ -0,0 +1,25 @@ +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 new file mode 100644 index 0000000..4d6b270 --- /dev/null +++ b/.svelte-kit/output/server/entries/endpoints/api/mappools/_id_/_server.ts.js @@ -0,0 +1,24 @@ +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 new file mode 100644 index 0000000..b61da5c --- /dev/null +++ b/.svelte-kit/output/server/entries/endpoints/api/mappools/_id_/slots/_server.ts.js @@ -0,0 +1,27 @@ +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 new file mode 100644 index 0000000..c77f59a --- /dev/null +++ b/.svelte-kit/output/server/entries/endpoints/api/mappools/_id_/slots/_slotId_/_server.ts.js @@ -0,0 +1,11 @@ +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 new file mode 100644 index 0000000..bf904be --- /dev/null +++ b/.svelte-kit/output/server/entries/endpoints/api/mappools/_server.ts.js @@ -0,0 +1,23 @@ +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 new file mode 100644 index 0000000..b383e98 --- /dev/null +++ b/.svelte-kit/output/server/entries/endpoints/api/matches/_id_/_server.ts.js @@ -0,0 +1,24 @@ +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 new file mode 100644 index 0000000..35ed7aa --- /dev/null +++ b/.svelte-kit/output/server/entries/endpoints/api/matches/_id_/lobby/_server.ts.js @@ -0,0 +1,15 @@ +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 new file mode 100644 index 0000000..a655c49 --- /dev/null +++ b/.svelte-kit/output/server/entries/endpoints/api/matches/_id_/pick/_server.ts.js @@ -0,0 +1,18 @@ +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 new file mode 100644 index 0000000..21f102e --- /dev/null +++ b/.svelte-kit/output/server/entries/endpoints/api/matches/_id_/roll/_server.ts.js @@ -0,0 +1,18 @@ +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 new file mode 100644 index 0000000..e5cc1e3 --- /dev/null +++ b/.svelte-kit/output/server/entries/endpoints/api/matches/_id_/rolling/_server.ts.js @@ -0,0 +1,14 @@ +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 new file mode 100644 index 0000000..cd031cb --- /dev/null +++ b/.svelte-kit/output/server/entries/endpoints/api/matches/_id_/score/_server.ts.js @@ -0,0 +1,18 @@ +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 new file mode 100644 index 0000000..3732a25 --- /dev/null +++ b/.svelte-kit/output/server/entries/endpoints/api/matches/_server.ts.js @@ -0,0 +1,37 @@ +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 new file mode 100644 index 0000000..c258470 --- /dev/null +++ b/.svelte-kit/output/server/entries/endpoints/api/osu/beatmap/_id_/_server.ts.js @@ -0,0 +1,14 @@ +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 new file mode 100644 index 0000000..d6b0508 --- /dev/null +++ b/.svelte-kit/output/server/entries/endpoints/api/queue/_server.ts.js @@ -0,0 +1,36 @@ +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 new file mode 100644 index 0000000..c3792df --- /dev/null +++ b/.svelte-kit/output/server/entries/fallbacks/layout.svelte.js @@ -0,0 +1,9 @@ +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 new file mode 100644 index 0000000..35278f0 --- /dev/null +++ b/.svelte-kit/output/server/entries/hooks.server.js @@ -0,0 +1,22 @@ +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 new file mode 100644 index 0000000..18d72d1 --- /dev/null +++ b/.svelte-kit/output/server/entries/pages/(app)/_layout.server.ts.js @@ -0,0 +1,14 @@ +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 new file mode 100644 index 0000000..068b523 --- /dev/null +++ b/.svelte-kit/output/server/entries/pages/(app)/_layout.svelte.js @@ -0,0 +1,97 @@ +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 new file mode 100644 index 0000000..e04978c --- /dev/null +++ b/.svelte-kit/output/server/entries/pages/(app)/_page.server.ts.js @@ -0,0 +1,39 @@ +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 new file mode 100644 index 0000000..6f98657 --- /dev/null +++ b/.svelte-kit/output/server/entries/pages/(app)/_page.svelte.js @@ -0,0 +1,118 @@ +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 new file mode 100644 index 0000000..7f5e1cf --- /dev/null +++ b/.svelte-kit/output/server/entries/pages/(app)/admin/_page.server.ts.js @@ -0,0 +1,70 @@ +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 new file mode 100644 index 0000000..59b9970 --- /dev/null +++ b/.svelte-kit/output/server/entries/pages/(app)/admin/_page.svelte.js @@ -0,0 +1,70 @@ +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 new file mode 100644 index 0000000..cbdf47b --- /dev/null +++ b/.svelte-kit/output/server/entries/pages/(app)/mappools/_id_/_page.server.ts.js @@ -0,0 +1,100 @@ +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 new file mode 100644 index 0000000..0a8825e --- /dev/null +++ b/.svelte-kit/output/server/entries/pages/(app)/mappools/_id_/_page.svelte.js @@ -0,0 +1,98 @@ +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 new file mode 100644 index 0000000..77c98ad --- /dev/null +++ b/.svelte-kit/output/server/entries/pages/(app)/mappools/_page.server.ts.js @@ -0,0 +1,24 @@ +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 new file mode 100644 index 0000000..c122aec --- /dev/null +++ b/.svelte-kit/output/server/entries/pages/(app)/mappools/_page.svelte.js @@ -0,0 +1,34 @@ +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 new file mode 100644 index 0000000..497a952 --- /dev/null +++ b/.svelte-kit/output/server/entries/pages/(app)/matches/_id_/_page.server.ts.js @@ -0,0 +1,129 @@ +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 new file mode 100644 index 0000000..e6b854f --- /dev/null +++ b/.svelte-kit/output/server/entries/pages/(app)/matches/_id_/_page.svelte.js @@ -0,0 +1,323 @@ +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 new file mode 100644 index 0000000..2891ac2 --- /dev/null +++ b/.svelte-kit/output/server/entries/pages/(app)/matches/_page.server.ts.js @@ -0,0 +1,58 @@ +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 new file mode 100644 index 0000000..9af67ae --- /dev/null +++ b/.svelte-kit/output/server/entries/pages/(app)/matches/_page.svelte.js @@ -0,0 +1,164 @@ +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 new file mode 100644 index 0000000..0198d65 --- /dev/null +++ b/.svelte-kit/output/server/entries/pages/(app)/settings/_page.server.ts.js @@ -0,0 +1,37 @@ +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 new file mode 100644 index 0000000..3b24951 --- /dev/null +++ b/.svelte-kit/output/server/entries/pages/(app)/settings/_page.svelte.js @@ -0,0 +1,48 @@ +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 new file mode 100644 index 0000000..dbeb11a --- /dev/null +++ b/.svelte-kit/output/server/entries/pages/(app)/teams/_page.server.ts.js @@ -0,0 +1,88 @@ +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 new file mode 100644 index 0000000..e5203aa --- /dev/null +++ b/.svelte-kit/output/server/entries/pages/(app)/teams/_page.svelte.js @@ -0,0 +1,138 @@ +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 new file mode 100644 index 0000000..85b4f7d --- /dev/null +++ b/.svelte-kit/output/server/entries/pages/_error.svelte.js @@ -0,0 +1,25 @@ +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 new file mode 100644 index 0000000..1b9e0e2 --- /dev/null +++ b/.svelte-kit/output/server/entries/pages/demo/_page.svelte.js @@ -0,0 +1,31 @@ +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 new file mode 100644 index 0000000..8fa1822 --- /dev/null +++ b/.svelte-kit/output/server/entries/pages/demo/better-auth/_page.server.ts.js @@ -0,0 +1,20 @@ +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 new file mode 100644 index 0000000..42126b3 --- /dev/null +++ b/.svelte-kit/output/server/entries/pages/demo/better-auth/_page.svelte.js @@ -0,0 +1,18 @@ +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 new file mode 100644 index 0000000..2e2ee65 --- /dev/null +++ b/.svelte-kit/output/server/entries/pages/demo/better-auth/login/_page.server.ts.js @@ -0,0 +1,75 @@ +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 new file mode 100644 index 0000000..c17dfef --- /dev/null +++ b/.svelte-kit/output/server/entries/pages/demo/better-auth/login/_page.svelte.js @@ -0,0 +1,18 @@ +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 new file mode 100644 index 0000000..a8c7c75 --- /dev/null +++ b/.svelte-kit/output/server/entries/pages/login/_page.server.ts.js @@ -0,0 +1,16 @@ +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 new file mode 100644 index 0000000..fb8a806 --- /dev/null +++ b/.svelte-kit/output/server/index.js @@ -0,0 +1,3698 @@ +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 `