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

- ERROR -

-
-
-
- -

- Something went wrong -

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

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

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

' + message + "

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

Welcome to Vash Esports

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

Sign in with osu!

Uses your osu! account. No extra registration needed.

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

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

Automated esports match management for osu!

${escape_html(data.stats.matches)}

Total Matches

${escape_html(data.stats.finished)}

Completed

${escape_html(data.stats.teams)}

Teams

${escape_html(data.stats.mappools)}

Mappools

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

Live Now

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

Ranked Queue

Find a match at your skill level

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

Recent Matches

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

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

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

No matches yet. Create one

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

Admin Panel

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

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

${escape_html(u.name)}

${escape_html(u.email)}

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

${escape_html(data.pool.name)}

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

Add Map

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

Beatmap #${escape_html(slot.beatmapId)}

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

No maps yet. Add your first map above.

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

Mappools

Create and manage your beatmap pools

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

${escape_html(pool.name)}

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

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

No mappools yet. Create one to get started.

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

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

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

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

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

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

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

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

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

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

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

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

🎲 Roll Phase

Highest roll picks first

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

${escape_html(p.team.name)}

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

${escape_html(p.rollValue)}

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

—

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

or type !roll in osu! chat

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

Waiting for all rolls...

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

🎯 Pick a Map

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

or type !pick NM1 in osu! chat

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

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

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

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

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

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

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

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

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

Games Played

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

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

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

Creating osu! lobby...

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

Lobby created. Waiting for players to join...

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

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

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

This match was cancelled.

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

Matches

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

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

Live Now

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

Past Matches

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

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

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

No matches yet. Create one to get started.

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

Settings

Your profile and account settings

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

${escape_html(data.profile.name)}

${escape_html(badge().label)}

${escape_html(data.profile.email)}

Connected Accounts

🎮

osu!

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

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

Ranked Stats

${escape_html(data.rating.elo)}

ELO Rating

${escape_html(data.rating.wins)}

Wins

${escape_html(data.rating.losses)}

Losses

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

Win Rate

Account

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

Teams

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

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

My Teams

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

Other Teams

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

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

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

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

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

${escape_html(page.status)}

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

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

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

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

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

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

Login

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


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

" + message + "

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

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

My Teams

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

'),ut=n('

Other Teams

'),xt=n('

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

'),ft=n('

Teams

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

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

Login


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

Staff

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

Welcome to Vash Esports

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

Sign in with osu!

Uses your osu! account. No extra registration needed.

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

Live Now

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

'),et=i('

No matches yet. Create one

'),tt=i('

Welcome back,

Automated esports match management for osu!

Total Matches

Completed

Teams

Mappools

Ranked Queue

Find a match at your skill level

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

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

/
'),be=x('

Admin Panel

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

→
'),J=i('

No mappools yet. Create one to get started.

'),K=i('

Mappools

Create and manage your beatmap pools

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

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

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

No maps yet. Add your first map above.

'),ee=c('

Add Map

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

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

Create Match

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

Live Now

'),Ue=f('

Past Matches

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

'),ze=f('

No matches yet. Create one to get started.

'),Je=f('

Matches

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

'),Ce=i('

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

vs

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

'),Ge=i('

—

'),Se=i('

'),Ee=i('

or type !roll in osu! chat

',1),Oe=i('

Waiting for all rolls...

'),De=i('

🎲 Roll Phase

Highest roll picks first

'),Be=i('

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

',1),Ye=i('

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

🎯 Pick a Map

's turn to pick

or type !pick NM1 in osu! chat

`),Ve=i('

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

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

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

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

Games Played

'),ar=i('

Creating osu! lobby...

'),sr=i('

'),or=i('

Lobby created. Waiting for players to join...

'),nr=i('

This match was cancelled.

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

Settings

Your profile and account settings

Connected Accounts

🎮

osu!

Ranked Stats

ELO Rating

Wins

Losses

Win Rate

Account

');function At(I,r){lt(r,!0);const L={player:{label:"Player",color:"bg-surface-600 text-text-secondary"},referee:{label:"Referee",color:"bg-yellow-500/20 text-yellow-400"},admin:{label:"Admin",color:"bg-red-500/20 text-red-400"}},R=D(()=>L[r.data.profile.role]??L.player),A=D(()=>r.data.rating.wins+r.data.rating.losses>0?(r.data.rating.wins/(r.data.rating.wins+r.data.rating.losses)*100).toFixed(1):"—");var x=_t(),f=d(t(x),4),m=t(f),C=t(m);{var J=a=>{var s=mt();l(()=>{H(s,"src",r.data.profile.image),H(s,"alt",r.data.profile.name)}),o(a,s)},K=a=>{var s=pt(),ot=t(s,!0);e(s),l(nt=>i(ot,nt),[()=>r.data.profile.name.charAt(0).toUpperCase()]),o(a,s)};k(C,a=>{r.data.profile.image?a(J):a(K,!1)})}var O=d(C,2),p=t(O),u=t(p),M=t(u,!0);e(u);var g=d(u,2),Q=t(g,!0);e(g),e(p);var S=d(p,2),T=t(S,!0);e(S),e(O),e(m);var W=d(m,2),j=d(t(W),2),_=d(t(j),2),B=d(t(_),2),V=t(B);{var X=a=>{var s=G();l(()=>i(s,`Connected as ${r.data.profile.name??""}`)),o(a,s)},Z=a=>{var s=G("Not connected");o(a,s)};k(V,a=>{r.data.hasOsuLinked?a(X):a(Z,!1)})}e(B),e(_);var $=d(_,2);{var tt=a=>{var s=ut();o(a,s)},et=a=>{var s=gt();o(a,s)};k($,a=>{r.data.hasOsuLinked?a(tt):a(et,!1)})}e(j),e(W),e(f);var b=d(f,2),E=d(t(b),2),h=t(E),F=t(h),at=t(F,!0);e(F),v(2),e(h);var y=d(h,2),N=t(y),rt=t(N,!0);e(N),v(2),e(y);var w=d(y,2),P=t(w),st=t(P,!0);e(P),v(2),e(w);var U=d(w,2),Y=t(U),dt=t(Y);e(Y),v(2),e(U),e(E),e(b);var q=d(b,2),z=d(t(q),2),it=t(z);ct(it,a=>xt?.(a)),e(z),e(q),e(x),l(()=>{i(M,r.data.profile.name),ft(g,1,`rounded px-2 py-0.5 text-xs font-600 ${c(R).color??""}`),i(Q,c(R).label),i(T,r.data.profile.email),i(at,r.data.rating.elo),i(rt,r.data.rating.wins),i(st,r.data.rating.losses),i(dt,`${c(A)??""}${c(A)!=="—"?"%":""}`)}),o(I,x),vt()}export{At as component}; diff --git a/.svelte-kit/output/client/_app/version.json b/.svelte-kit/output/client/_app/version.json deleted file mode 100644 index 0e8f73c..0000000 --- a/.svelte-kit/output/client/_app/version.json +++ /dev/null @@ -1 +0,0 @@ -{"version":"1772254297287"} \ No newline at end of file diff --git a/.svelte-kit/output/client/android-chrome-192x192.png b/.svelte-kit/output/client/android-chrome-192x192.png deleted file mode 100644 index e15a9abf8b8deee63ec91128231a0d65918364c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38272 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 z z&(%XeIT8uu;dH&BFc55rY^z0TTv=AconN)-ltf?AnxbwA2(y zQfL+SVAz(`F5;f2_a%P5x%~tgriKLqkrsh-ZN6euyu)sl9{Tb}_qS#07UKkOO9o&A z?4j1VVa~L7`JnB92ujJ~4BU!GX^t0o?DtmM9;~iR4K-eWf?Ml(S`<8}Ez&MtW`$S| z?sM#c=n>Sd0tCbaw>ncXg2v%6s4tEZ{nGPpHKO||G4}bUd#q=wBYMJ)H= zc)jI3ZhG(X3SJ?B#>FsVcu=2%&s5|$x-$L0#P&3)TNQ{Ry}r^ETZruuP%oP%ZK~}g ze-XNxZVl2(f}I8H+S7}Uw=6RQ{A>hZ2P!2S0>Yo02t-!uo-@Vw=0t?5P|1Q0K( zV!zn`vzwoY++@8^9PJijdlJAeekChV@);1(P{CRj#bM%?THv4x%4z}A0 zu1<{n_Vt19$)p#S>3;m!SBvGj`U6$FbNJfoJ9?<56RTcHwmigJmy^$oKYwyvIS@r@ z9*H%F61&2?u<0G<@KRZ#%N3$3MJYvoJnt*s1D}AC!IS3VH|ub>Y_Lh0F6$m=G%lvJ zo3&p2d9&jOgASmPK_)b+oz`k}Wc`Hy;#*z0@|H3HGk!|^!Po8Hp%>gW+h=vBpEEx3 z!{!cDCAoRyPtxn+&*$R4#@44)dpiBjO8LzCS6)5g((vS|KVJCA(ff}b zGvB;M2B&-14UMmT-*%w1->g>>Hb^nt<_wlesZ|3LYZE1=1Q|bmZBZ{|Ivderk=P*x z^9#B-%hq_HJ`a+KVACplaibT;&kMmMpyla^)aR8!+SCT(ff|UX`65jl>%A~_vg_*H z3DURnE$tn8OAhey`^Sq=n0{c!C=7q6u&QSk9CpTYszAhDUK!K1Hh!7y;pU%YkaP=# z+F9fc8!7U)n7UFKp`6u))YPHgS%j|gjNdak`HTT{@3;QVeQjmZ%nAOsck6u((>bC? z;bv9`=zb&Kwa?|l+43qL{n6eZRfQ=PoM`YKZEQ%K7Dv^LPQ_84XFkc8RW=A2E!Q(O z89%O5Fm{(v}cP$x*1%k)Q2u=ftxV*V$kf9K?K?uQ& z?@^PkKc^j@v%m_oJx#`+$M$f#Of`PQFi36v^hL!Ud~PU0LX7n>0M)Kehzw(F!*^ah z**Es)iIwDiXWBWzog+{7Lx;7!+S@lo9edEJmQ5q{(D6znG~g2+MFkE5PO7_T1?z)$@rD)MA2Vl_uNd9{A(gtNg*Ad@nBLi zQ-iAO_=Lb2+w)Fn;Gg{3@|$arE!hG14xev2w`_f_uwu9t>6?7eOlJBl#pB4IT!6B= zu*LQ^-T-TcJ#thM(L-f>;v0kus(iLboW|b7$ROB60BWwwL|OFqS6-R!nk$buCGF@} zKhu72zW?^o9_TC#gBCqtg^i*?8}Yra_Q)?azL#p-8~}0GmmYV$T5*417xvXly{-WP z*#3M%iHgQh-kD!K>SYI2G=EN%VRN=iT)xb>*eszF)!GVZsmEKn;M+-CcW0kUV{KO}Q7nHKA<-n31fStf-1^)hd z-P(8ADY;dx{SF@<-Enr1ZUQP!Z`Syw1`g-R)2qXY0ZN; zcoC^{8-kpSz=JEw06vBp%7hn>>X@!oPo@#yBVLE&Ol5XJMVA(RtN;KY07*naR0b;S z5im3#_DJ;r&!TL*2Mbaf0eh}i(Hs6@*9#7P`R=7P$d=>)AK7=so$% z00q&J6c~H)um^WzIp)hdkeU~}Nl~jP5ituAe+Jw&MS~^W8B$8NNpGXV074{eZ~y@y(j*|!h`ceLwgI(GHvH%-@4tSKmFl>P`BK|{2Z|HPnN!MA0itr zZ!SKQ`;oI9nqPk^_LHRt99nTh%A97Q>s34J@#j)E?J4pK$@t@dlNrDCdhBy@16Nop z5d_6?Qn7@-e3pjV{FrmgE5U{LaKi(1HWw#nQGL zmfIJxhF6^0v-GXj0BYkYyJ)#yXchUBSC%`LyfBg|z&Nxk=XbR{pDSy)s8NkOA~Qb9 zWYQfjbk0sf_tcfMS_pg2?)!xWRiY0*_#nA>^=jX18$Pt{+M4$r2#V%L_PLCP4>}Ey zlsUUD$w1VG7lt}q>MZD6IiidEBGnDdkdy{u9_HuwnM*`Oz)*(qa}Mkf^e(Rn1QF3X zSS*u{ou2-G?aYFC4a&dK^IjnIRC_1=98p8-Ls;!t|=y#^$`$g-x5=(&kwF{)>P;(oKqu8?g#GX*3zEK+cH&jvsKVojG`%k?j&S z2!xIWQA8jLwX=~9d#?Q2x<$#PKm6~%xFyi^hbGsp+cLX)4HU}rVEA6VD^pr4qVy&t zXqXm-$;1>Y>f^t(Fn&CBB^Z>X7m?dV$I)3Bf2O_SI6nDZ-8H0S8fA$Vj?`+V%8Xnc z(oxu`oXDRsLu`PC9oNJbs!%qkX9vm2Z`qXCsd&Amois9eb{W}}OLdSs%_Y7_uzkOq$J6$HGUvEA=l4nnR z4M+!-jB}#GSQtNo2#Rsb^dWnL%mFy*Anq-aI!o|O3NWZZM$A$It5Rn~`$Ev(0mbnfk$=3GdWxch4@05n7T1{QSRse6tVa$hf=y zzA<;b=@SD8rJ$!PK_r7kd_0e8ssl*c7!;v}5efxme&pvAUBZWF?kt=w*12%zV~Mif z6gDu*ZNAXWOsI1E#Pg%w^Vg15oEyiV9$uJj_|1L$+&QCbVD!EZ@2DR;(t@m(#!C_giSZnsq@K zwlp`~keW4ip8Uv<9Ti7@`Rf36#(jX2}Ve;*8=va5gr>q?nYyAA#;GLYt^(+JKi<1I7Vnm4!}MX z?*vbi!q&2B4_|baZF=45HhrSU57vkmeInymGD54!pIjhjds-K~O~#L>y(HMP!0?AedHAHATtVDFET6_b2mbsJ^_kuC^x5)YCE%D6 zopV$Hs=g<-ed#kG5<}D=O5{hdEs@WppC^hSOdNok6}o6fXvq%1jhhX>SBbU#l3f~_ zusa7YIbEiw5isIKu^BbmlI@8fIFAJUrlvf38iBHCkteapZWcbDixT#C71?~MsYB3J0B3F%Iwq&iMpWPP?LAu;#Wvjeci-6pKp%pTZqdR3Om@_2T$nb` z0|?{Av%}oTcrZ~hzo0eS!=8NOm!XjyU~q?+dqy_Lj5CLb@~SKaL##C7$M4a^8l{;- z%0SIdp$5SC@2nVR5(&!ywr^HjBqMaw4v@g1ZNoWMv+zf0T`9&bW?}Y|zFwei3$S<=wD*RHq zzG$#X)LKb2LA-A1%&#$Bf|m@gpD1e@1V~0k~me zc4*RFJvi1?GCcs${XiTZA>c<|7gCA*JY(b+uF1RJ9PCjdA(9MdkO(U^(f6lKsd`su z%qaC=_)f(w-#APx`%t@Ln0?+=k3a9)UB&$*4E7ajbFLY%6Xz55Ocbul=MnP`QbbfF z5~?ww`^zESTZcWeL_uboajT)WC`B4QSPrYzrgK4>i#09!dX5Gk^ny2Hcbc= z=e&yU(ZiYzhrZl`5qeu3Kw^jN!mgK=E#EMs7u+z?vxkfuF8D%oj6aJ+>bPKXnF-H- zGq9({q*zOsgz;~}BKdX^0^I>Ss8mSc9d>GD@swzR?hh?%U)}9;b)dkq0CT3?jS$?3 zq&JK-} z#@1Oq9KPJWcGGy*T2u3*xcQTb+)^XXfjyZQD=S5CDor_b!Si!kEhn>N6z9T`UrqfB zp3=gW+}RdXySu89ZX7LLogMkr=NBj zUY9>#*4#@XDVpWw(_4yRORs}|ra7|a6};K!Q)hV>>hR*|tg=1XbHpK|KK!QcJFpEt2~xemaNE{)9S7a`JK_r0}e7V8A;!WbOV zB5nJn-t|M*J68_Q7`=I{wNxOJ>fr~ly=H*(+^`_0W7RE2WM+_OICW__RXck#OpcZV8Wc*5p zR~Ww}d&v>ap`J%8%-{4{C`ePCK*KVibGizp8`ZNA(LH~0&mT6icDW8P@UO==>lFUP zC)%r1w(*GG6P~}ifAyjk5hcrUzh0Ux6?c@a&RrAk+6{HB=(0e^FfSi{lqg3D)b|)ToHr4=z9pbrb4V7j#tS{m!|mXDpz5zwv); zYd<)D|NZ8(zw%G-^PG+&)HF8}O#`#mV3TKp5z1H(EN$kvA8T*gHMx@Pkb6&B28|5j z@Gh?iC}~zvm8&Y-lXpMyHSxfO8+I5nsY5q6WBl=FXIteAJzl64fp#|1v_1dLeW1Mq zuvI5tU3TYv^QQSZ3gH?6?{uVvBh@v_UxeL@heK?0@*Egj8+vhg(pkA_+FE8N8`DCz zG$?!EA}V1eXAZsA!uSQ1DB(o>;8nGuY&eUF{K-Sk1b2*Y4h$Ot3m`JX=ZH`D{^A?Y zKJ)PI-EHCG&;P|=#V5|s-@fv`YG27LOwWVfU_X|;K3?Z2hWgo74AC%JB<$hqP7;fg zPjtzHi;AXS3IyEvB`JcsqbY^92!>(k^^U_H-cu6S#l-d+qj`ruFNQKc-Xvqz?Xx`8CVWEY=Cw1#kPkC;RK6wtcF&d}z)r z4VI0P$quSEAZY|;Fa{m(Bi13NH&lT=Swxb@`f{5}DE;D$qr#*tYGqJF;=Kh^lg+3` zI)Q4*g}~Cs`bS?qxomv=#JZLAOgks|q+yQp?D{1mjQMk2zh|sg)pW4i%2!4Eqci`X>L@ z43p%{f?!_i1nf9m<^Z8a#+JY7pX{2dpQxJh9wEsA*q$HTzW%_ZQ5^nuSAWlp?hqY( zYCvOFqx4ZN@*nB!SQ;F9vhnp2h2oBR28TMKOYj9rmb^zxnTr zi~I{3Kgv$>K^4i(u9dog5}mGk?X~GbxjfQUC?5Ul?u7^EnLOfe?*33udBcif5(W>L zbJe2W@IYsS^N2na4l7AXWDQdjToPP=j?$FhV~p!L?TQ#D5&3g4zv@U5bWxc!l?ugl zFUqFe@Fi#z|15SMBzNa5prSTT95-bMQ)gzir)Lw;s78Cn{pmt28fmPkAANYuXT%;M z$pP5BFSVlm70udr)$DMYw1JQisI5^w3?@juaax172!{$QHci{hOfzBIT|%y>slR12$y*Erfg{_4oj zUSGuE{NsMShkl@Q?Y{4AAZ(!v4u z?R(sPwbD26jqcla&yvDUjf4dj{kgHRlhq>~sP22SMi@NWsn;H%mcAr*2*aT(9cwo< zEX!r@VMK@`&BOetQ6fjV<^~F$c#rr@u0@x5PKMGaK7Bp z1FJ8d_iq{f_A^E!+c~qy0w-HR0qQ8Jps7^s4wMp)+uC>IH4DJMy{z?%+#_%Vbj>Gee zLWhK5WcvD{PM~g?HPQ%=-}3VHW4GK0L{m(B+)wWQ*2abf2VQX3Y=wU!O=J>UfI`vNUuUva(u};9= zG-iiD+dkFNJ2YSD8l1PgObtS?!UPUA!=9XimJev>2(DU1ejL4|0T7%Wa-tvZwqi*& z`#PgUL&E?zFca$bSxwjWyf(ODQ8MX&a`d4snyEcBdu!j8`L!#-sZ?V96hALahB&BM z*2M42o$jV>d{|=?--PBVvv#mYJQMY2Q5Rb-pfiYq`!x93=CM6kf}VXZ`;)A4m7+f` zz)`)xYXZtnp0spur)$tTSv?y?(VoBf$%FAT5)QEC4<@z*Iy`ihx?8SAg?NQWvhoB) zS+=5D(_&dL7(gArHmik=M;l(_k!pu?9+uE7i{X%7+%fNT?7Gs^zri<6mq{k#)gfZg zK3}^dBE6WF!VZ#$_vMEn#y7b!2<}>88!)G>Y+{p~!iZq5qX(*mu5&$e69@0OcK+1n zq1W0DW&g(S{LaS6a1V@q@Tay-{>1Hlg>sq1n8#;?$|O+-Mh@uLYZC757G z62SxQ`Dr?;HDzd8u|uly#}WxV)PkTIH(u;`Ny^TmI}UWs-FkjT!X->{@V^ z5^c|aTK?~32Uzw8l`WyKJ=D;(EgsRpq)FE{o&+-ZaQBkx=D zo|}V1PGNYmYx$;Gx7&1rI+(F+LfK->FJ4f6tva13{iU!6M}GEa`MPjpNrq1?BR_7s zrHsRTk@W;fWzEbRqh0m#v2t+Z_|t9H^s&MDdZ93I>F0lDccZ&=r$%YP@O_9E>T;vU z@6|5yrw))^Z_dW%T((DrjxAshH$E|ckOdxLj7<%xY*H+{re?M$OZ%C`qaE8LiSBUZ z=V3jCOso)QTcu-B2!*qtMSK3*`Zuxz!0$&}bS->HBXkSV0$^%I>5#eP$Hhv)_+&*x zhmc8nsXx{gl~3BxII*gC;HKcvwVstjv&F7K-z=DHtkMc=(jd0fnZyr~M`?wJ#%Wiu zMuOMRmc^>l2i15m6wU!YXO=z1GY`!4uQH{8b@e8&|`MD;xCyT&&kzc^D^dGTI zI_`+0GlqHOXU~F<2;tfRD_{9DN}eP8|D>P54ng#F9ehnc8|wO=uWE@bLgOmVZ}i-; z?G>l@0EK9y0X`5dJ?SF-fO+S0@m=~<2kM69SsfaW>QVRz)vD*O?r*;}fxR?)|0f&Y zD3yE69Tl^>4GcYfxSv8`)D8`}F+ z!EG2jC#!7%$vH)xOx0SDr~?P&x$~%ybE=m+EHzy7|foI07ll777vHu!HC># zp6aVR-CF}<4wnnvo9eb}7J~|yQKFMkBRU?Y=9vmNvEm4!Zi-WlL4q=Jp`9D~QH0H? z)T}sTgY)$jCAwnbjfq=FzjMm2hX=p7?|0h{&R;DBec!$NXSQ9tb=?80R@vyzO=qV} zE)w=MWjtQsA>$PRBS(r5&m~}^l%Q8)V97Phkza*svB4oKvK{PcqOFDFX0j7J8O9rB znN#r;A~(wfq!LaJ;2Sz<4O&_D#_VXJ>>UfW=(zTgeb2i^%h*4y75BYpu5#yf0wyFF zl>chCv6)TZ#Iv#n1w;47tlIoZ%lDQHhwlEPC;J1ZbNhU;XQ*lw1_NT5CT)Nf)srqM zzZeAq<+3FzOp+)>tb1=RwA;cSB?2e40%OPwXml3AtxQA5?2WT}5bk;Mf7`hzMrg}7 z|89#GMGt8v-J-GHh?h{J3r2nf|K!v!uaU$PSjoL=*52du)UW{y^(Uf`F*c6_O=|RV zrcSI!V%ySgyUgFC%?|NT$lO1cIEdFndy3LGY3ddy?~b7$n-S1J^C@&+tyauxc-W%B zA?>b1SKOlK@1F;2-y5{cZ2*7?nW&LnVD83dK^>+MfdKf9#a2_$Vxv5(dyPkRN|ywO zSSHxye4|9WI(F1_XV;9`y8%exT3QXvkgpQSku@jj025*vJ12h9l1tvvtQ!S#Rt)S?FGf9by;-x%ohK&7u|TcfMk=gif_iSv1w zAHzRslQV{OQo$=roh2jA$*}4Q6LHU!{Z5%YIw$fY*eSs+iSJK)6uHKqLO`BXc%dsb z)Of1P$p8X!C637U1~Gk5vFuk2KR8^|D~B{Df9Q1e{dHpOyFqN1LIfr|=}uuwnu|(> zZe-;K%LJCria}}zwTWV-eA)zmWO=Fj;&Z$2Z7UUy-;}|j($jr)qp&py$?#mawW-l* znZ-&3W)LR(Mf0FbD|RSN-8}N~Xw6f36ST@XH$a`+mENBlT>80K#Z~WhK@YvkZU6Is zjds0p=~&$+ix`~$lI#1N*-c7slKx-(M+wo5dTi6}h3#P%r66}~svSaaAU9HHeJ zD2?7I$R*b-H`GL?$bmil`-QegWQhz}V45~5WO3s)NB^T5esTd>mgMiDM1KB`ECaBc z=~Tmt;nTy7&`BI1?6miXn!ayd(_Qwk&6ELB3&SimHXA>`nXDf0S+k5#u)@YzsWy4C z%bz)+_ZH49+6e$4fkW>0N|!ZMa|(l@(P>)L2RmQ~fS{YxD&mP$k0PHUrpq&aNj%mf zG71I)HPHC8V9%r0U1TR&!Rm7tD#e-E!*$O)^hBFtnEm`+&p+-OMsYttxX+C0F6#-f z#u$fWctlWo7EP2X`&R{8aKZq0Omq7N$e?fpMLiMBhP8z~ycSEXP-S}(`^|?v+@{1t z8~W^t)vLyj`aS61xdTu`14;nQ5GqAq^M=su%WC(DwzPxjJ(IEuGwoUqtS} zVSKEnQU1M=M!>UecKSN)uHTp~_?1T;T7Lwz^7$9`x2Fc<56t0^Y3^t^&aUZY%QxsG zbe*6EI)g(hJJd8hjx;agCZol$619j5V60D3s8w753hc`TcJN)uQcV+Ul0se?tGM5I2%u{`pp5oTPF^8)~ zdsATBW=AaqBS2$>xdpF+c?BNLWB|!SN^cMrprwVK3JV0^uG9%hM>C~s*a0@JINCLJedL#Z`tREw<$3>SK2w};_z%plUN(H`LqF9+iW=#tOvz0_{9d_{KZQ$} za>PMQrHXSHn=IqBF#a^VW;VjDGSgP&9gKpDZ{Z*Uw(!rLMs)do1su>(N8v|rbveKrKH!TA5Yo4g3)#}~yuG=oE)X#;@( z3So7uqc(H0=+7@14#mfh7WM7bVsXf`>_ISW(+VQ60=8{J=@TfJKg0g{S{k8&;YQsO z7N8+?F2Uga0>Q@cqKzHpX~KMWr|;A&XI741K4I0vlVAJ9KVQ_~{N(#?9~%4cJ==9V z>@U`4K?@W~3Z_N{woi=^LzO)7oN|5Ghy^Ckqe+#_m~Z?U!-OM$9_+#Fkci$K(n!WH zOCJ*BR3K9eI20J>F8v^@XL}&m{bOF`k`JR+3Of6YR;z0fCGV!^EKvrihs`w5}0Y zeqr8U{mQ(reeyqk_t|gFEL;7`Tt^=7yb=Y;KE^m4bn8 zuoKwna({ASb$$G_?KehdOUsu8hwdz$>Lr>7^Z)=L07*naR113Ttqs!|uG!9}$TZAS z!vhl?&>@{yg*F~b1uu^PXF!<0B8z}MNu)yq;Ao#wGc%T^Z+0Kp{vd;ZUo1jsJI`5O zeeb=`ytJsn`Jw;o@MduIBQtldx^HgXGSix>g3<7r&lEtKoP;mWJ4OmY3bm$5y;Z&r zMHjRPYVdSdRjo+YtE zcmC%m`vY*dS8aR9H;qA^=%y0{!2ZKnF-zx47a2YDY<7UpCg;x=sEsiR^S8jz{IgWL zyCJacvD==1{$$_lub&`YYuXOZe`@6S`m4o`?PEXp-l4fwJ%i5GIn$^&vO@sVeW4;q zEfMzQVf@6=oAo{TdFR3&iIQz@u*rdEVYWwtV+hu?#QZ!%#n+#Nezh-wa}@hCbAW&l zaBnoA^I9FW5B=$z(WRgWSDjswJ)EaE|zCTx`WQ65AWVBhO*TM#Qx3(=U@2H?LAjF zt{SEk9x%&|qRuGMxIcrVe2an?aqcSYS;+WRY%T7gB*$omJ=}2dYiGucH9PVto~mv~ z`fTF<#$YMagNbY7y3ZJ^1=^>LEFba^uR0 z>`RFJ{53JGZW?DqO)eStvk%NEUD=tiMo1XB+AB~ZOsrjFa{o#Q_I!}<0PzPP>y@$I`i+yF{``sQt`$p%L%O@Y z;uu4|Z4R0dF^dcivEBPT^N1CU`7Dqey%dRqDyTyYiW*5X<4>1paY$jXxnTpUPKV!h z@yeN7|MuAvdac~{#QFQ5J!Zan(Hd;5E)G?1@7-?r_5Q+qC0jYaMA#$2ixxc)Z2Xdj zCw|7r_-@wt<2T^?9E8n9#^#tNYiMP9o>U7avUq0MLW{&-KQFEFud(46LcpwsU{(Uq z?)}rt(G}{zwKxO#V5GCQ3C=~HrxZ|9W{3?1@1jA&%lLKTS|ZhFvua#-*%`dFuW@Cz zqcQbpsWJ9Qq($c!vu-@To(Chc?#^$NA_sN^#N1W4x;EG$bvyhVqP%jmm)vPT9U!0 ztX&rM`GE)v!ycSLGRKt*-dsOO9l)rCU{yoV)*l{^=D>z3HNZ-@ILq{&Odqlrl@`{v zJdIsZT#9s?bz>>fAu!^uDP1-wLrvrAm z0>!Cve3l&mXH|W_?2X#ZW`?bGsh$25{zFpR*?|jnr?Cq|LCrz_;6x#edMPpPbXe`< zK%iS^BhdGJd&A(OWYYiV|NZ-00>gah%Gz7DT<=>Ah50hDvB~5!$Rn$Z=lOHk9>sw~ zK*+0!5CI@;5WyJvT{XL7gA1YCO>0b&l+wX+(}$KB4NY1GP$zuCap z{jGF%L#^0#t~fP$aP_MbiyEB&lf$3f=oiU>bML=r+naaX*5}Ms2EfX8(~OyO`NmCmuLQG336Y^E{Yc5wdCq2F{TyL$${^|PCISGqcPnlvbw zUI2s*%qU!WG8vcG%gCB!EsrG?L4Zf&tFm-BwDv1c_UpQ}JuDhSVCsVwXr{wt6LGT)ozjjXe>OhJjX!0L7Meawv1iN3 zkEI1Vh0ru0G6<7yRJ15O?9k$&C+=>qj{V5vhg^#m_XnNMzUum(r!? zXN4J`R>zWx>$o|#Ckfp00ePJ55fCXga*=go=jFI2!~DYOM5d6fHgkZtX#70c^!(X1 z(NVyVplN9>W@4-8y%vsLHn*>p6#rZA9ZQheyTa@F8m_bNz zWpQkeFn-Lx=hCKG!z#;Mc@B_e--KSr4v;}2RpM|{P>4O}-a}WjmYPynWl*L?XZG{vbIyp7}AM8XhUQceGlxwOKXC7<*>8? zPd5Inr-3_}i-JAM5-Rp!86_HY*03eukb6zZhx7k^EubIX2SaR9;g;F?7^ z0d|(G0hVPJWa2o>yj9ER5NP?~D-lzhW8B|1^1s8z&u>_u8Bnzu9P;RzYnNwN*5)4F zs8t{74<^s=U&M%Ee2okaef{gDz%1>E46+Lf_69fb-43rFpUssN#r(nM?WV`F>C6Dc zL(frIX4wyQJ^9098P3tcw{4&rIoJK#^@F!PfBw{}S!3d}pZzQvifw+vpM31_#=wjY zOy0h1+uZWbK4+>ddp_18=b_TpjTZ;TK z@r`(Wxd2Y?WtNe#1mkV9eoTX|{oDjQq5=Xk#ol6}ap8cEO&ejR!cQGOyI5 z_|W63VL?x$3b#~e#%`a#c5+31?!=lRIkRXd0D!emJ=sr*zMXL4U6-y_?78}3*YXa1`J)SOkz?=mkt>h8 zb-lV@r*xmusJjL`ah|PIM{HXXy;Izd0+|ZoTFD8TVNXt9LyFjPmS~j9+bp-Fav{nj-|NIwZsJ=^Mu%?yVe4%6~q-pgcw)lOu2=!nm5Z!;`N8 z1iBtOffWYy{WF(lduvmVYW1s+bOqY^cIyYl&0}!r8w?J0?9hm|%hL4?#RheqI+Ge> z4xQ_uxE2WU=)%x)WWEdT6hhF0)dGedivl$>sF_oh<10_Ta!juUqhCJUe406a_`mu5 zA=mee{l0DQEBExcESg$OCCailzSjt1WF2CZX>%Y4Cn)6exs>OpM*j3Y)l3mTH>FRJ zeGeMmLEpohT!|0h!uxH6KB^Srr~mX)G+`3BVG<}t6xb$$g^a(IF^fnj@MgBpMy6L0 z>`^GjteC=$n{+@wVyo>8@N}KAA9PLmjfwTsFQ0a(KVlY_FRfYj^r=2D$kqt7VH@;K zP86ALy%9&!_*aW#Nrj95=Bg{&-aYjUc$)9BG_#Rr<`1gyCL3S}R(U-;a`=yk(@ z%etO80N0Zs=0Fu$Ni2t;)DZKK1ACeqWSKrc&-i&H;n|2sA9mP5NK9zBE<10S-ZJ*m zY-#rTqdmd=Bg+D7>2S#I*r92#%QEy0ZVj2$I8)#j2~~T zh*Pl!enAH-@SxCWoCP3zzWS5xDN*JGf4gTal99M#!T$Qalo=>rj~S z!JYL$+xhTl^dhz4<}CDf@g34`f8YtVnEc125x!f1pjdd$@PoY@-W+Q>%{(s{{_C$D*i0RAWc-#@_g!DT%q-5; zKo6MSDYO6F$@;INm&ZOgc~wF(C*VwSzs`^bmTWv7RNt z>OL`G-Y9_UO~cB{m9gd16DND;XO|9#zRj9t(RQ7ZAuA+<1&^8q-vcX_QY!|f(4EaJ zR*Pdv#Vl_sIpCRs9k|_7g1~XcR=s-h{iCmZs=wj5+rM+ydxoZ# zmj>N()npTPiS=`%ZDIU4yQyQZ3sIfvYvaf-@%$pBr=J)HF?{{}pK&uR=HcHV+=E`W zX()cz7tcL=)-SAn*|+-Kh!PHgI7KCb_YeJ&&Li?V+B|7d`6hVnEc3}$*t8Q zQr`2EKI8Z^Xz_e;-7>)RYjoX}3$vZ`Q;(MFwWY(M7r$N#3}=TP!Y(s1H+1-3(kx@L z*|?n9HuZzG-MrbhgLO!qg^jd zkKFb5?FZ-YfA&~$zCQOrqi7G8*OhvRMu}6ai9-gZ4z6fYy>+%nhFA#3#1R3>T4KvX zl&2EmIl_47<9_xIO^dPEYDB9e+;33WSB$93dI537mMAK0%&KlDq1mKVhzn@3ND5P% zyip_nthzh08DgPmDq7`HvXdjbsQ4b(+-| zDQXdnncC#aa6RVuITCm$#BJ@IscALhszX=YT8FZS#b7tl>t#%H@HCm*d{xbR3| zMCaQzn8b}^&9WE2UWyEJ2Z3mptI-X`M(8>XHZIDi#xgj;&npny3%KF8f<64RbBL1u z9$FSuJG-Fs^&9@O^W)DLfxq`Z|BHoBoM)ecZI8Hcd-1-|B1i0ox7lX>j9A^J^a7Mq z<}*W4=w_us)}-r~nwrSm#Lq3V$tCKAcL(~!pET_ONXv1V12j7P{WOAopn+?#1FK_6 zgwp9$H!!RGzM_Z8wZjje_e4%;5tRIF3esVAprayTT@!)o&haq?*Kt`zxG zBVds^(sl5PPTbXXYV*%I)%xC_e|Gel-Mb%dd$7o_TsXQVBJhxJSzD-S#)Ci12{NdX zji5G1$ORlgjr<}2<-;C<^W!&`*&hDB-w)i+-WVpI1oF8aF*oe#_|fGC`3E@aiJ!h0&&(-9il=n)j^W?Vw^aG zL#!q!Oin__jmhM!uKVv_l;jv2$eowI+D{{GyB5HZ>1%_<8a3@O0F%iFMKQYo{EICj z+mhGH_>z4x0ho$Pz{@`>KA;+b|%@ag~Y=`GYSAG*G7)t1Tr72w1( z58393Ty2k{7vjd-)R5wEmQQ@;ozH~>l(6(n(=WZIi2Nx$YKK|g#(!rH!1mOV04f?y z56DHQ@+dBh|?5SAszgF|nAy<};y1Hx#R z?U4-yKXeQ1Fl)}Xq>Y}8BIYz?`Uac@5ja^c>;-d_%Cak6B``cn2hRS(boaH%5gp*@ zXLdil;3~yG`47Lb(KqY^uipFKZQ~pI`-+VkF@yAU&G`9b4YK4@$@FNx@uQ%}^>MjQCF6hh9UzYW0AN?5_=u!h< z=yli?udC~PXxWc=lZ{8;+_Y(SsZMa`<*)SxA#5cP3|qdo$!&xtTfU`7VSE5{f;E(# zo&0MmC(mJzvcZ8F4s+Z_sSqFIv*OKb6{lQ19Mz4sDp58#UtZBM@SUIAxVzTv?li$G z7-0a!Ph~ACu9rv)#AadWqACGWnR2$dAvItObx>B3B+aSQy&F9LLUE0u0=8bYbIPw6 z_3-fAeD#nZrhaeaFZ(rOee4B&ZU04M^_tFb{$pjM*nh()ffs2&NCcK1g2{FVAtM%0 zNP#_^I+fWDdCyLh(J1YA)fuwL-=2v|;81c>OQXZ}1D%`+!srAEf|D=*)CU)2SMqKm zhC@ym4R(fg(_z~g7}DU{At61;no&|SF$2Qs+DW<2iVq&Qbf7k2Ydb0s(!-$Zhn`sd zTa|VRi>X8lb#H&I!`?Twy5zDhb6gPPEZGkBpiGT<{={cdqlyP36w$G?IZlds#dN!i zcnANT-D!_e|i}B{)nBnmGX5NL((J?3coyAa__d28s}T`n!7nz)Qw0Zb0dJ zYUnPtNF4Rp25AOsSd9?Fo80rcxRf}P7H1G9EsPQDQJXNWv_rXHkKqIE!1AVI0>=W! z0?#siPd8rlwZ@1?>FLXNZ@XzYq($Mb4iao|tD$Sx;&CGBP;SXlQ6|XjKa-eXSjP>G zE!3^{7HYajkFS1d{MedmG@9Q?x^rq}Y4`b`xOE^h!7bLR=|<^Az#i53 zk;Y4WMsWdh*LHER=UrrbavX`hdxK>FFRHA#SRO5w{p6tRJf}N!=#V>QFI)c|eVtp6 zw1HK${OL=2_rS~MDpHGVn;06gtq^R@i_a6_-i~$WA_BzFpw;1YxJ%0CK~Zl23+>Pb z2g#8TRhso8aFZ%gGx(MXbxW`O|LwgCkX+Y!Cib6m?zzu?%nS1*36iFS5p1lKg5c0V zvc;t$DTQ4bRjGmiI&|VKR)i$1U63$Y#n|4G?8-Wyt20<>D162_dGa#SKm`i$*p#T zW*?a~6kH4Tw2g$Esmb{MJRi_DfL8=dKKr8%Dd+o_uK*wK;Lpc6c8Zq(ZBik}ac7ad1))CI#OiB4YYX0%T0b#)%I<_l4_& zLsajvShClGWS18xZblNAY(L-Snd6QIe`6nk?K~6502)d#g5)&-^5|b~>5RqNck%fh zK*$S`YwSo&3MNvw%_Lr9pVXGEZRh!$1HZ}6tv2{qZjM`QPo5~e0y4F!NpB*`x#po$ zIE;-O33&~ee)J{sKcuYSngOs98hH>OJZJWf{-V(D#jdp(l;P=w0;8FoGW|;@{FSie zI$=+HYCRWj<&W|5_jr0HPr+>OtY4X&}Nb$jHnGd;sM6s=GUh^m2uHgQt&9~7UuvfsIY!X{GN>);y zSK<5H1ODS0^!e}N%7pEz(hRwT*MN~n|J>{_0NPJJheq$&eO?vV=q3mbe#lCr@7lez z>UkDnidu;PJ636#^}NgZGEM&~Y)`fsz7iHJ!MPGUL&jE5OwbnnR$CU@7kIWlK>ASh4a5O#LAQK8uAIgso6m-EoeGsW%tpJmL#HA)n&taIOjMQzEu zoXNoARJal#9O8x$CY;f>95YY!-s}JXAOJ~3K~#u7@%EixSw9?_{r(70wZ}v$b)t89 z7zA;aCumWI*TDQu`gFOQ3-3|nT4^x!O)vPaA3j^R&1b&**-nh}&v*tipCpVvK@93~ zsj{+=YeAnpNSBR@D-G{0rE6;hH3xnJ`d|a!ggpAq-+cPU z0w9M*v$BsCOg8GV_~5%v|LC|k=+!N@IicWbrNB};T@6y^D9NsM}P;mO85l95xu7e*2DpvVL}G=`YH*%HWWb zkS&D}on-=R5;gtRt&MxWQEsPlTeN9Ae#UATDEHQc)V-zJi@)*Xw~m%B*T$cG^1Iih zMSu6rCp;2+PYTa^V)2eH&!8IIFwU~l`LwqJ%Ct{B%ZA_;)aVM#-<(*Qfa3s|q_28{x4j`k$ggHu*%^t{(g7rA2@9H^_~ z)cTj&4VOWlwiTcq1}w`8w+8=eu%XFyH`$kLaOHZYE0b#(D}^b!&|*+`m>-$y958Y$ z)^PmdUDv@5HQ*3eaL7yawnC`56(s;#wr$*3AN6+=o;5z5dHn zJc*wEgMa?#>BGC)3yt&AP>)sn3Wv_$e|NX?ICY|^QT?vni`%C1Z4PvN2(92;=JaY8 z*fmDavYG#igxk#-(Ca!XLH8h5Jz;gDDqpH}(~%|90!bJULI7tZbXzrpVHtzd);nO?MsZ~Zxiy%soW0tEsttZL2UjZy zadQ+|2KXiw!hkc{fH8UlaEMX0$5M2!oyc8YC^>esC#h_r#i+E-_evA{vONP}O(X`P zWkc`8W!QA_(rYvkj~@B$BOMv%XSek3eShcOdlH+EaDf83EN79wRyVb@GTZH@p7zaf zizaP<@*j<(Yh8mMKb)H22_zbPrS-FpX+HB^(t?p29so^f)YnJ5Yi!h1;lcO3^5`!M zU7iAKvoK8$6Fr=WRI!K?J+iZT#pY&N_O`5Q#z*Igt~SP}4YRg*=SG*xG`v?}?>0?K z)0KubdMJUq!J%$35n1}Iq;S}P>w`nvmj0rgq;LoxDJ6P~9SaYM0c3}AjyyZB)nU)d zjX&yF1T%mp0(ca^Mie~yZ+`8uHHCd>oPX_sJMIq))^m|%ZpS`?z_)N%Wh4!EM?qI9-(y9UQb*<^$r%#)4u_zCG{_|_f zajzDYP1dMb_5y&>ei0v>biC2`%Uv`qIF=>`HG~8w?c&nNs5aT27VKF`9k%iaZOYO7 zfv(6sG$B(vo!YK$MIh8zx4{<~z^wW-Ht*RM7G^xW8x zk+MT@r~qPHQ3!5g#uyvbtX76`nKz(ab(>Yg#2iLwSrA+18)l>*-~3+Ck#YX1mw$h| zV(hu;yL#@Qy`#ik5du=8%kJMw*+QGED;pfkn;)htRPNtxmqe_4YW@hmpaDXI1H_>E zCMpZIA0IAj@A+?h{u@nk;i>`fzy9b)BPN9}DxmMHV)4w41VMh8DKs+J?zg@2$i-55 zxJdQxz_3OZOdEuS5(}M5cu{NA63ngC4s{57R&l7UH1cQoua#g!SqEAZBa4G?D-jv- znS@lvsFEk%zVpAkE_R4T(~!N~LBNzyN_~E+N!joKg&UMv(w&zF0=y6bFK6nmy-xr4N2pU(UUEAf2>hjMPZy_L~Qs&RQ~ zzFZQ#Qnt}tA<_h1CZG#F0=^|goyBLt;DBRq_^n1S$& z5Hse>Gsf9{%M*pG)Y+r}k&A2)sNPHU1v?anp|||}w}(41&d1$LTZ)GiV~;Uvx*S=# zhF4&@z^#3AoSn}~Q_FIW{}vAbBss9p1S$XsdBYIu@h|@E`#)(P{LR2#IdFgd|NNUB zil}eNSl=mPI4xE3TttKMd+jClrM-KjKh6R9b*^FvjcQi!=68y&7n^*v9LEP|Ja6=a z?h-6I9^rsxNkVRDlwmgvB}gf*hWS@bqP3*StpVQF8mT$+=lhA)vD1t(ArQF$eu4Or zNzNry9}BDV$1mP>XyB*2W4CX8qe!sXB>U!ih64$2yk z7S)6VRO;uu&n+Cj=QpE;wKBtBd;J?OXZ6Pd*E%#e)YnZ6ppJ;L``SJNR?3>2H0df_ z|E&&v5V$o8V4+5fCh|2P`q4l4uB^JZ>I(2*{M$1-VxnJ|jOdPwA)N>*J=sV6$w7!F z2oon?{p$J?MpuiK92&jfT^uLKwb zX`{PlRp%D8TShzPk`K%bBPD7YP;*?-GgCeDng8(qm=*db{^+ZJc1?J8^!2at^L2OE z<=*n%$-4*l7&IC2u-r?-GMVXj+Td7YFVzlv@@KblLwud{-$(MbJo#0e4WT>}yk=h+Cys zR6O-i^re-@;BG)IFCVa^3%U@ zzp#wwxDwkfC9=(MqYiAo+GH!jm5Hup0dOmF{i{3!fy4nZRnIEPuQdbUJ1@WN{Sw^K z|9h@<;F6{f*KO$-ES1&zflwEEW!>+GXgpE+$b^IqgGP8_DQr0PgQ3VY2Sd|xyZrio zO~}5Q=Qu!sTS{=2AT(;QMvaHIj45g`8!HoF%gy-91E2+!T2ktafx%=MfykmhrN%iR z#<3vwkDtBkcRH3*qhl*J^p>Ej@W^6+_e1Z0?w+#nOlpN8G<7;T`?ym4*Om*xbBRq8 zm=eH~@C~af9{*4O>iv$4^S?LsKkd+u4LxUM=;9ROTNKQbQ3?j}&Xuz4!lw(rS6L0r@wPSWDuj*VK?Akl^nUOtn z1Kx;VG{K29a4c%u6qc=)oozrQs#9JYDN!QS#C<=0=fvQ-OC1^KpZb6P`yGj4yfAZj z-;Vh^yTDB%;JRU)Z_AG~BBHT9Sm6QaV70pyJ`ytnlpSrQN{ND%;YwF-8F$ zCd(`n0-K1~fU^dbhb_fVf2p@~ID|nk>+)^&l6C0f=B@{(hs#62Oll?oDLvT+;hIcW z<3=zqAx{x>&2IP>fMLyiuqiEI## z@mznEErTmCa=tR$9Gf0xLoDM?>b&Hlwb#ImZOU_s!7-}I@h_BrXQ|UY!80#E;nf!ETl})~$WpiS(1m;Z%F?u`7b88Hm!i2c zvzklGajA=J1GHAqJyG#3KYF%qgjb#6^3j|b=dIEA|MR;K1U>e{gy>Wz&5}G9lCeGc zMi-}ymAQahVRm2Z98$vz*s?XH5WoI!|7HhB{X!tg4xs=% zs(@$HZF<85QidovA_9y=1C?Z=YKoIRv_3hkq6vWH~n{C zsCL&qW29CxK$z%LCcqQGR!UhOp$!@>vjsLN)#ikEg>0fFRY<)GSxz=9XKu1oHla8< zLzo=X!aVWndf?FOU*j{sG*P&-`$3ZJG2FZ$9CLU_Tia_!IMkMUOBIwuoA&XC>}mX@*(r;e5>R zD;$p~eMl%!0j~k*M_(#u#+R$T)(n6>Cx5b4Xn5+Kh&(tW$WR|s)JC&M&K5LG@i;u{ zU_bywB{Yh9NT|9Y8K0-d5zun{P96D-IUC9vbw|;to9Kfd_B*2&haE4pV6!$150`PY z0W#2OhB?z5wI|Qoy~qvbqm6RR0B~Dksx3G$2(T7u-83Pwwa_L?smWm?to6a6*T2Rm z-{IR5Cxb&X!{s4rS=2)9zR1-lt=vU=N=@b~Yx3Z`R^5o?i+BF=gQNG(CaZ4p+8=yo zoKGHJ>MtC4ciX@yakb}(uqBYonW!A?+$M}qevLRO1O`)PsHTclamoPo^wFU|zNT_^ z%>ek)%P)Hnlt+Im>48M)hkFr>BcHxPuAI(Hn1H|xTndvoHn8w3vVNgY2mY{*$AzJf zRKVRZXp|?^F7%sTXpzxUAPz3|u+iy$i!Qp%0x+nR05~dY2<}?LA)igNl`MPW%Q`@= zqAAK@6VA?QvdqCh>T62Q0qA3N(Ler$yDt459O_Iv)DDNLUB!nc?j0&84yASyLRRa4 zdGf9$_-ix`v@KPdt4$3}Tt3CLeEOUBfAg9T`|Azk{Q1xJKRCO&@D!)8)yDGgvP~s= z8zi|_oy{AK6zkNi>jYlxn)i=xqR#lUYpjfG1_1upKR`yP7(SU0{Y0Gzj{|_40mg=) zdPN#Pg+vS@N+H&9T0O!vF(GfBSC>d z-6lX8fTa~yT}wU7=?vdq&ZW8Bx1<)?jN2v#Yf2dKuBa4>L>7bCB0>^zCXv-K1K`A~ zeTO<{hZ=CmckI2hy`?>K!`?`(-vL)B;OW53GPZe{%52w)?UhisWB{)VuxoLa>AdUO z%Y8m@e(&PH*Z}}9#07gt;+d&5qSY4aW5zMp`SS^y-ZceQ2cISIERn`D-|YYvb`$`6 zzyFGp6v)G~S{-;>$x%~-*NxL)dxPd&RoKMVS>{!NhR`4oa;*pC^P|Ft^cO#HmeZ)XXKcBm>JN z*A2Xk$+Ey<5V2TD9iLSo4;w_E{!;JKng;g#S!1GV_9tRn!pNcX+Xf$){B-{iwK&Cq zMS)<7GILdCn_w;VGH?@wHr^V%IREs0Z(i)kIRE=U`Tebuz*Dn#bUj$vOtIeS z#=AqVb2P8>Yd9r@oPki__squQPF)_gW~x_Ze%cS;Q2=0a>a8EVI`s2|J~)xUQ$?n> zc5%emD@r4-sBVxJ%tB3ex+0`HT1c3Jh=HFla-lnl{hlx$7xZR8qvGbv{nQIAI_d=E zV6}&i&J0tS?>4a`ICo-_*8R_0qh_k{c4cNuCY{SDavYuw6rEPf(+!zI-J%d0+D}w? zPLbr8Zd_yT;&(4cw_`M`XCf zYdsMdHy;|!4A7B__Zl!gWaHr9$z!!Ewg^XuT9Y+GJe;2QiUuLe5^C8X$#Ms+%FkGL zGUNp6ObV%!GYaDChC@pp-#gpm?5PeHN5nuOWwh{KwU12<2&8Hw&Ou26VA-@5*TAKKwi8GzaZC)8C+nl!VqZHx-emW{0g{%;+VOAM4oXe5Mk z6EPmx#t{N?ymv`$Fl!{~rOyt4G_~zk)xOw({g($Umk>JW#A?WpiZYe4Mwvsc%{tg% zy0X~<_YT<|$@d3&(h9A20Y^9_go5a-C6mJiLQikME;ytQO>P@`U}npvA!!q8XbC2E zfo$NETp61d{KDP>jMkmS@Wn0v?=O#*E=Ow`=QB#wNGZ{|fs)5e4Nii_`P=7}>Z4LO zA5~UWPIWEBr?ezbAN|y|nV;(pfG585rgwoQqdzYN2Yjj?ripeO0$}mH;YFK6Yh_lm ziK$x&7ln3299$?mGZ4ptpBVH)S5^2u)nq&-aHKL=9rt`&ed)JuT!xJoj!eiKrv``O zE@yCd6LZT^ykBdwuj-i&C5$^Ua3{$sKWFZzw$-f>ysNEv7%+K)5ZNJNDW8k@9EIc< z)8hE&%j<_j)w{YLS?n)7^!|O_W#TYe#Ksp`Y-TT)UPcb1n zGR{*Yd92#+9=h-!k94apMja`#0%EsG3}Bz-B-Q+oIuq)}?wRChm$f$YbKL=eU;N#d zU-mRLo?Ou6iSdYdIFpxHBXhb6>{(`L$p=unH)tz{g~h5c01T2s3oF5y7$zzfJ!z|G zazKU?JYgq)uyf-QYIrT!Ug#oIyCT=vxlndJFIGFPSni5V!jUyXT+CyYF(he8#(d^) zgL}(r?Pn_?_9aLx0>VJmo;X8fIF>~6#HqeNS~oj{$+DTD(jI@4J0iPGFr~;!9p)2C zItw!Jxd~m9OVB&H@S2gxN5A<%XU6%tEv3B|{^9T*<*^YgVUtRhFE{yd($yDkh^94W2_ZSTqlUmYjB({J1%Lwkj#N zQthowD~^0L&4&h2A&|(EvGTMSuQB6@)@*zz3Vpd$zTt#genT(_riOtBOSV&p>-z+U z{nOp9YZx%-CCLy=5E^BKSDI8?xfyLQ#gY$7v~D5uRltN*EU1dkvX~rZYW;8slV#Ge z4o%+M{lNSk#UZRYhDEn>4>eu~CV(Q-NM#^gsMj>3kG|wR(V21ni@o>Pi^g-pv9~MB z1WSr0F>tFc1USM_n-$Qk+VkN1)$zhobWP3Ah6MmJLW8GH4ZW$22i}Y6p$|cATLQ_u zF|CfQNZZV`tolJZWvxE=@vVGdVbEa1JLElZPpZ+=%&A|a^g>ZYes2*3#cO)H+K%UF(4&GE01*eS)xrI_q7I4)?!XJ$)_B&xQp+exSX7`N~LW&^^C|cyEOyyLzbN_6ms5gg;jq z{8!cR=QLkx0wEw!j!cld#|m>WQFGvAG4v<c&nU>0Q!6(hFH5(h%OYd3zfyS9VQJEdfZAq;NAd720iRnSfKT+!E}bX^@mPG{@R_xOAnQ19?Rn>OeS4RN z>|I5jaB~IYbStd{IK)uzQ!$t@G&xgF;xSNg;yZ5V@bZTC0Qr}3CHVjTuOD?+3&x>D z%f|!(7ug`*uAym^0BJg|+Tg;G2E%570#)Th#dF^g0ojlMcG*ZGTFOq$cN%qeTQkN1o=!7uDrJ|@WLM27&RBPlB zmMKpgtD)imb(@1EQjjD*%j4iMgmb62-*I)7;>vTxWZ65y-6kkMG~eI#K&8hUVg?FM za8=4??3f!!sj1>(w7`WtObzw?w})FLKvuhMT={1IChng46g{L(<1xduT+A1y6{T;n zS3dg-O&|_+pf!1(8gTd@6xa4fZ}Z-D>rjr zQJiWO)#b_@!m3WLlrbWy3>!DzlBD#XA6WWAS6KJ^{BS(dF7fE= zuX9?h?m8#+-d6?xkOROQ6ZkoLFyg<8(wB5Sc4k6mTy$#7hdr;spk^T|} zwnS|>)U=*h;QXXpk8Ub73arYmz+*cvZE`#_B0J4k?MiH9jR=?$z>HPRrH&X|gh#p*`jP+?D0;v>o>z!l1Vv4>#mUmJ_%&=%75|h0q86e=N`wcl_<*iJptWSpTQuWp#em8-h0!0Qh4V z1pj_kY^!K>=zWMEn5WTDH_l4fVl|x(8)SNeJ!z^iS7?W_kG9zn+bb1Zk!Z`Ycjik# zj2)U(g}@>=h*T+x$Nd65!Yn!7Uy1xBS-tSX4$6vma`W1uQNJJWt8=pda=+~oP6xeM z4e=ORBcx6nj8S^3E!q?*%g8ZscO#gH&XOoNtm4J%fLkspZRgZt23&Y)>Brb zPh0iq@ckF2&aSNUv)*&P;Q+uNM9H+NOIxPc+#_|aABqfKb~R8hEee~9<{GNTwiRG? zsMA)NAh+tZuNv(Mwnork=NE)Vs5!#IR)P~hu;4;D2>hOEI4%er5xOv5-eA_~{F~*W zN`Vb7^mDi1$NPc6zDj{Rh5_75B!D{O9fAp6hc4VCYZ>IiahX8n??y()hpvt}34Hm;qBEo_zJ+JN6iI>;$Szfkq^~`H7vA|zfsXPG#3N<+hjRaFEEHIRwSajIQ zLKIE*R>KKHMJLBT*STDIts98%e@!3d^Y6^>iqO2@?RuV+JIy576&nUO2!O2=7>NR+ zRElHKwI&Q~+bJPYk>FCDabp-$adcwr&VRYCWErwUfotxq_IP{3vN<9P1{jc}714B{ zChq?6#EHINEUwEqfBEjxj`__6C@Aa^{qbgoQR`F3l9h&m_vHkEWNa9E)?~Ljd2ZQ$ zZ3ABz1WYd8FB9@yq~!Jl6xf`m4Kk?CmK~%V(wfv~lvO zc&+tbYA3{C;0)>}Q!&?(7lx`>PsU@H9AQL_7b|LGp^-kyr>1}hN;us~xG!d8|K(oC zb(k6~Bw~mNN;91i1_DA0Op*cAEd@j-!iti!RLa97j!$pBqcbIA20=4+s0D|tA!2HZ zj2T}L>drSN778=|VF=B280QBbocWF3p#mt%n<~)_94H+g3I~6L<;?|vis&1__2UD@ z-j4Dc9sb0|1_1u(pPV|iJ!b0g2a&)1f~-SeTaXkuNQ=@?>onVrG@B#PyAkAvF zZIWB{=U3^l(yl2=qo!r*&IMvk(+K)z(o5a&K_=XavLL{h#AGJdkWlG6fjGydI#vsV>xM%? z(R^rjz%5IUQw{2i z`q2N08LMK;+1CI76$(j2K~#dMAtE#1Ik<~NrZOpH(Yk8njdblK2b_YhyAICw_3}wb`5Y2c4Hdthwgir5<}v*kzAI1rAClKFH+R zc**YAI3ECgGIIG73&RDEasqbRU+klOp~N|s49q1EUDNe5gBKRYcpR-+3Ua+?x#8D^ z39|Com^E1r>CY|!Ob-CS-~fDa`rT1ai-VwHv<4i`>mHc%90-dBBqpJjmV<^$h7v+4 zrMNm^0N}LxQqHi-V;H<~MmmHIqd=NnRYhR6n|@1EplkIBy?#cU$); zDNwI~0q_yALFto5CQDP0A@Mg&s&lTdjyW^615xGW!VANbjKN+Qm9%Ce3Rjp&a#Q3Hm(qHW~NDH z01ek!+I^z2saZMr+x0n_Y`IZ_JT>P~%%J+xu`U#v|P`zXsUn7hMMo&AE&@8d4&vASTLpeRKF@yl z&{Wwgcwsyuf zOLXM$>U7}epWE;iV7(`hZRC#fnajbhfRUXaSdO`fB}cHhkx60EHh~ywc*w8s)&L_B zCt1xL%nYYqW16xm>3$+DqJY$0(vTocObK zutT`&nD0#P3OL)l=-PV{N=87#YX%{Y{+qtFRib#e&^WKrIA64OhytoaTlUfGdB$sf zC)M~+ymk~p5@7}MO!tx)Q&Do_&$e{VjIH%ME8o8*0w50pgbMGP6>4HT-Fzth{%2UKOG- zt)ZeaMmLwml{R_g*6PZw1>;eH9}z4XFD@khQc+*%qySYX4*>@$OaZ@K5RSW8-KPxL zA9OjcW_nO-H54(Rc9;mao}9IGa@dLE(*x^ZhtlJ}Gr5g0I5b%LJ$riifT?Y3aUw(l}3XLiyLLZnv~%22NP*n^9aL;qUPKe1#-a*0^g~|D- zx?QJ64bFs$`h5RwPsYdUakMTt^u+Wt-dtGQGSy{20u+9`FA!6XO8&P+S$%Qr&TDs^ zUuK+l*uy0iJJ@jhX277dXEV*@&4$!xwIYXAC{J(gy*aR_eXQLU0dTG0Xu>B>c1{$D znX*o<2~iPv&-~I(JBWAHnaPD^0+^|FEgj^kYpbc#L9+|~VWkVqSzyMNrb#u8c26y_ z=k-M5u#-kDnslo11QpTAu`Smp!M)n`hi>Q*5RJJo|*ra+5_Ck1vKFk0DpI`LN2AyX#fVp5ADrUm-h+H_RpI| zyH@rfD%&7Ej@8@%dy-KJo3&P+W|?jYH_It>%G(E}Cx%)h3W=R|5Q|JdR=h69W7jys zXfj?37W~Vku))x1iigT{oFv*8Fk}A*-6fZ^sJAHn%bL+6!j4aGht88_7zCdQX16h= z4-lC+aUgTzA-k`95=$6YV)z%6$V~7)F?z2~pKcs9#8ubEa0u z62XptY90RR8$FfVeg(MN4anJy2)w~L+oemTG9-Nt2!})9a@e#WMtc{cg9%SY16yLo z7$TRae~Cj=_(Y}VG$LvJAIfCvz`_b-$QmhwTyUbmcj~oq0Cr?a8slZb)YdyT&Y^bc z?PREKTZ8ZScez&L@8=+X+hTHxQ~1|Cm!jkS>tKg)HfOH5Q^l%!PlwO~?;)PUT)*>R zrDQ$jO1ZVrDAaYM>j0`ceau!%5Kbb`5<(8sP@eAe+-`K>f1*}^>$w^K<6j;g(OmEL ztz@KTE2y{>f|8y72^V;&8tk-vu}foTQQTL!1QbUP9tFV-kea1MY?%}j3A0YRel%IE z`4c2mC%?17&?tv7rCPFg(?Yb{4&?h*l#KBZ)|5J5&%Igsov*~t?jTydU=p>%#6rV2 zVw_K_i4%x%UnaER63%#pjBz1P{MknYdp=Qnfa`t0IJ;HG$`&h2ij32x#(^#k48UOW zq1`*VxDN!~FAdMGbU9G%<+!f^to=h2@kk7tQ^6}XOrR{Xf=HQRJYI46k+5Wp56;!$ zo;RjcVacBsdk1cq!^R-^^2@*2W`_D;Vv%2qJ#rTF72n+X&GGBK2c3TJ_b&d)4r=HZ zLeJO{y9_MsW6+RtbaIST(%dLwl`1g2&( z3qB>MDnp@32NSDIm&z_wdJPaIo*G(uCYDA^^Yw#~%}4762NH{?g=*`}s0Re5IZf&V zO95>D+2zo!#^0MQxG!z0TlJx#NpU0kb!2A5Qna~Vq+Z}Df3R*{c=F4uxBj`2>tFfZ zfAR9~Zx@U_H?_HN|J-JWW4T78L_2{&?SmhMZINc+1X6f`I7>7+Y{L5J-Hp61Jl3xQ z;5zQ;AO7g^k;o>y1J@p@b$JlGHUzE>QmA2Xwz}Ie^#~T?br%yMsXimAdS&3g2+2xd2EvuRkacMWz~@6#}%D(*ytH=JUaw+^qaFDSUdhV$FJtBIAVrMF_R+&FN96 zE)Rx%e6%)PfJ({Hl4#-0)y#qSssmOv`2m;unAz=|`zU7a^<2}nKARioFKuxSX-*%b zoVh4xUrQy5c@?CZW2RNej48gLr+@8d3qf%y{$AAU9Jl_Hjo0?9_nL3L0Qh(R$~MEr z{dKJ#nkBIrP#Bx&D!#<*dWgEZf$2+7hzt5g;lz4xR41R$Axfp+^ycnGol_YS5YTGg7^+a+-Q@#9n zIQUbJpAjV~S&~{G=f3{lXI`BPHfmqg>A7F)bGKXo?nWLXms`(la`#Sc?%HEA zJyJ}N%xt|<^LkpU5g;NAnAB*goQO<%BH^&1POgo*wp%U$@WL<%UM{=aDkeK5bh1k& zNv|PdS`s1j)ay{J)Wew5m(Jfi^1TFf=!yV(D+%1WgdI~*XHR|3q6<%cdF{q=8+9Ys zf)EIqSd~$^Bvol|X+x^neH7>3{u^n>`FroaKe5?!7FFAAB)}TR`CP_~@^y3%sE{i& zmQ${XPiw9Y^S#Yt8At=n_(eH?>hwcq@& zFZ{`NO67B5k>4M=jH6T|+*l3I$Mx_&j^F)n&;8+uwv0Wqz4qR^Lw9*H;i%!ndeuxBLNR)V z2K1GCeqs29Me<7jCil#N&#zsh^y9deTY3d(4}vL};%|EMj%~1gkyei^Fug^x*fWR( ztgr*AXpN=86bbBkkLSo--&rCWwCN-nV<}LjdAd9{jgO z0OSu9t(NEC92?rCjRzdT9-nai(Tk-;8XLl*no%qUVx}cWuwEz0B+ZSIgv8LG6alHI zuL|UXA%$-T0<1`bSBasx7(j8p8WJtPci~g^OViywA^tAHCxlJ|moCAiefwhfjSh^j z=x?~7jK=`rF{+r`J4K;;hK|Pt^_=Jvrw2OJ8g2A>UC;4uX$Z911*N8Yu6F;TJU{YY z*TS$(^=_ZY5uawOfvqT*si;4z$BC{nWdP_@?5_cXfufx<$*NK??7tPoVAhq03&xqs zCi4{;3Q-6W=vq`TIBkMesRG1H6NE&!9eZ;&oi2WsUF9ACOjB#_wReChRRtz>i&afyIgM)^J~ufK!dZT#Ui4s*q~^z1dH>FI7_b zbSZ^Tg^Ral!tSFSV7K~j-F7R$)o$n?p8Nht!ouAbEPrH{i{Wy@cE?nX1V)l-`7sE% zWWW{0!Q3pU)vR9K=vjvUUmGN?uZbN96_#FUghyJ|Gm&7#Sdl^lizOJL1Qu$M6xf+? z6Mw}Gr7&v=*s~E7Kk#GIm$yyA?p7bHH{<+1F#&+ksPgJ_*6h8K7HXSDZK@AW@cQVq z9e6fPHZwv!swgl;8vP5>!qPy}nZK;y<`bmXR$?z#J&<>D27?%G!W7Pyv@PiGRkK-vC-Qs2aUMF zPM49!EA4-r74ITxe=`6jG%!IGa5ANBGEG1$GZ5g;h2YNC!I?|I3e|Y%@FPF{?BMtS z%IT1G!b48OEvt9>BnGzA{ty4hh;-EM2{RnIWWsPEHg`*29|@cQ>ezOv zVb(B!fT?l6K(ozq-jI4(8`SnXLoGEtLL>YJ(ymBArTu~%zzIFZSdIm87ZnOvT>|q3 z81=Nm!bD}jKABj05^34eBDVYtv(;l!$0Yt0e7e~I_lXYxOx%=TEnAbGq`mdej20C; zI9HwWq(Xbj3?Oj8S+c1s3^${3=o2W(?-H~vNI24;glFY?>If@JhkqwdgZjfe9623iHN z?1(FdjJtK zVJVd~>x|eZ-wxy*Y?cAdHOzx)^FLf6Al201r_+MjnUfZnCcq*98cKjL5s|~s)OyTU zG-zSQ3ADo}dnSOw`ASTD^-534J@cy|xOTYwy$%4pH5dd~qVSg#OELo7UF#ZkB|R7u zI=W;fFy~cZ$qPUl(z6m{GbrLA#>a}z`92uSE#}>U^HPkhj**Qf;0;iOjWMqE$~M#4 zE9-55k`9DUG!2fl%?S1!CIm}}YMw~2>k{0WhQgu*Zzcj~DhSL#K3`Pw`2z>O9c<)` z`AIw0-}?Yq`9Pm}^E)1Klg)u5-jV?@S6+fjsRF&eJ33Ht4+>zTbwh(NLkM{ck(q!n z5{T0_u8I;(tSrTry>Rx%Y;;zMk)$iewO+XYNdJR&LM$GYGECY2Ljx#9A)-K(r3i41 zEEWMOA+4C*yJSM&0tXhVfGK$10dS2Q{;L4!a7sfqNjqwH05IYk3PL-8 znjJ!5#}FF{goXkuHimlxXSX5ANMpiJWfoZTFXf3a%bb#=SA#@phyY1-8rYGZ0>>6I zjgKcxPt3XXlaZNB+6rr(q684bivs32`WJ23wCDl{8f$=8+|l^V0dng~kvqKgH}zw` z3V;r8Z;MUp%Vzh1OU+tB`9J@|^Y?AHgmD;vY|jw9hKe0S#TIFvK+qTjz4pG8D-K+l zX%Ded$e|RP>B^D4^cxXR4*mF^ciu?z1-To)@owswzBB-(O?3@JAbvIY*M7MFKVLrQ UX#KGOX8-^I07*qoM6N<$g30ad4gdfE diff --git a/.svelte-kit/output/client/android-chrome-512x512.png b/.svelte-kit/output/client/android-chrome-512x512.png deleted file mode 100644 index 58bc4cbffcf157d3b847fa7971259fad0f40a210..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 159273 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 z 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 !D?Ru;}|)M z3_&&@vC|Pgx!gtETFQ0nufYuE8K3?+>Ui_CT034sMj) z;EcoVpQ>Jx!&*eD14wQFM0Wq0yM1uW0&SJ`IUuv237;%0<4x&gY5l99_f_1-XnmU)ayA9K$(BWfD@OrABMNigsAMOZN zhz24l8hj9gV=8hXMLMs~Mz+7e?^cimzwoV2a2>(YS5xeJGIsv+C#F8Uuh3cphIbra=bqz~`8SHmh1$ zJO6t}qH+76v05yji#=vRdX&owbz)R@R!9Sc{3Rv;wgS6VdWc!2hEEXuIJwo})h+;L zNUQ^ceF8I>Vl;DqdvmXEo{`ul#fIRM$2j_90}!&XO2C>;)ziegLaz-TEr2JCX&*un zDOsY0fN1Vu_rF&PM>b{IEVx-b#@{-=R`Bu615w6@=YsM5H!bxx~<`PC?C66;x=HDjR05vBV)KAzuL1F;4PRPc?ixsXboyl1Ie9T zdPHS!n!yZgphqn>A#ZR$)j6mN@GBmPczz0}O3uf3v3%IL8(!Dw@7pnl$0=Sl1(b^G zjZoG<)aUw!8~eQXeCNpPa>PgJE0EkNIsqtuq%i1BWju9_6O)i8i7-B;b${i1OlzX2 zVZ%hh(O^~*G*B7hRq)o`BeRlTo0#j{P{|$#s;;fT;oU=xuljercnvWoS;wz?8BNCl z-zFB1u*b-f{Wt4{>mHhI8B3s#_#Lr)YqC${*`zeB-=-o`Ja=t4lUMMpv6|F?mWX>! zV$$M28&#iK_L{fcuA?1DiDE5lWWiz1Q$=PJA|jQ^!nRw z!Yzg2dT(fm3fI00_08&|r!MNlaj7$P#=5>y>PRt>MkOx78-(^ELi43Lrk`2lzX$}Nc_HgK z*l(?J!TUx4$dn{8`{>!#Ptn2gpo4<|idPQ>xa~R}MuE%6g|Lsbl-*B3dz#SkY$g<7 zve8Z@1v=s$0Z9-#e4twWXGE^-BCdsqVF?;!baW z+V^Fc=P#?sgda9Nygp8xkvK>5ehFe0l6yIVr1)lt{RI3fl#0A_Uz=m2X0#>zd1vQA zNa;^#>raSjS;gM8cp)P96T{m?fV~BoDV7qt0{axG8|ye>ZO&tyR~hUWUHg+RJC76h*O-Snm>kpTR@ z`RZc(CMPRc34it_%J7|88lGW7n7t1)H-gc}vp_S~q-Y)|g^3vF_y2S(pK6MZt&F3X zwO@YF4zJL5%N=GSuVkjye~n>mZ@2A* z;clbUb`m{@m6mp70?}UddnON^-EaQmBb8se4vZsSNWU?%s2lHa+IjDX1H*q82WUR~ z<&3VkS|;PTpW8H``}hYE@l<6d<=6&ck7cO4R71;9a?C=YZCL_;td%8q!l$f^t<-% z^oMLe%U1E1*7o;NDAtU9L-L#29sRergvxpy;v{TColg>6$><9%i83ar{pt=!oj%tn zp&%+;J$e~4`M|3b*X9&_(Mw?_h3^~JzxbU_Xsa^8F*M*pC;cqIrcm_)c!4Hh_aNkQ z8P`toPyc(LvwaQsyKY)<@WYLL!Xn%=IVgu&{9NH^W`R&ShF4-;rIxJQ?Ja*f39BIM z@87%9#3SmwOV`JP%1n%;w*HWA{+NaJ=ya{H55dE>rK=ZKp0d0&46*y+tnO!x7s2n_ zz_oNJW{WN#LOQ@3cxHOw)M$pcZqpzY%Zv>&#GE6k3*Hag4f3de;X(dKwB_2yH?;z0=9aouQm$Y zJ-uvM7=l*-BJdtV894vAMU=&;M^hMAt(l(2LyM5%E^B}scf2T>OYftyUZ);)ra$i2 zXB-25WbFZmwo`;c(x4Huj1XW0*E$DK;ADkO6FRLyNDR&@27ZEIUB4_lm@@684h zn0@hX%ySQ2;So);oKxfa%TMQCtB$M`m2Dg!{M5)6j@?+i^+tbOuc2nuGIGSS9Y(K; zG)~t99-x-YlbI!l{m_4{?&d#NY%5zJPMrVkml%jF;!Fjb% zB*1fp7n&b-Uq8Dq-G9f+R0YtxFUWBjqU$n|j|qeS^L$A@J4gV3JU6mMQ!A_Yj3F>{ z!K(cJ;qPiild-&f-Yq#~(U+O9uaUGkFB;AcZw75!X;~_C=`P=CXK>(1Q~Or^-UjKc z7fLDfkm&5HkNlAjV$L{bTSy}QxH9J80}b}?n10fA1eb~8hw>UF$^br1r%r=UF` zzY3PePR2neLuLxXvsXow>;)-oFxY#&sNrT;qyESQ0$g!opOIJx`<=5|mOTYYXkoK0 zVN-fdCsc2W&T7fQcpdtd&1y7lxoHq@!;SnDyrb!& z7eLN_CvH1&{_004veI3ld;dS%>d{;8)&K7WSj)Acww;OSIfq^eMLZrhT#s-Pe@9u) zB9{neIShv`BzH4ghuqe|Z%Q4TbFo#!Bjg`lcf`q3*4)s})9b~T&%rkJx(f>(_q}tluXPFS*Jhu!8 zz2;tva)7gLZ@)c92TL1lg+EEdP?RDSa+z~y$C8ceKL08fk_CLVVurr+K228F*Ac@{ z9gaPqx668DKmg#&-7j%u#;73k! z;imzw@$#p>&rXtnfMhA$Pnt}k|?0fqzQAiz&7hH0u3(XH#vnY6h3w#D-{9$Ut@F2jbYjsp&J((IWO12H+@@{E%;>Hui)R`S>f4>zkEm-o z?SQ-IhG#jRd3r0&hshvE8=uXgcS^C}8TFR8ejhIt?WeWJvV|CMljD_>Az_dWtuF&u z%s~2&Umc&STuoJpduFFr^PuBM4U`$o`ZBipy7i8^0f)jE%Tl)y4xqJ(Y_j2*`T&V_uf?h+?F`Db}>w=fG04$yS*H}mXptg*Cq1%Pjr*l zRirpPXbMl|?cUnS>2DULZse)0oX7ELBt1B^oE-b} zQ%?siv1TgUT*&?YCw7dmqKex^L3c&pcQv2)uvixz*K_CQ4!2;~{i!{FJlq8{uRBW3 zr{(_7|CEmy@^c7b{4lf2e!F|yjDE*%1>H=7diD8|qh5D~JZVOt^K|~<$n>>wrG}z>n&2Ou<=)_i-n)g4 zmniXs-AWiY8jkt6|qJuq_eVe=~eYa!veKmCv!3W#oJkD z1l|!MxuG#bzwcuW1d1Y+;O*`esp#~_`zzV!uOH?I#Z$WOv@-U7ObG$P55o+8OQ#AG z053oQeMAZf(J&Wb256>(A1B9r0ytYRZ_3?E|CHrMnGuXxQs|gHxFIf~)7vy)c&@Vb z!DM6m74^w_><8Bjz?B&656oU^!`E%Sz+~yuU9&zCK7AG25DC40YFe9g?i=kF^fU8dBu+lV`^rc3VY4-HKB%zwc_zHth9cZJyZsy^6j@7|W zJM6>!8_N8x^gPYH6q{ynxhNf_KjaCEC6L`rRK5LILdOs73qmht=)YP0CSomPN<=G%UXa7d;lSrU;QIs!kRx}2vwXQiB+-X1pAgA3ZCNwp9T@1734 zy^lmTgZD&l_7p>ggfY0%_-)PoV40U5VPxRwO;lF+u+D1e6v%he!>lE0F|9D{Ns473 zb=y|t0j0v@@bd-fh(W8XK)`*maZ@G$kWVki3(UpEY!e@oT3t^|BrUE65xv!;Xf#dV zGl1svkv^5#O2T=Zv&`%@Kkxa5Dn2S)C{5iP%q>CwcXjJQKp;dQNylax2fCne@{GDi zg6%@V3yePX@UX%ilMMT`-$ar1&yZZuKZ`wzlQ45@C!zj(X(GS+=rW&xX#)3IQy&7nZj!nKH|^p;TP`~4;trF1a!FRq;2AQXSI7?Jvp8+)hR}vS-Gfc zwD=WxTe_%zjl=oPOofaUhL>Kh&?Zi{Jve-4uXro#kc<4OK?eZMU;ldu#!^B5xc9#{ zIWK!J@Y#HLPgIsXC%3{o_%jPmOIZp4D8}Ow41_J(1-6gA-p!d(>0el9m0jFiRpJ$j z11erf#y#bj`V)Fp+hAyW($8LCCvSZ>`Mc25|IPh;ZcD3I$6Z2vvadk_>;4>F-2q)D z!rO}!4A2@icz+$M1#>=8>l+reP6j^+NeZ83lU}h249WO-_rKj}S!t`wbvTNqr~*Y= zYGl%lEf#w1LDqXt`=uRty`3E>m;z}^lwpL;oQy37zw3MG7yhF8zeYX>CK}-jcl#B! zUp$?N5QYtGf2+k{=E;Df$PYh{yDwbwS^|r(Ft+;^EAw$c;)Q?&qNA>RJCFQ&`M%;5 zokrImlaa@|O=j^1Ky;P95-`Ih7(*1;_Q`2?%vC*Ua8}cI`4j77^xfbvhv$*~_tq)e z9VSNcV4OdSrd+*yqqWfWP|d@kp^2{*)wiLc!o0;+IcH;a8zsi8)soOe(4lNXO4zAQF6LO!<$z4N4lEIvv- zkOH2q++7OhzOg`zzq{;HXNoY-0{8qY&#)w8Z53?w3qYOqx%&Fzz{)fLim&+AczhZ> zyEdjH5sPSX;t~yd0g7{vk4lPV=!daCY0YJiOkaBNZ&mV2+QrmUqUULB?UKy)UT6D_ zSRuD}aS(cA=d2wzKkTa0Eoth=rv^jnPOD50X*m>bb>$|J_wUp>{URsbmbt@CfbRq! z?ce~B7*!1Vl?d}8*W_lyYdwsReB$q=><`SUIXQyJ8wc!0h~NLzcGIAP7G5+1)lK8! zC++YjjmMP`kATunVIL+e2pcQS!7-8 z`j7j4uV-LEoXu@ZRqAg@*czR``BR(ior}@yyBjT*u>elS;;@j90>gt6olIusW9TOG z$CQ;K=VhJYkk%ZNYWk##wlwI=hDlZ4ivlh$u^=WD%k0Dd>E-z{YYWKpy<@dNUD=_^ z5S9hZR?Rc|PiV5Aj9P650o@i+lC4;|oX5XOW&)>bKrRPS9Sc+*z3R~zvXw7cd3pvi z5A56aQtBieAl3pNEU?r0JE6%|AySXHV5eYj1!gYo@0UrAG=8rhWf&X-!6Q>2wuViP z0KiSS{0i5t36oD-9`&DxF`}8>iG7t#xM9yE&tzm}@d0*B5M*@*H9JEH-mZQZE|Xo1 zn2HIms&9z#^7~8!RSOf)Y(HlRW;tdL_WU^Re)sQoZNUxOCMvM#j49eD~Xtas6N&zB`{6ttVl%B;>Oq ztEkLe5@1&M(L;g63VPSC|2DhRgHmCM2SrN8 zIh@#mBgeW%`MM^72D?dHrYjlJVT`#gdQ-2VF+kj3K%(t$81d)hK~dTn2IiygofASn z=A(#|7cG$!YPs7DVP}I@@6JTGP3cxM+Tj{tfDdBm0FpNhzf(rs_rO(Z0F}{`W9SX=_ zRh0M09R}t2;*roHkB%_6bmvBlt+L~RmV*?GR$g={mI@gSazhau$zBcx7<3^pyyM;S z+nW2|NqM}$Z0n_|s!6jFVyFuSW20ulU84+C{pK7!B`xj8k^<|vIp#aR!#7U6xygy> zn$$r*9EMvb+yoNj^Y$%te%*Z!pDEckp$QI+9=WglcUUC++xF5dK9N%9S2^4#G+P1? z>Xy$LLI%ClsEn+q48%5!I?T%aR{NhxWkqx1VHED)D8}4|f6;^2M z6wgf#Y@~REbO3;v)r}VjfVuxum0GhSSp7(_`T#f zA@r}owpV>7W*8VWSmc)iy`gSWqeh+beY^WRMfk%D493?G^dO2E6e~+@G~%d-h)RHE zI0m~j-Xv9PhVn^+x>GB2elGOi7`Yg!pkG3s|3hOD46oj*MOPE|EN=&I1){e;F#SE# z&wKTq8Q+_s&)eRPT%o#|MR4pJ_vTM^oa2yxA-p*6HdrHfq=&ct)mqQCJaV2T{EBvn5Tz@Bf-gcR4N@@GwR})(FVlig_nGSC_+#Xt1mV{i z&^|;*Q0Db;XS@KusN<7?FzdhcjqG^%w$gMW;yMr6`DJIdDb8oGi5HF999xwVi^(!@ z=8%i#bn)bGEvja1bZ(s8QRjD;znvTIO8sA@Jd&pwGfu3Hwc*ntt@KVpoW#oD3?5f= zE?gxg9?M|-<>ua9!|(Q&vin|bN&UvJG?zZd#_itM$~6*YyMd$jVLgwpmxL@Cad%BA zIC%@8j(=>_@c70$-iy-U{kVVD8T6A=m$-QK1yRGVPZzC+ln*Wd9h3}zum)yV-v|l37_nzz-2n%<`!C}NYwGg`CUBAo z9YQ-gFqluzqN)qX&YKlmg&V=O`5)yN|u*lD_-`7rjS--n0|>^tQN zdIeMJD;YsbQ6`zlu@E;eq2)-OwDm2sjc4uZ+bAIg<{*WU_g}k2{ zfcZ{x4>?Oyd$R_D_VNSk>13WSngp(Qj-|1p50^AruKn0z-e_4rycN2~Vt@l%9WReF zFdNr1di`_xFI))}DjkO91MU`wq%4^eCJTSlbC*eZ5oyIk3cg9g>eTYu>*02!0wtb| z`BlA#E4ztqAb_}c7JuXZy1Wwf(<6@O4+_15SFvenbXzRAy`sC_-L?O7`as7+DNm+U zKuV}vVV%RI93J}og7megO!O1@A=tw1RkW4!wJ6H?YRR1#WNl{6HQFf;B-?6uTmZ?0 z8=kj^l$e)Tvcmd1)z9o8c0e^Ox_`Ap*lU%52{z_oQ#w$~-|n4`wPXV`T(BvEd?g&V zvPw%ab?!w?{f(Fdb{}y2jU+GRuP`DRe>_L%5xS1Am{B@8A^Z0wA2b=Y*KzHm`}MIj zO$QG!k<099It0h+$!tr0n^sVp;i4b?Zlqr)P5L{&CF2unhZgL5O|adMX0ecp(wg9C zK8*e3&*Kc?a2icFA5h-&{B+@oN@&}iZ`-|y!qhyocxUHfwDDJfpgQI0+*kuPGC{PQ zxazXl%Hp(>l?r;6X<`j5E!3g zchybq1u()0?2<VdG9Vg02$snF?1v z8`oTlZT##dg;EZXVVRIF8=G#CIY`e35~N-2m2MOc0;~IZRTJ{3zg+qEgw5eS%4Gna zDO6b-`)sbOFIxPSFDw4ncJ!aV5?FuWHfmuHELO%e+LjQD}?nARU`h^cp9@?7nV>vZ0NeAbR=cqc$Y zj_t7rEslf6GO;ec(T=2~&bVqJ9cSO)*!|# zxlJA^NfD{t@NG|;2wVf)@>$hhr83v|am%r8- zlN6#|tp;yK8>Etj*r@;h?ReKs1pMf}0J5=fiyj~wO@mXA`9SM8Ef}RsHsXTiQPs=y zgT$=<1zyg1-#NZ7%&-e~m{=34q>WK~B|&@l`1LVj#BuGkhIPcS)w=!wFZ^j@3Umm^ zlPaEQbxTk7A$Hn6_egc9@7ye1(keq@9^Ul)Cb$s z+!rgUYN^f%=Y+XC)e-k%;!vp=N7DD%z(9tH4_+LvFEc0*(0E%jQun2 z1Q?L=yH5#3eggx9Y{|A$Z9_OZ_`o>N)=Km14++H|*rlTIVP0T*6|53Pyc#kd=Gs5F zp7Scm(?7Mh#n@k#>MhT=fSZV{%G@{cb=sbiLHGfD@fq1(2TkjL9BcdmAV`7 z?|%ewNCif-kk`@R^_3r_BOmi=KiaZtzYHHj3gZ0;d=OovFh$eyfHha+G`+ES^so|{ zqGeoz$W@o5;nV_}v}!-%?|#DH9l)XGsyf?JG!8uHH-5Ly7SP|{@}h$i|A3YtMGiB1 z&QEfoA$MmvP;CaSGJ?hOgJpVB^$nTCwqf=bh;I@AE&d(|a3(V)fQvu*(WKQv;Q8oi z(zX>#NN}L~HJl_Jz^4?5idQUy`&iU9-A~n-+3s2FFTGZ4XdH}r0*~wBJNmubB#Ng4 z*JdUlugNtFlzv(D+H``3Vj>M*+VC}}TW8Wvar(O(=<{`Xpyap~idV;s8vJSZga|%i z&JaC7&H=7!7=Tn&5HtXYZ6b1nwR6Natc&^?iA^B$+fp;2qc$G3&~G(d+vlkKTKq~m zUB!lq&c^6*jbfh4Bvdw6pio6GPX+7#Wvg13+8x7O?*HGlCkMp#Ayq=>IWCKAjM)>U zM^gKXgjinKz#`06D}!tGOh32UI=Q{h3yo)j*8beE#C$H8t4cLdl(*G|8xmI{Bl zN{=;a{jDb4MQ6ghsjQ7TeWZoyh<2*gvE^ZPP;^wpI4A@t;KCQe{22R&9V+>l9KEgf~Pr66J)Qo(<4 zZm?378w9|_1!-|xGtWFgslB$9t;NLL=R_$IshU0^H@Q<67gN!-QHRel@$KlWRYS`b zI+)YS{$Pzzy&b<>rF4jImxE$oJ%AJXJg6<%u(!bE?#ro8`QaDNqidLfR^;Wuyqw_~pA7U;Tvm77V z9cC?*Gd5%^9|Lp}VafY|!WCJp@-PKIzoMAw$Ef5xKCqkt{%g6^zf%|BKN3^5i71V) zKL|aSc=q0}HEjC&n=mH`#dyI>g=I}^w| z>Ik{G&Q1kGpyU%>amrx-c$3h?bvy55B%va<73omTY{_hnHD}~;cs`BO5i!^d82@lq zH8oRlXe~}eWvPB;NO9w)=iRMHy0574rWM8%#n*C=&!cw@gTn?X)Og zpZgE?YP~Z7Rs6Y*8O^v+zrMYW2AsKlU?WJbySJ2^f-CgC7GLik5Tw3}9eU3G0SBrG zFg;!o2Eh<4Kwmw?fC-@B>~RudApmdS392G^0^cN_nBo6)!J*SGy6~a8-{-FPr*u9N zYk_q}%YP!*VbZr3Qcto@W$NOV2FGw+6NI^8ZT)j9pF6M(e!$x4nK}i3Ii$9*5GM3D zz=VWF8yF`5O6tm|oIMQCTtBBOc>A1j{LBcRYBZ3$ji>!wdg=-wETe3mF92b$Ln~<$ z5e93!t3^s|Y=HHPD3HA{FNw(m{hL*9GO}?4mP!Z!1$A7N{_i~R*LlQHpMinc@lNolI`a!nV71}=lF@F?us!P zmHP3%m9f>8S{-vgqD%gW5&vP^8QS;I%qg0Ei8i@3Ib>)?^n{p9udFB=A5O`NCoFNY zN#xd%1HS^E92^$}!_~3%;lGm{xCQ_Q*!KY-V$eT!4MgBRqF}visAX{IK|#So?2Ue5 zFzwCeWcI+sDAzS^xc)IOZEPpWho-e)tlwd4;2|g=z0k;qubeSrxUeg=4TovW-~4&Y zzQZndMH|;#--v0cpruY*tF7&EznXqDs4%YyR0DoWy1v@_kQkz!+^|&jf#$3}#gH}$ zm33s?^62}MlXOe`8(ODNS41wI>~4GR^F<5D8kP&v1?YVpH)bBKGmh9{UI-Wphs6(K z(sO0Lbx5+=Umu1_4?e&qt)ceGL;snpAy`qPPZ-9q38@Jy}g3esVO6$5P8+I@A?d!=|qB zPDyHlADQd{W3tlZt00-n0PkvP5C?5h7@YrdNBO8KA^Vf>k#(jb^ACwdJ|mS6!lrd6 zB^W`vn`h9i6@8{?=m8aHGpy2fESlm^q^}}sKWiaP{ z`xG=O@Z>Ys6KPR1LNS*b3a{O!-%9t6{0CaQYw%+lby zM@&^)TW4Q69qU}3HOAVT;lU%w`kwi-dPd+Y|Iv@K&^xY4Fb;W5N6gy|4ho&LRw?8t z;-%m6b(jwp<@fK7PJt*B??-b~Uq(81$fcD8|Cpg09c-1(pK!lH(7Hizw?VJyTyA## zg00(oaJn@@ea8><0#(P7-b5%B%~NBEnsj`SCpK=iQYi~_NIq)-QSBe(_~#;(IS+Lq z*web43CAHI1pwygy*D_BBNSg*N{N}kM_HAVWES9w-0Iar&@vgYoJguaDyI(U&|(6M zd+!*Vk+7YpYTQ``DPIfKR})VwTz#<95dK75tE_joW=0I_S&>!ykYM~qEh)x?aPE^$ zP^7fwmxv6alUj2S_S~v_ARc)HeAGue7rbq}7oYiY)3|mjESXrB{62Jh|MWkx0vxWm)uF848&g@1rVW3s-tDcJJ0SKGEb*aPwZj=*_f`S^C!8ThRhZ=roc6!Z z3eQxaSfujP<=wNrOOr^_8Z!_uPi>69ZxyOkdGW(!MmD$q#`Nf~&;`X`TI1tK$v;8= zi6)`;88=KeP3N9ZbMP7nVDLp`pb*W7}GxY4{igj?3t~fc-*$ zBu^H0Z77uj@uVI7^#LzqZX2fAB1j*fk;?DZjo8>6aIkhTJ0^l0+nlEVCpZ|3y8o~FSyMy7rpJd8u?+0c94+SZvZ#r6s~nZ8s0 zKQx^MTU6iIhR+N`ryz}#NOv~_2qH)dN{FPObT`b<0wRc%v?ARh4MRwmbW3-G#1J#@ z{NC&Oe}#R{+57DE-0NOLHN-$|qbtv#HBGNlxhB`kFpqnV_xHG2vRF_2ofrKAYRU zzAL4DJtlK6s1`aqq1?kvF<6vMb(&Qq9~-m%h7kF8k%j%tc?Jw8;6&uaa z%uF3Hlh@`k{6PM;#J;ZlO5DJ<>h9uxa$9ldw0+0>SLhbI(HQEdoG)rBXmS=kPb`Df znD?HF6W??WYoMFI|FDjJ3J-gdc$lTW7GNk=_y18w*t7uPbR|7#MJ*lBL*ZV<;n81v(klFbm)2XCDrHdI=W- z$&aMc+hlq3*?K%KI5XTHN{W8^g%Q7jK?)RYQ0|AD$bV|7Xd-d8Hh>sCeCK^DVfw2K zn)}QmwJ1o;VsSRn%Rf%m8nb+5*fR3 zb{65X+w}FxicM;DYF~(nFq&pxceU}C^a9rwlG;C@e8(8##>DYca&HfsJNjo>#9a8vqQx;IaAHw97Oe4lP!xG7Dzjoer7*PE|r$bA(yd8Z5;Lhv|N zvfZazIZw*GR}orLHw$iPlM>uk!eXZKjX>xf_TXEe<+LZJ!i3m@7{pQ;>9$L((~4E8)gHbL zX~9$6g2wlf=`bnr@34P2sE-4%SU6;PJf8}|Z^`Suz!jmHk; z@Dh^V0r)pIAh{b}DbNT3>hve&Q4toauRdgZ_KPvqlBB>clG2o_U6iE5T%Csy#Bc19 z15;WKzM8$tv^AUwO+bV(g3SysW^APfKg2>&N>g1q@#A3+(7 z{-X$g5jVw$!UnZhro!Tmin>{{|!yGczN;A#)d*xA) zdew#*Y~MKu8|HKG^Wpwk&6K@=6~Z-MioS?>{}VT`Lgo}FcERFPgR%P7CNCQTKB3R$;Jk-29;0|1bb1 zja;lbeDr4p!p!xDw5RC!^UIk>gzB#=d4Edd2?q0px#L3^I_RH%V4$LKd_`qwH8vul znjTV)KdhMCQnjKjHM-0X9Zubo9eM4YE{-4gi{*nq0tDnRDC~B2U3~nI`H6D>K`_1X zEQ2pYH9t^yHPk3G7j%(}K@8>H_7^NV-I6HbNgz|YvoC}J8$i~BH)Br?aDLa65*2d& zRnNYn!98;~cKA&oe_@|W<=QJZ^{zPymVKwISBpzz4EW_Tj(G@vU9 z@qmsu={y7z$OD4gIc~}NfiH%Tw68WRMh`2d4G^nF=_VT29V1+HE=!8#u*YFjlqkVu zb3RBrr=$o852=;sLHEiqH*k`T2wx6N#o%0Yc2ED z48185+aa#<;$DJDR0>p1pPxJS>r)l+=M11{dg@llH|P77D+%N125k(E!CGZP^(D3; zb*JZewr1bA0YpMdStlY<(mkd~U{W-t%WGBawfvzFY~qJRg%Q=wA31Vj- zO!0V@q*?K&U&Y6<7d&`m7w1O{yG;~i$iw;tA8pi)^0o=>35GlL!{bd!QeH0CuI$E= zc#%b~=;n*Rwyj!CDG?)Vj%iN(sRUNXm{w8|Pf*S;S3KdfRr!9^>ZNny7^VftVC=RY zu%xG+>!=S{zni9@gNGbE@!%1SxStzMIhM0L)8-yH+76!8MhEVdpLG|l`F2e+Pb_AHKa?>O?>JUB;?2{#J*j~k4hoP8#<)nY)cBEeL4@Vm+FMg|1g|mef;_!|q$Vavf z(z`C!E^=jR-iu$E3&~i2hj zr)w-GxMZtiR64CV0IN)Il<6sTFTB~%B|iAYrBs%2SGm7h(6oJoVIO~8h%L`Jj?VD& z9WEcnAQ#@v2*!n=K1FYQUKCHlZeL?ijkEHUecm2RK-!Kzi&RK_tuVxps`}W+N<3lP zY6JiQ#%Q0qFB(mYw_;auQ!4owfg0fkrj_DXBk$sCO5Aqg+)cStOw@~!{P><7d?b1` z5ooA!wK+GM>(6X%V!cM9QSE4}u!JoiZH~Y z+5+IY>L71vaTU_B;Nk*boifubQhaAhy3gn$G$&vANaW*Nf|XAGCo>1LeI4x!cJglh33RBeY8-wZ5I)8G0ql#9-RWz|gwi2=_04oP^fpRfH2^?J#6eMcHA_ zHG)zsU}rk-$aU`@+lSFf4p?G{iR>tX|LZ5koprnn_aOwb6uaN=<9^GchN<~+A_%HX zYqDhotjX+Mv=2yaGP7)uYa@9ZMcVoa74-GK7-1S zaI{^b`(+s1asR#m`@o+uwDT4uUBtZsjD+j!6mb%qA`DHZV>!%n#Yp5Fu+onHGHQj? zF@K@Z@dZ*JpJRg=72}_s9c=V74qtyxx0d;PdTM$sIY$|$CAIpJNeU#9Eyl4@F)hL| zPX-a^%$w2c>6|?6Dcb)eqS_1HiQWL2hjM@@Ie-bQZ+-ivjzy<@PCCSVsmXnvLNF`$ zoq;+^%Kdk~p1}^fEqkMy`yF&yg4h{HTT^A@>N@W?gwtIPK6a!L6a_GTg#~}($~)^7 zA*+^Y3^-^^hD5+IF2X1~jV^#*V^PS!9ET_4Af3jDac&8qkw zJg>|U<5F5YNaDj3sBmdAwwV;UjU=5v7T0`ZVsH94!eRj7)u^RCw95tK0o2@2NcHeY z^iD|0T@qLc4`7%$xDE`EijXqew8^ezP@Tfqz-~Fj-wlnqmXcPat+I$awKCt$sVebU zc?DKwjK4D&Eju)N8eW-#r#_9RBjkSfT1+{Ffg$VB&2w2|o8F1duF#_F-_24FyrY<9 zw6+djwB7BAY(vZ~m=({en5{EjQsrm4Ymyz%1BSBiA1!N4XW8nzfh$#kGf*YgqmWQ? z>m-`mrL&5!>2~MBoLeT#QJ(vQN*Q)h>+|?hT^Rq=z6<2hUw_eL8gZtANE5Xe z^B_hp%ym)s*%A$sRDyyC*lSb5^q&1_WXUNLx3k8{#Fady6XP1_k7TZHR+c+b46IdM)IM+jCnF>z6e7A(NE&Fxfj5oaVap9IKv$?gBmG-tE0962s`Ti8H zCg}59&L_kFg!77-3c^q<3|Kz`y0COKy&}_}dKc9{aQv5|hvkYX3VU5T9-?|e5{Hef zMZ&>EI;C_w-~tj!qh!8Ok{?sKy<_uZU;DIKYuoi@ELIl2F8lUmz)k8iBw%n)@T<@a z8^zC_V7G%uIeQS7fpW_%-!;E@A439KZh62BE1m*=Y&vY>_;>_c52MfN{Lq1^Z2Vey z^JAO#yuOjlzB9kT^ZP&pPm(-Hz`XprMcK2J0CJ7I46w?#j;xhqQd zh{2qyU7W0;OVRbxlXQj1_3+XtTUl@{NPKg1t>FA%03WD)qa;#0YMietiyH;=$T z)0^tp(yuC3sHB+z>x2cB57~FV#wmz5%S|LSwF+7}cQSmM_e;1vcm8Wf#3v$xPjx0p z>$rA3JM7I10PE0ColWCoD0`>LI<5tq)bC3w75U$tnA3woYjjX&<*IlX5pK&m(VY?d zC@)`&Ji5#I{wEmF4kL^UC-l*RlqD*Jz$0*Tpz@BgfT<8sR5MXjBcHm`F8e)gpU&v{ zuc5Xz2&X)724)zscvok}fV*NlCI{7H-t>Nx<|yOjSG5P>9l&oFgszGUj7F#0;QeIz ziFie>BNtxWrj=IY^<;;^L6Kq#R=Z1oYx=Qs7pomYKTjDW$1V75VJx;$YD zU{rM7fLiy-(-=PnK2pOJrtV0L2uEztY*caw7f{|9odCmeKnH9;5%X__6SbK*z6(v8 z_9W}QJSnGw)M9RidF$(C~_;`{BRIl7audtR%_^OpN@cD?43iK{~{VesE7XEzdHx zI~|^Db8inG;MFsDQ@=#_2a>JXZnSi%xv2n)%V#c!q+7&ZG~Hha6%}ve_f^^F9ryG8 zw;^=wm@}!~-eS~;&%aRN)zkjz&xT==FhU^c&REU2O$D!o72fCc!w^&{tM=I*kJP9O z;BnSBsr*%$_%`MTLyGEbB?*aL`*-7_P1`i3!ZuaohnCBJbY$n^eCX+4xpI~~r%ju! zH>JzSyll-O7{7c(1SO6z>UOIj1NG_(CMBFa-gOg@>eiE}{cAM2y1JiI2T|o&B}=cOZnTlfrY@hD^C9sH-YK1F{C}H1=B7 zmJjj>6RnIA(b zau=b13l0lhD%6)IVK=ss_89pOfbLV8XMVEOF{XM+Nm0NY6>M0XB*V|FIQYP*j{NYM zy@+hq(_GOeLr<_)J3h@RMAeAku@OE-*R_}r#UiC??yF7{vBD{5=)GSsV82@c6= z{Fvbv!SX5DVnNIKF6tUps@D7JPk62#Bs>2OfkGgRTDnX?Qlb9O_qv1_!yag*o;JMy zGEzRM9OKoj2;|w2TKJ)23dbZi=~sBC zjV=lX$Q24?(Te;5OT3fnq*tX6nm?L(w5GpqG#5hK5k(BAAjOscX*ys3zy&;PIEnBY zJ%SL*T9+l)N7|e~&b7UdDggfl#NWr+axZi##Ny^WRqzpqm>lQK=v6ma1yj!Rd>L;~ z)lUNDbo<;s=P(so@+Dw-OFvkXpJn#w{Zi=&iTOJ(=FzuQkMZr(;SI_@b%!V3cpUA$ z#vmsso~vpL=fmHWT$S|kGra|r2X&427qxs#Q_CfHge5<8Snr+C$ZdKdl>B%$h=_i_ zMPzhY@9IZnZjM)>jhOD@WNJ+mMm7sdF7MIn*oh&(GVH8h3Z2Wu&@hPmaoFPA@CSx> zpD6-Q29iW72v5coZbM7j=h$@`NS->lEfas$P>f%zB8PNh_bR%5NCUFQDE<_d&c>e{ z{^VUsFTesO2-u1bbI70R z1?adtQ+(&8NxOR(rlkiaI*VTgpCE zBALi&7rnH&VQRbl_219sAnfdRzi8b-hgBT%eWv=Iz>DdWp8h=ZjB+0R~f5ZoqZoU_!p#c=hKwH_$ELLKG?~Y zGb5Qx9|9sc^;E1xfqI<3P0Ca|Lq|G#y(-2p-ZcCW)0j%8v{WV9bGk~NKVi>pHYU>C ztS|{3mK#GO*%uHk(OQ$=oGtBV+sR&tLnr=8dNhaG@9TTb^E634h_AYs#F+oa2q~E- zP#93IKHpx!*UArxXpuMdTVE~j>oz5`9<%1TiunWEL{cf*?r=7CZ8LV_uk~kCO4He z+4`$3h&s%BR`YKYEcudm%m0(H#RB#Yb|XTLPB9Yz?n-FT?cJu`8IH{D)l^#K;L7TW zQ@M8>7PN7g*X`$uqN=P~N4IE)gV;hGe_pY7`$sbeEogN{cxU)hHH{?Aa#Iu3%gNoRV)8*7C$8;yo5kj1FgC{7of2zFOZE z%XG1`2}#z_7_u*XnL&I0MDD`v+J0$lE@y8QJZ!VBBswbkt9C1Mo{EmI9lyCboW`Z* z-C9mP-fI5Wy|{fYi7;GRsU<+Ibse(gNw@u(c`1=yR#68lkfkdg(mrea4y<$`?wbO- z40UFyojiX+;VjLq+>oD+j4}I4-k$TafU>1iO#GdL5USjDyzJ>MYt43MJs7UUnsnTa zk*MM`=Y!Y^1>H&PzwOb(@3C5B+nxnGPslbaujd|)9julspY1@cAGBk_vrqOI!1}v4 zdakVGQ&)b@Kj{t{e%G!rq~bsbvug{SVDCDCB3?tgnbF{NAgqVtt3mk4flG4Oswm^9JScY^+C)MdV;e2lSZmsowXq- zWVGj7el&p&>60PTKdFdQdB@EACP0}2*s+?*zuU$MC3bjipBvn%-F30d+I0gtn?NlA zfMFa~3EBe03;|LpnP--7VOIrb1ut|`gR#E2YXJdyKOcxMB zf0IfkNU?3SWn&N%yFFOWZjM`MR@1KjPiq)*EE{xiPH%>+ie$ z{W8@C?o66AN;6xb(c`~)cZcTPvrIiSlPz{Q`$l!R$tuBbjA-zZ>`tzMklx4@1u3Wo zCXNP-Xio(GL$aph5cEGb1we2z6R;X5B=`+kd(A^NaI=n0wLE5EWNM81#aBB?SbQf(00GxMK&wa9%Vs7&l#*=W&2N#j*g zprm=frQx<0F1WA@p{ZDm1{4D2{yjAP5QFsgWK^d%kl3-2CDwR^V!{YJG zh@45t`g1GP%^#wu=ffZ)u{%C|769c z60V1*^sF5}(VZ)!SYo9=xSXL>*$k3cLT#lTsa^2I2Q1v%PdDxIRdUBQz5Bs)-!n?} zJq$b8El%l3s6E=h5W>|oB_dl1ac(0F(+cZz-fkal75vlNc6C7pcLag@K`WmrR8e>s z8e1C2DPp%eO7^j>>SsJZJff34EV$}syLfl05Gt~#q4}~#vnQKv%Phq=Us!OQ)&D9c z=$HJa8MGwWQ$NvnR#|=0sp2?B#S*pDRI?B&L^@b&`fhBz4eOu!Rqn)51kj-rxxF^vy_TWjW*>rxtl}+@HFDF z2j>DCzRvFH^Qx7>S>u#O#s%S($w}a`wJ)Av*&L}zW~ne{sf5VET)Cc!M=2aK8a1KK z@(Ta0@D;k>tgKn9?hAzny2hS1+@&YORcTl9i3cxUX+wM{p&<|8%W6pC`&Xv@=}|*p zQ`tAvBC2CxIc*#LZ~*ZbXJPX)Ww6^$cPI%KnDJ@lc_fgmB45dB?rUyhyI9|_@U8=> zCJcK4->#?4{d!2+;#bZHH}gHzVCg|&;TqdvpwC<)Eyp#xLnTduo16U~^78&ah(Sig*@W><$;`rs&o9$)-OUf- zZ94BYPe+5p6N*gLYfU=p!l${7mipR1$bJ-RHKi55q4}UtA3;8uM|}p!@@$$BrJkwf zO2$_i<=qKs$~_~2p30A+M?&`w-Gc#Wx65e?O;=BLX&Ica(@`GT9U-{p5wnF%PsebI zJFj5BXy~bTKP%RgqwNOF%>G>-fG~HMN00}2<`}o2F4umJdu;$o=!T1Q^kqRwZ(P2j zn+N7r!*n-+Fk-1xz{y!BGS83_{lwLp{9twkQz`^h-WTmbB$?X>DVf^4X8GN~(V`u` z%C61k!s|J91ykYumIKRV>g0c*X35?&;S;gWc9DtmFtDvTQ@d4!dt7#WWON-_;|?lt$`-6-sa=WvuGzI`vyP zhd>M9qZOz<4Z(yTYj}qFAqh7GUyMk*ovB}%9KZ@X{}(KELI8O1LTbRJ?oMrGFL# zT}sW|$3p(*00Ec44N2wRXFp^xY6ot@>eGQQ!hR&l-bP~#zrTVeieFK6&5OI2mGBv`I6KatDxLX{fGii~0abETQ4|?=(bGKnahOH&+jj(oB z)4yMSTSG5&r62Nn>c+R`w9fL+!3%JLzChl84`)%Veaq>?_mZ_X-W)tGFLwKUBf5IW zG(I;EKb|x}GM@1%6#hy(YY*3|gt+53U6cM`OX5)0(Ztf!lBa^NmW`?p>SN1ORn@mz zo(7s1g(m7Y+A~F8zkPXtMt7rO=&P5M57hMa;XD{Lq>E!Uyz3K%i_eiHD2~yLa7~gZ zW9(kd9e^u0k-JLfcZgkg1juXPnmI5V^X(937 zzN^?Ds59pf0E;6CHR(LXLg{+rSU^9ZpEms3{`k)|Xv84T;46y$=VvJ{_No)tXNUwo8x>T3)z}9KbJd zq830V&ry&=@*M=f`8vWs!{#1oA8TeeHc(M{ahMs@7AoGG)9`ivQA-tl(I~Qh3c0^6 zcs|3$%872a-_9m^Lvj0N)b-7u`RA5uf#gG7Y^k9i1mhSI{Y9UP8;Z8pG@LuE4=6Y| zo<`wa`7(6=dbWCFQm^GHAGk`0s3nRoC0BP=!wmnW79e8c7r>26F(YL}po|4~u`?p+ zfE=ZqXu$d~Zt4$}d0Q<%z1RD098B)$H6-vFBA88b`AcS_kB4jAh(WbvI)E6Ej0l`^ zuW6QZpEr5@XntyMwy0C}B%#2l#yRCxU!P%v>aO=GOS62@?3s;yjoyF*a>7ouFU$VX z_S+edU)Jb5fSIZMA;xMuc=>`l77sc{n@_>2vU&)nFY2i2L{Z|(P~dmJGS=V-h~heO zp}EZQ_D8x;%x=1k%Tu zZw+bv`~F_UIg=+7P(%t^qL_aKFzax@JC)+_PM(A1HQSZJTzfd?Og;}Y+n=Y<>)gd? zFtG-v7!_8CXYX)d@caPYSxv9pm5n#ueI=ebCchkwj~hfvY~8uvPU&%fdqyQn^9q2w z=HUwx->5S|$(s(tziOggTBH#78%}82{L~FR(ma_{!h#Z+({6zvH?GeX;d+K3rE-O4 zKVKi%wQ?v&XvfOjc#`7AZIeX1s2;8+`S1%ZAQR!274T(EGC8YU_Gxz)y-nu@YJ?W(V;qOf>`_gK&gBU_A?4U@n0+Ejo&PmCF=l!M98tK z?(j#mK9b(OmnK;2e{bO?dbaLE__IYr(W!^bxg2(BJDQ{gE%gAm?BjpuA@3s)to}^{ ztV3vUyYW|C!Ln3)8Ti^8EaFzHyRJMLh{onZ{xgcg^ZHL}yRBl0H)2v~Rjb3aY)=^& zu3=gF>zlNB#p1s}koE`g3N3`e=h?chGfXyZL5k+I%Oyt5^>v@V_Zm#nbSWy`4229g zuaLmZPatE(B~3A7`g{9j^}=?hyqtlbx0Ee|?>mE_Hu)36A@c9aU!$nFI{H+%UNlA2 z%BTQo>QeiVju-0+`!=0kd*VRl@7UtEy>CGzW$=HGYvx}c{$A*?X?r8QZD#9i`w2)r z{n)iBF(c_+)t$%(O-kjJUfZKsJw4nnLV3)?<*- zc@FESO*q5okCEkoD9c=GFT(rDqdzto6*g%kQtVO3iU!~AJTV4Cu$Eeh*LEs}mLmbrwgEci#NH~|f`fM6kN^U78{8@2E4Wa{lV7`@f z{6kA0rOdFEl074zm+?l8vFhWpxq`qp_|K`2dox)lN6N$V-pZi9MT#l)h-v+BygK|O z>P0eFpLCN)pI5#tq1%ggumC={*Esj$6G0+AS;yK z2|s1zjqu+)=>6)iKS0ct@7?m;=g1#dO*QhzHtvsJtkrWkdFMSRj)MB+cQ2nk?Y*Zp zh;)mlnm*+ASBJVQM{sWd$*)D{Ef4iK@c9gc4DJFR)k(gd)+hbLqHoe+y^~sLOqv}s z8O0*834BWCrg#m*@2gQM3ipGy>I83;Eppz_8Cv?T#JhmQ9x!JVKT@!xiRT1GyLF_J zq;@D$%Jfm-0QtGjjoEc-;W1`^8d!=_uP`dT63j+>F6EB8y!UkJo2!tV`AWeiD*#lo zj%)rLAvvn`y2@6Vl~M|^v3UtZ>bXaj53vbCCZ^nGwkIc876r?3zOM{aBf-*?*MsX7+f;V1VkgTX5 zQF?+a<=h5v)ke90r%P8(pVrZXJd4i-+9UkRsMPBxWIda^<||=0c}G%uVVuodcjx}4 zG@Ox&Ld4z!MT(}tC$Kp;FzT}`Iz94m^r_ku10HlSg3ZVb-7kW1>&KZfvFp~Vav5|& zJFS$3wiShsm4&xU+*HM5Cmw@YDS+U>$} z2vM>odir#4XnnWijgM#={c#*W!@;MJe&jfQ;U!6q^6u$=f-YNN8Sq2{a?7Gq?B)AH zX#oFE3!tAe1cI)QtU}yTTjjkOOky+6Vz0EIGRm2-;rm2~az}mjBw}psXHh{plJU}o zROoiBeUZ~;yg63pnY^$CaCor%&4eu-=(7U(S5C`&pq=q}hQOgf(1 z&M|QZ)iYN#n0{<|bY_Y(ZWOf0y1bZ(C2&|gJgnHQn{=o{&-4>4PhS@Jas)vXKYvid z`1>XULFkfnj~M(*2W_6VusyEG7%1CJ-gIxOJK)dRg)T%g=VR zL3>ZSfC%`Mp&J>DYIj4i#~@CYn_4+OhT{d8x0W(~Q^8JxRrov=Kn3OmlX?|5)}GweMx!aW=}JDK`~PB}lqLwDRg zlQZ`4fP4U$mf+7W6J8N$yO&Ys{!RDYm`*b7m^kijGv0cKiX`0|{j0)3@I~;PM8bRm=R`{Y`GX!M%6;rqlpYe(@q)`bP=x%W# zzt|KlzXSo43uw#mJD$rter)rjpo~pkKI4U&t)Ff^u(XL%)(Xq&sT#o&sj`V7WD0d0 zt)h!2K}j*IJwq6l${3O&)eVP2%c7H06J?yz> zp%uxxVm3N4NHukHi&N>xk)c^`yk0tt-9(=^nR>+BGA9&APHkAJ@_Qm;ozRr?SN-M@uRwa_qfLifvKap5LJz zf*Z)`SFFv0@@QQixS_U=5Mra5OSV=U<#&RPC^q!Kz_n3{EjzGMxCbkL2sdEgn{^Sz zYC6Aq>4x-X5>raG2{XyeVbUKl%Wbv$1*ZTSI?Xj>YWQqlMKd=Pi1FYp=|^if{W<1`q}tyg^7aN{_t(NULNP^_+0vT&!!ywCOU2wKQKF8 zbJ|9?NWltNGFDL+#~KE)53GXZumQlWxnANg5#y2LTh#5?Qa6*Vfiy+ffNlkDZbiV> zbkW|6y8&v2`iHq;wedXAm7DANHJ7Vr<;0)gB1CD-Oc>PScyrFLl!(D+c+j@W3-_s_ zPtx1AOKIgiS0dYQ{Fdq}{pQ+cNjlkcetp46f7In@zM`ZMd8}=&i)_M(5ZXQ ziTJkJ6{bT3U2Tz`c`}oX<&_-mnOU*R(4`J|pa>vCx16=^e_$;NY0U_crt8+;T$I(+ z=Nta-)?cw4f-Y*ZWehT-%x=$y!}}pPdhx*!sabSi(rOJ8{TouV)=J^VKV~fY{Hr4h zSRmfd+*H2o+h*JC_MTKk+v#mN;@cJcy3~2DNim+$K!A%B`eo!Exdb%deHiR`C$qp$$YCbSy#aIc zL|wW|#_rN?Vm6x2FI~gN#&$~q4j=PVNJD}@=HceGe|;WsYA(>?Q%V1JegQx9gHO2> zXdHJk#4Jg66QWaBN*N+qj15v}LFz(+7($tz6%$q4of12i4{1fHu7A8= zizjT7xuM3IOtm7bdFs!P3pFebF!kY`O#rT$>w`jRNy3he8m>bNES$ITp2O*(D-Gpw!n{K5!_nb%3FP`~=8wH>WKl#%7~-1#D9GW1n9VA`$D zhdtwurgH@Dw`9j>Mr=lpx`_e17j`^=<#f7>iO!jl(Cusijy?Sd=)F3`gRg|v6( z9&`lJiH!ETUlV46pe7{c_9LaWE_%JkTQn;i3t=2-`-b*ojjK=TI@CiujuIw{W92;> zf?jaFkj0^hQ{HhM#+RJckODPtXH%R|AM@J>Gy7rve1okX*?ErD-zXiwU6_fGCj(ZR zbpqP;m)it~z6E=Q>)3aqY;ZtHm6aN#y6)hVyqpPX6*KyBDq4CsAToa5z`m!Vxt zTE`b+pvehGtf{W^vipbn@z2&5mXPx_TfktcER+I&EZ0!Vc581A#3skob6kxV2@3tjwh-y-)99Y+JC zHU}-VC!(4?LkjX`1+Jux9AVo^{e1qvjxI3A1?Hp_^W5-(g_yqsE`4m{b)swenV&=S z&DRrYT72Bvq(H}Q&41F{p=vZ__*kU`@fl{g2alkA1T2+LqqeZDGXRCC_AXnEwM2>> z%>-8UR{+$z(`@~g{}56#{@X7rU3JBJ|Bh$*ctBTz?ydKTp)k19Hk#<8ErXi)XLziY zXM|c|H5A`vL3`)Mtj)8o6RL1^SRcteO9up=-`^TiWDu>x6&G#EF21>`dvFJ9VGHWx zJSEeaplfL3=8TNb6GS|^l*pCfpPATlIn>nKm6`XzbNEt%Gx?>!P@5B+v-%5UIIj+9 z;{l?dZM*wl|GFPko>XcPm3KgFV~S=fV00=7p7vfdkCQ1N6DF~}EEG8(ky_IS?E*Ut zu1d#-(pqX!!|fQKrjFz3NP~*?$vnZ(Oy2;^%A6cE-_b!=9zmfrkc4(JPSd2{D-f3{ zIki)8{6m`GFL%0M;^}F@?c8%E9~4D-Pn|ZC1@>mZK$bNEuDc`+`n>}(pN&JOS$-~x zo27MV+|TQWKp9AjN$*&nyI2wHJ%e3sebReiHoRK~v z1x#Z`#N0x|siG{d1rG=Nq;h^+DYZy!Om`*}N(p+~i~kEVsfLErC>(pKuvU6x|Wr#OP+{YACJTe|u) zyKiOa2hmrw`{29o;Z3&HlEip=y@9FS76sXsCK`sfnWQ}_+aX~>BfUb_xT+xTeRtI_ zSzyPLn^R}QyKf+qP zWnlyX&^p!~s-UEdZd!GnXNE6& z;(sgv`0@qwYn-^A5bX}f2i*Kb%O5uHh99X1nf)Re0ljeG`B@N)19}L}S-+BE%PJsY z-Kaw-{LS!hLinEg#~t&_OIn%26`q*_ZLE2Q-xJ>|7~@4?tZj4*7}Oz*`UdOy4w$rH zCHC=2&&#DzW>35MMzP7snfQM0u@DlH>c19ZlIQ@fIs=MYmtuzFTE4X}QbF4R)yk+m z>>PA1>b7KLdCMpfF>;E`pA3J1?Kpm^%?EFrQE$rmOPOxpC<9!R9iWCIhZ%c)c+b=c z0FO!qV$ytAJ*eHc^n8Y*BjCq*%6Ua*A<46s7VHHjimu?wO&$()aYI+|8Vw#@k7PuU zuv`OO+_TW#)t$(E|6HCiAB~U(4bFuyJaL7qxrsyc--wWkxeOqVH!0QQ$>3nq0P#iEJ{HTQ>!Ub%RCxZ3+q!rXeA0GOM*#dv7&&#ZB5$reA0 zhTEH8`_HJUUgZbEuz}<|p#iXVJH2+Tpw5;dPhL(B@Vd`BU#`;ZslSA*ZMa_dmv5K7 zPVc8{g$IC~q>^!!vwF??pIl42H{WE66GOues`kXik!yR*K|dK=9J=!yQ5qM;_WL>i}aI=TLVP^6Tmg;;6S!pBy-frFTl)GXB+-YpAVrq+VD`5V27|Ov49C)Dw*?V^*Dd>?uz^5-HD<2sos9}JO=P* z(V32mH?Ip8(5;?l3mI^EqHx@juxfhf1~*v~QM)2jRx#0z3g*&O`~&m>uAV)d3BzoD zHbeXFmtNK^?kL+7Oqs~)UCREf5Vx{P%}d?&pW8qF#hcHB`i#7`6^~j&;x@0|`4{oG zA7MW47XPmbK}3p+9Kq(o4OdnBUH5q!CAtW2Wx+aiib-tAfxKXMAf8^V_fyIGM?}Kp5d%0wJ%)}sd9~}iI$ILCU3C)r z2EYl+?B)zBQ^_>tV9Bpgfg6X`WH4~&4FL*!lf~91S93(kGKmA`gKCFYY(GskWxzhO z(Ld)9(91-ZO6>?I@P!vvho?^eE~!#|>=fo9L`SAaLb0dVC;4xkt3~K<_)MJF%Ec)^ zuj;Ctl6mOIjn5n#s?ZV48m%vFvORyrWyOt46h{2y6bt_?Gd^i*B11nMgNli`fd%)z zILm%Q&bCf%INbra>kjva9tSl!0g;7tI$r_%29UY$DUSXp)^wBZ;l z{kNdP{MbA|>ea50!ECO77(%N#jW{i-AF1Va@w__{d~Qxm)AC%0nmH=+FB`;J7)Q1S zl8!ZZT;LFHj5)S8x{+!C?}jd4-_=I zp|Fdd1a5zrW$(qJ8P_D`CC<>x|NPO7k{==ZsB3fg!J9P3jsV%E%Xckvak;}W6J5WxsiGc(>z{=8Pg0KBnkq5GBGQ+DLI}F67 zeMpVgb^B>4{O4T+yFI8~Xv;o&cd_|Ow#kCt>h(y21+Eo9o<|7hf@k4AUn#PYX|=^A zla+!09RY34jjh@P@jm;<0cR4URDkR)sWO3OEZ{}RX0OktOr@g!Ain!$w{Jh>MsKe93QrqE2FzHn~`+L)z`BOZb zBZTj;=d7tW4)DlFV7m3yL{V}=0qv<|Te@5}qKF_+Z#z35z&m@NM9eotg8Yt2YDN@Z zjhIEIoKEQ;Ohzzx+{LPfd}Is_n8}Vz8#2}R%&6{vsZm;N(jcHdvfOA;>xJrJE7dY| z2jz{x?Q}RQdE*74-B4K$QKZU`02Xi8RA+X zzk?4ApY z!d5}iTHt%PTg+vrc${zNMy~xz{%Jq4NjRdLQWcRy*-H!+2YPuy)dSohZJr`gU#g79 z$XrN^!;ca?u|9J9dVYM9f$D1EEnSow9>k{82p37m=h^d~zdYM!B3AsX;r(5;ZLkml zI0VQgDRX+oL;LmHkE28a0PHGCOK{ySnB@RjE^Nb|vvT9C-t;Cf!rj?JFSUd&KU|hB z1wJ5mPieegEH;kz^KwK#E;t*KmcZI<-nv)`ivn+J>|G?W{p4b9|1vI}5~|FUFq4A9 znEZZF>Qnor^;?U>hMh_|4k#24_!aCv9`!~fNjU!WC(wl?uJes*&e7GD@Rii?@ z?8OFn#j9XV+&mwktqmaNDLvnDJy?r%xH{9k>1Y70iSyy&-E37Kk#gsP*u`MfzrISr zAs`calf1kg^7j@cFBWuUS*n{$xmZ&+RoXHo9>ZMHmwXb~ZH8(YM5B`urSvE840W-z`|eNpaOggY7s&+sTV=o15|WB} z&cbHJBGHpTh)h(@6c$;A0Gt1OfVZyc1_Oi)@y!Mg`XHpB4Mg(b;BU>ke@`VrcmCB{zipFVsH88R^;rncN{$opVb9rV7wI-XlH) zb3fxUcK`G~nmZkB9g6Xe{K>A%rf;IPN=3iw={Zr^)lg0dxN_JfF$CIf}Z4jwzMh{z*Q; zOzdeHmlnM^2myJpji&$N?jpaykI znrtTYZkL!3zeLolelo*KR@a5JR|HuPI;=gdTcvDf1@-tKWTeUy!#(MJo+ZR2H&x`b!-<(c&2g|4T93V)?H4 z&4IpBn$!N_*Q^|-uIB^Jr9$5X4fas^euy`8z``qVj z&YzNtYE~gds>Y+wN3_$nk`*3>mtdW(Kh6;}oW8GPne|nz5NVIN>GM$dj{J*s@4Eik zF35ScX%~X)LMN>5Qj@t{;98mYV~!+E|E!4ZTX|3rlSk`E4P$_x)xrHL&zWR<2wmIm zidkvA$qh*4D`Fo$h?oll$pmPzBn98Q-KKlL7cR+!r@@Are1i}4cw)FRPu)sWhQHUc zXZOi1{sHwmYkjqV%cAGw;gJBg@$Co&m6A!pjtJymxYc7vm3J`^-~8{#3_D`U(AN zAsNCd=AyrRWdCcQs6EBSIOCK6X-t|hOyHal_Rb~sX7O1)`663*87UtrZ51X~FlgIA zEyU`oQ;;8zqcnVsfqH$X<2PwnB#S8pvtauJ=XP15$9K%r04xL7ov~-D(c??ta?$y7 zT&^(#UZdSwd_CQ!q-C{71|T6#=RVki!Qvr_o6G*wx<7{lWWX#N!MU8E-g}>|oS~_2 zSy;*gjDDlHC>VhQav|;zfM&tbEG<0^KnDCpKh$l2@=RsV_J^v*zL>6p+g+w$!UDzp zW2)NiZubw%mDx_}%!;Ho1Z6n!*|?x=<{seG7;9l!#D}+5nPD9Bn;x~>FV+UpT?@^3 zTSp&OA?`R042Zb^JQj?*nxfW)3@+#=rpXwmZd-l3R#)@>#kC6W zEyaedW_fz z{|jN%_V4&$@6u-$H!Up?&$-sUpp}x*3BWu!o!h?sOm*S6fqi1LLv;An=dLuNEix*0U$|k1(B>*$llBHVKs%qX829S+^(dpX%gsSVx-Z}LwPNJtb z=QF4fHWJudu&buqOQfr_Gxo0avTJ%mPom0-ruyZZ19&{b`A8@yv?6vBG00cSIJ(9EP zxNfP*r$lmTsxjl70@vYb+XAdZuGAowF_D`P?#Iro^)QLWZx;36G6byC)+Q4gD!=mb zRPk^c&6_oxCrQGMiwua>&}7t~OGKxp2vux|;uL*0U$t-&tEGUpuch5GD@2wD)14SC z8z1n+1;lfRU8Tb>j#svFHA<5{;EoTk^-w43g_8-WzW?nHF*8y+PWP-pLcYU4QJ^EfC?{7 z(lx2$9^$Jt6A&{e1-ew2F@vn~1wJj00S%&ueTzQ=)r|M0=Q$@JGS zd1hf^_**hoR(cvOjYvoeH_`a-?*YxyJupzVF!CRW_!4?>4kdZFgG+mgZf5^gdrB#= z9|tA6cR)4Lif2OYHo!HC-h}8XaUsSK8hxY3H=k%IOLq`#o=N3L&M1qZtT)MpCzlkA z59?CP^bF4z@53rY9ea!~N^49fN7@51ITA!t@JWkAeNJ#ij{ulu!!JdM(v&c5o`7I? z>H5m_30_-yGKe@|osNizEak_eeDxW!-z**vbN_zR3wX=EFmCt0#A)33C6m-lih#H8 zEXELJwTHot9)7cT3_wvz<%q&e<*&;b^*eL<`eTe07?DgDXV-=g$U_mIN*w($XzYc> z)7{SqBuzgoUDsccPBV@e7%;y%O}^e%RUlWIGZc5Bx~W!s16P@@!j?@}(qu>qqudU( zEjGl_CfhIarBV4l*>w2G;3EgYtAD46k3^we&$n3i72SVDcbB;6D5nR@%$TR{EoAEa z!BI%aK7^16G?|PJ8T!zM9y(4uVh(8H!^EI?c_lgV4kMZxj$bDR6`QIv;TN*>-|V*o zc{8-jJ@!-aD&m!&AjN`A*zR+84<*io*vYCNDmgCP16RF}ufW@)MOp=)B^7=HS24{B zVipeXB`KGIa@?rdrm6o#yjt$4Md9A|5Dj9*7ertorfhcE*^aO&C+LxSA6s4alB#|I;7B_}TBgNC2-47`|RMICzTPOObLdE)3dy_Y^;HS-l;Jp}SYLqzkbfaD?~ z0Cx*>?Cw_HMT_EMID;=YkM4TA=ygvvZ>WDe=`S%b^AB~btTHZ3T9aLg8AXc6J}osR z{XU6@_^--t@Ah-%X%DH{e5iNZAOxV7V79yYFO$!L7@p~S_jK*wH6Ifozi}=4<$6QD zLZE7jKyNl?Fmf4{2|{A8>e}_YehKo#a6}S@cH#9|^Tpu-C9@dGu`;ENicEbb6{Ml~ zey@|=VWl47f&b4T${W6EafAw&3!Ela`UhjI4d)|@h5BQj#$-#(z?&I_x1iBuLz zEwC4)Sj*4lS{Yl(J(^wVazAd_g&g@4F_%$CwBo^1zIdIlaW^3R~BX-WY=$%r2!^nAUPHep>8 z1hD>g`LlKX5?hY@a_x8acGlTdEM$HamWa$J4}sx?!w~V0$SmdM5C6uqqk#36drqy* z`ypNE>3=09=(kVKHTJEIBPV`3|9rZa$$+FyPG+;L*|^=e54Hr{Uk}MO3*UG&#hphY z`^29s;@0DKC02_9I3T@uz{Pm<-WJy(2u4=H^cUJcYDXs~=ufG;nF*P0)mrNfB-@CS z+w(M7RUFH@{%d#fxbO4p&3d*8vF}i$yU?|$X`0L;zYziBD0574A-)I#gwZPh|9+tvRSKkkQUj3x|HNoXyV)3e>8l! zv2f^0!6vmF0|@W)sN0*^Ov{BenU?r zrib7q@<4P_#?dwycw8m$XWtg5%kt0g&TJoVt8WE*Hj9X5XfN_H(R0oQ-x_?VT}!83 zHxu(s2gU{sDzMamgw+=sfbsVTL(ekH?@!XXn#%mRmH!Yl1|Wq#6)0$8E#T=3ZjFxs z1Iss=N?EKZE6eb~l}X2;iQc~dnh~B%d&25>W5<0;ZCY${K9a%XMX061tbY(fw06%{ zBW#!&H!tpVga-)awC#{JNX&%&=3#C&;j9{5^B>pwF^C!MSP1qWk^uQ(-xI%X3*8SR zW}p5DQ{vr508Er>gql*gQm!IZc{MI1y~^{{gQ`INxVFS+J6pFJhXR3WOt`VII_oZ? zrm=F`C4og;f>82p0uQjIlpG2W+ct|cyAAChx>>ehw+>cury>p8k5_Ks+{)X|a{Ybs zqeeMQ3Ma+;7rNDo#Eor!4jxzT?mkD}+pDm{lU1m-H)}L-wPK(GoWZ_;kI$(xPKK;> z!hAhz+M=G;{~5`ut%viVtiG-_SOv*GlAc=d(+r$QN#6Y0z|PgkRC9Va`O{A}^e;j4 z57C+F*7-YB7w%3@2w${LX8x%MG4N_52e>(rwXE@(VI`P`*rEj>doupZ7}%GoB+&ki z4s^Uqim7$&p_oIDx=k|W2g_T0k>?*W;3_VcA_?V1;tgIy&yINl8TrUR>T+{G*M0T- zA?sBiM21R{@&jRqt;{#MSq2N4e~-?&R8Y}0N7IJ_XD|^;W!^|ZP9{CYN*d@Bpu2;Z z5{d5#K1(>SACa^XeYwMnSH_w*DRs@OJ^O_06o?SujA>LPwB@Ts~gj zaX(8it~|6fHJAKGYQ({+5kLZs1-$(*A7}(!{*(HE8P=X_pKOzgwM5U9#MM3C$)Sq( zC5e^i#>Ssd8qQ^fPh5p>x%K5hCM%2E%n+`65zs3VN{$5eVc02jK^(!Om|_%@2;~;(2E7}VXsf*xYx#xcXlc3O z$hh~40h6%}F%LtYQh=$e8as#D^ecz_9D&Sz4Gv@_yUy^kLm2cggj_^m$D)k{YeQ?T+z(N11!-G>#Kc z6{ih?@v%^^NZi50>_ELNFSV?=amWek6B?U+1sVV*{k#}j?ky-ed*M& zSQ6px7CB}a?b;(6qxvE{g#Gk2+`|*IV*#fGviV~yqo0xL8X71`cnch*oy4~W_cv7! zz9$>#(@onI^ur4HXQy}BrOW&{!`?{K1np_3(CHEYZE^4bwwX@3Zp?DqdYDTGVL~`Q zKA_G6Fsw|WuA+rLH`+M3w>6?%}AL2DnDfOU*cswfh)F% zJtPLiF`l3^-V;zU{~eD>;!yy1qp+K4%>$_xxjFPMb_(`G(YBV?DdS??L}Tl1vUWI5 zG>=vn1kXLOS0=1cUAHI>1>lGu}GM^zOmD@TUnA@8vRT{!!ei$(%nI+L{F zf6fCqa}$n31(x$q{m}1F?bhKBK?vER+2i5onaJCkVyVD2M&S0m@Q5Ke{z_vhp> zy1x3!_NVx&WFPQA2|yB-6wyzP+Rb3FAWPSH_cUGg;_H6^lA_SqSJL9&Tu;$l#nYA@ zf;VNShk5&!!6NqmmIxH@|9G>*N0yx%*i|S6A_B%#fl$C3kVyl7PI`2w^Z&E}Tu6^; znIK%EzGgqC)#GIi(05G(Jl0R&Kxui-^)}sVDJSw`%DzNjOki~aD7Tj}>I5U6BLY?C z)rU`kX~}!`9+*EA`Y*!#b7(?NL)F*SVOAfAn06k-8_;npSZ7GOUtCBoi7h>q(7Eu*@t&&xlRsFT(&+xpBqtaqweWz@q9nYi z?^GIupzn1&%i9Ui%TAtAn0q`!P40sD@#XW8=k!tpLvuUDrzsYBkV+VoW2G}M#}1DL z>F={@lDyS^*t#LnCB#Wcb;kJtg1gkmB)If|9h+@q=T@p2kBGl-js z6o__xgiB;u9!#N!vpFOX05X57JW9x6665c0oj|rUHcbPK?u%{=#ASWDPm~-Z3I=@) zo+iFY&N=bx@iAy#mZb2=Dz>P%U1v`JL>?^ET61;R8f)yfBsXqJg*_2;72qPa$`7B9 z*Q?M*-L0%lqL;UJ%!S%yScpEm!$k}MV0ic*FiQk~r&Tv*)FA8$r81;`2|gIdROH_W{m7izHH}17$<5OuD1zl8!oa z)%=gG=?Dlvjver%ryGsWjVIBcELq4{(gsCGb&kD{mZ zsAnl%_Lcn#n9Mo8ymlXSciPVrd!SN!szdIdsqoetqg8zW)E>QWW<79Lo_<-h5gLv6 z1QJgcbstOwp~dy+f+(`(WDzi_nFHc~=25>lpV)X@zUHeZ;$%8REkh>DWO{?e8DIHzdyW=Kjhn{dp>2Yn3i} z%($Yk?qtlD7J8SW2kF(e7b~;YB!s=Sh@5%8KJ9Yp+cmg6I=Z>Kd4UsV?`1kvMp>ax zhxvaan(n>+p!e>%`4;&lVRYE>Mx%m1E1fCH&!H)2*22k-aGd(W z&%BZX5Th|=^jYNOaKT;rS$y^zUmhICNMfm*D#q2^t&H!S80@nXYbvDRcVne%E;#8w zgBl0E$Q~=g`3Zz41vnZ)@zA{MCbu^|1;Lm!Qr3_I0hC- zh+E#tNJ@M=Zrpz|Jp|a95ImrD{5<9A*OzVqV^fTt8kz9IOSeRP@-S!q+9@gQd_roY z>6*sQ)K6tQc?j@4>bgy8T$TBZnI&d(X^w$E_;9-jd*vMX;&wJ`-aPdT1}zqkhZ05_ zKa2=;GjCzGBr;kJXafTpTzCNE(9%U1I{B?1Qfs%)mFWRysV+c-$vgK+(Z4Mb)+V&y z!oYiRAoay!g9ZdCV92+$tpVuXY@TQ#w3i;^z~gRLX9CC^#=2JWl5e)<_MVF0LzSHB zVO(399+2Jd46p;#l#uLG!52W8z#AM0;I(UESp@(p znPqm)^Wp99y7YrFjzjIETXfB;3;Yxe-CH$^$=Ubz%EiTFSB)tsIy*25SAQ_Uza)rX zalcgp&x8IvbG<9YZd*owlw4qGzY%CR8Y6}(5qKMdixxp-BH94AC2&E3^c1l$D!}zu zL(>kzCmLOPP~3rzB=@AJl_t@1quH;QW6&sfy+^8*$5sd2mhaGz4w}9 z_AhrgF7vC7@u~(1vwtPA@9N!Tb@MZJg>kM$Ci66dak`7j(E{=IF{8WEs%-mWeHBzB z0N{txCWJdo$`=eP(00J!ESA65U@V(lE6>xSVmZDorX3u(?JWknX^g1Rc`;+I>YPwX zH1Y{FK!^$yrszJYP4_>6+lwztgXKQ2j5g1T>^`VIwV(CuvH;0v61qX}(&XJ91M#x~ z<)qn9K}XrvWT&}I|5po6cpIjh1O~abw|n45)yhSw@e%+hu<_;Hf1pYuy#9*Jl6F_s zke9q{O8HHR)F9T;G5`GelO1`xH?8Z?dPti;YB*4=od%b&z^zo@C>w-DghuJMpn-;z2$c%nTYmc4D1Y1=SS zTO%vyeRQI9NwN?dFMbP2MTOAEFG<;_TME)PKkD<@7D-jd8`&_fx@k=^oVa zOtKWrh!tTMN)JHkj*=h(5jMY)nL9YNk2i9{P2eLd5LCW|XTtdL@<+}r*TWRh{}CD)Y=kfic~1uX&_(n^dp@$W zyr5>*7_|SVZ8n z%C+m%l-!7pd17?RhOeTD0vP9AI zYQA(M#xtk<*_v^T+OwfgG>FA}T>6h0G{tbN8zl$T*>M#6QP*)uLyhDF_>2G3KU%Z!Rre0%c3&3mrkqeL^K-P>A_I|JvlN4fzZqXcp z5Nt1bG1~79rTZ>VN^YuxQmtV0rd&A#-?;MsJiVCQ3Ag4@r42uM&PkFN9uf{<-)6AL z#2GZhkk#@eyN9>yk4W*J`vl4@m1P+E#$b4dI;UOU3?ILTbx_9@~$TIdZ0KdR6)~reSc`08oWFs%;xQl z*-!&m{Tsc*uLCZtMvB}u`gZN1c9ZTm+`ps-|C0c}{Fr1!YTKk7FS0>Ktd*-^5DNFF z9hRG?cz7U3A~+AHyAJ#(E$^zzbHIUohS_q$9^eQ|6Zwb%4Wp2LhHxbB{i*?KuncSV zaFa~cGKA`V2dHDtB11)Y5wjMhu|E_h(~w>kMBMOTIoFGsA6wn^&k@%Y$njWMCH3csD?lwMok^=ekm^= z#nokumx#JrRJcWA+44!61w#lk!~R_3**n zZ_h+c7$RV~+$D&6`HBt*-ERQC2hJ840T*iX!Wl9dSZ>-eOZfQ@zP3|xYO6_H})4%^f2SQph zgI%K`Q%l=sjEIgoxHzO^3Q<5x0;9uIV%0@19$zt;P)EU)C}Afc1F>vQ#+j(HVJPab z4f6;Dd_6!k9yr@BiZKu2qn5cO7~cthX!3xNe227IX>iF)M%F6IPo`-@|ILJ94!%pB z_9=hJ0G6NWnqdDf$;?rD%vE3iyn(mTs#LM%n}Z0ZKk5Q7c@DCoY`n+)8Ne43{9*%> z{*MlLVJ=kVV{d*Y-uNM2sX(&BPn|U6cl-PHgc^P_iztQu2`{kK)mHG-BH8e$URaWw zZ>egnLGSn-ELb#MzSU3{Nlc9GBuyGEAHLl#_LP;qJ8-kP?0E{{K4}o#-`kq`>?iQC zCz-EGcI=HpeXK~=?hJj#i+@~!AvNwY6Njl(P4!!vfs0mxKH@x0u5lY!OLf6Vmv3%g zKbJ3VzfAJL9NajV&0)FWt{{Z-w~ae(ju}O1GR65fIIoX29wG+}a6|Ico)V9&KqNGg zcrrG$fFI@&(a0+xle!lvZ@26+)$%0SXHyb>DliNH-X0i!N$lo}dEM4!GJD@?d~Oh6 zXD3!|fU4~a=cUS{RZRr$DFtaNW_x5rM&XZ~$Lf49_jXRFx;j>YR|}<`5$KJCgxdm% z6ptt&U=#f|#Sb{oQzkILqmeW00O9NL5a80S!E=6SBMi!P_{c=X;e)r0+K+TqQ~1|P z!pr#ZHd1Wol^E$*1|Sbm%U=e)u_H1V=Fjqszw_d)#SrPddRfV1z4n8%IWNE(} z)VW8K?IhouerU{IrnMQmvN-law`Ve%690Q5Y|S7 z9jc&rl}=1+B900%uP~h_xYO6mDQGo$Be;-WoHe$Wx}O1eO0%)~l-oL6=2DK$y=ue* z;vr&$1Rnx9xyJ;+fa=z@xPTcIBBh}{lg-hehN$dCB6&}DB>M;3ftG4I&D4`dVtf31!n7b4H|b7Ldi#|CZhb&R51$YHFpQ=a>>JJa%vOe zCp`Z>Bg{K%`>+4Dd4_#I?~wD5TH z=3b}MC3AS?VxVBgl3_oBK`%-ga9(Q&-uw1)+N5EzDsz^*R2@^QtKQ-?~vYNW^OB9f;B z-zz|dLFlHtLzC?^pq~LK_Xvz{QvG`jm)X4uIv!=IjIu&s1{3=K5uF##JLE?MkMe&0XaR*BM6#Sm(R&m@n)1XKmD3gc?Q7R7&#rxD zT_t1hw!ilo57^6S_X;Q|rnu#!1{HQNYEFzsF8YHtE>)_|U=ZU&IYeV?7{B^YQ_6X5 zYLoW!^d$*H?OLIC|Opb9V*I$i}B=Iky4ohpn$zVk97Ws&E z?pWgioB$ZXaU}}j+uF^W_;b=u({Drt(V*osoPeNzS@df~Tr{Nd`B9jsyANad)K9 zbLvnJ1RF;&?;l#qk(^p{3GPa|B36OMPTTzVMWzo7!w4*_FWxt-e^)M0jk`JA{N2iyn-%(_{vg$`Bi?_KAY7u%OOQ7fnADcgAY8Y5 zJc(BefL^FU0j>5nLRIA1##Xl~O<#M@iAJ?td=ga=1}!mLM#-V`_3;6#+f}Zwt8_-(AMQifuNNnAvM)IiI+>um9hl$tD)itd zzTn4>X!d2{0ssP2!h1fbmHs+rsq8+0Bb^Vf#wAz0qw0t%b~1L^q#h%Czq(>t&lxGd za{LP1|D{%mt{afd!mMeaLVNg$jk#%Q7f@rG0s^BaVA6-_%`v}z!2+ZHV`&;-+I}a$4 zZlfN5>CX47jgJmG2inf?!c*}CFD2Ew?kl$?bn^qNe4}3<$6-0#^9=4Hdkmd zEJ?!=#xS?1h;@RmeLGagUs*<@k5VlmGKUGW%87~)+5!g`T6^jfyuJ{TSK&O5sn}{! zp4!brOW*m@Xez9(>N^I=-f8_Si}g-9s4g99mnAdy9Wwfq9o_qRTbVJ-uMk95IKCWy zCarZ3A28XxRq&V5elHkvXPJ8TE(hiuP5F;f{-6r-tgYrYx9}VL_emk|RY;T~7g7Uq z^{Y$swa?3{^pvG#FkiQAzxI4f$HuCSOePsg!aXU)*SOUS2n{ zTT14&a|s{h?DEgZ5{pumIDu?zidYrxYJK)%F)7|cOXHuF6sL~WR6;eyux9L@N~BKk z)y|H0@WIPH;R!zzBM!S-gW}vF!XfI}{WbS_%tGa~k@skh6!$zrsencS&iMy1 zMj*uV3~}r}wv9}!TD>ZOBxEvZOHeNR>k6nD?7zqkat#gL1Jos~At&syKzy=fCQ3t; zD|L9Vn#$=DIQh`yLJFIB{B*>x{H*f6qLUfo{#1*H!f7Kenxa0YmwKPSJ$*paBKka;} ziVMx0R|hdH`VazkH>1l{`;A7sw}Vd8K~^Gv|O?rJk(WS3^$h2Zs_2Fr94U)}hcm(}g1#&X9e+CCD{ zyPzzH#=WcibO}$~vn(Toj~~2yEwwB{@BZi>2P-MfW>+#=D2ExU0*L2t2MhnB7v zI+dn-Q+!KLE924{Pu<)xX*Ru{B@S;N?RM3C^T>x5=GjsK{u06s3cXr98*iw4{M7jB z!^5doUQdMeZMnf$%O8HCLFStry#TkxfQD0ThMZh|LJ*@`BlE0G;wU!|=sblVM^+8u zno3L^d%1NC?XprAk5i@A=5tB{e*pArHGj)5OCvqM9OHCdUv*M&wIjVccmLCMagRwo z2AqfsyLevmT{COqRn(H|P6|s4k&HY7CMrf9y}5>e+tZEQM~jI+Ag5>=SW_!B!1FJ4 zwf&DMxGn+8?qdgH?m9DQQMoyg!)L0wY53YcDgrLq&Eg%L;zxK`Tu{6wqF^VYuz~4^ zP?=1U5#filoqc@pKQXA4C4!iYXbq2N9mevGl->9KL5+sc4`ak9+wE$ZUv1FGPh>TX zUUz=I_?NLtxc4&vLKLqG{-`MlChB&H15WS&CGT&qGIc5nnADwymKb?T2Lx3BAIa%& z@tJ9nb@{>46KH!|HBr=7KdLdSJ>>mqh7ZOEKn{_A)#G>^BIKpG9czOz8(-BAfqurT zPq~kaw)I3%STP~&t6zk-Jjt717hbx(fnV!baccv3jq4f^0DM%Y8uC-1vEzinTj-sP z$Ua0={6g4LDA0h z*>3S)F~&XJRz|l#K>+v@I{+!@rHL=%AV4~#u_GEKD*!~|0~eN*+3F^#JZYOuIDJ~x z{Y7=?Kl3xDom;0zS5JG}aUgRYtq~;q#T~f> zuavHd-&_aLW`b3Cq^(kZr3v-mfCe#S-zJ|?NR=2TPJbK}fz9NN-M&EX-qqX>zTTI+ ziDkuadPzr;)>l`x#BgBV3N#xF0N-<&3GY1xB}>E$kUHZ7HF0iEGhR)yO?%g|Pp1s} zr!6;)hZTzH=P!~InJy0Ncj3gqZ06i)5EukVVO8r~x%wXr?rU4Sx|IyQPb}gEChU%j zO|Z8*JG_~H$X<=}4-QcQ6a*@W*JARHJ(cW$e_m8|Hw|~U>cD*CwQV70vDm9Wt6mZp zEYs|&Y{qacC|no)YWD(KbDi7}WZ8|NKh{~7UH!QKp6P4gTU3j)nmrnF^=hc{BnOcbXhkwVa zbd5c)e|B_j4Xt*C#TvHCs>t8*%QY5 zFs6~mfWp9Dv7R#_o%nvbu;#%Z$X|o*D0Pu<@@{8WEnZ*%1dvJef;c^qG`P@xWHhJ$ zzZaAs#HUYNy{fXtUdg*(Dyjbae_8;`-isCwfsrpKoz*tHUjJnv#u82i7c8DxRiluO zQV?M4R-Y13c0KL#7yU;nF4)o#=!fY8@#4irMZIh#j%hm~ZO~3xJO2M9XRjVEkKG;} z?-~>6d=((O5acJL)_zzk=AKszqDutTTe)PIxJ3h ziY#7f+nA9AJ3D;Fuj;w3(!e81U`GVPKk@;ZU%*0djv&cvJzI!4>QwSb`i&1xPB(KI z?T>igLfOA7X2MPXwniL%m3He=O--P-`H6bjckcUSsJ-OaV)lGuJ$wP+W@@N?Y&lp_ zD|$Z>kLHUM+$SQ8uAAH1lQzMYw#HTiS6l!U59vw2ti6-$rI%Yiit8kx#?El_ zlW>R*5fW!O%BJOV^vJF0$Ps1-$JtFzqEVG~8h5_W1a|%erCuDseX~GTItSO!l2j z;2ulxdjEOr6VfLtq#d8~s@7k8bfj2keMG4bkYsFkp$qE<1bvW?5!LOzbXb9@dQyN} zdId!YYzPHYdDNNp@5CygLCp?aE#9|<8&@@lb!rHx^&Cr2dTZBPuj7>~S2w?Ee1kY; zWtE38k*4!0V_K-3ERdSUzRWN8n)E1D0Q~(@4bb0KfH1Q4rPQ~4-6nz>BOG0UNIJR; zdR0mALIym|cCrp9H9Qg+T8d44;j^VU?h`+!(~w}SOTXX6 z`9$-iUs@rM{0!)^kG&bD=xXFrS-DN>8j;I*Em}m*y212kHMa6@pjIm z(d_|!A$W!1TBMVG#8;vH@RmW?zErtWq$k3VF0(_)(B*CQ8-Aj<_yBIYtyF1{1TWiO zPX~OZph8HYvV!u-!MN$SF7GV=RL%ueY1CjyzzsTh#VYF^S&*-vr@7 zSH3#7n6xXq!5vrM>FMAaH> z%9)$Au)wEv=dqr>TV$1&*<{tJxNMT3tc|i`2f}77y?L_&=a7&cnXj9sa@xxX$|oy( z!qrK}iW01jt_b~rsX6qZ4>919qao2t0ZDL*darg7@EGE=+dl8g- zF*)th1hTJKRV@58t?wAz9QKcEu21#X8X^H_tpY<31Qs=9S)8ao@lxkr%upUQ+tZDF zZNaW}({?q^Xv*@^)dhYdki`XtO`{(+W4{8+Wp8%8EV(kxn#7~0KqH>Ws`EDH2;LhT zK2vz)uW75EV#ymVBS~;;KH)8Rp6lU?Y%{=`9fzRv*Q5BAOjmD~`nrqi4|J9Bb;N9^ ziF3?`$~*fZND+S71GjJOM=QCzd8a$kr$>A=fdqrPg6%RO2To* z?4#EtZ!$*Xn)H6__325y$&`4o;bhzw_gniV!&4^gpT6RJ-UL#B(n}YBzNTZ1pQDE9 z1Gr)jBco1I9GRs`lJ^>Ugd+z>GJpyRkb?u%l}?|_U_dua{KsOB(tA$(uZ3O>){|eB z;N+!qWTw-3A3dG-_Zny6| zz*QseJ;OuegaG9GpQ`my9!g3dq2md&y~z@3v-5{bK4er^Ydv8z5&1BO&)kVuQ=8k}*8_BuQHlI) zeNFLwE`OHyK!|j9chEu23%XGalgMW8wD9SN%C)P}{+z7d4q2D5tQ!O>K9Djum5iRQ zf)X)hrE^-s+we{O{ToBbOy{7TNhVD_@0rcP;(2GKz3sz@j`y#O7G?EA_YJgQ3H1Ay zhitbS;@12^#*l2I!tASs_o*jLK{dHNPj%EYje_SmGZA3(N9U_M7LI^CEfJDEXC0~# z1jOg6CMIMbz4ic0kV$G(i1Hf6KSb6nf`o@mbx$8if|_0wPURavmRQ55qbQVdS(s!J z5Pem?Duk@CUa$a*{=N~FWc8IQyOPy9n0R+D@re{u_7-8uem+x<&&?}f5`K$EMezD{ ztlo72r16UoEx~J{{cWWb&Qe+}-Z$Zcp?l=Yr)8_wyhg z2PSpV2C~OXyEljyE7R@n8Sq!R2e~x|%ll1VoFtXAXYWN6cl{r(-ny%;?~C?63Bldn zic=`=l2F_!(BfXKxH|-wLUAeHFIHTNYk=Zf+@-WoN|E9e2v2@@-22ayG4cYk_Q_d$ z?=|OVe(LHa^QCBo4M?V*iv}|R#aS#wz;A54q3Ls{zgzF1$09_!z1>p>Oj6f945)-# z_FhcAZ8Rp0#%d3-pCzweZ?2?pzy)g@>p`YinVj&SpKFKartT==u&~~Tf^vE17n;oy z7}V~cS(sOCVN=Hu&zI{Kxf=4r$`TtZ#lnwPd5O}KwS5b?SBUVKuH$|)QL&7c5RJeF zsNRZavXa5fQ3sN;-ITy@+&Z3Uai(RX*ec$qz>C?{om8OO9h^WAu}B8DiCt~JhaTql z*+!pt-g)D5+N6s@U#8jDJoD24`N~z2Fc812I)U5&FPGQtX*vbR5KV0>gJkJh5y8lX zEFG^uzqyX>`yEYEov$zm2wavwkGW(^n+a_Vki#;V!y9u}H;EedL?-zl34-)G8+8qt zOk%I3PV1)oyx-%`=rNS~(ucnpxjskRR6?-|sK+`ToYVWEuWtw$$pD8S9Mn^*^6-AHvM+8>DWtZi0;vlY(+Rl2Yn)~|il(8FhwlunMk*_6)Jm+rM^ zI)PlY5^ehqMHSPG^{aEq>sZ^>pGKdg*5heyGhQ@VnXJAVqw4T2_dQT_>J};hc%Br- z)IM1KxSWh5`H%oCNPzqs#X;Ig_m3bGbR{B?F_uXnk8`sU@i@pKqTH5I+enxVrJa-)^Q4 zS_;-sUHPSC0KjeACDF5Iul)YmPl6nRm{7GH4OC|lC1i19U}y{w|Bj3p`3V;gwA3eH zosCwp90Jg!ONtZ6{VdU$)o?yzE{}nkXtQ#Uw1226Zm3pKwkb*5(493t%1F09IaGL)1z7ESB&t<|TpGXXa>2d|a z)diO%;+p~X9Gn~)0It#@<45Ld9^Ba{aoa!GwXCGw8W;8Is}%$&G3hIwNYOf)c{(>J zGD)yOVX~Icsb(5?x5_Nt+kfE?Ule|);{u9da17w?L+@}nB{A?==ZR9+b{qRnxbTE| zNxv%y+Z6e8mlpQ15%jsZGsZ#gprEf%s7&RTW6w(Vb~SSa7@*$O?&I7btBx_Kx)NDU ztGwh>|KGT)NC>d>f_y-jP~D9Z=ESB#W78cE1vTqt`%5?w2GR+7~fMms^0P}eu|1Pm)3$2 zV(`RcDx`s$rm1I-fVa_D9RsXJx~A}_qMo+*sVrU7keSE$(b1Y3>r@`y)!HVGw=-I0 zNg>42!2C+=i{1cCe#@DG2-YJx+(Z|n2oSGx;-%7G)g@R=w8-0uYw&N(WHtv&6*y>p zg_5F3U!)7IAAuM@clep6+0r!j?1-;gP>|)MXZ>JJUAKq+L_WBJFV((Qhv!gRa!r931LsjQ|kAfb7E?E0Hl!%#a*FNhppi6SidMdAPV?%;R^lC%D}N*<5Gf(dAKmP zN?E+W;&&cHK_(9xHSBiuR>S~qAdkp+Pm4iLqHva=a}^I*4rHrEUWvz_=X-WZ=oml% zFZ8DlgJWwoS#^^YH~yo*?EKin{yqr&#cy!m%(fUhP+C7A;Y0Ze2|fIPM`j1Ek)X_p zrLjDkS~eF1_>cY-WV2X`ryGJ1pd9StP3Y_iV=@`bR#AY$QL5^pS>$?aM~zp4Gs0ax4^4DYId8SiplEUbS|z)zzv1eWbZU$e7Y@L}^>- zlR+)@*hQf8bpx-Cv*3;!{9E2e&a5j5nF|GHNbW@wXK20m^oQo(VL;2VGrHjh_S@7Z({(7cam1H-)sH&VyfrJM49W2aU`F31Kj`(?mBL%rGElW`ZKDeSW#EtA0{)uBKfwW*aJVQ|3+}U38z#xbBdxNz z(}%(1WS-{o;4Q_U+xaN*qD!qXN5LPTEN%v0>=nIWY>_8H=Fg6YJJ=Voz3)v<4|DHG ztQpn4(n@`gMk*S-Ju$A*h0gvpuBRg8E&7)XPO|t^4rFF7WS_DLbf{F^B4B1f>lh;H zHk~(YybffDq2i;Y^fNp*yfbH@Xz>WzJ*2MtwE8Hdd^WS~Bm^2s6fBX?{(==(a&XOk zJ0rDRIC4>Qc{*znJwg-VnvXA`(+YvRw9~cro?AIRnGiS^jflw}*yrc5Aif$K=odc^ z7T+b0i&C!h@=vR|r}Ko+K>;(Y#PT;Ue_)MzfAbMp5za}X8+o@Y(F;=*L!50DHu!7c zBBS$U)#I`zKGd3F%&$Q{e zlnu+}ERh=jb|e!?nqF;h!z=hVie8r_rBWf%c@%Q2@-5jEN>pNuBVTES z*};SbRWXBHFkE!tJ!Y=)93~l7OVgSz+ zwDrXF_TBhcJnVkE>nC;FN5k{EzPo%k zf7cK2v!$Xy^)rnZAO`Jj;2GB^lvz;VwY3BoTcrdsFFxC@7@3@4nG>UB0&gmjks&p) z8W#la3jbwXidHI|xwbrxtgO4r`5m)xJA(IiwilM=8|XCi5d?*66c1hRbE&) zcxLrE;vgy=6-n_|rpju+R8&c+?XKbdq7FSQQGJh*SJ?|vmgZW(`D+sN!k0*#w7L8; z!T6xki`gtpJKtoD&T9MCN{an|(ldTQgl?K)Z-025Ip_EIaI#ZgYc>|HF&zs*?(~p@ zmhI3wHn_!I1z!x^S9W{zUj zW$=}JSw9;F%y*OOBA)U=ztN$ZHm!NMG+4k}?ZNYT2A+Jpy?)?+Bm1FyTPUN|YyeKY{0#+AhX6HRY3Hf?1c z->-_1E`XZ`Cf?PB$pLU907H#R1wt}S#AH|i*h~`SPP;RkJ8Hoz5--yr!I>CLIM9IU zTb(^?SD2CMW(BTl5@=Im%H3fpJ{M4VM5AiR4c>z+{3n-$>s92xYM%K74E2M_DU=9>&qec(0 ziJ*v%=%nV;M2zlKu2;@?&(VOBnq(okGPWhDA7Y{S8ift(U+&Jh?G3G zlJBa~qQZgmW7aIFzI|<0lT*fquDi(?DNADJZV=A~dQO|D`~w2O*4^jdSo($^8sws6 zw;)+=Gj3ZUUC!#fgh278cUg5s7lC#co+Oy8Vjjv7Ptr4dll0x0qft>9Na}iOb17Z) zuNsKZR9V~< z>)F7UMeh9CrJX;4tHPfgfMYY;m82zZC~KA=v=S?^V*g>pBBtTzBL1 zQ6Z=Ybb@%JA{19lj0bQx0)`tO>$|*XPf?Gkl-QQ!F%SLq!Mm;yTM&Xu8K(bRTY7=W zFlJ;6hktmfPR^|)!W>OWgmidGE1J;kkW{<)R2+=`#gXhSn(8bQwK0(sO%_>38UL}* z$Hf~c2{2J+I1eG5~Ows|COLsJmis~RZ z8=1Ae@4jc|J4pK*xgQXRI;j{rW$bx@hsAwJu^&8H!`!y`rK6Wq;84B^y>CsaB#1?3 z{fn{0f#lQOn2-@BOUP1A1UpF7s`(NGHV zr~5t@Z}%cg<~NTD<~yR=%*_CuDi%u-h>rSB#pUk5vwp`sgz0pwJ~NH^utV`|i?r}$=9o{@T@@o*pvwc!3&C|ZAx zj|ECy3X7hM%vYyR2;y8{%e}7I*Q_sJNW=mOn{VP{*);IFMR2t*6*PH?!c|?mDZHBl_QV8wzKNA^@ziOXY;5q zGF52Ht?<)L5ss!%=fJ`*+4({fB@ zaUXuX8p)KD{(ID5Q8`HL35mk{H-L-r67rb^UKzHl2K?ezao)+uEGW0aeE^=>ehZOO zJ=jL(O)+GkpFNyFUq|HC+qqeMTtB9yJfN<5N-dBh@J>9!EuERHxVezZ`nGnSVkvC;o{#zGt_1J3yLE}ScGW7g^B)+L&yig+GqioSga*wSuHP^@Z%lt zUSweV4c5?v{yizWdJwRblsuR}$7fKb8ok*(EA|wH)4It-(?SE(Mv8-4M;f)MSLBDR zj*xDB9Xh%@*}a!XM?lq(c%KcTdAe?Kz#bJy>wm3R-M@=z5a~abO%mD10y4HmtX}v@ zbLpi0D>8gJ;dbO1_{bM?Z=5-)yVCCW!q&y%#?|9WcvJ_nTE--Nimpi@(-Sf}H~S zS~5j=l-Q408+O1dtM`4A-=SP8zG>6=n_h9VmTb5Xze_kx$TnG6;_2IjBEPL2D35aD z#k2Co2gk$bjzyDw?Bv-0`FhP^H~82}of$JTB0SM%rFLHLL$J_3ReWOhpmM-+sqq7h zEY}4y&=n4&CKrP_`fs^Fk7mmc6M!3zN<1Ng`C2+oMpcbR>gxKjZ1>6w^YDJ91TAK12v_gy8>{Y z(UD%Gu-HYYwjcT-Z3Sx|9;F5gmO0aHa_}@nGcDDuUji%Pi`MjFUtgEd&c>571<{_~ z@6M#vuo(40hU@#tm{{ZfB|r9@r*1a@A+C(5hW^dkZA1gnO&Xhx(1w4=oBLe;-T7Ew zP5g>=#{*HjOC*X#!j>YiBQ9PT_VC3l{aUY27MdIuARzTs#4j;o}%_&9m! z_eCXKx8M4_vIC8$ip+J=>%;e)p0Xg}gN7-0F7R=>$h$sOQVy??fN)BDfqYNvh9QbUAFC~2^$ zmsr+uYvb2eomfd`ab=mIy!@*SeOoQbe3EK{jhPKDN|ly$HK9GPzIM(XKZdEgB)+w1 zg!J>{qI2arHmf&VekXWeZOsa*Z$1WK=-yj&`?h1OK`QBeW1BH2odxg-LF`>mJz)TX zwLaXEoFEb~mpZDeAKJ`9b)FFBrJ_4o>5J#WT4jU+7fed?%rTN+u(&;wcm$x-0QjIg z)Ur>(BWP z^y!L*(D^5qn=Uu0VO3+uIF|XtXTngj@ar`G>J*jsNR*mHad94Q`t74J;u&-@LqAZ=*ZtNCdZAz2RQu zZVUYBFPF$RZ~eYNjsJb)NP8of`i{x=-R#9{jE7&^y((J(;*OS+xF$R{Aw&Kc5u0hJ zB@{eAzspiq%_ZmEiwBok9-PPvy;ht<%6IHfb|0bkk2r*Un|&tEzyE}dJ7I<4?j207OB!zz6t2t;}CEL?a_)cF%lMs3zRU=+aA>KD?L1YG(m` zEP{9fB)pLnA2<0IBaRj}gw_>DCI|c27wGF@%Ilurtk?Xmpy9qKC4j1T8+{J>V#&05 z-{Oa)Mt(90S2HhzB3W1GfKl z9n|36R-SI-lE-OI?gC0gS@nIFgPwh|P~B8)#Krm&Z20{-CO|47%*I?w2OPY3 z)9amM)#XR};03d;kv6(UuYZT+GyCC}%|EZm{1|qGJh&n~`(?A8ghRnRq1MKf3zF8GhV*f{dxl=a|+bR5E$d|i>FY+Q69*zqaix! zKlp92n3&7@|0>6ecsNeUTG-HUEtI7-u+=l7lTczIQ9tsL*yifrD_J>YTNVlZ#7T3i zxP{ABYgt-KKRk}+ev{}!bhSKy2p(Y(+}b_dF}nj!(gTb^%r zBK!C&D12YfU;p=(?JPSfc5Okg?-?VW_;D|Xen$(*0^R>j|HFS`4~ z0{5TGADuk^aQbju@!{O19K9;vZ?z%)lY7XxI31tuSx{dXm%V`P8^)Yc-BmU zs63U|?GLB;EK9`>X9>Up!NF>af$Z#|aC;))^ItEcnzrnv?Gd!=faaZvh_FU^%Xe$r zwk+pIBjN!b(=?v!YC^|%u8p*LA4}Bi_02uRFi$ueh2?857E-k=n~apPKXZae9cSzF z{Sa6jz-1shzHed#PO){d=F_*h&APSP2Wo@=+K=*%9+JU}9T87aucNlcLO4v@8(5h7 zouYP(-0caX%z%cL*N-b+=)g_yKL>Sdo@Lv?E0erZxS2Ah7PM5JLT(-8JHPW z$*yml64Q*;_kQj#E{6c_|YRbd610*6cjhRri zdkxufCALod;SakVG19Z^#Q8t6jGqZz#oq%8tEU7)zVVz!<`aKF2P&gq{07`rMiZ7k zP^p78axrVjFz-TWrxYN&38(5<8~LPCRh()q`{&-h@8NF*qxZ z!WzIp#mpd3+tw4>*b#^t>&i-+k>vdR~LQvvVYZa?Pl z{@vq1_x3lqX$jt2cyH*iy7+%BABg>;eD?Trdh)EivpYA;N|BKghui#Pb@Nle>D0mX zgLBc_&l{@y(3f+mBa)T$ir?m5L8}dklKDv4lk@~ana!Qvi|Tl zH2CQM^@m&W$ykoRhX20&GsZ;XO< z7w(GK=!8mUpj|O+B0s(z9qF#Jtj2v(M$0mAb}BATOC*^)M5Bu9U_XPtt{26gdH%thV7T-)<5mv@+~ukvr}!ojc`$!wL)kPV$PpY{YL+V(sw8~EEN$E#&@&Vl+ z(hxtU;0LR=z#rZ>x=PQDQrOdjIBLv0?g|`(e-ue3ndXFFJ#;W)I`0()qXQK5>RZS6 zd(8;{w9Y51dm)2a{LV+MtM+Z9fTbgd*}Lk^#f@g>tYc{VJ*JnclLZyGT!)*72Cp!jZivMBKzgFI_7-tlwAu+eNs0CXDiZN8$v7PS8r z{2Vm5KjdM*AQ{#$883are7eTP?P0j-y*iY{fd^m<<3$e74}0F;TJXB%n-b>sbS?|$ z*M7o?T(oYuaegzLhwtd69SB(=iTUZ_5lK_QcKRo=wD%n~zd1zECmKoKZ& zBGb;XJC+V-Q?>MFyR9JH#w!ZtcfhYY*ZLk$foXU{29t!?8kjDP8NJcYO()GR5hODA z_r%F<>MLYB_d3Z4`@3!if}=+zPXtWx1leakao$Q10t-mWap(8FYeu1xE3OY`hlOBh zl{_D~UBnODW!fa*;U@TReV1E} zycRel0U8q0`GIv=Y8plXIpaA4C7abhv*{zj3+9U}V|18i>%f)F79*jw5VZCD>G zCn>$Y(B1OL1sC;UC>Qe zJW`1bx46U0m|@Psu#U4rki;2*aV}YgZ(FVGl(E8SRUJ3>QWM{L-!IiVyzeok%aYo! zUy6>%vid_{Q;xnCC8!0idyU8>P^iJl2Mn%NCjd6Te{atZ-2MC+gsM|(Ub=qRIUr)X z;K4#1Mfi>^y5hCC;w{dD{LwUB!r^A1&v>`Hcg>T0_GRd|Wm}Z;K%=90H)zdS(DD;N zAl|;qJonO2U$_mxhHae2BM_)qUqN`N~q4GhzQ~iIB)6n33)Eyt0 zwrMKM?8T2-U%305tNYdVwkJrNPQJ__}TB z1N@tD_oJvSuD<|V80w~>WxuE}3Y+4Kklxc}*}!IU-7tfoIZYMAXK%fqm(KKc+8*SvC z*@M*mKjXr2ihp(j>1&>`9PXa%c4TK=2Kin$MYY&_D$WDKJ!_B9`um%WqIA_K$@eav z5469ZEcEZ6P!P`jwmw?!**vDR7^^(vycWYoEvRS#r&WPMf8j7qb$F{r#5EMT)Mw_P zdAh-IYt~ylO8g7gJd6ecN0S5id*3Vv4lb7;QZEo&I@uRS6&`>X?nm)qAN5(4vGo~j zN@?Nmaj)t2is_ZLk~b6|Nd_!&u-KjME9&VjSf^iI_<^M5lf1CTEfI`C$OZjh{+k_% z_9?tMx5%}2zZeyX?x{get6q(n`I_bxK(8d?|p zfNI%!`zBYiFnNw9<{U?=5_#84jQQCg!@@?Xq%f_lUyM6g71RR!_%H6-WhHQhJo6@b zRt*s;V?^R-@a)l)yb^Sq1aW~CK_?$Pl?hm$jHNR!Fr{(3F$gk|4Q=( z6*d|d*PvVrIIz;a1`WWU26#q>+jX6~zaDDe;%hFQxV~kIo z1}m9@?#DRl6&uUe7E!5}@yCo0N=~0ddZH~-2QV`{AOvXe5A($B< zs5FL>>F+ccgQN@JaL;BlD3B;dOOJ#7OV6|5+9<&TwPJ$X$Fv>O5@(^ z#g`wzEsv3TMgEoh&pp9FA%sH*pA`?x_v#aP$r|qjXrM3%%pip|^;4PF4$`AuNeRT3 zx#SNVkhqUPu|n%=2pvdZa=3KxqvR?NRW$D$x+UC>{oT=NRo|nj4@mZYb0$XZOp_o{ z5Qt3B9)Q_Th=|uN!ves;neYlFACOvE$d`*eyRLowcD-O3-3?I|dnsCA^4_fQCL!=D z;7%xo`zh6*VtneErP7tQJ&y0I<0nNheD=QpvVl)!`>7bMwMkot9=)3vlO?a?EXj3* znIaMdRWqxx-pWLnoTB~jpbxD^KWlyyZNCV7hy9FojbEBkVl zdV{+0yjem86`X|`*Y{(eL!!_?b0dOs+dw6IqR{)m0ydRIjX|Rp{IoML^NY^fQfVLzRYZC zg6_h_M4!Phrh6q1@CO_ep?A%Zv#?dJ-Dom$wW}QPdYGB2#;k$Mm|ny5vEI^LJ8gdM zIj>nqBKoA)dsZb@Y%nAnqX+=+ld!kFt>y1ABDO=$x}0{{H0z8=0nzE-i)X)v)%M<& zt%;jdi6-t`;Q=Ya4X>~1SkU%oW)k(0Sbfh(HS@dWi?aS{_ivB>r0#lS(Dn3wI{DyH z(sQ15Gb}^o06~J5X|6HXm-$8iz9==LHF-SDOYORnzlKk?Cipo7{ErB}+7`0X&CBfQ7V?m7QI&ht)w5$m2ipEZ2ZDgq9Wj{T zy=P44;2pb$H}j84Y9wN1uQV;~@J%Y*KYeB4E$rB&Nx&|fc2`gvKo8aMAL)7f<5XGX z`l9a(8IZAfc06tnn!pZ^zU)d)pPAOXn6V}I+_oZ7M%ZbaYP{4<^1=45bbwPuLh=99 zikP8Sm3VK&Yi_*a>(D|}AeY{)vS8m7EZprgoej<(`5?ZT)yjWYmx9iT%4MTBa49U$ z7iOW^@h@{6YP^-J$T{~FVqqJy4W9^Mn5HAaIG3hUA;c)ed?v8@bI|o*80m4aWHKZ9 zJhq|~7t!L#k<#3E_7`gM>!15+f5p*=j-$J_80?GE&6=+NS@;och5Di$*{$ZVl?xv5 zmi9rqSS##-lZvKiX1obQuMm18>LMC&y;x?$x?xOaeGFQNUHc2X8wp{Z zIiUu=Ph!1j4Sk|Km`C;r13J!V()v6b@7ey~L;ehb3COG|D5wD%S-mkFFdzg>Li7^@ zzrtN;ZG6cP*V7!xP4(AaA#K?Ki7Y#+0aOrbW#EbK8xY3?C->q){f}U|vrNK5 zTSsd1I7R2TC?OD+q+$GXx`y>N_j85IZ*VCYHVF)1{NKX?Hj=boE>%&s@I0Sva?^JL z<5EHbi;KfDDr28WZYgU&=MY=D0M1HNtOXCa^8uecj&Z~{W1w7tzj&7iB8Pp%{f{w{ zLV1BXROk~xvYc;iIgZ^B4CngM>{b3SLP2@6wMsV`LI#HS8idQzI0cZOVW@hBJaKmZ z{lRY>bkAQ^p!Ahl@c*jFz6Q^gQ}(#2QlgrL*=GzeMt|SKBVpoZ{n+N|9 z1c)mkHL-;)`+VQP_o{lY=li#eEz<7`O3e9vl`ZOhVNvz6%(f70?TPd82nPS-Xc)Q{ z`LlwU{<%H&M@L6X!j6dA`##B{>!&gh{6C^u(xE|L3k)cNcw$G#BOVt|(*VGm^*&2E9 zaDto|I4y5#QX+0}VP-ytOwgL1CnLkeJo4~n6m!XW(Bs9YqVwDbEQT=;kYH`NX|A{I zt6b~?f@o67^Pmm;6@U8~6bak?K)V(dbcl)(_zgjP)&hi_N9;Yj>awp%PLwB_ltm6H zYe~<__#Qh+zkm0`%UN3WIWpcy0I-jn zEj<-K0rLLc0+N-hihIDoKJ)LY!^GKOqCYtt~bmW8ldi0K; zAZ0%V(1`wj8jGki=cOM~D z#Y_lVtjSPt_oh&H$bUnw;Qf#xVot4c3x9aX*6drYd-~(pS3;YT8?Ulqo9by8+WPVi zo0gV3ApXtm4VV&{U|p z+YD1J?+>-7ygm1M{k$b5{yB5SK$ZcI5IuIdz%u_%0$!AGWXQCk3EVkI>5tlr8$<(v z-xkP(&yZth!UDNsoCZtxasb=V+E2*&``-uddADqdn^cPYYfJhRkHKJh! z%&ORrmT9o#qGv8Y94;K7>7=%$nNbM44g7;jqOFA&zpV_yP~X&({1+Ln=|SVqIlB4B znrr&~i?zPF`#~M9#<7pQjX+LH2FE6o1tEvDh^{V|nvcE3P5}DT?nd7)x4yv5_Y!Da z+qh8r7Hj@1Mxo~@bXEEPPk+Hzrr>J@=m?|zlbgYPlC5&>UcAYjA#+ngED1MNZ|-cs z?S=gvY!lKjhP`bDB~z^m3U}%2wk_zwzmu&8pA~PNGKw|t;9JhlzFe~L){+Nyu+K7# zs=xk?$!66oPhmkUxl?8mX#++JlXo~&70i~=(Nr%kr~N;3p6k)PwZFVhzQ8NLyvq)S zsh(Ag3OIkv73Z=KY2)hO4$b_gDDEUD&yV=Hh{e>;gr`$8;bAVgM2wJ1jF%~&siZ0*$9w9L#xmk{!c=Dd?)!Oi$ zT#7ic;VreqMm(p<5QZD)M&*pFp>?i5VebljgU3)O3&*@+vVBAa@3|yL(wOMd<(6vC48PstX<-5hI zhT`u_?E7^NXyY*4Sr(N^yzdW7@D16$y1NiplANH}OS^ggK#oyLH3nyhT#=V&&f+h% z@3zsLfbS7UziS0e5^%0;89i;AbK3vh>e0k*b3>nyq2?Tl6eqHJ_DwctQvhMy^K&h* zkd*)PYs7n-3EFrYZu%sL^%5;uxPxSGjb^>Te0S~`t-B5$rGzVX-B-6=@$6YL+yky_ zlDr;2*5Ni7DzU<<_-Mv}`YavVp*)B9-)JtNE*cB7P)O*UXNO&z@caf=`+=^HUF@dF z?W_+BWD_M=Oq!Ge@JoT1xxUYj$*X|NPHN&+>$1A9>qC3n_ST;!}X7$IB${zzmSC1Y3uA!12YYCJYqd=>(mNHIpj+UhX_EAA}eaA}7|NeC4 zhJ0tnLz`5im|Bj_n%}AtDi{_d!>HDPBB^`!Tz6CkHla|N&Sy~$3 z^)&JOqR5I*8o&F8-jn>&-CJgg_jf(vB`cB(SwNg3`bv%>SqNn-1 z^tn_9oTKbn+}4xsaIgfG*+j0!CSOO*ep3~R-}#&V3;9_4Hud=xDnj%wg=H+QWI@82 zT{r4gE%?=9ta+xm#9Q*je#Yd|FZ=@@js5=K;RUrA;(F_0zfVv~IUY|fp7S2PpU~<| zE8DQ7{v<)T54h`}Z`{kcWF%RtiX z8^G3b8i-!NHYVI+FS*p*7fn`A2c#G!hv7a%JUZ2GfjsInKa$&c%XvS(s`TuR#tv(m zn>-H8sJG$+Ri)7#!LQSg46mcL`=j6)j!MBhU`Q^L4zKJw>Q2#6d%=^E!+wI?|8r3U z0>%X?2N9wX1;s6!$qCqi5|NN|+G$(7gWDldXOFu7deHm{}?U!%Sq1n)t`cHb) z^cXe9AT;k<{Z&^hJYB~t@=v6`&`!*Hh8z5!Zn6G~RzhvKM5sz&B`)22!Pi1)lH3m=D5-M*s90pO$<<4)X(=wW&0dAB(W2hc3V(K(Nyw$9%d z7H?C`SAtj+-!J7h-!KMcf^K1;;Y#If4 zHen9`d57=9_31IF?t9RYuThnz4?>B*6!=@v zv+_$W3&-qi16`FZsDQ(6w1j;4)|xI={etl%sh_Y- z?N(YF@{baE;pXT5{v>WZZU%iFGaigHn_>;btQPf*`im8fc8r6{yJYyt%bsva!FG6f z4bXzF#z@)oW4NT^+f>+Uvg_l;p2OiUvQ02*3lDP+JMnr7_(Ye;heS#EYCYr!w*foR zperWnhaC}dfBF&buRh5DY-kLvVjOPsw=_p_Y#pnDX@@Rg#e+YX{K3K-ukY-j!jed= zf8{3myP@eEadcP}N662w#0=G1Gw4)W9C~L$* z_a%SL>h!~@~~8i@svWMO4` z(3knE+v_h?!DI@=HA=8hw0)Tq5uNT7)SiE_6TE1RIOVtG9Rl6wL@G4EREepEZGXFI zF&yaQAk6K=OncJSus0(zPS+VSKNR#6yGwlvHj`Z+(!l=pb6<{B_PPA?fH(h8ac{26 zS#D*`0N__f^}xoOqe>j3X5_z+DD(1ysr(8xZgz3JG+*2!R(R8eR6K%g+`r#8%6{2G zrCb0kNmh@!ht)DjcfG=o63sHpC)>T<&UF?bI4P=eqb=h4QT;iR zh4n04>)pt!W^XdZt3h-9!;zq2L@UM$v6{P^ zjWhbUGt!RU?XJ>$oy0rC&<&4BSaaIMh{ng$4KPcN5ey)3+;Hib&uo%JN zJDj^4#$8Y%2 z-Pge`Cn{pEIlVIMIE9=1#wjVib6dPRAW3eh`nfikKtKO&VzMXLbmT*c+&)i%S=QHr z*^W76$B}itMV-^vN7_Q0cL6?g2tl=-wR9H408fpPamTP^0VNbr-1!mte?*8nKlJlA zs-m^SuI={DBA01433)`)U<;}38sA~l19{v`rT8gbQtzn&%F!?OlN7gp+EW(}a|Zw0 zvCVv{uYSqBhYb=`k4#!#P{f6Y}ec z*G6htvAADH(-+~x@x5vg=95i|HW43FW++#@D|0NOlkcBL*!voaQEZu9BFk^p<0cxR zAZBZwYuwPnnL_lMb*C{I$DcLSM(9OO%urLJWmZi*9mq37-7k7!U)Tt+YcKiu?Er-! zoEJw&pVgV<%&04f79DyRDeLFRyIi&Jx)xc+PeoEZ+fO0ZQ`40vg0qS|Yw!vGNI+SR zX6i>J7WBiV-^e7w*{wGCLDzNm{R@87@Yazm;hq2g8QvN#5(Z5mhY>fqjX$PB73&HX zpS!o}htCH_!>m$CQ#ca#>)jGCrpX`7c4pAvHHT5-VfmLY+>1p4lAQ?G-{nvUHQIIBA^wsu>Ne=ZR`rSODke5gP8b?us6aVG!&$Wf6pg zyI&hBf$!#>{^oT*%1H0D^Y?0xjZo`110A2LxFQjgxPmzUb67E+9K2CkkhV!?dPS&E zZG7fwH(^k2U})v5uTJxnLZmxnt5NNf}1Gblqi>vJ!S+N4ZGIRPe-7cO~ac zl@Y0BPEHGI@y7*uMTQPZflF12YuDO^5FS-<$#Xf~y-)jz-e6QvS@pl8EJDi>Dh{Rt zLB}g8IzZ!e;(ZNW^icsg@PXGqv{4FV!rw>=Ob}Rz`vd8lsq2B^4Wz+ z9(9*Jng7s#_?4vOfBWgE)_=9DBxFl4zqZ0oPhWCir@j_nX!Vo!@6ypF(R)?Jn6O5V zvu;W71+usLpa){lB#)>(OMVXG5C3~YybKF@n!xNi9wyx0(%Vt?`K1VC+b4&luKU*s zwf##vP0JE({Z?$z0Z;@Q-dFT<&NA&WqV>s?Lz;Kj?RVh1tNb@HT~AX}!u;^(@d-&)f-%>L{< zU(v=lr8^BYi&N+g9e$|vUfPd~XDf?oDmZA)ZT^WSUJKxaIAd5Fm76k=M{@u60LCLL*r+&}2yK`I#X zF(x(qm}2;_A~5G|C|ge0tSJ`OPa7oyydpy{(ejw#7X?cn1}BwdD~Fp`HU+X3WmoV` z@5V$Ab8M^agwXU_EK>r9%%$EKuv~jwULI0yi|7;){K>QQWfeUVSwZrWg)nJ9mQ50z z_Q=-+m$xZt3>M@b&jCTiqq7G_aYI|AHN|m;a`a;dJuUW+wadI3u06hr&U|%}0DWZR zK>XnqSYN`nnhoDJJ}Ytqi{nJbBt9Hne=R+x2Dhuq_!2Kh(<{>`fgfjimzVJfYUs1L&h%Q0-mH4-NT-o|p+ z{Z3MJqpg^>c6wu~YVQfgxtd7(Gd0v|;pLEDeEn4;em02b#@y=;78w0jr2Nj&8K|S> z|Hf>W%cp)}y{FrB$e()DHu)btjG_-8Ata}#Iui-W!bY(LBk*h?G=*jhGbPyDrLItk zhJT24>|cqB{QzP3gXjTQtkh*xH!@-|D3p!m*{JaZ?wgQMIJ_e@V6}STC%WeT>a%Ha z?X{)p2S3wWJI1SFv!`NFV$sb*yC15r&vBtP0`?Q#4i^D^q?!pOr(lql4m>oxPlfk6KK2Yo7i)u1JY08CGsW*~ZBPY|Zfr0{?y8v8zD zIKB@$U74h_{q=f$8*28O?i8%80jwS{Y9Pu8eKip;r^Iot931>2GWjPeXr^x!KS*xwO7dY-;^E5`?36eWlI;mjC}s=O zr}&jF59&b()2q3I@HgK?%1?P>MM7~tw&v1LZ|GTK7Zno24G?b@S|0N+kG4z-_K-n& z4QrM5EDH7zr1}|Qp%}jil=X|JtxNg<3C(RcFo$jK8H)JZa_hyfJ9k@Yz1HM+{&2pT zu{?_)YAB@nb9XxnqFsjpm?B;|-Tm;Q&x--s+%@$o5cR^i%|HjfWDSKnn;B(jP78(8 zfv3g7xm`cf4F7timW+A7+>r|bt5WwuXH`;0mH~He9`s4OG}A*_L$5L$AsHG#Ev{WF zS*OmQ&=`VOqzPbCTMal%MItu$drc|?)uTCX<(pl^bb|bHje(8>zk|7K!WzJum>^vX({4HOwT=w1i#Ho!@F@*)Gx!yt zOU>f-ew53oA2XQXM+$v|b>C+~XZrEHJyWi>u>f+(W>VZrKP}JBpKurUpPD}XbKcGQ zJb-GsPyg!yDzZ%d1?jBT5XEQaq1xjhk$&}9nIKWrDyNeWJpx9&P|^GLNwq?hz%&eC z!Cu3ejwf*uaFIr)u7wG1HaSov1O5WB6d`|+R#G@m9pu8%Ba}*J-K63_Uq~G4lc>VT zdcf^z7AVfXr}y9ZK#qhF%F5k>Ib&gbV;B~BfBpLs^el)ANPS(%4FQBba}t4GXAV0b zuJzal{3vWr)maw+sPQni3ms*PMTFXq$DsYCVoU`!;OG~96L0^_nKA*>b>#_#7R{?KB){$l5Bts?bV%{waLmb_wlnjGQiyI#QF~DO zss>{CE?;No1}27*2{0wB0AGNG1#$lTs`~=5@4qf*?of(RNquI8^IxgP%`yL|es?dI zUz^wqe;#Q1Tt1I2H}d4SBf%c}=-#lUg+%+PO&nmp-o5wYjejv_Gmd3OuY}i@{ipay zO@3ALC>&H63kK?V+@x+@R0kfwIbXF`G9cf61}Y&U$vBUd0H0*gv;%}`#NG@TmW52p zij=3P^2DJ2JJ}vqnhGe9RAl(FW*x6{Av?lKBBe2y0faH`&txJDhN`l#sUxeO7paw2 zr;;&UJEgDEs@}e|IaLk0zR1%s-r2ie-<-7JnJZqnk4sA4hKgh2a+yaFDd91ww@V}( zh?;2K27+mxd~y;T6XS1vc?Te-BUZCcoK_}}u$&X#%t0;D=W{=$(jKN_1yU1qdF=na zX{{HFOPB@YWc`VqA^s}ww_QEee0SFR{&vg#fumL;)!o<9wjMhYS-+-5aYG}!j5lQ> zQC+*7c+cA4-dREbg14WRo5|-o(lLo#5=OYtMBz;rYA0qqJ7djElk3tJ3g9S^Nw#z>F#(jlNiO5ppL@NYM~ z-|ZOW0wY;_++o-LN#_-}jUADFz#0rX?*etkalmzsun;7On<1%rYETBUSB-kdC8nTx zmZ~en>3E$^a#J-hp^u&Or$v_ia{X_xV`NZx>D6IVp?=(CQ5w5CtMyZ#ln#vy06|39 zDM|1*)bv3nLcYW3(~juYggwbb$)&pCYKkPtUQ}k!ZwQgx@PWf*mjOt(aSb^av;y)7 z?^3bMRJ`m9ng;*5l)3$#aVeN&w?wH@E2gD_IJdYNL{i#sgK8Q_noMlZcE8#}jgG4y zHA9&yo>`r$c5aS$AMhFP@=aSFF|15YC^dc(jx(`Wy8HCvmUulV{&eUpY}8Rs_b>YK zBH`5$lU`J#5;x`6&C%a${0Bey2>=IKZx$yIw6cNWf&zd9 zPzyy<>4AY)H)thK>UKsW#ZlL(u1O9@^(nqd1`+a{ROrA%7by0lm@CQ1t4A@?ZXKjF zt1t#OCDeR;Z#A~8(ZM9vus)S@xEX4dPq+*L}X*PIGgDDW& z{j0Qy1jc~(o!JE&FPCIaCA)_eC1=VhvS{>LbPD(D9eijNP{^vcM5oI}=DJ{j%o$#N;?znypwM&fNgOWz~Igd-1r4 z+2fo2hXu|pVk*{XNm78qoigy>a`NE}&S%4rqF>*nWB%6eGEKS=*0RhI(D-EjGQVnG z4Y=)i*@$tsArMhl#&|AZPV>U{t5F@x@1cGE zJoSLL7yw_Z(*wkEQa|_`P^N(ygIy@7r}qXvZll}4aw9R5rv~rPn>05v5v}ld?;I$WT52UHJ%(~TM?>;49v3|f9V!rfc8v4Hr%yWAkF&Z=w*v&91(1(o4O=A&!(1lKJ>$*A zqRyB#T19w2TQsK5H$<19+y*;*`1dA`O}+?g?p=53kk%=Bi-a50$>}>R1sz#PKLIqy zu>eGz-HC`p6HUHNynASuG^|{w^XT=yey`_8W*JQH>_n@s#7PbSkuTu1Sh!f6SfE#$ zxw%?oUUJKgjBbmviSMQas!ZuQ^*@>?(48$=OM*iXWsD^-@#aTp@8?g4Ha*PsAtLrP z?gdr+L1N*OqV|}Gj)sGm%Vaj#Ru8rf4iX{w84H+ zx#OadwfP;*YXmYjU}IZ5>x_2DaNhWYhGSA64QBwo z*8kc;bN&sxS}-RHTm4A^_8_5ijM8s|2HYII5-3^L>`5Rk)3pQp|*~tVPW51*FWNL&2(es7mLo&3w{he z6ailTxF=3jJjM_ek;-#--vPu6+xv_t9uV;Ra}OH|J1Bw36CzInU6bg#}lD;f>($ZVh^Y;Bm&IB zh)jkwHM=?(X1((Y9W9wQ-?jEYRIy_>u`5b~t(!xuKH?O}p7pq`_~eCL^_mm1w$h^} z;*AAp65wOLu2~&&9XigVH>q)(UvPo%NlA);(%D_RPb51qT66xGAMTb&BNI^_$tE4F zmHKZ^EKeb~*6V%X`v;D)$9zf84}i&o4>@Z1sChwb!=~RYcPBNJ-dD3iXqWOeqiDn* zJ1mx?Xcg99s~&s_tDn?;89(rbc9ce)h`yGTFW*N|1beYwXbVQJ{w~Ks)xy(0u%PRA z!Tx6r*@W`WKiz_#T2s=VrSJ?J5dpEYZqhX4y{J;$E@WD#)0cBYW0`{qDM&|i(EQ0o ze7H&|-hI;ZDoJWQ8`+@03PT*ETpGZf)Lc38BU05>TBLFqsr$?^IuYfK zIZ8dmv3mB){oK?ukTIwY>^VmXZ&MxQXB^PB_*%!aa5s25ICA!(`TUG&^|o7?wzZ^B zST&8p?rt??$w2REwK$5gGiRdA`>j_EoqHKp>r9PGj`TQ|CffG7Bl2OAC`7Z__wC;u z`XN8;(dMAtW)=35hg&}iXH~!2y?lNLKgboxw6an{V5TDOZT~y;k0F>sBQ7Sn$2sP0 zrMB8l^AjHcwo%X7MOC_+-DMfm@7c|5Xa9*fhd1NP|4G5oOafIRX^}U-Lt#u_65WB{ z7l_`tK>wLQLV!t)&l2u>!0*0sM$MN|4xDI0%V+H{-6vU~RS3-zLVn@Af2`HSVGWB! z3B_39sUrG%R%_!=PUrq_x4c^=ci_>d`9Agg zw{_@NEoe+Ea#2*R>2(HzKj_lj{smZlFc&w_JR?@wzxzD5QIV*U{HA4t)17fiLA8!(%new{=nb}lkjk4 zzGGA4eSBYqYGyU+em`W%7{YJsI`9Q3C!M%G+)^xY`K@i6F~LJfQXJE|)U`Y>q9kN= ztQdnq|7NXGCG68*Vvs>-05S62=~A0X_;b3m#!Z)&8sRk_c|GjBALJzvHc>${$G*k`4367GRMuQT!56&i^ty zw!{HSeRy9c4wfiGPCq#%#~kTTXuO=q$6u)X2&t+by(<2JRonrBzo{|T1oaW4jD>LV zF)esQVznfgt34xWQ>ZmNx33kQilGM8vnJ3S2Is@h!HF@j|!|82btd1_&UF_75GjUm8N)prS0wO=fh_BLnQIzR8-O8 z>`W!G^(h{qnvdQaW@&7h>cr0CCs_CW)ErB!;@^yijTL??4*KQtOM?N(^4rV827m8K zg9W+2#Z4ab2C~v~W1V}hjHyzothVl{3?iq%{7@25`AP}IKgcSOz%x<;_$U9G#Z`YMUR~h! ztg#sb|X4$ zr6Z98(kkPQ5R64KH(}?=Pe?#mTW4vwhYW5nkGf76Z>BAVl!I2$aamGIA8XaZgcdr! z-;23dsx5!x#bp`JmFElY#*JVzPk_bpGjgC8zlYA%1+QljB(2ChIdVnm1*c%*``Gk< z>YYwy|3}Ua&@s%H8(ttMH7D@E|2{Z361kqd5EkF2Ok=w!`1`fAID{R50s-42T4#wC z9`}z81N_O1gRUPIWfGmy)EMk!K8yT&oqh2w%#}Mr81yoj@AZfz&&B8LdRnF>0>hAx zjo+XgndAgFl;#~s7)kysZwqcyOqXK)7K+sS1Qvh{cS-EQ5$`b6;B-oeML}SS!;`E| zzkmT&+VrhS@`(K-Q0b+~i*Vze$ZdPV%@7Sxup%odlL!Zs<@T+oM_S&XdqVeXloauOq^JksL?Hn- z-k~CKHvBwXf(H!l%9}p9p|KG#-rEhV(+WA?+D<J z{Pt-mGAUSnkfy|%APlLA51jJT%-R^N{A83^&O6tF`^(*oN0siY^ulgz8QWD--y!Od zx+hDu(Ub=FfYFjc+`>Vz+ui(c;G?O<@$M3SJxO|0JH2B1fd1Cu>qpKz?8B$;hTj;e z0{|Ti+R0=)r%zR=>PgMsD#x~(bOaqGc9BXxseiVk;z6%yNN%hMvXtY(*1sIW;7oeE z0%2^pXaITVEYa0K^LxB3^~9r!I6^_#{7czOuCsA-{w(< zD2|R(Nl+8^NHq7eDf=8Aq1}+W%2qz3Rqf@xOo4cijj&i6g~+0=MJ6}wS#BzI3T0y; z*fnlAp2zXJFgXy`Hs^b+Fyy6lIugPko^$e@6z+%&SFjoGq`Bk`9&@S~Oq*m5$qO!H zI`|y~DA!C*yq-%42J%BZHJ1E(T>6QIYFoGkAKj~33 zNd_+qotHknU5Z`)@dSY!*2KcrNm}sOL9EI>I{lbkwUO;a&U3l`O}Dz8F`wOokh+*v zB3=jzkO(6{-+do%uc|1a&;BA#EzJCxPMV%=NPxGb5N|+N4J?S7RqrOxlxk@#uTZfP z{c?{r>}NV_FnvLqNC4ptPGLiEyKku}1x#)Se@VwPnB#c9EkQM(K!Cbwm7B_syDpZ_ z$?-|742~yfi6cgfgZ9`rp%m4JS{!h$i4_eFmZIz3t}^40Z&SKJtjj{dZm=u~CX03w zUP(Hb-&zoiXuSL^tSQe2*n)@EZI}Aw4`cv^Hh2zZwyX4>d8h_@*poev@4^V-Q>N3$ zXXg;+-vmG zUAXOD^UoYNrn=oQ-`yNcVV#Y*y5PX;V(RgNR)~Y^Z2!pj*Ze^<=ZKT|BoHUBgje|e z4zQ1p3X?~9!lH0OZk8~~TeWQc3DB9dAuF7#D6MpyVBlHcOvnrs*BTDAcN=DN-0fT| zLsIUhOFE~d`cI1lRIEsfK5D{fSTa2B1L-9o!$MIDAV>)a51&#T-25~KAW?#IvsFkT zwEM?{_9Lw7`|K~-#FaLLS-*&z{xcP0p8v#BX%R>XdUmxWmLJ_}I;`~oB_cQ*oTv*R z9vlFr0~*g${}yTajgpVNIC1sH!IT4Eo{2-V08w#&%+J@6on|~>{#qL^TX?SHZCUav zwm3=*7l_)z{|xVm#Zxc{_!jTxXrIo)mV({<-@rT#a@j^j!qTSP#2y_j>P_9!}Z*S7<>;3Re^ zRsw9hrP^6OHd#8p;p2>Th5l<0?j74SKZdc;7?c-`haOYYFU5+3tFP;nW^>m7FgE92 z?05MM7ArZ@Vn)BlfDPfj`}wlxbSZa1XN&BL32V~iH-DG+sp8{xCKj{?SZMV-qF5}H zdCXXf5qO!B*WV=wSa5T4rsO|o=0CJ)?SSzN{?O-8f#9+!=Y)^;BR{OirFLqAVNvdV zJBh3yW2m!e{BTUt{ELJ|V}r8(ZkU^w-{bqGc{XWQHlC{AQl>g-p(B+%tG4gopUvC{ z-Jjdy+y6#PqozTsVZyd4@>hq{K}Xs(D?^uy$e@~2Ye(9*5`|lSMD+C*f1k$y)d_80 z?^dNov10(^p4mqX7ohwsc$z)?f_Q)ZWREV-&3C=XF$R3H%<9Xbr*~bg>ybbX0im`s z{S%>$5Pg!Wq&u+lHNlOtH_h|Oy=Q1InUHb(EUTGyKb*(AP__3z7h4Ms+&lm3TKg)+ zYrx~31q5;S1jAmrSd?e$c?d{$e=u4Xk2NPvdH`@5O#CT8Q2`YEH_g7Xj3q(hOdfZ4 zBZKJ;FFl*Af1I;U)K#9eIyHHfo)1yiHV?0Y#b^(`q%Q`Z_AIW|2KW5MW?0ZgziS2n z0mkxQWSQrTp2t_4vS5m3{A1x?x5=cyyb?o{dC_&9?JC*sT^RvzF;M1TfQ9Q$VE)?r z=B@V08Qo=PBIf}!?pz&ujx^j?hL53}8=E9mX*Kr&iN2P8!)T?43#r8FhA9r2s#NRB zomN89(=XN=e@WV!YFs&12y<%XVfvCAUAl+ku#_(m1@o6jvwxl@0*J8b##s|cANi4+ zk*Tfai&0Xd-9aBErN$Z*>EZDEjrVNaZ%pZy&im_JAmu_1&|iXPzJNS{NofI<5Y&Ht zB&7)1K{%|x(;QkIVsdV@a0J~7zPZc_a|`=cLA4;#3dEen&&D5^NgRLqF zq9U_@!H)z#)CHGf3^li2kYJOcgr%BKTi^O_`VEaW+~2zR?v9M`dAF=G zMCFB!9NY{(8PuUhe+oLfWa1yj*tUGRv09AsTWwGmcPMLJUJxxO6odd6-m(|5K17@F zYO~pEp|Q1#0jW}72?f!Rc7~Wul<%8Ty{Fjp9QU>IOi(SlZV>{|catgpC+A+t@@e{| z6I*B1=SZOtwcmbNZji&_ju4VMizGN$(58}o;qIe`qXDt$PWDr(V%^cP4t3!s~ziJR19 z&eOO57xQyth>IbfjC{~u+dBOoe`oe308rB8N`$ZgqK}59SggjSkHd|=)e9Qx|4ge& z9b*z2ss-&GmhsI=nT26y6f*%AVkiM7v*=KlJgaerr3ArBnnyZ}qM$KJRN*Qo0($LT zwZ|VAPo{wgv11- zSsEkOCGVZrQf2<8I`@4XG1veeXJC>I;IwUdU8`SAGVl77feoIjq8<{uqWhemhHO>C z-3%hGkJ;V*VvgQEF!RG84)AuywdXd3gjUf>Z2%Yuh{LdHM23$-=9Yy`-f-b#+ z=CMd1=shNYAPQ|PLN}_?CK5TkV(_S&v^}i{Gee?(%rm&%}5WD9C>8F$CIuJzULaGMp>4hW~ zlEb$Z{)*0H-NqS5Id{J}HcQq(1vcbo?WXf4&d~DUdA9tjz_%h`bLN@~y&ST1Fv-?P3_;v z+kVgD!)tZ>w*!>r@7*lOVDajwojJlsM#2ONA2p1 z$(_fee1{H1q&}4V61G)j{AR&Z2*pKZJ&53VYR2Ni_eE}C$ud{STJ{YEh{eE+3_F3P z26@V1t{>zN-Hq)cdHD}rimgwHX1ZG(3OaoQLJ4uK9G33LT#iU(h78q8t~Nx+IQCNc zJS3qm6lpI~VRcdg%f+i-2$_ajtZ^lO_#oAorqGk!&0C)(wChD1@?r7voDr3ud~1x^ zmdlb7Ca?F2ph}yWjrb3XAE?j}{KMRKeF=C7sIW3uoaDB6`X;ub{m|D3zt4}W~dP)t%YlQm3 zKWt&KWBfLAMQh*)bZ7q@g@3$|Q65_B0=ws1;5Z)1Y517#+!y zhXJ*#A6lN6xI}iyXcpZZgI%-=#4NdIlikjab0QUf#n$amybw?){NJ zQ0>|VXxqDkKGKk@t%1=#)wCu$n?iB$NraFPJU=p7nIJsw89PP0+F&Xl;EtVx9>=CY*@QH=DxKz&7;z9gGvL>i`L=Ypf8$F-hB%1H4CZ}nE`0NIqhtC*77R#n z2dgEXGhpXXjj5D%Zt{PdbI?4tFLNC~$I0(m+LBPF> z{m&ETE=gy(>GR@qVybaD$?u-LugrEZyB000rz;bOe0ri&2`TPoZ?q$RI*R`~dSzVoxUWq>2R)(_i+nI+grjbqBVWQ& z1{%5;1{~x*j~v!J?fsZaWjn+VI`1+TVPs_lnT4>fEGV#pzCq0?*~$|tyzq>m8ZS24 zv*?aaV&j2-S={n(JXSaekyrBfNf~nLP1NysHebe*KiWwnwO44KV5<<~V`G5J{`)4kVbD&0Z2Eivk240?(k?l%-Q$izMd#ee@dyC!-( z;2@V6_2i>+Z5MYi8~d{6^IyVsbd&C6o01hZj6`mXpcUBg4+4ei+=3;Zzn*Kb*9BwL zf9&*rVDo*B;+u!7l5+TNYxe=KsQ8}3yHScXAh>J@R%{j0w}oGtUJ##6>yXiQrWBGb z6lV*L!;myinf43Uw)m}r2Z)+HuM6F8Ztg}Nk9M`X{#1soh;t_Iva76PNBcYE(dmN_ zIvlIoAL)-vQt?nseQ+dXA-z9_O?q8bjt*1zXl()xU%=GCHOyf~t zlj&EuzM(w~C-;q)if2d+n&amQWI`R$~az~LPgGEfouvM-S zZUdkBrh#(6(*MHN)m}NVZxRovqRK_+PG8-(ZNIlYHYG_j=sxEQiQ9QC9MppLGKrti z|3MwQON~#U9b4+M+~BewQV(;)78s;`Dg0;@*PQG4(9jJkd!C7w0ovl^8dAP`> zH}Is+!4_{#yr{*}pGGILnL!^zu8hH4-zK&ymr@5fr)0Gx+Sqmyk-y|Hx8k{cZ zDbod?^F!m->%o5?f)*~K-PVD}PO7FC>HH^w-Diu?P8dMpGM+xKEl@v!=<)qVf&G*( z7CBA%s~yPLV@Q;R=eP>SB>?Hb<|~f-34xxs*L7mmb>)YE#rwe6&%})=^m%2PSf{@x_uP4KDZ9VTHiB1Jv@R8yTQ3^))V)y@@OzwWUGsW#TLd37IC69TaV~! z1<)xWaKMZfhEGDv-IaIu@Hi#$$-Oh^6*zp!cQ>fzwMO?Xy9VO!^*j%qKl)+ACN06gXPz9p>f&~yXxNiK zurOCJ2SCrYuJdmYUnBO@iXr9aPVFt7r-Q7V;wfSOG_er-h&I_9d(R5Y6VKEiw4fd$ zQywxv@RN1XFeIe%0S>E+geVk%`KC-OSkETCXL5I8(=@%JPP*$o6lS6-Z&S#5AARhH zUeL5@$&~I3_quBdF~+ZW-_@I4XeM)k?v-CpnipQL zo`y@>i6%#fCLy5e_}<}Nc7y~01N#3?|5h+0Ny6*Y;GJyU&()eN{a=d9CHYh=jE=qC zJX(Igk(v@V<;C1u&yVW+4I8WZb-wn>erIORe#gg8owmbr1y8dX*o()}$|8QB2O6{| zy+|!H!U4Rmx?JBs-c?*-HWL_;V3Zn;_wZ(Ehm8+QwK%pCv;_7%Tu5xbN{+<56;Y;l zXBe8%JYO&#Sy6|1<`NofzrW>%-)S3cb5IGd! z{hCml5anTk&1jp`&RAVe6{MSPz$JD4vDMfGx}*5))JGTx{PT@dtPgSV1@`G4D6C#p z16Ut8V$pCzW}1-wdS7JXt5rO__^+_h;%}h{cMuHvj7D-M7Ef5)K+I4sbzelN34gGF#Q{(9 z#r+A#klvHGX%H80j_toe-zOw&ehw~Y=B>V)RM`rAZfo&SK4r;2Dte?RNT-Ke+gLc*GM`~xaAw{cyv)zBenU-Y9a8|>A&pE7 zG;P+@Sx5E1%o_jxR0WauZVOJg6;BiSl$+wLo0JopS8riUb)Dq*#AFJqx{|@rMr>_Q z)~$TCHAW5e&8g+O#TZw+*Jq)>j{(UVJ~{FQXc}C$A!Moix{!Jit*l^5C9n#crs+Eh zW|mPX1F4Z}5?d1b33wT1vg(sXNqV}phwGZ^Q!xqkLBh1D*Fc(V|BQNwbCzs3urdMr zR~u@0dIM5syHAX8;@rL0BEG#{E&MFHLdf=f33u^{Ru8UCzXXW#1z({=xKJw=D1RoJ zP8`5E0gceZzj}^}_k5}r>=~PUsG3+jeY*H{d$JoYa&;ViJfZ%pNrFgqur1p}Qwya>+nKWOdE7rx!o zh#Fmp%8!W@QFXs!k}^eIYPF0fM*|M;9eWzOacRnas?nSpTlo(8%Vz+6KtOi`5}=`r z2R_TATxTZn#e#hIxh+wjyDx{Be92zi{Mn!f^?39vgrN zgmhE>Iv)3!>J*5h+84x!@Z_e8O1zc^Mg4}+dxNJjp(4d$-K;NJk}3v*HnwxtmB&{$ zWoEK`C(est-&&=BU9^^%zUD#d69O5CTJELJ2@zZakk&T0;RMxJYRy+A5F;x5nCvnT zr`Si}H`1F>7OfbmHQmoZ4pCGulGV?0_D1zB%Wl*cx`kA$-#^?KHw)8I;W4@I!)fk% zVl&I$w+Z2_1l_!@I{!sZtfo3IoIprpzR>+`Kq92u?Vn_>yLLXVGXxm)wKtt#WF%hKv@u_9pyrkNcDC5>mK?ZhWmokuZGfTv;h3D^nW6oV7CMu5 zpYstE{Ur$03&0F(&pg*N5NrZ8orKYUXoD2D2<3^aWZ1eo+x;KcRoZfczbUdVxVml0?*SKV`jM zJ~5rl!~qPy1^0V{IhZyFiGTf}Ds5%J@rA*?B9TxvY+Hfy1WhX(%6qMp@#}l76feEKbkP$7m*2>LZUW;S_`M<)01=b_2IO}rdk}>u zRBg+u&<36NNYz*aGY@_Y>c=W~N^a8h%+>%_h^IQ7OPB;^z{f-JLVY?EK>1E2uzZ7&|^vD z*TCOM>tYo3Om=ZOY;m1I+ur!gL(J7M_t_}?1hbOWUPP6x%BlF@jgI}Cs6YyzY8U?t>XZEl7KrfeLT>e3Q==o3=nLh+FM+73T zup7mG9xE*bmfjs(J)E!HD;vF08hkWG^(Fz=Yi&?8ld)H?I zB0uoEW8f-AW zJi!f)ZiGe%$)_jV?f9N185-^^2wjB)}iu~19%KFk{nE!YcZE6-tb&R|2$ zmi(BDa9jG^c`gHQVA+(##=<@AzXWwt78c>y^|~)J8JE%(YD-patq8>*Uii0PR-({U_>t@ziUg!;E{g2 zTHmVtVavN7Y&rG>Y)_(^>A&qx%`TXRZ|Z)I+K*xH5f2FQ=@~H=^5Y{s2s_1y{Gh_{ zQ`lM;n);vC=d<+9fO*nF;sBj9J}+nc z#jvNWFvdT47o`ei0OCLrTWL`t@k1qi@0*TbwIxu_y=lr^VNM#tZo9ODxDU>_ui*SM zN@)-!oLqwd~LDjv-?Ec+}5E*lZg zh8~Wg`ThHWSrJr?{=wd3l|aA_H>Zch1v(62s@eaUpdneWOI~o}L4~Kk=Ks1G%8^_& z_+6VzF_``9^B(*|vnbB$l*?y*H_C3Wpa;M>E+BZLd%k4My&2-V#@~U9e$8(x%AKB0 zIjHw0RZ|90LWV7bYV}p4D`z1jxC?m8Z$cXvii9qmYcG`mEYs9Uh(s-u>^YiA`Yx z89S5!3#D7!p(ZV28^KKoue%o%GUXi)+`%@Hvg`j>etdYhBmZVu^ziGz{o~&N{(PvU zpa1ijl~KO|ad0YIez;{=H!(~aBppDalmlZxcF)T6b(EWx-!{6mlU_`;T;KA+1kL)F zAjBckD+@ypzv2#$ewkUFzOGNZL-O1UYEFSy>DC%Tf;~R8tzW*% zCp$!ZdiV=-X~?KxA3qJ@{En*dA$JEO995|Z(`@#r(tZgof(l%~Z~o*%A*3`YCK+h3 zyDM*#_Kd`_CY8QGF&>E-$q9IFl_-2<+@VY^lSu0RqBRV!is3r&#W?+vZQ-{$74`RA z>+kqNB(wog?oKZFUjgsxlOVY|QW%H0_D!EE2?7pRE2+N~AM=v!KcQz>ZETwC_b` zmcQ%Z{qwi?VdutyndGuVt_$80{M6FK8n5#eVgNebBua3~r^+aTo)9DlYQ!96s9fAZ z)|xhjpnB)dvPvI=8f30+g`0X$;dF{sM$~brgOuz^8AP$X2V-5J0-H~zLH$kr#0AT8 zT#T<0nmKu2B@^)FCr7;a^@Yr2lM#bN@K3sSg? z*^ikAW}H1J(&)=%_(xB>46ZiLIksozD|Q=~mIq@AQb#@qt`C(xH#n^U0oF%&!~LLI zg69gFYzQe$3Q}hZ(!w@dVf8xU_q8GevYi|EZ6YWPC>!~&;&e;F!@XEXy10?CcdG1B zWfxg1ZMvv~rbW0yep0Iit{;XL;?o{@E=kFHI@oe130~7_Wgr8jeEJQQKDOu4wvW*D z;PAUbX?zKxfq*Mkc_4EDy5dbTU2oXeDWIM-#RQ_NdN=>&!X1F;BfGI+>^XlxF8#UD z&S-?U+{R)-n*yCgwriJX)3MZIdpFG*^bLk_{gDAIim3$K!Z?#yNZ_)B$vz~Y!b|aG zam^Pj#L@I}x=KE?(!<*&9Eq=^tMEmw4K}3JoSyg&$xh6sma^Zz>5*L>egvQuC=l8} z4QiF6Wn!Umg}Tg2a=3Gj;Kg;Qsmf-IHDOA4r|kc~Pn$89QeOY{sGG zY{%m=9;y^!$MxjPh%&iVaQ|^+p5RORpi6cEr;jQQd15dcUIAKxOwg2s^FT?%2q~Nq zX;bv8wzspw-?QK!#wjZE4=JY)SZrl|IT;DX9`$`!*w^+n>D%nWNA>34vIY5tc6q^e zF{@vnOM?F3=CsMPm5hzj@J5f#HyDR=fj&u+cwUs$1)i(8fj>TT7ql*&GEc2dh!f_= zbxUn75~rdRGy?%JQHVPgi2Y;*~fnR2N{`TGNpebsgAa{;Y7t zqa4H$cKfn>IlG6elqym@?eNr9;=Z1A;2o^~&d17QU0LiaA*94wFp9y|WJ}W2n+PlG zO^MMkX#^%QcDkITT*elYdZ~Lz2MdI3>FcNFDOYPL%K4t`_z`CGl1BWBVl12vNtk9( zMzY&|j{?U{p%`q!xgamK=1SR_qp0u4iru#3wC5V-cWb#kW z38pa;x~q6Q(^74s3Xya*aog0|cG{A02q9@Nd%{l*4;tqWas;6&^-!eKi{vR@L@4*p zeh+D{k_gDN4Eg>LMc})+mJ7bZ{4qlSSC!#?-Oe)|{Ho6ehzXy2a+PzFq(r$+QvF;l zftEu4`pfL2rqeWs6XkN=V9FYYK3-^B!T%XDQ)c6wlaSIM+R zRH6V0WJ9BlYUoapl9cZ5y61o0&-Hnp z=f%7~d(S@W?DbpU^;=c}tZKU8Vf)TRjHX`(&!xtX4wyiC8#pIyS1hHsFZ{)0=zP2N z#QUA8aI&K;Bpc@D7&#$He{$l#`Z1$j%+rVZ#K*r_vpP;rw1onsFqsx>xQ1?XiLR<- znfIVpmo+ZxX(zIYrU*A0&3WIp?g_}rk&HWZTq{FCyw_akyfO?mV%3J}q0ek7KpGIkz0mA#%>^dwT_ zwyhGuoC+6n+r+WM3ZN8+3{&Zek|@Zf7_@{2b^?$u$_nFZKcg^nlPd|J*mtzwMWE zb@C36FkUm>YgMRIE8YQ3~PWbc@$Gs%f-Jc&#W+v!s65K5r>P_%FyOPzt&ZK|W_>Q2zzz$B)C8r4om7 zH%-C0yJ%T(e6`=LE#mx0b`N4(=4QzIdorOa5UUuPBiZmYl2uwc8W_0_NWlb2UCn%0 zD%xM%dmG08MQXGY^s1HQDHs4EE~eucilN;fjfN=1F#Klr;rB9!!TyL)8i%e;;}1U5!O!j zibv>W61x%yhEt*->W`lbj(h843$ypPms!DTpRkh0S4#=DaO@P30jRSq&=x{BXA1W&X1A_B!3aeL!sus6pX2q`ELL{1cU$(N`#MxW;TorD{qvWJD+ z*SW4)NmA!=_GpkLuy+JykLcpA%syvdEf7myem-IR1`N8%!r!(%VT!9}>|qG~p3heM zK*c|0d7Dv|#QSN8yT~z`d8acqz7>TRDSi?9nk{ML=XMf3{N^g3pxd?X7E$X6TB8o? zU;`!~TREr_%;7r)u!(y7&g4%3e#(&03;!~U<5Uk5UL-wZV2%)AF61I2sARPL&_21P zYBlTfs9;J}9AhI4LIc2fE@qNM$R~8TZPLepxE0RN=I!p1l$M0oyeYphFc)33VXsu6 z>zi#p!*`-%ol27a5 zN>f7hmRRp}=>Oui+JFkJc&0___yCFw?ya;L3*Kz^y5lx}lz-qdd~U|3xd-d5ApK?j za_}zVU_*3oL)nW2$`<}S8P+n=sIkF6w@rXU16Jpz{9XVIV;=I*RM)RnE#?jPvxi0K z+pY1C=s3aI3h=ou@7Mr%z&dVnf~?qG3JCh`HPPK*Z-?nzR!JZC>ZOL-b+cW{DyYt2QFQ`a!hG+hSHjZ5pt(W;$Q}d@w{W1Ea`&O~ zk{x;Xd--mybXLD7SjPo?vJv;rZAdp_64RYf)g1)ni36zVEsuSYZw#KzgzcXn*Rut@ zbC3PTHI8L}I9u@GrXAF@cA)OnZD-lQMD^ z#aGdB)jNz1uXm9mXvOC1eDb1}mg7>2)UdaTiUelzFmlkqWaIp1`e=}b?j}M+cXWFE zJOcupE~ee6t{J61Y$#t~ZwI238*iezf{I1iENM=s;WgqS(XkLfO*oMwyH@4zgRUH4 zQgqny=|*=YHL;Y=WJbg+$b!iswDNegB${Z}xDaBq-TOlD`w2JsR{{b~ zfi9`bPs`?aGr_?*l@gf;q1Pf~oeD}Mk7LIH>qZ^N#LxfE#Y~_lC_qPsK;d%d5{lL+ z9|OZH0N(B-5ZI0SVD+=3x+LPBG4(OxHiQPw6FD0k{th;84p-ad>P?5KtXR&z-hLjE z1Cj_~3;&{EZnQCeWc>c5pOKIra%>y{UG1@?c~QcHD2TVNuKVuBmP3LpubZ7jXC;X{n?E4Lh^3XsyXK&k{~s^7 zRsZ5TC&&vsC$I!rRpM`G!3zLZo8Sit{L>eV1c-|Rc_hxG-0?#>c1|t>lWY++N$04I z96bCeUb>+Z7&w>oP3=O@x-SvMpqi%@$IB-7ukg3&95*?#1b9D+*0)pu7(S3h0?MoX z>T-w6-&DDHVqawxaaPuDTZUQ_*5WM`O2Q>$3)n;X@Xz=DA+K9%x%>efEzH>XmDUjB7ToK%M3>|(bONOa# zu9z1s(kM?}aQ!!~**pu;S%41BLDJS)ZHrr5TE&Dhi3+`OxxbHc*+)hE?xXOiw^}F; zjX=wdG*sd@@m1Mn#wW+mPgPzZp|=!@@j=|p6@IFI`+Kg9#W|jaL-ll|^rkVHTp;ME z!ruCENYy2q7GyH^AZn0qzxqJv0*3^=8nwzXfB$reoFc=u_pgcJ+yza+#J6WocamCWSwXjQM0 zsGxW-G4KyKF7&e~hTW0Kpq$*9dcIjdW(Tz$s{JSF@>AFUcJ`wnI8?gKPFY^)cMQiM zej{rTa3xqM74!b2GfzudU%c<-&;S?>t_8S(u*jrnnexE!ZxyQ0x#QQU^hb};z_<2&_lY z{Go;+=1^XJJI5UXM?O#s@1rB!%5sezGj{s#KiLFdv0(z@9Swih!Sn!B$*{SxP1+E_ zy}<$#K$;=pwCtTfqNO`)kclxDCR|Kz)G##8w^+}Y*7|xTC~7=D(*u9DOn;^Q84Vb- zIB=g*4C;jKgvW+y+XvTwuKKmW_$zK3nPsDN!sNg&}MS{F(3_e9K7ky;hE$?Qb*Yru&wCa*0|D9 z=Q?M1amg|7U1R(9ECI?XjmM1{3e^_5rwcwGaD%-6K3siEOmx-X=h_DHG=ox-*;0@t zH7_CK;&vkK$^=~6aOyDc6;#e6_P4#Y;m>`3*DS)SEaANRd-kpv3$Krblt`BrtjDDR zAT*zkr$MP<%jogR>=mYQM9%q=UWvw89dq3?(HkjeeV#jY_2M_WmcE)CC?WYN!QsAx z`#@ryJ}W+qd-!(T>)blEmgG$0YPp{dU@BrB(%0H$Nmbv{(4=XVXRebBg3*-eaD4%- z@x9^7P9MvR24EpFGwWG*J{Df2 z^7+g(&>Me=;C9$aamO&zMK~f5KlE2r@b>o|gU9wui!*GyDq|Kdv3QI@iwgXQdb_dw zl4p&qiTx%tSp35slJz-+T8$MwT^RfaQnIhv9n3&PlrIOhMe}8=D~Kfo7>G80R&Yd) zyl6pgG#LDjfa{KmG4l~kDLZ;s2~JG*tyE=&mkJqrO6(;x6+i-c84^^{!2uL~u`e|? z+k73diQ948*BcoSyu15IW!6KmN_kA`2f3h768z{Q*tvszW-HYK0;sK@3z@B1E(IU0braKph{Ne{}p)zKiz9>`2^`PrT2%z+~q8{^`V zqnX$&TizhYOHqs`H7H4gI`(F6=sb|eK+P3=QbWY^%?Ifvr@Towr{^d5i!8hM!1jBSD?OIe#UJrA!^LhSq2 z^@zDd9R6>G;D7Yk>QBF1A??!%MLhwo)Ntnwje2~5LW9LzSs3h@06Uq$sEf4Ew1L)o zP$O8GAq?<_!?XvO`vugx=8L$Cp2g}_=PmyE4rS6YY}8vQYTDp4qhdOOv)f$At(-y^ zwC|-{O3D_+rzAXoxjZZ0r$8M8fqAC~;L`+j7;8a1U=+ap2^TprA|n3}O!x9#NKzf- zt4gd%B^{bwTyzqqc2JVASu|wvAxj+mhd}m6kXE}9>l3m$8Z4Bk0Q%l*kpwX$(Jp;? zIk#xE&|=oNqdS|Ll)I4YaVR&}L4Rj=Wg~#UcvIqPcPlCM@EFm)(A1GPy!~D}6ahm^7dTAJJU8WJG0L&%F9h5(=Cyy< z1nn`MsD1Q;Tu?&7PZ+Trhh-anngzZrpv~!?ljZfSQLc#9K;cfnbyrB>jqVrPaxoQ2 zfEH*)z5WZ@5@}AY5CWoIH1$@|0Lw$QG+LHF5tgcpTc4PtCs`l{Br1#vz@Qka3ILkd z5dYkhV|$nH4SSn`{REor6rph#z^1oeL7$OVflkU~!zRjmNMJ~bf5fRkFkBV@cHL*lk3mRbLmILylt)1Q2B7c~B5XgooP`W4*uLk^#+<*RYIa*PBjV+89jzW{^ zmqbQ0MP;>hy}lSX%|P8iMSaLu!#*u-FhGNHu}aKEyqYun$Hy83f2`oReFManv*P6S zncvdVD9hZ9c<9T+b?m zrFqBDAkhz(XJk#s$HN`Z!3ep4Xxl{pyMp|x{&)K75&Y^b?~e?Tq6svrbW=7^12!lB zX$5&28RLmhU$zYOL1AK4Np2zWk|EmQWm5GGgN@#Xa~v0-*c%2u!_iZvk$*-ef^|Nd z$BQA+1^ON@dv}Qk3_Kk+>wwr-#IK+KVYX4XbER?6+X*?uE}u6Ni3YQUgf$W&<`Izu zDk~YoesNFue!!W1^t9PGWI@V4Pde`J!+>qgNn0M|@m%3;2PFzg5H&A3QCLe~c6M^E zXIyF6H~H&I_*{23D@mKq=ylWrtLr#BkI#4g#xb71u#S9j`vEu+0|gX3-Ws}{XEsF7 zOn~#|y%~2JEEzUsLL35cb46S$370m>e_4A)ng$8eSs->j$EC^Jz@2`J=Mu72yhoKr zG2(vX83dBU-y;lmEv+a(Z-o*pYrbdC?Y9=KA#KRRS!z z;OloteJrgm&zL+*tM*)zfD)d(*^#gUYXS*n-YqOEzWR0+fG-NH3j3il>`>-SZ|D@1 z>?>KdhW()qaQXDD%s(D{VD>ul8rdo z34Fh#Yx5hbv8Aw{txonc_cY`9taPanrRV1{a*2cfmj$rJiTu_Drhpj# zkQQIsCdp^dSkN+6eEcKeM_!aVfOV(u&)hbSa-4Q`c{>;6aWa;7qJLW%_mexwxT38YEa$pt|LFi z(Bt84sD}|6xJbLNav)&Gw93w;+siW?+a3~)V?-@cldnL9YA`*Wg13_vp_rZAyRONP zwvx2nDj%0y3oX$9e_*-0%eT+Brj4%#+Skj+)rnVCru@$`@6J_TZV<22w=%i1#rlaQ`atU)I| z=kOjVPNU;Y5RwpLh%1}reZuWe&Te%wu{9gt(@#*r?Wf$U)5R5C!~pYU+c^O|G@Riu zXR33V>XJtg1QN#tMKTQ4hPx3cW~w^qC;#-wY3G@-dtKME{Ff5f(Taxb@wV^Q3GMoM z*!kbxR1B7fXxP~AF$3pk`AqV4fq(5zgYCrSlp`ad`K0q1pT9~JqdE(QU^b#qGAnJ% z$HFa&U$Pp#w5^M`vh3i(A|K3(|0F$!PuM;j@wS=pzuqr|*`X=iTl;7CS2Q@f?!Tv* zK=hNJ7VF>7=yc%RB4W>j(b8%lK(>Q03V3eYz{l$cf{E}-S2g)nLe|Rt83ZZNLGl_& zDnc;(f@bBjPnsT9>M0h~iMMnT(`r z4A=nUaRD)*vm+uj{)O{wnQp7$t*BTi8AMA+KME88e`UfdRrf%f%-z2R`*KcRV%7PU zL58sZ%gGUgD+Cg$Sl-8-ajHw)d^c=k%Kdo)EIxsA= zQA(^xsLT%UfxL?f4W&mAH%r)q>cU}GKfZ6z9Quw$$+=A7PwbDjAs`7O z`Ty#99yr^?AD;C5-q0f}p^%o?xV&ba5P>HL0|^3tsNBbmX`bD4x5i@`=~MeH-jWh# zpWhbT9R@e8G?<|-*7;*SK;O=b*fQ+VC{F9i7M)KHVdxFJ!^MBTVMa1QjGi@ZGh>5{OBj1yIHrLzM95f4AeHuFo>Kkr^704BLM-Z2EAN3y>EYB+qo@bWH z(Tjrbt~MjJo-fBfFA&6vBdypdJ6dU6^eIkf$knC{qIDl}lvl~;Q|{HUC*^Y|1)Bn* z4_l>NKUr5l2f1|ggAPOI5x@i^+Kl@*ZH>LO)yG(!evcvW5&-6{_ z&FDLZZe6pQ`6f9(D8D1KK9bTDrT#E0_-wNTz|N^H{i3W@B**eRnIRN1U`9G{{H-2V zy9F!2k8xu4R?Nwz>EvG@?u8(ws~(&3z2@%#%L?W@Y|A?Zjge$(*jaipscQ8h_E)jT zg#5osb-7U47dp7bzM&g(VOKZGy5AN?zN6)D;O60>6X39I`B-PiIeU-n*xJE#=h()n zYVur+O6ZlsN`~4#0xGwZp=0lu8;Yn?TY7g;vi0WYl#+i5D!u!ZlmN$;H>;#~5tauQ zimXE>(`$?PNkoyEBok+|4(gEVlmrD5;#AXI?LM{ed3ntW&EY4+(}Ygu25$wp@02d} zb=*>37z_xT$^IwGOI_6}I1y!CQf>!!>ysOU6~Ur6oyWW=xYEyydP{+=^+!*}7KwY*~mfMJr|YG;LR_Ygy=BzI1kPEeG1C2t*iU(r0@e6l>T zOvG);70SfQ#PP&fgoF1j7|cVH!Mrh@8p5JN_qF|dpy_||ltHPRn-HQTwJ*bYFQYtT z<{)k;>6&NO7$NHxnw)~2*fn5q!{~F7zGrNp>!U{aUN#w%`Bi2ym#{1f*hSJzlOGJZr+(w?%txy`_=z zbey!yq%hFmx#!ZO+pP)JmiW^re-Gl+m@i6Ax}-K@<7NQx+HTX8pi`X!=_&$m17`r< zhMO)y@g`_p3Iw1dp|_*Mmv8gMJKrY{m`re^8KCId5#a;X(^2)y`A0I4+MXUDGnn8f>{KH`%q@ez)?=G~S zVWy7Et3zS(o;4y(5PK~|=o%JT+Gh$iBV=WOT;3S-@T;9diew9EH_)tl@M$PPW05Ld zUNf;#QTqrPoCX_oL9rV7wI@FTo*#69W+FlfV)JcO)0-rqxNP0{BvkbU7u$VHi*7(n z`&(YM+9yK=H&oU}G_)%cKUBaG^EmP$)*W1;ag`&G=2vOqIT5W*E5j;^Mep!)_S|t! zOt4i=rMtFKGF_(aG&_>4Fun6ordeTNfOO%Z#$0%{;Q^f~BI%s#{4urQ%&ZA%l-+i% z^*zv{aCg3AP1|!~II8=VC}5`fKbl)uL-)Y7)D7dLhmk^XO$mTCTy`e)e}tBFBlM`J zxwn`Vh6|oEyt8&h?cJjF3Jl0^ad*RwcX6f_f~`q?%@{b?2&ky5X`~H>UZr0Srw!5m zi&|jmSXgDFQDY*DY-Bx0*1n)dmq;zeDb;3uqz!`Z;8)8CEd-GL!!V<4`Rr&#AU;HH z(ce=|P5lCImx3-{N;-&Q4<3kNPGf)ONXHgY~dqd9?k%0(T!3ghgWGmtxA>rm|p)?0(~!im1Mz6g@8rBuWtp`%DWD zhs@*p*nd(I&$W#qPQ7j0&TmBI8$XQ|rFlTBbv8J@BUyX}!E{9l5d|jP@151c(-D6F zvp9|Rks7{>>iw)0bGRJA#twO-$zknkT_uwMuv$*<*-PckT1q4J1bampN<$Ui27FYB zs#io&0l8sv6I6@y95ym}SsMQhdfga^J0a(imwXxjvPS!;4XaIaG>By}Y@^$kzjH4H zBl#|g6U`^z?K`GUgZqP;rl1k#SsiorXRosw5at>Q z*v93*zOaioM!ttIax49!l-HehrrT1^5KFF6_a|+@7@dO(P%n zyKI<=Pyl-SnPZ{u@REF0qh_+`Z5xe@Jr4%bIS0fuf`d4@a+_Q{4~9EFF|lzN}h2~eIk#R?YkoE zp5GK3M2FEFX$`)|jU4b3Ly0TLW0XQxgNYeS#6X~Yh z=7VDUDMHK*JQFKb^`hBioHw3)M|%rWwhJ`>${p9g zeIt*1J2E5Ai;%v4GU{&9xXI&w@3Ya-_~9Dj$Sp=*`L&(!mgeD2h{cgoyu#|^kpm}* zz`jbb_UDHh0e~#lM(`@B!cp758CI2Miz#;WxW}n%Six!W0JS#WNb6o18kD2llO{*-cr0sj@lXOuAu&-iT$LqMsbFNJoM-++lDL*|PGS0|P)A>l})R)5GKKTBWnjI=9!Ow&tx z-rNY9-EspcJi%r(S;s8fX;LO}(zv)#^Y6`^@KUZB&KsLj(<6P_HwYUQEVGob{a)rL zWE?v7!E%O>@1fg&Mvx#<&!UToOwT{Ys3Ta5&kgh@=IFN}B;cF8!{^Jd2wekv7jc6| zv=A(cAM&V#z^?E?08W$)qIFk#H9mACf*BJ8r>;!af=_*xdQq{W=~ND z8~}k=?Dp7p)E(nr$Xy-P4qUifzTpGQB}uP7Q+;~WMK!fomAoS5p2nDq?z~O~ogGGt z1?E0dJGJ79-CSo!M47gj0VnRN>Lh5F0PF`CVc{OaHf1Ce?M1sU#tdl}eggh{P#xPz zt9RBvHmyKudc%F(zbMU0@iyZ8%XL3*2PICB7K}7-eP%N~Kj&}PBai6~3J@>?3ee7J zkJWT30&py0g&F~9!)Ut@4z(l(#|H>N2a0!`YCnIlE#w)zch$M*lx|riz~Ia?<4wZF zhnjs<+hN`z*YbNNVxbAiO&Z3fy%*}VxmDJD0kFGZya&q`w{bjPFY>W4ho=dHt#8eW zgNUH=KA#C-acySb2}M0MN>)vr6X0%?ZI%VavlfC~XmA6FSssUb3vD$0>V1MFc^S{i zFY?wcioUK4zEIJ3c?!jiEmQ{y^cp%IyOR}Ki}PMWj&hPAU)vR%GC5y1X$wE)kcdqN8uop~uTa{eEp7BF$uF?d^*gNk?q@0O`^cbH5ES!gJI(Q?ky z-gIJ6fu44Q?~YKHL=tgOe=r}R@1xArIWf`=_(0}}dFjA($#|CNIFbPRsM%=HO}0YB zbQgLyBw2~3`aoYHBOq=$>bJF^wN5-%;*XSx0v%!S$9YvKDp4r>y09KaPS{0#(+tLQ zSmQd;>QW^jZ}vT*J&8u~v&9yFlIOasI386S%3|JX!N<#sb%w}7200FllqM+w$C9*h zkAo3TfIRg4FI^wr;pQI1(Qo=6YD480-l?+m7(e``5UT?!7&Z5W6xd`B(KZI$JV-1Z z>$`lVxDf$@ek;rj6I!8~rO7n~tJOB!SA}w`iESs62b*M;TKo6_%-Q&qJv;hq(nC1g zgx=isybGT1{j4>Vb9XEr(c9;+fg1?wxo6OKYYBIx)-r3XOnL52o()&Xn`AQrMKL*S z1j*0pPNf)5VoVbs%y*Z6NLhD|LBV{CZ=v=x=Zzy#?spBe`rF?U<7wzN-$6qW>3~^p zZ@!0QS`Z$I_T_VEo{?PIAC_jCK92;Om>fZ8$r5yLI4C9 zDKx{2jEsa8shM+9RI?{KQ=Ko@(@xjZra7T)BBvy~*UfsCjHSMr*-7IA=%)U30b(|10{-(HCr436=wQBK=I0a)o80>i?4 z-<+_o<}1Ou@i5rO?h;!4DJp~-^H_5?kWA=vfp<4zNA?9rHqU&GCGJMI+m-064{V%d z7P}^%@#S-oQgz}xS#flF)m9Y^^EIeTkOTp{mr32`YHV>pW`=WB{9)u!py|s>+~vj( zEcP;c?%$lEcR>L-8Dz+-YN||0LIhxp4I=i>Ea|-Yog6h3gRyve806Yktkc+N&zP9@ z`b*UV_<)E?Ed^a6?HDgR{o?i5kzk~d6G`Cur-qYp|4NGA3pNFpj_=eVt1cWU<3|3Y zR^-XUcT@T!-`N;xkdHKJYod%tmi+qU^-8XXvzT|7;PrL*InuaMW0KZBlAK`P%G=K}T5MRi{t(>!H5RJ#TZN=9gxm)G zYNffrX!#{q$Ue@}fEEo!8=D@Y@LoDi@_^FjBL&FjU6u{rwvZWD`FtUTz}yFO^P9`J zGhGtLyG`W{i4>s4hcd>sZ)NOzXgB^8i!hK!_(`T~)pwg}OsoMF5(rjDFXv}M=r6QH zsA4bC=bZQNwSV3ael~M%6>Z-&RCiuXMIs#bPw#~Ktn|j4rUB5qsn_emAXsemKGHRl zbh8`hH+e{s9&U_elC(^J#&rF*ldUxm8(Ul4zWeg^tZ&;BqTQk@xy^Seksmz#3zFXA zgs%?jQ1NrqnWUQuR0Jaa)%SKdV@F6WMsu17XONsOaF{>{`!rFy}*a-1`E;w zGOu?{u+#K;Bz%6ogL)8htB2&(o7-w+Gv0a4Ao#+!3gWILsE~0jo!oM`_4;+|`Qu<^ zgkGcB575yb>T&zR`g!eV=ikrwRE;>ppq2j;-ja(-;?D)p8hQK#-uIsIZh*E2wlgaP zP`E2Qds669E}tFp$<`~SFF!|pV`cT`Rpj$-g|6YZee3OheQE?GhREOq5?dzl^=4ji zk2HK72*XFI=7Km4#Ki@>r3!I^pa>_1!AJ%z#Hc|Gc-x2GUpoWfulp|hhDC`KZfKI# z3SCAN-;|NGibHO=V|i2UP?Us5Qc))4=EJIy6)d47VHrb#{XGNdJVUar-GVEL(KLFn zDIxKrXXj%F3wp)c^LAqVj5LO_;P+8thM!{iX{Bk}CS+kDTOa(KY5`Cv2>sJRSYS1W zzquqP7yB-sNGURe%h9I>)0P1)u17%AdD4kW?SEDDFOc@dE4Y(g%+i9>7?!`Dm9=$W z;-iU`&Wn!+PF}e4-4^ov1z{4}`ube2Nln|Y+m6Y5Q;Vro5Etl>*MV1K&XuW^vo$|I z&*qnAbERP-Y2HhE9b9>AQoH)XXYGB+Q`S(A1D!7nRN)R!@7b}6_!^P_Ev=qHk-nmU zcr(XH@FBmBx}c*NJ+lP5|B8;rUz-}n|8hmE*>V<*)Q59lo7;-My>}aA#)_*6!_~}v zX3MTY2U<1erao38KGujs7|=LIX}`JZ#)TqVdm|8pf(3*d!aqdnGu~a~Xk+-Ujq&RY zxdk3twWfW({8_p8Vbd;K*Z(PH@b${1;Za%o^4?qw-eD>|vu!iVA|;L6K!L)`iufYj zkhf?R+Po={nESpz6KrA^a=2;Og{|dkse~Y4;TIC@3a=~gr`JiTp{e8O{g1?Li`>VB zn!l|gKYqs6{2gPP#9`LL1AV5AN&2X8eB}EA<=g1$-{Ziq4NJcZW8hq`0W)(N*<+NK zDBw4S*&O)D2DV|@b$^<~d9toZad%p`uEb*>3H2k0?}^~_>^gz7dSVZN9B7a zJ>@r-k=lLy>cg|HaOMBI8QZ%A%1s?AH%O;Tg`XwwJ-c~q1tEv-;fUI+#N`bWc_VJ3 zSKRq^gQo~=!Ho6~6eWju4cEog)0kN+dk%w{5|ky0$F_MR{)r_?N9H|x52Flqv4Tn( z77XEAfS1duD~;m|s5`uVH3M5VWIT1QoO z{rqLm*G{#;*L+kFc*S82?vE?M$08I}7q)aK4(rYzx^7YPzF`7gCH0lDNjeX8V=qSw z;%U2}v(+zY$S7P*Uu}+i1{Yg=&BbMAO;j0u`5UJ%B9M6|9?og^M_1UtsMghPNNxEZ zEJ!M_DWeRmmQV~{2<4E6$Od2HO-E{usEp(5)g;xSM08p8Mn8U7G6$POfGko$X*!~f zyx3L!G8o1rhwW2dgN3wuyP%0hfIx~izZ+Fb=Ck0je?j}7djGlI3*6s^#Vc2 z5mkDVNIpFB_yHgYgZVUTk|6lEfq5-NeJj4DfhM78xL(#x?C9l zNl0ZX%7RW$pSb?WTjuwubCysMCU>+oxII5}JXxGun*h%q&F9|S>ml>QqQ0g6{-(>K zo(d)=J)z2;mDa6vA+wv#Do*cr0qO!>4hGvkv&zd>C&j&E{Aoar>(bMf>ElsJs2?=X z8|egY?N?{?=Sw+RDw`Z1N8EJ**1#Q5!MnOYhE$I^qTEyVp-`;iaNIMf2}X04Yq2E8 zD~{#9AC=)Qz1~fKTvIBBon(HphV5JyXdGNg2>2K$s~n$4$eB%=8cTXox@M-Y`rP`OML|ss1vM;OGUkD2*u;-z%5d|8f z&u&jyjDU-ftFmG97QWtvuI@yEHLi!%c<=tI(=^i;H_Xhe))OqUWyyPDwq%oTc3I^mo2KL^soD{%TIyUdkN?w+;SfdT z>syCd$-?bLZLW8+w5vyB-R+=i)dkM+i?&JQ-{;LoTeM)9uQP1U=(+aT>vVg3_Ca5o ze&~JUM~Ukj`7Y|&+dnC*XAC0Y2S-t+=Sxh6CS& zfzRaQ^$h|H;E!3MdD@LHbHlK#lV#26(z#!BAYBQmeLJVnE>W|OPb(bsyWaI-lgM$j zDPCg4*bn(&jEQWDr%T#7*{PIxaaOFHs=8Qf*cSpR@AiRuGqI0ZOV_QV>kJ>1(`N4UjH&-~IZ;wWGC&8a{vy^C1l-Q|3lEKV;% zGrZbj3U;26mJ^YgGn0j0O}w;*;-e6F1x`bnqyYFw46d65DGJBs-YxNo>K&LYLy2}-Y>6u1@1AFZVWDsnpXx;;rhXc>pyrAzi&@~0Di;ex+zA^X$-bEh$+ zm-zYq&`!Htyy9cSxT85^kODjVMt3FMN)_AV4&yG0QCXNbws&M22=ojnwP8}v(VL~z zDU_o#48iEIh=`vBO(&yl>$z^mf>D5*BkCE+&*{qgDXiy&&MSUK|0?<|7atL$d~4nU zSFt#Q=Wo6OaALfR^X0R+iw`GD=oATSYQng0gJkk(ZxOc;vzs>4cPupyZaXG+0xun! z-puY_a>W1mn!jg1%|^=D#lro~ZH9IA$rja`@ob~Fu-|Q6>OQj zG<|P3bd#HoFfpa)-%#(ysw0%Rn_4H-e^~kSM)#|d9>RpkFQybuTzxID!$CaiY=3h( zC4%?_gl<0^hg=6GDqv$Btah9JnqN2-*qO+=SO1@9U%JylK>=MFOw)h+qCD^+LY5PS z1q)cU-&v5w=`?Tq!*cjD=(;h+ zTFB@{$v1;Dy-_^A7%Cv;t)VfHUe(TyM@4&%*Boshv(yEDZ#aK6Dfcuvbi2xl$K^&mKs;D&dc$rTFW=N?b<~0-om{*UZp3^yp-E& zd;lyaBo0_WzOxqJu+v{@3YVEOO#$J}NYpTS?Zym2rL6sW0NC6E#?G_zUAEQH1+QdB z!8RhC$c6;Yk8-91DnxG*dG{zCE|jF(lnU9gu~mfaU8<%0*NrI4wc+;I&EID2qxi>( zed4v-C-%vHu_vcBU?Ge#53LgiJ%gSKa6;VlY=ESiID6ztY=u{_{QwA;_X^^1Q=Hmw zFW$1XjUR2ar8KmnN*m)NyQ$QJNC2a7)Egs?=aSM~S%jqIq7f1zJHii!%hk%|DCay=-DdSgz;v7SodB{@l*t)Pz@sdX_Dg z>KS)H<~j1FyaPWH43R7S}}ac#YuJ^I({Ex0q;Z zpY{dDy7k6q+OQxvp(P=|`M%gLxKob4`c9jOGqjegNylRv^%~)Vv+qLm6kOq0gMAWp z?D0mzc>h4Fx!pO&%bwED@@(^qqpxx$!|`D(_9u{D1IS^&ACQ$1m{%~Tmyet~fGFL+xxMIIB36BJT zt174BkYcP8NAEmLhuai_z>osBooSQz>kmN_KaSB`m?-~HFAY(V?$pB7Zz0SQ1-J*; z;uLSsClO(}Bx3MGA*8;lQHH%q4N{3w-+ukb1{s$0s9Jik_-utTQ>sCTMHJ^_v zA9{nuzn)anT;2rij;B_Pzg{DiZtva=QWA9_JeOt*Y z?OhC^V#-f&@S`eT@_UW2;YB1u!WGoOo-z0<%IzoxX!4#{0R?IR`dj~4*EM}{Sy#>_ za{2Q|P{AfOkt3oL2Y?+;BQgfVmkn(1P7;9&X*lP2aDB4E@a(BFA_)?vdI8`DT`=vV zy#I^Zfh}veV6Lg#UP|e=5Rrr1ZkQ~K{V|h*S+Dxa`-qbFxCeu;OzdodzAj+*U*6EU zWOF($&T;ucypuKRud6A8z7N*;%G};G?djWpG{T0lurO-xJo2KaqX)1ZG^9O*yK$HA z7j`luc@K4B;pD_2rcbF6Av7OC7GJ=-ph`$t6}rMQt~7~qv?t}<6Beeyj+WxzjgY8)pm>u>NQg~0yAR_lPvilrFicS@;H147s~QD!VoMopE9avc0v z5q}F3Jzhk}1(Jm|e3cp^`&FE&nmK8_fRCmT?8XS&mbHf4TweAge7R=BAHGZo>F}oZ zf>Nm=>!_Sx4KNU4o<{6&go9RK3_k+ zLw$xywqb^&&P=@jWA4flkN#D~P6s7U07G<+&Fty495KyXNMCVB{8c$6s|POneE3y! z$IAa{>dPOY{G$J#8H2G8#*%dq5wd2NF$USmUY4<|>`Igv+uN31w(QDMM9IF**ku`o zWEZkz8)PfXXZrr|{d}J1A2{cpd++OVebM6c$RJ5(5Lp&&$f~e}4Kq#XWKPCDYE3cj(N9mkRD)g+SBPg^Bzg>*T2D0SI$RWS;g2E^*$!CF@lyasK(q(vG%UuI$CFA!f zyGdj7sdUDZx*>63KZ+^*K=#fw!^_F8f!ACiyKU+GHmRmk+pA3IMf>gN{&R)%LXn>Q zZ8tZ{hnL@Pyo}mNP<~6PX`4df^&jf$>E8ar=Mya&K0E%C26pn|B1`tC1{$Vc*N^&i zSubaJ{f}dH1@VFk60A?8Kv+RV_l4&tH8c3vYlY9K$N$P!x2TC365Z>%8RD5<25dI8 zOvpVs%y*0xSVjM8y^_RfUbTmO6yT;KG}<_ZVRW^b;Z($ zcj8hx#+9}`kx&u@G_^klS^3|^|U#|wXRs$;Tb zBGWwY-TL#lA;oih%B}Gg`NT)Klp_Ucp8Q72ESE5{IKcVE<|#h|WVi~6hUSEI&TDd?sNLzz!FG&9Zwk9>6M)t!JIR zbGFDoDjI!)+qr6b&QbZ3VOCYlXAOo^s3Vua-%kN>(mb!@w+__KUtP8raR&g+445+h zj-c1UQg@0JzP$H={%3kwIso>0Yadof4kcEpNu2rC9IKFl+9fd3qhf*zGt4@)(h-e$ zQ<(0%?)L_Bt-Zu)I|Uc<;@YNg#_v+J#d?^R)7*1%=ht@8-VxkX7L%AjVysKP99%4tJVf^qGyaB3`W&hGauR@31LqYgC`%*l!@gA zq%tD3{^ZWaZ<86MNv>V8gpY%YZP$bT<6{K6e-&PZo+ickizz@J%=W$(|KM;%`wJsD zEg`}U3;F>YkGhg>TPrW(Qz#lBa?l_6-ibVQAoflvh9|6?!!N!#Q!$8pHaSiH`3un` zoJ1rEVWTN^wHuINxi{p-3TnZ5DHL9aj1h3ZX`{gYEIlJFRC&4=H+;szZ=M4p0 zMAh7@f6y@jfpqF2+}?YlY9}&3pu*Iu?h|8m^IJF%k+S-_vTfbd!{thFQd%YIjkwjE zC_M!kBsCYQ9Fqn%#rn+0GKruV(fZ!IoN0^~iXHi&a3CSz$1#K#gzI;EuujeKEs6&v z6OD@(PN5aLru1GzdXy-6N7rXvUuFOEO(E@p&Be#L_cl~B)WEbr`hghqw-*uu?8PNb zHdZv1@k+-rl6fg%dvR+H7|TvOVPbz8Z|b)$`m_L3`^)_T`0$4gM&1>JOV|+O$>1|1 z>a;18h`oo3?OdzNLEg~2zt=}ctY#97lmu^i_3Bu3i87Ss4xNqKX^_7^zQ10oQb?7$ zx~3U?AvHmjDZ!4G{R!Ssi4lwpe2C|C^^(FXqkMcR8d$Q8I}6bxD&ZJ9iL*+9k*e5l z+C`~aRWC^N^S;AGN%MWBz%jz3+!sF6iLtt(zvcRYh` zY!a@0+P(S5@bBDy;x6y;ddlbCHzFi8dP+jh3$mqw$xHUOuRJ$?QM~y0bop8jyGlOX ziOYqVj3urxm@!=x*6$OSpS3rLz)pI3ajzUIQ%CoB0BU7(0@i&!e@p@Fa*ut50!;w` zr3KSE#xpLQHUL;XsF=>%h@s$2iTGP?AhCyVBBA(h_K=(|CujTLYHod(o@HFjq`J5r z<&Bb%yv@0;Cl-Iy{`|^2&(MagWs^cHTHP1|DcaF+<&fOP7AVB}OOFM;Ik?fb{#0wR zAo5s#v4%P3G1_@P8I1jXBKoK|a(psWHEGU#hZGrEUYV2dnTc-(37A%^u>wBee53v5 zS0?Klu%|gF0-5c%KNXC)S|a!rJ%;a(jutjjvOkY39)Xkw^tqfb0A^}|L>LUm$wZAU z1ma{Os7TX`OmJ1vxdO?bIw+;?C(pop%3n`0P=G6KgbA^N;Z`>m_pxhS-C?3bn2)X$ z+E4b|_P8GdM-o0fq@lyJsr}vE>;QP|nvE)qZta);I4OvrcS{Tf3^&KxC zy4)3EsX)6SC<3132X`>d?-~lN-#1Ww0I1ndBt~2KiN9{Yc<5Vhw`q74Al~gd|1QXu_mBS(E0J0;K4OUU zMid*|a;sypfj4ty4Mr<3jsc7p`>>cNhCAES~ zc;h;}bm^@Ky$t%rJ***jHE^DuxDL>4}0BAwTMn)sc{QMv@20SsQS8C%4t86edLdptf72 zF|Jm@Q$`b^xp;s^fUpGSHo=hXj)lKzkI7mL;_5mlzGclS-J_8KPP)y+Xr{LVCpMAC z(nhL)ZTs%(ew*1W+emJJVqzrzyPd4<+Kjo~Yx10D=ckhm$igpN?jVrFnK*2b7K;T& zz~x8hnj(b`!jcdS0CO>javx1+p8ks348pynl#~B_J=HQ#+>eWA)8?l13rFf^*d zlOOSWdBM9Y76GJLUya~q*Ebr`vl^eNt>@NR((SfhX8R{w^2F6qKR}3r{BHPCXPi9M zY02mJVHQXRa0V)G*-rF#FBb{TX^vlMZv0NCZj(CQDSE%>Yq4x>*;@I2VK1+WrL4Xd zIm6@7W|l8Qwm5YohV0;uN6bpdtgLwCSE@D731C=l}`RFJD!gzp8bO!KSABeZ0)JL@>8p-?4mJQ zX=V$hPovEBM)f8e$vRP}+b>?D%@s!@Ti~rRZ=F>vhfJZdraoZ@(yD_0EOMwxvdARc z=EFn7Ax2!=wI1QxD2w)TeNTG)8Gv1TX5Q{Q`8a@DQX9EFz9JXNixImuc2lS|d_+}& zs=!~(SEes9tkkonh$8opIZM2sk@k~#ls_T8K>jMOG!j?tc=V!Pph%EfPWh%MZ;XUn zIDaN)u>V1r9R9$ekcShy};_^RnAL>lJKo6C|F!Yu;w z+nv90G0ZTccHQ#`^CgGa>LzasHHgBtQ9AEE85YAJbvbgaV=!8}Y;+wCd!37wNDt*t z(wv*!i?>-rS;ZWS9kvC@5HfC%oF4nhrKp-+>4}D>Y1NQxyP^9N@7Lk_=L{TG;T4o9 zMRmN8Xtc`;BbTz?gF6&Xy0a~oA;fvg*{WQz=O;MKiKP8BK%pX2m|7>0FtORmMBc2?a7L5qD|F_ zL0}gob}YN>V?1fb<`$38j@)3o^`KQbwA~4(sEY`nWD@o!ZO;1$E4#(rH^qFp;ZF_d z40l$Z9di34g25TeuHIx{_%J^NZU_XfT%(`zP1x$^Q%D_qV3=f;+`6ukN z{>)`M`y2t}5M#_4_KvcZm%xg00Ed@Lb=loE(xczStDsf!?-`zpNcu zx-YLjE|AOz2xNeYBljwEVFf($a#bp_GZ_^>sA4SeV6E(5Z2kW1VrWWqz91eqPuaxL zOiwqL!;xBQ0+*rYH@tclHXT7qcwSLn5#V8jWPKK-$NSkR-Ip+hWC(#t_ug>P(>CQl zA4&NYMoAM5qyl(4?Bpl|gkAlnf~)Dneq!py-v!e`0#~K+X0q#7u3&qhpQO7}&W>Mb z`~OE!=I9OX_8`xE(IsN&NCsX7&@G1*8765u?lRO;kH4HvGV!{2*{Rp)7DXNjZW#Z9 zRk9j@Z}3L0ha#?`zKKC4o#M~>`ISHRYuf}sV>O6RCBlAtiGbxv9gM*2iAL~EUZN&f zSZux4Lwomql(ZRIYrs~`4RB;dxI)+kJ_%y4oQCFv6ud7eGnzQDwdpRP0rHRcUWws? zeo{<%{mr0*B@f|cBP5rZ8~?KkT&-FS$hIFSerNKoP)f;9-NPzd8}SA_0({cCEtm;R zxS51Nc&9gUM$2Fu6X5zvczwZ4#g-O_SKq*nA=2 zrXA|h2FR6tPn^o4Uw1&vJNe~AoITkscIZOkOs=Ux7qlg zWIU84Xl5}2t~bN1lwxecH4X6<2?fm`9Y^?n!Mh0@ZS;=WNLN;|B|mimyKW3Fou`>r z+EihXPvJ0RUT4t3&QAo-=VlO|y2kPADoL~mJ)vz>9Ih^&bcQE)lEwPy+hPPp!|X$q zv#Pubw-fsU5O*caaaQC+n_3pB59LO=r(W$Ze={DdQIHvAAU~21AA3fH+#(xYnI|yV zJj)E7_huWpFpUo-<0`em%5^Pdz&R+p`^6R3q;oFZ=YgUxBJM}`=O3y|zVN=w^c+I= zw)YX%&>xC2EICc;7Shq0rY|uq7O~~JrZUN>f7LepXJg}6yHaRtDU{?iu}EahBxw^qNXD2YIda1+l4fPgAA z_4kZOn6|HdYG^d8=z^bmx^NaS@3Rip{uKoj?kQ$fHE&z4*=m{Yqh2Y;$e(&ns+*#) z{3bG9J+bHq*3B%%Pff;?D3Yul2I=iy)>LOC*mp8ug)C*<5+-6J{z*!XiusKM7CoaKHaKHFeo|Ou1R( zdXL#t!{MEo!?~otyEgfwgp&ND@v*Qrir`7k=)x+63*YY?^{%zof#3U}a9FHy(YlFu5llgDyIp*G*l6i$%d7K~Y3jjOWpUot2KFC!{IBBYgE`U(_`>38uVg#D33(Vo8Rg1uqJ5mG3COx;pj#X{~kik zr07{W7yZFqB=-Hm;f#5^xk7E8VjFjV_2enU+)mxq$;1?yfT$I)*m?-4`@2clLJ}gY z)2Y5kAVYeyBc@Pu^WyS@$JxuWEw8+W;~XiGGx#UB0QW(9{|D-B^(qe~JSHegd#Ky@ zbEFQCF`QYkf^tjb1~ZPowI0mDIb)Z##*nwF-C^i$(COWnC>cw1itFNn%p}%*Md^Xn zhe`a~D^DX*0>t!J(Cfm?zWgL6e~<7i_1kuo8yrTAjV7dvWKoNIWb?p*G1%qt70M%Cul8(&(tK$e7fS&!IM5y7*3C@xU zC$4H9r%wUlX|3I{M+zpa*HEmqz0t-HBn8s->G8t)iIF+QS}Ta~2s$+Qcf{qdi>hY@ znZKpxyKMp9YI1;WkKcW1FE}B5EdCz3he65ak<@bS3TPf0k2Q zV84Q5U!c%sTr`|MlH0!?S`1r|CaZ$mj2F}-c-XAZjBK$458uVQsb~Z z8U~|bpat9gj;SARJ*iy<+`v|^V+zHcV_tta1pabM-iDEDP*C_%L`CGZ(ObAnKGoZP z*)SeMFIUrzfUAm4 zxd&sv8Wd<2K!b>(p+EH}hQEA; zyJ5E5HkZc>e@8-^L+(KCK;FxdJSQ8^;IVHKBBTOP@Xe?M>003gGJ=@cZ<`SSFA0oN zgCUV>i=0N_{8#6>gEa)Nf}iiA^j!XIzpw}tQXHKRA@pIqKuK0hvf_KzdDNzXKC5xh zD_kyeOTKsz1r^C#`To;RqlQeE~0`hAy806GPwI3jngfTQw1;4aZ*#kk4MXTI57G%4SRB*KL9L4tyfAN z(f%so{iqj0S_G>yBXj0bV2M2bk4zwCrZ3SM@9nEs>%X=Koh}%5)8mI^9jJSK6f)_M zdaD@wQ$tyKm1#(UJYUi;n`1gR`ifGC;WO?)2@Z0$36cKZn;**<0cUOI4E0+`=(Bkz z3@ydNNpFErBHkre_CBW`cUU^e>Q~qC>eg9MGuXw%v6I_%h&%aoDmM(6uA#0$OJDzK z;&M}{RLkYTcyFgPVpL!3g>Iw_;BzGXqX7M*C8#{&S=MUYs;K=mUMf zvR+W6+L~o5`CN;}aFsUot})}A1VyP)XEs&^@>zR8^NlwJYb(7OMzAY>6YlI3y|n>Z zt))J7V|l`}#azzYx`7mJD2lX1K1YzQgT01wTD?{B5*3!~-RkPWaU22#fm7(?&WfB}*==4uGXE>sATg;+ zs*yJ=D#~P%9i#c=)HIwemA`N{FBcyXjXJ`_hz16)e;VyCEi?<(yF?y5rZ)5r`lGYz z%w)I$SNJ9ZEjGe%R5%{V$6W2|rTNj#&p9DEZ2a;Wx-e;R@A=x9cE|DI<)t0Q%`DO?sCyt!#7QVf07Pmaf$+g-3-ux>e7bCRCTr zjMN{yEh!lc--`@eN={WTQ5}5%`_zZY&`NrKdO#I6#ti4Pphd`X^MPJ%o-ZA%JF|W^4p4KwnOoYzvkJL8) zk+MX7_e_z;sW};d^M4)>$Lxfp@Ju#?>gR!ds@3@yA2JsKM(B8)w`qAwn1zqGg)HO;|OSM?+wK%_FRd8XMf(b*Bl<=#oz&a%O@ z9y*C3%1sa|Mp_O$+hU(Z^@sB~Ov_H5mwf;JNd&$11xCX;LQ3ckU9Ws8l=wm2u9nZt zDXzO)W6=akdJ=p?Qi5>#ie#4E-?#7G{rb-=uPJYAA5Ca2YI1@5s3TiXUMU4Iy9+Ts z9lt)J0=eoF4T=Cl+J%|-#b~}>NyH!A`f|p-&t)BYl-l&DN#!_I5%8SiFC`K<*airk zDTN}IONzY0u*z$!^we)Gi)gVfhMJH3U&OaNaD&hhW#rkVGR?G26YCiibH0i9T!aA3 zg*rs&{1A`Qm_7{Mbh~un2ia{4rq{Pa{;e<-{hjHaN!~CvUnp0QLf4Z^)>}@SOW!q( zIWq)S3;L8VzkBt&fOtVbCI~)Rb10Gs@~6)~7AaFAe^6@eb98!O@XV62_K46krN-&m zQqoVUR(AMdPE^~$xsKPOm##0HQ)ydEZ0ITiGi}TGl7k$UoBBYht?@wa;O<~&hunzs z&UovaCdw$Xz^x`2g=7FRp(-?Q8mL}^>&)1^{kME((W2X1n{gyITZo@q_3~T?;X%sP z)u=qTRYoWq_7r?pca}JIsj@_{e7gnjLz35Bv=VwN4(q#d2i6h1H^kBB;T7zJHxznX zY0kcGQ!AP-=o@-9ucbFHweSC2yS%@*!f>6N!o`l^*1%w!uN^PZ;^x9$ysnchQ(PYF zT@`Z24stbC)+a#rSfj10m1-;!@uaMvBt~l_s)*X*JKp)EuHf%oCUEokfq;?>edir5Pp*ob zHq{KbYe^j+*4E!$^rC{hgegb2=51u~J4=4En9mfg6X#VseQ=6@wks&I$i`jt`!6Ri z$!+#J<1^$XDrqgMolk_${U$QN$6G)@K-l56?Q3Z?n)_C*3|4J5jBM_9-AuiSS>CWd zvjJl2Eft9qrS%QO0CeNpcAbmQThUoVwO!)r*xS8`r diff --git a/.svelte-kit/output/client/apple-touch-icon.png b/.svelte-kit/output/client/apple-touch-icon.png deleted file mode 100644 index fb8b64b537048492de285f22519de261c0892b1f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36949 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 QqcQ&f`~RPTf7J~9FZj=DC;$Ke diff --git a/.svelte-kit/output/client/robots.txt b/.svelte-kit/output/client/robots.txt deleted file mode 100644 index b6dd667..0000000 --- a/.svelte-kit/output/client/robots.txt +++ /dev/null @@ -1,3 +0,0 @@ -# allow crawling everything by default -User-agent: * -Disallow: diff --git a/.svelte-kit/output/client/site.webmanifest b/.svelte-kit/output/client/site.webmanifest deleted file mode 100644 index 45dc8a2..0000000 --- a/.svelte-kit/output/client/site.webmanifest +++ /dev/null @@ -1 +0,0 @@ -{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file diff --git a/.svelte-kit/output/server/.vite/manifest.json b/.svelte-kit/output/server/.vite/manifest.json deleted file mode 100644 index 36de7fb..0000000 --- a/.svelte-kit/output/server/.vite/manifest.json +++ /dev/null @@ -1,661 +0,0 @@ -{ - ".svelte-kit/generated/server/internal.js": { - "file": "internal.js", - "name": "internal", - "src": ".svelte-kit/generated/server/internal.js", - "isEntry": true, - "imports": [ - "_root.js", - "_environment.js", - "_server.js", - "_internal.js", - "_shared-server.js" - ] - }, - "_api.js": { - "file": "chunks/api.js", - "name": "api", - "imports": [ - "_shared-server.js", - "_index2.js" - ] - }, - "_auth.js": { - "file": "chunks/auth.js", - "name": "auth", - "imports": [ - "_shared-server.js", - "_url.js", - "_root.js", - "_utils.js", - "_query.js", - "_index2.js" - ], - "dynamicImports": [ - "node_modules/better-auth/dist/adapters/memory-adapter/index.mjs", - "node_modules/better-auth/dist/adapters/kysely-adapter/index.mjs", - "node_modules/better-auth/dist/adapters/kysely-adapter/index.mjs", - "node_modules/better-auth/dist/adapters/kysely-adapter/bun-sqlite-dialect.mjs", - "node_modules/better-auth/dist/adapters/kysely-adapter/node-sqlite-dialect.mjs" - ] - }, - "_engine.js": { - "file": "chunks/engine.js", - "name": "engine", - "imports": [ - "_index2.js" - ] - }, - "_environment.js": { - "file": "chunks/environment.js", - "name": "environment" - }, - "_exports.js": { - "file": "chunks/exports.js", - "name": "exports" - }, - "_false.js": { - "file": "chunks/false.js", - "name": "false" - }, - "_index.js": { - "file": "chunks/index.js", - "name": "index", - "imports": [ - "_index3.js", - "_root.js" - ] - }, - "_index2.js": { - "file": "chunks/index2.js", - "name": "index", - "imports": [ - "_shared-server.js" - ] - }, - "_index3.js": { - "file": "chunks/index3.js", - "name": "index" - }, - "_index4.js": { - "file": "chunks/index4.js", - "name": "index", - "imports": [ - "_state.svelte.js", - "_url.js", - "_utils.js", - "_index.js", - "_root.js", - "_exports.js", - "_index3.js" - ] - }, - "_internal.js": { - "file": "chunks/internal.js", - "name": "internal", - "imports": [ - "_root.js", - "_environment.js", - "_server.js", - "_shared-server.js" - ], - "dynamicImports": [ - "src/hooks.server.ts" - ] - }, - "_orchestrator.js": { - "file": "chunks/orchestrator.js", - "name": "orchestrator", - "imports": [ - "_index2.js", - "_engine.js", - "_shared-server.js" - ] - }, - "_query.js": { - "file": "chunks/query.js", - "name": "query", - "imports": [ - "_shared.js", - "_environment.js" - ] - }, - "_root.js": { - "file": "chunks/root.js", - "name": "root", - "imports": [ - "_index3.js", - "_false.js" - ] - }, - "_routing.js": { - "file": "chunks/routing.js", - "name": "routing", - "imports": [ - "_url.js" - ] - }, - "_server.js": { - "file": "chunks/server.js", - "name": "server" - }, - "_shared-server.js": { - "file": "chunks/shared-server.js", - "name": "shared-server" - }, - "_shared.js": { - "file": "chunks/shared.js", - "name": "shared", - "imports": [ - "_utils.js" - ] - }, - "_state.svelte.js": { - "file": "chunks/state.svelte.js", - "name": "state.svelte", - "imports": [ - "_index3.js", - "_url.js", - "_root.js" - ] - }, - "_url.js": { - "file": "chunks/url.js", - "name": "url" - }, - "_utils.js": { - "file": "chunks/utils.js", - "name": "utils" - }, - "node_modules/@sveltejs/kit/src/runtime/app/server/remote/index.js": { - "file": "remote-entry.js", - "name": "remote-entry", - "src": "node_modules/@sveltejs/kit/src/runtime/app/server/remote/index.js", - "isEntry": true, - "imports": [ - "_query.js", - "_shared.js", - "_false.js", - "_server.js" - ] - }, - "node_modules/@sveltejs/kit/src/runtime/components/svelte-5/layout.svelte": { - "file": "entries/fallbacks/layout.svelte.js", - "name": "entries/fallbacks/layout.svelte", - "src": "node_modules/@sveltejs/kit/src/runtime/components/svelte-5/layout.svelte", - "isEntry": true - }, - "node_modules/@sveltejs/kit/src/runtime/server/index.js": { - "file": "index.js", - "name": "index", - "src": "node_modules/@sveltejs/kit/src/runtime/server/index.js", - "isEntry": true, - "imports": [ - "_false.js", - "_server.js", - "_shared.js", - "_url.js", - "_utils.js", - "_index.js", - "_shared-server.js", - "_routing.js", - "_exports.js", - "_internal.js" - ] - }, - "node_modules/better-auth/dist/adapters/kysely-adapter/bun-sqlite-dialect.mjs": { - "file": "chunks/bun-sqlite-dialect.js", - "name": "bun-sqlite-dialect", - "src": "node_modules/better-auth/dist/adapters/kysely-adapter/bun-sqlite-dialect.mjs", - "isDynamicEntry": true - }, - "node_modules/better-auth/dist/adapters/kysely-adapter/index.mjs": { - "file": "chunks/index6.js", - "name": "index", - "src": "node_modules/better-auth/dist/adapters/kysely-adapter/index.mjs", - "isDynamicEntry": true, - "imports": [ - "_auth.js" - ] - }, - "node_modules/better-auth/dist/adapters/kysely-adapter/node-sqlite-dialect.mjs": { - "file": "chunks/node-sqlite-dialect.js", - "name": "node-sqlite-dialect", - "src": "node_modules/better-auth/dist/adapters/kysely-adapter/node-sqlite-dialect.mjs", - "isDynamicEntry": true - }, - "node_modules/better-auth/dist/adapters/memory-adapter/index.mjs": { - "file": "chunks/index5.js", - "name": "index", - "src": "node_modules/better-auth/dist/adapters/memory-adapter/index.mjs", - "isDynamicEntry": true - }, - "src/hooks.server.ts": { - "file": "entries/hooks.server.js", - "name": "entries/hooks.server", - "src": "src/hooks.server.ts", - "isEntry": true, - "isDynamicEntry": true, - "imports": [ - "_environment.js", - "_auth.js", - "_index2.js" - ] - }, - "src/routes/(app)/+layout.server.ts": { - "file": "entries/pages/(app)/_layout.server.ts.js", - "name": "entries/pages/(app)/_layout.server.ts", - "src": "src/routes/(app)/+layout.server.ts", - "isEntry": true - }, - "src/routes/(app)/+layout.svelte": { - "file": "entries/pages/(app)/_layout.svelte.js", - "name": "entries/pages/(app)/_layout.svelte", - "src": "src/routes/(app)/+layout.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_index4.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ], - "css": [ - "_app/immutable/assets/_layout.Dv2no-8m.css" - ] - }, - "src/routes/(app)/+page.server.ts": { - "file": "entries/pages/(app)/_page.server.ts.js", - "name": "entries/pages/(app)/_page.server.ts", - "src": "src/routes/(app)/+page.server.ts", - "isEntry": true, - "imports": [ - "_index2.js" - ] - }, - "src/routes/(app)/+page.svelte": { - "file": "entries/pages/(app)/_page.svelte.js", - "name": "entries/pages/(app)/_page.svelte", - "src": "src/routes/(app)/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js" - ] - }, - "src/routes/(app)/admin/+page.server.ts": { - "file": "entries/pages/(app)/admin/_page.server.ts.js", - "name": "entries/pages/(app)/admin/_page.server.ts", - "src": "src/routes/(app)/admin/+page.server.ts", - "isEntry": true, - "imports": [ - "_index2.js" - ] - }, - "src/routes/(app)/admin/+page.svelte": { - "file": "entries/pages/(app)/admin/_page.svelte.js", - "name": "entries/pages/(app)/admin/_page.svelte", - "src": "src/routes/(app)/admin/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ] - }, - "src/routes/(app)/mappools/+page.server.ts": { - "file": "entries/pages/(app)/mappools/_page.server.ts.js", - "name": "entries/pages/(app)/mappools/_page.server.ts", - "src": "src/routes/(app)/mappools/+page.server.ts", - "isEntry": true, - "imports": [ - "_index2.js" - ] - }, - "src/routes/(app)/mappools/+page.svelte": { - "file": "entries/pages/(app)/mappools/_page.svelte.js", - "name": "entries/pages/(app)/mappools/_page.svelte", - "src": "src/routes/(app)/mappools/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ] - }, - "src/routes/(app)/mappools/[id]/+page.server.ts": { - "file": "entries/pages/(app)/mappools/_id_/_page.server.ts.js", - "name": "entries/pages/(app)/mappools/_id_/_page.server.ts", - "src": "src/routes/(app)/mappools/[id]/+page.server.ts", - "isEntry": true, - "imports": [ - "_index2.js", - "_api.js" - ] - }, - "src/routes/(app)/mappools/[id]/+page.svelte": { - "file": "entries/pages/(app)/mappools/_id_/_page.svelte.js", - "name": "entries/pages/(app)/mappools/_id_/_page.svelte", - "src": "src/routes/(app)/mappools/[id]/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ] - }, - "src/routes/(app)/matches/+page.server.ts": { - "file": "entries/pages/(app)/matches/_page.server.ts.js", - "name": "entries/pages/(app)/matches/_page.server.ts", - "src": "src/routes/(app)/matches/+page.server.ts", - "isEntry": true, - "imports": [ - "_index2.js", - "_engine.js", - "_orchestrator.js" - ] - }, - "src/routes/(app)/matches/+page.svelte": { - "file": "entries/pages/(app)/matches/_page.svelte.js", - "name": "entries/pages/(app)/matches/_page.svelte", - "src": "src/routes/(app)/matches/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ] - }, - "src/routes/(app)/matches/[id]/+page.server.ts": { - "file": "entries/pages/(app)/matches/_id_/_page.server.ts.js", - "name": "entries/pages/(app)/matches/_id_/_page.server.ts", - "src": "src/routes/(app)/matches/[id]/+page.server.ts", - "isEntry": true, - "imports": [ - "_index2.js", - "_engine.js", - "_orchestrator.js", - "_api.js" - ] - }, - "src/routes/(app)/matches/[id]/+page.svelte": { - "file": "entries/pages/(app)/matches/_id_/_page.svelte.js", - "name": "entries/pages/(app)/matches/_id_/_page.svelte", - "src": "src/routes/(app)/matches/[id]/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ] - }, - "src/routes/(app)/settings/+page.server.ts": { - "file": "entries/pages/(app)/settings/_page.server.ts.js", - "name": "entries/pages/(app)/settings/_page.server.ts", - "src": "src/routes/(app)/settings/+page.server.ts", - "isEntry": true, - "imports": [ - "_auth.js", - "_index2.js" - ] - }, - "src/routes/(app)/settings/+page.svelte": { - "file": "entries/pages/(app)/settings/_page.svelte.js", - "name": "entries/pages/(app)/settings/_page.svelte", - "src": "src/routes/(app)/settings/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ] - }, - "src/routes/(app)/teams/+page.server.ts": { - "file": "entries/pages/(app)/teams/_page.server.ts.js", - "name": "entries/pages/(app)/teams/_page.server.ts", - "src": "src/routes/(app)/teams/+page.server.ts", - "isEntry": true, - "imports": [ - "_index2.js" - ] - }, - "src/routes/(app)/teams/+page.svelte": { - "file": "entries/pages/(app)/teams/_page.svelte.js", - "name": "entries/pages/(app)/teams/_page.svelte", - "src": "src/routes/(app)/teams/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ] - }, - "src/routes/+error.svelte": { - "file": "entries/pages/_error.svelte.js", - "name": "entries/pages/_error.svelte", - "src": "src/routes/+error.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_index4.js" - ] - }, - "src/routes/api/health/+server.ts": { - "file": "entries/endpoints/api/health/_server.ts.js", - "name": "entries/endpoints/api/health/_server.ts", - "src": "src/routes/api/health/+server.ts", - "isEntry": true, - "imports": [ - "_index2.js" - ] - }, - "src/routes/api/mappools/+server.ts": { - "file": "entries/endpoints/api/mappools/_server.ts.js", - "name": "entries/endpoints/api/mappools/_server.ts", - "src": "src/routes/api/mappools/+server.ts", - "isEntry": true, - "imports": [ - "_index2.js" - ] - }, - "src/routes/api/mappools/[id]/+server.ts": { - "file": "entries/endpoints/api/mappools/_id_/_server.ts.js", - "name": "entries/endpoints/api/mappools/_id_/_server.ts", - "src": "src/routes/api/mappools/[id]/+server.ts", - "isEntry": true, - "imports": [ - "_index2.js" - ] - }, - "src/routes/api/mappools/[id]/slots/+server.ts": { - "file": "entries/endpoints/api/mappools/_id_/slots/_server.ts.js", - "name": "entries/endpoints/api/mappools/_id_/slots/_server.ts", - "src": "src/routes/api/mappools/[id]/slots/+server.ts", - "isEntry": true, - "imports": [ - "_index2.js" - ] - }, - "src/routes/api/mappools/[id]/slots/[slotId]/+server.ts": { - "file": "entries/endpoints/api/mappools/_id_/slots/_slotId_/_server.ts.js", - "name": "entries/endpoints/api/mappools/_id_/slots/_slotId_/_server.ts", - "src": "src/routes/api/mappools/[id]/slots/[slotId]/+server.ts", - "isEntry": true, - "imports": [ - "_index2.js" - ] - }, - "src/routes/api/matches/+server.ts": { - "file": "entries/endpoints/api/matches/_server.ts.js", - "name": "entries/endpoints/api/matches/_server.ts", - "src": "src/routes/api/matches/+server.ts", - "isEntry": true, - "imports": [ - "_index2.js", - "_engine.js" - ] - }, - "src/routes/api/matches/[id]/+server.ts": { - "file": "entries/endpoints/api/matches/_id_/_server.ts.js", - "name": "entries/endpoints/api/matches/_id_/_server.ts", - "src": "src/routes/api/matches/[id]/+server.ts", - "isEntry": true, - "imports": [ - "_engine.js" - ] - }, - "src/routes/api/matches/[id]/lobby/+server.ts": { - "file": "entries/endpoints/api/matches/_id_/lobby/_server.ts.js", - "name": "entries/endpoints/api/matches/_id_/lobby/_server.ts", - "src": "src/routes/api/matches/[id]/lobby/+server.ts", - "isEntry": true, - "imports": [ - "_engine.js" - ] - }, - "src/routes/api/matches/[id]/pick/+server.ts": { - "file": "entries/endpoints/api/matches/_id_/pick/_server.ts.js", - "name": "entries/endpoints/api/matches/_id_/pick/_server.ts", - "src": "src/routes/api/matches/[id]/pick/+server.ts", - "isEntry": true, - "imports": [ - "_engine.js" - ] - }, - "src/routes/api/matches/[id]/roll/+server.ts": { - "file": "entries/endpoints/api/matches/_id_/roll/_server.ts.js", - "name": "entries/endpoints/api/matches/_id_/roll/_server.ts", - "src": "src/routes/api/matches/[id]/roll/+server.ts", - "isEntry": true, - "imports": [ - "_engine.js" - ] - }, - "src/routes/api/matches/[id]/rolling/+server.ts": { - "file": "entries/endpoints/api/matches/_id_/rolling/_server.ts.js", - "name": "entries/endpoints/api/matches/_id_/rolling/_server.ts", - "src": "src/routes/api/matches/[id]/rolling/+server.ts", - "isEntry": true, - "imports": [ - "_engine.js" - ] - }, - "src/routes/api/matches/[id]/score/+server.ts": { - "file": "entries/endpoints/api/matches/_id_/score/_server.ts.js", - "name": "entries/endpoints/api/matches/_id_/score/_server.ts", - "src": "src/routes/api/matches/[id]/score/+server.ts", - "isEntry": true, - "imports": [ - "_engine.js" - ] - }, - "src/routes/api/osu/beatmap/[id]/+server.ts": { - "file": "entries/endpoints/api/osu/beatmap/_id_/_server.ts.js", - "name": "entries/endpoints/api/osu/beatmap/_id_/_server.ts", - "src": "src/routes/api/osu/beatmap/[id]/+server.ts", - "isEntry": true, - "imports": [ - "_api.js" - ] - }, - "src/routes/api/queue/+server.ts": { - "file": "entries/endpoints/api/queue/_server.ts.js", - "name": "entries/endpoints/api/queue/_server.ts", - "src": "src/routes/api/queue/+server.ts", - "isEntry": true, - "imports": [ - "_engine.js", - "_index2.js" - ] - }, - "src/routes/demo/+page.svelte": { - "file": "entries/pages/demo/_page.svelte.js", - "name": "entries/pages/demo/_page.svelte", - "src": "src/routes/demo/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_server.js", - "_routing.js", - "_url.js", - "_root.js" - ] - }, - "src/routes/demo/better-auth/+page.server.ts": { - "file": "entries/pages/demo/better-auth/_page.server.ts.js", - "name": "entries/pages/demo/better-auth/_page.server.ts", - "src": "src/routes/demo/better-auth/+page.server.ts", - "isEntry": true, - "imports": [ - "_auth.js" - ] - }, - "src/routes/demo/better-auth/+page.svelte": { - "file": "entries/pages/demo/better-auth/_page.svelte.js", - "name": "entries/pages/demo/better-auth/_page.svelte", - "src": "src/routes/demo/better-auth/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ] - }, - "src/routes/demo/better-auth/login/+page.server.ts": { - "file": "entries/pages/demo/better-auth/login/_page.server.ts.js", - "name": "entries/pages/demo/better-auth/login/_page.server.ts", - "src": "src/routes/demo/better-auth/login/+page.server.ts", - "isEntry": true, - "imports": [ - "_auth.js" - ] - }, - "src/routes/demo/better-auth/login/+page.svelte": { - "file": "entries/pages/demo/better-auth/login/_page.svelte.js", - "name": "entries/pages/demo/better-auth/login/_page.svelte", - "src": "src/routes/demo/better-auth/login/+page.svelte", - "isEntry": true, - "imports": [ - "_index3.js", - "_url.js", - "_utils.js", - "_root.js", - "_exports.js", - "_state.svelte.js" - ] - }, - "src/routes/login/+page.server.ts": { - "file": "entries/pages/login/_page.server.ts.js", - "name": "entries/pages/login/_page.server.ts", - "src": "src/routes/login/+page.server.ts", - "isEntry": true, - "imports": [ - "_auth.js" - ] - } -} \ No newline at end of file diff --git a/.svelte-kit/output/server/_app/immutable/assets/_layout.Dv2no-8m.css b/.svelte-kit/output/server/_app/immutable/assets/_layout.Dv2no-8m.css deleted file mode 100644 index d32e9ae..0000000 --- a/.svelte-kit/output/server/_app/immutable/assets/_layout.Dv2no-8m.css +++ /dev/null @@ -1 +0,0 @@ -@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:"Geist Mono", ui-monospace, monospace;--color-red-400:oklch(70.4% .191 22.216);--color-red-500:oklch(63.7% .237 25.331);--color-yellow-400:oklch(85.2% .199 91.936);--color-yellow-500:oklch(79.5% .184 86.047);--color-green-400:oklch(79.2% .209 151.711);--color-green-500:oklch(72.3% .219 149.579);--color-blue-400:oklch(70.7% .165 254.624);--color-blue-500:oklch(62.3% .214 259.815);--color-blue-600:oklch(54.6% .245 262.881);--color-blue-700:oklch(48.8% .243 264.376);--color-purple-400:oklch(71.4% .203 305.504);--color-purple-500:oklch(62.7% .265 303.9);--color-pink-400:oklch(71.8% .202 349.761);--color-pink-500:oklch(65.6% .241 354.308);--color-gray-300:oklch(87.2% .01 258.338);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-md:28rem;--container-2xl:42rem;--container-3xl:48rem;--container-4xl:56rem;--container-5xl:64rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height: 1.5 ;--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height: 1.2 ;--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--text-6xl:3.75rem;--text-6xl--line-height:1;--tracking-tight:-.025em;--tracking-wider:.05em;--tracking-widest:.1em;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--animate-ping:ping 1s cubic-bezier(0, 0, .2, 1) infinite;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--blur-sm:8px;--blur-md:12px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-surface-900:#0a0a0f;--color-surface-800:#12121a;--color-surface-700:#1a1a25;--color-surface-600:#24243a;--color-accent:#ff66ab;--color-accent-hover:#ff85be;--color-accent-dim:#ff66ab33;--color-text-primary:#eeeef0;--color-text-secondary:#8888a0;--color-border:#2a2a3d;--font-body:"Geist", system-ui, sans-serif}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing) * 0)}.start{inset-inline-start:var(--spacing)}.top-0{top:calc(var(--spacing) * 0)}.left-0{left:calc(var(--spacing) * 0)}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.col-span-2{grid-column:span 2/span 2}.mx-auto{margin-inline:auto}.my-4{margin-block:calc(var(--spacing) * 4)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.ml-56{margin-left:calc(var(--spacing) * 56)}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline-block{display:inline-block}.table{display:table}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-2{height:calc(var(--spacing) * 2)}.h-3{height:calc(var(--spacing) * 3)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-10{height:calc(var(--spacing) * 10)}.h-12{height:calc(var(--spacing) * 12)}.h-14{height:calc(var(--spacing) * 14)}.h-16{height:calc(var(--spacing) * 16)}.h-full{height:100%}.max-h-\[80vh\]{max-height:80vh}.min-h-\[70vh\]{min-height:70vh}.min-h-dvh{min-height:100dvh}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-2{width:calc(var(--spacing) * 2)}.w-3{width:calc(var(--spacing) * 3)}.w-6{width:calc(var(--spacing) * 6)}.w-7{width:calc(var(--spacing) * 7)}.w-8{width:calc(var(--spacing) * 8)}.w-10{width:calc(var(--spacing) * 10)}.w-16{width:calc(var(--spacing) * 16)}.w-20{width:calc(var(--spacing) * 20)}.w-24{width:calc(var(--spacing) * 24)}.w-56{width:calc(var(--spacing) * 56)}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-3xl{max-width:var(--container-3xl)}.max-w-4xl{max-width:var(--container-4xl)}.max-w-5xl{max-width:var(--container-5xl)}.max-w-md{max-width:var(--container-md)}.min-w-0{min-width:calc(var(--spacing) * 0)}.flex-1{flex:1}.rotate-90{rotate:90deg}.animate-ping{animation:var(--animate-ping)}.animate-pulse{animation:var(--animate-pulse)}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-\[auto_1fr_auto_auto_auto\]{grid-template-columns:auto 1fr auto auto auto}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-6{gap:calc(var(--spacing) * 6)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-accent\/20{border-color:#ff66ab33}@supports (color:color-mix(in lab,red,red)){.border-accent\/20{border-color:color-mix(in oklab,var(--color-accent) 20%,transparent)}}.border-accent\/30{border-color:#ff66ab4d}@supports (color:color-mix(in lab,red,red)){.border-accent\/30{border-color:color-mix(in oklab,var(--color-accent) 30%,transparent)}}.border-blue-500\/30{border-color:#3080ff4d}@supports (color:color-mix(in lab,red,red)){.border-blue-500\/30{border-color:color-mix(in oklab,var(--color-blue-500) 30%,transparent)}}.border-border{border-color:var(--color-border)}.border-border\/50{border-color:#2a2a3d80}@supports (color:color-mix(in lab,red,red)){.border-border\/50{border-color:color-mix(in oklab,var(--color-border) 50%,transparent)}}.border-gray-300{border-color:var(--color-gray-300)}.border-green-500\/20{border-color:#00c75833}@supports (color:color-mix(in lab,red,red)){.border-green-500\/20{border-color:color-mix(in oklab,var(--color-green-500) 20%,transparent)}}.border-green-500\/30{border-color:#00c7584d}@supports (color:color-mix(in lab,red,red)){.border-green-500\/30{border-color:color-mix(in oklab,var(--color-green-500) 30%,transparent)}}.border-green-500\/40{border-color:#00c75866}@supports (color:color-mix(in lab,red,red)){.border-green-500\/40{border-color:color-mix(in oklab,var(--color-green-500) 40%,transparent)}}.border-pink-500\/30{border-color:#f6339a4d}@supports (color:color-mix(in lab,red,red)){.border-pink-500\/30{border-color:color-mix(in oklab,var(--color-pink-500) 30%,transparent)}}.border-purple-500\/30{border-color:#ac4bff4d}@supports (color:color-mix(in lab,red,red)){.border-purple-500\/30{border-color:color-mix(in oklab,var(--color-purple-500) 30%,transparent)}}.border-red-500\/30{border-color:#fb2c364d}@supports (color:color-mix(in lab,red,red)){.border-red-500\/30{border-color:color-mix(in oklab,var(--color-red-500) 30%,transparent)}}.border-yellow-500\/30{border-color:#edb2004d}@supports (color:color-mix(in lab,red,red)){.border-yellow-500\/30{border-color:color-mix(in oklab,var(--color-yellow-500) 30%,transparent)}}.bg-accent{background-color:var(--color-accent)}.bg-accent-dim{background-color:var(--color-accent-dim)}.bg-accent\/10{background-color:#ff66ab1a}@supports (color:color-mix(in lab,red,red)){.bg-accent\/10{background-color:color-mix(in oklab,var(--color-accent) 10%,transparent)}}.bg-black\/70{background-color:#000000b3}@supports (color:color-mix(in lab,red,red)){.bg-black\/70{background-color:color-mix(in oklab,var(--color-black) 70%,transparent)}}.bg-blue-400{background-color:var(--color-blue-400)}.bg-blue-500\/10{background-color:#3080ff1a}@supports (color:color-mix(in lab,red,red)){.bg-blue-500\/10{background-color:color-mix(in oklab,var(--color-blue-500) 10%,transparent)}}.bg-blue-500\/20{background-color:#3080ff33}@supports (color:color-mix(in lab,red,red)){.bg-blue-500\/20{background-color:color-mix(in oklab,var(--color-blue-500) 20%,transparent)}}.bg-blue-600{background-color:var(--color-blue-600)}.bg-green-400{background-color:var(--color-green-400)}.bg-green-500\/5{background-color:#00c7580d}@supports (color:color-mix(in lab,red,red)){.bg-green-500\/5{background-color:color-mix(in oklab,var(--color-green-500) 5%,transparent)}}.bg-green-500\/20{background-color:#00c75833}@supports (color:color-mix(in lab,red,red)){.bg-green-500\/20{background-color:color-mix(in oklab,var(--color-green-500) 20%,transparent)}}.bg-pink-500\/20{background-color:#f6339a33}@supports (color:color-mix(in lab,red,red)){.bg-pink-500\/20{background-color:color-mix(in oklab,var(--color-pink-500) 20%,transparent)}}.bg-purple-500\/10{background-color:#ac4bff1a}@supports (color:color-mix(in lab,red,red)){.bg-purple-500\/10{background-color:color-mix(in oklab,var(--color-purple-500) 10%,transparent)}}.bg-purple-500\/20{background-color:#ac4bff33}@supports (color:color-mix(in lab,red,red)){.bg-purple-500\/20{background-color:color-mix(in oklab,var(--color-purple-500) 20%,transparent)}}.bg-red-500\/5{background-color:#fb2c360d}@supports (color:color-mix(in lab,red,red)){.bg-red-500\/5{background-color:color-mix(in oklab,var(--color-red-500) 5%,transparent)}}.bg-red-500\/10{background-color:#fb2c361a}@supports (color:color-mix(in lab,red,red)){.bg-red-500\/10{background-color:color-mix(in oklab,var(--color-red-500) 10%,transparent)}}.bg-red-500\/20{background-color:#fb2c3633}@supports (color:color-mix(in lab,red,red)){.bg-red-500\/20{background-color:color-mix(in oklab,var(--color-red-500) 20%,transparent)}}.bg-surface-600{background-color:var(--color-surface-600)}.bg-surface-700{background-color:var(--color-surface-700)}.bg-surface-800{background-color:var(--color-surface-800)}.bg-surface-900{background-color:var(--color-surface-900)}.bg-surface-900\/80{background-color:#0a0a0fcc}@supports (color:color-mix(in lab,red,red)){.bg-surface-900\/80{background-color:color-mix(in oklab,var(--color-surface-900) 80%,transparent)}}.bg-transparent{background-color:#0000}.bg-white{background-color:var(--color-white)}.bg-yellow-400{background-color:var(--color-yellow-400)}.bg-yellow-500\/5{background-color:#edb2000d}@supports (color:color-mix(in lab,red,red)){.bg-yellow-500\/5{background-color:color-mix(in oklab,var(--color-yellow-500) 5%,transparent)}}.bg-yellow-500\/20{background-color:#edb20033}@supports (color:color-mix(in lab,red,red)){.bg-yellow-500\/20{background-color:color-mix(in oklab,var(--color-yellow-500) 20%,transparent)}}.object-cover{object-fit:cover}.p-1{padding:calc(var(--spacing) * 1)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-3\.5{padding-inline:calc(var(--spacing) * 3.5)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.px-8{padding-inline:calc(var(--spacing) * 8)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-5{padding-block:calc(var(--spacing) * 5)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-12{padding-block:calc(var(--spacing) * 12)}.pt-3{padding-top:calc(var(--spacing) * 3)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.text-accent{color:var(--color-accent)}.text-blue-400{color:var(--color-blue-400)}.text-green-400{color:var(--color-green-400)}.text-pink-400{color:var(--color-pink-400)}.text-purple-400{color:var(--color-purple-400)}.text-red-400{color:var(--color-red-400)}.text-red-500{color:var(--color-red-500)}.text-surface-900{color:var(--color-surface-900)}.text-text-primary{color:var(--color-text-primary)}.text-text-secondary{color:var(--color-text-secondary)}.text-text-secondary\/30{color:#8888a04d}@supports (color:color-mix(in lab,red,red)){.text-text-secondary\/30{color:color-mix(in oklab,var(--color-text-secondary) 30%,transparent)}}.text-white{color:var(--color-white)}.text-yellow-400{color:var(--color-yellow-400)}.uppercase{text-transform:uppercase}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.opacity-0{opacity:0}.opacity-30{opacity:.3}.opacity-50{opacity:.5}.opacity-75{opacity:.75}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.backdrop-blur-md{--tw-backdrop-blur:blur(var(--blur-md));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-blur-sm{--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media(hover:hover){.group-hover\:text-accent:is(:where(.group):hover *){color:var(--color-accent)}.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}.placeholder\:text-text-secondary\/50::placeholder{color:#8888a080}@supports (color:color-mix(in lab,red,red)){.placeholder\:text-text-secondary\/50::placeholder{color:color-mix(in oklab,var(--color-text-secondary) 50%,transparent)}}.last\:border-b-0:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}@media(hover:hover){.hover\:border-accent:hover{border-color:var(--color-accent)}.hover\:border-accent\/30:hover{border-color:#ff66ab4d}@supports (color:color-mix(in lab,red,red)){.hover\:border-accent\/30:hover{border-color:color-mix(in oklab,var(--color-accent) 30%,transparent)}}.hover\:border-accent\/40:hover{border-color:#ff66ab66}@supports (color:color-mix(in lab,red,red)){.hover\:border-accent\/40:hover{border-color:color-mix(in oklab,var(--color-accent) 40%,transparent)}}.hover\:border-green-500\/40:hover{border-color:#00c75866}@supports (color:color-mix(in lab,red,red)){.hover\:border-green-500\/40:hover{border-color:color-mix(in oklab,var(--color-green-500) 40%,transparent)}}.hover\:border-red-500\/30:hover{border-color:#fb2c364d}@supports (color:color-mix(in lab,red,red)){.hover\:border-red-500\/30:hover{border-color:color-mix(in oklab,var(--color-red-500) 30%,transparent)}}.hover\:bg-accent-hover:hover{background-color:var(--color-accent-hover)}.hover\:bg-blue-700:hover{background-color:var(--color-blue-700)}.hover\:bg-red-500\/10:hover{background-color:#fb2c361a}@supports (color:color-mix(in lab,red,red)){.hover\:bg-red-500\/10:hover{background-color:color-mix(in oklab,var(--color-red-500) 10%,transparent)}}.hover\:bg-surface-600:hover{background-color:var(--color-surface-600)}.hover\:bg-surface-700:hover{background-color:var(--color-surface-700)}.hover\:bg-yellow-500\/10:hover{background-color:#edb2001a}@supports (color:color-mix(in lab,red,red)){.hover\:bg-yellow-500\/10:hover{background-color:color-mix(in oklab,var(--color-yellow-500) 10%,transparent)}}.hover\:text-accent:hover{color:var(--color-accent)}.hover\:text-red-400:hover{color:var(--color-red-400)}.hover\:text-text-primary:hover{color:var(--color-text-primary)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}}.focus\:border-accent:focus{border-color:var(--color-accent)}.focus\:border-blue-500:focus{border-color:var(--color-blue-500)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-blue-500:focus{--tw-ring-color:var(--color-blue-500)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.disabled\:opacity-50:disabled{opacity:.5}@media(min-width:40rem){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}@media(min-width:64rem){.lg\:col-span-1{grid-column:span 1/span 1}.lg\:col-span-2{grid-column:span 2/span 2}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}}html{background-color:var(--color-surface-900);color:var(--color-text-primary);font-family:var(--font-body)}body{min-height:100dvh}::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:var(--color-surface-900)}::-webkit-scrollbar-thumb{background:var(--color-surface-600);border-radius:3px}::-webkit-scrollbar-thumb:hover{background:var(--color-accent)}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@keyframes ping{75%,to{opacity:0;transform:scale(2)}}@keyframes pulse{50%{opacity:.5}} diff --git a/.svelte-kit/output/server/chunks/api.js b/.svelte-kit/output/server/chunks/api.js deleted file mode 100644 index 5e6cc8c..0000000 --- a/.svelte-kit/output/server/chunks/api.js +++ /dev/null @@ -1,69 +0,0 @@ -import { b as private_env } from "./shared-server.js"; -import "./index2.js"; -const CACHE_TTL = 10 * 60 * 1e3; -const MAX_ENTRIES = 500; -const cache = /* @__PURE__ */ new Map(); -function getCached(key) { - const entry = cache.get(key); - if (!entry) return null; - if (Date.now() > entry.expiresAt) { - cache.delete(key); - return null; - } - return entry.data; -} -function setCache(key, data, ttl = CACHE_TTL) { - if (cache.size >= MAX_ENTRIES) { - const firstKey = cache.keys().next().value; - if (firstKey) cache.delete(firstKey); - } - cache.set(key, { data, expiresAt: Date.now() + ttl }); -} -let clientToken = null; -let clientTokenExpiresAt = 0; -async function getClientToken() { - if (clientToken && Date.now() < clientTokenExpiresAt - 6e4) { - return clientToken; - } - const res = await fetch("https://osu.ppy.sh/oauth/token", { - method: "POST", - headers: { - Accept: "application/json", - "Content-Type": "application/x-www-form-urlencoded" - }, - body: new URLSearchParams({ - client_id: private_env.OSU_CLIENT_ID, - client_secret: private_env.OSU_CLIENT_SECRET, - grant_type: "client_credentials", - scope: "identify public" - }) - }); - if (!res.ok) { - throw new Error(`Failed to get osu! client token: ${res.status} ${res.statusText}`); - } - const data = await res.json(); - clientToken = data.access_token; - clientTokenExpiresAt = Date.now() + data.expires_in * 1e3; - return clientToken; -} -async function osuFetch(path, token) { - const t = await getClientToken(); - const res = await fetch(`https://osu.ppy.sh/api/v2${path}`, { - headers: { Authorization: `Bearer ${t}` } - }); - if (!res.ok) { - throw new Error(`osu! API ${path}: ${res.status} ${res.statusText}`); - } - return res.json(); -} -async function getBeatmap(beatmapId) { - const cacheKey = `beatmap:${beatmapId}`; - const cached = getCached(cacheKey); - if (cached) return cached; - const data = await osuFetch(`/beatmaps/${beatmapId}`); - setCache(cacheKey, data); - return data; -} -export { - getBeatmap as g -}; diff --git a/.svelte-kit/output/server/chunks/auth.js b/.svelte-kit/output/server/chunks/auth.js deleted file mode 100644 index 588593c..0000000 --- a/.svelte-kit/output/server/chunks/auth.js +++ /dev/null @@ -1,7983 +0,0 @@ -import { env, isTest, isDevelopment, logger, createLogger, isProduction, shouldPublishLog } from "@better-auth/core/env"; -import { BetterAuthError, BASE_ERROR_CODES } from "@better-auth/core/error"; -import { isValidIP, normalizeIP, deprecate, normalizePathname, createRateLimitKey, safeJSONParse, generateId, filterOutputFields, defineErrorCodes } from "@better-auth/core/utils"; -import { defineRequestState, getCurrentAuthContext, getCurrentAdapter, runWithTransaction, hasRequestState, runWithRequestState, runWithEndpointContext, runWithAdapter, getBetterAuthVersion } from "@better-auth/core/context"; -import { APIError, toResponse, createRouter } from "better-call"; -import { createAuthMiddleware, createAuthEndpoint } from "@better-auth/core/api"; -import * as import___better_auth_core_db from "@better-auth/core/db"; -import { getAuthTables } from "@better-auth/core/db"; -import * as z from "zod"; -import { Kysely, SqliteDialect, MysqlDialect, PostgresDialect, MssqlDialect, sql } from "kysely"; -import { initGetModelName, initGetFieldName, createAdapterFactory } from "@better-auth/core/db/adapter"; -import { hkdf } from "@noble/hashes/hkdf.js"; -import { sha256 } from "@noble/hashes/sha2.js"; -import { jwtDecrypt, calculateJwkThumbprint, base64url, jwtVerify, EncryptJWT, SignJWT, decodeJwt } from "jose"; -import { hex } from "@better-auth/utils/hex"; -import { createRandomStringGenerator } from "@better-auth/utils/random"; -import "@better-auth/utils"; -import { createHash } from "@better-auth/utils/hash"; -import { base64Url } from "@better-auth/utils/base64"; -import { binary } from "@better-auth/utils/binary"; -import { createHMAC } from "@better-auth/utils/hmac"; -import { xchacha20poly1305 } from "@noble/ciphers/chacha.js"; -import { hexToBytes as hexToBytes$1, managedNonce, utf8ToBytes, bytesToHex } from "@noble/ciphers/utils.js"; -import { SocialProviderListEnum, socialProviders } from "@better-auth/core/social-providers"; -import { JWTExpired } from "jose/errors"; -import defu$1, { createDefu, defu } from "defu"; -import { scryptAsync } from "@noble/hashes/scrypt.js"; -import { hexToBytes } from "@noble/hashes/utils.js"; -import { createTelemetry } from "@better-auth/telemetry"; -import { count, desc, asc, inArray, notInArray, like, lt, lte, ne, gt, gte, eq, and, or, sql as sql$1 } from "drizzle-orm"; -import { b as private_env } from "./shared-server.js"; -import "./url.js"; -import { getRequestEvent } from "@sveltejs/kit/internal/server"; -import "./root.js"; -import "./utils.js"; -import "@sveltejs/kit"; -import "@sveltejs/kit/internal"; -import "./query.js"; -import { d as db, c as team, t as teamMember } from "./index2.js"; -import { betterFetch } from "@better-fetch/fetch"; -import { createAuthorizationURL, validateAuthorizationCode, refreshAccessToken } from "@better-auth/core/oauth2"; -import "@better-auth/utils/otp"; -function checkHasPath(url) { - try { - return (new URL(url).pathname.replace(/\/+$/, "") || "/") !== "/"; - } catch { - throw new BetterAuthError(`Invalid base URL: ${url}. Please provide a valid base URL.`); - } -} -function assertHasProtocol(url) { - try { - const parsedUrl = new URL(url); - if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") throw new BetterAuthError(`Invalid base URL: ${url}. URL must include 'http://' or 'https://'`); - } catch (error2) { - if (error2 instanceof BetterAuthError) throw error2; - throw new BetterAuthError(`Invalid base URL: ${url}. Please provide a valid base URL.`, { cause: error2 }); - } -} -function withPath(url, path = "/api/auth") { - assertHasProtocol(url); - if (checkHasPath(url)) return url; - const trimmedUrl = url.replace(/\/+$/, ""); - if (!path || path === "/") return trimmedUrl; - path = path.startsWith("/") ? path : `/${path}`; - return `${trimmedUrl}${path}`; -} -function validateProxyHeader(header, type) { - if (!header || header.trim() === "") return false; - if (type === "proto") return header === "http" || header === "https"; - if (type === "host") { - if ([ - /\.\./, - /\0/, - /[\s]/, - /^[.]/, - /[<>'"]/, - /javascript:/i, - /file:/i, - /data:/i - ].some((pattern) => pattern.test(header))) return false; - return /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*(:[0-9]{1,5})?$/.test(header) || /^(\d{1,3}\.){3}\d{1,3}(:[0-9]{1,5})?$/.test(header) || /^\[[0-9a-fA-F:]+\](:[0-9]{1,5})?$/.test(header) || /^localhost(:[0-9]{1,5})?$/i.test(header); - } - return false; -} -function getBaseURL(url, path, request, loadEnv, trustedProxyHeaders) { - if (url) return withPath(url, path); - { - const fromEnv = env.BETTER_AUTH_URL || env.NEXT_PUBLIC_BETTER_AUTH_URL || env.PUBLIC_BETTER_AUTH_URL || env.NUXT_PUBLIC_BETTER_AUTH_URL || env.NUXT_PUBLIC_AUTH_URL || (env.BASE_URL !== "/" ? env.BASE_URL : void 0); - if (fromEnv) return withPath(fromEnv, path); - } - const fromRequest = request?.headers.get("x-forwarded-host"); - const fromRequestProto = request?.headers.get("x-forwarded-proto"); - if (fromRequest && fromRequestProto && trustedProxyHeaders) { - if (validateProxyHeader(fromRequestProto, "proto") && validateProxyHeader(fromRequest, "host")) try { - return withPath(`${fromRequestProto}://${fromRequest}`, path); - } catch (_error) { - } - } - if (request) { - const url$1 = getOrigin(request.url); - if (!url$1) throw new BetterAuthError("Could not get origin from request. Please provide a valid base URL."); - return withPath(url$1, path); - } - if (typeof window !== "undefined" && window.location) return withPath(window.location.origin, path); -} -function getOrigin(url) { - try { - const parsedUrl = new URL(url); - return parsedUrl.origin === "null" ? null : parsedUrl.origin; - } catch { - return null; - } -} -function getProtocol(url) { - try { - return new URL(url).protocol; - } catch { - return null; - } -} -function getHost(url) { - try { - return new URL(url).host; - } catch { - return null; - } -} -const LOCALHOST_IP = "127.0.0.1"; -function getIp(req, options) { - if (options.advanced?.ipAddress?.disableIpTracking) return null; - const headers = "headers" in req ? req.headers : req; - const ipHeaders = options.advanced?.ipAddress?.ipAddressHeaders || ["x-forwarded-for"]; - for (const key of ipHeaders) { - const value = "get" in headers ? headers.get(key) : headers[key]; - if (typeof value === "string") { - const ip = value.split(",")[0].trim(); - if (isValidIP(ip)) return normalizeIP(ip, { ipv6Subnet: options.advanced?.ipAddress?.ipv6Subnet }); - } - } - if (isTest() || isDevelopment()) return LOCALHOST_IP; - return null; -} -const { get: getOAuthState, set: setOAuthState } = defineRequestState(() => null); -function escapeRegExpChar(char) { - if (char === "-" || char === "^" || char === "$" || char === "+" || char === "." || char === "(" || char === ")" || char === "|" || char === "[" || char === "]" || char === "{" || char === "}" || char === "*" || char === "?" || char === "\\") return `\\${char}`; - else return char; -} -function escapeRegExpString(str) { - let result = ""; - for (let i = 0; i < str.length; i++) result += escapeRegExpChar(str[i]); - return result; -} -function transform(pattern, separator = true) { - if (Array.isArray(pattern)) return `(?:${pattern.map((p) => `^${transform(p, separator)}$`).join("|")})`; - let separatorSplitter = ""; - let separatorMatcher = ""; - let wildcard = "."; - if (separator === true) { - separatorSplitter = "/"; - separatorMatcher = "[/\\\\]"; - wildcard = "[^/\\\\]"; - } else if (separator) { - separatorSplitter = separator; - separatorMatcher = escapeRegExpString(separatorSplitter); - if (separatorMatcher.length > 1) { - separatorMatcher = `(?:${separatorMatcher})`; - wildcard = `((?!${separatorMatcher}).)`; - } else wildcard = `[^${separatorMatcher}]`; - } - const requiredSeparator = separator ? `${separatorMatcher}+?` : ""; - const optionalSeparator = separator ? `${separatorMatcher}*?` : ""; - const segments = separator ? pattern.split(separatorSplitter) : [pattern]; - let result = ""; - for (let s = 0; s < segments.length; s++) { - const segment = segments[s]; - const nextSegment = segments[s + 1]; - let currentSeparator = ""; - if (!segment && s > 0) continue; - if (separator) if (s === segments.length - 1) currentSeparator = optionalSeparator; - else if (nextSegment !== "**") currentSeparator = requiredSeparator; - else currentSeparator = ""; - if (separator && segment === "**") { - if (currentSeparator) { - result += s === 0 ? "" : currentSeparator; - result += `(?:${wildcard}*?${currentSeparator})*?`; - } - continue; - } - for (let c = 0; c < segment.length; c++) { - const char = segment[c]; - if (char === "\\") { - if (c < segment.length - 1) { - result += escapeRegExpChar(segment[c + 1]); - c++; - } - } else if (char === "?") result += wildcard; - else if (char === "*") result += `${wildcard}*?`; - else result += escapeRegExpChar(char); - } - result += currentSeparator; - } - return result; -} -function isMatch(regexp, sample) { - if (typeof sample !== "string") throw new TypeError(`Sample must be a string, but ${typeof sample} given`); - return regexp.test(sample); -} -function wildcardMatch(pattern, options) { - if (typeof pattern !== "string" && !Array.isArray(pattern)) throw new TypeError(`The first argument must be a single pattern string or an array of patterns, but ${typeof pattern} given`); - if (typeof options === "string" || typeof options === "boolean") options = { separator: options }; - if (arguments.length === 2 && !(typeof options === "undefined" || typeof options === "object" && options !== null && !Array.isArray(options))) throw new TypeError(`The second argument must be an options object or a string/boolean separator, but ${typeof options} given`); - options = options || {}; - if (options.separator === "\\") throw new Error("\\ is not a valid separator because it is used for escaping. Try setting the separator to `true` instead"); - const regexpPattern = transform(pattern, options.separator); - const regexp = new RegExp(`^${regexpPattern}$`, options.flags); - const fn = isMatch.bind(null, regexp); - fn.options = options; - fn.pattern = pattern; - fn.regexp = regexp; - return fn; -} -const matchesOriginPattern = (url, pattern, settings) => { - if (url.startsWith("/")) { - if (settings?.allowRelativePaths) return url.startsWith("/") && /^\/(?!\/|\\|%2f|%5c)[\w\-.\+/@]*(?:\?[\w\-.\+/=&%@]*)?$/.test(url); - return false; - } - if (pattern.includes("*") || pattern.includes("?")) { - if (pattern.includes("://")) return wildcardMatch(pattern)(getOrigin(url) || url); - const host = getHost(url); - if (!host) return false; - return wildcardMatch(pattern)(host); - } - const protocol = getProtocol(url); - return protocol === "http:" || protocol === "https:" || !protocol ? pattern === getOrigin(url) : url.startsWith(pattern); -}; -function shouldSkipCSRFForBackwardCompat(ctx) { - return ctx.context.skipOriginCheck === true && ctx.context.options.advanced?.disableCSRFCheck === void 0; -} -const logBackwardCompatWarning = deprecate(function logBackwardCompatWarning$1() { -}, "disableOriginCheck: true currently also disables CSRF checks. In a future version, disableOriginCheck will ONLY disable URL validation. To keep CSRF disabled, add disableCSRFCheck: true to your config."); -const originCheckMiddleware = createAuthMiddleware(async (ctx) => { - if (ctx.request?.method === "GET" || ctx.request?.method === "OPTIONS" || ctx.request?.method === "HEAD" || !ctx.request) return; - await validateOrigin(ctx); - if (ctx.context.skipOriginCheck) return; - const { body, query } = ctx; - const callbackURL = body?.callbackURL || query?.callbackURL; - const redirectURL = body?.redirectTo; - const errorCallbackURL = body?.errorCallbackURL; - const newUserCallbackURL = body?.newUserCallbackURL; - const validateURL = (url, label) => { - if (!url) return; - if (!ctx.context.isTrustedOrigin(url, { allowRelativePaths: label !== "origin" })) { - ctx.context.logger.error(`Invalid ${label}: ${url}`); - ctx.context.logger.info(`If it's a valid URL, please add ${url} to trustedOrigins in your auth config -`, `Current list of trustedOrigins: ${ctx.context.trustedOrigins}`); - throw new APIError("FORBIDDEN", { message: `Invalid ${label}` }); - } - }; - callbackURL && validateURL(callbackURL, "callbackURL"); - redirectURL && validateURL(redirectURL, "redirectURL"); - errorCallbackURL && validateURL(errorCallbackURL, "errorCallbackURL"); - newUserCallbackURL && validateURL(newUserCallbackURL, "newUserCallbackURL"); -}); -const originCheck = (getValue) => createAuthMiddleware(async (ctx) => { - if (!ctx.request) return; - if (ctx.context.skipOriginCheck) return; - const callbackURL = getValue(ctx); - const validateURL = (url, label) => { - if (!url) return; - if (!ctx.context.isTrustedOrigin(url, { allowRelativePaths: label !== "origin" })) { - ctx.context.logger.error(`Invalid ${label}: ${url}`); - ctx.context.logger.info(`If it's a valid URL, please add ${url} to trustedOrigins in your auth config -`, `Current list of trustedOrigins: ${ctx.context.trustedOrigins}`); - throw new APIError("FORBIDDEN", { message: `Invalid ${label}` }); - } - }; - const callbacks = Array.isArray(callbackURL) ? callbackURL : [callbackURL]; - for (const url of callbacks) validateURL(url, "callbackURL"); -}); -async function validateOrigin(ctx, forceValidate = false) { - const headers = ctx.request?.headers; - if (!headers || !ctx.request) return; - const originHeader = headers.get("origin") || headers.get("referer") || ""; - const useCookies = headers.has("cookie"); - if (ctx.context.skipCSRFCheck) return; - if (shouldSkipCSRFForBackwardCompat(ctx)) { - ctx.context.options.advanced?.disableOriginCheck === true && logBackwardCompatWarning(); - return; - } - const skipOriginCheck = ctx.context.skipOriginCheck; - if (Array.isArray(skipOriginCheck)) try { - const basePath = new URL(ctx.context.baseURL).pathname; - const currentPath = normalizePathname(ctx.request.url, basePath); - if (skipOriginCheck.some((skipPath) => currentPath.startsWith(skipPath))) return; - } catch { - } - if (!(forceValidate || useCookies)) return; - if (!originHeader || originHeader === "null") throw new APIError("FORBIDDEN", { message: BASE_ERROR_CODES.MISSING_OR_NULL_ORIGIN }); - const trustedOrigins = Array.isArray(ctx.context.options.trustedOrigins) ? ctx.context.trustedOrigins : [...ctx.context.trustedOrigins, ...(await ctx.context.options.trustedOrigins?.(ctx.request))?.filter((v) => Boolean(v)) || []]; - if (!trustedOrigins.some((origin) => matchesOriginPattern(originHeader, origin))) { - ctx.context.logger.error(`Invalid origin: ${originHeader}`); - ctx.context.logger.info(`If it's a valid URL, please add ${originHeader} to trustedOrigins in your auth config -`, `Current list of trustedOrigins: ${trustedOrigins}`); - throw new APIError("FORBIDDEN", { message: "Invalid origin" }); - } -} -const formCsrfMiddleware = createAuthMiddleware(async (ctx) => { - if (!ctx.request) return; - await validateFormCsrf(ctx); -}); -async function validateFormCsrf(ctx) { - const req = ctx.request; - if (!req) return; - if (ctx.context.skipCSRFCheck) return; - if (shouldSkipCSRFForBackwardCompat(ctx)) return; - const headers = req.headers; - if (headers.has("cookie")) return await validateOrigin(ctx); - const site = headers.get("Sec-Fetch-Site"); - const mode = headers.get("Sec-Fetch-Mode"); - const dest = headers.get("Sec-Fetch-Dest"); - if (Boolean(site && site.trim() || mode && mode.trim() || dest && dest.trim())) { - if (site === "cross-site" && mode === "navigate") { - ctx.context.logger.error("Blocked cross-site navigation login attempt (CSRF protection)", { - secFetchSite: site, - secFetchMode: mode, - secFetchDest: dest - }); - throw new APIError("FORBIDDEN", { message: BASE_ERROR_CODES.CROSS_SITE_NAVIGATION_LOGIN_BLOCKED }); - } - return await validateOrigin(ctx, true); - } -} -const memory = /* @__PURE__ */ new Map(); -function shouldRateLimit(max, window2, rateLimitData) { - const now2 = Date.now(); - const windowInMs = window2 * 1e3; - return now2 - rateLimitData.lastRequest < windowInMs && rateLimitData.count >= max; -} -function rateLimitResponse(retryAfter) { - return new Response(JSON.stringify({ message: "Too many requests. Please try again later." }), { - status: 429, - statusText: "Too Many Requests", - headers: { "X-Retry-After": retryAfter.toString() } - }); -} -function getRetryAfter(lastRequest, window2) { - const now2 = Date.now(); - const windowInMs = window2 * 1e3; - return Math.ceil((lastRequest + windowInMs - now2) / 1e3); -} -function createDatabaseStorageWrapper(ctx) { - const model = "rateLimit"; - const db2 = ctx.adapter; - return { - get: async (key) => { - const data = (await db2.findMany({ - model, - where: [{ - field: "key", - value: key - }] - }))[0]; - if (typeof data?.lastRequest === "bigint") data.lastRequest = Number(data.lastRequest); - return data; - }, - set: async (key, value, _update) => { - try { - if (_update) await db2.updateMany({ - model, - where: [{ - field: "key", - value: key - }], - update: { - count: value.count, - lastRequest: value.lastRequest - } - }); - else await db2.create({ - model, - data: { - key, - count: value.count, - lastRequest: value.lastRequest - } - }); - } catch (e) { - ctx.logger.error("Error setting rate limit", e); - } - } - }; -} -function getRateLimitStorage(ctx, rateLimitSettings) { - if (ctx.options.rateLimit?.customStorage) return ctx.options.rateLimit.customStorage; - const storage = ctx.rateLimit.storage; - if (storage === "secondary-storage") return { - get: async (key) => { - const data = await ctx.options.secondaryStorage?.get(key); - return data ? safeJSONParse(data) : null; - }, - set: async (key, value, _update) => { - const ttl = rateLimitSettings?.window ?? ctx.options.rateLimit?.window ?? 10; - await ctx.options.secondaryStorage?.set?.(key, JSON.stringify(value), ttl); - } - }; - else if (storage === "memory") return { - async get(key) { - const entry = memory.get(key); - if (!entry) return null; - if (Date.now() >= entry.expiresAt) { - memory.delete(key); - return null; - } - return entry.data; - }, - async set(key, value, _update) { - const ttl = rateLimitSettings?.window ?? ctx.options.rateLimit?.window ?? 10; - const expiresAt = Date.now() + ttl * 1e3; - memory.set(key, { - data: value, - expiresAt - }); - } - }; - return createDatabaseStorageWrapper(ctx); -} -async function onRequestRateLimit(req, ctx) { - if (!ctx.rateLimit.enabled) return; - const basePath = new URL(ctx.baseURL).pathname; - const path = normalizePathname(req.url, basePath); - let currentWindow = ctx.rateLimit.window; - let currentMax = ctx.rateLimit.max; - const ip = getIp(req, ctx.options); - if (!ip) return; - const key = createRateLimitKey(ip, path); - const specialRule = getDefaultSpecialRules().find((rule) => rule.pathMatcher(path)); - if (specialRule) { - currentWindow = specialRule.window; - currentMax = specialRule.max; - } - for (const plugin of ctx.options.plugins || []) if (plugin.rateLimit) { - const matchedRule = plugin.rateLimit.find((rule) => rule.pathMatcher(path)); - if (matchedRule) { - currentWindow = matchedRule.window; - currentMax = matchedRule.max; - break; - } - } - if (ctx.rateLimit.customRules) { - const _path = Object.keys(ctx.rateLimit.customRules).find((p) => { - if (p.includes("*")) return wildcardMatch(p)(path); - return p === path; - }); - if (_path) { - const customRule = ctx.rateLimit.customRules[_path]; - const resolved = typeof customRule === "function" ? await customRule(req, { - window: currentWindow, - max: currentMax - }) : customRule; - if (resolved) { - currentWindow = resolved.window; - currentMax = resolved.max; - } - if (resolved === false) return; - } - } - const storage = getRateLimitStorage(ctx, { window: currentWindow }); - const data = await storage.get(key); - const now2 = Date.now(); - if (!data) await storage.set(key, { - key, - count: 1, - lastRequest: now2 - }); - else { - const timeSinceLastRequest = now2 - data.lastRequest; - if (shouldRateLimit(currentMax, currentWindow, data)) return rateLimitResponse(getRetryAfter(data.lastRequest, currentWindow)); - else if (timeSinceLastRequest > currentWindow * 1e3) await storage.set(key, { - ...data, - count: 1, - lastRequest: now2 - }, true); - else await storage.set(key, { - ...data, - count: data.count + 1, - lastRequest: now2 - }, true); - } -} -function getDefaultSpecialRules() { - return [{ - pathMatcher(path) { - return path.startsWith("/sign-in") || path.startsWith("/sign-up") || path.startsWith("/change-password") || path.startsWith("/change-email"); - }, - window: 10, - max: 3 - }]; -} -const getDate = (span, unit = "ms") => { - return new Date(Date.now() + (unit === "sec" ? span * 1e3 : span)); -}; -const cache = /* @__PURE__ */ new WeakMap(); -function parseOutputData(data, schema2) { - const fields = schema2.fields; - const parsedData = {}; - for (const key in data) { - const field = fields[key]; - if (!field) { - parsedData[key] = data[key]; - continue; - } - if (field.returned === false && key !== "id") continue; - parsedData[key] = data[key]; - } - return parsedData; -} -function getFields(options, table, mode) { - const cacheKey = `${table}:${mode}`; - if (!cache.has(options)) cache.set(options, /* @__PURE__ */ new Map()); - const tableCache = cache.get(options); - if (tableCache.has(cacheKey)) return tableCache.get(cacheKey); - const coreSchema = mode === "output" ? getAuthTables(options)[table]?.fields ?? {} : {}; - const additionalFields = table === "user" || table === "session" || table === "account" ? options[table]?.additionalFields : void 0; - let schema2 = { - ...coreSchema, - ...additionalFields ?? {} - }; - for (const plugin of options.plugins || []) if (plugin.schema && plugin.schema[table]) schema2 = { - ...schema2, - ...plugin.schema[table].fields - }; - tableCache.set(cacheKey, schema2); - return schema2; -} -function parseUserOutput(options, user) { - return parseOutputData(user, { fields: getFields(options, "user", "output") }); -} -function parseSessionOutput(options, session) { - return parseOutputData(session, { fields: getFields(options, "session", "output") }); -} -function parseAccountOutput(options, account) { - const { accessToken: _accessToken, refreshToken: _refreshToken, idToken: _idToken, accessTokenExpiresAt: _accessTokenExpiresAt, refreshTokenExpiresAt: _refreshTokenExpiresAt, password: _password, ...rest } = parseOutputData(account, { fields: getFields(options, "account", "output") }); - return rest; -} -function parseInputData(data, schema2) { - const action = schema2.action || "create"; - const fields = schema2.fields; - const parsedData = Object.assign(/* @__PURE__ */ Object.create(null), null); - for (const key in fields) { - if (key in data) { - if (fields[key].input === false) { - if (fields[key].defaultValue !== void 0) { - if (action !== "update") { - parsedData[key] = fields[key].defaultValue; - continue; - } - } - if (data[key]) throw new APIError("BAD_REQUEST", { message: `${key} is not allowed to be set` }); - continue; - } - if (fields[key].validator?.input && data[key] !== void 0) { - const result = fields[key].validator.input["~standard"].validate(data[key]); - if (result instanceof Promise) throw new APIError("INTERNAL_SERVER_ERROR", { message: "Async validation is not supported for additional fields" }); - if ("issues" in result && result.issues) throw new APIError("BAD_REQUEST", { message: result.issues[0]?.message || "Validation Error" }); - parsedData[key] = result.value; - continue; - } - if (fields[key].transform?.input && data[key] !== void 0) { - parsedData[key] = fields[key].transform?.input(data[key]); - continue; - } - parsedData[key] = data[key]; - continue; - } - if (fields[key].defaultValue !== void 0 && action === "create") { - if (typeof fields[key].defaultValue === "function") { - parsedData[key] = fields[key].defaultValue(); - continue; - } - parsedData[key] = fields[key].defaultValue; - continue; - } - if (fields[key].required && action === "create") throw new APIError("BAD_REQUEST", { message: `${key} is required` }); - } - return parsedData; -} -function parseUserInput(options, user = {}, action) { - return parseInputData(user, { - fields: getFields(options, "user", "input"), - action - }); -} -function parseAdditionalUserInput(options, user) { - const schema2 = getFields(options, "user", "input"); - return parseInputData(user || {}, { fields: schema2 }); -} -function parseAccountInput(options, account) { - return parseInputData(account, { fields: getFields(options, "account", "input") }); -} -function parseSessionInput(options, session) { - return parseInputData(session, { fields: getFields(options, "session", "input") }); -} -function mergeSchema(schema2, newSchema) { - if (!newSchema) return schema2; - for (const table in newSchema) { - const newModelName = newSchema[table]?.modelName; - if (newModelName) schema2[table].modelName = newModelName; - for (const field in schema2[table].fields) { - const newField = newSchema[table]?.fields?.[field]; - if (!newField) continue; - schema2[table].fields[field].fieldName = newField; - } - } - return schema2; -} -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (all, symbols) => { - let target = {}; - for (var name in all) { - __defProp(target, name, { - get: all[name], - enumerable: true - }); - } - return target; -}; -var __copyProps = (to, from, except, desc2) => { - if (from && typeof from === "object" || typeof from === "function") { - for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) { - key = keys[i]; - if (!__hasOwnProp.call(to, key) && key !== except) { - __defProp(to, key, { - get: ((k) => from[k]).bind(null, key), - enumerable: !(desc2 = __getOwnPropDesc(from, key)) || desc2.enumerable - }); - } - } - } - return to; -}; -var __reExport = (target, mod, secondTarget, symbols) => { - __copyProps(target, mod, "default"); -}; -async function getBaseAdapter(options, handleDirectDatabase) { - let adapter; - if (!options.database) { - const tables = getAuthTables(options); - const memoryDB = Object.keys(tables).reduce((acc, key) => { - acc[key] = []; - return acc; - }, {}); - const { memoryAdapter } = await import("./index5.js"); - adapter = memoryAdapter(memoryDB)(options); - } else if (typeof options.database === "function") adapter = options.database(options); - else adapter = await handleDirectDatabase(options); - if (!adapter.transaction) { - logger.warn("Adapter does not correctly implement transaction function, patching it automatically. Please update your adapter implementation."); - adapter.transaction = async (cb) => { - return cb(adapter); - }; - } - return adapter; -} -async function getAdapter(options) { - return getBaseAdapter(options, async (opts) => { - const { createKyselyAdapter: createKyselyAdapter2 } = await import("./index6.js"); - const { kysely, databaseType, transaction } = await createKyselyAdapter2(opts); - if (!kysely) throw new BetterAuthError("Failed to initialize database adapter"); - const { kyselyAdapter } = await import("./index6.js"); - return kyselyAdapter(kysely, { - type: databaseType || "sqlite", - debugLogs: opts.database && "debugLogs" in opts.database ? opts.database.debugLogs : false, - transaction - })(opts); - }); -} -const createFieldAttribute = (type, config2) => { - return { - type, - ...config2 - }; -}; -function convertToDB(fields, values) { - const result = values.id ? { id: values.id } : {}; - for (const key in fields) { - const field = fields[key]; - const value = values[key]; - if (value === void 0) continue; - result[field.fieldName || key] = value; - } - return result; -} -function convertFromDB(fields, values) { - if (!values) return null; - const result = { id: values.id }; - for (const [key, value] of Object.entries(fields)) result[key] = values[value.fieldName || key]; - return result; -} -function getWithHooks(adapter, ctx) { - const hooks = ctx.hooks; - async function createWithHooks(data, model, customCreateFn) { - const context = await getCurrentAuthContext().catch(() => null); - let actualData = data; - for (const hook of hooks || []) { - const toRun = hook[model]?.create?.before; - if (toRun) { - const result = await toRun(actualData, context); - if (result === false) return null; - if (typeof result === "object" && "data" in result) actualData = { - ...actualData, - ...result.data - }; - } - } - const customCreated = customCreateFn ? await customCreateFn.fn(actualData) : null; - const created = !customCreateFn || customCreateFn.executeMainFn ? await (await getCurrentAdapter(adapter)).create({ - model, - data: actualData, - forceAllowId: true - }) : customCreated; - for (const hook of hooks || []) { - const toRun = hook[model]?.create?.after; - if (toRun) await toRun(created, context); - } - return created; - } - async function updateWithHooks(data, where, model, customUpdateFn) { - const context = await getCurrentAuthContext().catch(() => null); - let actualData = data; - for (const hook of hooks || []) { - const toRun = hook[model]?.update?.before; - if (toRun) { - const result = await toRun(data, context); - if (result === false) return null; - if (typeof result === "object" && "data" in result) actualData = { - ...actualData, - ...result.data - }; - } - } - const customUpdated = customUpdateFn ? await customUpdateFn.fn(actualData) : null; - const updated = !customUpdateFn || customUpdateFn.executeMainFn ? await (await getCurrentAdapter(adapter)).update({ - model, - update: actualData, - where - }) : customUpdated; - for (const hook of hooks || []) { - const toRun = hook[model]?.update?.after; - if (toRun) await toRun(updated, context); - } - return updated; - } - async function updateManyWithHooks(data, where, model, customUpdateFn) { - const context = await getCurrentAuthContext().catch(() => null); - let actualData = data; - for (const hook of hooks || []) { - const toRun = hook[model]?.update?.before; - if (toRun) { - const result = await toRun(data, context); - if (result === false) return null; - if (typeof result === "object" && "data" in result) actualData = { - ...actualData, - ...result.data - }; - } - } - const customUpdated = customUpdateFn ? await customUpdateFn.fn(actualData) : null; - const updated = !customUpdateFn || customUpdateFn.executeMainFn ? await (await getCurrentAdapter(adapter)).updateMany({ - model, - update: actualData, - where - }) : customUpdated; - for (const hook of hooks || []) { - const toRun = hook[model]?.update?.after; - if (toRun) await toRun(updated, context); - } - return updated; - } - async function deleteWithHooks(where, model, customDeleteFn) { - const context = await getCurrentAuthContext().catch(() => null); - let entityToDelete = null; - try { - entityToDelete = (await (await getCurrentAdapter(adapter)).findMany({ - model, - where, - limit: 1 - }))[0] || null; - } catch { - } - if (entityToDelete) for (const hook of hooks || []) { - const toRun = hook[model]?.delete?.before; - if (toRun) { - if (await toRun(entityToDelete, context) === false) return null; - } - } - const customDeleted = customDeleteFn ? await customDeleteFn.fn(where) : null; - const deleted = !customDeleteFn || customDeleteFn.executeMainFn ? await (await getCurrentAdapter(adapter)).delete({ - model, - where - }) : customDeleted; - if (entityToDelete) for (const hook of hooks || []) { - const toRun = hook[model]?.delete?.after; - if (toRun) await toRun(entityToDelete, context); - } - return deleted; - } - async function deleteManyWithHooks(where, model, customDeleteFn) { - const context = await getCurrentAuthContext().catch(() => null); - let entitiesToDelete = []; - try { - entitiesToDelete = await (await getCurrentAdapter(adapter)).findMany({ - model, - where - }); - } catch { - } - for (const entity of entitiesToDelete) for (const hook of hooks || []) { - const toRun = hook[model]?.delete?.before; - if (toRun) { - if (await toRun(entity, context) === false) return null; - } - } - const customDeleted = customDeleteFn ? await customDeleteFn.fn(where) : null; - const deleted = !customDeleteFn || customDeleteFn.executeMainFn ? await (await getCurrentAdapter(adapter)).deleteMany({ - model, - where - }) : customDeleted; - for (const entity of entitiesToDelete) for (const hook of hooks || []) { - const toRun = hook[model]?.delete?.after; - if (toRun) await toRun(entity, context); - } - return deleted; - } - return { - createWithHooks, - updateWithHooks, - updateManyWithHooks, - deleteWithHooks, - deleteManyWithHooks - }; -} -const createInternalAdapter = (adapter, ctx) => { - const logger2 = ctx.logger; - const options = ctx.options; - const secondaryStorage = options.secondaryStorage; - const sessionExpiration = options.session?.expiresIn || 3600 * 24 * 7; - const { createWithHooks, updateWithHooks, updateManyWithHooks, deleteWithHooks, deleteManyWithHooks } = getWithHooks(adapter, ctx); - async function refreshUserSessions(user) { - if (!secondaryStorage) return; - const listRaw = await secondaryStorage.get(`active-sessions-${user.id}`); - if (!listRaw) return; - const now2 = Date.now(); - const validSessions = (safeJSONParse(listRaw) || []).filter((s) => s.expiresAt > now2); - await Promise.all(validSessions.map(async ({ token }) => { - const cached = await secondaryStorage.get(token); - if (!cached) return; - const parsed = safeJSONParse(cached); - if (!parsed) return; - const sessionTTL = Math.max(Math.floor(new Date(parsed.session.expiresAt).getTime() - now2) / 1e3, 0); - await secondaryStorage.set(token, JSON.stringify({ - session: parsed.session, - user - }), Math.floor(sessionTTL)); - })); - } - return { - createOAuthUser: async (user, account) => { - return runWithTransaction(adapter, async () => { - const createdUser = await createWithHooks({ - createdAt: /* @__PURE__ */ new Date(), - updatedAt: /* @__PURE__ */ new Date(), - ...user - }, "user", void 0); - return { - user: createdUser, - account: await createWithHooks({ - ...account, - userId: createdUser.id, - createdAt: /* @__PURE__ */ new Date(), - updatedAt: /* @__PURE__ */ new Date() - }, "account", void 0) - }; - }); - }, - createUser: async (user) => { - return await createWithHooks({ - createdAt: /* @__PURE__ */ new Date(), - updatedAt: /* @__PURE__ */ new Date(), - ...user, - email: user.email?.toLowerCase() - }, "user", void 0); - }, - createAccount: async (account) => { - return await createWithHooks({ - createdAt: /* @__PURE__ */ new Date(), - updatedAt: /* @__PURE__ */ new Date(), - ...account - }, "account", void 0); - }, - listSessions: async (userId) => { - if (secondaryStorage) { - const currentList = await secondaryStorage.get(`active-sessions-${userId}`); - if (!currentList) return []; - const list = safeJSONParse(currentList) || []; - const now2 = Date.now(); - const seenTokens = /* @__PURE__ */ new Set(); - const sessions = []; - for (const { token, expiresAt } of list) { - if (expiresAt <= now2 || seenTokens.has(token)) continue; - seenTokens.add(token); - const data = await secondaryStorage.get(token); - if (!data) continue; - try { - const parsed = typeof data === "string" ? JSON.parse(data) : data; - if (!parsed?.session) continue; - sessions.push(parseSessionOutput(ctx.options, { - ...parsed.session, - expiresAt: new Date(parsed.session.expiresAt) - })); - } catch { - continue; - } - } - return sessions; - } - return await (await getCurrentAdapter(adapter)).findMany({ - model: "session", - where: [{ - field: "userId", - value: userId - }] - }); - }, - listUsers: async (limit, offset, sortBy, where) => { - return await (await getCurrentAdapter(adapter)).findMany({ - model: "user", - limit, - offset, - sortBy, - where - }); - }, - countTotalUsers: async (where) => { - const total = await (await getCurrentAdapter(adapter)).count({ - model: "user", - where - }); - if (typeof total === "string") return parseInt(total); - return total; - }, - deleteUser: async (userId) => { - if (!secondaryStorage || options.session?.storeSessionInDatabase) await deleteManyWithHooks([{ - field: "userId", - value: userId - }], "session", void 0); - await deleteManyWithHooks([{ - field: "userId", - value: userId - }], "account", void 0); - await deleteWithHooks([{ - field: "id", - value: userId - }], "user", void 0); - }, - createSession: async (userId, dontRememberMe, override, overrideAll) => { - const ctx$1 = await getCurrentAuthContext().catch(() => null); - const headers = ctx$1?.headers || ctx$1?.request?.headers; - const { id: _, ...rest } = override || {}; - const defaultAdditionalFields = parseSessionInput(ctx$1?.context.options ?? options, {}); - const data = { - ipAddress: ctx$1?.request || ctx$1?.headers ? getIp(ctx$1?.request || ctx$1?.headers, ctx$1?.context.options) || "" : "", - userAgent: headers?.get("user-agent") || "", - ...rest, - expiresAt: dontRememberMe ? getDate(3600 * 24, "sec") : getDate(sessionExpiration, "sec"), - userId, - token: generateId(32), - createdAt: /* @__PURE__ */ new Date(), - updatedAt: /* @__PURE__ */ new Date(), - ...defaultAdditionalFields, - ...overrideAll ? rest : {} - }; - return await createWithHooks(data, "session", secondaryStorage ? { - fn: async (sessionData) => { - const currentList = await secondaryStorage.get(`active-sessions-${userId}`); - let list = []; - const now2 = Date.now(); - if (currentList) { - list = safeJSONParse(currentList) || []; - list = list.filter((session) => session.expiresAt > now2 && session.token !== data.token); - } - const sorted = [...list, { - token: data.token, - expiresAt: data.expiresAt.getTime() - }].sort((a, b) => a.expiresAt - b.expiresAt); - const furthestSessionExp = sorted.at(-1)?.expiresAt ?? data.expiresAt.getTime(); - const furthestSessionTTL = Math.max(Math.floor((furthestSessionExp - now2) / 1e3), 0); - if (furthestSessionTTL > 0) await secondaryStorage.set(`active-sessions-${userId}`, JSON.stringify(sorted), furthestSessionTTL); - const user = await (await getCurrentAdapter(adapter)).findOne({ - model: "user", - where: [{ - field: "id", - value: userId - }] - }); - const sessionTTL = Math.max(Math.floor((data.expiresAt.getTime() - now2) / 1e3), 0); - if (sessionTTL > 0) await secondaryStorage.set(data.token, JSON.stringify({ - session: sessionData, - user - }), sessionTTL); - return sessionData; - }, - executeMainFn: options.session?.storeSessionInDatabase - } : void 0); - }, - findSession: async (token) => { - if (secondaryStorage) { - const sessionStringified = await secondaryStorage.get(token); - if (!sessionStringified && !options.session?.storeSessionInDatabase) return null; - if (sessionStringified) { - const s = safeJSONParse(sessionStringified); - if (!s) return null; - return { - session: parseSessionOutput(ctx.options, { - ...s.session, - expiresAt: new Date(s.session.expiresAt), - createdAt: new Date(s.session.createdAt), - updatedAt: new Date(s.session.updatedAt) - }), - user: parseUserOutput(ctx.options, { - ...s.user, - createdAt: new Date(s.user.createdAt), - updatedAt: new Date(s.user.updatedAt) - }) - }; - } - } - const result = await (await getCurrentAdapter(adapter)).findOne({ - model: "session", - where: [{ - value: token, - field: "token" - }], - join: { user: true } - }); - if (!result) return null; - const { user, ...session } = result; - if (!user) return null; - return { - session: parseSessionOutput(ctx.options, session), - user: parseUserOutput(ctx.options, user) - }; - }, - findSessions: async (sessionTokens) => { - if (secondaryStorage) { - const sessions$1 = []; - for (const sessionToken of sessionTokens) { - const sessionStringified = await secondaryStorage.get(sessionToken); - if (sessionStringified) try { - const s = typeof sessionStringified === "string" ? JSON.parse(sessionStringified) : sessionStringified; - if (!s?.session) continue; - const session = { - session: { - ...s.session, - expiresAt: new Date(s.session.expiresAt) - }, - user: { - ...s.user, - createdAt: new Date(s.user.createdAt), - updatedAt: new Date(s.user.updatedAt) - } - }; - sessions$1.push(session); - } catch { - continue; - } - } - return sessions$1; - } - const sessions = await (await getCurrentAdapter(adapter)).findMany({ - model: "session", - where: [{ - field: "token", - value: sessionTokens, - operator: "in" - }], - join: { user: true } - }); - if (!sessions.length) return []; - if (sessions.some((session) => !session.user)) return []; - return sessions.map((_session) => { - const { user, ...session } = _session; - return { - session, - user - }; - }); - }, - updateSession: async (sessionToken, session) => { - return await updateWithHooks(session, [{ - field: "token", - value: sessionToken - }], "session", secondaryStorage ? { - async fn(data) { - const currentSession = await secondaryStorage.get(sessionToken); - if (!currentSession) return null; - const parsedSession = safeJSONParse(currentSession); - if (!parsedSession) return null; - const mergedSession = { - ...parsedSession.session, - ...data, - expiresAt: new Date(data.expiresAt ?? parsedSession.session.expiresAt), - createdAt: new Date(parsedSession.session.createdAt), - updatedAt: new Date(data.updatedAt ?? parsedSession.session.updatedAt) - }; - const updatedSession = parseSessionOutput(ctx.options, mergedSession); - const now2 = Date.now(); - const expiresMs = new Date(updatedSession.expiresAt).getTime(); - const sessionTTL = Math.max(Math.floor((expiresMs - now2) / 1e3), 0); - if (sessionTTL > 0) { - await secondaryStorage.set(sessionToken, JSON.stringify({ - session: updatedSession, - user: parsedSession.user - }), sessionTTL); - const listKey = `active-sessions-${updatedSession.userId}`; - const listRaw = await secondaryStorage.get(listKey); - const sorted = (listRaw ? safeJSONParse(listRaw) || [] : []).filter((s) => s.token !== sessionToken && s.expiresAt > now2).concat([{ - token: sessionToken, - expiresAt: expiresMs - }]).sort((a, b) => a.expiresAt - b.expiresAt); - const furthestSessionExp = sorted.at(-1)?.expiresAt; - if (furthestSessionExp && furthestSessionExp > now2) await secondaryStorage.set(listKey, JSON.stringify(sorted), Math.floor((furthestSessionExp - now2) / 1e3)); - else await secondaryStorage.delete(listKey); - } - return updatedSession; - }, - executeMainFn: options.session?.storeSessionInDatabase - } : void 0); - }, - deleteSession: async (token) => { - if (secondaryStorage) { - const data = await secondaryStorage.get(token); - if (data) { - const { session } = safeJSONParse(data) ?? {}; - if (!session) { - logger2.error("Session not found in secondary storage"); - return; - } - const userId = session.userId; - const currentList = await secondaryStorage.get(`active-sessions-${userId}`); - if (currentList) { - const list = safeJSONParse(currentList) || []; - const now2 = Date.now(); - const filtered = list.filter((session$1) => session$1.expiresAt > now2 && session$1.token !== token); - const furthestSessionExp = filtered.sort((a, b) => a.expiresAt - b.expiresAt).at(-1)?.expiresAt; - if (filtered.length > 0 && furthestSessionExp && furthestSessionExp > Date.now()) await secondaryStorage.set(`active-sessions-${userId}`, JSON.stringify(filtered), Math.floor((furthestSessionExp - now2) / 1e3)); - else await secondaryStorage.delete(`active-sessions-${userId}`); - } else logger2.error("Active sessions list not found in secondary storage"); - } - await secondaryStorage.delete(token); - if (!options.session?.storeSessionInDatabase || ctx.options.session?.preserveSessionInDatabase) return; - } - await deleteWithHooks([{ - field: "token", - value: token - }], "session", void 0); - }, - deleteAccounts: async (userId) => { - await deleteManyWithHooks([{ - field: "userId", - value: userId - }], "account", void 0); - }, - deleteAccount: async (accountId) => { - await deleteWithHooks([{ - field: "id", - value: accountId - }], "account", void 0); - }, - deleteSessions: async (userIdOrSessionTokens) => { - if (secondaryStorage) { - if (typeof userIdOrSessionTokens === "string") { - const activeSession = await secondaryStorage.get(`active-sessions-${userIdOrSessionTokens}`); - const sessions = activeSession ? safeJSONParse(activeSession) : []; - if (!sessions) return; - for (const session of sessions) await secondaryStorage.delete(session.token); - await secondaryStorage.delete(`active-sessions-${userIdOrSessionTokens}`); - } else for (const sessionToken of userIdOrSessionTokens) if (await secondaryStorage.get(sessionToken)) await secondaryStorage.delete(sessionToken); - if (!options.session?.storeSessionInDatabase || ctx.options.session?.preserveSessionInDatabase) return; - } - await deleteManyWithHooks([{ - field: Array.isArray(userIdOrSessionTokens) ? "token" : "userId", - value: userIdOrSessionTokens, - operator: Array.isArray(userIdOrSessionTokens) ? "in" : void 0 - }], "session", void 0); - }, - findOAuthUser: async (email, accountId, providerId) => { - const account = await (await getCurrentAdapter(adapter)).findOne({ - model: "account", - where: [{ - value: accountId, - field: "accountId" - }, { - value: providerId, - field: "providerId" - }], - join: { user: true } - }); - if (account) if (account.user) return { - user: account.user, - linkedAccount: account, - accounts: [account] - }; - else { - const user = await (await getCurrentAdapter(adapter)).findOne({ - model: "user", - where: [{ - value: email.toLowerCase(), - field: "email" - }] - }); - if (user) return { - user, - linkedAccount: account, - accounts: [account] - }; - return null; - } - else { - const user = await (await getCurrentAdapter(adapter)).findOne({ - model: "user", - where: [{ - value: email.toLowerCase(), - field: "email" - }] - }); - if (user) return { - user, - linkedAccount: null, - accounts: await (await getCurrentAdapter(adapter)).findMany({ - model: "account", - where: [{ - value: user.id, - field: "userId" - }] - }) || [] - }; - else return null; - } - }, - findUserByEmail: async (email, options$1) => { - const result = await (await getCurrentAdapter(adapter)).findOne({ - model: "user", - where: [{ - value: email.toLowerCase(), - field: "email" - }], - join: { ...options$1?.includeAccounts ? { account: true } : {} } - }); - if (!result) return null; - const { account: accounts, ...user } = result; - return { - user, - accounts: accounts ?? [] - }; - }, - findUserById: async (userId) => { - if (!userId) return null; - return await (await getCurrentAdapter(adapter)).findOne({ - model: "user", - where: [{ - field: "id", - value: userId - }] - }); - }, - linkAccount: async (account) => { - return await createWithHooks({ - createdAt: /* @__PURE__ */ new Date(), - updatedAt: /* @__PURE__ */ new Date(), - ...account - }, "account", void 0); - }, - updateUser: async (userId, data) => { - const user = await updateWithHooks(data, [{ - field: "id", - value: userId - }], "user", void 0); - await refreshUserSessions(user); - return user; - }, - updateUserByEmail: async (email, data) => { - const user = await updateWithHooks(data, [{ - field: "email", - value: email.toLowerCase() - }], "user", void 0); - await refreshUserSessions(user); - return user; - }, - updatePassword: async (userId, password) => { - await updateManyWithHooks({ password }, [{ - field: "userId", - value: userId - }, { - field: "providerId", - value: "credential" - }], "account", void 0); - }, - findAccounts: async (userId) => { - return await (await getCurrentAdapter(adapter)).findMany({ - model: "account", - where: [{ - field: "userId", - value: userId - }] - }); - }, - findAccount: async (accountId) => { - return await (await getCurrentAdapter(adapter)).findOne({ - model: "account", - where: [{ - field: "accountId", - value: accountId - }] - }); - }, - findAccountByProviderId: async (accountId, providerId) => { - return await (await getCurrentAdapter(adapter)).findOne({ - model: "account", - where: [{ - field: "accountId", - value: accountId - }, { - field: "providerId", - value: providerId - }] - }); - }, - findAccountByUserId: async (userId) => { - return await (await getCurrentAdapter(adapter)).findMany({ - model: "account", - where: [{ - field: "userId", - value: userId - }] - }); - }, - updateAccount: async (id, data) => { - return await updateWithHooks(data, [{ - field: "id", - value: id - }], "account", void 0); - }, - createVerificationValue: async (data) => { - return await createWithHooks({ - createdAt: /* @__PURE__ */ new Date(), - updatedAt: /* @__PURE__ */ new Date(), - ...data - }, "verification", void 0); - }, - findVerificationValue: async (identifier) => { - const verification = await (await getCurrentAdapter(adapter)).findMany({ - model: "verification", - where: [{ - field: "identifier", - value: identifier - }], - sortBy: { - field: "createdAt", - direction: "desc" - }, - limit: 1 - }); - if (!options.verification?.disableCleanup) await deleteManyWithHooks([{ - field: "expiresAt", - value: /* @__PURE__ */ new Date(), - operator: "lt" - }], "verification", void 0); - return verification[0]; - }, - deleteVerificationValue: async (id) => { - await deleteWithHooks([{ - field: "id", - value: id - }], "verification", void 0); - }, - deleteVerificationByIdentifier: async (identifier) => { - await deleteWithHooks([{ - field: "identifier", - value: identifier - }], "verification", void 0); - }, - updateVerificationValue: async (id, data) => { - return await updateWithHooks(data, [{ - field: "id", - value: id - }], "verification", void 0); - } - }; -}; -function toZodSchema({ fields, isClientSide }) { - const zodFields = Object.keys(fields).reduce((acc, key) => { - const field = fields[key]; - if (!field) return acc; - if (isClientSide && field.input === false) return acc; - let schema2; - if (field.type === "json") schema2 = z.json ? z.json() : z.any(); - else if (field.type === "string[]" || field.type === "number[]") schema2 = z.array(field.type === "string[]" ? z.string() : z.number()); - else if (Array.isArray(field.type)) schema2 = z.any(); - else schema2 = z[field.type](); - if (field?.required === false) schema2 = schema2.optional(); - if (!isClientSide && field?.returned === false) return acc; - return { - ...acc, - [key]: schema2 - }; - }, {}); - return z.object(zodFields); -} -function getSchema(config2) { - const tables = (0, db_exports.getAuthTables)(config2); - const schema2 = {}; - for (const key in tables) { - const table = tables[key]; - const fields = table.fields; - const actualFields = {}; - Object.entries(fields).forEach(([key$1, field]) => { - actualFields[field.fieldName || key$1] = field; - if (field.references) { - const refTable = tables[field.references.model]; - if (refTable) actualFields[field.fieldName || key$1].references = { - ...field.references, - model: refTable.modelName, - field: field.references.field - }; - } - }); - if (schema2[table.modelName]) { - schema2[table.modelName].fields = { - ...schema2[table.modelName].fields, - ...actualFields - }; - continue; - } - schema2[table.modelName] = { - fields: actualFields, - order: table.order || Infinity - }; - } - return schema2; -} -function getKyselyDatabaseType(db2) { - if (!db2) return null; - if ("dialect" in db2) return getKyselyDatabaseType(db2.dialect); - if ("createDriver" in db2) { - if (db2 instanceof SqliteDialect) return "sqlite"; - if (db2 instanceof MysqlDialect) return "mysql"; - if (db2 instanceof PostgresDialect) return "postgres"; - if (db2 instanceof MssqlDialect) return "mssql"; - } - if ("aggregate" in db2) return "sqlite"; - if ("getConnection" in db2) return "mysql"; - if ("connect" in db2) return "postgres"; - if ("fileControl" in db2) return "sqlite"; - if ("open" in db2 && "close" in db2 && "prepare" in db2) return "sqlite"; - return null; -} -const createKyselyAdapter = async (config2) => { - const db2 = config2.database; - if (!db2) return { - kysely: null, - databaseType: null, - transaction: void 0 - }; - if ("db" in db2) return { - kysely: db2.db, - databaseType: db2.type, - transaction: db2.transaction - }; - if ("dialect" in db2) return { - kysely: new Kysely({ dialect: db2.dialect }), - databaseType: db2.type, - transaction: db2.transaction - }; - let dialect = void 0; - const databaseType = getKyselyDatabaseType(db2); - if ("createDriver" in db2) dialect = db2; - if ("aggregate" in db2 && !("createSession" in db2)) dialect = new SqliteDialect({ database: db2 }); - if ("getConnection" in db2) dialect = new MysqlDialect(db2); - if ("connect" in db2) dialect = new PostgresDialect({ pool: db2 }); - if ("fileControl" in db2) { - const { BunSqliteDialect } = await import("./bun-sqlite-dialect.js"); - dialect = new BunSqliteDialect({ database: db2 }); - } - if ("createSession" in db2) { - let DatabaseSync = void 0; - try { - const nodeSqlite = "node:sqlite"; - ({ DatabaseSync } = await import( - /* @vite-ignore */ - /* webpackIgnore: true */ - nodeSqlite - )); - } catch (error2) { - if (error2 !== null && typeof error2 === "object" && "code" in error2 && error2.code !== "ERR_UNKNOWN_BUILTIN_MODULE") throw error2; - } - if (DatabaseSync && db2 instanceof DatabaseSync) { - const { NodeSqliteDialect } = await import("./node-sqlite-dialect.js"); - dialect = new NodeSqliteDialect({ database: db2 }); - } - } - return { - kysely: dialect ? new Kysely({ dialect }) : null, - databaseType, - transaction: void 0 - }; -}; -const map = { - postgres: { - string: [ - "character varying", - "varchar", - "text", - "uuid" - ], - number: [ - "int4", - "integer", - "bigint", - "smallint", - "numeric", - "real", - "double precision" - ], - boolean: ["bool", "boolean"], - date: [ - "timestamptz", - "timestamp", - "date" - ], - json: ["json", "jsonb"] - }, - mysql: { - string: [ - "varchar", - "text", - "uuid" - ], - number: [ - "integer", - "int", - "bigint", - "smallint", - "decimal", - "float", - "double" - ], - boolean: ["boolean", "tinyint"], - date: [ - "timestamp", - "datetime", - "date" - ], - json: ["json"] - }, - sqlite: { - string: ["TEXT"], - number: ["INTEGER", "REAL"], - boolean: ["INTEGER", "BOOLEAN"], - date: ["DATE", "INTEGER"], - json: ["TEXT"] - }, - mssql: { - string: [ - "varchar", - "nvarchar", - "uniqueidentifier" - ], - number: [ - "int", - "bigint", - "smallint", - "decimal", - "float", - "double" - ], - boolean: ["bit", "smallint"], - date: [ - "datetime2", - "date", - "datetime" - ], - json: ["varchar", "nvarchar"] - } -}; -function matchType(columnDataType, fieldType, dbType) { - function normalize(type) { - return type.toLowerCase().split("(")[0].trim(); - } - if (fieldType === "string[]" || fieldType === "number[]") return columnDataType.toLowerCase().includes("json"); - const types2 = map[dbType]; - return (Array.isArray(fieldType) ? types2["string"].map((t) => t.toLowerCase()) : types2[fieldType].map((t) => t.toLowerCase())).includes(normalize(columnDataType)); -} -async function getPostgresSchema(db2) { - try { - const result = await sql`SHOW search_path`.execute(db2); - if (result.rows[0]?.search_path) return result.rows[0].search_path.split(",").map((s) => s.trim()).map((s) => s.replace(/^["']|["']$/g, "")).filter((s) => !s.startsWith("$"))[0] || "public"; - } catch { - } - return "public"; -} -async function getMigrations(config2) { - const betterAuthSchema = getSchema(config2); - const logger$1 = createLogger(config2.logger); - let { kysely: db2, databaseType: dbType } = await createKyselyAdapter(config2); - if (!dbType) { - logger$1.warn("Could not determine database type, defaulting to sqlite. Please provide a type in the database options to avoid this."); - dbType = "sqlite"; - } - if (!db2) { - logger$1.error("Only kysely adapter is supported for migrations. You can use `generate` command to generate the schema, if you're using a different adapter."); - process.exit(1); - } - let currentSchema = "public"; - if (dbType === "postgres") { - currentSchema = await getPostgresSchema(db2); - logger$1.debug(`PostgreSQL migration: Using schema '${currentSchema}' (from search_path)`); - try { - if (!(await sql` - SELECT schema_name - FROM information_schema.schemata - WHERE schema_name = ${currentSchema} - `.execute(db2)).rows[0]) logger$1.warn(`Schema '${currentSchema}' does not exist. Tables will be inspected from available schemas. Consider creating the schema first or checking your database configuration.`); - } catch (error2) { - logger$1.debug(`Could not verify schema existence: ${error2 instanceof Error ? error2.message : String(error2)}`); - } - } - const allTableMetadata = await db2.introspection.getTables(); - let tableMetadata = allTableMetadata; - if (dbType === "postgres") try { - const tablesInSchema = await sql` - SELECT table_name - FROM information_schema.tables - WHERE table_schema = ${currentSchema} - AND table_type = 'BASE TABLE' - `.execute(db2); - const tableNamesInSchema = new Set(tablesInSchema.rows.map((row) => row.table_name)); - tableMetadata = allTableMetadata.filter((table) => table.schema === currentSchema && tableNamesInSchema.has(table.name)); - logger$1.debug(`Found ${tableMetadata.length} table(s) in schema '${currentSchema}': ${tableMetadata.map((t) => t.name).join(", ") || "(none)"}`); - } catch (error2) { - logger$1.warn(`Could not filter tables by schema. Using all discovered tables. Error: ${error2 instanceof Error ? error2.message : String(error2)}`); - } - const toBeCreated = []; - const toBeAdded = []; - for (const [key, value] of Object.entries(betterAuthSchema)) { - const table = tableMetadata.find((t) => t.name === key); - if (!table) { - const tIndex = toBeCreated.findIndex((t) => t.table === key); - const tableData = { - table: key, - fields: value.fields, - order: value.order || Infinity - }; - const insertIndex = toBeCreated.findIndex((t) => (t.order || Infinity) > tableData.order); - if (insertIndex === -1) if (tIndex === -1) toBeCreated.push(tableData); - else toBeCreated[tIndex].fields = { - ...toBeCreated[tIndex].fields, - ...value.fields - }; - else toBeCreated.splice(insertIndex, 0, tableData); - continue; - } - const toBeAddedFields = {}; - for (const [fieldName, field] of Object.entries(value.fields)) { - const column = table.columns.find((c) => c.name === fieldName); - if (!column) { - toBeAddedFields[fieldName] = field; - continue; - } - if (matchType(column.dataType, field.type, dbType)) continue; - else logger$1.warn(`Field ${fieldName} in table ${key} has a different type in the database. Expected ${field.type} but got ${column.dataType}.`); - } - if (Object.keys(toBeAddedFields).length > 0) toBeAdded.push({ - table: key, - fields: toBeAddedFields, - order: value.order || Infinity - }); - } - const migrations = []; - const useUUIDs = config2.advanced?.database?.generateId === "uuid"; - const useNumberId = config2.advanced?.database?.useNumberId || config2.advanced?.database?.generateId === "serial"; - function getType(field, fieldName) { - const type = field.type; - const provider = dbType || "sqlite"; - const typeMap = { - string: { - sqlite: "text", - postgres: "text", - mysql: field.unique ? "varchar(255)" : field.references ? "varchar(36)" : field.sortable ? "varchar(255)" : field.index ? "varchar(255)" : "text", - mssql: field.unique || field.sortable ? "varchar(255)" : field.references ? "varchar(36)" : "varchar(8000)" - }, - boolean: { - sqlite: "integer", - postgres: "boolean", - mysql: "boolean", - mssql: "smallint" - }, - number: { - sqlite: field.bigint ? "bigint" : "integer", - postgres: field.bigint ? "bigint" : "integer", - mysql: field.bigint ? "bigint" : "integer", - mssql: field.bigint ? "bigint" : "integer" - }, - date: { - sqlite: "date", - postgres: "timestamptz", - mysql: "timestamp(3)", - mssql: sql`datetime2(3)` - }, - json: { - sqlite: "text", - postgres: "jsonb", - mysql: "json", - mssql: "varchar(8000)" - }, - id: { - postgres: useNumberId ? sql`integer GENERATED BY DEFAULT AS IDENTITY` : useUUIDs ? "uuid" : "text", - mysql: useNumberId ? "integer" : useUUIDs ? "varchar(36)" : "varchar(36)", - mssql: useNumberId ? "integer" : useUUIDs ? "varchar(36)" : "varchar(36)", - sqlite: useNumberId ? "integer" : "text" - }, - foreignKeyId: { - postgres: useNumberId ? "integer" : useUUIDs ? "uuid" : "text", - mysql: useNumberId ? "integer" : useUUIDs ? "varchar(36)" : "varchar(36)", - mssql: useNumberId ? "integer" : useUUIDs ? "varchar(36)" : "varchar(36)", - sqlite: useNumberId ? "integer" : "text" - }, - "string[]": { - sqlite: "text", - postgres: "jsonb", - mysql: "json", - mssql: "varchar(8000)" - }, - "number[]": { - sqlite: "text", - postgres: "jsonb", - mysql: "json", - mssql: "varchar(8000)" - } - }; - if (fieldName === "id" || field.references?.field === "id") { - if (fieldName === "id") return typeMap.id[provider]; - return typeMap.foreignKeyId[provider]; - } - if (Array.isArray(type)) return "text"; - if (!(type in typeMap)) throw new Error(`Unsupported field type '${String(type)}' for field '${fieldName}'. Allowed types are: string, number, boolean, date, string[], number[]. If you need to store structured data, store it as a JSON string (type: "string") or split it into primitive fields. See https://better-auth.com/docs/advanced/schema#additional-fields`); - return typeMap[type][provider]; - } - const getModelName = initGetModelName({ - schema: getAuthTables(config2), - usePlural: false - }); - const getFieldName = initGetFieldName({ - schema: getAuthTables(config2), - usePlural: false - }); - function getReferencePath(model, field) { - try { - return `${getModelName(model)}.${getFieldName({ - model, - field - })}`; - } catch { - return `${model}.${field}`; - } - } - if (toBeAdded.length) for (const table of toBeAdded) for (const [fieldName, field] of Object.entries(table.fields)) { - const type = getType(field, fieldName); - const builder = db2.schema.alterTable(table.table); - if (field.index) { - const index = db2.schema.alterTable(table.table).addIndex(`${table.table}_${fieldName}_idx`); - migrations.push(index); - } - const built = builder.addColumn(fieldName, type, (col) => { - col = field.required !== false ? col.notNull() : col; - if (field.references) col = col.references(getReferencePath(field.references.model, field.references.field)).onDelete(field.references.onDelete || "cascade"); - if (field.unique) col = col.unique(); - if (field.type === "date" && typeof field.defaultValue === "function" && (dbType === "postgres" || dbType === "mysql" || dbType === "mssql")) if (dbType === "mysql") col = col.defaultTo(sql`CURRENT_TIMESTAMP(3)`); - else col = col.defaultTo(sql`CURRENT_TIMESTAMP`); - return col; - }); - migrations.push(built); - } - const toBeIndexed = []; - if (config2.advanced?.database?.useNumberId) logger$1.warn("`useNumberId` is deprecated. Please use `generateId` with `serial` instead."); - if (toBeCreated.length) for (const table of toBeCreated) { - const idType = getType({ type: useNumberId ? "number" : "string" }, "id"); - let dbT = db2.schema.createTable(table.table).addColumn("id", idType, (col) => { - if (useNumberId) { - if (dbType === "postgres") return col.primaryKey().notNull(); - else if (dbType === "sqlite") return col.primaryKey().notNull(); - else if (dbType === "mssql") return col.identity().primaryKey().notNull(); - return col.autoIncrement().primaryKey().notNull(); - } - if (useUUIDs) { - if (dbType === "postgres") return col.primaryKey().defaultTo(sql`pg_catalog.gen_random_uuid()`).notNull(); - return col.primaryKey().notNull(); - } - return col.primaryKey().notNull(); - }); - for (const [fieldName, field] of Object.entries(table.fields)) { - const type = getType(field, fieldName); - dbT = dbT.addColumn(fieldName, type, (col) => { - col = field.required !== false ? col.notNull() : col; - if (field.references) col = col.references(getReferencePath(field.references.model, field.references.field)).onDelete(field.references.onDelete || "cascade"); - if (field.unique) col = col.unique(); - if (field.type === "date" && typeof field.defaultValue === "function" && (dbType === "postgres" || dbType === "mysql" || dbType === "mssql")) if (dbType === "mysql") col = col.defaultTo(sql`CURRENT_TIMESTAMP(3)`); - else col = col.defaultTo(sql`CURRENT_TIMESTAMP`); - return col; - }); - if (field.index) { - const builder = db2.schema.createIndex(`${table.table}_${fieldName}_${field.unique ? "uidx" : "idx"}`).on(table.table).columns([fieldName]); - toBeIndexed.push(field.unique ? builder.unique() : builder); - } - } - migrations.push(dbT); - } - if (toBeIndexed.length) for (const index of toBeIndexed) migrations.push(index); - async function runMigrations() { - for (const migration of migrations) await migration.execute(); - } - async function compileMigrations() { - return migrations.map((m) => m.compile().sql).join(";\n\n") + ";"; - } - return { - toBeCreated, - toBeAdded, - runMigrations, - compileMigrations - }; -} -var db_exports = /* @__PURE__ */ __export({ - convertFromDB: () => convertFromDB, - convertToDB: () => convertToDB, - createFieldAttribute: () => createFieldAttribute, - createInternalAdapter: () => createInternalAdapter, - getAdapter: () => getAdapter, - getBaseAdapter: () => getBaseAdapter, - getMigrations: () => getMigrations, - getSchema: () => getSchema, - getWithHooks: () => getWithHooks, - matchType: () => matchType, - mergeSchema: () => mergeSchema, - parseAccountInput: () => parseAccountInput, - parseAccountOutput: () => parseAccountOutput, - parseAdditionalUserInput: () => parseAdditionalUserInput, - parseInputData: () => parseInputData, - parseSessionInput: () => parseSessionInput, - parseSessionOutput: () => parseSessionOutput, - parseUserInput: () => parseUserInput, - parseUserOutput: () => parseUserOutput, - toZodSchema: () => toZodSchema -}); -__reExport(db_exports, import___better_auth_core_db); -async function signJWT(payload, secret, expiresIn = 3600) { - return await new SignJWT(payload).setProtectedHeader({ alg: "HS256" }).setIssuedAt().setExpirationTime(Math.floor(Date.now() / 1e3) + expiresIn).sign(new TextEncoder().encode(secret)); -} -async function verifyJWT(token, secret) { - try { - return (await jwtVerify(token, new TextEncoder().encode(secret))).payload; - } catch { - return null; - } -} -const info = new Uint8Array([ - 66, - 101, - 116, - 116, - 101, - 114, - 65, - 117, - 116, - 104, - 46, - 106, - 115, - 32, - 71, - 101, - 110, - 101, - 114, - 97, - 116, - 101, - 100, - 32, - 69, - 110, - 99, - 114, - 121, - 112, - 116, - 105, - 111, - 110, - 32, - 75, - 101, - 121 -]); -const now = () => Date.now() / 1e3 | 0; -const alg = "dir"; -const enc = "A256CBC-HS512"; -async function symmetricEncodeJWT(payload, secret, salt, expiresIn = 3600) { - const encryptionSecret = hkdf(sha256, new TextEncoder().encode(secret), new TextEncoder().encode(salt), info, 64); - const thumbprint = await calculateJwkThumbprint({ - kty: "oct", - k: base64url.encode(encryptionSecret) - }, "sha256"); - return await new EncryptJWT(payload).setProtectedHeader({ - alg, - enc, - kid: thumbprint - }).setIssuedAt().setExpirationTime(now() + expiresIn).setJti(crypto.randomUUID()).encrypt(encryptionSecret); -} -async function symmetricDecodeJWT(token, secret, salt) { - if (!token) return null; - try { - const { payload } = await jwtDecrypt(token, async ({ kid }) => { - const encryptionSecret = hkdf(sha256, new TextEncoder().encode(secret), new TextEncoder().encode(salt), info, 64); - if (kid === void 0) return encryptionSecret; - if (kid === await calculateJwkThumbprint({ - kty: "oct", - k: base64url.encode(encryptionSecret) - }, "sha256")) return encryptionSecret; - throw new Error("no matching decryption secret"); - }, { - clockTolerance: 15, - keyManagementAlgorithms: [alg], - contentEncryptionAlgorithms: [enc, "A256GCM"] - }); - return payload; - } catch { - return null; - } -} -function constantTimeEqual(a, b) { - if (typeof a === "string") a = new TextEncoder().encode(a); - if (typeof b === "string") b = new TextEncoder().encode(b); - const aBuffer = new Uint8Array(a); - const bBuffer = new Uint8Array(b); - let c = aBuffer.length ^ bBuffer.length; - const length = Math.max(aBuffer.length, bBuffer.length); - for (let i = 0; i < length; i++) c |= (i < aBuffer.length ? aBuffer[i] : 0) ^ (i < bBuffer.length ? bBuffer[i] : 0); - return c === 0; -} -const config = { - N: 16384, - r: 16, - p: 1, - dkLen: 64 -}; -async function generateKey(password, salt) { - return await scryptAsync(password.normalize("NFKC"), salt, { - N: config.N, - p: config.p, - r: config.r, - dkLen: config.dkLen, - maxmem: 128 * config.N * config.r * 2 - }); -} -const hashPassword = async (password) => { - const salt = hex.encode(crypto.getRandomValues(new Uint8Array(16))); - const key = await generateKey(password, salt); - return `${salt}:${hex.encode(key)}`; -}; -const verifyPassword$1 = async ({ hash, password }) => { - const [salt, key] = hash.split(":"); - if (!salt || !key) throw new BetterAuthError("Invalid password hash"); - return constantTimeEqual(await generateKey(password, salt), hexToBytes(key)); -}; -const generateRandomString = createRandomStringGenerator("a-z", "0-9", "A-Z", "-_"); -const symmetricEncrypt = async ({ key, data }) => { - const keyAsBytes = await createHash("SHA-256").digest(key); - const dataAsBytes = utf8ToBytes(data); - return bytesToHex(managedNonce(xchacha20poly1305)(new Uint8Array(keyAsBytes)).encrypt(dataAsBytes)); -}; -const symmetricDecrypt = async ({ key, data }) => { - const keyAsBytes = await createHash("SHA-256").digest(key); - const dataAsBytes = hexToBytes$1(data); - const chacha = managedNonce(xchacha20poly1305)(new Uint8Array(keyAsBytes)); - return new TextDecoder().decode(chacha.decrypt(dataAsBytes)); -}; -const ALLOWED_COOKIE_SIZE = 4096; -const ESTIMATED_EMPTY_COOKIE_SIZE = 200; -const CHUNK_SIZE = ALLOWED_COOKIE_SIZE - ESTIMATED_EMPTY_COOKIE_SIZE; -function parseCookiesFromContext(ctx) { - const cookieHeader = ctx.headers?.get("cookie"); - if (!cookieHeader) return {}; - const cookies = {}; - const pairs = cookieHeader.split("; "); - for (const pair of pairs) { - const [name, ...valueParts] = pair.split("="); - if (name && valueParts.length > 0) cookies[name] = valueParts.join("="); - } - return cookies; -} -function getChunkIndex(cookieName) { - const parts = cookieName.split("."); - const lastPart = parts[parts.length - 1]; - const index = parseInt(lastPart || "0", 10); - return isNaN(index) ? 0 : index; -} -function readExistingChunks(cookieName, ctx) { - const chunks = {}; - const cookies = parseCookiesFromContext(ctx); - for (const [name, value] of Object.entries(cookies)) if (name.startsWith(cookieName)) chunks[name] = value; - return chunks; -} -function joinChunks(chunks) { - return Object.keys(chunks).sort((a, b) => { - return getChunkIndex(a) - getChunkIndex(b); - }).map((key) => chunks[key]).join(""); -} -function chunkCookie(storeName, cookie, chunks, logger2) { - const chunkCount = Math.ceil(cookie.value.length / CHUNK_SIZE); - if (chunkCount === 1) { - chunks[cookie.name] = cookie.value; - return [cookie]; - } - const cookies = []; - for (let i = 0; i < chunkCount; i++) { - const name = `${cookie.name}.${i}`; - const start = i * CHUNK_SIZE; - const value = cookie.value.substring(start, start + CHUNK_SIZE); - cookies.push({ - ...cookie, - name, - value - }); - chunks[name] = value; - } - logger2.debug(`CHUNKING_${storeName.toUpperCase()}_COOKIE`, { - message: `${storeName} cookie exceeds allowed ${ALLOWED_COOKIE_SIZE} bytes.`, - emptyCookieSize: ESTIMATED_EMPTY_COOKIE_SIZE, - valueSize: cookie.value.length, - chunkCount, - chunks: cookies.map((c) => c.value.length + ESTIMATED_EMPTY_COOKIE_SIZE) - }); - return cookies; -} -function getCleanCookies(chunks, cookieOptions) { - const cleanedChunks = {}; - for (const name in chunks) cleanedChunks[name] = { - name, - value: "", - attributes: { - ...cookieOptions, - maxAge: 0 - } - }; - return cleanedChunks; -} -const storeFactory = (storeName) => (cookieName, cookieOptions, ctx) => { - const chunks = readExistingChunks(cookieName, ctx); - const logger2 = ctx.context.logger; - return { - getValue() { - return joinChunks(chunks); - }, - hasChunks() { - return Object.keys(chunks).length > 0; - }, - chunk(value, options) { - const cleanedChunks = getCleanCookies(chunks, cookieOptions); - for (const name in chunks) delete chunks[name]; - const cookies = cleanedChunks; - const chunked = chunkCookie(storeName, { - name: cookieName, - value, - attributes: { - ...cookieOptions, - ...options - } - }, chunks, logger2); - for (const chunk of chunked) cookies[chunk.name] = chunk; - return Object.values(cookies); - }, - clean() { - const cleanedChunks = getCleanCookies(chunks, cookieOptions); - for (const name in chunks) delete chunks[name]; - return Object.values(cleanedChunks); - }, - setCookies(cookies) { - for (const cookie of cookies) ctx.setCookie(cookie.name, cookie.value, cookie.attributes); - } - }; -}; -const createSessionStore = storeFactory("Session"); -const createAccountStore = storeFactory("Account"); -function getChunkedCookie(ctx, cookieName) { - const value = ctx.getCookie(cookieName); - if (value) return value; - const chunks = []; - const cookieHeader = ctx.headers?.get("cookie"); - if (!cookieHeader) return null; - const cookies = {}; - const pairs = cookieHeader.split("; "); - for (const pair of pairs) { - const [name, ...valueParts] = pair.split("="); - if (name && valueParts.length > 0) cookies[name] = valueParts.join("="); - } - for (const [name, val] of Object.entries(cookies)) if (name.startsWith(cookieName + ".")) { - const indexStr = name.split(".").at(-1); - const index = parseInt(indexStr || "0", 10); - if (!isNaN(index)) chunks.push({ - index, - value: val - }); - } - if (chunks.length > 0) { - chunks.sort((a, b) => a.index - b.index); - return chunks.map((c) => c.value).join(""); - } - return null; -} -async function setAccountCookie(c, accountData) { - const accountDataCookie = c.context.authCookies.accountData; - const options = { - maxAge: 300, - ...accountDataCookie.attributes - }; - const data = await symmetricEncodeJWT(accountData, c.context.secret, "better-auth-account", options.maxAge); - if (data.length > ALLOWED_COOKIE_SIZE) { - const accountStore = createAccountStore(accountDataCookie.name, options, c); - const cookies = accountStore.chunk(data, options); - accountStore.setCookies(cookies); - } else { - const accountStore = createAccountStore(accountDataCookie.name, options, c); - if (accountStore.hasChunks()) { - const cleanCookies = accountStore.clean(); - accountStore.setCookies(cleanCookies); - } - c.setCookie(accountDataCookie.name, data, options); - } -} -async function getAccountCookie(c) { - const accountCookie = getChunkedCookie(c, c.context.authCookies.accountData.name); - if (accountCookie) { - const accountData = safeJSONParse(await symmetricDecodeJWT(accountCookie, c.context.secret, "better-auth-account")); - if (accountData) return accountData; - } - return null; -} -const getSessionQuerySchema = z.optional(z.object({ - disableCookieCache: z.coerce.boolean().meta({ description: "Disable cookie cache and fetch session from database" }).optional(), - disableRefresh: z.coerce.boolean().meta({ description: "Disable session refresh. Useful for checking session status, without updating the session" }).optional() -})); -function isPromise(obj) { - return !!obj && (typeof obj === "object" || typeof obj === "function") && typeof obj.then === "function"; -} -const SEC = 1e3; -const MIN = SEC * 60; -const HOUR = MIN * 60; -const DAY = HOUR * 24; -const WEEK = DAY * 7; -const MONTH = DAY * 30; -const YEAR = DAY * 365.25; -const REGEX = /^(\+|\-)? ?(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|months?|mo|years?|yrs?|y)(?: (ago|from now))?$/i; -function parse(value) { - const match = REGEX.exec(value); - if (!match || match[4] && match[1]) throw new TypeError(`Invalid time string format: "${value}". Use formats like "7d", "30m", "1 hour", etc.`); - const n = parseFloat(match[2]); - const unit = match[3].toLowerCase(); - let result; - switch (unit) { - case "years": - case "year": - case "yrs": - case "yr": - case "y": - result = n * YEAR; - break; - case "months": - case "month": - case "mo": - result = n * MONTH; - break; - case "weeks": - case "week": - case "w": - result = n * WEEK; - break; - case "days": - case "day": - case "d": - result = n * DAY; - break; - case "hours": - case "hour": - case "hrs": - case "hr": - case "h": - result = n * HOUR; - break; - case "minutes": - case "minute": - case "mins": - case "min": - case "m": - result = n * MIN; - break; - case "seconds": - case "second": - case "secs": - case "sec": - case "s": - result = n * SEC; - break; - default: - throw new TypeError(`Unknown time unit: "${unit}"`); - } - if (match[1] === "-" || match[4] === "ago") return -result; - return result; -} -function ms(value) { - return parse(value); -} -function sec(value) { - return Math.round(parse(value) / 1e3); -} -const SECURE_COOKIE_PREFIX = "__Secure-"; -function splitSetCookieHeader(setCookie) { - if (!setCookie) return []; - const result = []; - let current = ""; - let i = 0; - while (i < setCookie.length) { - const c = setCookie[i]; - if (c === ",") { - const lower = current.toLowerCase(); - if (lower.includes("expires=") && !lower.includes("gmt")) { - current += c; - i++; - } else { - const trimmed$1 = current.trim(); - if (trimmed$1) result.push(trimmed$1); - current = ""; - i++; - if (i < setCookie.length && setCookie[i] === " ") i++; - } - continue; - } - current += c; - i++; - } - const trimmed = current.trim(); - if (trimmed) result.push(trimmed); - return result; -} -function parseSetCookieHeader(setCookie) { - const cookies = /* @__PURE__ */ new Map(); - splitSetCookieHeader(setCookie).forEach((cookieString) => { - const [nameValue, ...attributes] = cookieString.split(";").map((part) => part.trim()); - const [name, ...valueParts] = (nameValue || "").split("="); - const value = valueParts.join("="); - if (!name || value === void 0) return; - const attrObj = { value }; - attributes.forEach((attribute) => { - const [attrName, ...attrValueParts] = attribute.split("="); - const attrValue = attrValueParts.join("="); - const normalizedAttrName = attrName.trim().toLowerCase(); - switch (normalizedAttrName) { - case "max-age": - attrObj["max-age"] = attrValue ? parseInt(attrValue.trim(), 10) : void 0; - break; - case "expires": - attrObj.expires = attrValue ? new Date(attrValue.trim()) : void 0; - break; - case "domain": - attrObj.domain = attrValue ? attrValue.trim() : void 0; - break; - case "path": - attrObj.path = attrValue ? attrValue.trim() : void 0; - break; - case "secure": - attrObj.secure = true; - break; - case "httponly": - attrObj.httponly = true; - break; - case "samesite": - attrObj.samesite = attrValue ? attrValue.trim().toLowerCase() : void 0; - break; - default: - attrObj[normalizedAttrName] = attrValue ? attrValue.trim() : true; - break; - } - }); - cookies.set(name, attrObj); - }); - return cookies; -} -function createCookieGetter(options) { - const secureCookiePrefix = (options.advanced?.useSecureCookies !== void 0 ? options.advanced?.useSecureCookies : options.baseURL ? options.baseURL.startsWith("https://") ? true : false : isProduction) ? SECURE_COOKIE_PREFIX : ""; - const crossSubdomainEnabled = !!options.advanced?.crossSubDomainCookies?.enabled; - const domain = crossSubdomainEnabled ? options.advanced?.crossSubDomainCookies?.domain || (options.baseURL ? new URL(options.baseURL).hostname : void 0) : void 0; - if (crossSubdomainEnabled && !domain) throw new BetterAuthError("baseURL is required when crossSubdomainCookies are enabled"); - function createCookie(cookieName, overrideAttributes = {}) { - const prefix = options.advanced?.cookiePrefix || "better-auth"; - const name = options.advanced?.cookies?.[cookieName]?.name || `${prefix}.${cookieName}`; - const attributes = options.advanced?.cookies?.[cookieName]?.attributes; - return { - name: `${secureCookiePrefix}${name}`, - attributes: { - secure: !!secureCookiePrefix, - sameSite: "lax", - path: "/", - httpOnly: true, - ...crossSubdomainEnabled ? { domain } : {}, - ...options.advanced?.defaultCookieAttributes, - ...overrideAttributes, - ...attributes - } - }; - } - return createCookie; -} -function getCookies(options) { - const createCookie = createCookieGetter(options); - const sessionToken = createCookie("session_token", { maxAge: options.session?.expiresIn || sec("7d") }); - const sessionData = createCookie("session_data", { maxAge: options.session?.cookieCache?.maxAge || 300 }); - const accountData = createCookie("account_data", { maxAge: options.session?.cookieCache?.maxAge || 300 }); - const dontRememberToken = createCookie("dont_remember"); - return { - sessionToken: { - name: sessionToken.name, - attributes: sessionToken.attributes - }, - sessionData: { - name: sessionData.name, - attributes: sessionData.attributes - }, - dontRememberToken: { - name: dontRememberToken.name, - attributes: dontRememberToken.attributes - }, - accountData: { - name: accountData.name, - attributes: accountData.attributes - } - }; -} -async function setCookieCache(ctx, session, dontRememberMe) { - if (!ctx.context.options.session?.cookieCache?.enabled) return; - const filteredSession = filterOutputFields(session.session, ctx.context.options.session?.additionalFields); - const filteredUser = parseUserOutput(ctx.context.options, session.user); - const versionConfig = ctx.context.options.session?.cookieCache?.version; - let version = "1"; - if (versionConfig) { - if (typeof versionConfig === "string") version = versionConfig; - else if (typeof versionConfig === "function") { - const result = versionConfig(session.session, session.user); - version = isPromise(result) ? await result : result; - } - } - const sessionData = { - session: filteredSession, - user: filteredUser, - updatedAt: Date.now(), - version - }; - const options = { - ...ctx.context.authCookies.sessionData.attributes, - maxAge: dontRememberMe ? void 0 : ctx.context.authCookies.sessionData.attributes.maxAge - }; - const expiresAtDate = getDate(options.maxAge || 60, "sec").getTime(); - const strategy = ctx.context.options.session?.cookieCache?.strategy || "compact"; - let data; - if (strategy === "jwe") data = await symmetricEncodeJWT(sessionData, ctx.context.secret, "better-auth-session", options.maxAge || 300); - else if (strategy === "jwt") data = await signJWT(sessionData, ctx.context.secret, options.maxAge || 300); - else data = base64Url.encode(JSON.stringify({ - session: sessionData, - expiresAt: expiresAtDate, - signature: await createHMAC("SHA-256", "base64urlnopad").sign(ctx.context.secret, JSON.stringify({ - ...sessionData, - expiresAt: expiresAtDate - })) - }), { padding: false }); - if (data.length > 4093) { - const sessionStore = createSessionStore(ctx.context.authCookies.sessionData.name, options, ctx); - const cookies = sessionStore.chunk(data, options); - sessionStore.setCookies(cookies); - } else { - const sessionStore = createSessionStore(ctx.context.authCookies.sessionData.name, options, ctx); - if (sessionStore.hasChunks()) { - const cleanCookies = sessionStore.clean(); - sessionStore.setCookies(cleanCookies); - } - ctx.setCookie(ctx.context.authCookies.sessionData.name, data, options); - } - if (ctx.context.options.account?.storeAccountCookie) { - const accountData = await getAccountCookie(ctx); - if (accountData) await setAccountCookie(ctx, accountData); - } -} -async function setSessionCookie(ctx, session, dontRememberMe, overrides) { - const dontRememberMeCookie = await ctx.getSignedCookie(ctx.context.authCookies.dontRememberToken.name, ctx.context.secret); - dontRememberMe = dontRememberMe !== void 0 ? dontRememberMe : !!dontRememberMeCookie; - const options = ctx.context.authCookies.sessionToken.attributes; - const maxAge = dontRememberMe ? void 0 : ctx.context.sessionConfig.expiresIn; - await ctx.setSignedCookie(ctx.context.authCookies.sessionToken.name, session.session.token, ctx.context.secret, { - ...options, - maxAge, - ...overrides - }); - if (dontRememberMe) await ctx.setSignedCookie(ctx.context.authCookies.dontRememberToken.name, "true", ctx.context.secret, ctx.context.authCookies.dontRememberToken.attributes); - await setCookieCache(ctx, session, dontRememberMe); - ctx.context.setNewSession(session); -} -function expireCookie(ctx, cookie) { - ctx.setCookie(cookie.name, "", { - ...cookie.attributes, - maxAge: 0 - }); -} -function deleteSessionCookie(ctx, skipDontRememberMe) { - expireCookie(ctx, ctx.context.authCookies.sessionToken); - expireCookie(ctx, ctx.context.authCookies.sessionData); - if (ctx.context.options.account?.storeAccountCookie) { - expireCookie(ctx, ctx.context.authCookies.accountData); - const accountStore = createAccountStore(ctx.context.authCookies.accountData.name, ctx.context.authCookies.accountData.attributes, ctx); - const cleanCookies$1 = accountStore.clean(); - accountStore.setCookies(cleanCookies$1); - } - if (ctx.context.oauthConfig.storeStateStrategy === "cookie") expireCookie(ctx, ctx.context.createAuthCookie("oauth_state")); - const sessionStore = createSessionStore(ctx.context.authCookies.sessionData.name, ctx.context.authCookies.sessionData.attributes, ctx); - const cleanCookies = sessionStore.clean(); - sessionStore.setCookies(cleanCookies); - expireCookie(ctx, ctx.context.authCookies.dontRememberToken); -} -const getSession = () => createAuthEndpoint("/get-session", { - method: "GET", - operationId: "getSession", - query: getSessionQuerySchema, - requireHeaders: true, - metadata: { openapi: { - operationId: "getSession", - description: "Get the current session", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - nullable: true, - properties: { - session: { $ref: "#/components/schemas/Session" }, - user: { $ref: "#/components/schemas/User" } - }, - required: ["session", "user"] - } } } - } } - } } -}, async (ctx) => { - try { - const sessionCookieToken = await ctx.getSignedCookie(ctx.context.authCookies.sessionToken.name, ctx.context.secret); - if (!sessionCookieToken) return null; - const sessionDataCookie = getChunkedCookie(ctx, ctx.context.authCookies.sessionData.name); - let sessionDataPayload = null; - if (sessionDataCookie) { - const strategy = ctx.context.options.session?.cookieCache?.strategy || "compact"; - if (strategy === "jwe") { - const payload = await symmetricDecodeJWT(sessionDataCookie, ctx.context.secret, "better-auth-session"); - if (payload && payload.session && payload.user) sessionDataPayload = { - session: { - session: payload.session, - user: payload.user, - updatedAt: payload.updatedAt, - version: payload.version - }, - expiresAt: payload.exp ? payload.exp * 1e3 : Date.now() - }; - else { - expireCookie(ctx, ctx.context.authCookies.sessionData); - return ctx.json(null); - } - } else if (strategy === "jwt") { - const payload = await verifyJWT(sessionDataCookie, ctx.context.secret); - if (payload && payload.session && payload.user) sessionDataPayload = { - session: { - session: payload.session, - user: payload.user, - updatedAt: payload.updatedAt, - version: payload.version - }, - expiresAt: payload.exp ? payload.exp * 1e3 : Date.now() - }; - else { - expireCookie(ctx, ctx.context.authCookies.sessionData); - return ctx.json(null); - } - } else { - const parsed = safeJSONParse(binary.decode(base64Url.decode(sessionDataCookie))); - if (parsed) if (await createHMAC("SHA-256", "base64urlnopad").verify(ctx.context.secret, JSON.stringify({ - ...parsed.session, - expiresAt: parsed.expiresAt - }), parsed.signature)) sessionDataPayload = parsed; - else { - expireCookie(ctx, ctx.context.authCookies.sessionData); - return ctx.json(null); - } - } - } - const dontRememberMe = await ctx.getSignedCookie(ctx.context.authCookies.dontRememberToken.name, ctx.context.secret); - if (sessionDataPayload?.session && ctx.context.options.session?.cookieCache?.enabled && !ctx.query?.disableCookieCache) { - const session$1 = sessionDataPayload.session; - const versionConfig = ctx.context.options.session?.cookieCache?.version; - let expectedVersion = "1"; - if (versionConfig) { - if (typeof versionConfig === "string") expectedVersion = versionConfig; - else if (typeof versionConfig === "function") { - const result = versionConfig(session$1.session, session$1.user); - expectedVersion = result instanceof Promise ? await result : result; - } - } - if ((session$1.version || "1") !== expectedVersion) expireCookie(ctx, ctx.context.authCookies.sessionData); - else { - const cachedSessionExpiresAt = new Date(session$1.session.expiresAt); - if (sessionDataPayload.expiresAt < Date.now() || cachedSessionExpiresAt < /* @__PURE__ */ new Date()) expireCookie(ctx, ctx.context.authCookies.sessionData); - else { - const cookieRefreshCache = ctx.context.sessionConfig.cookieRefreshCache; - if (cookieRefreshCache === false) { - ctx.context.session = session$1; - const parsedSession$2 = parseSessionOutput(ctx.context.options, { - ...session$1.session, - expiresAt: new Date(session$1.session.expiresAt), - createdAt: new Date(session$1.session.createdAt), - updatedAt: new Date(session$1.session.updatedAt) - }); - const parsedUser$2 = parseUserOutput(ctx.context.options, { - ...session$1.user, - createdAt: new Date(session$1.user.createdAt), - updatedAt: new Date(session$1.user.updatedAt) - }); - return ctx.json({ - session: parsedSession$2, - user: parsedUser$2 - }); - } - if (sessionDataPayload.expiresAt - Date.now() < cookieRefreshCache.updateAge * 1e3) { - const newExpiresAt = getDate(ctx.context.options.session?.cookieCache?.maxAge || 300, "sec"); - const refreshedSession = { - session: { - ...session$1.session, - expiresAt: newExpiresAt - }, - user: session$1.user, - updatedAt: Date.now() - }; - await setCookieCache(ctx, refreshedSession, false); - const parsedRefreshedSession = parseSessionOutput(ctx.context.options, { - ...refreshedSession.session, - expiresAt: new Date(refreshedSession.session.expiresAt), - createdAt: new Date(refreshedSession.session.createdAt), - updatedAt: new Date(refreshedSession.session.updatedAt) - }); - const parsedRefreshedUser = parseUserOutput(ctx.context.options, { - ...refreshedSession.user, - createdAt: new Date(refreshedSession.user.createdAt), - updatedAt: new Date(refreshedSession.user.updatedAt) - }); - ctx.context.session = { - session: parsedRefreshedSession, - user: parsedRefreshedUser - }; - return ctx.json({ - session: parsedRefreshedSession, - user: parsedRefreshedUser - }); - } - const parsedSession$1 = parseSessionOutput(ctx.context.options, { - ...session$1.session, - expiresAt: new Date(session$1.session.expiresAt), - createdAt: new Date(session$1.session.createdAt), - updatedAt: new Date(session$1.session.updatedAt) - }); - const parsedUser$1 = parseUserOutput(ctx.context.options, { - ...session$1.user, - createdAt: new Date(session$1.user.createdAt), - updatedAt: new Date(session$1.user.updatedAt) - }); - ctx.context.session = { - session: parsedSession$1, - user: parsedUser$1 - }; - return ctx.json({ - session: parsedSession$1, - user: parsedUser$1 - }); - } - } - } - const session = await ctx.context.internalAdapter.findSession(sessionCookieToken); - ctx.context.session = session; - if (!session || session.session.expiresAt < /* @__PURE__ */ new Date()) { - deleteSessionCookie(ctx); - if (session) - await ctx.context.internalAdapter.deleteSession(session.session.token); - return ctx.json(null); - } - if (dontRememberMe || ctx.query?.disableRefresh) { - const parsedSession$1 = parseSessionOutput(ctx.context.options, session.session); - const parsedUser$1 = parseUserOutput(ctx.context.options, session.user); - return ctx.json({ - session: parsedSession$1, - user: parsedUser$1 - }); - } - const expiresIn = ctx.context.sessionConfig.expiresIn; - const updateAge = ctx.context.sessionConfig.updateAge; - if (session.session.expiresAt.valueOf() - expiresIn * 1e3 + updateAge * 1e3 <= Date.now() && (!ctx.query?.disableRefresh || !ctx.context.options.session?.disableSessionRefresh)) { - const updatedSession = await ctx.context.internalAdapter.updateSession(session.session.token, { - expiresAt: getDate(ctx.context.sessionConfig.expiresIn, "sec"), - updatedAt: /* @__PURE__ */ new Date() - }); - if (!updatedSession) { - deleteSessionCookie(ctx); - return ctx.json(null, { status: 401 }); - } - const maxAge = (updatedSession.expiresAt.valueOf() - Date.now()) / 1e3; - await setSessionCookie(ctx, { - session: updatedSession, - user: session.user - }, false, { maxAge }); - const parsedUpdatedSession = parseSessionOutput(ctx.context.options, updatedSession); - const parsedUser$1 = parseUserOutput(ctx.context.options, session.user); - return ctx.json({ - session: parsedUpdatedSession, - user: parsedUser$1 - }); - } - await setCookieCache(ctx, session, !!dontRememberMe); - const parsedSession = parseSessionOutput(ctx.context.options, session.session); - const parsedUser = parseUserOutput(ctx.context.options, session.user); - return ctx.json({ - session: parsedSession, - user: parsedUser - }); - } catch (error2) { - ctx.context.logger.error("INTERNAL_SERVER_ERROR", error2); - throw new APIError("INTERNAL_SERVER_ERROR", { message: BASE_ERROR_CODES.FAILED_TO_GET_SESSION }); - } -}); -const getSessionFromCtx = async (ctx, config2) => { - if (ctx.context.session) return ctx.context.session; - const session = await getSession()({ - ...ctx, - asResponse: false, - headers: ctx.headers, - returnHeaders: false, - returnStatus: false, - query: { - ...config2, - ...ctx.query - } - }).catch((e) => { - return null; - }); - ctx.context.session = session; - return session; -}; -const sessionMiddleware = createAuthMiddleware(async (ctx) => { - const session = await getSessionFromCtx(ctx); - if (!session?.session) throw new APIError("UNAUTHORIZED"); - return { session }; -}); -const sensitiveSessionMiddleware = createAuthMiddleware(async (ctx) => { - const session = await getSessionFromCtx(ctx, { disableCookieCache: true }); - if (!session?.session) throw new APIError("UNAUTHORIZED"); - return { session }; -}); -createAuthMiddleware(async (ctx) => { - const session = await getSessionFromCtx(ctx); - if (!session?.session && (ctx.request || ctx.headers)) throw new APIError("UNAUTHORIZED"); - return { session }; -}); -const freshSessionMiddleware = createAuthMiddleware(async (ctx) => { - const session = await getSessionFromCtx(ctx); - if (!session?.session) throw new APIError("UNAUTHORIZED"); - if (ctx.context.sessionConfig.freshAge === 0) return { session }; - const freshAge = ctx.context.sessionConfig.freshAge; - const lastUpdated = new Date(session.session.updatedAt || session.session.createdAt).getTime(); - if (!(Date.now() - lastUpdated < freshAge * 1e3)) throw new APIError("FORBIDDEN", { message: "Session is not fresh" }); - return { session }; -}); -const listSessions = () => createAuthEndpoint("/list-sessions", { - method: "GET", - operationId: "listUserSessions", - use: [sessionMiddleware], - requireHeaders: true, - metadata: { openapi: { - operationId: "listUserSessions", - description: "List all active sessions for the user", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "array", - items: { $ref: "#/components/schemas/Session" } - } } } - } } - } } -}, async (ctx) => { - try { - const activeSessions = (await ctx.context.internalAdapter.listSessions(ctx.context.session.user.id)).filter((session) => { - return session.expiresAt > /* @__PURE__ */ new Date(); - }); - return ctx.json(activeSessions.map((session) => parseSessionOutput(ctx.context.options, session))); - } catch (e) { - ctx.context.logger.error(e); - throw ctx.error("INTERNAL_SERVER_ERROR"); - } -}); -const revokeSession = createAuthEndpoint("/revoke-session", { - method: "POST", - body: z.object({ token: z.string().meta({ description: "The token to revoke" }) }), - use: [sensitiveSessionMiddleware], - requireHeaders: true, - metadata: { openapi: { - description: "Revoke a single session", - requestBody: { content: { "application/json": { schema: { - type: "object", - properties: { token: { - type: "string", - description: "The token to revoke" - } }, - required: ["token"] - } } } }, - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { status: { - type: "boolean", - description: "Indicates if the session was revoked successfully" - } }, - required: ["status"] - } } } - } } - } } -}, async (ctx) => { - const token = ctx.body.token; - if ((await ctx.context.internalAdapter.findSession(token))?.session.userId === ctx.context.session.user.id) try { - await ctx.context.internalAdapter.deleteSession(token); - } catch (error2) { - ctx.context.logger.error(error2 && typeof error2 === "object" && "name" in error2 ? error2.name : "", error2); - throw new APIError("INTERNAL_SERVER_ERROR"); - } - return ctx.json({ status: true }); -}); -const revokeSessions = createAuthEndpoint("/revoke-sessions", { - method: "POST", - use: [sensitiveSessionMiddleware], - requireHeaders: true, - metadata: { openapi: { - description: "Revoke all sessions for the user", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { status: { - type: "boolean", - description: "Indicates if all sessions were revoked successfully" - } }, - required: ["status"] - } } } - } } - } } -}, async (ctx) => { - try { - await ctx.context.internalAdapter.deleteSessions(ctx.context.session.user.id); - } catch (error2) { - ctx.context.logger.error(error2 && typeof error2 === "object" && "name" in error2 ? error2.name : "", error2); - throw new APIError("INTERNAL_SERVER_ERROR"); - } - return ctx.json({ status: true }); -}); -const revokeOtherSessions = createAuthEndpoint("/revoke-other-sessions", { - method: "POST", - requireHeaders: true, - use: [sensitiveSessionMiddleware], - metadata: { openapi: { - description: "Revoke all other sessions for the user except the current one", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { status: { - type: "boolean", - description: "Indicates if all other sessions were revoked successfully" - } }, - required: ["status"] - } } } - } } - } } -}, async (ctx) => { - const session = ctx.context.session; - if (!session.user) throw new APIError("UNAUTHORIZED"); - const otherSessions = (await ctx.context.internalAdapter.listSessions(session.user.id)).filter((session$1) => { - return session$1.expiresAt > /* @__PURE__ */ new Date(); - }).filter((session$1) => session$1.token !== ctx.context.session.session.token); - await Promise.all(otherSessions.map((session$1) => ctx.context.internalAdapter.deleteSession(session$1.token))); - return ctx.json({ status: true }); -}); -const stateDataSchema = z.looseObject({ - callbackURL: z.string(), - codeVerifier: z.string(), - errorURL: z.string().optional(), - newUserURL: z.string().optional(), - expiresAt: z.number(), - link: z.object({ - email: z.string(), - userId: z.coerce.string() - }).optional(), - requestSignUp: z.boolean().optional() -}); -var StateError = class extends BetterAuthError { - code; - details; - constructor(message, options) { - super(message, options); - this.code = options.code; - this.details = options.details; - } -}; -async function generateGenericState(c, stateData, settings) { - const state = generateRandomString(32); - if (c.context.oauthConfig.storeStateStrategy === "cookie") { - const encryptedData = await symmetricEncrypt({ - key: c.context.secret, - data: JSON.stringify(stateData) - }); - const stateCookie$1 = c.context.createAuthCookie("oauth_state", { maxAge: 600 }); - c.setCookie(stateCookie$1.name, encryptedData, stateCookie$1.attributes); - return { - state, - codeVerifier: stateData.codeVerifier - }; - } - const stateCookie = c.context.createAuthCookie("state", { maxAge: 300 }); - await c.setSignedCookie(stateCookie.name, state, c.context.secret, stateCookie.attributes); - const expiresAt = /* @__PURE__ */ new Date(); - expiresAt.setMinutes(expiresAt.getMinutes() + 10); - const verification = await c.context.internalAdapter.createVerificationValue({ - value: JSON.stringify(stateData), - identifier: state, - expiresAt - }); - if (!verification) throw new StateError("Unable to create verification. Make sure the database adapter is properly working and there is a verification table in the database", { code: "state_generation_error" }); - return { - state: verification.identifier, - codeVerifier: stateData.codeVerifier - }; -} -async function parseGenericState(c, state, settings) { - const storeStateStrategy = c.context.oauthConfig.storeStateStrategy; - let parsedData; - if (storeStateStrategy === "cookie") { - const stateCookie = c.context.createAuthCookie("oauth_state"); - const encryptedData = c.getCookie(stateCookie.name); - if (!encryptedData) throw new StateError("State mismatch: auth state cookie not found", { - code: "state_mismatch", - details: { state } - }); - try { - const decryptedData = await symmetricDecrypt({ - key: c.context.secret, - data: encryptedData - }); - parsedData = stateDataSchema.parse(JSON.parse(decryptedData)); - } catch (error2) { - throw new StateError("State invalid: Failed to decrypt or parse auth state", { - code: "state_invalid", - details: { state }, - cause: error2 - }); - } - expireCookie(c, stateCookie); - } else { - const data = await c.context.internalAdapter.findVerificationValue(state); - if (!data) throw new StateError("State mismatch: verification not found", { - code: "state_mismatch", - details: { state } - }); - parsedData = stateDataSchema.parse(JSON.parse(data.value)); - const stateCookie = c.context.createAuthCookie("state"); - const stateCookieValue = await c.getSignedCookie(stateCookie.name, c.context.secret); - if (!c.context.oauthConfig.skipStateCookieCheck && (!stateCookieValue || stateCookieValue !== state)) throw new StateError("State mismatch: State not persisted correctly", { - code: "state_security_mismatch", - details: { state } - }); - expireCookie(c, stateCookie); - await c.context.internalAdapter.deleteVerificationValue(data.id); - } - if (parsedData.expiresAt < Date.now()) throw new StateError("Invalid state: request expired", { - code: "state_mismatch", - details: { expiresAt: parsedData.expiresAt } - }); - return parsedData; -} -async function generateState(c, link, additionalData) { - const callbackURL = c.body?.callbackURL || c.context.options.baseURL; - if (!callbackURL) throw new APIError("BAD_REQUEST", { message: "callbackURL is required" }); - const codeVerifier = generateRandomString(128); - const stateData = { - ...additionalData ? additionalData : {}, - callbackURL, - codeVerifier, - errorURL: c.body?.errorCallbackURL, - newUserURL: c.body?.newUserCallbackURL, - link, - expiresAt: Date.now() + 600 * 1e3, - requestSignUp: c.body?.requestSignUp - }; - await setOAuthState(stateData); - try { - return generateGenericState(c, stateData); - } catch (error2) { - c.context.logger.error("Failed to create verification", error2); - throw new APIError("INTERNAL_SERVER_ERROR", { - message: "Unable to create verification", - cause: error2 - }); - } -} -async function parseState(c) { - const state = c.query.state || c.body.state; - const errorURL = c.context.options.onAPIError?.errorURL || `${c.context.baseURL}/error`; - let parsedData; - try { - parsedData = await parseGenericState(c, state); - } catch (error2) { - c.context.logger.error("Failed to parse state", error2); - if (error2 instanceof StateError && error2.code === "state_security_mismatch") throw c.redirect(`${errorURL}?error=state_mismatch`); - throw c.redirect(`${errorURL}?error=please_restart_the_process`); - } - if (!parsedData.errorURL) parsedData.errorURL = errorURL; - if (parsedData) await setOAuthState(parsedData); - return parsedData; -} -function decryptOAuthToken(token, ctx) { - if (!token) return token; - if (ctx.options.account?.encryptOAuthTokens) return symmetricDecrypt({ - key: ctx.secret, - data: token - }); - return token; -} -function setTokenUtil(token, ctx) { - if (ctx.options.account?.encryptOAuthTokens && token) return symmetricEncrypt({ - key: ctx.secret, - data: token - }); - return token; -} -const listUserAccounts = createAuthEndpoint("/list-accounts", { - method: "GET", - use: [sessionMiddleware], - metadata: { openapi: { - operationId: "listUserAccounts", - description: "List all accounts linked to the user", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "array", - items: { - type: "object", - properties: { - id: { type: "string" }, - providerId: { type: "string" }, - createdAt: { - type: "string", - format: "date-time" - }, - updatedAt: { - type: "string", - format: "date-time" - }, - accountId: { type: "string" }, - userId: { type: "string" }, - scopes: { - type: "array", - items: { type: "string" } - } - }, - required: [ - "id", - "providerId", - "createdAt", - "updatedAt", - "accountId", - "userId", - "scopes" - ] - } - } } } - } } - } } -}, async (c) => { - const session = c.context.session; - const accounts = await c.context.internalAdapter.findAccounts(session.user.id); - return c.json(accounts.map((a) => { - const { scope, ...parsed } = parseAccountOutput(c.context.options, a); - return { - ...parsed, - scopes: scope?.split(",") || [] - }; - })); -}); -const linkSocialAccount = createAuthEndpoint("/link-social", { - method: "POST", - requireHeaders: true, - body: z.object({ - callbackURL: z.string().meta({ description: "The URL to redirect to after the user has signed in" }).optional(), - provider: SocialProviderListEnum, - idToken: z.object({ - token: z.string(), - nonce: z.string().optional(), - accessToken: z.string().optional(), - refreshToken: z.string().optional(), - scopes: z.array(z.string()).optional() - }).optional(), - requestSignUp: z.boolean().optional(), - scopes: z.array(z.string()).meta({ description: "Additional scopes to request from the provider" }).optional(), - errorCallbackURL: z.string().meta({ description: "The URL to redirect to if there is an error during the link process" }).optional(), - disableRedirect: z.boolean().meta({ description: "Disable automatic redirection to the provider. Useful for handling the redirection yourself" }).optional(), - additionalData: z.record(z.string(), z.any()).optional() - }), - use: [sessionMiddleware], - metadata: { openapi: { - description: "Link a social account to the user", - operationId: "linkSocialAccount", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { - url: { - type: "string", - description: "The authorization URL to redirect the user to" - }, - redirect: { - type: "boolean", - description: "Indicates if the user should be redirected to the authorization URL" - }, - status: { type: "boolean" } - }, - required: ["redirect"] - } } } - } } - } } -}, async (c) => { - const session = c.context.session; - const provider = c.context.socialProviders.find((p) => p.id === c.body.provider); - if (!provider) { - c.context.logger.error("Provider not found. Make sure to add the provider in your auth config", { provider: c.body.provider }); - throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.PROVIDER_NOT_FOUND }); - } - if (c.body.idToken) { - if (!provider.verifyIdToken) { - c.context.logger.error("Provider does not support id token verification", { provider: c.body.provider }); - throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.ID_TOKEN_NOT_SUPPORTED }); - } - const { token, nonce } = c.body.idToken; - if (!await provider.verifyIdToken(token, nonce)) { - c.context.logger.error("Invalid id token", { provider: c.body.provider }); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.INVALID_TOKEN }); - } - const linkingUserInfo = await provider.getUserInfo({ - idToken: token, - accessToken: c.body.idToken.accessToken, - refreshToken: c.body.idToken.refreshToken - }); - if (!linkingUserInfo || !linkingUserInfo?.user) { - c.context.logger.error("Failed to get user info", { provider: c.body.provider }); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.FAILED_TO_GET_USER_INFO }); - } - const linkingUserId = String(linkingUserInfo.user.id); - if (!linkingUserInfo.user.email) { - c.context.logger.error("User email not found", { provider: c.body.provider }); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.USER_EMAIL_NOT_FOUND }); - } - if ((await c.context.internalAdapter.findAccounts(session.user.id)).find((a) => a.providerId === provider.id && a.accountId === linkingUserId)) return c.json({ - url: "", - status: true, - redirect: false - }); - if (!c.context.options.account?.accountLinking?.trustedProviders?.includes(provider.id) && !linkingUserInfo.user.emailVerified || c.context.options.account?.accountLinking?.enabled === false) throw new APIError("UNAUTHORIZED", { message: "Account not linked - linking not allowed" }); - if (linkingUserInfo.user.email?.toLowerCase() !== session.user.email.toLowerCase() && c.context.options.account?.accountLinking?.allowDifferentEmails !== true) throw new APIError("UNAUTHORIZED", { message: "Account not linked - different emails not allowed" }); - try { - await c.context.internalAdapter.createAccount({ - userId: session.user.id, - providerId: provider.id, - accountId: linkingUserId, - accessToken: c.body.idToken.accessToken, - idToken: token, - refreshToken: c.body.idToken.refreshToken, - scope: c.body.idToken.scopes?.join(",") - }); - } catch { - throw new APIError("EXPECTATION_FAILED", { message: "Account not linked - unable to create account" }); - } - if (c.context.options.account?.accountLinking?.updateUserInfoOnLink === true) try { - await c.context.internalAdapter.updateUser(session.user.id, { - name: linkingUserInfo.user?.name, - image: linkingUserInfo.user?.image - }); - } catch (e) { - console.warn("Could not update user - " + e.toString()); - } - return c.json({ - url: "", - status: true, - redirect: false - }); - } - const state = await generateState(c, { - userId: session.user.id, - email: session.user.email - }, c.body.additionalData); - const url = await provider.createAuthorizationURL({ - state: state.state, - codeVerifier: state.codeVerifier, - redirectURI: `${c.context.baseURL}/callback/${provider.id}`, - scopes: c.body.scopes - }); - if (!c.body.disableRedirect) c.setHeader("Location", url.toString()); - return c.json({ - url: url.toString(), - redirect: !c.body.disableRedirect - }); -}); -const unlinkAccount = createAuthEndpoint("/unlink-account", { - method: "POST", - body: z.object({ - providerId: z.string(), - accountId: z.string().optional() - }), - use: [freshSessionMiddleware], - metadata: { openapi: { - description: "Unlink an account", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { status: { type: "boolean" } } - } } } - } } - } } -}, async (ctx) => { - const { providerId, accountId } = ctx.body; - const accounts = await ctx.context.internalAdapter.findAccounts(ctx.context.session.user.id); - if (accounts.length === 1 && !ctx.context.options.account?.accountLinking?.allowUnlinkingAll) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.FAILED_TO_UNLINK_LAST_ACCOUNT }); - const accountExist = accounts.find((account) => accountId ? account.accountId === accountId && account.providerId === providerId : account.providerId === providerId); - if (!accountExist) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.ACCOUNT_NOT_FOUND }); - await ctx.context.internalAdapter.deleteAccount(accountExist.id); - return ctx.json({ status: true }); -}); -const getAccessToken = createAuthEndpoint("/get-access-token", { - method: "POST", - body: z.object({ - providerId: z.string().meta({ description: "The provider ID for the OAuth provider" }), - accountId: z.string().meta({ description: "The account ID associated with the refresh token" }).optional(), - userId: z.string().meta({ description: "The user ID associated with the account" }).optional() - }), - metadata: { openapi: { - description: "Get a valid access token, doing a refresh if needed", - responses: { - 200: { - description: "A Valid access token", - content: { "application/json": { schema: { - type: "object", - properties: { - tokenType: { type: "string" }, - idToken: { type: "string" }, - accessToken: { type: "string" }, - accessTokenExpiresAt: { - type: "string", - format: "date-time" - } - } - } } } - }, - 400: { description: "Invalid refresh token or provider configuration" } - } - } } -}, async (ctx) => { - const { providerId, accountId, userId } = ctx.body || {}; - const req = ctx.request; - const session = await getSessionFromCtx(ctx); - if (req && !session) throw ctx.error("UNAUTHORIZED"); - const resolvedUserId = session?.user?.id || userId; - if (!resolvedUserId) throw ctx.error("UNAUTHORIZED"); - if (!ctx.context.socialProviders.find((p) => p.id === providerId)) throw new APIError("BAD_REQUEST", { message: `Provider ${providerId} is not supported.` }); - const accountData = await getAccountCookie(ctx); - let account = void 0; - if (accountData && providerId === accountData.providerId && (!accountId || accountData.id === accountId)) account = accountData; - else account = (await ctx.context.internalAdapter.findAccounts(resolvedUserId)).find((acc) => accountId ? acc.id === accountId && acc.providerId === providerId : acc.providerId === providerId); - if (!account) throw new APIError("BAD_REQUEST", { message: "Account not found" }); - const provider = ctx.context.socialProviders.find((p) => p.id === providerId); - if (!provider) throw new APIError("BAD_REQUEST", { message: `Provider ${providerId} not found.` }); - try { - let newTokens = null; - const accessTokenExpired = account.accessTokenExpiresAt && new Date(account.accessTokenExpiresAt).getTime() - Date.now() < 5e3; - if (account.refreshToken && accessTokenExpired && provider.refreshAccessToken) { - const refreshToken$1 = await decryptOAuthToken(account.refreshToken, ctx.context); - newTokens = await provider.refreshAccessToken(refreshToken$1); - const updatedData = { - accessToken: await setTokenUtil(newTokens.accessToken, ctx.context), - accessTokenExpiresAt: newTokens.accessTokenExpiresAt, - refreshToken: await setTokenUtil(newTokens.refreshToken, ctx.context), - refreshTokenExpiresAt: newTokens.refreshTokenExpiresAt - }; - let updatedAccount = null; - if (account.id) updatedAccount = await ctx.context.internalAdapter.updateAccount(account.id, updatedData); - if (ctx.context.options.account?.storeAccountCookie) await setAccountCookie(ctx, { - ...account, - ...updatedAccount ?? updatedData - }); - } - const accessTokenExpiresAt = (() => { - if (newTokens?.accessTokenExpiresAt) { - if (typeof newTokens.accessTokenExpiresAt === "string") return new Date(newTokens.accessTokenExpiresAt); - return newTokens.accessTokenExpiresAt; - } - if (account.accessTokenExpiresAt) { - if (typeof account.accessTokenExpiresAt === "string") return new Date(account.accessTokenExpiresAt); - return account.accessTokenExpiresAt; - } - })(); - const tokens = { - accessToken: newTokens?.accessToken ?? await decryptOAuthToken(account.accessToken ?? "", ctx.context), - accessTokenExpiresAt, - scopes: account.scope?.split(",") ?? [], - idToken: newTokens?.idToken ?? account.idToken ?? void 0 - }; - return ctx.json(tokens); - } catch (error2) { - throw new APIError("BAD_REQUEST", { - message: "Failed to get a valid access token", - cause: error2 - }); - } -}); -const refreshToken = createAuthEndpoint("/refresh-token", { - method: "POST", - body: z.object({ - providerId: z.string().meta({ description: "The provider ID for the OAuth provider" }), - accountId: z.string().meta({ description: "The account ID associated with the refresh token" }).optional(), - userId: z.string().meta({ description: "The user ID associated with the account" }).optional() - }), - metadata: { openapi: { - description: "Refresh the access token using a refresh token", - responses: { - 200: { - description: "Access token refreshed successfully", - content: { "application/json": { schema: { - type: "object", - properties: { - tokenType: { type: "string" }, - idToken: { type: "string" }, - accessToken: { type: "string" }, - refreshToken: { type: "string" }, - accessTokenExpiresAt: { - type: "string", - format: "date-time" - }, - refreshTokenExpiresAt: { - type: "string", - format: "date-time" - } - } - } } } - }, - 400: { description: "Invalid refresh token or provider configuration" } - } - } } -}, async (ctx) => { - const { providerId, accountId, userId } = ctx.body; - const req = ctx.request; - const session = await getSessionFromCtx(ctx); - if (req && !session) throw ctx.error("UNAUTHORIZED"); - const resolvedUserId = session?.user?.id || userId; - if (!resolvedUserId) throw new APIError("BAD_REQUEST", { message: `Either userId or session is required` }); - const provider = ctx.context.socialProviders.find((p) => p.id === providerId); - if (!provider) throw new APIError("BAD_REQUEST", { message: `Provider ${providerId} not found.` }); - if (!provider.refreshAccessToken) throw new APIError("BAD_REQUEST", { message: `Provider ${providerId} does not support token refreshing.` }); - let account = void 0; - const accountData = await getAccountCookie(ctx); - if (accountData && (!providerId || providerId === accountData?.providerId)) account = accountData; - else account = (await ctx.context.internalAdapter.findAccounts(resolvedUserId)).find((acc) => accountId ? acc.id === accountId && acc.providerId === providerId : acc.providerId === providerId); - if (!account) throw new APIError("BAD_REQUEST", { message: "Account not found" }); - let refreshToken$1 = void 0; - if (accountData && providerId === accountData.providerId) refreshToken$1 = accountData.refreshToken ?? void 0; - else refreshToken$1 = account.refreshToken ?? void 0; - if (!refreshToken$1) throw new APIError("BAD_REQUEST", { message: "Refresh token not found" }); - try { - const decryptedRefreshToken = await decryptOAuthToken(refreshToken$1, ctx.context); - const tokens = await provider.refreshAccessToken(decryptedRefreshToken); - if (account.id) { - const updateData = { - ...account || {}, - accessToken: await setTokenUtil(tokens.accessToken, ctx.context), - refreshToken: await setTokenUtil(tokens.refreshToken, ctx.context), - accessTokenExpiresAt: tokens.accessTokenExpiresAt, - refreshTokenExpiresAt: tokens.refreshTokenExpiresAt, - scope: tokens.scopes?.join(",") || account.scope, - idToken: tokens.idToken || account.idToken - }; - await ctx.context.internalAdapter.updateAccount(account.id, updateData); - } - if (accountData && providerId === accountData.providerId && ctx.context.options.account?.storeAccountCookie) await setAccountCookie(ctx, { - ...accountData, - accessToken: await setTokenUtil(tokens.accessToken, ctx.context), - refreshToken: await setTokenUtil(tokens.refreshToken, ctx.context), - accessTokenExpiresAt: tokens.accessTokenExpiresAt, - refreshTokenExpiresAt: tokens.refreshTokenExpiresAt, - scope: tokens.scopes?.join(",") || accountData.scope, - idToken: tokens.idToken || accountData.idToken - }); - return ctx.json({ - accessToken: tokens.accessToken, - refreshToken: tokens.refreshToken, - accessTokenExpiresAt: tokens.accessTokenExpiresAt, - refreshTokenExpiresAt: tokens.refreshTokenExpiresAt, - scope: tokens.scopes?.join(",") || account.scope, - idToken: tokens.idToken || account.idToken, - providerId: account.providerId, - accountId: account.accountId - }); - } catch (error2) { - throw new APIError("BAD_REQUEST", { - message: "Failed to refresh access token", - cause: error2 - }); - } -}); -const accountInfoQuerySchema = z.optional(z.object({ accountId: z.string().meta({ description: "The provider given account id for which to get the account info" }).optional() })); -const accountInfo = createAuthEndpoint("/account-info", { - method: "GET", - use: [sessionMiddleware], - metadata: { openapi: { - description: "Get the account info provided by the provider", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { - user: { - type: "object", - properties: { - id: { type: "string" }, - name: { type: "string" }, - email: { type: "string" }, - image: { type: "string" }, - emailVerified: { type: "boolean" } - }, - required: ["id", "emailVerified"] - }, - data: { - type: "object", - properties: {}, - additionalProperties: true - } - }, - required: ["user", "data"], - additionalProperties: false - } } } - } } - } }, - query: accountInfoQuerySchema -}, async (ctx) => { - const providedAccountId = ctx.query?.accountId; - let account = void 0; - if (!providedAccountId) { - if (ctx.context.options.account?.storeAccountCookie) { - const accountData = await getAccountCookie(ctx); - if (accountData) account = accountData; - } - } else { - const accountData = await ctx.context.internalAdapter.findAccount(providedAccountId); - if (accountData) account = accountData; - } - if (!account || account.userId !== ctx.context.session.user.id) throw new APIError("BAD_REQUEST", { message: "Account not found" }); - const provider = ctx.context.socialProviders.find((p) => p.id === account.providerId); - if (!provider) throw new APIError("INTERNAL_SERVER_ERROR", { message: `Provider account provider is ${account.providerId} but it is not configured` }); - const tokens = await getAccessToken({ - ...ctx, - method: "POST", - body: { - accountId: account.id, - providerId: account.providerId - }, - returnHeaders: false, - returnStatus: false - }); - if (!tokens.accessToken) throw new APIError("BAD_REQUEST", { message: "Access token not found" }); - const info2 = await provider.getUserInfo({ - ...tokens, - accessToken: tokens.accessToken - }); - return ctx.json(info2); -}); -async function createEmailVerificationToken(secret, email, updateTo, expiresIn = 3600, extraPayload) { - return await signJWT({ - email: email.toLowerCase(), - updateTo, - ...extraPayload - }, secret, expiresIn); -} -async function sendVerificationEmailFn(ctx, user) { - if (!ctx.context.options.emailVerification?.sendVerificationEmail) { - ctx.context.logger.error("Verification email isn't enabled."); - throw new APIError("BAD_REQUEST", { message: "Verification email isn't enabled" }); - } - const token = await createEmailVerificationToken(ctx.context.secret, user.email, void 0, ctx.context.options.emailVerification?.expiresIn); - const callbackURL = ctx.body.callbackURL ? encodeURIComponent(ctx.body.callbackURL) : encodeURIComponent("/"); - const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${callbackURL}`; - await ctx.context.runInBackgroundOrAwait(ctx.context.options.emailVerification.sendVerificationEmail({ - user, - url, - token - }, ctx.request)); -} -const sendVerificationEmail = createAuthEndpoint("/send-verification-email", { - method: "POST", - operationId: "sendVerificationEmail", - body: z.object({ - email: z.email().meta({ description: "The email to send the verification email to" }), - callbackURL: z.string().meta({ description: "The URL to use for email verification callback" }).optional() - }), - metadata: { openapi: { - operationId: "sendVerificationEmail", - description: "Send a verification email to the user", - requestBody: { content: { "application/json": { schema: { - type: "object", - properties: { - email: { - type: "string", - description: "The email to send the verification email to", - example: "user@example.com" - }, - callbackURL: { - type: "string", - description: "The URL to use for email verification callback", - example: "https://example.com/callback", - nullable: true - } - }, - required: ["email"] - } } } }, - responses: { - "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { status: { - type: "boolean", - description: "Indicates if the email was sent successfully", - example: true - } } - } } } - }, - "400": { - description: "Bad Request", - content: { "application/json": { schema: { - type: "object", - properties: { message: { - type: "string", - description: "Error message", - example: "Verification email isn't enabled" - } } - } } } - } - } - } } -}, async (ctx) => { - if (!ctx.context.options.emailVerification?.sendVerificationEmail) { - ctx.context.logger.error("Verification email isn't enabled."); - throw new APIError("BAD_REQUEST", { message: "Verification email isn't enabled" }); - } - const { email } = ctx.body; - const session = await getSessionFromCtx(ctx); - if (!session) { - const user = await ctx.context.internalAdapter.findUserByEmail(email); - if (!user || user.user.emailVerified) { - await createEmailVerificationToken(ctx.context.secret, email, void 0, ctx.context.options.emailVerification?.expiresIn); - return ctx.json({ status: true }); - } - await sendVerificationEmailFn(ctx, user.user); - return ctx.json({ status: true }); - } - if (session?.user.email !== email) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.EMAIL_MISMATCH }); - if (session?.user.emailVerified) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.EMAIL_ALREADY_VERIFIED }); - await sendVerificationEmailFn(ctx, session.user); - return ctx.json({ status: true }); -}); -const verifyEmail = createAuthEndpoint("/verify-email", { - method: "GET", - operationId: "verifyEmail", - query: z.object({ - token: z.string().meta({ description: "The token to verify the email" }), - callbackURL: z.string().meta({ description: "The URL to redirect to after email verification" }).optional() - }), - use: [originCheck((ctx) => ctx.query.callbackURL)], - metadata: { openapi: { - description: "Verify the email of the user", - parameters: [{ - name: "token", - in: "query", - description: "The token to verify the email", - required: true, - schema: { type: "string" } - }, { - name: "callbackURL", - in: "query", - description: "The URL to redirect to after email verification", - required: false, - schema: { type: "string" } - }], - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { - user: { - type: "object", - $ref: "#/components/schemas/User" - }, - status: { - type: "boolean", - description: "Indicates if the email was verified successfully" - } - }, - required: ["user", "status"] - } } } - } } - } } -}, async (ctx) => { - function redirectOnError(error2) { - if (ctx.query.callbackURL) { - if (ctx.query.callbackURL.includes("?")) throw ctx.redirect(`${ctx.query.callbackURL}&error=${error2}`); - throw ctx.redirect(`${ctx.query.callbackURL}?error=${error2}`); - } - throw new APIError("UNAUTHORIZED", { message: error2 }); - } - const { token } = ctx.query; - let jwt; - try { - jwt = await jwtVerify(token, new TextEncoder().encode(ctx.context.secret), { algorithms: ["HS256"] }); - } catch (e) { - if (e instanceof JWTExpired) return redirectOnError("token_expired"); - return redirectOnError("invalid_token"); - } - const parsed = z.object({ - email: z.email(), - updateTo: z.string().optional(), - requestType: z.string().optional() - }).parse(jwt.payload); - const user = await ctx.context.internalAdapter.findUserByEmail(parsed.email); - if (!user) return redirectOnError("user_not_found"); - if (parsed.updateTo) { - const session = await getSessionFromCtx(ctx); - if (session && session.user.email !== parsed.email) return redirectOnError("unauthorized"); - switch (parsed.requestType) { - case "change-email-confirmation": { - const newToken = await createEmailVerificationToken(ctx.context.secret, parsed.email, parsed.updateTo, ctx.context.options.emailVerification?.expiresIn, { requestType: "change-email-verification" }); - const updateCallbackURL = ctx.query.callbackURL ? encodeURIComponent(ctx.query.callbackURL) : encodeURIComponent("/"); - const url = `${ctx.context.baseURL}/verify-email?token=${newToken}&callbackURL=${updateCallbackURL}`; - if (ctx.context.options.emailVerification?.sendVerificationEmail) await ctx.context.runInBackgroundOrAwait(ctx.context.options.emailVerification.sendVerificationEmail({ - user: { - ...user.user, - email: parsed.updateTo - }, - url, - token: newToken - }, ctx.request)); - if (ctx.query.callbackURL) throw ctx.redirect(ctx.query.callbackURL); - return ctx.json({ status: true }); - } - case "change-email-verification": { - let activeSession = session; - if (!activeSession) { - const newSession = await ctx.context.internalAdapter.createSession(user.user.id); - if (!newSession) throw new APIError("INTERNAL_SERVER_ERROR", { message: BASE_ERROR_CODES.FAILED_TO_CREATE_SESSION }); - activeSession = { - session: newSession, - user: user.user - }; - } - if (ctx.context.options.emailVerification?.onEmailVerification) await ctx.context.options.emailVerification.onEmailVerification(user.user, ctx.request); - const updatedUser$1 = await ctx.context.internalAdapter.updateUserByEmail(parsed.email, { - email: parsed.updateTo, - emailVerified: true - }); - if (ctx.context.options.emailVerification?.afterEmailVerification) await ctx.context.options.emailVerification.afterEmailVerification(updatedUser$1, ctx.request); - await setSessionCookie(ctx, { - session: activeSession.session, - user: { - ...activeSession.user, - email: parsed.updateTo, - emailVerified: true - } - }); - if (ctx.query.callbackURL) throw ctx.redirect(ctx.query.callbackURL); - return ctx.json({ - status: true, - user: parseUserOutput(ctx.context.options, updatedUser$1) - }); - } - default: { - let activeSession = session; - if (!activeSession) { - const newSession = await ctx.context.internalAdapter.createSession(user.user.id); - if (!newSession) throw new APIError("INTERNAL_SERVER_ERROR", { message: BASE_ERROR_CODES.FAILED_TO_CREATE_SESSION }); - activeSession = { - session: newSession, - user: user.user - }; - } - const updatedUser$1 = await ctx.context.internalAdapter.updateUserByEmail(parsed.email, { - email: parsed.updateTo, - emailVerified: false - }); - const newToken = await createEmailVerificationToken(ctx.context.secret, parsed.updateTo); - const updateCallbackURL = ctx.query.callbackURL ? encodeURIComponent(ctx.query.callbackURL) : encodeURIComponent("/"); - if (ctx.context.options.emailVerification?.sendVerificationEmail) await ctx.context.runInBackgroundOrAwait(ctx.context.options.emailVerification.sendVerificationEmail({ - user: updatedUser$1, - url: `${ctx.context.baseURL}/verify-email?token=${newToken}&callbackURL=${updateCallbackURL}`, - token: newToken - }, ctx.request)); - await setSessionCookie(ctx, { - session: activeSession.session, - user: { - ...activeSession.user, - email: parsed.updateTo, - emailVerified: false - } - }); - if (ctx.query.callbackURL) throw ctx.redirect(ctx.query.callbackURL); - return ctx.json({ - status: true, - user: parseUserOutput(ctx.context.options, updatedUser$1) - }); - } - } - } - if (user.user.emailVerified) { - if (ctx.query.callbackURL) throw ctx.redirect(ctx.query.callbackURL); - return ctx.json({ - status: true, - user: null - }); - } - if (ctx.context.options.emailVerification?.beforeEmailVerification) await ctx.context.options.emailVerification.beforeEmailVerification(user.user, ctx.request); - if (ctx.context.options.emailVerification?.onEmailVerification) await ctx.context.options.emailVerification.onEmailVerification(user.user, ctx.request); - const updatedUser = await ctx.context.internalAdapter.updateUserByEmail(parsed.email, { emailVerified: true }); - if (ctx.context.options.emailVerification?.afterEmailVerification) await ctx.context.options.emailVerification.afterEmailVerification(updatedUser, ctx.request); - if (ctx.context.options.emailVerification?.autoSignInAfterVerification) { - const currentSession = await getSessionFromCtx(ctx); - if (!currentSession || currentSession.user.email !== parsed.email) { - const session = await ctx.context.internalAdapter.createSession(user.user.id); - if (!session) throw new APIError("INTERNAL_SERVER_ERROR", { message: "Failed to create session" }); - await setSessionCookie(ctx, { - session, - user: { - ...user.user, - emailVerified: true - } - }); - } else await setSessionCookie(ctx, { - session: currentSession.session, - user: { - ...currentSession.user, - emailVerified: true - } - }); - } - if (ctx.query.callbackURL) throw ctx.redirect(ctx.query.callbackURL); - return ctx.json({ - status: true, - user: null - }); -}); -async function handleOAuthUserInfo(c, opts) { - const { userInfo, account, callbackURL, disableSignUp, overrideUserInfo } = opts; - const dbUser = await c.context.internalAdapter.findOAuthUser(userInfo.email.toLowerCase(), account.accountId, account.providerId).catch((e) => { - logger.error("Better auth was unable to query your database.\nError: ", e); - const errorURL = c.context.options.onAPIError?.errorURL || `${c.context.baseURL}/error`; - throw c.redirect(`${errorURL}?error=internal_server_error`); - }); - let user = dbUser?.user; - const isRegister = !user; - if (dbUser) { - const linkedAccount = dbUser.linkedAccount ?? dbUser.accounts.find((acc) => acc.providerId === account.providerId && acc.accountId === account.accountId); - if (!linkedAccount) { - const accountLinking = c.context.options.account?.accountLinking; - const trustedProviders = c.context.options.account?.accountLinking?.trustedProviders; - if (!(opts.isTrustedProvider || trustedProviders?.includes(account.providerId)) && !userInfo.emailVerified || accountLinking?.enabled === false || accountLinking?.disableImplicitLinking === true) { - if (isDevelopment()) logger.warn(`User already exist but account isn't linked to ${account.providerId}. To read more about how account linking works in Better Auth see https://www.better-auth.com/docs/concepts/users-accounts#account-linking.`); - return { - error: "account not linked", - data: null - }; - } - try { - await c.context.internalAdapter.linkAccount({ - providerId: account.providerId, - accountId: userInfo.id.toString(), - userId: dbUser.user.id, - accessToken: await setTokenUtil(account.accessToken, c.context), - refreshToken: await setTokenUtil(account.refreshToken, c.context), - idToken: account.idToken, - accessTokenExpiresAt: account.accessTokenExpiresAt, - refreshTokenExpiresAt: account.refreshTokenExpiresAt, - scope: account.scope - }); - } catch (e) { - logger.error("Unable to link account", e); - return { - error: "unable to link account", - data: null - }; - } - if (userInfo.emailVerified && !dbUser.user.emailVerified && userInfo.email.toLowerCase() === dbUser.user.email) await c.context.internalAdapter.updateUser(dbUser.user.id, { emailVerified: true }); - } else { - const freshTokens = c.context.options.account?.updateAccountOnSignIn !== false ? Object.fromEntries(Object.entries({ - idToken: account.idToken, - accessToken: await setTokenUtil(account.accessToken, c.context), - refreshToken: await setTokenUtil(account.refreshToken, c.context), - accessTokenExpiresAt: account.accessTokenExpiresAt, - refreshTokenExpiresAt: account.refreshTokenExpiresAt, - scope: account.scope - }).filter(([_, value]) => value !== void 0)) : {}; - if (c.context.options.account?.storeAccountCookie) await setAccountCookie(c, { - ...linkedAccount, - ...freshTokens - }); - if (Object.keys(freshTokens).length > 0) await c.context.internalAdapter.updateAccount(linkedAccount.id, freshTokens); - if (userInfo.emailVerified && !dbUser.user.emailVerified && userInfo.email.toLowerCase() === dbUser.user.email) await c.context.internalAdapter.updateUser(dbUser.user.id, { emailVerified: true }); - } - if (overrideUserInfo) { - const { id: _, ...restUserInfo } = userInfo; - user = await c.context.internalAdapter.updateUser(dbUser.user.id, { - ...restUserInfo, - email: userInfo.email.toLowerCase(), - emailVerified: userInfo.email.toLowerCase() === dbUser.user.email ? dbUser.user.emailVerified || userInfo.emailVerified : userInfo.emailVerified - }); - } - } else { - if (disableSignUp) return { - error: "signup disabled", - data: null, - isRegister: false - }; - try { - const { id: _, ...restUserInfo } = userInfo; - const accountData = { - accessToken: await setTokenUtil(account.accessToken, c.context), - refreshToken: await setTokenUtil(account.refreshToken, c.context), - idToken: account.idToken, - accessTokenExpiresAt: account.accessTokenExpiresAt, - refreshTokenExpiresAt: account.refreshTokenExpiresAt, - scope: account.scope, - providerId: account.providerId, - accountId: userInfo.id.toString() - }; - const { user: createdUser, account: createdAccount } = await c.context.internalAdapter.createOAuthUser({ - ...restUserInfo, - email: userInfo.email.toLowerCase() - }, accountData); - user = createdUser; - if (c.context.options.account?.storeAccountCookie) await setAccountCookie(c, createdAccount); - if (!userInfo.emailVerified && user && c.context.options.emailVerification?.sendOnSignUp && c.context.options.emailVerification?.sendVerificationEmail) { - const token = await createEmailVerificationToken(c.context.secret, user.email, void 0, c.context.options.emailVerification?.expiresIn); - const url = `${c.context.baseURL}/verify-email?token=${token}&callbackURL=${callbackURL}`; - await c.context.runInBackgroundOrAwait(c.context.options.emailVerification.sendVerificationEmail({ - user, - url, - token - }, c.request)); - } - } catch (e) { - logger.error(e); - if (e instanceof APIError) return { - error: e.message, - data: null, - isRegister: false - }; - return { - error: "unable to create user", - data: null, - isRegister: false - }; - } - } - if (!user) return { - error: "unable to create user", - data: null, - isRegister: false - }; - const session = await c.context.internalAdapter.createSession(user.id); - if (!session) return { - error: "unable to create session", - data: null, - isRegister: false - }; - return { - data: { - session, - user - }, - error: null, - isRegister - }; -} -const HIDE_METADATA = { scope: "server" }; -const schema = z.object({ - code: z.string().optional(), - error: z.string().optional(), - device_id: z.string().optional(), - error_description: z.string().optional(), - state: z.string().optional(), - user: z.string().optional() -}); -const callbackOAuth = createAuthEndpoint("/callback/:id", { - method: ["GET", "POST"], - operationId: "handleOAuthCallback", - body: schema.optional(), - query: schema.optional(), - metadata: { - ...HIDE_METADATA, - allowedMediaTypes: ["application/x-www-form-urlencoded", "application/json"] - } -}, async (c) => { - let queryOrBody; - const defaultErrorURL = c.context.options.onAPIError?.errorURL || `${c.context.baseURL}/error`; - if (c.method === "POST") { - const postData = c.body ? schema.parse(c.body) : {}; - const queryData = c.query ? schema.parse(c.query) : {}; - const mergedData = schema.parse({ - ...postData, - ...queryData - }); - const params = new URLSearchParams(); - for (const [key, value] of Object.entries(mergedData)) if (value !== void 0 && value !== null) params.set(key, String(value)); - const redirectURL = `${c.context.baseURL}/callback/${c.params.id}?${params.toString()}`; - throw c.redirect(redirectURL); - } - try { - if (c.method === "GET") queryOrBody = schema.parse(c.query); - else if (c.method === "POST") queryOrBody = schema.parse(c.body); - else throw new Error("Unsupported method"); - } catch (e) { - c.context.logger.error("INVALID_CALLBACK_REQUEST", e); - throw c.redirect(`${defaultErrorURL}?error=invalid_callback_request`); - } - const { code, error: error2, state, error_description, device_id, user: userData } = queryOrBody; - if (!state) { - c.context.logger.error("State not found", error2); - const url = `${defaultErrorURL}${defaultErrorURL.includes("?") ? "&" : "?"}state=state_not_found`; - throw c.redirect(url); - } - const { codeVerifier, callbackURL, link, errorURL, newUserURL, requestSignUp } = await parseState(c); - function redirectOnError(error$1, description) { - const baseURL = errorURL ?? defaultErrorURL; - const params = new URLSearchParams({ error: error$1 }); - if (description) params.set("error_description", description); - const url = `${baseURL}${baseURL.includes("?") ? "&" : "?"}${params.toString()}`; - throw c.redirect(url); - } - if (error2) redirectOnError(error2, error_description); - if (!code) { - c.context.logger.error("Code not found"); - throw redirectOnError("no_code"); - } - const provider = c.context.socialProviders.find((p) => p.id === c.params.id); - if (!provider) { - c.context.logger.error("Oauth provider with id", c.params.id, "not found"); - throw redirectOnError("oauth_provider_not_found"); - } - let tokens; - try { - tokens = await provider.validateAuthorizationCode({ - code, - codeVerifier, - deviceId: device_id, - redirectURI: `${c.context.baseURL}/callback/${provider.id}` - }); - } catch (e) { - c.context.logger.error("", e); - throw redirectOnError("invalid_code"); - } - if (!tokens) throw redirectOnError("invalid_code"); - const parsedUserData = userData ? safeJSONParse(userData) : null; - const userInfo = await provider.getUserInfo({ - ...tokens, - user: parsedUserData ?? void 0 - }).then((res) => res?.user); - if (!userInfo) { - c.context.logger.error("Unable to get user info"); - return redirectOnError("unable_to_get_user_info"); - } - if (!callbackURL) { - c.context.logger.error("No callback URL found"); - throw redirectOnError("no_callback_url"); - } - if (link) { - if (!c.context.options.account?.accountLinking?.trustedProviders?.includes(provider.id) && !userInfo.emailVerified || c.context.options.account?.accountLinking?.enabled === false) { - c.context.logger.error("Unable to link account - untrusted provider"); - return redirectOnError("unable_to_link_account"); - } - if (userInfo.email?.toLowerCase() !== link.email.toLowerCase() && c.context.options.account?.accountLinking?.allowDifferentEmails !== true) return redirectOnError("email_doesn't_match"); - const existingAccount = await c.context.internalAdapter.findAccount(String(userInfo.id)); - if (existingAccount) { - if (existingAccount.userId.toString() !== link.userId.toString()) return redirectOnError("account_already_linked_to_different_user"); - const updateData = Object.fromEntries(Object.entries({ - accessToken: await setTokenUtil(tokens.accessToken, c.context), - refreshToken: await setTokenUtil(tokens.refreshToken, c.context), - idToken: tokens.idToken, - accessTokenExpiresAt: tokens.accessTokenExpiresAt, - refreshTokenExpiresAt: tokens.refreshTokenExpiresAt, - scope: tokens.scopes?.join(",") - }).filter(([_, value]) => value !== void 0)); - await c.context.internalAdapter.updateAccount(existingAccount.id, updateData); - } else if (!await c.context.internalAdapter.createAccount({ - userId: link.userId, - providerId: provider.id, - accountId: String(userInfo.id), - ...tokens, - accessToken: await setTokenUtil(tokens.accessToken, c.context), - refreshToken: await setTokenUtil(tokens.refreshToken, c.context), - scope: tokens.scopes?.join(",") - })) return redirectOnError("unable_to_link_account"); - let toRedirectTo$1; - try { - toRedirectTo$1 = callbackURL.toString(); - } catch { - toRedirectTo$1 = callbackURL; - } - throw c.redirect(toRedirectTo$1); - } - if (!userInfo.email) { - c.context.logger.error("Provider did not return email. This could be due to misconfiguration in the provider settings."); - return redirectOnError("email_not_found"); - } - const accountData = { - providerId: provider.id, - accountId: String(userInfo.id), - ...tokens, - scope: tokens.scopes?.join(",") - }; - const result = await handleOAuthUserInfo(c, { - userInfo: { - ...userInfo, - id: String(userInfo.id), - email: userInfo.email, - name: userInfo.name || userInfo.email - }, - account: accountData, - callbackURL, - disableSignUp: provider.disableImplicitSignUp && !requestSignUp || provider.options?.disableSignUp, - overrideUserInfo: provider.options?.overrideUserInfoOnSignIn - }); - if (result.error) { - c.context.logger.error(result.error.split(" ").join("_")); - return redirectOnError(result.error.split(" ").join("_")); - } - const { session, user } = result.data; - await setSessionCookie(c, { - session, - user - }); - let toRedirectTo; - try { - toRedirectTo = (result.isRegister ? newUserURL || callbackURL : callbackURL).toString(); - } catch { - toRedirectTo = result.isRegister ? newUserURL || callbackURL : callbackURL; - } - throw c.redirect(toRedirectTo); -}); -function sanitize(input) { - return input.replace(//g, ">").replace(/"/g, """).replace(/'/g, "'").replace(/&(?!amp;|lt;|gt;|quot;|#39;|#x[0-9a-fA-F]+;|#[0-9]+;)/g, "&"); -} -const html = (options, code = "Unknown", description = null) => { - const custom = options.onAPIError?.customizeDefaultErrorPage; - return ` - - - - - Error - - - - - -`; -}; -const error = createAuthEndpoint("/error", { - method: "GET", - metadata: { - ...HIDE_METADATA, - openapi: { - description: "Displays an error page", - responses: { "200": { - description: "Success", - content: { "text/html": { schema: { - type: "string", - description: "The HTML content of the error page" - } } } - } } - } - } -}, async (c) => { - const url = new URL(c.request?.url || ""); - const unsanitizedCode = url.searchParams.get("error") || "UNKNOWN"; - const unsanitizedDescription = url.searchParams.get("error_description") || null; - const safeCode = /^[\'A-Za-z0-9_-]+$/.test(unsanitizedCode) ? unsanitizedCode : "UNKNOWN"; - const safeDescription = unsanitizedDescription ? sanitize(unsanitizedDescription) : null; - const queryParams = new URLSearchParams(); - queryParams.set("error", safeCode); - if (unsanitizedDescription) queryParams.set("error_description", unsanitizedDescription); - const options = c.context.options; - const errorURL = options.onAPIError?.errorURL; - if (errorURL) return new Response(null, { - status: 302, - headers: { Location: `${errorURL}${errorURL.includes("?") ? "&" : "?"}${queryParams.toString()}` } - }); - if (isProduction && !options.onAPIError?.customizeDefaultErrorPage) return new Response(null, { - status: 302, - headers: { Location: `/?${queryParams.toString()}` } - }); - return new Response(html(c.context.options, safeCode, safeDescription), { headers: { "Content-Type": "text/html" } }); -}); -const ok = createAuthEndpoint("/ok", { - method: "GET", - metadata: { - ...HIDE_METADATA, - openapi: { - description: "Check if the API is working", - responses: { "200": { - description: "API is working", - content: { "application/json": { schema: { - type: "object", - properties: { ok: { - type: "boolean", - description: "Indicates if the API is working" - } }, - required: ["ok"] - } } } - } } - } - } -}, async (ctx) => { - return ctx.json({ ok: true }); -}); -async function validatePassword(ctx, data) { - const credentialAccount = (await ctx.context.internalAdapter.findAccounts(data.userId))?.find((account) => account.providerId === "credential"); - const currentPassword = credentialAccount?.password; - if (!credentialAccount || !currentPassword) return false; - return await ctx.context.password.verify({ - hash: currentPassword, - password: data.password - }); -} -async function checkPassword(userId, c) { - const credentialAccount = (await c.context.internalAdapter.findAccounts(userId))?.find((account) => account.providerId === "credential"); - const currentPassword = credentialAccount?.password; - if (!credentialAccount || !currentPassword || !c.body.password) throw new APIError("BAD_REQUEST", { message: "No password credential found" }); - if (!await c.context.password.verify({ - hash: currentPassword, - password: c.body.password - })) throw new APIError("BAD_REQUEST", { message: "Invalid password" }); - return true; -} -function redirectError(ctx, callbackURL, query) { - const url = callbackURL ? new URL(callbackURL, ctx.baseURL) : new URL(`${ctx.baseURL}/error`); - if (query) Object.entries(query).forEach(([k, v]) => url.searchParams.set(k, v)); - return url.href; -} -function redirectCallback(ctx, callbackURL, query) { - const url = new URL(callbackURL, ctx.baseURL); - if (query) Object.entries(query).forEach(([k, v]) => url.searchParams.set(k, v)); - return url.href; -} -const requestPasswordReset = createAuthEndpoint("/request-password-reset", { - method: "POST", - body: z.object({ - email: z.email().meta({ description: "The email address of the user to send a password reset email to" }), - redirectTo: z.string().meta({ description: "The URL to redirect the user to reset their password. If the token isn't valid or expired, it'll be redirected with a query parameter `?error=INVALID_TOKEN`. If the token is valid, it'll be redirected with a query parameter `?token=VALID_TOKEN" }).optional() - }), - metadata: { openapi: { - operationId: "requestPasswordReset", - description: "Send a password reset email to the user", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { - status: { type: "boolean" }, - message: { type: "string" } - } - } } } - } } - } } -}, async (ctx) => { - if (!ctx.context.options.emailAndPassword?.sendResetPassword) { - ctx.context.logger.error("Reset password isn't enabled.Please pass an emailAndPassword.sendResetPassword function in your auth config!"); - throw new APIError("BAD_REQUEST", { message: "Reset password isn't enabled" }); - } - const { email, redirectTo } = ctx.body; - const user = await ctx.context.internalAdapter.findUserByEmail(email, { includeAccounts: true }); - if (!user) { - generateId(24); - await ctx.context.internalAdapter.findVerificationValue("dummy-verification-token"); - ctx.context.logger.error("Reset Password: User not found", { email }); - return ctx.json({ - status: true, - message: "If this email exists in our system, check your email for the reset link" - }); - } - const expiresAt = getDate(ctx.context.options.emailAndPassword.resetPasswordTokenExpiresIn || 3600 * 1, "sec"); - const verificationToken = generateId(24); - await ctx.context.internalAdapter.createVerificationValue({ - value: user.user.id, - identifier: `reset-password:${verificationToken}`, - expiresAt - }); - const callbackURL = redirectTo ? encodeURIComponent(redirectTo) : ""; - const url = `${ctx.context.baseURL}/reset-password/${verificationToken}?callbackURL=${callbackURL}`; - await ctx.context.runInBackgroundOrAwait(ctx.context.options.emailAndPassword.sendResetPassword({ - user: user.user, - url, - token: verificationToken - }, ctx.request)); - return ctx.json({ - status: true, - message: "If this email exists in our system, check your email for the reset link" - }); -}); -const requestPasswordResetCallback = createAuthEndpoint("/reset-password/:token", { - method: "GET", - operationId: "forgetPasswordCallback", - query: z.object({ callbackURL: z.string().meta({ description: "The URL to redirect the user to reset their password" }) }), - use: [originCheck((ctx) => ctx.query.callbackURL)], - metadata: { openapi: { - operationId: "resetPasswordCallback", - description: "Redirects the user to the callback URL with the token", - parameters: [{ - name: "token", - in: "path", - required: true, - description: "The token to reset the password", - schema: { type: "string" } - }, { - name: "callbackURL", - in: "query", - required: true, - description: "The URL to redirect the user to reset their password", - schema: { type: "string" } - }], - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { token: { type: "string" } } - } } } - } } - } } -}, async (ctx) => { - const { token } = ctx.params; - const { callbackURL } = ctx.query; - if (!token || !callbackURL) throw ctx.redirect(redirectError(ctx.context, callbackURL, { error: "INVALID_TOKEN" })); - const verification = await ctx.context.internalAdapter.findVerificationValue(`reset-password:${token}`); - if (!verification || verification.expiresAt < /* @__PURE__ */ new Date()) throw ctx.redirect(redirectError(ctx.context, callbackURL, { error: "INVALID_TOKEN" })); - throw ctx.redirect(redirectCallback(ctx.context, callbackURL, { token })); -}); -const resetPassword = createAuthEndpoint("/reset-password", { - method: "POST", - operationId: "resetPassword", - query: z.object({ token: z.string().optional() }).optional(), - body: z.object({ - newPassword: z.string().meta({ description: "The new password to set" }), - token: z.string().meta({ description: "The token to reset the password" }).optional() - }), - metadata: { openapi: { - operationId: "resetPassword", - description: "Reset the password for a user", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { status: { type: "boolean" } } - } } } - } } - } } -}, async (ctx) => { - const token = ctx.body.token || ctx.query?.token; - if (!token) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_TOKEN }); - const { newPassword } = ctx.body; - const minLength = ctx.context.password?.config.minPasswordLength; - const maxLength = ctx.context.password?.config.maxPasswordLength; - if (newPassword.length < minLength) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_SHORT }); - if (newPassword.length > maxLength) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_LONG }); - const id = `reset-password:${token}`; - const verification = await ctx.context.internalAdapter.findVerificationValue(id); - if (!verification || verification.expiresAt < /* @__PURE__ */ new Date()) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_TOKEN }); - const userId = verification.value; - const hashedPassword = await ctx.context.password.hash(newPassword); - if (!(await ctx.context.internalAdapter.findAccounts(userId)).find((ac) => ac.providerId === "credential")) await ctx.context.internalAdapter.createAccount({ - userId, - providerId: "credential", - password: hashedPassword, - accountId: userId - }); - else await ctx.context.internalAdapter.updatePassword(userId, hashedPassword); - await ctx.context.internalAdapter.deleteVerificationValue(verification.id); - if (ctx.context.options.emailAndPassword?.onPasswordReset) { - const user = await ctx.context.internalAdapter.findUserById(userId); - if (user) await ctx.context.options.emailAndPassword.onPasswordReset({ user }, ctx.request); - } - if (ctx.context.options.emailAndPassword?.revokeSessionsOnPasswordReset) await ctx.context.internalAdapter.deleteSessions(userId); - return ctx.json({ status: true }); -}); -const verifyPassword = createAuthEndpoint("/verify-password", { - method: "POST", - body: z.object({ password: z.string().meta({ description: "The password to verify" }) }), - metadata: { - scope: "server", - openapi: { - operationId: "verifyPassword", - description: "Verify the current user's password", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { status: { type: "boolean" } } - } } } - } } - } - }, - use: [sensitiveSessionMiddleware] -}, async (ctx) => { - const { password } = ctx.body; - const session = ctx.context.session; - if (!await validatePassword(ctx, { - password, - userId: session.user.id - })) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_PASSWORD }); - return ctx.json({ status: true }); -}); -const socialSignInBodySchema = z.object({ - callbackURL: z.string().meta({ description: "Callback URL to redirect to after the user has signed in" }).optional(), - newUserCallbackURL: z.string().optional(), - errorCallbackURL: z.string().meta({ description: "Callback URL to redirect to if an error happens" }).optional(), - provider: SocialProviderListEnum, - disableRedirect: z.boolean().meta({ description: "Disable automatic redirection to the provider. Useful for handling the redirection yourself" }).optional(), - idToken: z.optional(z.object({ - token: z.string().meta({ description: "ID token from the provider" }), - nonce: z.string().meta({ description: "Nonce used to generate the token" }).optional(), - accessToken: z.string().meta({ description: "Access token from the provider" }).optional(), - refreshToken: z.string().meta({ description: "Refresh token from the provider" }).optional(), - expiresAt: z.number().meta({ description: "Expiry date of the token" }).optional() - })), - scopes: z.array(z.string()).meta({ description: "Array of scopes to request from the provider. This will override the default scopes passed." }).optional(), - requestSignUp: z.boolean().meta({ description: "Explicitly request sign-up. Useful when disableImplicitSignUp is true for this provider" }).optional(), - loginHint: z.string().meta({ description: "The login hint to use for the authorization code request" }).optional(), - additionalData: z.record(z.string(), z.any()).optional().meta({ description: "Additional data to be passed through the OAuth flow" }) -}); -const signInSocial = () => createAuthEndpoint("/sign-in/social", { - method: "POST", - operationId: "socialSignIn", - body: socialSignInBodySchema, - metadata: { - $Infer: { - body: {}, - returned: {} - }, - openapi: { - description: "Sign in with a social provider", - operationId: "socialSignIn", - responses: { "200": { - description: "Success - Returns either session details or redirect URL", - content: { "application/json": { schema: { - type: "object", - description: "Session response when idToken is provided", - properties: { - token: { type: "string" }, - user: { - type: "object", - $ref: "#/components/schemas/User" - }, - url: { type: "string" }, - redirect: { - type: "boolean", - enum: [false] - } - }, - required: [ - "redirect", - "token", - "user" - ] - } } } - } } - } - } -}, async (c) => { - const provider = c.context.socialProviders.find((p) => p.id === c.body.provider); - if (!provider) { - c.context.logger.error("Provider not found. Make sure to add the provider in your auth config", { provider: c.body.provider }); - throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.PROVIDER_NOT_FOUND }); - } - if (c.body.idToken) { - if (!provider.verifyIdToken) { - c.context.logger.error("Provider does not support id token verification", { provider: c.body.provider }); - throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.ID_TOKEN_NOT_SUPPORTED }); - } - const { token, nonce } = c.body.idToken; - if (!await provider.verifyIdToken(token, nonce)) { - c.context.logger.error("Invalid id token", { provider: c.body.provider }); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.INVALID_TOKEN }); - } - const userInfo = await provider.getUserInfo({ - idToken: token, - accessToken: c.body.idToken.accessToken, - refreshToken: c.body.idToken.refreshToken - }); - if (!userInfo || !userInfo?.user) { - c.context.logger.error("Failed to get user info", { provider: c.body.provider }); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.FAILED_TO_GET_USER_INFO }); - } - if (!userInfo.user.email) { - c.context.logger.error("User email not found", { provider: c.body.provider }); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.USER_EMAIL_NOT_FOUND }); - } - const data = await handleOAuthUserInfo(c, { - userInfo: { - ...userInfo.user, - email: userInfo.user.email, - id: String(userInfo.user.id), - name: userInfo.user.name || "", - image: userInfo.user.image, - emailVerified: userInfo.user.emailVerified || false - }, - account: { - providerId: provider.id, - accountId: String(userInfo.user.id), - accessToken: c.body.idToken.accessToken - }, - callbackURL: c.body.callbackURL, - disableSignUp: provider.disableImplicitSignUp && !c.body.requestSignUp || provider.disableSignUp - }); - if (data.error) throw new APIError("UNAUTHORIZED", { message: data.error }); - await setSessionCookie(c, data.data); - return c.json({ - redirect: false, - token: data.data.session.token, - url: void 0, - user: parseUserOutput(c.context.options, data.data.user) - }); - } - const { codeVerifier, state } = await generateState(c, void 0, c.body.additionalData); - const url = await provider.createAuthorizationURL({ - state, - codeVerifier, - redirectURI: `${c.context.baseURL}/callback/${provider.id}`, - scopes: c.body.scopes, - loginHint: c.body.loginHint - }); - if (!c.body.disableRedirect) c.setHeader("Location", url.toString()); - return c.json({ - url: url.toString(), - redirect: !c.body.disableRedirect - }); -}); -const signInEmail = () => createAuthEndpoint("/sign-in/email", { - method: "POST", - operationId: "signInEmail", - use: [formCsrfMiddleware], - body: z.object({ - email: z.string().meta({ description: "Email of the user" }), - password: z.string().meta({ description: "Password of the user" }), - callbackURL: z.string().meta({ description: "Callback URL to use as a redirect for email verification" }).optional(), - rememberMe: z.boolean().meta({ description: "If this is false, the session will not be remembered. Default is `true`." }).default(true).optional() - }), - metadata: { - allowedMediaTypes: ["application/x-www-form-urlencoded", "application/json"], - $Infer: { - body: {}, - returned: {} - }, - openapi: { - operationId: "signInEmail", - description: "Sign in with email and password", - responses: { "200": { - description: "Success - Returns either session details or redirect URL", - content: { "application/json": { schema: { - type: "object", - description: "Session response when idToken is provided", - properties: { - redirect: { - type: "boolean", - enum: [false] - }, - token: { - type: "string", - description: "Session token" - }, - url: { - type: "string", - nullable: true - }, - user: { - type: "object", - $ref: "#/components/schemas/User" - } - }, - required: [ - "redirect", - "token", - "user" - ] - } } } - } } - } - } -}, async (ctx) => { - if (!ctx.context.options?.emailAndPassword?.enabled) { - ctx.context.logger.error("Email and password is not enabled. Make sure to enable it in the options on you `auth.ts` file. Check `https://better-auth.com/docs/authentication/email-password` for more!"); - throw new APIError("BAD_REQUEST", { message: "Email and password is not enabled" }); - } - const { email, password } = ctx.body; - if (!z.email().safeParse(email).success) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_EMAIL }); - const user = await ctx.context.internalAdapter.findUserByEmail(email, { includeAccounts: true }); - if (!user) { - await ctx.context.password.hash(password); - ctx.context.logger.error("User not found", { email }); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD }); - } - const credentialAccount = user.accounts.find((a) => a.providerId === "credential"); - if (!credentialAccount) { - await ctx.context.password.hash(password); - ctx.context.logger.error("Credential account not found", { email }); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD }); - } - const currentPassword = credentialAccount?.password; - if (!currentPassword) { - await ctx.context.password.hash(password); - ctx.context.logger.error("Password not found", { email }); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD }); - } - if (!await ctx.context.password.verify({ - hash: currentPassword, - password - })) { - ctx.context.logger.error("Invalid password"); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD }); - } - if (ctx.context.options?.emailAndPassword?.requireEmailVerification && !user.user.emailVerified) { - if (!ctx.context.options?.emailVerification?.sendVerificationEmail) throw new APIError("FORBIDDEN", { message: BASE_ERROR_CODES.EMAIL_NOT_VERIFIED }); - if (ctx.context.options?.emailVerification?.sendOnSignIn) { - const token = await createEmailVerificationToken(ctx.context.secret, user.user.email, void 0, ctx.context.options.emailVerification?.expiresIn); - const callbackURL = ctx.body.callbackURL ? encodeURIComponent(ctx.body.callbackURL) : encodeURIComponent("/"); - const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${callbackURL}`; - await ctx.context.runInBackgroundOrAwait(ctx.context.options.emailVerification.sendVerificationEmail({ - user: user.user, - url, - token - }, ctx.request)); - } - throw new APIError("FORBIDDEN", { message: BASE_ERROR_CODES.EMAIL_NOT_VERIFIED }); - } - const session = await ctx.context.internalAdapter.createSession(user.user.id, ctx.body.rememberMe === false); - if (!session) { - ctx.context.logger.error("Failed to create session"); - throw new APIError("UNAUTHORIZED", { message: BASE_ERROR_CODES.FAILED_TO_CREATE_SESSION }); - } - await setSessionCookie(ctx, { - session, - user: user.user - }, ctx.body.rememberMe === false); - if (ctx.body.callbackURL) ctx.setHeader("Location", ctx.body.callbackURL); - return ctx.json({ - redirect: !!ctx.body.callbackURL, - token: session.token, - url: ctx.body.callbackURL, - user: parseUserOutput(ctx.context.options, user.user) - }); -}); -const signOut = createAuthEndpoint("/sign-out", { - method: "POST", - operationId: "signOut", - requireHeaders: true, - metadata: { openapi: { - operationId: "signOut", - description: "Sign out the current user", - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { success: { type: "boolean" } } - } } } - } } - } } -}, async (ctx) => { - const sessionCookieToken = await ctx.getSignedCookie(ctx.context.authCookies.sessionToken.name, ctx.context.secret); - if (sessionCookieToken) try { - await ctx.context.internalAdapter.deleteSession(sessionCookieToken); - } catch (e) { - ctx.context.logger.error("Failed to delete session from database", e); - } - deleteSessionCookie(ctx); - return ctx.json({ success: true }); -}); -const signUpEmailBodySchema = z.object({ - name: z.string(), - email: z.email(), - password: z.string().nonempty(), - image: z.string().optional(), - callbackURL: z.string().optional(), - rememberMe: z.boolean().optional() -}).and(z.record(z.string(), z.any())); -const signUpEmail = () => createAuthEndpoint("/sign-up/email", { - method: "POST", - operationId: "signUpWithEmailAndPassword", - use: [formCsrfMiddleware], - body: signUpEmailBodySchema, - metadata: { - allowedMediaTypes: ["application/x-www-form-urlencoded", "application/json"], - $Infer: { - body: {}, - returned: {} - }, - openapi: { - operationId: "signUpWithEmailAndPassword", - description: "Sign up a user using email and password", - requestBody: { content: { "application/json": { schema: { - type: "object", - properties: { - name: { - type: "string", - description: "The name of the user" - }, - email: { - type: "string", - description: "The email of the user" - }, - password: { - type: "string", - description: "The password of the user" - }, - image: { - type: "string", - description: "The profile image URL of the user" - }, - callbackURL: { - type: "string", - description: "The URL to use for email verification callback" - }, - rememberMe: { - type: "boolean", - description: "If this is false, the session will not be remembered. Default is `true`." - } - }, - required: [ - "name", - "email", - "password" - ] - } } } }, - responses: { - "200": { - description: "Successfully created user", - content: { "application/json": { schema: { - type: "object", - properties: { - token: { - type: "string", - nullable: true, - description: "Authentication token for the session" - }, - user: { - type: "object", - properties: { - id: { - type: "string", - description: "The unique identifier of the user" - }, - email: { - type: "string", - format: "email", - description: "The email address of the user" - }, - name: { - type: "string", - description: "The name of the user" - }, - image: { - type: "string", - format: "uri", - nullable: true, - description: "The profile image URL of the user" - }, - emailVerified: { - type: "boolean", - description: "Whether the email has been verified" - }, - createdAt: { - type: "string", - format: "date-time", - description: "When the user was created" - }, - updatedAt: { - type: "string", - format: "date-time", - description: "When the user was last updated" - } - }, - required: [ - "id", - "email", - "name", - "emailVerified", - "createdAt", - "updatedAt" - ] - } - }, - required: ["user"] - } } } - }, - "422": { - description: "Unprocessable Entity. User already exists or failed to create user.", - content: { "application/json": { schema: { - type: "object", - properties: { message: { type: "string" } } - } } } - } - } - } - } -}, async (ctx) => { - return runWithTransaction(ctx.context.adapter, async () => { - if (!ctx.context.options.emailAndPassword?.enabled || ctx.context.options.emailAndPassword?.disableSignUp) throw new APIError("BAD_REQUEST", { message: "Email and password sign up is not enabled" }); - const body = ctx.body; - const { name, email, password, image, callbackURL: _callbackURL, rememberMe, ...rest } = body; - if (!z.email().safeParse(email).success) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_EMAIL }); - if (!password || typeof password !== "string") throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_PASSWORD }); - const minPasswordLength = ctx.context.password.config.minPasswordLength; - if (password.length < minPasswordLength) { - ctx.context.logger.error("Password is too short"); - throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_SHORT }); - } - const maxPasswordLength = ctx.context.password.config.maxPasswordLength; - if (password.length > maxPasswordLength) { - ctx.context.logger.error("Password is too long"); - throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_LONG }); - } - if ((await ctx.context.internalAdapter.findUserByEmail(email))?.user) { - ctx.context.logger.info(`Sign-up attempt for existing email: ${email}`); - throw new APIError("UNPROCESSABLE_ENTITY", { message: BASE_ERROR_CODES.USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL }); - } - const hash = await ctx.context.password.hash(password); - let createdUser; - try { - const data = parseUserInput(ctx.context.options, rest, "create"); - createdUser = await ctx.context.internalAdapter.createUser({ - email: email.toLowerCase(), - name, - image, - ...data, - emailVerified: false - }); - if (!createdUser) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.FAILED_TO_CREATE_USER }); - } catch (e) { - if (isDevelopment()) ctx.context.logger.error("Failed to create user", e); - if (e instanceof APIError) throw e; - ctx.context.logger?.error("Failed to create user", e); - throw new APIError("UNPROCESSABLE_ENTITY", { message: BASE_ERROR_CODES.FAILED_TO_CREATE_USER }); - } - if (!createdUser) throw new APIError("UNPROCESSABLE_ENTITY", { message: BASE_ERROR_CODES.FAILED_TO_CREATE_USER }); - await ctx.context.internalAdapter.linkAccount({ - userId: createdUser.id, - providerId: "credential", - accountId: createdUser.id, - password: hash - }); - if (ctx.context.options.emailVerification?.sendOnSignUp ?? ctx.context.options.emailAndPassword.requireEmailVerification) { - const token = await createEmailVerificationToken(ctx.context.secret, createdUser.email, void 0, ctx.context.options.emailVerification?.expiresIn); - const callbackURL = body.callbackURL ? encodeURIComponent(body.callbackURL) : encodeURIComponent("/"); - const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${callbackURL}`; - if (ctx.context.options.emailVerification?.sendVerificationEmail) await ctx.context.runInBackgroundOrAwait(ctx.context.options.emailVerification.sendVerificationEmail({ - user: createdUser, - url, - token - }, ctx.request)); - } - if (ctx.context.options.emailAndPassword.autoSignIn === false || ctx.context.options.emailAndPassword.requireEmailVerification) return ctx.json({ - token: null, - user: parseUserOutput(ctx.context.options, createdUser) - }); - const session = await ctx.context.internalAdapter.createSession(createdUser.id, rememberMe === false); - if (!session) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.FAILED_TO_CREATE_SESSION }); - await setSessionCookie(ctx, { - session, - user: createdUser - }, rememberMe === false); - return ctx.json({ - token: session.token, - user: parseUserOutput(ctx.context.options, createdUser) - }); - }); -}); -const updateUserBodySchema = z.record(z.string().meta({ description: "Field name must be a string" }), z.any()); -const updateUser = () => createAuthEndpoint("/update-user", { - method: "POST", - operationId: "updateUser", - body: updateUserBodySchema, - use: [sessionMiddleware], - metadata: { - $Infer: { body: {} }, - openapi: { - operationId: "updateUser", - description: "Update the current user", - requestBody: { content: { "application/json": { schema: { - type: "object", - properties: { - name: { - type: "string", - description: "The name of the user" - }, - image: { - type: "string", - description: "The image of the user", - nullable: true - } - } - } } } }, - responses: { "200": { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { user: { - type: "object", - $ref: "#/components/schemas/User" - } } - } } } - } } - } - } -}, async (ctx) => { - const body = ctx.body; - if (typeof body !== "object" || Array.isArray(body)) throw new APIError("BAD_REQUEST", { message: "Body must be an object" }); - if (body.email) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.EMAIL_CAN_NOT_BE_UPDATED }); - const { name, image, ...rest } = body; - const session = ctx.context.session; - const additionalFields = parseUserInput(ctx.context.options, rest, "update"); - if (image === void 0 && name === void 0 && Object.keys(additionalFields).length === 0) throw new APIError("BAD_REQUEST", { message: "No fields to update" }); - const updatedUser = await ctx.context.internalAdapter.updateUser(session.user.id, { - name, - image, - ...additionalFields - }) ?? { - ...session.user, - ...name !== void 0 && { name }, - ...image !== void 0 && { image }, - ...additionalFields - }; - await setSessionCookie(ctx, { - session: session.session, - user: updatedUser - }); - return ctx.json({ status: true }); -}); -const changePassword = createAuthEndpoint("/change-password", { - method: "POST", - operationId: "changePassword", - body: z.object({ - newPassword: z.string().meta({ description: "The new password to set" }), - currentPassword: z.string().meta({ description: "The current password is required" }), - revokeOtherSessions: z.boolean().meta({ description: "Must be a boolean value" }).optional() - }), - use: [sensitiveSessionMiddleware], - metadata: { openapi: { - operationId: "changePassword", - description: "Change the password of the user", - responses: { "200": { - description: "Password successfully changed", - content: { "application/json": { schema: { - type: "object", - properties: { - token: { - type: "string", - nullable: true, - description: "New session token if other sessions were revoked" - }, - user: { - type: "object", - properties: { - id: { - type: "string", - description: "The unique identifier of the user" - }, - email: { - type: "string", - format: "email", - description: "The email address of the user" - }, - name: { - type: "string", - description: "The name of the user" - }, - image: { - type: "string", - format: "uri", - nullable: true, - description: "The profile image URL of the user" - }, - emailVerified: { - type: "boolean", - description: "Whether the email has been verified" - }, - createdAt: { - type: "string", - format: "date-time", - description: "When the user was created" - }, - updatedAt: { - type: "string", - format: "date-time", - description: "When the user was last updated" - } - }, - required: [ - "id", - "email", - "name", - "emailVerified", - "createdAt", - "updatedAt" - ] - } - }, - required: ["user"] - } } } - } } - } } -}, async (ctx) => { - const { newPassword, currentPassword, revokeOtherSessions: revokeOtherSessions2 } = ctx.body; - const session = ctx.context.session; - const minPasswordLength = ctx.context.password.config.minPasswordLength; - if (newPassword.length < minPasswordLength) { - ctx.context.logger.error("Password is too short"); - throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_SHORT }); - } - const maxPasswordLength = ctx.context.password.config.maxPasswordLength; - if (newPassword.length > maxPasswordLength) { - ctx.context.logger.error("Password is too long"); - throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_LONG }); - } - const account = (await ctx.context.internalAdapter.findAccounts(session.user.id)).find((account$1) => account$1.providerId === "credential" && account$1.password); - if (!account || !account.password) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.CREDENTIAL_ACCOUNT_NOT_FOUND }); - const passwordHash = await ctx.context.password.hash(newPassword); - if (!await ctx.context.password.verify({ - hash: account.password, - password: currentPassword - })) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_PASSWORD }); - await ctx.context.internalAdapter.updateAccount(account.id, { password: passwordHash }); - let token = null; - if (revokeOtherSessions2) { - await ctx.context.internalAdapter.deleteSessions(session.user.id); - const newSession = await ctx.context.internalAdapter.createSession(session.user.id); - if (!newSession) throw new APIError("INTERNAL_SERVER_ERROR", { message: BASE_ERROR_CODES.FAILED_TO_GET_SESSION }); - await setSessionCookie(ctx, { - session: newSession, - user: session.user - }); - token = newSession.token; - } - return ctx.json({ - token, - user: parseUserOutput(ctx.context.options, session.user) - }); -}); -const setPassword = createAuthEndpoint({ - method: "POST", - body: z.object({ newPassword: z.string().meta({ description: "The new password to set is required" }) }), - use: [sensitiveSessionMiddleware] -}, async (ctx) => { - const { newPassword } = ctx.body; - const session = ctx.context.session; - const minPasswordLength = ctx.context.password.config.minPasswordLength; - if (newPassword.length < minPasswordLength) { - ctx.context.logger.error("Password is too short"); - throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_SHORT }); - } - const maxPasswordLength = ctx.context.password.config.maxPasswordLength; - if (newPassword.length > maxPasswordLength) { - ctx.context.logger.error("Password is too long"); - throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.PASSWORD_TOO_LONG }); - } - const account = (await ctx.context.internalAdapter.findAccounts(session.user.id)).find((account$1) => account$1.providerId === "credential" && account$1.password); - const passwordHash = await ctx.context.password.hash(newPassword); - if (!account) { - await ctx.context.internalAdapter.linkAccount({ - userId: session.user.id, - providerId: "credential", - accountId: session.user.id, - password: passwordHash - }); - return ctx.json({ status: true }); - } - throw new APIError("BAD_REQUEST", { message: "user already has a password" }); -}); -const deleteUser = createAuthEndpoint("/delete-user", { - method: "POST", - use: [sensitiveSessionMiddleware], - body: z.object({ - callbackURL: z.string().meta({ description: "The callback URL to redirect to after the user is deleted" }).optional(), - password: z.string().meta({ description: "The password of the user is required to delete the user" }).optional(), - token: z.string().meta({ description: "The token to delete the user is required" }).optional() - }), - metadata: { openapi: { - operationId: "deleteUser", - description: "Delete the user", - requestBody: { content: { "application/json": { schema: { - type: "object", - properties: { - callbackURL: { - type: "string", - description: "The callback URL to redirect to after the user is deleted" - }, - password: { - type: "string", - description: "The user's password. Required if session is not fresh" - }, - token: { - type: "string", - description: "The deletion verification token" - } - } - } } } }, - responses: { "200": { - description: "User deletion processed successfully", - content: { "application/json": { schema: { - type: "object", - properties: { - success: { - type: "boolean", - description: "Indicates if the operation was successful" - }, - message: { - type: "string", - enum: ["User deleted", "Verification email sent"], - description: "Status message of the deletion process" - } - }, - required: ["success", "message"] - } } } - } } - } } -}, async (ctx) => { - if (!ctx.context.options.user?.deleteUser?.enabled) { - ctx.context.logger.error("Delete user is disabled. Enable it in the options"); - throw new APIError("NOT_FOUND"); - } - const session = ctx.context.session; - if (ctx.body.password) { - const account = (await ctx.context.internalAdapter.findAccounts(session.user.id)).find((account$1) => account$1.providerId === "credential" && account$1.password); - if (!account || !account.password) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.CREDENTIAL_ACCOUNT_NOT_FOUND }); - if (!await ctx.context.password.verify({ - hash: account.password, - password: ctx.body.password - })) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_PASSWORD }); - } - if (ctx.body.token) { - await deleteUserCallback({ - ...ctx, - query: { token: ctx.body.token } - }); - return ctx.json({ - success: true, - message: "User deleted" - }); - } - if (ctx.context.options.user.deleteUser?.sendDeleteAccountVerification) { - const token = generateRandomString(32, "0-9", "a-z"); - await ctx.context.internalAdapter.createVerificationValue({ - value: session.user.id, - identifier: `delete-account-${token}`, - expiresAt: new Date(Date.now() + (ctx.context.options.user.deleteUser?.deleteTokenExpiresIn || 3600 * 24) * 1e3) - }); - const url = `${ctx.context.baseURL}/delete-user/callback?token=${token}&callbackURL=${encodeURIComponent(ctx.body.callbackURL || "/")}`; - await ctx.context.runInBackgroundOrAwait(ctx.context.options.user.deleteUser.sendDeleteAccountVerification({ - user: session.user, - url, - token - }, ctx.request)); - return ctx.json({ - success: true, - message: "Verification email sent" - }); - } - if (!ctx.body.password && ctx.context.sessionConfig.freshAge !== 0) { - const currentAge = new Date(session.session.createdAt).getTime(); - const freshAge = ctx.context.sessionConfig.freshAge * 1e3; - if (Date.now() - currentAge > freshAge * 1e3) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.SESSION_EXPIRED }); - } - const beforeDelete = ctx.context.options.user.deleteUser?.beforeDelete; - if (beforeDelete) await beforeDelete(session.user, ctx.request); - await ctx.context.internalAdapter.deleteUser(session.user.id); - await ctx.context.internalAdapter.deleteSessions(session.user.id); - deleteSessionCookie(ctx); - const afterDelete = ctx.context.options.user.deleteUser?.afterDelete; - if (afterDelete) await afterDelete(session.user, ctx.request); - return ctx.json({ - success: true, - message: "User deleted" - }); -}); -const deleteUserCallback = createAuthEndpoint("/delete-user/callback", { - method: "GET", - query: z.object({ - token: z.string().meta({ description: "The token to verify the deletion request" }), - callbackURL: z.string().meta({ description: "The URL to redirect to after deletion" }).optional() - }), - use: [originCheck((ctx) => ctx.query.callbackURL)], - metadata: { openapi: { - description: "Callback to complete user deletion with verification token", - responses: { "200": { - description: "User successfully deleted", - content: { "application/json": { schema: { - type: "object", - properties: { - success: { - type: "boolean", - description: "Indicates if the deletion was successful" - }, - message: { - type: "string", - enum: ["User deleted"], - description: "Confirmation message" - } - }, - required: ["success", "message"] - } } } - } } - } } -}, async (ctx) => { - if (!ctx.context.options.user?.deleteUser?.enabled) { - ctx.context.logger.error("Delete user is disabled. Enable it in the options"); - throw new APIError("NOT_FOUND"); - } - const session = await getSessionFromCtx(ctx); - if (!session) throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.FAILED_TO_GET_USER_INFO }); - const token = await ctx.context.internalAdapter.findVerificationValue(`delete-account-${ctx.query.token}`); - if (!token || token.expiresAt < /* @__PURE__ */ new Date()) throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.INVALID_TOKEN }); - if (token.value !== session.user.id) throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.INVALID_TOKEN }); - const beforeDelete = ctx.context.options.user.deleteUser?.beforeDelete; - if (beforeDelete) await beforeDelete(session.user, ctx.request); - await ctx.context.internalAdapter.deleteUser(session.user.id); - await ctx.context.internalAdapter.deleteSessions(session.user.id); - await ctx.context.internalAdapter.deleteAccounts(session.user.id); - await ctx.context.internalAdapter.deleteVerificationValue(token.id); - deleteSessionCookie(ctx); - const afterDelete = ctx.context.options.user.deleteUser?.afterDelete; - if (afterDelete) await afterDelete(session.user, ctx.request); - if (ctx.query.callbackURL) throw ctx.redirect(ctx.query.callbackURL || "/"); - return ctx.json({ - success: true, - message: "User deleted" - }); -}); -const changeEmail = createAuthEndpoint("/change-email", { - method: "POST", - body: z.object({ - newEmail: z.email().meta({ description: "The new email address to set must be a valid email address" }), - callbackURL: z.string().meta({ description: "The URL to redirect to after email verification" }).optional() - }), - use: [sensitiveSessionMiddleware], - metadata: { openapi: { - operationId: "changeEmail", - responses: { - "200": { - description: "Email change request processed successfully", - content: { "application/json": { schema: { - type: "object", - properties: { - user: { - type: "object", - $ref: "#/components/schemas/User" - }, - status: { - type: "boolean", - description: "Indicates if the request was successful" - }, - message: { - type: "string", - enum: ["Email updated", "Verification email sent"], - description: "Status message of the email change process", - nullable: true - } - }, - required: ["status"] - } } } - }, - "422": { - description: "Unprocessable Entity. Email already exists", - content: { "application/json": { schema: { - type: "object", - properties: { message: { type: "string" } } - } } } - } - } - } } -}, async (ctx) => { - if (!ctx.context.options.user?.changeEmail?.enabled) { - ctx.context.logger.error("Change email is disabled."); - throw new APIError("BAD_REQUEST", { message: "Change email is disabled" }); - } - const newEmail = ctx.body.newEmail.toLowerCase(); - if (newEmail === ctx.context.session.user.email) { - ctx.context.logger.error("Email is the same"); - throw new APIError("BAD_REQUEST", { message: "Email is the same" }); - } - if (await ctx.context.internalAdapter.findUserByEmail(newEmail)) { - ctx.context.logger.error("Email already exists"); - throw new APIError("UNPROCESSABLE_ENTITY", { message: BASE_ERROR_CODES.USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL }); - } - if (ctx.context.session.user.emailVerified !== true && ctx.context.options.user.changeEmail.updateEmailWithoutVerification) { - await ctx.context.internalAdapter.updateUserByEmail(ctx.context.session.user.email, { email: newEmail }); - await setSessionCookie(ctx, { - session: ctx.context.session.session, - user: { - ...ctx.context.session.user, - email: newEmail - } - }); - if (ctx.context.options.emailVerification?.sendVerificationEmail) { - const token$1 = await createEmailVerificationToken(ctx.context.secret, newEmail, void 0, ctx.context.options.emailVerification?.expiresIn); - const url$1 = `${ctx.context.baseURL}/verify-email?token=${token$1}&callbackURL=${ctx.body.callbackURL || "/"}`; - await ctx.context.runInBackgroundOrAwait(ctx.context.options.emailVerification.sendVerificationEmail({ - user: { - ...ctx.context.session.user, - email: newEmail - }, - url: url$1, - token: token$1 - }, ctx.request)); - } - return ctx.json({ status: true }); - } - if (ctx.context.session.user.emailVerified && (ctx.context.options.user.changeEmail.sendChangeEmailConfirmation || ctx.context.options.user.changeEmail.sendChangeEmailVerification)) { - const token$1 = await createEmailVerificationToken(ctx.context.secret, ctx.context.session.user.email, newEmail, ctx.context.options.emailVerification?.expiresIn, { requestType: "change-email-confirmation" }); - const url$1 = `${ctx.context.baseURL}/verify-email?token=${token$1}&callbackURL=${ctx.body.callbackURL || "/"}`; - const sendFn = ctx.context.options.user.changeEmail.sendChangeEmailConfirmation || ctx.context.options.user.changeEmail.sendChangeEmailVerification; - if (sendFn) await ctx.context.runInBackgroundOrAwait(sendFn({ - user: ctx.context.session.user, - newEmail, - url: url$1, - token: token$1 - }, ctx.request)); - return ctx.json({ status: true }); - } - if (!ctx.context.options.emailVerification?.sendVerificationEmail) { - ctx.context.logger.error("Verification email isn't enabled."); - throw new APIError("BAD_REQUEST", { message: "Verification email isn't enabled" }); - } - const token = await createEmailVerificationToken(ctx.context.secret, ctx.context.session.user.email, newEmail, ctx.context.options.emailVerification?.expiresIn, { requestType: "change-email-verification" }); - const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${ctx.body.callbackURL || "/"}`; - await ctx.context.runInBackgroundOrAwait(ctx.context.options.emailVerification.sendVerificationEmail({ - user: { - ...ctx.context.session.user, - email: newEmail - }, - url, - token - }, ctx.request)); - return ctx.json({ status: true }); -}); -const defuReplaceArrays = createDefu((obj, key, value) => { - if (Array.isArray(obj[key]) && Array.isArray(value)) { - obj[key] = value; - return true; - } -}); -const hooksSourceWeakMap = /* @__PURE__ */ new WeakMap(); -function toAuthEndpoints(endpoints, ctx) { - const api = {}; - for (const [key, endpoint] of Object.entries(endpoints)) { - api[key] = async (context) => { - const run = async () => { - const authContext = await ctx; - let internalContext = { - ...context, - context: { - ...authContext, - returned: void 0, - responseHeaders: void 0, - session: null - }, - path: endpoint.path, - headers: context?.headers ? new Headers(context?.headers) : void 0 - }; - return runWithEndpointContext(internalContext, async () => { - const { beforeHooks, afterHooks } = getHooks(authContext); - const before = await runBeforeHooks(internalContext, beforeHooks); - if ("context" in before && before.context && typeof before.context === "object") { - const { headers, ...rest } = before.context; - if (headers) headers.forEach((value, key$1) => { - internalContext.headers.set(key$1, value); - }); - internalContext = defuReplaceArrays(rest, internalContext); - } else if (before) return context?.asResponse ? toResponse(before, { headers: context?.headers }) : context?.returnHeaders ? { - headers: context?.headers, - response: before - } : before; - internalContext.asResponse = false; - internalContext.returnHeaders = true; - internalContext.returnStatus = true; - const result = await runWithEndpointContext(internalContext, () => endpoint(internalContext)).catch((e) => { - if (e instanceof APIError) - return { - response: e, - status: e.statusCode, - headers: e.headers ? new Headers(e.headers) : null - }; - throw e; - }); - if (result && result instanceof Response) return result; - internalContext.context.returned = result.response; - internalContext.context.responseHeaders = result.headers; - const after = await runAfterHooks(internalContext, afterHooks); - if (after.response) result.response = after.response; - if (result.response instanceof APIError && shouldPublishLog(authContext.logger.level, "debug")) result.response.stack = result.response.errorStack; - if (result.response instanceof APIError && !context?.asResponse) throw result.response; - return context?.asResponse ? toResponse(result.response, { - headers: result.headers, - status: result.status - }) : context?.returnHeaders ? context?.returnStatus ? { - headers: result.headers, - response: result.response, - status: result.status - } : { - headers: result.headers, - response: result.response - } : context?.returnStatus ? { - response: result.response, - status: result.status - } : result.response; - }); - }; - if (await hasRequestState()) return run(); - else return runWithRequestState(/* @__PURE__ */ new WeakMap(), run); - }; - api[key].path = endpoint.path; - api[key].options = endpoint.options; - } - return api; -} -async function runBeforeHooks(context, hooks) { - let modifiedContext = {}; - for (const hook of hooks) { - let matched = false; - try { - matched = hook.matcher(context); - } catch (error2) { - const hookSource = hooksSourceWeakMap.get(hook.handler) ?? "unknown"; - context.context.logger.error(`An error occurred during ${hookSource} hook matcher execution:`, error2); - throw new APIError("INTERNAL_SERVER_ERROR", { message: `An error occurred during hook matcher execution. Check the logs for more details.` }); - } - if (matched) { - const result = await hook.handler({ - ...context, - returnHeaders: false - }).catch((e) => { - if (e instanceof APIError && shouldPublishLog(context.context.logger.level, "debug")) e.stack = e.errorStack; - throw e; - }); - if (result && typeof result === "object") { - if ("context" in result && typeof result.context === "object") { - const { headers, ...rest } = result.context; - if (headers instanceof Headers) if (modifiedContext.headers) headers.forEach((value, key) => { - modifiedContext.headers?.set(key, value); - }); - else modifiedContext.headers = headers; - modifiedContext = defuReplaceArrays(rest, modifiedContext); - continue; - } - return result; - } - } - } - return { context: modifiedContext }; -} -async function runAfterHooks(context, hooks) { - for (const hook of hooks) if (hook.matcher(context)) { - const result = await hook.handler(context).catch((e) => { - if (e instanceof APIError) { - if (shouldPublishLog(context.context.logger.level, "debug")) e.stack = e.errorStack; - return { - response: e, - headers: e.headers ? new Headers(e.headers) : null - }; - } - throw e; - }); - if (result.headers) result.headers.forEach((value, key) => { - if (!context.context.responseHeaders) context.context.responseHeaders = new Headers({ [key]: value }); - else if (key.toLowerCase() === "set-cookie") context.context.responseHeaders.append(key, value); - else context.context.responseHeaders.set(key, value); - }); - if (result.response) context.context.returned = result.response; - } - return { - response: context.context.returned, - headers: context.context.responseHeaders - }; -} -function getHooks(authContext) { - const plugins = authContext.options.plugins || []; - const beforeHooks = []; - const afterHooks = []; - const beforeHookHandler = authContext.options.hooks?.before; - if (beforeHookHandler) { - hooksSourceWeakMap.set(beforeHookHandler, "user"); - beforeHooks.push({ - matcher: () => true, - handler: beforeHookHandler - }); - } - const afterHookHandler = authContext.options.hooks?.after; - if (afterHookHandler) { - hooksSourceWeakMap.set(afterHookHandler, "user"); - afterHooks.push({ - matcher: () => true, - handler: afterHookHandler - }); - } - const pluginBeforeHooks = plugins.filter((plugin) => plugin.hooks?.before).map((plugin) => plugin.hooks?.before).flat(); - const pluginAfterHooks = plugins.filter((plugin) => plugin.hooks?.after).map((plugin) => plugin.hooks?.after).flat(); - if (pluginBeforeHooks.length) beforeHooks.push(...pluginBeforeHooks); - if (pluginAfterHooks.length) afterHooks.push(...pluginAfterHooks); - return { - beforeHooks, - afterHooks - }; -} -function checkEndpointConflicts(options, logger$1) { - const endpointRegistry = /* @__PURE__ */ new Map(); - options.plugins?.forEach((plugin) => { - if (plugin.endpoints) { - for (const [key, endpoint] of Object.entries(plugin.endpoints)) if (endpoint && "path" in endpoint && typeof endpoint.path === "string") { - const path = endpoint.path; - let methods = []; - if (endpoint.options && "method" in endpoint.options) { - if (Array.isArray(endpoint.options.method)) methods = endpoint.options.method; - else if (typeof endpoint.options.method === "string") methods = [endpoint.options.method]; - } - if (methods.length === 0) methods = ["*"]; - if (!endpointRegistry.has(path)) endpointRegistry.set(path, []); - endpointRegistry.get(path).push({ - pluginId: plugin.id, - endpointKey: key, - methods - }); - } - } - }); - const conflicts = []; - for (const [path, entries] of endpointRegistry.entries()) if (entries.length > 1) { - const methodMap = /* @__PURE__ */ new Map(); - let hasConflict = false; - for (const entry of entries) for (const method of entry.methods) { - if (!methodMap.has(method)) methodMap.set(method, []); - methodMap.get(method).push(entry.pluginId); - if (methodMap.get(method).length > 1) hasConflict = true; - if (method === "*" && entries.length > 1) hasConflict = true; - else if (method !== "*" && methodMap.has("*")) hasConflict = true; - } - if (hasConflict) { - const uniquePlugins = [...new Set(entries.map((e) => e.pluginId))]; - const conflictingMethods = []; - for (const [method, plugins] of methodMap.entries()) if (plugins.length > 1 || method === "*" && entries.length > 1 || method !== "*" && methodMap.has("*")) conflictingMethods.push(method); - conflicts.push({ - path, - plugins: uniquePlugins, - conflictingMethods - }); - } - } - if (conflicts.length > 0) { - const conflictMessages = conflicts.map((conflict) => ` - "${conflict.path}" [${conflict.conflictingMethods.join(", ")}] used by plugins: ${conflict.plugins.join(", ")}`).join("\n"); - logger$1.error(`Endpoint path conflicts detected! Multiple plugins are trying to use the same endpoint paths with conflicting HTTP methods: -${conflictMessages} - -To resolve this, you can: - 1. Use only one of the conflicting plugins - 2. Configure the plugins to use different paths (if supported) - 3. Ensure plugins use different HTTP methods for the same path -`); - } -} -function getEndpoints(ctx, options) { - const pluginEndpoints = options.plugins?.reduce((acc, plugin) => { - return { - ...acc, - ...plugin.endpoints - }; - }, {}) ?? {}; - const middlewares = options.plugins?.map((plugin) => plugin.middlewares?.map((m) => { - const middleware = (async (context) => { - const authContext = await ctx; - return m.middleware({ - ...context, - context: { - ...authContext, - ...context.context - } - }); - }); - middleware.options = m.middleware.options; - return { - path: m.path, - middleware - }; - })).filter((plugin) => plugin !== void 0).flat() || []; - return { - api: toAuthEndpoints({ - signInSocial: signInSocial(), - callbackOAuth, - getSession: getSession(), - signOut, - signUpEmail: signUpEmail(), - signInEmail: signInEmail(), - resetPassword, - verifyPassword, - verifyEmail, - sendVerificationEmail, - changeEmail, - changePassword, - setPassword, - updateUser: updateUser(), - deleteUser, - requestPasswordReset, - requestPasswordResetCallback, - listSessions: listSessions(), - revokeSession, - revokeSessions, - revokeOtherSessions, - linkSocialAccount, - listUserAccounts, - deleteUserCallback, - unlinkAccount, - refreshToken, - getAccessToken, - accountInfo, - ...pluginEndpoints, - ok, - error - }, ctx), - middlewares - }; -} -const router = (ctx, options) => { - const { api, middlewares } = getEndpoints(ctx, options); - const basePath = new URL(ctx.baseURL).pathname; - return createRouter(api, { - routerContext: ctx, - openapi: { disabled: true }, - basePath, - routerMiddleware: [{ - path: "/**", - middleware: originCheckMiddleware - }, ...middlewares], - allowedMediaTypes: ["application/json"], - skipTrailingSlashes: options.advanced?.skipTrailingSlashes ?? false, - async onRequest(req) { - const disabledPaths = ctx.options.disabledPaths || []; - const normalizedPath = normalizePathname(req.url, basePath); - if (disabledPaths.includes(normalizedPath)) return new Response("Not Found", { status: 404 }); - let currentRequest = req; - for (const plugin of ctx.options.plugins || []) if (plugin.onRequest) { - const response = await plugin.onRequest(currentRequest, ctx); - if (response && "response" in response) return response.response; - if (response && "request" in response) currentRequest = response.request; - } - const rateLimitResponse2 = await onRequestRateLimit(currentRequest, ctx); - if (rateLimitResponse2) return rateLimitResponse2; - return currentRequest; - }, - async onResponse(res) { - for (const plugin of ctx.options.plugins || []) if (plugin.onResponse) { - const response = await plugin.onResponse(res, ctx); - if (response) return response.response; - } - return res; - }, - onError(e) { - if (e instanceof APIError && e.status === "FOUND") return; - if (options.onAPIError?.throw) throw e; - if (options.onAPIError?.onError) { - options.onAPIError.onError(e, ctx); - return; - } - const optLogLevel = options.logger?.level; - const log = optLogLevel === "error" || optLogLevel === "warn" || optLogLevel === "debug" ? logger : void 0; - if (options.logger?.disabled !== true) { - if (e && typeof e === "object" && "message" in e && typeof e.message === "string") { - if (e.message.includes("no column") || e.message.includes("column") || e.message.includes("relation") || e.message.includes("table") || e.message.includes("does not exist")) { - ctx.logger?.error(e.message); - return; - } - } - if (e instanceof APIError) { - if (e.status === "INTERNAL_SERVER_ERROR") ctx.logger.error(e.status, e); - log?.error(e.message); - } else ctx.logger?.error(e && typeof e === "object" && "name" in e ? e.name : "", e); - } - } - }); -}; -async function runPluginInit(ctx) { - let options = ctx.options; - const plugins = options.plugins || []; - let context = ctx; - const dbHooks = []; - for (const plugin of plugins) if (plugin.init) { - const initPromise = plugin.init(context); - let result; - if (isPromise(initPromise)) result = await initPromise; - else result = initPromise; - if (typeof result === "object") { - if (result.options) { - const { databaseHooks, ...restOpts } = result.options; - if (databaseHooks) dbHooks.push(databaseHooks); - options = defu(options, restOpts); - } - if (result.context) context = { - ...context, - ...result.context - }; - } - } - dbHooks.push(options.databaseHooks); - context.internalAdapter = createInternalAdapter(context.adapter, { - options, - logger: context.logger, - hooks: dbHooks.filter((u) => u !== void 0), - generateId: context.generateId - }); - context.options = options; - return { context }; -} -function getInternalPlugins(options) { - const plugins = []; - if (options.advanced?.crossSubDomainCookies?.enabled) ; - return plugins; -} -async function getTrustedOrigins(options, request) { - const baseURL = getBaseURL(options.baseURL, options.basePath, request); - const trustedOrigins = baseURL ? [new URL(baseURL).origin] : []; - if (options.trustedOrigins) { - if (Array.isArray(options.trustedOrigins)) trustedOrigins.push(...options.trustedOrigins); - if (typeof options.trustedOrigins === "function") { - const validOrigins = await options.trustedOrigins(request); - trustedOrigins.push(...validOrigins); - } - } - const envTrustedOrigins = env.BETTER_AUTH_TRUSTED_ORIGINS; - if (envTrustedOrigins) trustedOrigins.push(...envTrustedOrigins.split(",")); - return trustedOrigins.filter((v) => Boolean(v)); -} -const createBetterAuth = (options, initFn) => { - const authContext = initFn(options); - const { api } = getEndpoints(authContext, options); - return { - handler: async (request) => { - const ctx = await authContext; - const basePath = ctx.options.basePath || "/api/auth"; - if (!ctx.options.baseURL) { - const baseURL = getBaseURL(void 0, basePath, request, void 0, ctx.options.advanced?.trustedProxyHeaders); - if (baseURL) { - ctx.baseURL = baseURL; - ctx.options.baseURL = getOrigin(ctx.baseURL) || void 0; - } else throw new BetterAuthError("Could not get base URL from request. Please provide a valid base URL."); - } - ctx.trustedOrigins = await getTrustedOrigins(ctx.options, request); - const { handler } = router(ctx, options); - return runWithAdapter(ctx.adapter, () => handler(request)); - }, - api, - options, - $context: authContext, - $ERROR_CODES: { - ...options.plugins?.reduce((acc, plugin) => { - if (plugin.$ERROR_CODES) return { - ...acc, - ...plugin.$ERROR_CODES - }; - return acc; - }, {}), - ...BASE_ERROR_CODES - } - }; -}; -const DEFAULT_SECRET = "better-auth-secret-12345678901234567890"; -function estimateEntropy(str) { - const unique = new Set(str).size; - if (unique === 0) return 0; - return Math.log2(Math.pow(unique, str.length)); -} -function validateSecret(secret, logger$1) { - const isDefaultSecret = secret === DEFAULT_SECRET; - if (isTest()) return; - if (isDefaultSecret && isProduction) throw new BetterAuthError("You are using the default secret. Please set `BETTER_AUTH_SECRET` in your environment variables or pass `secret` in your auth config."); - if (secret.length < 32) logger$1.warn(`[better-auth] Warning: your BETTER_AUTH_SECRET should be at least 32 characters long for adequate security. Generate one with \`npx @better-auth/cli secret\` or \`openssl rand -base64 32\`.`); - if (estimateEntropy(secret) < 120) logger$1.warn("[better-auth] Warning: your BETTER_AUTH_SECRET appears low-entropy. Use a randomly generated secret for production."); -} -async function createAuthContext(adapter, options, getDatabaseType) { - if (!options.database) options = defu$1(options, { - session: { cookieCache: { - enabled: true, - strategy: "jwe", - refreshCache: true - } }, - account: { - storeStateStrategy: "cookie", - storeAccountCookie: true - } - }); - const plugins = options.plugins || []; - const internalPlugins = getInternalPlugins(options); - const logger$1 = createLogger(options.logger); - const baseURL = getBaseURL(options.baseURL, options.basePath); - if (!baseURL) logger$1.warn(`[better-auth] Base URL could not be determined. Please set a valid base URL using the baseURL config option or the BETTER_AUTH_URL environment variable. Without this, callbacks and redirects may not work correctly.`); - if (adapter.id === "memory" && options.advanced?.database?.generateId === false) logger$1.error(`[better-auth] Misconfiguration detected. -You are using the memory DB with generateId: false. -This will cause no id to be generated for any model. -Most of the features of Better Auth will not work correctly.`); - const secret = options.secret || env.BETTER_AUTH_SECRET || env.AUTH_SECRET || DEFAULT_SECRET; - validateSecret(secret, logger$1); - options = { - ...options, - secret, - baseURL: baseURL ? new URL(baseURL).origin : "", - basePath: options.basePath || "/api/auth", - plugins: plugins.concat(internalPlugins) - }; - checkEndpointConflicts(options, logger$1); - const cookies = getCookies(options); - const tables = getAuthTables(options); - const providers = Object.entries(options.socialProviders || {}).map(([key, config2]) => { - if (config2 == null) return null; - if (config2.enabled === false) return null; - if (!config2.clientId) logger$1.warn(`Social provider ${key} is missing clientId or clientSecret`); - const provider = socialProviders[key](config2); - provider.disableImplicitSignUp = config2.disableImplicitSignUp; - return provider; - }).filter((x) => x !== null); - const generateIdFunc = ({ model, size }) => { - if (typeof options.advanced?.generateId === "function") return options.advanced.generateId({ - model, - size - }); - const dbGenerateId = options?.advanced?.database?.generateId; - if (typeof dbGenerateId === "function") return dbGenerateId({ - model, - size - }); - if (dbGenerateId === "uuid") return crypto.randomUUID(); - if (dbGenerateId === "serial" || dbGenerateId === false) return false; - return generateId(size); - }; - const { publish } = await createTelemetry(options, { - adapter: adapter.id, - database: typeof options.database === "function" ? "adapter" : getDatabaseType(options.database) - }); - const trustedOrigins = await getTrustedOrigins(options); - const initOrPromise = runPluginInit({ - appName: options.appName || "Better Auth", - baseURL: baseURL || "", - version: getBetterAuthVersion(), - socialProviders: providers, - options, - oauthConfig: { - storeStateStrategy: options.account?.storeStateStrategy || (options.database ? "database" : "cookie"), - skipStateCookieCheck: !!options.account?.skipStateCookieCheck - }, - tables, - trustedOrigins, - isTrustedOrigin(url, settings) { - return this.trustedOrigins.some((origin) => matchesOriginPattern(url, origin, settings)); - }, - sessionConfig: { - updateAge: options.session?.updateAge !== void 0 ? options.session.updateAge : 1440 * 60, - expiresIn: options.session?.expiresIn || 3600 * 24 * 7, - freshAge: options.session?.freshAge === void 0 ? 3600 * 24 : options.session.freshAge, - cookieRefreshCache: (() => { - const refreshCache = options.session?.cookieCache?.refreshCache; - const maxAge = options.session?.cookieCache?.maxAge || 300; - if ((!!options.database || !!options.secondaryStorage) && refreshCache) { - logger$1.warn("[better-auth] `session.cookieCache.refreshCache` is enabled while `database` or `secondaryStorage` is configured. `refreshCache` is meant for stateless (DB-less) setups. Disabling `refreshCache` — remove it from your config to silence this warning."); - return false; - } - if (refreshCache === false || refreshCache === void 0) return false; - if (refreshCache === true) return { - enabled: true, - updateAge: Math.floor(maxAge * 0.2) - }; - return { - enabled: true, - updateAge: refreshCache.updateAge !== void 0 ? refreshCache.updateAge : Math.floor(maxAge * 0.2) - }; - })() - }, - secret, - rateLimit: { - ...options.rateLimit, - enabled: options.rateLimit?.enabled ?? isProduction, - window: options.rateLimit?.window || 10, - max: options.rateLimit?.max || 100, - storage: options.rateLimit?.storage || (options.secondaryStorage ? "secondary-storage" : "memory") - }, - authCookies: cookies, - logger: logger$1, - generateId: generateIdFunc, - session: null, - secondaryStorage: options.secondaryStorage, - password: { - hash: options.emailAndPassword?.password?.hash || hashPassword, - verify: options.emailAndPassword?.password?.verify || verifyPassword$1, - config: { - minPasswordLength: options.emailAndPassword?.minPasswordLength || 8, - maxPasswordLength: options.emailAndPassword?.maxPasswordLength || 128 - }, - checkPassword - }, - setNewSession(session) { - this.newSession = session; - }, - newSession: null, - adapter, - internalAdapter: createInternalAdapter(adapter, { - options, - logger: logger$1, - hooks: options.databaseHooks ? [options.databaseHooks] : [], - generateId: generateIdFunc - }), - createAuthCookie: createCookieGetter(options), - async runMigrations() { - throw new BetterAuthError("runMigrations will be set by the specific init implementation"); - }, - publishTelemetry: publish, - skipCSRFCheck: !!options.advanced?.disableCSRFCheck, - skipOriginCheck: options.advanced?.disableOriginCheck !== void 0 ? options.advanced.disableOriginCheck : isTest() ? true : false, - runInBackground: options.advanced?.backgroundTasks?.handler ?? ((p) => { - p.catch(() => { - }); - }), - async runInBackgroundOrAwait(promise) { - try { - if (options.advanced?.backgroundTasks?.handler) { - if (promise instanceof Promise) options.advanced.backgroundTasks.handler(promise.catch((e) => { - logger$1.error("Failed to run background task:", e); - })); - } else await promise; - } catch (e) { - logger$1.error("Failed to run background task:", e); - } - }, - getPlugin: (id) => options.plugins.find((p) => p.id === id) ?? null - }); - let context; - if (isPromise(initOrPromise)) ({ context } = await initOrPromise); - else ({ context } = initOrPromise); - if (typeof context.options.emailVerification?.onEmailVerification === "function") context.options.emailVerification.onEmailVerification = deprecate(context.options.emailVerification.onEmailVerification, "Use `afterEmailVerification` instead. This will be removed in 1.5", context.logger); - return context; -} -const initMinimal = async (options) => { - const adapter = await getBaseAdapter(options, async () => { - throw new BetterAuthError("Direct database connection requires Kysely. Please use `better-auth` instead of `better-auth/minimal`, or provide an adapter (drizzleAdapter, prismaAdapter, etc.)"); - }); - const getDatabaseType = (_database) => "unknown"; - const ctx = await createAuthContext(adapter, options, getDatabaseType); - ctx.runMigrations = async function() { - throw new BetterAuthError("Migrations are not supported in 'better-auth/minimal'. Please use 'better-auth' for migration support."); - }; - return ctx; -}; -const betterAuth = (options) => { - return createBetterAuth(options, initMinimal); -}; -const drizzleAdapter = (db2, config2) => { - let lazyOptions = null; - const createCustomAdapter = (db$1) => ({ getFieldName, getDefaultFieldName, options }) => { - function getSchema2(model) { - const schema2 = config2.schema || db$1._.fullSchema; - if (!schema2) throw new BetterAuthError("Drizzle adapter failed to initialize. Schema not found. Please provide a schema object in the adapter options object."); - const schemaModel = schema2[model]; - if (!schemaModel) throw new BetterAuthError(`[# Drizzle Adapter]: The model "${model}" was not found in the schema object. Please pass the schema directly to the adapter options.`); - return schemaModel; - } - const withReturning = async (model, builder, data, where) => { - if (config2.provider !== "mysql") return (await builder.returning())[0]; - await builder.execute(); - const schemaModel = getSchema2(model); - const builderVal = builder.config?.values; - if (where?.length) { - const clause = convertWhereClause(where.map((w) => { - if (data[w.field] !== void 0) return { - ...w, - value: data[w.field] - }; - return w; - }), model); - return (await db$1.select().from(schemaModel).where(...clause))[0]; - } else if (builderVal && builderVal[0]?.id?.value) { - let tId = builderVal[0]?.id?.value; - if (!tId) tId = (await db$1.select({ id: sql$1`LAST_INSERT_ID()` }).from(schemaModel).orderBy(desc(schemaModel.id)).limit(1))[0].id; - return (await db$1.select().from(schemaModel).where(eq(schemaModel.id, tId)).limit(1).execute())[0]; - } else if (data.id) return (await db$1.select().from(schemaModel).where(eq(schemaModel.id, data.id)).limit(1).execute())[0]; - else { - if (!("id" in schemaModel)) throw new BetterAuthError(`The model "${model}" does not have an "id" field. Please use the "id" field as your primary key.`); - return (await db$1.select().from(schemaModel).orderBy(desc(schemaModel.id)).limit(1).execute())[0]; - } - }; - function convertWhereClause(where, model) { - const schemaModel = getSchema2(model); - if (!where) return []; - if (where.length === 1) { - const w = where[0]; - if (!w) return []; - const field = getFieldName({ - model, - field: w.field - }); - if (!schemaModel[field]) throw new BetterAuthError(`The field "${w.field}" does not exist in the schema for the model "${model}". Please update your schema.`); - if (w.operator === "in") { - if (!Array.isArray(w.value)) throw new BetterAuthError(`The value for the field "${w.field}" must be an array when using the "in" operator.`); - return [inArray(schemaModel[field], w.value)]; - } - if (w.operator === "not_in") { - if (!Array.isArray(w.value)) throw new BetterAuthError(`The value for the field "${w.field}" must be an array when using the "not_in" operator.`); - return [notInArray(schemaModel[field], w.value)]; - } - if (w.operator === "contains") return [like(schemaModel[field], `%${w.value}%`)]; - if (w.operator === "starts_with") return [like(schemaModel[field], `${w.value}%`)]; - if (w.operator === "ends_with") return [like(schemaModel[field], `%${w.value}`)]; - if (w.operator === "lt") return [lt(schemaModel[field], w.value)]; - if (w.operator === "lte") return [lte(schemaModel[field], w.value)]; - if (w.operator === "ne") return [ne(schemaModel[field], w.value)]; - if (w.operator === "gt") return [gt(schemaModel[field], w.value)]; - if (w.operator === "gte") return [gte(schemaModel[field], w.value)]; - return [eq(schemaModel[field], w.value)]; - } - const andGroup = where.filter((w) => w.connector === "AND" || !w.connector); - const orGroup = where.filter((w) => w.connector === "OR"); - const andClause = and(...andGroup.map((w) => { - const field = getFieldName({ - model, - field: w.field - }); - if (w.operator === "in") { - if (!Array.isArray(w.value)) throw new BetterAuthError(`The value for the field "${w.field}" must be an array when using the "in" operator.`); - return inArray(schemaModel[field], w.value); - } - if (w.operator === "not_in") { - if (!Array.isArray(w.value)) throw new BetterAuthError(`The value for the field "${w.field}" must be an array when using the "not_in" operator.`); - return notInArray(schemaModel[field], w.value); - } - if (w.operator === "contains") return like(schemaModel[field], `%${w.value}%`); - if (w.operator === "starts_with") return like(schemaModel[field], `${w.value}%`); - if (w.operator === "ends_with") return like(schemaModel[field], `%${w.value}`); - if (w.operator === "lt") return lt(schemaModel[field], w.value); - if (w.operator === "lte") return lte(schemaModel[field], w.value); - if (w.operator === "gt") return gt(schemaModel[field], w.value); - if (w.operator === "gte") return gte(schemaModel[field], w.value); - if (w.operator === "ne") return ne(schemaModel[field], w.value); - return eq(schemaModel[field], w.value); - })); - const orClause = or(...orGroup.map((w) => { - const field = getFieldName({ - model, - field: w.field - }); - if (w.operator === "in") { - if (!Array.isArray(w.value)) throw new BetterAuthError(`The value for the field "${w.field}" must be an array when using the "in" operator.`); - return inArray(schemaModel[field], w.value); - } - if (w.operator === "not_in") { - if (!Array.isArray(w.value)) throw new BetterAuthError(`The value for the field "${w.field}" must be an array when using the "not_in" operator.`); - return notInArray(schemaModel[field], w.value); - } - if (w.operator === "contains") return like(schemaModel[field], `%${w.value}%`); - if (w.operator === "starts_with") return like(schemaModel[field], `${w.value}%`); - if (w.operator === "ends_with") return like(schemaModel[field], `%${w.value}`); - if (w.operator === "lt") return lt(schemaModel[field], w.value); - if (w.operator === "lte") return lte(schemaModel[field], w.value); - if (w.operator === "gt") return gt(schemaModel[field], w.value); - if (w.operator === "gte") return gte(schemaModel[field], w.value); - if (w.operator === "ne") return ne(schemaModel[field], w.value); - return eq(schemaModel[field], w.value); - })); - const clause = []; - if (andGroup.length) clause.push(andClause); - if (orGroup.length) clause.push(orClause); - return clause; - } - function checkMissingFields(schema2, model, values) { - if (!schema2) throw new BetterAuthError("Drizzle adapter failed to initialize. Drizzle Schema not found. Please provide a schema object in the adapter options object."); - for (const key in values) if (!schema2[key]) throw new BetterAuthError(`The field "${key}" does not exist in the "${model}" Drizzle schema. Please update your drizzle schema or re-generate using "npx @better-auth/cli@latest generate".`); - } - return { - async create({ model, data: values }) { - const schemaModel = getSchema2(model); - checkMissingFields(schemaModel, model, values); - return await withReturning(model, db$1.insert(schemaModel).values(values), values); - }, - async findOne({ model, where, select, join }) { - const schemaModel = getSchema2(model); - const clause = convertWhereClause(where, model); - if (options.experimental?.joins) if (!db$1.query || !db$1.query[model]) { - logger.error(`[# Drizzle Adapter]: The model "${model}" was not found in the query object. Please update your Drizzle schema to include relations or re-generate using "npx @better-auth/cli@latest generate".`); - logger.info("Falling back to regular query"); - } else { - let includes; - const pluralJoinResults = []; - if (join) { - includes = {}; - const joinEntries = Object.entries(join); - for (const [model$1, joinAttr] of joinEntries) { - const limit = joinAttr.limit ?? options.advanced?.database?.defaultFindManyLimit ?? 100; - const isUnique = joinAttr.relation === "one-to-one"; - const pluralSuffix = isUnique || config2.usePlural ? "" : "s"; - includes[`${model$1}${pluralSuffix}`] = isUnique ? true : { limit }; - if (!isUnique) pluralJoinResults.push(`${model$1}${pluralSuffix}`); - } - } - const res$1 = await db$1.query[model].findFirst({ - where: clause[0], - columns: select?.length && select.length > 0 ? select.reduce((acc, field) => { - acc[getFieldName({ - model, - field - })] = true; - return acc; - }, {}) : void 0, - with: includes - }); - if (res$1) for (const pluralJoinResult of pluralJoinResults) { - const singularKey = !config2.usePlural ? pluralJoinResult.slice(0, -1) : pluralJoinResult; - res$1[singularKey] = res$1[pluralJoinResult]; - if (pluralJoinResult !== singularKey) delete res$1[pluralJoinResult]; - } - return res$1; - } - const res = await db$1.select(select?.length && select.length > 0 ? select.reduce((acc, field) => { - const fieldName = getFieldName({ - model, - field - }); - return { - ...acc, - [fieldName]: schemaModel[fieldName] - }; - }, {}) : void 0).from(schemaModel).where(...clause); - if (!res.length) return null; - return res[0]; - }, - async findMany({ model, where, sortBy, limit, select, offset, join }) { - const schemaModel = getSchema2(model); - const clause = where ? convertWhereClause(where, model) : []; - const sortFn = sortBy?.direction === "desc" ? desc : asc; - if (options.experimental?.joins) if (!db$1.query[model]) { - logger.error(`[# Drizzle Adapter]: The model "${model}" was not found in the query object. Please update your Drizzle schema to include relations or re-generate using "npx @better-auth/cli@latest generate".`); - logger.info("Falling back to regular query"); - } else { - let includes; - const pluralJoinResults = []; - if (join) { - includes = {}; - const joinEntries = Object.entries(join); - for (const [model$1, joinAttr] of joinEntries) { - const isUnique = joinAttr.relation === "one-to-one"; - const limit$1 = joinAttr.limit ?? options.advanced?.database?.defaultFindManyLimit ?? 100; - const pluralSuffix = isUnique || config2.usePlural ? "" : "s"; - includes[`${model$1}${pluralSuffix}`] = isUnique ? true : { limit: limit$1 }; - if (!isUnique) pluralJoinResults.push(`${model$1}${pluralSuffix}`); - } - } - let orderBy = void 0; - if (sortBy?.field) orderBy = [sortFn(schemaModel[getFieldName({ - model, - field: sortBy?.field - })])]; - const res = await db$1.query[model].findMany({ - where: clause[0], - with: includes, - columns: select?.length && select.length > 0 ? select.reduce((acc, field) => { - acc[getFieldName({ - model, - field - })] = true; - return acc; - }, {}) : void 0, - limit: limit ?? 100, - offset: offset ?? 0, - orderBy - }); - if (res) for (const item of res) for (const pluralJoinResult of pluralJoinResults) { - const singularKey = !config2.usePlural ? pluralJoinResult.slice(0, -1) : pluralJoinResult; - if (singularKey === pluralJoinResult) continue; - item[singularKey] = item[pluralJoinResult]; - delete item[pluralJoinResult]; - } - return res; - } - let builder = db$1.select(select?.length && select.length > 0 ? select.reduce((acc, field) => { - const fieldName = getFieldName({ - model, - field - }); - return { - ...acc, - [fieldName]: schemaModel[fieldName] - }; - }, {}) : void 0).from(schemaModel); - const effectiveLimit = limit; - const effectiveOffset = offset; - if (typeof effectiveLimit !== "undefined") builder = builder.limit(effectiveLimit); - if (typeof effectiveOffset !== "undefined") builder = builder.offset(effectiveOffset); - if (sortBy?.field) builder = builder.orderBy(sortFn(schemaModel[getFieldName({ - model, - field: sortBy?.field - })])); - return await builder.where(...clause); - }, - async count({ model, where }) { - const schemaModel = getSchema2(model); - const clause = where ? convertWhereClause(where, model) : []; - return (await db$1.select({ count: count() }).from(schemaModel).where(...clause))[0].count; - }, - async update({ model, where, update: values }) { - const schemaModel = getSchema2(model); - const clause = convertWhereClause(where, model); - return await withReturning(model, db$1.update(schemaModel).set(values).where(...clause), values, where); - }, - async updateMany({ model, where, update: values }) { - const schemaModel = getSchema2(model); - const clause = convertWhereClause(where, model); - return await db$1.update(schemaModel).set(values).where(...clause); - }, - async delete({ model, where }) { - const schemaModel = getSchema2(model); - const clause = convertWhereClause(where, model); - return await db$1.delete(schemaModel).where(...clause); - }, - async deleteMany({ model, where }) { - const schemaModel = getSchema2(model); - const clause = convertWhereClause(where, model); - const res = await db$1.delete(schemaModel).where(...clause); - let count$1 = 0; - if (res && "rowCount" in res) count$1 = res.rowCount; - else if (Array.isArray(res)) count$1 = res.length; - else if (res && ("affectedRows" in res || "rowsAffected" in res || "changes" in res)) count$1 = res.affectedRows ?? res.rowsAffected ?? res.changes; - if (typeof count$1 !== "number") logger.error("[Drizzle Adapter] The result of the deleteMany operation is not a number. This is likely a bug in the adapter. Please report this issue to the Better Auth team.", { - res, - model, - where - }); - return count$1; - }, - options: config2 - }; - }; - let adapterOptions = null; - adapterOptions = { - config: { - adapterId: "drizzle", - adapterName: "Drizzle Adapter", - usePlural: config2.usePlural ?? false, - debugLogs: config2.debugLogs ?? false, - supportsUUIDs: config2.provider === "pg" ? true : false, - supportsJSON: config2.provider === "pg" ? true : false, - supportsArrays: config2.provider === "pg" ? true : false, - transaction: config2.transaction ?? false ? (cb) => db2.transaction((tx) => { - return cb(createAdapterFactory({ - config: adapterOptions.config, - adapter: createCustomAdapter(tx) - })(lazyOptions)); - }) : false - }, - adapter: createCustomAdapter(db2) - }; - const adapter = createAdapterFactory(adapterOptions); - return (options) => { - lazyOptions = options; - return adapter(options); - }; -}; -const svelteKitHandler = async ({ auth: auth2, event, resolve, building }) => { - if (building) return resolve(event); - const { request, url } = event; - if (isAuthPath(url.toString(), auth2.options)) return auth2.handler(request); - return resolve(event); -}; -function isAuthPath(url, options) { - const _url = new URL(url); - const baseURL = new URL(`${options.baseURL || _url.origin}${options.basePath || "/api/auth"}`); - if (_url.origin !== baseURL.origin) return false; - if (!_url.pathname.startsWith(baseURL.pathname.endsWith("/") ? baseURL.pathname : `${baseURL.pathname}/`)) return false; - return true; -} -const sveltekitCookies = (getRequestEvent2) => { - return { - id: "sveltekit-cookies", - hooks: { after: [{ - matcher() { - return true; - }, - handler: createAuthMiddleware(async (ctx) => { - const returned = ctx.context.responseHeaders; - if ("_flag" in ctx && ctx._flag === "router") return; - if (returned instanceof Headers) { - const setCookies = returned?.get("set-cookie"); - if (!setCookies) return; - const event = getRequestEvent2(); - if (!event) return; - const parsed = parseSetCookieHeader(setCookies); - for (const [name, { value, ...ops }] of parsed) try { - event.cookies.set(name, decodeURIComponent(value), { - sameSite: ops.samesite, - path: ops.path || "/", - expires: ops.expires, - secure: ops.secure, - httpOnly: ops.httponly, - domain: ops.domain, - maxAge: ops["max-age"] - }); - } catch { - } - } - }) - }] } - }; -}; -defineErrorCodes({ - FAILED_TO_CREATE_USER: "Failed to create user", - USER_ALREADY_EXISTS: "User already exists.", - USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL: "User already exists. Use another email.", - YOU_CANNOT_BAN_YOURSELF: "You cannot ban yourself", - YOU_ARE_NOT_ALLOWED_TO_CHANGE_USERS_ROLE: "You are not allowed to change users role", - YOU_ARE_NOT_ALLOWED_TO_CREATE_USERS: "You are not allowed to create users", - YOU_ARE_NOT_ALLOWED_TO_LIST_USERS: "You are not allowed to list users", - YOU_ARE_NOT_ALLOWED_TO_LIST_USERS_SESSIONS: "You are not allowed to list users sessions", - YOU_ARE_NOT_ALLOWED_TO_BAN_USERS: "You are not allowed to ban users", - YOU_ARE_NOT_ALLOWED_TO_IMPERSONATE_USERS: "You are not allowed to impersonate users", - YOU_ARE_NOT_ALLOWED_TO_REVOKE_USERS_SESSIONS: "You are not allowed to revoke users sessions", - YOU_ARE_NOT_ALLOWED_TO_DELETE_USERS: "You are not allowed to delete users", - YOU_ARE_NOT_ALLOWED_TO_SET_USERS_PASSWORD: "You are not allowed to set users password", - BANNED_USER: "You have been banned from this application", - YOU_ARE_NOT_ALLOWED_TO_GET_USER: "You are not allowed to get user", - NO_DATA_TO_UPDATE: "No data to update", - YOU_ARE_NOT_ALLOWED_TO_UPDATE_USERS: "You are not allowed to update users", - YOU_CANNOT_REMOVE_YOURSELF: "You cannot remove yourself", - YOU_ARE_NOT_ALLOWED_TO_SET_NON_EXISTENT_VALUE: "You are not allowed to set a non-existent role value", - YOU_CANNOT_IMPERSONATE_ADMINS: "You cannot impersonate admins", - INVALID_ROLE_TYPE: "Invalid role type" -}); -createAuthMiddleware(async (ctx) => { - const session = await getSessionFromCtx(ctx); - if (!session) throw new APIError("UNAUTHORIZED"); - return { session }; -}); -z.object({ - userId: z.coerce.string().meta({ description: "The user id" }), - role: z.union([z.string().meta({ description: "The role to set. `admin` or `user` by default" }), z.array(z.string().meta({ description: "The roles to set. `admin` or `user` by default" }))]).meta({ description: "The role to set, this can be a string or an array of strings. Eg: `admin` or `[admin, user]`" }) -}); -z.object({ id: z.string().meta({ description: "The id of the User" }) }); -z.object({ - email: z.string().meta({ description: "The email of the user" }), - password: z.string().optional().meta({ description: "The password of the user. If not provided, the user will be created without a credential account (useful for magic link or social login only users)." }), - name: z.string().meta({ description: "The name of the user" }), - role: z.union([z.string().meta({ description: "The role of the user" }), z.array(z.string().meta({ description: "The roles of user" }))]).optional().meta({ description: `A string or array of strings representing the roles to apply to the new user. Eg: "user"` }), - data: z.record(z.string(), z.any()).optional().meta({ description: "Extra fields for the user. Including custom additional fields." }) -}); -z.object({ - userId: z.coerce.string().meta({ description: "The user id" }), - data: z.record(z.any(), z.any()).meta({ description: "The user data to update" }) -}); -z.object({ - searchValue: z.string().optional().meta({ description: 'The value to search for. Eg: "some name"' }), - searchField: z.enum(["email", "name"]).meta({ description: 'The field to search in, defaults to email. Can be `email` or `name`. Eg: "name"' }).optional(), - searchOperator: z.enum([ - "contains", - "starts_with", - "ends_with" - ]).meta({ description: 'The operator to use for the search. Can be `contains`, `starts_with` or `ends_with`. Eg: "contains"' }).optional(), - limit: z.string().meta({ description: "The number of users to return" }).or(z.number()).optional(), - offset: z.string().meta({ description: "The offset to start from" }).or(z.number()).optional(), - sortBy: z.string().meta({ description: "The field to sort by" }).optional(), - sortDirection: z.enum(["asc", "desc"]).meta({ description: "The direction to sort by" }).optional(), - filterField: z.string().meta({ description: "The field to filter by" }).optional(), - filterValue: z.string().meta({ description: "The value to filter by" }).or(z.number()).or(z.boolean()).optional(), - filterOperator: z.enum([ - "eq", - "ne", - "lt", - "lte", - "gt", - "gte", - "contains" - ]).meta({ description: "The operator to use for the filter" }).optional() -}); -z.object({ userId: z.coerce.string().meta({ description: "The user id" }) }); -z.object({ userId: z.coerce.string().meta({ description: "The user id" }) }); -z.object({ - userId: z.coerce.string().meta({ description: "The user id" }), - banReason: z.string().meta({ description: "The reason for the ban" }).optional(), - banExpiresIn: z.number().meta({ description: "The number of seconds until the ban expires" }).optional() -}); -z.object({ userId: z.coerce.string().meta({ description: "The user id" }) }); -z.object({ sessionToken: z.string().meta({ description: "The session token" }) }); -z.object({ userId: z.coerce.string().meta({ description: "The user id" }) }); -z.object({ userId: z.coerce.string().meta({ description: "The user id" }) }); -z.object({ - newPassword: z.string().nonempty("newPassword cannot be empty").meta({ description: "The new password" }), - userId: z.coerce.string().nonempty("userId cannot be empty").meta({ description: "The user id" }) -}); -z.object({ - userId: z.coerce.string().optional().meta({ description: `The user id. Eg: "user-id"` }), - role: z.string().optional().meta({ description: `The role to check permission for. Eg: "admin"` }) -}).and(z.union([z.object({ - permission: z.record(z.string(), z.array(z.string())), - permissions: z.undefined() -}), z.object({ - permission: z.undefined(), - permissions: z.record(z.string(), z.array(z.string())) -})])); -defineErrorCodes({ - INVALID_EMAIL_FORMAT: "Email was not generated in a valid format", - FAILED_TO_CREATE_USER: "Failed to create user", - COULD_NOT_CREATE_SESSION: "Could not create session", - ANONYMOUS_USERS_CANNOT_SIGN_IN_AGAIN_ANONYMOUSLY: "Anonymous users cannot sign in again anonymously", - FAILED_TO_DELETE_ANONYMOUS_USER: "Failed to delete anonymous user", - USER_IS_NOT_ANONYMOUS: "User is not anonymous", - DELETE_ANONYMOUS_USER_DISABLED: "Deleting anonymous users is disabled" -}); -z.object({ - key: z.string().meta({ description: "The key to verify" }), - permissions: z.record(z.string(), z.array(z.string())).meta({ description: "The permissions to verify." }).optional() -}); -z.object({ - name: z.string().meta({ description: "Name of the Api Key" }).optional(), - expiresIn: z.number().meta({ description: "Expiration time of the Api Key in seconds" }).min(1).optional().nullable().default(null), - userId: z.coerce.string().meta({ description: 'User Id of the user that the Api Key belongs to. server-only. Eg: "user-id"' }).optional(), - prefix: z.string().meta({ description: "Prefix of the Api Key" }).regex(/^[a-zA-Z0-9_-]+$/, { message: "Invalid prefix format, must be alphanumeric and contain only underscores and hyphens." }).optional(), - remaining: z.number().meta({ description: "Remaining number of requests. Server side only" }).min(0).optional().nullable().default(null), - metadata: z.any().optional(), - refillAmount: z.number().meta({ description: "Amount to refill the remaining count of the Api Key. server-only. Eg: 100" }).min(1).optional(), - refillInterval: z.number().meta({ description: "Interval to refill the Api Key in milliseconds. server-only. Eg: 1000" }).optional(), - rateLimitTimeWindow: z.number().meta({ description: "The duration in milliseconds where each request is counted. Once the `maxRequests` is reached, the request will be rejected until the `timeWindow` has passed, at which point the `timeWindow` will be reset. server-only. Eg: 1000" }).optional(), - rateLimitMax: z.number().meta({ description: "Maximum amount of requests allowed within a window. Once the `maxRequests` is reached, the request will be rejected until the `timeWindow` has passed, at which point the `timeWindow` will be reset. server-only. Eg: 100" }).optional(), - rateLimitEnabled: z.boolean().meta({ description: "Whether the key has rate limiting enabled. server-only. Eg: true" }).optional(), - permissions: z.record(z.string(), z.array(z.string())).meta({ description: "Permissions of the Api Key." }).optional() -}); -z.object({ keyId: z.string().meta({ description: "The id of the Api Key" }) }); -z.object({ id: z.string().meta({ description: "The id of the Api Key" }) }); -z.object({ - keyId: z.string().meta({ description: "The id of the Api Key" }), - userId: z.coerce.string().meta({ description: 'The id of the user which the api key belongs to. server-only. Eg: "some-user-id"' }).optional(), - name: z.string().meta({ description: "The name of the key" }).optional(), - enabled: z.boolean().meta({ description: "Whether the Api Key is enabled or not" }).optional(), - remaining: z.number().meta({ description: "The number of remaining requests" }).min(1).optional(), - refillAmount: z.number().meta({ description: "The refill amount" }).optional(), - refillInterval: z.number().meta({ description: "The refill interval" }).optional(), - metadata: z.any().optional(), - expiresIn: z.number().meta({ description: "Expiration time of the Api Key in seconds" }).min(1).optional().nullable(), - rateLimitEnabled: z.boolean().meta({ description: "Whether the key has rate limiting enabled." }).optional(), - rateLimitTimeWindow: z.number().meta({ description: "The duration in milliseconds where each request is counted. server-only. Eg: 1000" }).optional(), - rateLimitMax: z.number().meta({ description: "Maximum amount of requests allowed within a window. Once the `maxRequests` is reached, the request will be rejected until the `timeWindow` has passed, at which point the `timeWindow` will be reset. server-only. Eg: 100" }).optional(), - permissions: z.record(z.string(), z.array(z.string())).meta({ description: "Update the permissions on the API Key. server-only." }).optional().nullable() -}); -defineErrorCodes({ - INVALID_METADATA_TYPE: "metadata must be an object or undefined", - REFILL_AMOUNT_AND_INTERVAL_REQUIRED: "refillAmount is required when refillInterval is provided", - REFILL_INTERVAL_AND_AMOUNT_REQUIRED: "refillInterval is required when refillAmount is provided", - USER_BANNED: "User is banned", - UNAUTHORIZED_SESSION: "Unauthorized or invalid session", - KEY_NOT_FOUND: "API Key not found", - KEY_DISABLED: "API Key is disabled", - KEY_EXPIRED: "API Key has expired", - USAGE_EXCEEDED: "API Key has reached its usage limit", - KEY_NOT_RECOVERABLE: "API Key is not recoverable", - EXPIRES_IN_IS_TOO_SMALL: "The expiresIn is smaller than the predefined minimum value.", - EXPIRES_IN_IS_TOO_LARGE: "The expiresIn is larger than the predefined maximum value.", - INVALID_REMAINING: "The remaining count is either too large or too small.", - INVALID_PREFIX_LENGTH: "The prefix length is either too large or too small.", - INVALID_NAME_LENGTH: "The name length is either too large or too small.", - METADATA_DISABLED: "Metadata is disabled.", - RATE_LIMIT_EXCEEDED: "Rate limit exceeded.", - NO_VALUES_TO_UPDATE: "No values to update.", - KEY_DISABLED_EXPIRATION: "Custom key expiration values are disabled.", - INVALID_API_KEY: "Invalid API key.", - INVALID_USER_ID_FROM_API_KEY: "The user id from the API key is invalid.", - INVALID_API_KEY_GETTER_RETURN_TYPE: "API Key getter returned an invalid key type. Expected string.", - SERVER_ONLY_PROPERTY: "The property you're trying to set can only be set from the server auth instance only.", - FAILED_TO_UPDATE_API_KEY: "Failed to update API key", - NAME_REQUIRED: "API Key name is required." -}); -defineErrorCodes({ - VERIFICATION_FAILED: "Captcha verification failed", - MISSING_RESPONSE: "Missing CAPTCHA response", - UNKNOWN_ERROR: "Something went wrong" -}); -defineErrorCodes({ - MISSING_SECRET_KEY: "Missing secret key", - SERVICE_UNAVAILABLE: "CAPTCHA service unavailable" -}); -z.optional(z.object({ - disableCookieCache: z.boolean().meta({ description: "Disable cookie cache and fetch session from database" }).or(z.string().transform((v) => v === "true")).optional(), - disableRefresh: z.boolean().meta({ description: "Disable session refresh. Useful for checking session status, without updating the session" }).optional() -})); -const DEVICE_AUTHORIZATION_ERROR_CODES = defineErrorCodes({ - INVALID_DEVICE_CODE: "Invalid device code", - EXPIRED_DEVICE_CODE: "Device code has expired", - EXPIRED_USER_CODE: "User code has expired", - AUTHORIZATION_PENDING: "Authorization pending", - ACCESS_DENIED: "Access denied", - INVALID_USER_CODE: "Invalid user code", - DEVICE_CODE_ALREADY_PROCESSED: "Device code already processed", - POLLING_TOO_FREQUENTLY: "Polling too frequently", - USER_NOT_FOUND: "User not found", - FAILED_TO_CREATE_SESSION: "Failed to create session", - INVALID_DEVICE_CODE_STATUS: "Invalid device code status", - AUTHENTICATION_REQUIRED: "Authentication required" -}); -z.object({ - client_id: z.string().meta({ description: "The client ID of the application" }), - scope: z.string().meta({ description: "Space-separated list of scopes" }).optional() -}); -z.object({ - error: z.enum(["invalid_request", "invalid_client"]).meta({ description: "Error code" }), - error_description: z.string().meta({ description: "Detailed error description" }) -}); -z.object({ - grant_type: z.literal("urn:ietf:params:oauth:grant-type:device_code").meta({ description: "The grant type for device flow" }), - device_code: z.string().meta({ description: "The device verification code" }), - client_id: z.string().meta({ description: "The client ID of the application" }) -}); -z.object({ - error: z.enum([ - "authorization_pending", - "slow_down", - "expired_token", - "access_denied", - "invalid_request", - "invalid_grant" - ]).meta({ description: "Error code" }), - error_description: z.string().meta({ description: "Detailed error description" }) -}); -createAuthEndpoint("/device", { - method: "GET", - query: z.object({ user_code: z.string().meta({ description: "The user code to verify" }) }), - error: z.object({ - error: z.enum(["invalid_request"]).meta({ description: "Error code" }), - error_description: z.string().meta({ description: "Detailed error description" }) - }), - metadata: { openapi: { - description: "Verify user code and get device authorization status", - responses: { 200: { - description: "Device authorization status", - content: { "application/json": { schema: { - type: "object", - properties: { - user_code: { - type: "string", - description: "The user code to verify" - }, - status: { - type: "string", - enum: [ - "pending", - "approved", - "denied" - ], - description: "Current status of the device authorization" - } - } - } } } - } } - } } -}, async (ctx) => { - const { user_code } = ctx.query; - const cleanUserCode = user_code.replace(/-/g, ""); - const deviceCodeRecord = await ctx.context.adapter.findOne({ - model: "deviceCode", - where: [{ - field: "userCode", - value: cleanUserCode - }] - }); - if (!deviceCodeRecord) throw new APIError("BAD_REQUEST", { - error: "invalid_request", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.INVALID_USER_CODE - }); - if (deviceCodeRecord.expiresAt < /* @__PURE__ */ new Date()) throw new APIError("BAD_REQUEST", { - error: "expired_token", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.EXPIRED_USER_CODE - }); - return ctx.json({ - user_code, - status: deviceCodeRecord.status - }); -}); -createAuthEndpoint("/device/approve", { - method: "POST", - body: z.object({ userCode: z.string().meta({ description: "The user code to approve" }) }), - error: z.object({ - error: z.enum([ - "invalid_request", - "expired_token", - "device_code_already_processed", - "unauthorized", - "access_denied" - ]).meta({ description: "Error code" }), - error_description: z.string().meta({ description: "Detailed error description" }) - }), - requireHeaders: true, - metadata: { openapi: { - description: "Approve device authorization", - responses: { 200: { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { success: { type: "boolean" } } - } } } - } } - } } -}, async (ctx) => { - const session = await getSessionFromCtx(ctx); - if (!session) throw new APIError("UNAUTHORIZED", { - error: "unauthorized", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.AUTHENTICATION_REQUIRED - }); - const { userCode } = ctx.body; - const cleanUserCode = userCode.replace(/-/g, ""); - const deviceCodeRecord = await ctx.context.adapter.findOne({ - model: "deviceCode", - where: [{ - field: "userCode", - value: cleanUserCode - }] - }); - if (!deviceCodeRecord) throw new APIError("BAD_REQUEST", { - error: "invalid_request", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.INVALID_USER_CODE - }); - if (deviceCodeRecord.expiresAt < /* @__PURE__ */ new Date()) throw new APIError("BAD_REQUEST", { - error: "expired_token", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.EXPIRED_USER_CODE - }); - if (deviceCodeRecord.status !== "pending") throw new APIError("BAD_REQUEST", { - error: "invalid_request", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.DEVICE_CODE_ALREADY_PROCESSED - }); - if (deviceCodeRecord.userId && deviceCodeRecord.userId !== session.user.id) throw new APIError("FORBIDDEN", { - error: "access_denied", - error_description: "You are not authorized to approve this device authorization" - }); - await ctx.context.adapter.update({ - model: "deviceCode", - where: [{ - field: "id", - value: deviceCodeRecord.id - }], - update: { - status: "approved", - userId: session.user.id - } - }); - return ctx.json({ success: true }); -}); -createAuthEndpoint("/device/deny", { - method: "POST", - body: z.object({ userCode: z.string().meta({ description: "The user code to deny" }) }), - error: z.object({ - error: z.enum([ - "invalid_request", - "expired_token", - "unauthorized", - "access_denied" - ]).meta({ description: "Error code" }), - error_description: z.string().meta({ description: "Detailed error description" }) - }), - requireHeaders: true, - metadata: { openapi: { - description: "Deny device authorization", - responses: { 200: { - description: "Success", - content: { "application/json": { schema: { - type: "object", - properties: { success: { type: "boolean" } } - } } } - } } - } } -}, async (ctx) => { - const session = await getSessionFromCtx(ctx); - if (!session) throw new APIError("UNAUTHORIZED", { - error: "unauthorized", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.AUTHENTICATION_REQUIRED - }); - const { userCode } = ctx.body; - const cleanUserCode = userCode.replace(/-/g, ""); - const deviceCodeRecord = await ctx.context.adapter.findOne({ - model: "deviceCode", - where: [{ - field: "userCode", - value: cleanUserCode - }] - }); - if (!deviceCodeRecord) throw new APIError("BAD_REQUEST", { - error: "invalid_request", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.INVALID_USER_CODE - }); - if (deviceCodeRecord.expiresAt < /* @__PURE__ */ new Date()) throw new APIError("BAD_REQUEST", { - error: "expired_token", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.EXPIRED_USER_CODE - }); - if (deviceCodeRecord.status !== "pending") throw new APIError("BAD_REQUEST", { - error: "invalid_request", - error_description: DEVICE_AUTHORIZATION_ERROR_CODES.DEVICE_CODE_ALREADY_PROCESSED - }); - if (deviceCodeRecord.userId && deviceCodeRecord.userId !== session.user.id) throw new APIError("FORBIDDEN", { - error: "access_denied", - error_description: "You are not authorized to deny this device authorization" - }); - await ctx.context.adapter.update({ - model: "deviceCode", - where: [{ - field: "id", - value: deviceCodeRecord.id - }], - update: { - status: "denied", - userId: deviceCodeRecord.userId || session.user.id - } - }); - return ctx.json({ success: true }); -}); -z.object({ - id: z.string(), - deviceCode: z.string(), - userCode: z.string(), - userId: z.string().optional(), - expiresAt: z.date(), - status: z.string(), - lastPolledAt: z.date().optional(), - pollingInterval: z.number().optional(), - clientId: z.string().optional(), - scope: z.string().optional() -}); -const timeStringSchema = z.custom((val) => { - if (typeof val !== "string") return false; - try { - ms(val); - return true; - } catch { - return false; - } -}, { message: "Invalid time string format. Use formats like '30m', '5s', '1h', etc." }); -z.object({ - expiresIn: timeStringSchema.default("30m").describe("Time in seconds until the device code expires. Use formats like '30m', '5s', '1h', etc."), - interval: timeStringSchema.default("5s").describe("Time in seconds between polling attempts. Use formats like '30m', '5s', '1h', etc."), - deviceCodeLength: z.number().int().positive().default(40).describe("Length of the device code to be generated. Default is 40 characters."), - userCodeLength: z.number().int().positive().default(8).describe("Length of the user code to be generated. Default is 8 characters."), - generateDeviceCode: z.custom((val) => typeof val === "function", { message: "generateDeviceCode must be a function that returns a string or a promise that resolves to a string." }).optional().describe("Function to generate a device code. If not provided, a default random string generator will be used."), - generateUserCode: z.custom((val) => typeof val === "function", { message: "generateUserCode must be a function that returns a string or a promise that resolves to a string." }).optional().describe("Function to generate a user code. If not provided, a default random string generator will be used."), - validateClient: z.custom((val) => typeof val === "function", { message: "validateClient must be a function that returns a boolean or a promise that resolves to a boolean." }).optional().describe("Function to validate the client ID. If not provided, no validation will be performed."), - onDeviceAuthRequest: z.custom((val) => typeof val === "function", { message: "onDeviceAuthRequest must be a function that returns void or a promise that resolves to void." }).optional().describe("Function to handle device authorization requests. If not provided, no additional actions will be taken."), - verificationUri: z.string().optional().describe("The URI where users verify their device code. Can be an absolute URL (https://example.com/device) or relative path (/custom-path). This will be returned as verification_uri in the device code response. If not provided, defaults to /device."), - schema: z.custom(() => true) -}); -const types = [ - "email-verification", - "sign-in", - "forget-password" -]; -defineErrorCodes({ - OTP_EXPIRED: "OTP expired", - INVALID_OTP: "Invalid OTP", - TOO_MANY_ATTEMPTS: "Too many attempts" -}); -z.object({ - email: z.string({}).meta({ description: "Email address to send the OTP" }), - type: z.enum(types).meta({ description: "Type of the OTP" }) -}); -z.object({ - email: z.string({}).meta({ description: "Email address to send the OTP" }), - type: z.enum(types).meta({ - required: true, - description: "Type of the OTP" - }) -}); -z.object({ - email: z.string({}).meta({ description: "Email address the OTP was sent to" }), - type: z.enum(types).meta({ - required: true, - description: "Type of the OTP" - }) -}); -z.object({ - email: z.string().meta({ description: "Email address the OTP was sent to" }), - type: z.enum(types).meta({ - required: true, - description: "Type of the OTP" - }), - otp: z.string().meta({ - required: true, - description: "OTP to verify" - }) -}); -z.object({ - email: z.string({}).meta({ description: "Email address to verify" }), - otp: z.string().meta({ - required: true, - description: "OTP to verify" - }) -}); -z.object({ - email: z.string({}).meta({ description: "Email address to sign in" }), - otp: z.string().meta({ - required: true, - description: "OTP sent to the email" - }) -}); -z.object({ email: z.string().meta({ description: "Email address to send the OTP" }) }); -z.object({ email: z.string().meta({ description: "Email address to send the OTP" }) }); -z.object({ - email: z.string().meta({ description: "Email address to reset the password" }), - otp: z.string().meta({ description: "OTP sent to the email" }), - password: z.string().meta({ description: "New password" }) -}); -const GENERIC_OAUTH_ERROR_CODES = defineErrorCodes({ - INVALID_OAUTH_CONFIGURATION: "Invalid OAuth configuration", - TOKEN_URL_NOT_FOUND: "Invalid OAuth configuration. Token URL not found.", - PROVIDER_CONFIG_NOT_FOUND: "No config found for provider", - PROVIDER_ID_REQUIRED: "Provider ID is required", - INVALID_OAUTH_CONFIG: "Invalid OAuth configuration.", - SESSION_REQUIRED: "Session is required", - ISSUER_MISMATCH: "OAuth issuer mismatch. The authorization server issuer does not match the expected value (RFC 9207).", - ISSUER_MISSING: "OAuth issuer parameter missing. The authorization server did not include the required iss parameter (RFC 9207)." -}); -const signInWithOAuth2BodySchema = z.object({ - providerId: z.string().meta({ description: "The provider ID for the OAuth provider" }), - callbackURL: z.string().meta({ description: "The URL to redirect to after sign in" }).optional(), - errorCallbackURL: z.string().meta({ description: "The URL to redirect to if an error occurs" }).optional(), - newUserCallbackURL: z.string().meta({ description: 'The URL to redirect to after login if the user is new. Eg: "/welcome"' }).optional(), - disableRedirect: z.boolean().meta({ description: "Disable redirect" }).optional(), - scopes: z.array(z.string()).meta({ description: "Scopes to be passed to the provider authorization request." }).optional(), - requestSignUp: z.boolean().meta({ description: "Explicitly request sign-up. Useful when disableImplicitSignUp is true for this provider. Eg: false" }).optional(), - additionalData: z.record(z.string(), z.any()).optional() -}); -const signInWithOAuth2 = (options) => createAuthEndpoint("/sign-in/oauth2", { - method: "POST", - body: signInWithOAuth2BodySchema, - metadata: { openapi: { - description: "Sign in with OAuth2", - responses: { 200: { - description: "Sign in with OAuth2", - content: { "application/json": { schema: { - type: "object", - properties: { - url: { type: "string" }, - redirect: { type: "boolean" } - } - } } } - } } - } } -}, async (ctx) => { - const { providerId } = ctx.body; - const config2 = options.config.find((c) => c.providerId === providerId); - if (!config2) throw new APIError("BAD_REQUEST", { message: `${GENERIC_OAUTH_ERROR_CODES.PROVIDER_CONFIG_NOT_FOUND} ${providerId}` }); - const { discoveryUrl, authorizationUrl, tokenUrl, clientId, clientSecret, scopes, redirectURI, responseType, pkce, prompt, accessType, authorizationUrlParams, responseMode } = config2; - let finalAuthUrl = authorizationUrl; - let finalTokenUrl = tokenUrl; - if (discoveryUrl) { - const discovery = await betterFetch(discoveryUrl, { - method: "GET", - headers: config2.discoveryHeaders, - onError(context) { - ctx.context.logger.error(context.error.message, context.error, { discoveryUrl }); - } - }); - if (discovery.data) { - finalAuthUrl = discovery.data.authorization_endpoint; - finalTokenUrl = discovery.data.token_endpoint; - } - } - if (!finalAuthUrl || !finalTokenUrl) throw new APIError("BAD_REQUEST", { message: GENERIC_OAUTH_ERROR_CODES.INVALID_OAUTH_CONFIGURATION }); - if (authorizationUrlParams) { - const withAdditionalParams = new URL(finalAuthUrl); - for (const [paramName, paramValue] of Object.entries(authorizationUrlParams)) withAdditionalParams.searchParams.set(paramName, paramValue); - finalAuthUrl = withAdditionalParams.toString(); - } - const additionalParams = typeof authorizationUrlParams === "function" ? authorizationUrlParams(ctx) : authorizationUrlParams; - const { state, codeVerifier } = await generateState(ctx, void 0, ctx.body.additionalData); - const authUrl = await createAuthorizationURL({ - id: providerId, - options: { - clientId, - clientSecret, - redirectURI - }, - authorizationEndpoint: finalAuthUrl, - state, - codeVerifier: pkce ? codeVerifier : void 0, - scopes: ctx.body.scopes ? [...ctx.body.scopes, ...scopes || []] : scopes || [], - redirectURI: `${ctx.context.baseURL}/oauth2/callback/${providerId}`, - prompt, - accessType, - responseType, - responseMode, - additionalParams - }); - return ctx.json({ - url: authUrl.toString(), - redirect: !ctx.body.disableRedirect - }); -}); -const OAuth2CallbackQuerySchema = z.object({ - code: z.string().meta({ description: "The OAuth2 code" }).optional(), - error: z.string().meta({ description: "The error message, if any" }).optional(), - error_description: z.string().meta({ description: "The error description, if any" }).optional(), - state: z.string().meta({ description: "The state parameter from the OAuth2 request" }).optional(), - iss: z.string().meta({ description: "The issuer identifier" }).optional() -}); -const oAuth2Callback = (options) => createAuthEndpoint("/oauth2/callback/:providerId", { - method: "GET", - query: OAuth2CallbackQuerySchema, - metadata: { - ...HIDE_METADATA, - allowedMediaTypes: ["application/x-www-form-urlencoded", "application/json"], - openapi: { - description: "OAuth2 callback", - responses: { 200: { - description: "OAuth2 callback", - content: { "application/json": { schema: { - type: "object", - properties: { url: { type: "string" } } - } } } - } } - } - } -}, async (ctx) => { - const defaultErrorURL = ctx.context.options.onAPIError?.errorURL || `${ctx.context.baseURL}/error`; - if (ctx.query.error || !ctx.query.code) throw ctx.redirect(`${defaultErrorURL}?error=${ctx.query.error || "oAuth_code_missing"}&error_description=${ctx.query.error_description}`); - const providerId = ctx.params?.providerId; - if (!providerId) throw new APIError("BAD_REQUEST", { message: GENERIC_OAUTH_ERROR_CODES.PROVIDER_ID_REQUIRED }); - const providerConfig = options.config.find((p) => p.providerId === providerId); - if (!providerConfig) throw new APIError("BAD_REQUEST", { message: `${GENERIC_OAUTH_ERROR_CODES.PROVIDER_CONFIG_NOT_FOUND} ${providerId}` }); - let tokens = void 0; - const { callbackURL, codeVerifier, errorURL, requestSignUp, newUserURL, link } = await parseState(ctx); - const code = ctx.query.code; - function redirectOnError(error2) { - const defaultErrorURL$1 = ctx.context.options.onAPIError?.errorURL || `${ctx.context.baseURL}/error`; - let url = errorURL || defaultErrorURL$1; - if (url.includes("?")) url = `${url}&error=${error2}`; - else url = `${url}?error=${error2}`; - throw ctx.redirect(url); - } - let finalTokenUrl = providerConfig.tokenUrl; - let finalUserInfoUrl = providerConfig.userInfoUrl; - let expectedIssuer = providerConfig.issuer; - if (providerConfig.discoveryUrl) { - const discovery = await betterFetch(providerConfig.discoveryUrl, { - method: "GET", - headers: providerConfig.discoveryHeaders - }); - if (discovery.data) { - finalTokenUrl = discovery.data.token_endpoint; - finalUserInfoUrl = discovery.data.userinfo_endpoint; - if (!expectedIssuer && discovery.data.issuer) expectedIssuer = discovery.data.issuer; - } - } - if (expectedIssuer) { - if (ctx.query.iss) { - if (ctx.query.iss !== expectedIssuer) { - ctx.context.logger.error("OAuth issuer mismatch", { - expected: expectedIssuer, - received: ctx.query.iss - }); - return redirectOnError("issuer_mismatch"); - } - } else if (providerConfig.requireIssuerValidation) { - ctx.context.logger.error("OAuth issuer parameter missing", { expected: expectedIssuer }); - return redirectOnError("issuer_missing"); - } - } - try { - if (providerConfig.getToken) tokens = await providerConfig.getToken({ - code, - redirectURI: `${ctx.context.baseURL}/oauth2/callback/${providerConfig.providerId}`, - codeVerifier: providerConfig.pkce ? codeVerifier : void 0 - }); - else { - if (!finalTokenUrl) throw new APIError("BAD_REQUEST", { message: GENERIC_OAUTH_ERROR_CODES.INVALID_OAUTH_CONFIG }); - const additionalParams = typeof providerConfig.tokenUrlParams === "function" ? providerConfig.tokenUrlParams(ctx) : providerConfig.tokenUrlParams; - tokens = await validateAuthorizationCode({ - headers: providerConfig.authorizationHeaders, - code, - codeVerifier: providerConfig.pkce ? codeVerifier : void 0, - redirectURI: `${ctx.context.baseURL}/oauth2/callback/${providerConfig.providerId}`, - options: { - clientId: providerConfig.clientId, - clientSecret: providerConfig.clientSecret, - redirectURI: providerConfig.redirectURI - }, - tokenEndpoint: finalTokenUrl, - authentication: providerConfig.authentication, - additionalParams - }); - } - } catch (e) { - ctx.context.logger.error(e && typeof e === "object" && "name" in e ? e.name : "", e); - throw redirectOnError("oauth_code_verification_failed"); - } - if (!tokens) throw new APIError("BAD_REQUEST", { message: GENERIC_OAUTH_ERROR_CODES.INVALID_OAUTH_CONFIG }); - const userInfo = await (async function handleUserInfo() { - const userInfo$1 = providerConfig.getUserInfo ? await providerConfig.getUserInfo(tokens) : await getUserInfo(tokens, finalUserInfoUrl); - if (!userInfo$1) throw redirectOnError("user_info_is_missing"); - const mapUser = providerConfig.mapProfileToUser ? await providerConfig.mapProfileToUser(userInfo$1) : userInfo$1; - const email = mapUser.email ? mapUser.email.toLowerCase() : userInfo$1.email?.toLowerCase(); - if (!email) { - ctx.context.logger.error("Unable to get user info", userInfo$1); - throw redirectOnError("email_is_missing"); - } - const id = mapUser.id ? String(mapUser.id) : String(userInfo$1.id); - const name = mapUser.name ? mapUser.name : userInfo$1.name; - if (!name) { - ctx.context.logger.error("Unable to get user info", userInfo$1); - throw redirectOnError("name_is_missing"); - } - return { - ...userInfo$1, - ...mapUser, - email, - id, - name - }; - })(); - if (link) { - if (ctx.context.options.account?.accountLinking?.allowDifferentEmails !== true && link.email.toLowerCase() !== userInfo.email.toLowerCase()) return redirectOnError("email_doesn't_match"); - const existingAccount = await ctx.context.internalAdapter.findAccountByProviderId(String(userInfo.id), providerConfig.providerId); - if (existingAccount) { - if (existingAccount.userId !== link.userId) return redirectOnError("account_already_linked_to_different_user"); - const updateData = Object.fromEntries(Object.entries({ - accessToken: await setTokenUtil(tokens.accessToken, ctx.context), - idToken: tokens.idToken, - refreshToken: await setTokenUtil(tokens.refreshToken, ctx.context), - accessTokenExpiresAt: tokens.accessTokenExpiresAt, - refreshTokenExpiresAt: tokens.refreshTokenExpiresAt, - scope: tokens.scopes?.join(",") - }).filter(([_, value]) => value !== void 0)); - await ctx.context.internalAdapter.updateAccount(existingAccount.id, updateData); - } else if (!await ctx.context.internalAdapter.createAccount({ - userId: link.userId, - providerId: providerConfig.providerId, - accountId: userInfo.id, - accessToken: await setTokenUtil(tokens.accessToken, ctx.context), - accessTokenExpiresAt: tokens.accessTokenExpiresAt, - refreshTokenExpiresAt: tokens.refreshTokenExpiresAt, - scope: tokens.scopes?.join(","), - refreshToken: await setTokenUtil(tokens.refreshToken, ctx.context), - idToken: tokens.idToken - })) return redirectOnError("unable_to_link_account"); - let toRedirectTo$1; - try { - toRedirectTo$1 = callbackURL.toString(); - } catch { - toRedirectTo$1 = callbackURL; - } - throw ctx.redirect(toRedirectTo$1); - } - const result = await handleOAuthUserInfo(ctx, { - userInfo, - account: { - providerId: providerConfig.providerId, - accountId: userInfo.id, - ...tokens, - scope: tokens.scopes?.join(",") - }, - callbackURL, - disableSignUp: providerConfig.disableImplicitSignUp && !requestSignUp || providerConfig.disableSignUp, - overrideUserInfo: providerConfig.overrideUserInfo - }); - if (result.error) return redirectOnError(result.error.split(" ").join("_")); - const { session, user } = result.data; - await setSessionCookie(ctx, { - session, - user - }); - let toRedirectTo; - try { - toRedirectTo = (result.isRegister ? newUserURL || callbackURL : callbackURL).toString(); - } catch { - toRedirectTo = result.isRegister ? newUserURL || callbackURL : callbackURL; - } - throw ctx.redirect(toRedirectTo); -}); -const OAuth2LinkAccountBodySchema = z.object({ - providerId: z.string(), - callbackURL: z.string(), - scopes: z.array(z.string()).meta({ description: "Additional scopes to request when linking the account" }).optional(), - errorCallbackURL: z.string().meta({ description: "The URL to redirect to if there is an error during the link process" }).optional() -}); -const oAuth2LinkAccount = (options) => createAuthEndpoint("/oauth2/link", { - method: "POST", - body: OAuth2LinkAccountBodySchema, - use: [sessionMiddleware], - metadata: { openapi: { - description: "Link an OAuth2 account to the current user session", - responses: { "200": { - description: "Authorization URL generated successfully for linking an OAuth2 account", - content: { "application/json": { schema: { - type: "object", - properties: { - url: { - type: "string", - format: "uri", - description: "The authorization URL to redirect the user to for linking the OAuth2 account" - }, - redirect: { - type: "boolean", - description: "Indicates that the client should redirect to the provided URL", - enum: [true] - } - }, - required: ["url", "redirect"] - } } } - } } - } } -}, async (c) => { - const session = c.context.session; - if (!session) throw new APIError("UNAUTHORIZED", { message: GENERIC_OAUTH_ERROR_CODES.SESSION_REQUIRED }); - const provider = options.config.find((p) => p.providerId === c.body.providerId); - if (!provider) throw new APIError("NOT_FOUND", { message: BASE_ERROR_CODES.PROVIDER_NOT_FOUND }); - const { providerId, clientId, clientSecret, redirectURI, authorizationUrl, discoveryUrl, pkce, scopes, prompt, accessType, authorizationUrlParams } = provider; - let finalAuthUrl = authorizationUrl; - if (!finalAuthUrl) { - if (!discoveryUrl) throw new APIError("BAD_REQUEST", { message: GENERIC_OAUTH_ERROR_CODES.INVALID_OAUTH_CONFIGURATION }); - const discovery = await betterFetch(discoveryUrl, { - method: "GET", - headers: provider.discoveryHeaders, - onError(context) { - c.context.logger.error(context.error.message, context.error, { discoveryUrl }); - } - }); - if (discovery.data) finalAuthUrl = discovery.data.authorization_endpoint; - } - if (!finalAuthUrl) throw new APIError("BAD_REQUEST", { message: GENERIC_OAUTH_ERROR_CODES.INVALID_OAUTH_CONFIGURATION }); - const state = await generateState(c, { - userId: session.user.id, - email: session.user.email - }, void 0); - const additionalParams = typeof authorizationUrlParams === "function" ? authorizationUrlParams(c) : authorizationUrlParams; - const url = await createAuthorizationURL({ - id: providerId, - options: { - clientId, - clientSecret, - redirectURI: redirectURI || `${c.context.baseURL}/oauth2/callback/${providerId}` - }, - authorizationEndpoint: finalAuthUrl, - state: state.state, - codeVerifier: pkce ? state.codeVerifier : void 0, - scopes: c.body.scopes || scopes || [], - redirectURI: redirectURI || `${c.context.baseURL}/oauth2/callback/${providerId}`, - prompt, - accessType, - additionalParams - }); - return c.json({ - url: url.toString(), - redirect: true - }); -}); -async function getUserInfo(tokens, finalUserInfoUrl) { - if (tokens.idToken) { - const decoded = decodeJwt(tokens.idToken); - if (decoded) { - if (decoded.sub && decoded.email) return { - id: decoded.sub, - emailVerified: decoded.email_verified, - image: decoded.picture, - ...decoded - }; - } - } - if (!finalUserInfoUrl) return null; - const userInfo = await betterFetch(finalUserInfoUrl, { - method: "GET", - headers: { Authorization: `Bearer ${tokens.accessToken}` } - }); - return { - id: userInfo.data?.sub ?? "", - emailVerified: userInfo.data?.email_verified ?? false, - email: userInfo.data?.email, - image: userInfo.data?.picture, - name: userInfo.data?.name, - ...userInfo.data - }; -} -const genericOAuth = (options) => { - const seenIds = /* @__PURE__ */ new Set(); - const nonUniqueIds = /* @__PURE__ */ new Set(); - for (const config2 of options.config) { - const id = config2.providerId; - if (seenIds.has(id)) nonUniqueIds.add(id); - seenIds.add(id); - } - if (nonUniqueIds.size > 0) console.warn(`Duplicate provider IDs found: ${Array.from(nonUniqueIds).join(", ")}`); - return { - id: "generic-oauth", - init: (ctx) => { - return { context: { socialProviders: options.config.map((c) => { - let finalUserInfoUrl = c.userInfoUrl; - return { - id: c.providerId, - name: c.providerId, - async createAuthorizationURL(data) { - let finalAuthUrl = c.authorizationUrl; - if (!finalAuthUrl && c.discoveryUrl) { - const discovery = await betterFetch(c.discoveryUrl, { - method: "GET", - headers: c.discoveryHeaders - }); - if (discovery.data) { - finalAuthUrl = discovery.data.authorization_endpoint; - finalUserInfoUrl = finalUserInfoUrl ?? discovery.data.userinfo_endpoint; - } - } - if (!finalAuthUrl) throw new APIError("BAD_REQUEST", { message: GENERIC_OAUTH_ERROR_CODES.INVALID_OAUTH_CONFIGURATION }); - return createAuthorizationURL({ - id: c.providerId, - options: { - clientId: c.clientId, - clientSecret: c.clientSecret, - redirectURI: c.redirectURI - }, - authorizationEndpoint: finalAuthUrl, - state: data.state, - codeVerifier: c.pkce ? data.codeVerifier : void 0, - scopes: c.scopes || [], - redirectURI: `${ctx.baseURL}/oauth2/callback/${c.providerId}` - }); - }, - async validateAuthorizationCode(data) { - if (c.getToken) return c.getToken(data); - let finalTokenUrl = c.tokenUrl; - if (c.discoveryUrl) { - const discovery = await betterFetch(c.discoveryUrl, { - method: "GET", - headers: c.discoveryHeaders - }); - if (discovery.data) { - finalTokenUrl = discovery.data.token_endpoint; - finalUserInfoUrl = discovery.data.userinfo_endpoint; - } - } - if (!finalTokenUrl) throw new APIError("BAD_REQUEST", { message: GENERIC_OAUTH_ERROR_CODES.TOKEN_URL_NOT_FOUND }); - return validateAuthorizationCode({ - headers: c.authorizationHeaders, - code: data.code, - codeVerifier: data.codeVerifier, - redirectURI: data.redirectURI, - options: { - clientId: c.clientId, - clientSecret: c.clientSecret, - redirectURI: c.redirectURI - }, - tokenEndpoint: finalTokenUrl, - authentication: c.authentication - }); - }, - async refreshAccessToken(refreshToken2) { - let finalTokenUrl = c.tokenUrl; - if (c.discoveryUrl) { - const discovery = await betterFetch(c.discoveryUrl, { - method: "GET", - headers: c.discoveryHeaders - }); - if (discovery.data) finalTokenUrl = discovery.data.token_endpoint; - } - if (!finalTokenUrl) throw new APIError("BAD_REQUEST", { message: GENERIC_OAUTH_ERROR_CODES.TOKEN_URL_NOT_FOUND }); - return refreshAccessToken({ - refreshToken: refreshToken2, - options: { - clientId: c.clientId, - clientSecret: c.clientSecret - }, - authentication: c.authentication, - tokenEndpoint: finalTokenUrl - }); - }, - async getUserInfo(tokens) { - const userInfo = c.getUserInfo ? await c.getUserInfo(tokens) : await getUserInfo(tokens, finalUserInfoUrl); - if (!userInfo) return null; - const userMap = await c.mapProfileToUser?.(userInfo); - return { - user: { - id: userInfo?.id, - email: userInfo?.email, - emailVerified: userInfo?.emailVerified, - image: userInfo?.image, - name: userInfo?.name, - ...userMap - }, - data: userInfo - }; - }, - options: { overrideUserInfoOnSignIn: c.overrideUserInfo } - }; - }).concat(ctx.socialProviders) } }; - }, - endpoints: { - signInWithOAuth2: signInWithOAuth2(options), - oAuth2Callback: oAuth2Callback(options), - oAuth2LinkAccount: oAuth2LinkAccount(options) - }, - options, - $ERROR_CODES: GENERIC_OAUTH_ERROR_CODES - }; -}; -defineErrorCodes({ PASSWORD_COMPROMISED: "The password you entered has been compromised. Please choose a different password." }); -z.object({ - payload: z.record(z.string(), z.any()), - overrideOptions: z.record(z.string(), z.any()).optional() -}); -z.object({ - token: z.string(), - issuer: z.string().optional() -}); -z.object({ - email: z.email().meta({ description: "Email address to send the magic link" }), - name: z.string().meta({ description: 'User display name. Only used if the user is registering for the first time. Eg: "my-name"' }).optional(), - callbackURL: z.string().meta({ description: "URL to redirect after magic link verification" }).optional(), - newUserCallbackURL: z.string().meta({ description: "URL to redirect after new user signup. Only used if the user is registering for the first time." }).optional(), - errorCallbackURL: z.string().meta({ description: "URL to redirect after error." }).optional() -}); -z.object({ - token: z.string().meta({ description: "Verification token" }), - callbackURL: z.string().meta({ description: 'URL to redirect after magic link verification, if not provided the user will be redirected to the root URL. Eg: "/dashboard"' }).optional(), - errorCallbackURL: z.string().meta({ description: "URL to redirect after error." }).optional(), - newUserCallbackURL: z.string().meta({ description: "URL to redirect after new user signup. Only used if the user is registering for the first time." }).optional() -}); -z.object({ - clientId: z.string(), - clientSecret: z.string().optional(), - type: z.enum([ - "web", - "native", - "user-agent-based", - "public" - ]), - name: z.string(), - icon: z.string().optional(), - metadata: z.string().optional(), - disabled: z.boolean().optional().default(false), - redirectUrls: z.string(), - userId: z.string().optional(), - createdAt: z.date(), - updatedAt: z.date() -}); -z.object({ - accept: z.boolean(), - consent_code: z.string().optional().nullish() -}); -z.record(z.any(), z.any()); -z.object({ - redirect_uris: z.array(z.string()).meta({ description: 'A list of redirect URIs. Eg: ["https://client.example.com/callback"]' }), - token_endpoint_auth_method: z.enum([ - "none", - "client_secret_basic", - "client_secret_post" - ]).meta({ description: 'The authentication method for the token endpoint. Eg: "client_secret_basic"' }).default("client_secret_basic").optional(), - grant_types: z.array(z.enum([ - "authorization_code", - "implicit", - "password", - "client_credentials", - "refresh_token", - "urn:ietf:params:oauth:grant-type:jwt-bearer", - "urn:ietf:params:oauth:grant-type:saml2-bearer" - ])).meta({ description: 'The grant types supported by the application. Eg: ["authorization_code"]' }).default(["authorization_code"]).optional(), - response_types: z.array(z.enum(["code", "token"])).meta({ description: 'The response types supported by the application. Eg: ["code"]' }).default(["code"]).optional(), - client_name: z.string().meta({ description: 'The name of the application. Eg: "My App"' }).optional(), - client_uri: z.string().meta({ description: 'The URI of the application. Eg: "https://client.example.com"' }).optional(), - logo_uri: z.string().meta({ description: 'The URI of the application logo. Eg: "https://client.example.com/logo.png"' }).optional(), - scope: z.string().meta({ description: 'The scopes supported by the application. Separated by spaces. Eg: "profile email"' }).optional(), - contacts: z.array(z.string()).meta({ description: 'The contact information for the application. Eg: ["admin@example.com"]' }).optional(), - tos_uri: z.string().meta({ description: 'The URI of the application terms of service. Eg: "https://client.example.com/tos"' }).optional(), - policy_uri: z.string().meta({ description: 'The URI of the application privacy policy. Eg: "https://client.example.com/policy"' }).optional(), - jwks_uri: z.string().meta({ description: 'The URI of the application JWKS. Eg: "https://client.example.com/jwks"' }).optional(), - jwks: z.record(z.any(), z.any()).meta({ description: 'The JWKS of the application. Eg: {"keys": [{"kty": "RSA", "alg": "RS256", "use": "sig", "n": "...", "e": "..."}]}' }).optional(), - metadata: z.record(z.any(), z.any()).meta({ description: 'The metadata of the application. Eg: {"key": "value"}' }).optional(), - software_id: z.string().meta({ description: 'The software ID of the application. Eg: "my-software"' }).optional(), - software_version: z.string().meta({ description: 'The software version of the application. Eg: "1.0.0"' }).optional(), - software_statement: z.string().meta({ description: "The software statement of the application." }).optional() -}); -z.object({ - redirect_uris: z.array(z.string()), - token_endpoint_auth_method: z.enum([ - "none", - "client_secret_basic", - "client_secret_post" - ]).default("client_secret_basic").optional(), - grant_types: z.array(z.enum([ - "authorization_code", - "implicit", - "password", - "client_credentials", - "refresh_token", - "urn:ietf:params:oauth:grant-type:jwt-bearer", - "urn:ietf:params:oauth:grant-type:saml2-bearer" - ])).default(["authorization_code"]).optional(), - response_types: z.array(z.enum(["code", "token"])).default(["code"]).optional(), - client_name: z.string().optional(), - client_uri: z.string().optional(), - logo_uri: z.string().optional(), - scope: z.string().optional(), - contacts: z.array(z.string()).optional(), - tos_uri: z.string().optional(), - policy_uri: z.string().optional(), - jwks_uri: z.string().optional(), - jwks: z.record(z.string(), z.any()).optional(), - metadata: z.record(z.any(), z.any()).optional(), - software_id: z.string().optional(), - software_version: z.string().optional(), - software_statement: z.string().optional() -}); -z.record(z.any(), z.any()); -defineErrorCodes({ INVALID_SESSION_TOKEN: "Invalid session token" }); -z.object({ sessionToken: z.string().meta({ description: "The session token to set as active" }) }); -z.object({ sessionToken: z.string().meta({ description: "The session token to revoke" }) }); -z.object({ - callbackURL: z.string().meta({ description: "The URL to redirect to after the proxy" }), - cookies: z.string().meta({ description: "The cookies to set after the proxy" }) -}); -z.object({ idToken: z.string().meta({ description: "Google ID token, which the client obtains from the One Tap API" }) }); -z.object({ token: z.string().meta({ description: 'The token to verify. Eg: "some-token"' }) }); -createAuthMiddleware(async () => { - return {}; -}); -createAuthMiddleware({ use: [sessionMiddleware] }, async (ctx) => { - return { session: ctx.context.session }; -}); -defineErrorCodes({ - YOU_ARE_NOT_ALLOWED_TO_CREATE_A_NEW_ORGANIZATION: "You are not allowed to create a new organization", - YOU_HAVE_REACHED_THE_MAXIMUM_NUMBER_OF_ORGANIZATIONS: "You have reached the maximum number of organizations", - ORGANIZATION_ALREADY_EXISTS: "Organization already exists", - ORGANIZATION_SLUG_ALREADY_TAKEN: "Organization slug already taken", - ORGANIZATION_NOT_FOUND: "Organization not found", - USER_IS_NOT_A_MEMBER_OF_THE_ORGANIZATION: "User is not a member of the organization", - YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_ORGANIZATION: "You are not allowed to update this organization", - YOU_ARE_NOT_ALLOWED_TO_DELETE_THIS_ORGANIZATION: "You are not allowed to delete this organization", - NO_ACTIVE_ORGANIZATION: "No active organization", - USER_IS_ALREADY_A_MEMBER_OF_THIS_ORGANIZATION: "User is already a member of this organization", - MEMBER_NOT_FOUND: "Member not found", - ROLE_NOT_FOUND: "Role not found", - YOU_ARE_NOT_ALLOWED_TO_CREATE_A_NEW_TEAM: "You are not allowed to create a new team", - TEAM_ALREADY_EXISTS: "Team already exists", - TEAM_NOT_FOUND: "Team not found", - YOU_CANNOT_LEAVE_THE_ORGANIZATION_AS_THE_ONLY_OWNER: "You cannot leave the organization as the only owner", - YOU_CANNOT_LEAVE_THE_ORGANIZATION_WITHOUT_AN_OWNER: "You cannot leave the organization without an owner", - YOU_ARE_NOT_ALLOWED_TO_DELETE_THIS_MEMBER: "You are not allowed to delete this member", - YOU_ARE_NOT_ALLOWED_TO_INVITE_USERS_TO_THIS_ORGANIZATION: "You are not allowed to invite users to this organization", - USER_IS_ALREADY_INVITED_TO_THIS_ORGANIZATION: "User is already invited to this organization", - INVITATION_NOT_FOUND: "Invitation not found", - YOU_ARE_NOT_THE_RECIPIENT_OF_THE_INVITATION: "You are not the recipient of the invitation", - EMAIL_VERIFICATION_REQUIRED_BEFORE_ACCEPTING_OR_REJECTING_INVITATION: "Email verification required before accepting or rejecting invitation", - YOU_ARE_NOT_ALLOWED_TO_CANCEL_THIS_INVITATION: "You are not allowed to cancel this invitation", - INVITER_IS_NO_LONGER_A_MEMBER_OF_THE_ORGANIZATION: "Inviter is no longer a member of the organization", - YOU_ARE_NOT_ALLOWED_TO_INVITE_USER_WITH_THIS_ROLE: "You are not allowed to invite a user with this role", - FAILED_TO_RETRIEVE_INVITATION: "Failed to retrieve invitation", - YOU_HAVE_REACHED_THE_MAXIMUM_NUMBER_OF_TEAMS: "You have reached the maximum number of teams", - UNABLE_TO_REMOVE_LAST_TEAM: "Unable to remove last team", - YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_MEMBER: "You are not allowed to update this member", - ORGANIZATION_MEMBERSHIP_LIMIT_REACHED: "Organization membership limit reached", - YOU_ARE_NOT_ALLOWED_TO_CREATE_TEAMS_IN_THIS_ORGANIZATION: "You are not allowed to create teams in this organization", - YOU_ARE_NOT_ALLOWED_TO_DELETE_TEAMS_IN_THIS_ORGANIZATION: "You are not allowed to delete teams in this organization", - YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_TEAM: "You are not allowed to update this team", - YOU_ARE_NOT_ALLOWED_TO_DELETE_THIS_TEAM: "You are not allowed to delete this team", - INVITATION_LIMIT_REACHED: "Invitation limit reached", - TEAM_MEMBER_LIMIT_REACHED: "Team member limit reached", - USER_IS_NOT_A_MEMBER_OF_THE_TEAM: "User is not a member of the team", - YOU_CAN_NOT_ACCESS_THE_MEMBERS_OF_THIS_TEAM: "You are not allowed to list the members of this team", - YOU_DO_NOT_HAVE_AN_ACTIVE_TEAM: "You do not have an active team", - YOU_ARE_NOT_ALLOWED_TO_CREATE_A_NEW_TEAM_MEMBER: "You are not allowed to create a new member", - YOU_ARE_NOT_ALLOWED_TO_REMOVE_A_TEAM_MEMBER: "You are not allowed to remove a team member", - YOU_ARE_NOT_ALLOWED_TO_ACCESS_THIS_ORGANIZATION: "You are not allowed to access this organization as an owner", - YOU_ARE_NOT_A_MEMBER_OF_THIS_ORGANIZATION: "You are not a member of this organization", - MISSING_AC_INSTANCE: "Dynamic Access Control requires a pre-defined ac instance on the server auth plugin. Read server logs for more information", - YOU_MUST_BE_IN_AN_ORGANIZATION_TO_CREATE_A_ROLE: "You must be in an organization to create a role", - YOU_ARE_NOT_ALLOWED_TO_CREATE_A_ROLE: "You are not allowed to create a role", - YOU_ARE_NOT_ALLOWED_TO_UPDATE_A_ROLE: "You are not allowed to update a role", - YOU_ARE_NOT_ALLOWED_TO_DELETE_A_ROLE: "You are not allowed to delete a role", - YOU_ARE_NOT_ALLOWED_TO_READ_A_ROLE: "You are not allowed to read a role", - YOU_ARE_NOT_ALLOWED_TO_LIST_A_ROLE: "You are not allowed to list a role", - YOU_ARE_NOT_ALLOWED_TO_GET_A_ROLE: "You are not allowed to get a role", - TOO_MANY_ROLES: "This organization has too many roles", - INVALID_RESOURCE: "The provided permission includes an invalid resource", - ROLE_NAME_IS_ALREADY_TAKEN: "That role name is already taken", - CANNOT_DELETE_A_PRE_DEFINED_ROLE: "Cannot delete a pre-defined role", - ROLE_IS_ASSIGNED_TO_MEMBERS: "Cannot delete a role that is assigned to members. Please reassign the members to a different role first" -}); -z.object({ - organizationId: z.string().optional().meta({ description: "The id of the organization to create the role in. If not provided, the user's active organization will be used." }), - role: z.string().meta({ description: "The name of the role to create" }), - permission: z.record(z.string(), z.array(z.string())).meta({ description: "The permission to assign to the role" }) -}); -z.object({ organizationId: z.string().optional().meta({ description: "The id of the organization to create the role in. If not provided, the user's active organization will be used." }) }).and(z.union([z.object({ roleName: z.string().nonempty().meta({ description: "The name of the role to delete" }) }), z.object({ roleId: z.string().nonempty().meta({ description: "The id of the role to delete" }) })])); -z.object({ organizationId: z.string().optional().meta({ description: "The id of the organization to list roles for. If not provided, the user's active organization will be used." }) }).optional(); -z.object({ organizationId: z.string().optional().meta({ description: "The id of the organization to read a role for. If not provided, the user's active organization will be used." }) }).and(z.union([z.object({ roleName: z.string().nonempty().meta({ description: "The name of the role to read" }) }), z.object({ roleId: z.string().nonempty().meta({ description: "The id of the role to read" }) })])).optional(); -z.union([z.object({ roleName: z.string().nonempty().meta({ description: "The name of the role to update" }) }), z.object({ roleId: z.string().nonempty().meta({ description: "The id of the role to update" }) })]); -z.object({ - email: z.string().meta({ description: "The email address of the user to invite" }), - role: z.union([z.string().meta({ description: "The role to assign to the user" }), z.array(z.string().meta({ description: "The roles to assign to the user" }))]).meta({ description: 'The role(s) to assign to the user. It can be `admin`, `member`, owner. Eg: "member"' }), - organizationId: z.string().meta({ description: "The organization ID to invite the user to" }).optional(), - resend: z.boolean().meta({ description: "Resend the invitation email, if the user is already invited. Eg: true" }).optional(), - teamId: z.union([z.string().meta({ description: "The team ID to invite the user to" }).optional(), z.array(z.string()).meta({ description: "The team IDs to invite the user to" }).optional()]) -}); -z.object({ invitationId: z.string().meta({ description: "The ID of the invitation to accept" }) }); -z.object({ invitationId: z.string().meta({ description: "The ID of the invitation to reject" }) }); -z.object({ invitationId: z.string().meta({ description: "The ID of the invitation to cancel" }) }); -z.object({ id: z.string().meta({ description: "The ID of the invitation to get" }) }); -z.object({ organizationId: z.string().meta({ description: "The ID of the organization to list invitations for" }).optional() }).optional(); -z.object({ - userId: z.coerce.string().meta({ description: 'The user Id which represents the user to be added as a member. If `null` is provided, then it\'s expected to provide session headers. Eg: "user-id"' }), - role: z.union([z.string(), z.array(z.string())]).meta({ description: 'The role(s) to assign to the new member. Eg: ["admin", "sale"]' }), - organizationId: z.string().meta({ description: `An optional organization ID to pass. If not provided, will default to the user's active organization. Eg: "org-id"` }).optional(), - teamId: z.string().meta({ description: 'An optional team ID to add the member to. Eg: "team-id"' }).optional() -}); -z.object({ - memberIdOrEmail: z.string().meta({ description: "The ID or email of the member to remove" }), - organizationId: z.string().meta({ description: 'The ID of the organization to remove the member from. If not provided, the active organization will be used. Eg: "org-id"' }).optional() -}); -z.object({ - role: z.union([z.string(), z.array(z.string())]).meta({ description: 'The new role to be applied. This can be a string or array of strings representing the roles. Eg: ["admin", "sale"]' }), - memberId: z.string().meta({ description: 'The member id to apply the role update to. Eg: "member-id"' }), - organizationId: z.string().meta({ description: 'An optional organization ID which the member is a part of to apply the role update. If not provided, you must provide session headers to get the active organization. Eg: "organization-id"' }).optional() -}); -z.object({ organizationId: z.string().meta({ description: 'The organization Id for the member to leave. Eg: "organization-id"' }) }); -z.object({ - userId: z.string().meta({ description: "The user ID to get the role for. If not provided, will default to the current user's" }).optional(), - organizationId: z.string().meta({ description: `The organization ID to list members for. If not provided, will default to the user's active organization. Eg: "organization-id"` }).optional(), - organizationSlug: z.string().meta({ description: `The organization slug to list members for. If not provided, will default to the user's active organization. Eg: "organization-slug"` }).optional() -}).optional(); -z.object({ - name: z.string().min(1).meta({ description: "The name of the organization" }), - slug: z.string().min(1).meta({ description: "The slug of the organization" }), - userId: z.coerce.string().meta({ description: 'The user id of the organization creator. If not provided, the current user will be used. Should only be used by admins or when called by the server. server-only. Eg: "user-id"' }).optional(), - logo: z.string().meta({ description: "The logo of the organization" }).optional(), - metadata: z.record(z.string(), z.any()).meta({ description: "The metadata of the organization" }).optional(), - keepCurrentActiveOrganization: z.boolean().meta({ description: "Whether to keep the current active organization active after creating a new one. Eg: true" }).optional() -}); -z.object({ slug: z.string().meta({ description: 'The organization slug to check. Eg: "my-org"' }) }); -z.object({ - name: z.string().min(1).meta({ description: "The name of the organization" }).optional(), - slug: z.string().min(1).meta({ description: "The slug of the organization" }).optional(), - logo: z.string().meta({ description: "The logo of the organization" }).optional(), - metadata: z.record(z.string(), z.any()).meta({ description: "The metadata of the organization" }).optional() -}); -z.object({ organizationId: z.string().meta({ description: "The organization id to delete" }) }); -z.optional(z.object({ - organizationId: z.string().meta({ description: "The organization id to get" }).optional(), - organizationSlug: z.string().meta({ description: "The organization slug to get" }).optional(), - membersLimit: z.number().or(z.string().transform((val) => parseInt(val))).meta({ description: "The limit of members to get. By default, it uses the membershipLimit option which defaults to 100." }).optional() -})); -z.object({ - organizationId: z.string().meta({ description: 'The organization id to set as active. It can be null to unset the active organization. Eg: "org-id"' }).nullable().optional(), - organizationSlug: z.string().meta({ description: 'The organization slug to set as active. It can be null to unset the active organization if organizationId is not provided. Eg: "org-slug"' }).optional() -}); -const roleSchema = z.string(); -const invitationStatus = z.enum([ - "pending", - "accepted", - "rejected", - "canceled" -]).default("pending"); -z.object({ - id: z.string().default(generateId), - name: z.string(), - slug: z.string(), - logo: z.string().nullish().optional(), - metadata: z.record(z.string(), z.unknown()).or(z.string().transform((v) => JSON.parse(v))).optional(), - createdAt: z.date() -}); -z.object({ - id: z.string().default(generateId), - organizationId: z.string(), - userId: z.coerce.string(), - role: roleSchema, - createdAt: z.date().default(() => /* @__PURE__ */ new Date()) -}); -z.object({ - id: z.string().default(generateId), - organizationId: z.string(), - email: z.string(), - role: roleSchema, - status: invitationStatus, - teamId: z.string().nullish(), - inviterId: z.string(), - expiresAt: z.date(), - createdAt: z.date().default(() => /* @__PURE__ */ new Date()) -}); -z.object({ - id: z.string().default(generateId), - name: z.string().min(1), - organizationId: z.string(), - createdAt: z.date(), - updatedAt: z.date().optional() -}); -z.object({ - id: z.string().default(generateId), - teamId: z.string(), - userId: z.string(), - createdAt: z.date().default(() => /* @__PURE__ */ new Date()) -}); -z.object({ - id: z.string().default(generateId), - organizationId: z.string(), - role: z.string(), - permission: z.record(z.string(), z.array(z.string())), - createdAt: z.date().default(() => /* @__PURE__ */ new Date()), - updatedAt: z.date().optional() -}); -const defaultRoles = [ - "admin", - "member", - "owner" -]; -z.union([z.enum(defaultRoles), z.array(z.enum(defaultRoles))]); -z.object({ - name: z.string().meta({ description: 'The name of the team. Eg: "my-team"' }), - organizationId: z.string().meta({ description: 'The organization ID which the team will be created in. Defaults to the active organization. Eg: "organization-id"' }).optional() -}); -z.object({ - teamId: z.string().meta({ description: `The team ID of the team to remove. Eg: "team-id"` }), - organizationId: z.string().meta({ description: `The organization ID which the team falls under. If not provided, it will default to the user's active organization. Eg: "organization-id"` }).optional() -}); -z.optional(z.object({ organizationId: z.string().meta({ description: `The organization ID which the teams are under to list. Defaults to the users active organization. Eg: "organization-id"` }).optional() })); -z.object({ teamId: z.string().meta({ description: "The team id to set as active. It can be null to unset the active team" }).nullable().optional() }); -z.optional(z.object({ teamId: z.string().optional().meta({ description: "The team whose members we should return. If this is not provided the members of the current active team get returned." }) })); -z.object({ - teamId: z.string().meta({ description: "The team the user should be a member of." }), - userId: z.coerce.string().meta({ description: "The user Id which represents the user to be added as a member." }) -}); -z.object({ - teamId: z.string().meta({ description: "The team the user should be removed from." }), - userId: z.coerce.string().meta({ description: "The user which should be removed from the team." }) -}); -z.object({ organizationId: z.string().optional() }).and(z.union([z.object({ - permission: z.record(z.string(), z.array(z.string())), - permissions: z.undefined() -}), z.object({ - permission: z.undefined(), - permissions: z.record(z.string(), z.array(z.string())) -})])); -defineErrorCodes({ - INVALID_PHONE_NUMBER: "Invalid phone number", - PHONE_NUMBER_EXIST: "Phone number already exists", - PHONE_NUMBER_NOT_EXIST: "phone number isn't registered", - INVALID_PHONE_NUMBER_OR_PASSWORD: "Invalid phone number or password", - UNEXPECTED_ERROR: "Unexpected error", - OTP_NOT_FOUND: "OTP not found", - OTP_EXPIRED: "OTP expired", - INVALID_OTP: "Invalid OTP", - PHONE_NUMBER_NOT_VERIFIED: "Phone number not verified", - PHONE_NUMBER_CANNOT_BE_UPDATED: "Phone number cannot be updated", - SEND_OTP_NOT_IMPLEMENTED: "sendOTP not implemented", - TOO_MANY_ATTEMPTS: "Too many attempts" -}); -z.object({ - phoneNumber: z.string().meta({ description: 'Phone number to sign in. Eg: "+1234567890"' }), - password: z.string().meta({ description: "Password to use for sign in." }), - rememberMe: z.boolean().meta({ description: "Remember the session. Eg: true" }).optional() -}); -z.object({ phoneNumber: z.string().meta({ description: 'Phone number to send OTP. Eg: "+1234567890"' }) }); -z.object({ - phoneNumber: z.string().meta({ description: 'Phone number to verify. Eg: "+1234567890"' }), - code: z.string().meta({ description: 'OTP code. Eg: "123456"' }), - disableSession: z.boolean().meta({ description: "Disable session creation after verification. Eg: false" }).optional(), - updatePhoneNumber: z.boolean().meta({ description: "Check if there is a session and update the phone number. Eg: true" }).optional() -}).and(z.record(z.string(), z.any())); -z.object({ phoneNumber: z.string() }); -z.object({ - otp: z.string().meta({ description: 'The one time password to reset the password. Eg: "123456"' }), - phoneNumber: z.string().meta({ description: 'The phone number to the account which intends to reset the password for. Eg: "+1234567890"' }), - newPassword: z.string().meta({ description: `The new password. Eg: "new-and-secure-password"` }) -}); -z.object({ - walletAddress: z.string().regex(/^0[xX][a-fA-F0-9]{40}$/i).length(42), - chainId: z.number().int().positive().max(2147483647).optional().default(1) -}); -defineErrorCodes({ - OTP_NOT_ENABLED: "OTP not enabled", - OTP_HAS_EXPIRED: "OTP has expired", - TOTP_NOT_ENABLED: "TOTP not enabled", - TWO_FACTOR_NOT_ENABLED: "Two factor isn't enabled", - BACKUP_CODES_NOT_ENABLED: "Backup codes aren't enabled", - INVALID_BACKUP_CODE: "Invalid backup code", - INVALID_CODE: "Invalid code", - TOO_MANY_ATTEMPTS_REQUEST_NEW_CODE: "Too many attempts. Please request a new code.", - INVALID_TWO_FACTOR_COOKIE: "Invalid two factor cookie" -}); -z.object({ - code: z.string().meta({ description: `A backup code to verify. Eg: "123456"` }), - disableSession: z.boolean().meta({ description: "If true, the session cookie will not be set." }).optional(), - trustDevice: z.boolean().meta({ description: "If true, the device will be trusted for 30 days. It'll be refreshed on every sign in request within this time. Eg: true" }).optional() -}); -z.object({ userId: z.coerce.string().meta({ description: `The user ID to view all backup codes. Eg: "user-id"` }) }); -z.object({ password: z.string().meta({ description: "The users password." }) }); -z.object({ - code: z.string().meta({ description: 'The otp code to verify. Eg: "012345"' }), - trustDevice: z.boolean().optional().meta({ description: "If true, the device will be trusted for 30 days. It'll be refreshed on every sign in request within this time. Eg: true" }) -}); -z.object({ trustDevice: z.boolean().optional().meta({ description: "If true, the device will be trusted for 30 days. It'll be refreshed on every sign in request within this time. Eg: true" }) }).optional(); -z.object({ secret: z.string().meta({ description: "The secret to generate the TOTP code" }) }); -z.object({ password: z.string().meta({ description: "User password" }) }); -z.object({ - code: z.string().meta({ description: 'The otp code to verify. Eg: "012345"' }), - trustDevice: z.boolean().meta({ description: "If true, the device will be trusted for 30 days. It'll be refreshed on every sign in request within this time. Eg: true" }).optional() -}); -z.object({ - password: z.string().meta({ description: "User password" }), - issuer: z.string().meta({ description: "Custom issuer for the TOTP URI" }).optional() -}); -z.object({ password: z.string().meta({ description: "User password" }) }); -defineErrorCodes({ - INVALID_USERNAME_OR_PASSWORD: "Invalid username or password", - EMAIL_NOT_VERIFIED: "Email not verified", - UNEXPECTED_ERROR: "Unexpected error", - USERNAME_IS_ALREADY_TAKEN: "Username is already taken. Please try another.", - USERNAME_TOO_SHORT: "Username is too short", - USERNAME_TOO_LONG: "Username is too long", - INVALID_USERNAME: "Username is invalid", - INVALID_DISPLAY_USERNAME: "Display username is invalid" -}); -z.object({ - username: z.string().meta({ description: "The username of the user" }), - password: z.string().meta({ description: "The password of the user" }), - rememberMe: z.boolean().meta({ description: "Remember the user session" }).optional(), - callbackURL: z.string().meta({ description: "The URL to redirect to after email verification" }).optional() -}); -z.object({ username: z.string().meta({ description: "The username to check" }) }); -const auth = betterAuth({ - baseURL: private_env.ORIGIN, - secret: private_env.BETTER_AUTH_SECRET, - database: drizzleAdapter(db, { provider: "pg" }), - emailAndPassword: { enabled: true }, - databaseHooks: { - user: { - create: { - after: async (user) => { - const [personalTeam] = await db.insert(team).values({ - name: user.name, - isPersonal: true, - ownerId: user.id, - avatarUrl: user.image - }).returning(); - await db.insert(teamMember).values({ - teamId: personalTeam.id, - userId: user.id, - role: "owner" - }); - } - } - } - }, - plugins: [ - genericOAuth({ - config: [ - { - providerId: "osu", - clientId: private_env.OSU_CLIENT_ID, - clientSecret: private_env.OSU_CLIENT_SECRET, - authorizationUrl: "https://osu.ppy.sh/oauth/authorize", - tokenUrl: "https://osu.ppy.sh/oauth/token", - userInfoUrl: "https://osu.ppy.sh/api/v2/me", - scopes: ["identify", "public"], - pkce: false, - authentication: "post", - // ── FIX: Use ORIGIN env var instead of hardcoded localhost ── - redirectURI: `${private_env.ORIGIN}/api/auth/oauth2/callback/osu`, - getToken: async ({ code, redirectURI }) => { - const res = await fetch("https://osu.ppy.sh/oauth/token", { - method: "POST", - headers: { - Accept: "application/json", - "Content-Type": "application/x-www-form-urlencoded" - }, - body: new URLSearchParams({ - client_id: private_env.OSU_CLIENT_ID, - client_secret: private_env.OSU_CLIENT_SECRET, - code, - grant_type: "authorization_code", - redirect_uri: redirectURI - }) - }); - const data = await res.json(); - if (!res.ok) { - console.error("osu! token exchange failed:", data); - throw new Error("Token exchange failed"); - } - return { - accessToken: data.access_token, - refreshToken: data.refresh_token, - accessTokenExpiresAt: new Date(Date.now() + data.expires_in * 1e3), - scopes: ["identify", "public"], - raw: data - }; - }, - mapProfileToUser(profile) { - return { - name: profile.username, - image: profile.avatar_url, - email: `${profile.id}@osu.local` - }; - } - } - ] - }), - sveltekitCookies(getRequestEvent) - // must be last - ] -}); -export { - auth as a, - createKyselyAdapter as c, - getKyselyDatabaseType as g, - svelteKitHandler as s -}; diff --git a/.svelte-kit/output/server/chunks/bun-sqlite-dialect.js b/.svelte-kit/output/server/chunks/bun-sqlite-dialect.js deleted file mode 100644 index 6fe94c6..0000000 --- a/.svelte-kit/output/server/chunks/bun-sqlite-dialect.js +++ /dev/null @@ -1,155 +0,0 @@ -import { CompiledQuery, DefaultQueryCompiler, DEFAULT_MIGRATION_TABLE, DEFAULT_MIGRATION_LOCK_TABLE, sql } from "kysely"; -var BunSqliteAdapter = class { - get supportsCreateIfNotExists() { - return true; - } - get supportsTransactionalDdl() { - return false; - } - get supportsReturning() { - return true; - } - async acquireMigrationLock() { - } - async releaseMigrationLock() { - } - get supportsOutput() { - return true; - } -}; -var BunSqliteDriver = class { - #config; - #connectionMutex = new ConnectionMutex(); - #db; - #connection; - constructor(config) { - this.#config = { ...config }; - } - async init() { - this.#db = this.#config.database; - this.#connection = new BunSqliteConnection(this.#db); - if (this.#config.onCreateConnection) await this.#config.onCreateConnection(this.#connection); - } - async acquireConnection() { - await this.#connectionMutex.lock(); - return this.#connection; - } - async beginTransaction(connection) { - await connection.executeQuery(CompiledQuery.raw("begin")); - } - async commitTransaction(connection) { - await connection.executeQuery(CompiledQuery.raw("commit")); - } - async rollbackTransaction(connection) { - await connection.executeQuery(CompiledQuery.raw("rollback")); - } - async releaseConnection() { - this.#connectionMutex.unlock(); - } - async destroy() { - this.#db?.close(); - } -}; -var BunSqliteConnection = class { - #db; - constructor(db) { - this.#db = db; - } - executeQuery(compiledQuery) { - const { sql: sql$1, parameters } = compiledQuery; - const stmt = this.#db.prepare(sql$1); - return Promise.resolve({ rows: stmt.all(parameters) }); - } - async *streamQuery() { - throw new Error("Streaming query is not supported by SQLite driver."); - } -}; -var ConnectionMutex = class { - #promise; - #resolve; - async lock() { - while (await this.#promise) await this.#promise; - this.#promise = new Promise((resolve) => { - this.#resolve = resolve; - }); - } - unlock() { - const resolve = this.#resolve; - this.#promise = void 0; - this.#resolve = void 0; - resolve?.(); - } -}; -var BunSqliteIntrospector = class { - #db; - constructor(db) { - this.#db = db; - } - async getSchemas() { - return []; - } - async getTables(options = { withInternalKyselyTables: false }) { - let query = this.#db.selectFrom("sqlite_schema").where("type", "=", "table").where("name", "not like", "sqlite_%").select("name").$castTo(); - if (!options.withInternalKyselyTables) query = query.where("name", "!=", DEFAULT_MIGRATION_TABLE).where("name", "!=", DEFAULT_MIGRATION_LOCK_TABLE); - const tables = await query.execute(); - return Promise.all(tables.map(({ name }) => this.#getTableMetadata(name))); - } - async getMetadata(options) { - return { tables: await this.getTables(options) }; - } - async #getTableMetadata(table) { - const db = this.#db; - const autoIncrementCol = (await db.selectFrom("sqlite_master").where("name", "=", table).select("sql").$castTo().execute())[0]?.sql?.split(/[\(\),]/)?.find((it) => it.toLowerCase().includes("autoincrement"))?.split(/\s+/)?.[0]?.replace(/["`]/g, ""); - return { - name: table, - columns: (await db.selectFrom(sql`pragma_table_info(${table})`.as("table_info")).select([ - "name", - "type", - "notnull", - "dflt_value" - ]).execute()).map((col) => ({ - name: col.name, - dataType: col.type, - isNullable: !col.notnull, - isAutoIncrementing: col.name === autoIncrementCol, - hasDefaultValue: col.dflt_value != null - })), - isView: true - }; - } -}; -var BunSqliteQueryCompiler = class extends DefaultQueryCompiler { - getCurrentParameterPlaceholder() { - return "?"; - } - getLeftIdentifierWrapper() { - return '"'; - } - getRightIdentifierWrapper() { - return '"'; - } - getAutoIncrement() { - return "autoincrement"; - } -}; -var BunSqliteDialect = class { - #config; - constructor(config) { - this.#config = { ...config }; - } - createDriver() { - return new BunSqliteDriver(this.#config); - } - createQueryCompiler() { - return new BunSqliteQueryCompiler(); - } - createAdapter() { - return new BunSqliteAdapter(); - } - createIntrospector(db) { - return new BunSqliteIntrospector(db); - } -}; -export { - BunSqliteDialect -}; diff --git a/.svelte-kit/output/server/chunks/engine.js b/.svelte-kit/output/server/chunks/engine.js deleted file mode 100644 index f6bafe4..0000000 --- a/.svelte-kit/output/server/chunks/engine.js +++ /dev/null @@ -1,350 +0,0 @@ -import { d as db, b as match, e as matchParticipant, t as teamMember, f as matchParticipantPlayer, g as matchGame, h as matchGameScore, i as matchQueue, p as playerRating } from "./index2.js"; -import { eq, sql, asc } from "drizzle-orm"; -const MATCH_STATES = { - CREATED: "CREATED", - LOBBY: "LOBBY", - ROLLING: "ROLLING", - PICKING: "PICKING", - PLAYING: "PLAYING", - FINISHED: "FINISHED", - CANCELLED: "CANCELLED" -}; -const GAME_STATES = { - PLAYING: "PLAYING", - FINISHED: "FINISHED" -}; -async function joinQueue(userId, teamId) { - let rating = await db.query.playerRating.findFirst({ - where: eq(playerRating.userId, userId) - }); - if (!rating) { - [rating] = await db.insert(playerRating).values({ userId, elo: 1e3 }).returning(); - } - const existing = await db.query.matchQueue.findFirst({ - where: eq(matchQueue.userId, userId) - }); - if (existing) throw new Error("Already in queue"); - await db.insert(matchQueue).values({ - userId, - teamId, - elo: rating.elo - }); - return tryMatchFromQueue(); -} -async function leaveQueue(userId) { - await db.delete(matchQueue).where(eq(matchQueue.userId, userId)); -} -async function getQueueStatus(userId) { - const entry = await db.query.matchQueue.findFirst({ - where: eq(matchQueue.userId, userId) - }); - const count = await db.select({ count: sql`count(*)` }).from(matchQueue); - return { - inQueue: !!entry, - queueSize: Number(count[0].count), - joinedAt: entry?.joinedAt ?? null - }; -} -async function tryMatchFromQueue() { - const queue = await db.query.matchQueue.findMany({ - orderBy: asc(matchQueue.elo) - }); - if (queue.length < 2) return null; - let bestPair = null; - let smallestGap = Infinity; - for (let i = 0; i < queue.length - 1; i++) { - const gap = Math.abs(queue[i].elo - queue[i + 1].elo); - if (gap < smallestGap) { - smallestGap = gap; - bestPair = [queue[i], queue[i + 1]]; - } - } - if (!bestPair) return null; - const avgElo = (bestPair[0].elo + bestPair[1].elo) / 2; - const selectedPool = await selectMappoolForRating(avgElo); - if (!selectedPool) throw new Error("No mappools available"); - await db.delete(matchQueue).where(eq(matchQueue.userId, bestPair[0].userId)); - await db.delete(matchQueue).where(eq(matchQueue.userId, bestPair[1].userId)); - const created = await createMatch({ - name: "Ranked Match", - config: { bestOf: 7, teamSize: 1, scoringType: "score" }, - mappoolId: selectedPool.id, - teams: [bestPair[0].teamId, bestPair[1].teamId], - createdBy: "system" - }); - return created; -} -async function selectMappoolForRating(avgElo) { - const pools = await db.query.mappool.findMany({ - with: { slots: true } - }); - if (pools.length === 0) return null; - const targetStars = 3 + (avgElo - 800) / 400 * 4; - const clampedTarget = Math.max(2, Math.min(8, targetStars)); - let bestPool = pools[0]; - let bestDiff = Infinity; - for (const pool of pools) { - if (pool.slots.length === 0) continue; - const avgStars = pool.slots.reduce((sum, s) => sum + (s.starRating ?? 0), 0) / pool.slots.length; - const diff = Math.abs(avgStars - clampedTarget); - if (diff < bestDiff) { - bestDiff = diff; - bestPool = pool; - } - } - return bestPool; -} -async function createMatch(opts) { - const { name, config, mappoolId, teams, createdBy } = opts; - const [created] = await db.insert(match).values({ - name, - config, - mappoolId, - createdBy, - state: MATCH_STATES.CREATED - }).returning(); - for (let i = 0; i < teams.length; i++) { - const [participant] = await db.insert(matchParticipant).values({ - matchId: created.id, - teamId: teams[i], - slot: i + 1 - }).returning(); - const members = await db.query.teamMember.findMany({ - where: eq(teamMember.teamId, teams[i]) - }); - for (const member of members) { - await db.insert(matchParticipantPlayer).values({ - participantId: participant.id, - userId: member.userId - }); - } - } - return getMatchFull(created.id); -} -async function moveToLobby(matchId, osuLobbyId) { - const m = await getMatchOrThrow(matchId); - assertState(m.state, MATCH_STATES.CREATED); - await db.update(match).set({ - state: MATCH_STATES.LOBBY, - osuLobbyId: osuLobbyId ?? null, - startedAt: /* @__PURE__ */ new Date() - }).where(eq(match.id, matchId)); - return getMatchFull(matchId); -} -async function moveToRolling(matchId) { - const m = await getMatchOrThrow(matchId); - assertState(m.state, MATCH_STATES.LOBBY); - await db.update(match).set({ state: MATCH_STATES.ROLLING }).where(eq(match.id, matchId)); - return getMatchFull(matchId); -} -async function submitRoll(matchId, participantId, value) { - const m = await getMatchOrThrow(matchId); - assertState(m.state, MATCH_STATES.ROLLING); - await db.update(matchParticipant).set({ rollValue: value }).where(eq(matchParticipant.id, participantId)); - const participants = await db.query.matchParticipant.findMany({ - where: eq(matchParticipant.matchId, matchId) - }); - const allRolled = participants.every( - (p) => p.id === participantId ? true : p.rollValue !== null - ); - if (allRolled) { - const sorted = [...participants].map((p) => ({ - ...p, - rollValue: p.id === participantId ? value : p.rollValue - })).sort((a, b) => b.rollValue - a.rollValue); - for (let i = 0; i < sorted.length; i++) { - await db.update(matchParticipant).set({ pickOrder: i + 1 }).where(eq(matchParticipant.id, sorted[i].id)); - } - await db.update(match).set({ state: MATCH_STATES.PICKING }).where(eq(match.id, matchId)); - } - return getMatchFull(matchId); -} -async function pickMap(matchId, participantId, mappoolSlotId) { - const m = await getMatchOrThrow(matchId); - assertState(m.state, MATCH_STATES.PICKING); - const participants = await db.query.matchParticipant.findMany({ - where: eq(matchParticipant.matchId, matchId) - }); - const totalGames = await db.query.matchGame.findMany({ - where: eq(matchGame.matchId, matchId) - }); - const expectedPicker = getExpectedPicker(participants, totalGames.length); - if (expectedPicker.id !== participantId) { - throw new Error("Not your turn to pick"); - } - const alreadyPlayed = totalGames.some((g) => g.mappoolSlotId === mappoolSlotId); - if (alreadyPlayed) { - throw new Error("This map has already been played"); - } - const [game] = await db.insert(matchGame).values({ - matchId, - gameNumber: totalGames.length + 1, - mappoolSlotId, - pickedByParticipantId: participantId, - state: GAME_STATES.PLAYING, - startedAt: /* @__PURE__ */ new Date() - }).returning(); - await db.update(match).set({ state: MATCH_STATES.PLAYING }).where(eq(match.id, matchId)); - return game; -} -async function submitGameScores(matchGameId, scores) { - const game = await db.query.matchGame.findFirst({ - where: eq(matchGame.id, matchGameId) - }); - if (!game) throw new Error("Game not found"); - if (game.state !== GAME_STATES.PLAYING) throw new Error(`Game is ${game.state}, not PLAYING`); - for (const s of scores) { - await db.insert(matchGameScore).values({ - matchGameId, - playerId: s.playerId, - score: s.score, - accuracy: s.accuracy ?? 0, - maxCombo: s.maxCombo ?? 0, - count300: s.count300 ?? 0, - count100: s.count100 ?? 0, - count50: s.count50 ?? 0, - countMiss: s.countMiss ?? 0, - mods: s.mods ?? [], - passed: s.passed ?? true - }); - } - const allScores = await db.query.matchGameScore.findMany({ - where: eq(matchGameScore.matchGameId, matchGameId), - with: { player: true } - }); - const participantScores = /* @__PURE__ */ new Map(); - for (const s of allScores) { - const pid = s.player.participantId; - participantScores.set(pid, (participantScores.get(pid) ?? 0) + s.score); - } - let winnerId = null; - let highScore = -1; - for (const [pid, total] of participantScores) { - if (total > highScore) { - highScore = total; - winnerId = pid; - } - } - await db.update(matchGame).set({ - state: GAME_STATES.FINISHED, - winnerParticipantId: winnerId, - finishedAt: /* @__PURE__ */ new Date() - }).where(eq(matchGame.id, matchGameId)); - if (winnerId) { - const participant = await db.query.matchParticipant.findFirst({ - where: eq(matchParticipant.id, winnerId) - }); - if (participant) { - await db.update(matchParticipant).set({ score: participant.score + 1 }).where(eq(matchParticipant.id, winnerId)); - } - } - const m = await getMatchOrThrow(game.matchId); - const config = m.config; - const winsNeeded = Math.ceil(config.bestOf / 2); - const participants = await db.query.matchParticipant.findMany({ - where: eq(matchParticipant.matchId, game.matchId) - }); - const matchWinner = participants.find((p) => p.score >= winsNeeded); - if (matchWinner) { - await db.update(match).set({ - state: MATCH_STATES.FINISHED, - winnerId: matchWinner.teamId, - finishedAt: /* @__PURE__ */ new Date() - }).where(eq(match.id, game.matchId)); - await updateElo(participants, matchWinner.id); - } else { - await db.update(match).set({ state: MATCH_STATES.PICKING }).where(eq(match.id, game.matchId)); - } - return getMatchFull(game.matchId); -} -async function updateElo(participants, winnerId) { - for (const p of participants) { - const players = await db.query.matchParticipantPlayer.findMany({ - where: eq(matchParticipantPlayer.participantId, p.id) - }); - const isWinner = p.id === winnerId; - for (const player of players) { - let rating = await db.query.playerRating.findFirst({ - where: eq(playerRating.userId, player.userId) - }); - if (!rating) { - [rating] = await db.insert(playerRating).values({ userId: player.userId, elo: 1e3 }).returning(); - } - const K = 32; - const expected = 0.5; - const actual = isWinner ? 1 : 0; - const newElo = Math.round(rating.elo + K * (actual - expected)); - await db.update(playerRating).set({ - elo: newElo, - wins: isWinner ? rating.wins + 1 : rating.wins, - losses: isWinner ? rating.losses : rating.losses + 1, - updatedAt: /* @__PURE__ */ new Date() - }).where(eq(playerRating.userId, player.userId)); - } - } -} -async function cancelMatch(matchId) { - await db.update(match).set({ - state: MATCH_STATES.CANCELLED, - finishedAt: /* @__PURE__ */ new Date() - }).where(eq(match.id, matchId)); - return getMatchFull(matchId); -} -function getExpectedPicker(participants, gameCount) { - const sorted = [...participants].sort((a, b) => (a.pickOrder ?? 99) - (b.pickOrder ?? 99)); - const pickerIndex = gameCount % sorted.length; - return sorted[pickerIndex]; -} -async function getMatchFull(matchId) { - const m = await db.query.match.findFirst({ - where: eq(match.id, matchId), - with: { - mappool: { - with: { slots: true } - }, - participants: { - with: { - team: true, - players: true - } - }, - games: { - with: { - slot: true, - scores: { - with: { player: true } - } - }, - orderBy: (g, { asc: asc2 }) => [asc2(g.gameNumber)] - } - } - }); - if (!m) throw new Error("Match not found"); - return m; -} -async function getMatchOrThrow(matchId) { - const m = await db.query.match.findFirst({ - where: eq(match.id, matchId) - }); - if (!m) throw new Error("Match not found"); - return m; -} -function assertState(current, expected) { - if (current !== expected) { - throw new Error(`Match is ${current}, expected ${expected}`); - } -} -export { - MATCH_STATES as M, - cancelMatch as a, - moveToRolling as b, - createMatch as c, - submitGameScores as d, - getQueueStatus as e, - getMatchFull as g, - joinQueue as j, - leaveQueue as l, - moveToLobby as m, - pickMap as p, - submitRoll as s -}; diff --git a/.svelte-kit/output/server/chunks/environment.js b/.svelte-kit/output/server/chunks/environment.js deleted file mode 100644 index d81356b..0000000 --- a/.svelte-kit/output/server/chunks/environment.js +++ /dev/null @@ -1,14 +0,0 @@ -let building = false; -let prerendering = false; -function set_building() { - building = true; -} -function set_prerendering() { - prerendering = true; -} -export { - set_prerendering as a, - building as b, - prerendering as p, - set_building as s -}; diff --git a/.svelte-kit/output/server/chunks/exports.js b/.svelte-kit/output/server/chunks/exports.js deleted file mode 100644 index 441ec91..0000000 --- a/.svelte-kit/output/server/chunks/exports.js +++ /dev/null @@ -1,70 +0,0 @@ -function validator(expected) { - function validate(module, file) { - if (!module) return; - for (const key in module) { - if (key[0] === "_" || expected.has(key)) continue; - const values = [...expected.values()]; - const hint = hint_for_supported_files(key, file?.slice(file.lastIndexOf("."))) ?? `valid exports are ${values.join(", ")}, or anything with a '_' prefix`; - throw new Error(`Invalid export '${key}'${file ? ` in ${file}` : ""} (${hint})`); - } - } - return validate; -} -function hint_for_supported_files(key, ext = ".js") { - const supported_files = []; - if (valid_layout_exports.has(key)) { - supported_files.push(`+layout${ext}`); - } - if (valid_page_exports.has(key)) { - supported_files.push(`+page${ext}`); - } - if (valid_layout_server_exports.has(key)) { - supported_files.push(`+layout.server${ext}`); - } - if (valid_page_server_exports.has(key)) { - supported_files.push(`+page.server${ext}`); - } - if (valid_server_exports.has(key)) { - supported_files.push(`+server${ext}`); - } - if (supported_files.length > 0) { - return `'${key}' is a valid export in ${supported_files.slice(0, -1).join(", ")}${supported_files.length > 1 ? " or " : ""}${supported_files.at(-1)}`; - } -} -const valid_layout_exports = /* @__PURE__ */ new Set([ - "load", - "prerender", - "csr", - "ssr", - "trailingSlash", - "config" -]); -const valid_page_exports = /* @__PURE__ */ new Set([...valid_layout_exports, "entries"]); -const valid_layout_server_exports = /* @__PURE__ */ new Set([...valid_layout_exports]); -const valid_page_server_exports = /* @__PURE__ */ new Set([...valid_layout_server_exports, "actions", "entries"]); -const valid_server_exports = /* @__PURE__ */ new Set([ - "GET", - "POST", - "PATCH", - "PUT", - "DELETE", - "OPTIONS", - "HEAD", - "fallback", - "prerender", - "trailingSlash", - "config", - "entries" -]); -const validate_layout_exports = validator(valid_layout_exports); -const validate_page_exports = validator(valid_page_exports); -const validate_layout_server_exports = validator(valid_layout_server_exports); -const validate_page_server_exports = validator(valid_page_server_exports); -const validate_server_exports = validator(valid_server_exports); -export { - validate_layout_exports as a, - validate_page_server_exports as b, - validate_page_exports as c, - validate_server_exports as d, - validate_layout_server_exports as v -}; diff --git a/.svelte-kit/output/server/chunks/false.js b/.svelte-kit/output/server/chunks/false.js deleted file mode 100644 index f3effd6..0000000 --- a/.svelte-kit/output/server/chunks/false.js +++ /dev/null @@ -1,4 +0,0 @@ -const DEV = false; -export { - DEV as D -}; diff --git a/.svelte-kit/output/server/chunks/index.js b/.svelte-kit/output/server/chunks/index.js deleted file mode 100644 index 14b637b..0000000 --- a/.svelte-kit/output/server/chunks/index.js +++ /dev/null @@ -1,60 +0,0 @@ -import { n as noop } from "./index3.js"; -import { s as safe_not_equal } from "./root.js"; -import "clsx"; -const subscriber_queue = []; -function readable(value, start) { - return { - subscribe: writable(value, start).subscribe - }; -} -function writable(value, start = noop) { - let stop = null; - const subscribers = /* @__PURE__ */ new Set(); - function set(new_value) { - if (safe_not_equal(value, new_value)) { - value = new_value; - if (stop) { - const run_queue = !subscriber_queue.length; - for (const subscriber of subscribers) { - subscriber[1](); - subscriber_queue.push(subscriber, value); - } - if (run_queue) { - for (let i = 0; i < subscriber_queue.length; i += 2) { - subscriber_queue[i][0](subscriber_queue[i + 1]); - } - subscriber_queue.length = 0; - } - } - } - } - function update(fn) { - set(fn( - /** @type {T} */ - value - )); - } - function subscribe(run, invalidate = noop) { - const subscriber = [run, invalidate]; - subscribers.add(subscriber); - if (subscribers.size === 1) { - stop = start(set, update) || noop; - } - run( - /** @type {T} */ - value - ); - return () => { - subscribers.delete(subscriber); - if (subscribers.size === 0 && stop) { - stop(); - stop = null; - } - }; - } - return { set, update, subscribe }; -} -export { - readable as r, - writable as w -}; diff --git a/.svelte-kit/output/server/chunks/index2.js b/.svelte-kit/output/server/chunks/index2.js deleted file mode 100644 index 2c507a6..0000000 --- a/.svelte-kit/output/server/chunks/index2.js +++ /dev/null @@ -1,302 +0,0 @@ -import { drizzle } from "drizzle-orm/postgres-js"; -import postgres from "postgres"; -import { pgTable, timestamp, text, boolean, index, uuid, real, integer, jsonb, uniqueIndex } from "drizzle-orm/pg-core"; -import { relations } from "drizzle-orm"; -import { b as private_env } from "./shared-server.js"; -const user = pgTable("user", { - id: text("id").primaryKey(), - name: text("name").notNull(), - email: text("email").notNull().unique(), - emailVerified: boolean("email_verified").default(false).notNull(), - image: text("image"), - // ── Staff role: 'player' | 'referee' | 'admin' ── - role: text("role").default("player").notNull(), - createdAt: timestamp("created_at").defaultNow().notNull(), - updatedAt: timestamp("updated_at").defaultNow().$onUpdate(() => /* @__PURE__ */ new Date()).notNull() -}); -const session = pgTable( - "session", - { - id: text("id").primaryKey(), - expiresAt: timestamp("expires_at").notNull(), - token: text("token").notNull().unique(), - createdAt: timestamp("created_at").defaultNow().notNull(), - updatedAt: timestamp("updated_at").$onUpdate(() => /* @__PURE__ */ new Date()).notNull(), - ipAddress: text("ip_address"), - userAgent: text("user_agent"), - userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }) - }, - (table) => [index("session_userId_idx").on(table.userId)] -); -const account = pgTable( - "account", - { - id: text("id").primaryKey(), - accountId: text("account_id").notNull(), - providerId: text("provider_id").notNull(), - userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }), - accessToken: text("access_token"), - refreshToken: text("refresh_token"), - idToken: text("id_token"), - accessTokenExpiresAt: timestamp("access_token_expires_at"), - refreshTokenExpiresAt: timestamp("refresh_token_expires_at"), - scope: text("scope"), - password: text("password"), - createdAt: timestamp("created_at").defaultNow().notNull(), - updatedAt: timestamp("updated_at").$onUpdate(() => /* @__PURE__ */ new Date()).notNull() - }, - (table) => [index("account_userId_idx").on(table.userId)] -); -const verification = pgTable( - "verification", - { - id: text("id").primaryKey(), - identifier: text("identifier").notNull(), - value: text("value").notNull(), - expiresAt: timestamp("expires_at").notNull(), - createdAt: timestamp("created_at").defaultNow().notNull(), - updatedAt: timestamp("updated_at").defaultNow().$onUpdate(() => /* @__PURE__ */ new Date()).notNull() - }, - (table) => [index("verification_identifier_idx").on(table.identifier)] -); -const userRelations = relations(user, ({ many }) => ({ - sessions: many(session), - accounts: many(account) -})); -const sessionRelations = relations(session, ({ one }) => ({ - user: one(user, { - fields: [session.userId], - references: [user.id] - }) -})); -const accountRelations = relations(account, ({ one }) => ({ - user: one(user, { - fields: [account.userId], - references: [user.id] - }) -})); -const team = pgTable("team", { - id: uuid("id").primaryKey().defaultRandom(), - name: text("name").notNull(), - isPersonal: boolean("is_personal").default(false).notNull(), - ownerId: text("owner_id"), - avatarUrl: text("avatar_url"), - createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull() -}); -const teamMember = pgTable("team_member", { - id: uuid("id").primaryKey().defaultRandom(), - teamId: uuid("team_id").notNull().references(() => team.id, { onDelete: "cascade" }), - userId: text("user_id").notNull(), - role: text("role").default("member"), - joinedAt: timestamp("joined_at", { withTimezone: true }).defaultNow() -}); -const mappool = pgTable("mappool", { - id: uuid("id").primaryKey().defaultRandom(), - name: text("name").notNull(), - createdBy: text("created_by"), - createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull() -}); -const mappoolSlot = pgTable("mappool_slot", { - id: uuid("id").primaryKey().defaultRandom(), - mappoolId: uuid("mappool_id").notNull().references(() => mappool.id, { onDelete: "cascade" }), - category: text("category").notNull(), - orderInCategory: integer("order_in_category").notNull(), - beatmapId: text("beatmap_id").notNull(), - starRating: real("star_rating"), - mods: text("mods").array().default([]).notNull() -}); -const match = pgTable( - "match", - { - id: uuid("id").primaryKey().defaultRandom(), - name: text("name"), - state: text("state").default("CREATED").notNull(), - config: jsonb("config").notNull(), - mappoolId: uuid("mappool_id").references(() => mappool.id), - osuLobbyId: integer("osu_lobby_id"), - scheduledAt: timestamp("scheduled_at", { withTimezone: true }), - startedAt: timestamp("started_at", { withTimezone: true }), - finishedAt: timestamp("finished_at", { withTimezone: true }), - winnerId: uuid("winner_id").references(() => team.id), - createdBy: text("created_by"), - createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull() - }, - (t) => [index("idx_match_state").on(t.state)] -); -const matchParticipant = pgTable( - "match_participant", - { - id: uuid("id").primaryKey().defaultRandom(), - matchId: uuid("match_id").notNull().references(() => match.id, { onDelete: "cascade" }), - teamId: uuid("team_id").notNull().references(() => team.id), - slot: integer("slot").notNull(), - score: integer("score").default(0).notNull(), - rollValue: integer("roll_value"), - pickOrder: integer("pick_order") - }, - (t) => [ - index("idx_mp_match_team").on(t.matchId, t.teamId), - uniqueIndex("idx_mp_match_slot").on(t.matchId, t.slot), - index("idx_mp_match").on(t.matchId) - ] -); -const matchParticipantPlayer = pgTable( - "match_participant_player", - { - id: uuid("id").primaryKey().defaultRandom(), - participantId: uuid("participant_id").notNull().references(() => matchParticipant.id, { onDelete: "cascade" }), - userId: text("user_id").notNull() - }, - (t) => [ - uniqueIndex("idx_mpp_participant_user").on(t.participantId, t.userId), - index("idx_mpp_participant").on(t.participantId) - ] -); -const matchGame = pgTable( - "match_game", - { - id: uuid("id").primaryKey().defaultRandom(), - matchId: uuid("match_id").notNull().references(() => match.id, { onDelete: "cascade" }), - gameNumber: integer("game_number").notNull(), - mappoolSlotId: uuid("mappool_slot_id").notNull().references(() => mappoolSlot.id), - pickedByParticipantId: uuid("picked_by_participant_id").references(() => matchParticipant.id), - winnerParticipantId: uuid("winner_participant_id").references(() => matchParticipant.id), - state: text("state").default("PENDING").notNull(), - startedAt: timestamp("started_at", { withTimezone: true }), - finishedAt: timestamp("finished_at", { withTimezone: true }) - }, - (t) => [index("idx_match_game_match").on(t.matchId)] -); -const matchGameScore = pgTable( - "match_game_score", - { - id: uuid("id").primaryKey().defaultRandom(), - matchGameId: uuid("match_game_id").notNull().references(() => matchGame.id, { onDelete: "cascade" }), - playerId: uuid("player_id").notNull().references(() => matchParticipantPlayer.id), - score: integer("score").default(0).notNull(), - accuracy: real("accuracy").default(0).notNull(), - maxCombo: integer("max_combo").default(0).notNull(), - count300: integer("count_300").default(0).notNull(), - count100: integer("count_100").default(0).notNull(), - count50: integer("count_50").default(0).notNull(), - countMiss: integer("count_miss").default(0).notNull(), - mods: text("mods").array().default([]).notNull(), - passed: boolean("passed").default(false).notNull() - }, - (t) => [index("idx_mgs_game").on(t.matchGameId)] -); -const matchQueue = pgTable( - "match_queue", - { - id: uuid("id").primaryKey().defaultRandom(), - userId: text("user_id").notNull(), - teamId: uuid("team_id").notNull().references(() => team.id), - elo: integer("elo").default(1e3).notNull(), - joinedAt: timestamp("joined_at", { withTimezone: true }).defaultNow().notNull() - }, - (t) => [ - uniqueIndex("idx_queue_user").on(t.userId), - index("idx_queue_elo").on(t.elo) - ] -); -const playerRating = pgTable("player_rating", { - id: uuid("id").primaryKey().defaultRandom(), - userId: text("user_id").notNull().unique(), - elo: integer("elo").default(1e3).notNull(), - wins: integer("wins").default(0).notNull(), - losses: integer("losses").default(0).notNull(), - updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull() -}); -const teamRelations = relations(team, ({ many }) => ({ - members: many(teamMember) -})); -const teamMemberRelations = relations(teamMember, ({ one }) => ({ - team: one(team, { fields: [teamMember.teamId], references: [team.id] }) -})); -const mappoolRelations = relations(mappool, ({ many }) => ({ - slots: many(mappoolSlot) -})); -const mappoolSlotRelations = relations(mappoolSlot, ({ one }) => ({ - mappool: one(mappool, { fields: [mappoolSlot.mappoolId], references: [mappool.id] }) -})); -const matchRelations = relations(match, ({ one, many }) => ({ - mappool: one(mappool, { fields: [match.mappoolId], references: [mappool.id] }), - participants: many(matchParticipant), - games: many(matchGame) -})); -const matchParticipantRelations = relations(matchParticipant, ({ one, many }) => ({ - match: one(match, { fields: [matchParticipant.matchId], references: [match.id] }), - team: one(team, { fields: [matchParticipant.teamId], references: [team.id] }), - players: many(matchParticipantPlayer) -})); -const matchParticipantPlayerRelations = relations(matchParticipantPlayer, ({ one }) => ({ - participant: one(matchParticipant, { - fields: [matchParticipantPlayer.participantId], - references: [matchParticipant.id] - }) -})); -const matchGameRelations = relations(matchGame, ({ one, many }) => ({ - match: one(match, { fields: [matchGame.matchId], references: [match.id] }), - slot: one(mappoolSlot, { fields: [matchGame.mappoolSlotId], references: [mappoolSlot.id] }), - scores: many(matchGameScore) -})); -const matchGameScoreRelations = relations(matchGameScore, ({ one }) => ({ - game: one(matchGame, { fields: [matchGameScore.matchGameId], references: [matchGame.id] }), - player: one(matchParticipantPlayer, { - fields: [matchGameScore.playerId], - references: [matchParticipantPlayer.id] - }) -})); -const matchQueueRelations = relations(matchQueue, ({ one }) => ({ - team: one(team, { fields: [matchQueue.teamId], references: [team.id] }) -})); -const schema = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({ - __proto__: null, - account, - accountRelations, - mappool, - mappoolRelations, - mappoolSlot, - mappoolSlotRelations, - match, - matchGame, - matchGameRelations, - matchGameScore, - matchGameScoreRelations, - matchParticipant, - matchParticipantPlayer, - matchParticipantPlayerRelations, - matchParticipantRelations, - matchQueue, - matchQueueRelations, - matchRelations, - playerRating, - session, - sessionRelations, - team, - teamMember, - teamMemberRelations, - teamRelations, - user, - userRelations, - verification -}, Symbol.toStringTag, { value: "Module" })); -if (!private_env.DATABASE_URL) throw new Error("DATABASE_URL is not set"); -const client = postgres(private_env.DATABASE_URL); -const db = drizzle(client, { schema }); -export { - mappoolSlot as a, - match as b, - team as c, - db as d, - matchParticipant as e, - matchParticipantPlayer as f, - matchGame as g, - matchGameScore as h, - matchQueue as i, - account as j, - mappool as m, - playerRating as p, - teamMember as t, - user as u -}; diff --git a/.svelte-kit/output/server/chunks/index3.js b/.svelte-kit/output/server/chunks/index3.js deleted file mode 100644 index 20b173b..0000000 --- a/.svelte-kit/output/server/chunks/index3.js +++ /dev/null @@ -1,1249 +0,0 @@ -import { clsx as clsx$1 } from "clsx"; -import * as devalue from "devalue"; -var is_array = Array.isArray; -var index_of = Array.prototype.indexOf; -var includes = Array.prototype.includes; -var array_from = Array.from; -var define_property = Object.defineProperty; -var get_descriptor = Object.getOwnPropertyDescriptor; -var object_prototype = Object.prototype; -var array_prototype = Array.prototype; -var get_prototype_of = Object.getPrototypeOf; -var is_extensible = Object.isExtensible; -var has_own_property = Object.prototype.hasOwnProperty; -const noop = () => { -}; -function run_all(arr) { - for (var i = 0; i < arr.length; i++) { - arr[i](); - } -} -function deferred() { - var resolve; - var reject; - var promise = new Promise((res, rej) => { - resolve = res; - reject = rej; - }); - return { promise, resolve, reject }; -} -const DERIVED = 1 << 1; -const EFFECT = 1 << 2; -const RENDER_EFFECT = 1 << 3; -const MANAGED_EFFECT = 1 << 24; -const BLOCK_EFFECT = 1 << 4; -const BRANCH_EFFECT = 1 << 5; -const ROOT_EFFECT = 1 << 6; -const BOUNDARY_EFFECT = 1 << 7; -const CONNECTED = 1 << 9; -const CLEAN = 1 << 10; -const DIRTY = 1 << 11; -const MAYBE_DIRTY = 1 << 12; -const INERT = 1 << 13; -const DESTROYED = 1 << 14; -const REACTION_RAN = 1 << 15; -const EFFECT_TRANSPARENT = 1 << 16; -const EAGER_EFFECT = 1 << 17; -const HEAD_EFFECT = 1 << 18; -const EFFECT_PRESERVED = 1 << 19; -const USER_EFFECT = 1 << 20; -const WAS_MARKED = 1 << 16; -const REACTION_IS_UPDATING = 1 << 21; -const ASYNC = 1 << 22; -const ERROR_VALUE = 1 << 23; -const STATE_SYMBOL = /* @__PURE__ */ Symbol("$state"); -const LEGACY_PROPS = /* @__PURE__ */ Symbol("legacy props"); -const STALE_REACTION = new class StaleReactionError extends Error { - name = "StaleReactionError"; - message = "The reaction that called `getAbortSignal()` was re-run or destroyed"; -}(); -const COMMENT_NODE = 8; -function lifecycle_outside_component(name) { - { - throw new Error(`https://svelte.dev/e/lifecycle_outside_component`); - } -} -const HYDRATION_START = "["; -const HYDRATION_START_ELSE = "[!"; -const HYDRATION_START_FAILED = "[?"; -const HYDRATION_END = "]"; -const HYDRATION_ERROR = {}; -const ELEMENT_IS_NAMESPACED = 1; -const ELEMENT_PRESERVE_ATTRIBUTE_CASE = 1 << 1; -const ELEMENT_IS_INPUT = 1 << 2; -const UNINITIALIZED = /* @__PURE__ */ Symbol(); -const DOM_BOOLEAN_ATTRIBUTES = [ - "allowfullscreen", - "async", - "autofocus", - "autoplay", - "checked", - "controls", - "default", - "disabled", - "formnovalidate", - "indeterminate", - "inert", - "ismap", - "loop", - "multiple", - "muted", - "nomodule", - "novalidate", - "open", - "playsinline", - "readonly", - "required", - "reversed", - "seamless", - "selected", - "webkitdirectory", - "defer", - "disablepictureinpicture", - "disableremoteplayback" -]; -function is_boolean_attribute(name) { - return DOM_BOOLEAN_ATTRIBUTES.includes(name); -} -const PASSIVE_EVENTS = ["touchstart", "touchmove"]; -function is_passive_event(name) { - return PASSIVE_EVENTS.includes(name); -} -const ATTR_REGEX = /[&"<]/g; -const CONTENT_REGEX = /[&<]/g; -function escape_html(value, is_attr) { - const str = String(value ?? ""); - const pattern = is_attr ? ATTR_REGEX : CONTENT_REGEX; - pattern.lastIndex = 0; - let escaped = ""; - let last = 0; - while (pattern.test(str)) { - const i = pattern.lastIndex - 1; - const ch = str[i]; - escaped += str.substring(last, i) + (ch === "&" ? "&" : ch === '"' ? """ : "<"); - last = i + 1; - } - return escaped + str.substring(last); -} -const replacements = { - translate: /* @__PURE__ */ new Map([ - [true, "yes"], - [false, "no"] - ]) -}; -function attr(name, value, is_boolean = false) { - if (name === "hidden" && value !== "until-found") { - is_boolean = true; - } - if (value == null || !value && is_boolean) return ""; - const normalized = has_own_property.call(replacements, name) && replacements[name].get(value) || value; - const assignment = is_boolean ? `=""` : `="${escape_html(normalized, true)}"`; - return ` ${name}${assignment}`; -} -function clsx(value) { - if (typeof value === "object") { - return clsx$1(value); - } else { - return value ?? ""; - } -} -const whitespace = [..." \n\r\f \v\uFEFF"]; -function to_class(value, hash, directives) { - var classname = value == null ? "" : "" + value; - if (hash) { - classname = classname ? classname + " " + hash : hash; - } - if (directives) { - for (var key of Object.keys(directives)) { - if (directives[key]) { - classname = classname ? classname + " " + key : key; - } else if (classname.length) { - var len = key.length; - var a = 0; - while ((a = classname.indexOf(key, a)) >= 0) { - var b = a + len; - if ((a === 0 || whitespace.includes(classname[a - 1])) && (b === classname.length || whitespace.includes(classname[b]))) { - classname = (a === 0 ? "" : classname.substring(0, a)) + classname.substring(b + 1); - } else { - a = b; - } - } - } - } - } - return classname === "" ? null : classname; -} -function append_styles(styles, important = false) { - var separator = important ? " !important;" : ";"; - var css = ""; - for (var key of Object.keys(styles)) { - var value = styles[key]; - if (value != null && value !== "") { - css += " " + key + ": " + value + separator; - } - } - return css; -} -function to_css_name(name) { - if (name[0] !== "-" || name[1] !== "-") { - return name.toLowerCase(); - } - return name; -} -function to_style(value, styles) { - if (styles) { - var new_style = ""; - var normal_styles; - var important_styles; - if (Array.isArray(styles)) { - normal_styles = styles[0]; - important_styles = styles[1]; - } else { - normal_styles = styles; - } - if (value) { - value = String(value).replaceAll(/\s*\/\*.*?\*\/\s*/g, "").trim(); - var in_str = false; - var in_apo = 0; - var in_comment = false; - var reserved_names = []; - if (normal_styles) { - reserved_names.push(...Object.keys(normal_styles).map(to_css_name)); - } - if (important_styles) { - reserved_names.push(...Object.keys(important_styles).map(to_css_name)); - } - var start_index = 0; - var name_index = -1; - const len = value.length; - for (var i = 0; i < len; i++) { - var c = value[i]; - if (in_comment) { - if (c === "/" && value[i - 1] === "*") { - in_comment = false; - } - } else if (in_str) { - if (in_str === c) { - in_str = false; - } - } else if (c === "/" && value[i + 1] === "*") { - in_comment = true; - } else if (c === '"' || c === "'") { - in_str = c; - } else if (c === "(") { - in_apo++; - } else if (c === ")") { - in_apo--; - } - if (!in_comment && in_str === false && in_apo === 0) { - if (c === ":" && name_index === -1) { - name_index = i; - } else if (c === ";" || i === len - 1) { - if (name_index !== -1) { - var name = to_css_name(value.substring(start_index, name_index).trim()); - if (!reserved_names.includes(name)) { - if (c !== ";") { - i++; - } - var property = value.substring(start_index, i).trim(); - new_style += " " + property + ";"; - } - } - start_index = i + 1; - name_index = -1; - } - } - } - } - if (normal_styles) { - new_style += append_styles(normal_styles); - } - if (important_styles) { - new_style += append_styles(important_styles, true); - } - new_style = new_style.trim(); - return new_style === "" ? null : new_style; - } - return value == null ? null : String(value); -} -const BLOCK_OPEN = ``; -const BLOCK_CLOSE = ``; -let controller = null; -function abort() { - controller?.abort(STALE_REACTION); - controller = null; -} -function await_invalid() { - const error = new Error(`await_invalid -Encountered asynchronous work while rendering synchronously. -https://svelte.dev/e/await_invalid`); - error.name = "Svelte error"; - throw error; -} -function invalid_csp() { - const error = new Error(`invalid_csp -\`csp.nonce\` was set while \`csp.hash\` was \`true\`. These options cannot be used simultaneously. -https://svelte.dev/e/invalid_csp`); - error.name = "Svelte error"; - throw error; -} -function server_context_required() { - const error = new Error(`server_context_required -Could not resolve \`render\` context. -https://svelte.dev/e/server_context_required`); - error.name = "Svelte error"; - throw error; -} -var ssr_context = null; -function set_ssr_context(v) { - ssr_context = v; -} -function getContext(key) { - const context_map = get_or_init_context_map(); - const result = ( - /** @type {T} */ - context_map.get(key) - ); - return result; -} -function setContext(key, context) { - get_or_init_context_map().set(key, context); - return context; -} -function get_or_init_context_map(name) { - if (ssr_context === null) { - lifecycle_outside_component(); - } - return ssr_context.c ??= new Map(get_parent_context(ssr_context) || void 0); -} -function push(fn) { - ssr_context = { p: ssr_context, c: null, r: null }; -} -function pop() { - ssr_context = /** @type {SSRContext} */ - ssr_context.p; -} -function get_parent_context(ssr_context2) { - let parent = ssr_context2.p; - while (parent !== null) { - const context_map = parent.c; - if (context_map !== null) { - return context_map; - } - parent = parent.p; - } - return null; -} -function unresolved_hydratable(key, stack) { - { - console.warn(`https://svelte.dev/e/unresolved_hydratable`); - } -} -function get_render_context() { - const store = als?.getStore(); - { - server_context_required(); - } - return store; -} -let als = null; -let text_encoder; -let crypto; -const obfuscated_import = (module_name) => import( - /* @vite-ignore */ - module_name -); -async function sha256(data) { - text_encoder ??= new TextEncoder(); - crypto ??= globalThis.crypto?.subtle?.digest ? globalThis.crypto : ( - // @ts-ignore - we don't install node types in the prod build - // don't use import('node:crypto') directly because static analysers will think we rely on node when we don't - (await obfuscated_import("node:crypto")).webcrypto - ); - const hash_buffer = await crypto.subtle.digest("SHA-256", text_encoder.encode(data)); - return base64_encode(hash_buffer); -} -function base64_encode(bytes) { - if (globalThis.Buffer) { - return globalThis.Buffer.from(bytes).toString("base64"); - } - let binary = ""; - for (let i = 0; i < bytes.length; i++) { - binary += String.fromCharCode(bytes[i]); - } - return btoa(binary); -} -class Renderer { - /** - * The contents of the renderer. - * @type {RendererItem[]} - */ - #out = []; - /** - * Any `onDestroy` callbacks registered during execution of this renderer. - * @type {(() => void)[] | undefined} - */ - #on_destroy = void 0; - /** - * Whether this renderer is a component body. - * @type {boolean} - */ - #is_component_body = false; - /** - * If set, this renderer is an error boundary. When async collection - * of the children fails, the failed snippet is rendered instead. - * @type {{ - * failed: (renderer: Renderer, error: unknown, reset: () => void) => void; - * transformError: (error: unknown) => unknown; - * context: SSRContext | null; - * } | null} - */ - #boundary = null; - /** - * The type of string content that this renderer is accumulating. - * @type {RendererType} - */ - type; - /** @type {Renderer | undefined} */ - #parent; - /** - * Asynchronous work associated with this renderer - * @type {Promise | undefined} - */ - promise = void 0; - /** - * State which is associated with the content tree as a whole. - * It will be re-exposed, uncopied, on all children. - * @type {SSRState} - * @readonly - */ - global; - /** - * State that is local to the branch it is declared in. - * It will be shallow-copied to all children. - * - * @type {{ select_value: string | undefined }} - */ - local; - /** - * @param {SSRState} global - * @param {Renderer | undefined} [parent] - */ - constructor(global, parent) { - this.#parent = parent; - this.global = global; - this.local = parent ? { ...parent.local } : { select_value: void 0 }; - this.type = parent ? parent.type : "body"; - } - /** - * @param {(renderer: Renderer) => void} fn - */ - head(fn) { - const head = new Renderer(this.global, this); - head.type = "head"; - this.#out.push(head); - head.child(fn); - } - /** - * @param {Array>} blockers - * @param {(renderer: Renderer) => void} fn - */ - async_block(blockers, fn) { - this.#out.push(BLOCK_OPEN); - this.async(blockers, fn); - this.#out.push(BLOCK_CLOSE); - } - /** - * @param {Array>} blockers - * @param {(renderer: Renderer) => void} fn - */ - async(blockers, fn) { - let callback = fn; - if (blockers.length > 0) { - const context = ssr_context; - callback = (renderer) => { - return Promise.all(blockers).then(() => { - const previous_context = ssr_context; - try { - set_ssr_context(context); - return fn(renderer); - } finally { - set_ssr_context(previous_context); - } - }); - }; - } - this.child(callback); - } - /** - * @param {Array<() => void>} thunks - */ - run(thunks) { - const context = ssr_context; - let promise = Promise.resolve(thunks[0]()); - const promises = [promise]; - for (const fn of thunks.slice(1)) { - promise = promise.then(() => { - const previous_context = ssr_context; - set_ssr_context(context); - try { - return fn(); - } finally { - set_ssr_context(previous_context); - } - }); - promises.push(promise); - } - promise.catch(noop); - this.promise = promise; - return promises; - } - /** - * @param {(renderer: Renderer) => MaybePromise} fn - */ - child_block(fn) { - this.#out.push(BLOCK_OPEN); - this.child(fn); - this.#out.push(BLOCK_CLOSE); - } - /** - * Create a child renderer. The child renderer inherits the state from the parent, - * but has its own content. - * @param {(renderer: Renderer) => MaybePromise} fn - */ - child(fn) { - const child = new Renderer(this.global, this); - this.#out.push(child); - const parent = ssr_context; - set_ssr_context({ - ...ssr_context, - p: parent, - c: null, - r: child - }); - const result = fn(child); - set_ssr_context(parent); - if (result instanceof Promise) { - result.catch(noop); - result.finally(() => set_ssr_context(null)).catch(noop); - if (child.global.mode === "sync") { - await_invalid(); - } - child.promise = result; - } - return child; - } - /** - * Render children inside an error boundary. If the children throw and the API-level - * `transformError` transform handles the error (doesn't re-throw), the `failed` snippet is - * rendered instead. Otherwise the error propagates. - * - * @param {{ failed?: (renderer: Renderer, error: unknown, reset: () => void) => void }} props - * @param {(renderer: Renderer) => MaybePromise} children_fn - */ - boundary(props, children_fn) { - const child = new Renderer(this.global, this); - this.#out.push(child); - const parent_context = ssr_context; - if (props.failed) { - child.#boundary = { - failed: props.failed, - transformError: this.global.transformError, - context: parent_context - }; - } - set_ssr_context({ - ...ssr_context, - p: parent_context, - c: null, - r: child - }); - try { - const result = children_fn(child); - set_ssr_context(parent_context); - if (result instanceof Promise) { - if (child.global.mode === "sync") { - await_invalid(); - } - result.catch(noop); - child.promise = result; - } - } catch (error) { - set_ssr_context(parent_context); - const failed_snippet = props.failed; - if (!failed_snippet) throw error; - const result = this.global.transformError(error); - child.#out.length = 0; - child.#boundary = null; - if (result instanceof Promise) { - if (this.global.mode === "sync") { - await_invalid(); - } - child.promise = /** @type {Promise} */ - result.then((transformed) => { - set_ssr_context(parent_context); - child.#out.push(Renderer.#serialize_failed_boundary(transformed)); - failed_snippet(child, transformed, noop); - child.#out.push(BLOCK_CLOSE); - }); - child.promise.catch(noop); - } else { - child.#out.push(Renderer.#serialize_failed_boundary(result)); - failed_snippet(child, result, noop); - child.#out.push(BLOCK_CLOSE); - } - } - } - /** - * Create a component renderer. The component renderer inherits the state from the parent, - * but has its own content. It is treated as an ordering boundary for ondestroy callbacks. - * @param {(renderer: Renderer) => MaybePromise} fn - * @param {Function} [component_fn] - * @returns {void} - */ - component(fn, component_fn) { - push(); - const child = this.child(fn); - child.#is_component_body = true; - pop(); - } - /** - * @param {Record} attrs - * @param {(renderer: Renderer) => void} fn - * @param {string | undefined} [css_hash] - * @param {Record | undefined} [classes] - * @param {Record | undefined} [styles] - * @param {number | undefined} [flags] - * @param {boolean | undefined} [is_rich] - * @returns {void} - */ - select(attrs, fn, css_hash, classes, styles, flags, is_rich) { - const { value, ...select_attrs } = attrs; - this.push(``); - this.child((renderer) => { - renderer.local.select_value = value; - fn(renderer); - }); - this.push(`${is_rich ? "" : ""}`); - } - /** - * @param {Record} attrs - * @param {string | number | boolean | ((renderer: Renderer) => void)} body - * @param {string | undefined} [css_hash] - * @param {Record | undefined} [classes] - * @param {Record | undefined} [styles] - * @param {number | undefined} [flags] - * @param {boolean | undefined} [is_rich] - */ - option(attrs, body, css_hash, classes, styles, flags, is_rich) { - this.#out.push(` { - if (has_own_property.call(attrs, "value")) { - value = attrs.value; - } - if (value === this.local.select_value) { - renderer.#out.push(' selected=""'); - } - renderer.#out.push(`>${body2}${is_rich ? "" : ""}`); - if (head) { - renderer.head((child) => child.push(head)); - } - }; - if (typeof body === "function") { - this.child((renderer) => { - const r = new Renderer(this.global, this); - body(r); - if (this.global.mode === "async") { - return r.#collect_content_async().then((content) => { - close(renderer, content.body.replaceAll("", ""), content); - }); - } else { - const content = r.#collect_content(); - close(renderer, content.body.replaceAll("", ""), content); - } - }); - } else { - close(this, body, { body: escape_html(body) }); - } - } - /** - * @param {(renderer: Renderer) => void} fn - */ - title(fn) { - const path = this.get_path(); - const close = (head) => { - this.global.set_title(head, path); - }; - this.child((renderer) => { - const r = new Renderer(renderer.global, renderer); - fn(r); - if (renderer.global.mode === "async") { - return r.#collect_content_async().then((content) => { - close(content.head); - }); - } else { - const content = r.#collect_content(); - close(content.head); - } - }); - } - /** - * @param {string | (() => Promise)} content - */ - push(content) { - if (typeof content === "function") { - this.child(async (renderer) => renderer.push(await content())); - } else { - this.#out.push(content); - } - } - /** - * @param {() => void} fn - */ - on_destroy(fn) { - (this.#on_destroy ??= []).push(fn); - } - /** - * @returns {number[]} - */ - get_path() { - return this.#parent ? [...this.#parent.get_path(), this.#parent.#out.indexOf(this)] : []; - } - /** - * @deprecated this is needed for legacy component bindings - */ - copy() { - const copy = new Renderer(this.global, this.#parent); - copy.#out = this.#out.map((item) => item instanceof Renderer ? item.copy() : item); - copy.promise = this.promise; - return copy; - } - /** - * @param {Renderer} other - * @deprecated this is needed for legacy component bindings - */ - subsume(other) { - if (this.global.mode !== other.global.mode) { - throw new Error( - "invariant: A renderer cannot switch modes. If you're seeing this, there's a compiler bug. File an issue!" - ); - } - this.local = other.local; - this.#out = other.#out.map((item) => { - if (item instanceof Renderer) { - item.subsume(item); - } - return item; - }); - this.promise = other.promise; - this.type = other.type; - } - get length() { - return this.#out.length; - } - /** - * Creates the hydration comment that marks the start of a failed boundary. - * The error is JSON-serialized and embedded inside an HTML comment for the client - * to parse during hydration. The JSON is escaped to prevent `-->` or ``; - } - /** - * Only available on the server and when compiling with the `server` option. - * Takes a component and returns an object with `body` and `head` properties on it, which you can use to populate the HTML when server-rendering your app. - * @template {Record} Props - * @param {Component} component - * @param {{ props?: Omit; context?: Map; idPrefix?: string; csp?: Csp }} [options] - * @returns {RenderOutput} - */ - static render(component, options = {}) { - let sync; - const result = ( - /** @type {RenderOutput} */ - {} - ); - Object.defineProperties(result, { - html: { - get: () => { - return (sync ??= Renderer.#render(component, options)).body; - } - }, - head: { - get: () => { - return (sync ??= Renderer.#render(component, options)).head; - } - }, - body: { - get: () => { - return (sync ??= Renderer.#render(component, options)).body; - } - }, - hashes: { - value: { - script: "" - } - }, - then: { - value: ( - /** - * this is not type-safe, but honestly it's the best I can do right now, and it's a straightforward function. - * - * @template TResult1 - * @template [TResult2=never] - * @param { (value: SyncRenderOutput) => TResult1 } onfulfilled - * @param { (reason: unknown) => TResult2 } onrejected - */ - (onfulfilled, onrejected) => { - { - const result2 = sync ??= Renderer.#render(component, options); - const user_result = onfulfilled({ - head: result2.head, - body: result2.body, - html: result2.body, - hashes: { script: [] } - }); - return Promise.resolve(user_result); - } - } - ) - } - }); - return result; - } - /** - * Collect all of the `onDestroy` callbacks registered during rendering. In an async context, this is only safe to call - * after awaiting `collect_async`. - * - * Child renderers are "porous" and don't affect execution order, but component body renderers - * create ordering boundaries. Within a renderer, callbacks run in order until hitting a component boundary. - * @returns {Iterable<() => void>} - */ - *#collect_on_destroy() { - for (const component of this.#traverse_components()) { - yield* component.#collect_ondestroy(); - } - } - /** - * Performs a depth-first search of renderers, yielding the deepest components first, then additional components as we backtrack up the tree. - * @returns {Iterable} - */ - *#traverse_components() { - for (const child of this.#out) { - if (typeof child !== "string") { - yield* child.#traverse_components(); - } - } - if (this.#is_component_body) { - yield this; - } - } - /** - * @returns {Iterable<() => void>} - */ - *#collect_ondestroy() { - if (this.#on_destroy) { - for (const fn of this.#on_destroy) { - yield fn; - } - } - for (const child of this.#out) { - if (child instanceof Renderer && !child.#is_component_body) { - yield* child.#collect_ondestroy(); - } - } - } - /** - * Render a component. Throws if any of the children are performing asynchronous work. - * - * @template {Record} Props - * @param {Component} component - * @param {{ props?: Omit; context?: Map; idPrefix?: string }} options - * @returns {AccumulatedContent} - */ - static #render(component, options) { - var previous_context = ssr_context; - try { - const renderer = Renderer.#open_render("sync", component, options); - const content = renderer.#collect_content(); - return Renderer.#close_render(content, renderer); - } finally { - abort(); - set_ssr_context(previous_context); - } - } - /** - * Render a component. - * - * @template {Record} Props - * @param {Component} component - * @param {{ props?: Omit; context?: Map; idPrefix?: string; csp?: Csp }} options - * @returns {Promise} - */ - static async #render_async(component, options) { - const previous_context = ssr_context; - try { - const renderer = Renderer.#open_render("async", component, options); - const content = await renderer.#collect_content_async(); - const hydratables = await renderer.#collect_hydratables(); - if (hydratables !== null) { - content.head = hydratables + content.head; - } - return Renderer.#close_render(content, renderer); - } finally { - set_ssr_context(previous_context); - abort(); - } - } - /** - * Collect all of the code from the `out` array and return it as a string, or a promise resolving to a string. - * @param {AccumulatedContent} content - * @returns {AccumulatedContent} - */ - #collect_content(content = { head: "", body: "" }) { - for (const item of this.#out) { - if (typeof item === "string") { - content[this.type] += item; - } else if (item instanceof Renderer) { - item.#collect_content(content); - } - } - return content; - } - /** - * Collect all of the code from the `out` array and return it as a string. - * @param {AccumulatedContent} content - * @returns {Promise} - */ - async #collect_content_async(content = { head: "", body: "" }) { - await this.promise; - for (const item of this.#out) { - if (typeof item === "string") { - content[this.type] += item; - } else if (item instanceof Renderer) { - if (item.#boundary) { - const boundary_content = { head: "", body: "" }; - try { - await item.#collect_content_async(boundary_content); - content.head += boundary_content.head; - content.body += boundary_content.body; - } catch (error) { - const { context, failed, transformError } = item.#boundary; - set_ssr_context(context); - let transformed = await transformError(error); - const failed_renderer = new Renderer(item.global, item); - failed_renderer.type = item.type; - failed_renderer.#out.push(Renderer.#serialize_failed_boundary(transformed)); - failed(failed_renderer, transformed, noop); - failed_renderer.#out.push(BLOCK_CLOSE); - await failed_renderer.#collect_content_async(content); - } - } else { - await item.#collect_content_async(content); - } - } - } - return content; - } - async #collect_hydratables() { - const ctx = get_render_context().hydratable; - for (const [_, key] of ctx.unresolved_promises) { - unresolved_hydratable(key, ctx.lookup.get(key)?.stack ?? ""); - } - for (const comparison of ctx.comparisons) { - await comparison; - } - return await this.#hydratable_block(ctx); - } - /** - * @template {Record} Props - * @param {'sync' | 'async'} mode - * @param {import('svelte').Component} component - * @param {{ props?: Omit; context?: Map; idPrefix?: string; csp?: Csp; transformError?: (error: unknown) => unknown }} options - * @returns {Renderer} - */ - static #open_render(mode, component, options) { - var previous_context = ssr_context; - try { - const renderer = new Renderer( - new SSRState( - mode, - options.idPrefix ? options.idPrefix + "-" : "", - options.csp, - options.transformError - ) - ); - const context = { p: null, c: options.context ?? null, r: renderer }; - set_ssr_context(context); - renderer.push(BLOCK_OPEN); - component(renderer, options.props ?? {}); - renderer.push(BLOCK_CLOSE); - return renderer; - } finally { - set_ssr_context(previous_context); - } - } - /** - * @param {AccumulatedContent} content - * @param {Renderer} renderer - * @returns {AccumulatedContent & { hashes: { script: Sha256Source[] } }} - */ - static #close_render(content, renderer) { - for (const cleanup of renderer.#collect_on_destroy()) { - cleanup(); - } - let head = content.head + renderer.global.get_title(); - let body = content.body; - for (const { hash, code } of renderer.global.css) { - head += ``; - } - return { - head, - body, - hashes: { - script: renderer.global.csp.script_hashes - } - }; - } - /** - * @param {HydratableContext} ctx - */ - async #hydratable_block(ctx) { - if (ctx.lookup.size === 0) { - return null; - } - let entries = []; - let has_promises = false; - for (const [k, v] of ctx.lookup) { - if (v.promises) { - has_promises = true; - for (const p of v.promises) await p; - } - entries.push(`[${devalue.uneval(k)},${v.serialized}]`); - } - let prelude = `const h = (window.__svelte ??= {}).h ??= new Map();`; - if (has_promises) { - prelude = `const r = (v) => Promise.resolve(v); - ${prelude}`; - } - const body = ` - { - ${prelude} - - for (const [k, v] of [ - ${entries.join(",\n ")} - ]) { - h.set(k, v); - } - } - `; - let csp_attr = ""; - if (this.global.csp.nonce) { - csp_attr = ` nonce="${this.global.csp.nonce}"`; - } else if (this.global.csp.hash) { - const hash = await sha256(body); - this.global.csp.script_hashes.push(`sha256-${hash}`); - } - return ` - ${body}<\/script>`; - } -} -class SSRState { - /** @readonly @type {Csp & { script_hashes: Sha256Source[] }} */ - csp; - /** @readonly @type {'sync' | 'async'} */ - mode; - /** @readonly @type {() => string} */ - uid; - /** @readonly @type {Set<{ hash: string; code: string }>} */ - css = /* @__PURE__ */ new Set(); - /** - * `transformError` passed to `render`. Called when an error boundary catches an error. - * Throws by default if unset in `render`. - * @type {(error: unknown) => unknown} - */ - transformError; - /** @type {{ path: number[], value: string }} */ - #title = { path: [], value: "" }; - /** - * @param {'sync' | 'async'} mode - * @param {string} id_prefix - * @param {Csp} csp - * @param {((error: unknown) => unknown) | undefined} [transformError] - */ - constructor(mode, id_prefix = "", csp = { hash: false }, transformError) { - this.mode = mode; - this.csp = { ...csp, script_hashes: [] }; - this.transformError = transformError ?? ((error) => { - throw error; - }); - let uid = 1; - this.uid = () => `${id_prefix}s${uid++}`; - } - get_title() { - return this.#title.value; - } - /** - * Performs a depth-first (lexicographic) comparison using the path. Rejects sets - * from earlier than or equal to the current value. - * @param {string} value - * @param {number[]} path - */ - set_title(value, path) { - const current = this.#title.path; - let i = 0; - let l = Math.min(path.length, current.length); - while (i < l && path[i] === current[i]) i += 1; - if (path[i] === void 0) return; - if (current[i] === void 0 || path[i] > current[i]) { - this.#title.path = path; - this.#title.value = value; - } - } -} -const INVALID_ATTR_NAME_CHAR_REGEX = /[\s'">/=\u{FDD0}-\u{FDEF}\u{FFFE}\u{FFFF}\u{1FFFE}\u{1FFFF}\u{2FFFE}\u{2FFFF}\u{3FFFE}\u{3FFFF}\u{4FFFE}\u{4FFFF}\u{5FFFE}\u{5FFFF}\u{6FFFE}\u{6FFFF}\u{7FFFE}\u{7FFFF}\u{8FFFE}\u{8FFFF}\u{9FFFE}\u{9FFFF}\u{AFFFE}\u{AFFFF}\u{BFFFE}\u{BFFFF}\u{CFFFE}\u{CFFFF}\u{DFFFE}\u{DFFFF}\u{EFFFE}\u{EFFFF}\u{FFFFE}\u{FFFFF}\u{10FFFE}\u{10FFFF}]/u; -function render(component, options = {}) { - if (options.csp?.hash && options.csp.nonce) { - invalid_csp(); - } - return Renderer.render( - /** @type {Component} */ - component, - options - ); -} -function attributes(attrs, css_hash, classes, styles, flags = 0) { - if (styles) { - attrs.style = to_style(attrs.style, styles); - } - if (attrs.class) { - attrs.class = clsx(attrs.class); - } - if (css_hash || classes) { - attrs.class = to_class(attrs.class, css_hash, classes); - } - let attr_str = ""; - let name; - const is_html = (flags & ELEMENT_IS_NAMESPACED) === 0; - const lowercase = (flags & ELEMENT_PRESERVE_ATTRIBUTE_CASE) === 0; - const is_input = (flags & ELEMENT_IS_INPUT) !== 0; - for (name of Object.keys(attrs)) { - if (typeof attrs[name] === "function") continue; - if (name[0] === "$" && name[1] === "$") continue; - if (INVALID_ATTR_NAME_CHAR_REGEX.test(name)) continue; - var value = attrs[name]; - if (lowercase) { - name = name.toLowerCase(); - } - if (name.length > 2 && name.startsWith("on")) continue; - if (is_input) { - if (name === "defaultvalue" || name === "defaultchecked") { - name = name === "defaultvalue" ? "value" : "checked"; - if (attrs[name]) continue; - } - } - attr_str += attr(name, value, is_html && is_boolean_attribute(name)); - } - return attr_str; -} -function stringify(value) { - return typeof value === "string" ? value : value == null ? "" : value + ""; -} -function attr_class(value, hash, directives) { - var result = to_class(value, hash, directives); - return result ? ` class="${escape_html(result, true)}"` : ""; -} -function ensure_array_like(array_like_or_iterator) { - if (array_like_or_iterator) { - return array_like_or_iterator.length !== void 0 ? array_like_or_iterator : Array.from(array_like_or_iterator); - } - return []; -} -function once(get_value) { - let value = ( - /** @type {V} */ - UNINITIALIZED - ); - return () => { - if (value === UNINITIALIZED) { - value = get_value(); - } - return value; - }; -} -function derived(fn) { - const get_value = ssr_context === null ? fn : once(fn); - let updated_value; - return function(new_value) { - if (arguments.length === 0) { - return updated_value ?? get_value(); - } - updated_value = new_value; - return updated_value; - }; -} -export { - is_passive_event as $, - ASYNC as A, - BOUNDARY_EFFECT as B, - COMMENT_NODE as C, - DIRTY as D, - ERROR_VALUE as E, - EFFECT_TRANSPARENT as F, - EFFECT_PRESERVED as G, - HYDRATION_ERROR as H, - INERT as I, - EAGER_EFFECT as J, - STATE_SYMBOL as K, - object_prototype as L, - MAYBE_DIRTY as M, - array_prototype as N, - get_descriptor as O, - get_prototype_of as P, - is_array as Q, - REACTION_RAN as R, - STALE_REACTION as S, - is_extensible as T, - UNINITIALIZED as U, - USER_EFFECT as V, - WAS_MARKED as W, - REACTION_IS_UPDATING as X, - index_of as Y, - define_property as Z, - array_from as _, - ensure_array_like as a, - LEGACY_PROPS as a0, - render as a1, - setContext as a2, - attr as b, - attr_class as c, - derived as d, - escape_html as e, - HYDRATION_END as f, - getContext as g, - HYDRATION_START as h, - HYDRATION_START_ELSE as i, - EFFECT as j, - CONNECTED as k, - CLEAN as l, - DERIVED as m, - noop as n, - BLOCK_EFFECT as o, - deferred as p, - BRANCH_EFFECT as q, - run_all as r, - stringify as s, - ROOT_EFFECT as t, - RENDER_EFFECT as u, - MANAGED_EFFECT as v, - HEAD_EFFECT as w, - DESTROYED as x, - includes as y, - HYDRATION_START_FAILED as z -}; diff --git a/.svelte-kit/output/server/chunks/index4.js b/.svelte-kit/output/server/chunks/index4.js deleted file mode 100644 index 2ae44a6..0000000 --- a/.svelte-kit/output/server/chunks/index4.js +++ /dev/null @@ -1,47 +0,0 @@ -import "./state.svelte.js"; -import "clsx"; -import "@sveltejs/kit/internal"; -import "./url.js"; -import "./utils.js"; -import { w as writable } from "./index.js"; -import "@sveltejs/kit/internal/server"; -import "./root.js"; -import "./exports.js"; -import { g as getContext } from "./index3.js"; -function create_updated_store() { - const { set, subscribe } = writable(false); - { - return { - subscribe, - // eslint-disable-next-line @typescript-eslint/require-await - check: async () => false - }; - } -} -const stores = { - updated: /* @__PURE__ */ create_updated_store() -}; -({ - check: stores.updated.check -}); -function context() { - return getContext("__request__"); -} -const page$1 = { - get data() { - return context().page.data; - }, - get error() { - return context().page.error; - }, - get status() { - return context().page.status; - }, - get url() { - return context().page.url; - } -}; -const page = page$1; -export { - page as p -}; diff --git a/.svelte-kit/output/server/chunks/index5.js b/.svelte-kit/output/server/chunks/index5.js deleted file mode 100644 index 5a5bcdc..0000000 --- a/.svelte-kit/output/server/chunks/index5.js +++ /dev/null @@ -1,224 +0,0 @@ -import { logger } from "@better-auth/core/env"; -import { createAdapterFactory } from "@better-auth/core/db/adapter"; -const memoryAdapter = (db, config) => { - let lazyOptions = null; - const adapterCreator = createAdapterFactory({ - config: { - adapterId: "memory", - adapterName: "Memory Adapter", - usePlural: false, - debugLogs: config?.debugLogs || false, - supportsArrays: true, - customTransformInput(props) { - if ((props.options.advanced?.database?.useNumberId || props.options.advanced?.database?.generateId === "serial") && props.field === "id" && props.action === "create") return db[props.model].length + 1; - return props.data; - }, - transaction: async (cb) => { - const clone = structuredClone(db); - try { - return await cb(adapterCreator(lazyOptions)); - } catch (error) { - Object.keys(db).forEach((key) => { - db[key] = clone[key]; - }); - throw error; - } - } - }, - adapter: ({ getFieldName, getDefaultFieldName, options, getModelName }) => { - const applySortToRecords = (records, sortBy, model) => { - if (!sortBy) return records; - return records.sort((a, b) => { - const field = getFieldName({ - model, - field: sortBy.field - }); - const aValue = a[field]; - const bValue = b[field]; - let comparison = 0; - if (aValue == null && bValue == null) comparison = 0; - else if (aValue == null) comparison = -1; - else if (bValue == null) comparison = 1; - else if (typeof aValue === "string" && typeof bValue === "string") comparison = aValue.localeCompare(bValue); - else if (aValue instanceof Date && bValue instanceof Date) comparison = aValue.getTime() - bValue.getTime(); - else if (typeof aValue === "number" && typeof bValue === "number") comparison = aValue - bValue; - else if (typeof aValue === "boolean" && typeof bValue === "boolean") comparison = aValue === bValue ? 0 : aValue ? 1 : -1; - else comparison = String(aValue).localeCompare(String(bValue)); - return sortBy.direction === "asc" ? comparison : -comparison; - }); - }; - function convertWhereClause(where, model, join, select) { - const baseRecords = (() => { - const table = db[model]; - if (!table) { - logger.error(`[MemoryAdapter] Model ${model} not found in the DB`, Object.keys(db)); - throw new Error(`Model ${model} not found`); - } - const evalClause = (record, clause) => { - const { field, value, operator } = clause; - switch (operator) { - case "in": - if (!Array.isArray(value)) throw new Error("Value must be an array"); - return value.includes(record[field]); - case "not_in": - if (!Array.isArray(value)) throw new Error("Value must be an array"); - return !value.includes(record[field]); - case "contains": - return record[field].includes(value); - case "starts_with": - return record[field].startsWith(value); - case "ends_with": - return record[field].endsWith(value); - case "ne": - return record[field] !== value; - case "gt": - return value != null && Boolean(record[field] > value); - case "gte": - return value != null && Boolean(record[field] >= value); - case "lt": - return value != null && Boolean(record[field] < value); - case "lte": - return value != null && Boolean(record[field] <= value); - default: - return record[field] === value; - } - }; - let records = table.filter((record) => { - if (!where.length || where.length === 0) return true; - let result = evalClause(record, where[0]); - for (const clause of where) { - const clauseResult = evalClause(record, clause); - if (clause.connector === "OR") result = result || clauseResult; - else result = result && clauseResult; - } - return result; - }); - if (select?.length && select.length > 0) records = records.map((record) => Object.fromEntries(Object.entries(record).filter(([key]) => select.includes(getDefaultFieldName({ - model, - field: key - }))))); - return records; - })(); - if (!join) return baseRecords; - const grouped = /* @__PURE__ */ new Map(); - const seenIds = /* @__PURE__ */ new Map(); - for (const baseRecord of baseRecords) { - const baseId = String(baseRecord.id); - if (!grouped.has(baseId)) { - const nested = { ...baseRecord }; - for (const [joinModel, joinAttr] of Object.entries(join)) { - const joinModelName = getModelName(joinModel); - if (joinAttr.relation === "one-to-one") nested[joinModelName] = null; - else { - nested[joinModelName] = []; - seenIds.set(`${baseId}-${joinModel}`, /* @__PURE__ */ new Set()); - } - } - grouped.set(baseId, nested); - } - const nestedEntry = grouped.get(baseId); - for (const [joinModel, joinAttr] of Object.entries(join)) { - const joinModelName = getModelName(joinModel); - const joinTable = db[joinModelName]; - if (!joinTable) { - logger.error(`[MemoryAdapter] JoinOption model ${joinModelName} not found in the DB`, Object.keys(db)); - throw new Error(`JoinOption model ${joinModelName} not found`); - } - const matchingRecords = joinTable.filter((joinRecord) => joinRecord[joinAttr.on.to] === baseRecord[joinAttr.on.from]); - if (joinAttr.relation === "one-to-one") nestedEntry[joinModelName] = matchingRecords[0] || null; - else { - const seenSet = seenIds.get(`${baseId}-${joinModel}`); - const limit = joinAttr.limit ?? 100; - let count = 0; - for (const matchingRecord of matchingRecords) { - if (count >= limit) break; - if (!seenSet.has(matchingRecord.id)) { - nestedEntry[joinModelName].push(matchingRecord); - seenSet.add(matchingRecord.id); - count++; - } - } - } - } - } - return Array.from(grouped.values()); - } - return { - create: async ({ model, data }) => { - if (options.advanced?.database?.useNumberId || options.advanced?.database?.generateId === "serial") data.id = db[getModelName(model)].length + 1; - if (!db[model]) db[model] = []; - db[model].push(data); - return data; - }, - findOne: async ({ model, where, select, join }) => { - const res = convertWhereClause(where, model, join, select); - if (join) { - const resArray = res; - if (!resArray.length) return null; - return resArray[0]; - } - return res[0] || null; - }, - findMany: async ({ model, where, sortBy, limit, select, offset, join }) => { - const res = convertWhereClause(where || [], model, join, select); - if (join) { - const resArray = res; - if (!resArray.length) return []; - applySortToRecords(resArray, sortBy, model); - let paginatedRecords = resArray; - if (offset !== void 0) paginatedRecords = paginatedRecords.slice(offset); - if (limit !== void 0) paginatedRecords = paginatedRecords.slice(0, limit); - return paginatedRecords; - } - let table = applySortToRecords(res, sortBy, model); - if (offset !== void 0) table = table.slice(offset); - if (limit !== void 0) table = table.slice(0, limit); - return table || []; - }, - count: async ({ model, where }) => { - if (where) return convertWhereClause(where, model).length; - return db[model].length; - }, - update: async ({ model, where, update }) => { - const res = convertWhereClause(where, model); - res.forEach((record) => { - Object.assign(record, update); - }); - return res[0] || null; - }, - delete: async ({ model, where }) => { - const table = db[model]; - const res = convertWhereClause(where, model); - db[model] = table.filter((record) => !res.includes(record)); - }, - deleteMany: async ({ model, where }) => { - const table = db[model]; - const res = convertWhereClause(where, model); - let count = 0; - db[model] = table.filter((record) => { - if (res.includes(record)) { - count++; - return false; - } - return !res.includes(record); - }); - return count; - }, - updateMany({ model, where, update }) { - const res = convertWhereClause(where, model); - res.forEach((record) => { - Object.assign(record, update); - }); - return res[0] || null; - } - }; - } - }); - return (options) => { - lazyOptions = options; - return adapterCreator(options); - }; -}; -export { - memoryAdapter -}; diff --git a/.svelte-kit/output/server/chunks/index6.js b/.svelte-kit/output/server/chunks/index6.js deleted file mode 100644 index f55374c..0000000 --- a/.svelte-kit/output/server/chunks/index6.js +++ /dev/null @@ -1,307 +0,0 @@ -import { c as createKyselyAdapter } from "./auth.js"; -import { g } from "./auth.js"; -import { sql } from "kysely"; -import { createAdapterFactory } from "@better-auth/core/db/adapter"; -const kyselyAdapter = (db, config) => { - let lazyOptions = null; - const createCustomAdapter = (db$1) => { - return ({ getFieldName, schema, getDefaultFieldName, getDefaultModelName, getFieldAttributes, getModelName }) => { - const selectAllJoins = (join) => { - const allSelects = []; - const allSelectsStr = []; - if (join) for (const [joinModel, _] of Object.entries(join)) { - const fields = schema[getDefaultModelName(joinModel)]?.fields; - const [_joinModelSchema, joinModelName] = joinModel.includes(".") ? joinModel.split(".") : [void 0, joinModel]; - if (!fields) continue; - fields.id = { type: "string" }; - for (const [field, fieldAttr] of Object.entries(fields)) { - allSelects.push(sql`${sql.ref(`join_${joinModelName}`)}.${sql.ref(fieldAttr.fieldName || field)} as ${sql.ref(`_joined_${joinModelName}_${fieldAttr.fieldName || field}`)}`); - allSelectsStr.push({ - joinModel, - joinModelRef: joinModelName, - fieldName: fieldAttr.fieldName || field - }); - } - } - return { - allSelectsStr, - allSelects - }; - }; - const withReturning = async (values, builder, model, where) => { - let res; - if (config?.type === "mysql") { - await builder.execute(); - const field = values.id ? "id" : where.length > 0 && where[0]?.field ? where[0].field : "id"; - if (!values.id && where.length === 0) { - res = await db$1.selectFrom(model).selectAll().orderBy(getFieldName({ - model, - field - }), "desc").limit(1).executeTakeFirst(); - return res; - } - const value = values[field] || where[0]?.value; - res = await db$1.selectFrom(model).selectAll().orderBy(getFieldName({ - model, - field - }), "desc").where(getFieldName({ - model, - field - }), "=", value).limit(1).executeTakeFirst(); - return res; - } - if (config?.type === "mssql") { - res = await builder.outputAll("inserted").executeTakeFirst(); - return res; - } - res = await builder.returningAll().executeTakeFirst(); - return res; - }; - function convertWhereClause(model, w) { - if (!w) return { - and: null, - or: null - }; - const conditions = { - and: [], - or: [] - }; - w.forEach((condition) => { - const { field: _field, value: _value, operator = "=", connector = "AND" } = condition; - const value = _value; - const field = getFieldName({ - model, - field: _field - }); - const expr = (eb) => { - const f = `${model}.${field}`; - if (operator.toLowerCase() === "in") return eb(f, "in", Array.isArray(value) ? value : [value]); - if (operator.toLowerCase() === "not_in") return eb(f, "not in", Array.isArray(value) ? value : [value]); - if (operator === "contains") return eb(f, "like", `%${value}%`); - if (operator === "starts_with") return eb(f, "like", `${value}%`); - if (operator === "ends_with") return eb(f, "like", `%${value}`); - if (operator === "eq") return eb(f, "=", value); - if (operator === "ne") return eb(f, "<>", value); - if (operator === "gt") return eb(f, ">", value); - if (operator === "gte") return eb(f, ">=", value); - if (operator === "lt") return eb(f, "<", value); - if (operator === "lte") return eb(f, "<=", value); - return eb(f, operator, value); - }; - if (connector === "OR") conditions.or.push(expr); - else conditions.and.push(expr); - }); - return { - and: conditions.and.length ? conditions.and : null, - or: conditions.or.length ? conditions.or : null - }; - } - function processJoinedResults(rows, joinConfig, allSelectsStr) { - if (!joinConfig || !rows.length) return rows; - const groupedByMainId = /* @__PURE__ */ new Map(); - for (const currentRow of rows) { - const mainModelFields = {}; - const joinedModelFields = {}; - for (const [joinModel] of Object.entries(joinConfig)) joinedModelFields[getModelName(joinModel)] = {}; - for (const [key, value] of Object.entries(currentRow)) { - const keyStr = String(key); - let assigned = false; - for (const { joinModel, fieldName, joinModelRef } of allSelectsStr) if (keyStr === `_joined_${joinModelRef}_${fieldName}`) { - joinedModelFields[getModelName(joinModel)][getFieldName({ - model: joinModel, - field: fieldName - })] = value; - assigned = true; - break; - } - if (!assigned) mainModelFields[key] = value; - } - const mainId = mainModelFields.id; - if (!mainId) continue; - if (!groupedByMainId.has(mainId)) { - const entry$1 = { ...mainModelFields }; - for (const [joinModel, joinAttr] of Object.entries(joinConfig)) entry$1[getModelName(joinModel)] = joinAttr.relation === "one-to-one" ? null : []; - groupedByMainId.set(mainId, entry$1); - } - const entry = groupedByMainId.get(mainId); - for (const [joinModel, joinAttr] of Object.entries(joinConfig)) { - const isUnique = joinAttr.relation === "one-to-one"; - const limit = joinAttr.limit ?? 100; - const joinedObj = joinedModelFields[getModelName(joinModel)]; - const hasData = joinedObj && Object.keys(joinedObj).length > 0 && Object.values(joinedObj).some((value) => value !== null && value !== void 0); - if (isUnique) entry[getModelName(joinModel)] = hasData ? joinedObj : null; - else { - const joinModelName = getModelName(joinModel); - if (Array.isArray(entry[joinModelName]) && hasData) { - if (entry[joinModelName].length >= limit) continue; - const idFieldName = getFieldName({ - model: joinModel, - field: "id" - }); - const joinedId = joinedObj[idFieldName]; - if (joinedId) { - if (!entry[joinModelName].some((item) => item[idFieldName] === joinedId) && entry[joinModelName].length < limit) entry[joinModelName].push(joinedObj); - } else if (entry[joinModelName].length < limit) entry[joinModelName].push(joinedObj); - } - } - } - } - const result = Array.from(groupedByMainId.values()); - for (const entry of result) for (const [joinModel, joinAttr] of Object.entries(joinConfig)) if (joinAttr.relation !== "one-to-one") { - const joinModelName = getModelName(joinModel); - if (Array.isArray(entry[joinModelName])) { - const limit = joinAttr.limit ?? 100; - if (entry[joinModelName].length > limit) entry[joinModelName] = entry[joinModelName].slice(0, limit); - } - } - return result; - } - return { - async create({ data, model }) { - return await withReturning(data, db$1.insertInto(model).values(data), model, []); - }, - async findOne({ model, where, select, join }) { - const { and, or } = convertWhereClause(model, where); - let query = db$1.selectFrom((eb) => { - let b = eb.selectFrom(model); - if (and) b = b.where((eb$1) => eb$1.and(and.map((expr) => expr(eb$1)))); - if (or) b = b.where((eb$1) => eb$1.or(or.map((expr) => expr(eb$1)))); - if (select?.length && select.length > 0) b = b.select(select.map((field) => getFieldName({ - model, - field - }))); - else b = b.selectAll(); - return b.as("primary"); - }).selectAll("primary"); - if (join) for (const [joinModel, joinAttr] of Object.entries(join)) { - const [_joinModelSchema, joinModelName] = joinModel.includes(".") ? joinModel.split(".") : [void 0, joinModel]; - query = query.leftJoin(`${joinModel} as join_${joinModelName}`, (join$1) => join$1.onRef(`join_${joinModelName}.${joinAttr.on.to}`, "=", `primary.${joinAttr.on.from}`)); - } - const { allSelectsStr, allSelects } = selectAllJoins(join); - query = query.select(allSelects); - const res = await query.execute(); - if (!res || !Array.isArray(res) || res.length === 0) return null; - const row = res[0]; - if (join) return processJoinedResults(res, join, allSelectsStr)[0]; - return row; - }, - async findMany({ model, where, limit, select, offset, sortBy, join }) { - const { and, or } = convertWhereClause(model, where); - let query = db$1.selectFrom((eb) => { - let b = eb.selectFrom(model); - if (config?.type === "mssql") { - if (offset !== void 0) { - if (!sortBy) b = b.orderBy(getFieldName({ - model, - field: "id" - })); - b = b.offset(offset).fetch(limit || 100); - } else if (limit !== void 0) b = b.top(limit); - } else { - if (limit !== void 0) b = b.limit(limit); - if (offset !== void 0) b = b.offset(offset); - } - if (sortBy?.field) b = b.orderBy(`${getFieldName({ - model, - field: sortBy.field - })}`, sortBy.direction); - if (and) b = b.where((eb$1) => eb$1.and(and.map((expr) => expr(eb$1)))); - if (or) b = b.where((eb$1) => eb$1.or(or.map((expr) => expr(eb$1)))); - if (select?.length && select.length > 0) b = b.select(select.map((field) => getFieldName({ - model, - field - }))); - else b = b.selectAll(); - return b.as("primary"); - }).selectAll("primary"); - if (join) for (const [joinModel, joinAttr] of Object.entries(join)) { - const [_joinModelSchema, joinModelName] = joinModel.includes(".") ? joinModel.split(".") : [void 0, joinModel]; - query = query.leftJoin(`${joinModel} as join_${joinModelName}`, (join$1) => join$1.onRef(`join_${joinModelName}.${joinAttr.on.to}`, "=", `primary.${joinAttr.on.from}`)); - } - const { allSelectsStr, allSelects } = selectAllJoins(join); - query = query.select(allSelects); - if (sortBy?.field) query = query.orderBy(`${getFieldName({ - model, - field: sortBy.field - })}`, sortBy.direction); - const res = await query.execute(); - if (!res) return []; - if (join) return processJoinedResults(res, join, allSelectsStr); - return res; - }, - async update({ model, where, update: values }) { - const { and, or } = convertWhereClause(model, where); - let query = db$1.updateTable(model).set(values); - if (and) query = query.where((eb) => eb.and(and.map((expr) => expr(eb)))); - if (or) query = query.where((eb) => eb.or(or.map((expr) => expr(eb)))); - return await withReturning(values, query, model, where); - }, - async updateMany({ model, where, update: values }) { - const { and, or } = convertWhereClause(model, where); - let query = db$1.updateTable(model).set(values); - if (and) query = query.where((eb) => eb.and(and.map((expr) => expr(eb)))); - if (or) query = query.where((eb) => eb.or(or.map((expr) => expr(eb)))); - const res = (await query.executeTakeFirst()).numUpdatedRows; - return res > Number.MAX_SAFE_INTEGER ? Number.MAX_SAFE_INTEGER : Number(res); - }, - async count({ model, where }) { - const { and, or } = convertWhereClause(model, where); - let query = db$1.selectFrom(model).select(db$1.fn.count("id").as("count")); - if (and) query = query.where((eb) => eb.and(and.map((expr) => expr(eb)))); - if (or) query = query.where((eb) => eb.or(or.map((expr) => expr(eb)))); - const res = await query.execute(); - if (typeof res[0].count === "number") return res[0].count; - if (typeof res[0].count === "bigint") return Number(res[0].count); - return parseInt(res[0].count); - }, - async delete({ model, where }) { - const { and, or } = convertWhereClause(model, where); - let query = db$1.deleteFrom(model); - if (and) query = query.where((eb) => eb.and(and.map((expr) => expr(eb)))); - if (or) query = query.where((eb) => eb.or(or.map((expr) => expr(eb)))); - await query.execute(); - }, - async deleteMany({ model, where }) { - const { and, or } = convertWhereClause(model, where); - let query = db$1.deleteFrom(model); - if (and) query = query.where((eb) => eb.and(and.map((expr) => expr(eb)))); - if (or) query = query.where((eb) => eb.or(or.map((expr) => expr(eb)))); - const res = (await query.executeTakeFirst()).numDeletedRows; - return res > Number.MAX_SAFE_INTEGER ? Number.MAX_SAFE_INTEGER : Number(res); - }, - options: config - }; - }; - }; - let adapterOptions = null; - adapterOptions = { - config: { - adapterId: "kysely", - adapterName: "Kysely Adapter", - usePlural: config?.usePlural, - debugLogs: config?.debugLogs, - supportsBooleans: config?.type === "sqlite" || config?.type === "mssql" || config?.type === "mysql" || !config?.type ? false : true, - supportsDates: config?.type === "sqlite" || config?.type === "mssql" || !config?.type ? false : true, - supportsJSON: config?.type === "postgres" ? true : false, - supportsArrays: false, - supportsUUIDs: config?.type === "postgres" ? true : false, - transaction: config?.transaction ? (cb) => db.transaction().execute((trx) => { - return cb(createAdapterFactory({ - config: adapterOptions.config, - adapter: createCustomAdapter(trx) - })(lazyOptions)); - }) : false - }, - adapter: createCustomAdapter(db) - }; - const adapter = createAdapterFactory(adapterOptions); - return (options) => { - lazyOptions = options; - return adapter(options); - }; -}; -export { - createKyselyAdapter, - g as getKyselyDatabaseType, - kyselyAdapter -}; diff --git a/.svelte-kit/output/server/chunks/internal.js b/.svelte-kit/output/server/chunks/internal.js deleted file mode 100644 index 55b3eeb..0000000 --- a/.svelte-kit/output/server/chunks/internal.js +++ /dev/null @@ -1,127 +0,0 @@ -import { r as root } from "./root.js"; -import "./environment.js"; -import "./server.js"; -import "./shared-server.js"; -let read_implementation = null; -function set_read_implementation(fn) { - read_implementation = fn; -} -function set_manifest(_) { -} -const options = { - app_template_contains_nonce: false, - async: false, - csp: { "mode": "auto", "directives": { "upgrade-insecure-requests": false, "block-all-mixed-content": false }, "reportOnly": { "upgrade-insecure-requests": false, "block-all-mixed-content": false } }, - csrf_check_origin: true, - csrf_trusted_origins: [], - embedded: false, - env_public_prefix: "PUBLIC_", - env_private_prefix: "", - hash_routing: false, - hooks: null, - // added lazily, via `get_hooks` - preload_strategy: "modulepreload", - root, - service_worker: false, - service_worker_options: void 0, - templates: { - app: ({ head, body, assets, nonce, env }) => '\n\n \n \n \n \n \n \n Vash Esports\n ' + head + '\n \n \n
' + body + "
\n \n\n", - error: ({ status, message }) => '\n\n \n \n ' + message + ` - - - - -
- ` + status + '\n
\n

' + message + "

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

Welcome to Vash Esports

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

Sign in with osu!

Uses your osu! account. No extra registration needed.

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

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

Automated esports match management for osu!

${escape_html(data.stats.matches)}

Total Matches

${escape_html(data.stats.finished)}

Completed

${escape_html(data.stats.teams)}

Teams

${escape_html(data.stats.mappools)}

Mappools

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

Live Now

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

Ranked Queue

Find a match at your skill level

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

Recent Matches

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

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

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

No matches yet. Create one

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

Admin Panel

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

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

${escape_html(u.name)}

${escape_html(u.email)}

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

${escape_html(data.pool.name)}

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

Add Map

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

Beatmap #${escape_html(slot.beatmapId)}

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

No maps yet. Add your first map above.

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

Mappools

Create and manage your beatmap pools

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

${escape_html(pool.name)}

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

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

No mappools yet. Create one to get started.

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

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

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

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

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

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

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

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

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

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

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

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

🎲 Roll Phase

Highest roll picks first

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

${escape_html(p.team.name)}

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

${escape_html(p.rollValue)}

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

—

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

or type !roll in osu! chat

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

Waiting for all rolls...

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

🎯 Pick a Map

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

or type !pick NM1 in osu! chat

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

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

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

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

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

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

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

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

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

Games Played

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

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

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

Creating osu! lobby...

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

Lobby created. Waiting for players to join...

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

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

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

This match was cancelled.

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

Matches

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

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

Live Now

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

Past Matches

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

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

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

No matches yet. Create one to get started.

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

Settings

Your profile and account settings

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

${escape_html(data.profile.name)}

${escape_html(badge().label)}

${escape_html(data.profile.email)}

Connected Accounts

🎮

osu!

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

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

Ranked Stats

${escape_html(data.rating.elo)}

ELO Rating

${escape_html(data.rating.wins)}

Wins

${escape_html(data.rating.losses)}

Losses

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

Win Rate

Account

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

Teams

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

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

My Teams

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

Other Teams

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

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

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

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

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

${escape_html(page.status)}

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

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

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

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

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

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

Login

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


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

Admin Panel

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

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

{u.name}

+
+

{u.name}

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

{u.email}

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

Permission Levels

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

Leaderboard

+

Rankings and top performances

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

No ranked players yet. Play some matches!

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

No team results yet.

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

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

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

No scores recorded yet.

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

+ {s.matchName} +

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

How ELO Works

+

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

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

{data.pool.name}

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

{data.pool.name}

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

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

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

Add Map

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

Add Map

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

{addError}

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

{addError}

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

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

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

No matches yet. Create one to get started.

+

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

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

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

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