From e9f9821222242880372c7cefbb2fc0a2db6d0786 Mon Sep 17 00:00:00 2001 From: Dominic Ferrando Date: Thu, 18 Sep 2025 00:01:27 -0400 Subject: [PATCH] View update --- bun.lock | 268 +++++++++++- main.ts | 113 ----- package.json | 23 +- src/api.ts | 88 ++++ {data => src/data}/data.db | Bin {data => src/data}/seed.sql | 0 {data => src/data}/standards.json | 24 +- .../services/calculator/main.ts | 203 +++++---- .../services/calculator}/util.ts | 39 +- .../services/commerce}/printful.ts | 0 .../services/commerce}/webflow.ts | 4 +- .../test.ts => src/test/test-calculator.ts | 9 +- src/view/.svelte-kit/ambient.d.ts | 271 ++++++++++++ src/view/.svelte-kit/generated/client/app.js | 28 ++ .../.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/2.js | 1 + src/view/.svelte-kit/generated/root.js | 3 + src/view/.svelte-kit/generated/root.svelte | 66 +++ .../.svelte-kit/generated/server/internal.js | 52 +++ src/view/.svelte-kit/non-ambient.d.ts | 42 ++ src/view/.svelte-kit/tsconfig.json | 52 +++ .../.svelte-kit/types/route_meta_data.json | 9 + .../.svelte-kit/types/src/routes/$types.d.ts | 28 ++ .../types/src/routes/[...slugs]/$types.d.ts | 11 + .../types/src/routes/proxy+layout.server.ts | 12 + src/view/src/app.css | 27 ++ src/view/src/app.d.ts | 13 + src/view/src/app.html | 11 + src/view/src/lib/assets/favicon.svg | 1 + src/view/src/lib/index.ts | 6 + src/view/src/routes/+layout.server.ts | 11 + src/view/src/routes/+layout.svelte | 12 + src/view/src/routes/+page.svelte | 407 ++++++++++++++++++ src/view/src/routes/[...slugs]/+server.ts | 4 + src/view/static/robots.txt | 3 + src/view/svelte.config.js | 18 + src/view/tsconfig.json | 20 + src/view/vite.config.ts | 6 + 40 files changed, 1646 insertions(+), 242 deletions(-) delete mode 100644 main.ts create mode 100644 src/api.ts rename {data => src/data}/data.db (100%) rename {data => src/data}/seed.sql (100%) rename {data => src/data}/standards.json (99%) rename calculator/calc.ts => src/services/calculator/main.ts (69%) rename {calculator => src/services/calculator}/util.ts (64%) rename {commerce => src/services/commerce}/printful.ts (100%) rename {commerce => src/services/commerce}/webflow.ts (99%) rename calculator/test.ts => src/test/test-calculator.ts (87%) create mode 100644 src/view/.svelte-kit/ambient.d.ts create mode 100644 src/view/.svelte-kit/generated/client/app.js create mode 100644 src/view/.svelte-kit/generated/client/matchers.js create mode 100644 src/view/.svelte-kit/generated/client/nodes/0.js create mode 100644 src/view/.svelte-kit/generated/client/nodes/1.js create mode 100644 src/view/.svelte-kit/generated/client/nodes/2.js create mode 100644 src/view/.svelte-kit/generated/root.js create mode 100644 src/view/.svelte-kit/generated/root.svelte create mode 100644 src/view/.svelte-kit/generated/server/internal.js create mode 100644 src/view/.svelte-kit/non-ambient.d.ts create mode 100644 src/view/.svelte-kit/tsconfig.json create mode 100644 src/view/.svelte-kit/types/route_meta_data.json create mode 100644 src/view/.svelte-kit/types/src/routes/$types.d.ts create mode 100644 src/view/.svelte-kit/types/src/routes/[...slugs]/$types.d.ts create mode 100644 src/view/.svelte-kit/types/src/routes/proxy+layout.server.ts create mode 100644 src/view/src/app.css create mode 100644 src/view/src/app.d.ts create mode 100644 src/view/src/app.html create mode 100644 src/view/src/lib/assets/favicon.svg create mode 100644 src/view/src/lib/index.ts create mode 100644 src/view/src/routes/+layout.server.ts create mode 100644 src/view/src/routes/+layout.svelte create mode 100644 src/view/src/routes/+page.svelte create mode 100644 src/view/src/routes/[...slugs]/+server.ts create mode 100644 src/view/static/robots.txt create mode 100644 src/view/svelte.config.js create mode 100644 src/view/tsconfig.json create mode 100644 src/view/vite.config.ts diff --git a/bun.lock b/bun.lock index af2db4f..b2d81c4 100644 --- a/bun.lock +++ b/bun.lock @@ -2,18 +2,276 @@ "lockfileVersion": 1, "workspaces": { "": { + "dependencies": { + "@elysiajs/cors": "^1.4.0", + "@elysiajs/eden": "^1.4.1", + "elysia": "^1.4.5", + }, "devDependencies": { - "@types/bun": "^1.2.11", + "@sveltejs/kit": "^2.22.0", + "@sveltejs/vite-plugin-svelte": "^6.0.0", + "@types/bun": "^1.2.22", + "svelte": "^5.0.0", + "svelte-adapter-bun": "^0.5.2", + "svelte-check": "^4.0.0", + "typescript": "^5.0.0", + "vite": "^7.0.4", }, }, }, "packages": { - "@types/bun": ["@types/bun@1.2.11", "", { "dependencies": { "bun-types": "1.2.11" } }, "sha512-ZLbbI91EmmGwlWTRWuV6J19IUiUC5YQ3TCEuSHI3usIP75kuoA8/0PVF+LTrbEnVc8JIhpElWOxv1ocI1fJBbw=="], + "@borewit/text-codec": ["@borewit/text-codec@0.1.1", "", {}, "sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA=="], - "@types/node": ["@types/node@22.15.3", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw=="], + "@elysiajs/cors": ["@elysiajs/cors@1.4.0", "", { "peerDependencies": { "elysia": ">= 1.4.0" } }, "sha512-pb0SCzBfFbFSYA/U40HHO7R+YrcXBJXOWgL20eSViK33ol1e20ru2/KUaZYo5IMUn63yaTJI/bQERuQ+77ND8g=="], - "bun-types": ["bun-types@1.2.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-dbkp5Lo8HDrXkLrONm6bk+yiiYQSntvFUzQp0v3pzTAsXk6FtgVMjdQ+lzFNVAmQFUkPQZ3WMZqH5tTo+Dp/IA=="], + "@elysiajs/eden": ["@elysiajs/eden@1.4.1", "", { "peerDependencies": { "elysia": ">= 1.4.0-exp.0" } }, "sha512-9VXMau/cvafuBa1r19ucKi+l9eesCmeuvD6uYSeq5MFO/URc233JaxZmUlWQ8gztu+pp6L7auTZdkzOQz26O+A=="], - "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.10", "", { "os": "aix", "cpu": "ppc64" }, "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.25.10", "", { "os": "android", "cpu": "arm" }, "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.10", "", { "os": "android", "cpu": "arm64" }, "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.25.10", "", { "os": "android", "cpu": "x64" }, "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.10", "", { "os": "darwin", "cpu": "x64" }, "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.10", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.10", "", { "os": "freebsd", "cpu": "x64" }, "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.10", "", { "os": "linux", "cpu": "arm" }, "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.10", "", { "os": "linux", "cpu": "ia32" }, "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.10", "", { "os": "linux", "cpu": "none" }, "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.10", "", { "os": "linux", "cpu": "none" }, "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.10", "", { "os": "linux", "cpu": "ppc64" }, "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.10", "", { "os": "linux", "cpu": "none" }, "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.10", "", { "os": "linux", "cpu": "s390x" }, "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.10", "", { "os": "linux", "cpu": "x64" }, "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA=="], + + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.10", "", { "os": "none", "cpu": "arm64" }, "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.10", "", { "os": "none", "cpu": "x64" }, "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig=="], + + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.10", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.10", "", { "os": "openbsd", "cpu": "x64" }, "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw=="], + + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.10", "", { "os": "none", "cpu": "arm64" }, "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.10", "", { "os": "sunos", "cpu": "x64" }, "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.10", "", { "os": "win32", "cpu": "arm64" }, "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.10", "", { "os": "win32", "cpu": "ia32" }, "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.10", "", { "os": "win32", "cpu": "x64" }, "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw=="], + + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], + + "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], + + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], + + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + + "@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="], + + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.50.2", "", { "os": "android", "cpu": "arm" }, "sha512-uLN8NAiFVIRKX9ZQha8wy6UUs06UNSZ32xj6giK/rmMXAgKahwExvK6SsmgU5/brh4w/nSgj8e0k3c1HBQpa0A=="], + + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.50.2", "", { "os": "android", "cpu": "arm64" }, "sha512-oEouqQk2/zxxj22PNcGSskya+3kV0ZKH+nQxuCCOGJ4oTXBdNTbv+f/E3c74cNLeMO1S5wVWacSws10TTSB77g=="], + + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.50.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-OZuTVTpj3CDSIxmPgGH8en/XtirV5nfljHZ3wrNwvgkT5DQLhIKAeuFSiwtbMto6oVexV0k1F1zqURPKf5rI1Q=="], + + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.50.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-Wa/Wn8RFkIkr1vy1k1PB//VYhLnlnn5eaJkfTQKivirOvzu5uVd2It01ukeQstMursuz7S1bU+8WW+1UPXpa8A=="], + + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.50.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-QkzxvH3kYN9J1w7D1A+yIMdI1pPekD+pWx7G5rXgnIlQ1TVYVC6hLl7SOV9pi5q9uIDF9AuIGkuzcbF7+fAhow=="], + + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.50.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-dkYXB0c2XAS3a3jmyDkX4Jk0m7gWLFzq1C3qUnJJ38AyxIF5G/dyS4N9B30nvFseCfgtCEdbYFhk0ChoCGxPog=="], + + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.50.2", "", { "os": "linux", "cpu": "arm" }, "sha512-9VlPY/BN3AgbukfVHAB8zNFWB/lKEuvzRo1NKev0Po8sYFKx0i+AQlCYftgEjcL43F2h9Ui1ZSdVBc4En/sP2w=="], + + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.50.2", "", { "os": "linux", "cpu": "arm" }, "sha512-+GdKWOvsifaYNlIVf07QYan1J5F141+vGm5/Y8b9uCZnG/nxoGqgCmR24mv0koIWWuqvFYnbURRqw1lv7IBINw=="], + + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.50.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-df0Eou14ojtUdLQdPFnymEQteENwSJAdLf5KCDrmZNsy1c3YaCNaJvYsEUHnrg+/DLBH612/R0xd3dD03uz2dg=="], + + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.50.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-iPeouV0UIDtz8j1YFR4OJ/zf7evjauqv7jQ/EFs0ClIyL+by++hiaDAfFipjOgyz6y6xbDvJuiU4HwpVMpRFDQ=="], + + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.50.2", "", { "os": "linux", "cpu": "none" }, "sha512-OL6KaNvBopLlj5fTa5D5bau4W82f+1TyTZRr2BdnfsrnQnmdxh4okMxR2DcDkJuh4KeoQZVuvHvzuD/lyLn2Kw=="], + + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.50.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-I21VJl1w6z/K5OTRl6aS9DDsqezEZ/yKpbqlvfHbW0CEF5IL8ATBMuUx6/mp683rKTK8thjs/0BaNrZLXetLag=="], + + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.50.2", "", { "os": "linux", "cpu": "none" }, "sha512-Hq6aQJT/qFFHrYMjS20nV+9SKrXL2lvFBENZoKfoTH2kKDOJqff5OSJr4x72ZaG/uUn+XmBnGhfr4lwMRrmqCQ=="], + + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.50.2", "", { "os": "linux", "cpu": "none" }, "sha512-82rBSEXRv5qtKyr0xZ/YMF531oj2AIpLZkeNYxmKNN6I2sVE9PGegN99tYDLK2fYHJITL1P2Lgb4ZXnv0PjQvw=="], + + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.50.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-4Q3S3Hy7pC6uaRo9gtXUTJ+EKo9AKs3BXKc2jYypEcMQ49gDPFU2P1ariX9SEtBzE5egIX6fSUmbmGazwBVF9w=="], + + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.50.2", "", { "os": "linux", "cpu": "x64" }, "sha512-9Jie/At6qk70dNIcopcL4p+1UirusEtznpNtcq/u/C5cC4HBX7qSGsYIcG6bdxj15EYWhHiu02YvmdPzylIZlA=="], + + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.50.2", "", { "os": "linux", "cpu": "x64" }, "sha512-HPNJwxPL3EmhzeAnsWQCM3DcoqOz3/IC6de9rWfGR8ZCuEHETi9km66bH/wG3YH0V3nyzyFEGUZeL5PKyy4xvw=="], + + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.50.2", "", { "os": "none", "cpu": "arm64" }, "sha512-nMKvq6FRHSzYfKLHZ+cChowlEkR2lj/V0jYj9JnGUVPL2/mIeFGmVM2mLaFeNa5Jev7W7TovXqXIG2d39y1KYA=="], + + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.50.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-eFUvvnTYEKeTyHEijQKz81bLrUQOXKZqECeiWH6tb8eXXbZk+CXSG2aFrig2BQ/pjiVRj36zysjgILkqarS2YA=="], + + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.50.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-cBaWmXqyfRhH8zmUxK3d3sAhEWLrtMjWBRwdMMHJIXSjvjLKvv49adxiEz+FJ8AP90apSDDBx2Tyd/WylV6ikA=="], + + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.50.2", "", { "os": "win32", "cpu": "x64" }, "sha512-APwKy6YUhvZaEoHyM+9xqmTpviEI+9eL7LoCH+aLcvWYHJ663qG5zx7WzWZY+a9qkg5JtzcMyJ9z0WtQBMDmgA=="], + + "@sinclair/typebox": ["@sinclair/typebox@0.34.41", "", {}, "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g=="], + + "@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="], + + "@sveltejs/acorn-typescript": ["@sveltejs/acorn-typescript@1.0.5", "", { "peerDependencies": { "acorn": "^8.9.0" } }, "sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ=="], + + "@sveltejs/kit": ["@sveltejs/kit@2.42.1", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/cookie": "^0.6.0", "acorn": "^8.14.1", "cookie": "^0.6.0", "devalue": "^5.3.2", "esm-env": "^1.2.2", "kleur": "^4.1.5", "magic-string": "^0.30.5", "mrmime": "^2.0.0", "sade": "^1.8.1", "set-cookie-parser": "^2.6.0", "sirv": "^3.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0", "svelte": "^4.0.0 || ^5.0.0-next.0", "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0" }, "optionalPeers": ["@opentelemetry/api"], "bin": { "svelte-kit": "svelte-kit.js" } }, "sha512-SoWdb/OxEKHMlXZ78eNZa4pR1YdOGnUfcFj5NylJv+ZaTrnHK5xapw+7RJP2MiS1D4T+sEH25/tmMtmEl8p6VA=="], + + "@sveltejs/vite-plugin-svelte": ["@sveltejs/vite-plugin-svelte@6.2.0", "", { "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^5.0.0", "debug": "^4.4.1", "deepmerge": "^4.3.1", "magic-string": "^0.30.17", "vitefu": "^1.1.1" }, "peerDependencies": { "svelte": "^5.0.0", "vite": "^6.3.0 || ^7.0.0" } }, "sha512-nJsV36+o7rZUDlrnSduMNl11+RoDE1cKqOI0yUEBCcqFoAZOk47TwD3dPKS2WmRutke9StXnzsPBslY7prDM9w=="], + + "@sveltejs/vite-plugin-svelte-inspector": ["@sveltejs/vite-plugin-svelte-inspector@5.0.1", "", { "dependencies": { "debug": "^4.4.1" }, "peerDependencies": { "@sveltejs/vite-plugin-svelte": "^6.0.0-next.0", "svelte": "^5.0.0", "vite": "^6.3.0 || ^7.0.0" } }, "sha512-ubWshlMk4bc8mkwWbg6vNvCeT7lGQojE3ijDh3QTR6Zr/R+GXxsGbyH4PExEPpiFmqPhYiVSVmHBjUcVc1JIrA=="], + + "@tokenizer/inflate": ["@tokenizer/inflate@0.2.7", "", { "dependencies": { "debug": "^4.4.0", "fflate": "^0.8.2", "token-types": "^6.0.0" } }, "sha512-MADQgmZT1eKjp06jpI2yozxaU9uVs4GzzgSL+uEq7bVcJ9V1ZXQkeGNql1fsSI0gMy1vhvNTNbUqrx+pZfJVmg=="], + + "@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="], + + "@types/bun": ["@types/bun@1.2.22", "", { "dependencies": { "bun-types": "1.2.22" } }, "sha512-5A/KrKos2ZcN0c6ljRSOa1fYIyCKhZfIVYeuyb4snnvomnpFqC0tTsEkdqNxbAgExV384OETQ//WAjl3XbYqQA=="], + + "@types/cookie": ["@types/cookie@0.6.0", "", {}, "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="], + + "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], + + "@types/node": ["@types/node@24.5.1", "", { "dependencies": { "undici-types": "~7.12.0" } }, "sha512-/SQdmUP2xa+1rdx7VwB9yPq8PaKej8TD5cQ+XfKDPWWC+VDJU4rvVVagXqKUzhKjtFoNA8rXDJAkCxQPAe00+Q=="], + + "@types/react": ["@types/react@19.1.13", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ=="], + + "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], + + "aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="], + + "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], + + "bun-types": ["bun-types@1.2.22", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-hwaAu8tct/Zn6Zft4U9BsZcXkYomzpHJX28ofvx7k0Zz2HNz54n1n+tDgxoWFGB4PcFvJXJQloPhaV2eP3Q6EA=="], + + "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], + + "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], + + "cookie": ["cookie@0.6.0", "", {}, "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw=="], + + "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], + + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="], + + "devalue": ["devalue@5.3.2", "", {}, "sha512-UDsjUbpQn9kvm68slnrs+mfxwFkIflOhkanmyabZ8zOYk8SMEIbJ3TK+88g70hSIeytu4y18f0z/hYHMTrXIWw=="], + + "elysia": ["elysia@1.4.5", "", { "dependencies": { "cookie": "^1.0.2", "elysia": "1.4.3-beta.0", "exact-mirror": "0.2.2", "fast-decode-uri-component": "^1.0.1" }, "optionalDependencies": { "@sinclair/typebox": ">= 0.34.0 < 1", "openapi-types": ">= 12.0.0" }, "peerDependencies": { "file-type": ">= 20.0.0", "typescript": ">= 5.0.0" } }, "sha512-slSMNyAuh6lFEjEwSkSkpzbUOLCtx6hOw4AYhpGOHqczu27eqxHbNtRtIPQuXDq6sqJ1ezXgw3gUjoasZozWRg=="], + + "esbuild": ["esbuild@0.25.10", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.10", "@esbuild/android-arm": "0.25.10", "@esbuild/android-arm64": "0.25.10", "@esbuild/android-x64": "0.25.10", "@esbuild/darwin-arm64": "0.25.10", "@esbuild/darwin-x64": "0.25.10", "@esbuild/freebsd-arm64": "0.25.10", "@esbuild/freebsd-x64": "0.25.10", "@esbuild/linux-arm": "0.25.10", "@esbuild/linux-arm64": "0.25.10", "@esbuild/linux-ia32": "0.25.10", "@esbuild/linux-loong64": "0.25.10", "@esbuild/linux-mips64el": "0.25.10", "@esbuild/linux-ppc64": "0.25.10", "@esbuild/linux-riscv64": "0.25.10", "@esbuild/linux-s390x": "0.25.10", "@esbuild/linux-x64": "0.25.10", "@esbuild/netbsd-arm64": "0.25.10", "@esbuild/netbsd-x64": "0.25.10", "@esbuild/openbsd-arm64": "0.25.10", "@esbuild/openbsd-x64": "0.25.10", "@esbuild/openharmony-arm64": "0.25.10", "@esbuild/sunos-x64": "0.25.10", "@esbuild/win32-arm64": "0.25.10", "@esbuild/win32-ia32": "0.25.10", "@esbuild/win32-x64": "0.25.10" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ=="], + + "esm-env": ["esm-env@1.2.2", "", {}, "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA=="], + + "esrap": ["esrap@2.1.0", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" } }, "sha512-yzmPNpl7TBbMRC5Lj2JlJZNPml0tzqoqP5B1JXycNUwtqma9AKCO0M2wHrdgsHcy1WRW7S9rJknAMtByg3usgA=="], + + "exact-mirror": ["exact-mirror@0.2.2", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.15" }, "optionalPeers": ["@sinclair/typebox"] }, "sha512-CrGe+4QzHZlnrXZVlo/WbUZ4qQZq8C0uATQVGVgXIrNXgHDBBNFD1VRfssRA2C9t3RYvh3MadZSdg2Wy7HBoQA=="], + + "fast-decode-uri-component": ["fast-decode-uri-component@1.0.1", "", {}, "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="], + + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + + "fflate": ["fflate@0.8.2", "", {}, "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="], + + "file-type": ["file-type@21.0.0", "", { "dependencies": { "@tokenizer/inflate": "^0.2.7", "strtok3": "^10.2.2", "token-types": "^6.0.0", "uint8array-extras": "^1.4.0" } }, "sha512-ek5xNX2YBYlXhiUXui3D/BXa3LdqPmoLJ7rqEx2bKJ7EAUEfmXgW0Das7Dc6Nr9MvqaOnIqiPV0mZk/r/UpNAg=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "globalyzer": ["globalyzer@0.1.0", "", {}, "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q=="], + + "globrex": ["globrex@0.1.2", "", {}, "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg=="], + + "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + + "is-reference": ["is-reference@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.6" } }, "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw=="], + + "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], + + "locate-character": ["locate-character@3.0.0", "", {}, "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="], + + "magic-string": ["magic-string@0.30.19", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw=="], + + "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="], + + "mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + + "openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + + "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], + + "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], + + "rollup": ["rollup@4.50.2", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.50.2", "@rollup/rollup-android-arm64": "4.50.2", "@rollup/rollup-darwin-arm64": "4.50.2", "@rollup/rollup-darwin-x64": "4.50.2", "@rollup/rollup-freebsd-arm64": "4.50.2", "@rollup/rollup-freebsd-x64": "4.50.2", "@rollup/rollup-linux-arm-gnueabihf": "4.50.2", "@rollup/rollup-linux-arm-musleabihf": "4.50.2", "@rollup/rollup-linux-arm64-gnu": "4.50.2", "@rollup/rollup-linux-arm64-musl": "4.50.2", "@rollup/rollup-linux-loong64-gnu": "4.50.2", "@rollup/rollup-linux-ppc64-gnu": "4.50.2", "@rollup/rollup-linux-riscv64-gnu": "4.50.2", "@rollup/rollup-linux-riscv64-musl": "4.50.2", "@rollup/rollup-linux-s390x-gnu": "4.50.2", "@rollup/rollup-linux-x64-gnu": "4.50.2", "@rollup/rollup-linux-x64-musl": "4.50.2", "@rollup/rollup-openharmony-arm64": "4.50.2", "@rollup/rollup-win32-arm64-msvc": "4.50.2", "@rollup/rollup-win32-ia32-msvc": "4.50.2", "@rollup/rollup-win32-x64-msvc": "4.50.2", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-BgLRGy7tNS9H66aIMASq1qSYbAAJV6Z6WR4QYTvj5FgF15rZ/ympT1uixHXwzbZUBDbkvqUI1KR0fH1FhMaQ9w=="], + + "sade": ["sade@1.8.1", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="], + + "set-cookie-parser": ["set-cookie-parser@2.7.1", "", {}, "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ=="], + + "sirv": ["sirv@3.0.2", "", { "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", "totalist": "^3.0.0" } }, "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g=="], + + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + + "strtok3": ["strtok3@10.3.4", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg=="], + + "svelte": ["svelte@5.38.10", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", "acorn": "^8.12.1", "aria-query": "^5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "esm-env": "^1.2.1", "esrap": "^2.1.0", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-UY+OhrWK7WI22bCZ00P/M3HtyWgwJPi9IxSRkoAE2MeAy6kl7ZlZWJZ8RaB+X4KD/G+wjis+cGVnVYaoqbzBqg=="], + + "svelte-adapter-bun": ["svelte-adapter-bun@0.5.2", "", { "dependencies": { "tiny-glob": "^0.2.9" } }, "sha512-xEtFgaal6UgrCwwkSIcapO9kopoFNUYCYqyKCikdqxX9bz2TDYnrWQZ7qBnkunMxi1HOIERUCvTcebYGiarZLA=="], + + "svelte-check": ["svelte-check@4.3.1", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "chokidar": "^4.0.1", "fdir": "^6.2.0", "picocolors": "^1.0.0", "sade": "^1.7.4" }, "peerDependencies": { "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": ">=5.0.0" }, "bin": { "svelte-check": "bin/svelte-check" } }, "sha512-lkh8gff5gpHLjxIV+IaApMxQhTGnir2pNUAqcNgeKkvK5bT/30Ey/nzBxNLDlkztCH4dP7PixkMt9SWEKFPBWg=="], + + "tiny-glob": ["tiny-glob@0.2.9", "", { "dependencies": { "globalyzer": "0.1.0", "globrex": "^0.1.2" } }, "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg=="], + + "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], + + "token-types": ["token-types@6.1.1", "", { "dependencies": { "@borewit/text-codec": "^0.1.0", "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-kh9LVIWH5CnL63Ipf0jhlBIy0UsrMj/NJDfpsy1SqOXlLKEVyXXYrnFxFT1yOOYVGBSApeVnjPw/sBz5BfEjAQ=="], + + "totalist": ["totalist@3.0.1", "", {}, "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ=="], + + "typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="], + + "uint8array-extras": ["uint8array-extras@1.5.0", "", {}, "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A=="], + + "undici-types": ["undici-types@7.12.0", "", {}, "sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ=="], + + "vite": ["vite@7.1.5", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ=="], + + "vitefu": ["vitefu@1.1.1", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" }, "optionalPeers": ["vite"] }, "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ=="], + + "zimmerframe": ["zimmerframe@1.1.4", "", {}, "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ=="], + + "elysia/cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="], + + "elysia/elysia": ["elysia@1.4.3-beta.0", "", { "dependencies": { "cookie": "^1.0.2", "exact-mirror": "0.2.2", "fast-decode-uri-component": "^1.0.1" }, "optionalDependencies": { "@sinclair/typebox": ">= 0.34.0 < 1", "openapi-types": ">= 12.0.0" }, "peerDependencies": { "file-type": ">= 20.0.0", "typescript": ">= 5.0.0" } }, "sha512-UzanGZSqoKKcKgg+I4YB+ZOGeJNA7mlA8JPj7klYi0LDVcj/vtXKGRmsp4jEzZO+LjSpFuYTZcwHi4rCnvJj1w=="], } } diff --git a/main.ts b/main.ts deleted file mode 100644 index 861b794..0000000 --- a/main.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { ActivityStandards, LevelCalculator, Standards } from "./calculator/calc.ts"; -import { ActivityPerformance, Player } from "./calculator/util.ts"; -import { Printful } from "./commerce/printful.ts" -import { Webflow } from "./commerce/webflow.ts"; -import rawStandards from "./data/standards.json" assert { type: "json" } - -interface CalcRequest { - player: Player, - activityPerformances: ActivityPerformance[] -} - -export class ClientResponse extends Response { - constructor(body?: BodyInit | null, init: ResponseInit = {}) { - const headers = new Headers(init.headers); - headers.set("Access-Control-Allow-Origin", "*"); - headers.set("Access-Control-Allow-Methods", "POST, OPTIONS"); - headers.set("Access-Control-Allow-Headers", "Content-Type"); - super(body, { ...init, headers }); - } - - static json(data: unknown, init: ResponseInit = {}) { - const body = JSON.stringify(data); - const headers = new Headers(init.headers); - headers.set("Content-Type", "application/json"); - return new ClientResponse(body, { ...init, headers }); - } -} - -const MAIN_STANDARDS = new Standards(rawStandards as ActivityStandards); - -const server = Bun.serve({ - idleTimeout: 180, - routes: { - "/calc": { - OPTIONS() { - return new ClientResponse(undefined, { status: 204 }); - }, - async POST(req) { - const calcReq: CalcRequest = await req.json(); - const { player, activityPerformances } = calcReq; - - const levelCalculator = new LevelCalculator(MAIN_STANDARDS); - - return ClientResponse.json({ - levels: levelCalculator.calculate(player, activityPerformances) - }) - } - }, - "/products/sync": { - OPTIONS() { - return new ClientResponse(undefined, { status: 204 }); - }, - async POST(req) { - const printfulProducts = await Printful.Products.getAll(); - - // handle update/create - for (const printfulProduct of printfulProducts) { - const webflowProductExists = await Webflow.Products.exists(printfulProduct.sync_product.external_id); - if (webflowProductExists) { - await Webflow.Products.updateUsingPrintful(printfulProduct); - } - else { - await Webflow.Products.createUsingPrintful(printfulProduct); - } - console.log("DONE"); - } - - // handle delete (TODO) - - return ClientResponse.json({}); - } - }, - "/webhook/printful": { - OPTIONS() { - return new ClientResponse(undefined, { status: 204 }); - }, - async POST(req) { - const payload: Printful.Webhook.EventPayload = await req.json() - try { - switch (payload.type) { - // ADD/UPDATE - case Printful.Webhook.Event.ProductUpdated: { - const printfulProduct = await Printful.Products.get(payload.data.sync_product.id); - const webflowProductExists = await Webflow.Products.exists(printfulProduct.sync_product.external_id); - if (webflowProductExists) { - await Webflow.Products.updateUsingPrintful(printfulProduct); - } - else { - await Webflow.Products.createUsingPrintful(printfulProduct); - } - break; - } - // DELETE - case Printful.Webhook.Event.ProductDeleted: { - const webflowProductId = payload.data.sync_product.external_id; - await Webflow.Products.remove(webflowProductId); - break; - } - } - } - catch (error) { - console.error(error); - ClientResponse.error(); - } - - return ClientResponse.json(""); - } - } - }, - development: true -}) - -console.log(`Listening on ${server.url}`); diff --git a/package.json b/package.json index 4ed378a..6b4363c 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,28 @@ { - "dependencies": {}, + "type": "module", "devDependencies": { - "@types/bun": "^1.2.11" + "@sveltejs/kit": "^2.22.0", + "@sveltejs/vite-plugin-svelte": "^6.0.0", + "@types/bun": "^1.2.22", + "svelte": "^5.0.0", + "svelte-adapter-bun": "^0.5.2", + "svelte-check": "^4.0.0", + "typescript": "^5.0.0", + "vite": "^7.0.4" }, "scripts": { "db:seed:dev": "sqlite3 ./data/data.db < ./data/seed.sql", "db:seed:prod": "sqlite3 /data/data.db < ./data/seed.sql", - "start": "bun run main.ts" + "dev": "cd ./src/view && vite dev", + "build": "cd ./src/view && vite build", + "preview": "cd ./src/view && vite preview", + "prepare": "cd ./src/view && svelte-kit sync || echo ''", + "check": "cd ./src/view && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "cd ./src/view && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch" + }, + "dependencies": { + "@elysiajs/cors": "^1.4.0", + "@elysiajs/eden": "^1.4.1", + "elysia": "^1.4.5" } } diff --git a/src/api.ts b/src/api.ts new file mode 100644 index 0000000..6d1227d --- /dev/null +++ b/src/api.ts @@ -0,0 +1,88 @@ +import { Elysia } from "elysia"; +import { cors } from "@elysiajs/cors"; +import { ActivityStandards, LevelCalculator, Standards } from "./services/calculator/main"; +import { ActivityPerformance, Player } from "./services/calculator/util"; +import { Printful } from "./services/commerce/printful"; +import { Webflow } from "./services/commerce/webflow"; +import rawStandards from "./data/standards.json" assert { type: "json" } +import { fileURLToPath } from 'url'; +import { dirname, join } from 'path'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +export const app = new Elysia({ prefix: "/api" }) + .use(cors()) + + .get("/", () => "Hello world") + + // CALCULATOR + + .post("/calculate", async ({ body }) => { + const MAIN_STANDARDS = new Standards(rawStandards as ActivityStandards); + interface CalcRequest { + player: Player; + activityPerformances: ActivityPerformance[]; + } + const { player, activityPerformances } = body as CalcRequest; + const levelCalculator = new LevelCalculator(MAIN_STANDARDS); + return { levels: levelCalculator.calculate(player, activityPerformances) }; + }) + + // COMMERCE + + .post("/products/sync", async () => { + const printfulProducts = await Printful.Products.getAll(); + for (const p of printfulProducts) { + const exists = await Webflow.Products.exists(p.sync_product.external_id); + if (exists) await Webflow.Products.updateUsingPrintful(p); + else await Webflow.Products.createUsingPrintful(p); + } + return {}; + }) + + + // DATA + + .get("/data/standards", async () => { + try { + return Bun.file(join(__dirname, "data/standards.json")).json(); + } catch (error) { + console.error(error); + return new Response("Failed to load standards", { status: 500 }); + } + }) + + // WEBHOOKS + + .post("/webhook/printful", async ({ body, set }) => { + const payload = body as Printful.Webhook.EventPayload; + try { + switch (payload.type) { + case Printful.Webhook.Event.ProductUpdated: { + const prod = await Printful.Products.get(payload.data.sync_product.id); + const exists = await Webflow.Products.exists(prod.sync_product.external_id); + if (exists) await Webflow.Products.updateUsingPrintful(prod); + else await Webflow.Products.createUsingPrintful(prod); + break; + } + case Printful.Webhook.Event.ProductDeleted: { + await Webflow.Products.remove(payload.data.sync_product.external_id); + break; + } + } + } catch (error) { + console.error(error); + set.status = 500; + return { error: "internal_error" }; + } + return ""; + }); + +if (import.meta.main) { + app.listen(3000); + console.log( + `Listening at ${app.server?.hostname}:${app.server?.port}`, + ); +} + +export type App = typeof app; diff --git a/data/data.db b/src/data/data.db similarity index 100% rename from data/data.db rename to src/data/data.db diff --git a/data/seed.sql b/src/data/seed.sql similarity index 100% rename from data/seed.sql rename to src/data/seed.sql diff --git a/data/standards.json b/src/data/standards.json similarity index 99% rename from data/standards.json rename to src/data/standards.json index e0f380c..af8a1f2 100644 --- a/data/standards.json +++ b/src/data/standards.json @@ -2,7 +2,9 @@ "BackSquat": { "metadata": { "attribute": "Strength", - "generators": [] + "generators": [], + "unit": "kg", + "name": "Squat" }, "standards": [ { @@ -1578,7 +1580,9 @@ "Deadlift": { "metadata": { "attribute": "Strength", - "generators": [] + "generators": [], + "unit": "kg", + "name": "Deadlift" }, "standards": [ { @@ -3154,7 +3158,9 @@ "BenchPress": { "metadata": { "attribute": "Strength", - "generators": [] + "generators": [], + "unit": "kg", + "name": "Bench Press" }, "standards": [ { @@ -4737,7 +4743,9 @@ "step": 12, "ratio": "inverse" } - ] + ], + "unit": "ms", + "name": "Mile Run" }, "standards": [ { @@ -5221,7 +5229,9 @@ "BroadJump": { "metadata": { "attribute": "Power", - "generators": [] + "generators": [], + "unit": "cm", + "name": "Broad Jump" }, "standards": [ { @@ -5257,7 +5267,9 @@ "ConeDrill": { "metadata": { "attribute": "Agility", - "generators": [] + "generators": [], + "unit": "ms", + "name": "3 Cone Drill" }, "standards": [ { diff --git a/calculator/calc.ts b/src/services/calculator/main.ts similarity index 69% rename from calculator/calc.ts rename to src/services/calculator/main.ts index 01ff38f..18a6116 100644 --- a/calculator/calc.ts +++ b/src/services/calculator/main.ts @@ -1,4 +1,4 @@ -import { Activity, Attribute, Player, Gender, ActivityPerformance, lbToKg } from "./util"; +import { Activity, Attribute, Player, Gender, ActivityPerformance, lbToKg, StandardUnit } from "./util"; // SOURCES // Squat, Bench, Dead Lift: @@ -45,7 +45,9 @@ type Generator = { export type ActivityStandards = Record; @@ -112,7 +114,7 @@ export class LevelCalculator { (Object.values(Attribute) as Attribute[]).forEach((attribute) => { const attrActivityPerformances = activityPerformances.filter( - (p) => this.standards.getActivityAttribute(p.activity) === attribute, + (p) => this.standards.byActivity(p.activity).getMetadata().attribute === attribute, ); attrLevels[attribute] = this.calculateAttributeLevel(attribute, player, attrActivityPerformances); }); @@ -127,7 +129,7 @@ export class LevelCalculator { activityPerformances: ActivityPerformance[], ): number { // must be activities of the given attribute - if (activityPerformances.some((p) => this.standards.getActivityAttribute(p.activity) !== attribute)) { + if (activityPerformances.some((p) => this.standards.byActivity(p.activity).getMetadata().attribute !== attribute)) { throw new Error("Wrong activity performance attribute"); } @@ -148,7 +150,7 @@ export class LevelCalculator { const interpolatedStandard = this.standards .byActivity(p.activity) .byMetrics(player.metrics) - .getInterpolated(); + .getOneInterpolated(); return this.findLevel(interpolatedStandard, p.performance); }); @@ -168,7 +170,9 @@ export class LevelCalculator { let resultLevelDiff = Infinity; for (const level in standard.levels) { - const diff = Math.abs(performance - standard.levels[level as unknown as number]); + if (!standard.levels[level]) continue; + + const diff = Math.abs(performance - standard.levels[level]); if (diff < resultLevelDiff) { resultLevel = +level; resultLevelDiff = diff; @@ -178,17 +182,26 @@ export class LevelCalculator { } } +type StandardsConfig = { + maxLevel: number +} + export class Standards { + readonly cfg: StandardsConfig; private activityStandards: ActivityStandards; - constructor(activityStandards: ActivityStandards) { + constructor(activityStandards: ActivityStandards, cfg?: Partial) { + this.cfg = { + maxLevel: cfg?.maxLevel ?? 100 + }; + // prepare data - this.activityStandards = activityStandards; + this.activityStandards = structuredClone(activityStandards); for (const activity of Object.keys(this.activityStandards) as Activity[]) { // expand/compress for (const standard of this.activityStandards[activity].standards) { const expandedLevels = this.expandLevels(standard.levels, 5); - const compressedLevels = this.compressLevels(expandedLevels, 100); + const compressedLevels = this.compressLevels(expandedLevels, this.cfg.maxLevel); standard.levels = compressedLevels; } @@ -216,7 +229,7 @@ export class Standards { const referenceStandard = this .byActivity(activity) .byMetrics({ weight: referenceWeight, gender: gender, age: age }) - .getInterpolated(); + .getOneInterpolated(); let currWeight = minWeight; while (currWeight <= maxWeight) { @@ -231,6 +244,8 @@ export class Standards { // apply allometric scaling to generate levels for (const lvl in referenceStandard.levels) { + if (!referenceStandard.levels[lvl]) continue; + const scalingExponent = .1; const coefficient = weightGenerator.ratio === "inverse" ? referenceWeight / currWeight : @@ -257,8 +272,6 @@ export class Standards { } } - - Bun.write("./newStandards.json", JSON.stringify(this.activityStandards, null, 2)); } public byActivity(activity: Activity) { @@ -270,78 +283,112 @@ export class Standards { const execMethods = { exact: { // these will get EXACT matches - getAll: function(): Standard[] { - let filtered = [...self.activityStandards[activity].standards]; - if (state.gender) - filtered = filtered.filter((s) => s.metrics.gender === state.gender); - if (state.age) - filtered = filtered.filter((s) => s.metrics.age === state.age); - if (state.weight) - filtered = filtered.filter((s) => s.metrics.weight === state.weight); - return filtered; + getAll(): Standard[] { + const src = self.activityStandards[activity].standards; + + const out: Standard[] = []; + for (let i = 0; i < src.length; i++) { + const s = src[i]; + if (state.gender != null && s.metrics.gender !== state.gender) continue; + if (state.age != null && s.metrics.age !== state.age) continue; + if (state.weight != null && s.metrics.weight !== state.weight) continue; + out.push(s); + } + return out; }, getOne: function(): Standard | undefined { return execMethods.exact.getAll()[0]; }, - getNearest(metric: NumberMetric, target: number): { lower: Standard, upper: Standard } { + getNearest(metric: NumberMetric, target: number): { lower: Standard; upper: Standard } { const standards = execMethods.exact.getAll(); - const lower = [...standards] - .sort((a, b) => a.metrics[metric] - b.metrics[metric]) - .reverse() - .find((s) => s.metrics[metric] <= target) ?? standards.at(0)!; - const upper = [...standards] - .sort((a, b) => a.metrics[metric] - b.metrics[metric]) - .find((s) => s.metrics[metric] >= target) ?? standards.at(-1)!; - return { lower, upper }; - }, - }, - interpolated: { - getInterpolated: (): Standard => { - const metrics: Metrics = state as Metrics; + if (standards.length === 0) throw new Error('no standards'); - const interpolateByWeight = (targetAge: number): Levels => { - const { lower: lowerAgeWeightStandard, upper: upperAgeWeightStandard } = this - .byActivity(activity) - .byGender(metrics.gender) - .byAge(targetAge) - .getNearest("weight", metrics.weight); + let lower = standards[0]; // best <= target + let upper = standards[0]; // best >= target + let hasLower = false, hasUpper = false; - const weightLower = lowerAgeWeightStandard.metrics.weight; - const weightUpper = upperAgeWeightStandard.metrics.weight; + for (const standard of standards) { + const standardMetricValue = standard.metrics[metric]; - let weightRatio = weightUpper === weightLower ? 1 : (metrics.weight - weightLower) / (weightUpper - weightLower); - weightRatio = Math.max(0, Math.min(1, weightRatio)); - - return this.interpolateLevels(lowerAgeWeightStandard.levels, upperAgeWeightStandard.levels, weightRatio); + if (standardMetricValue <= target) { + if (!hasLower || standardMetricValue > lower.metrics[metric]) { lower = standard; hasLower = true; } + } + if (standardMetricValue >= target) { + if (!hasUpper || standardMetricValue < upper.metrics[metric]) { upper = standard; hasUpper = true; } + } } - // Find nearest age standards - const { lower: lowerAgeStandard, upper: upperAgeStandard } = this - .byActivity(activity) - .byGender(metrics.gender) - .getNearest("age", metrics.age); - - const ageLower = lowerAgeStandard.metrics.age; - const ageUpper = upperAgeStandard.metrics.age; - - // Interpolate by age and weight - let ageRatio = ageUpper === ageLower ? 1 : (metrics.age - ageLower) / (ageUpper - ageLower); - ageRatio = Math.max(0, Math.min(1, ageRatio)); - - const interpolatedLevels = this.interpolateLevels( - interpolateByWeight(ageLower), - interpolateByWeight(ageUpper), - ageRatio - ); - - return { - metrics, - levels: interpolatedLevels - }; + // clamp to ends if one side missing + if (!hasLower) lower = standards[0]; + if (!hasUpper) upper = standards[standards.length - 1]; + return { lower, upper }; } } }; + const interpolateByAgeAndWeight = (metrics: Metrics): Standard => { + const interpolateByWeight = (targetAge: number): Levels => { + const { lower: lowerAgeWeightStandard, upper: upperAgeWeightStandard } = this + .byActivity(activity) + .byGender(metrics.gender) + .byAge(targetAge) + .getNearest("weight", metrics.weight); + + const weightLower = lowerAgeWeightStandard.metrics.weight; + const weightUpper = upperAgeWeightStandard.metrics.weight; + + let weightRatio = weightUpper === weightLower ? 1 : (metrics.weight - weightLower) / (weightUpper - weightLower); + weightRatio = Math.max(0, Math.min(1, weightRatio)); + + return this.interpolateLevels(lowerAgeWeightStandard.levels, upperAgeWeightStandard.levels, weightRatio); + } + + // Find nearest age standards + const { lower: lowerAgeStandard, upper: upperAgeStandard } = this + .byActivity(activity) + .byGender(metrics.gender) + .getNearest("age", metrics.age); + + const ageLower = lowerAgeStandard.metrics.age; + const ageUpper = upperAgeStandard.metrics.age; + + // Interpolate by age and weight + let ageRatio = ageUpper === ageLower ? 1 : (metrics.age - ageLower) / (ageUpper - ageLower); + ageRatio = Math.max(0, Math.min(1, ageRatio)); + + const interpolatedLevels = this.interpolateLevels( + interpolateByWeight(ageLower), + interpolateByWeight(ageUpper), + ageRatio + ); + + return { + metrics: metrics, + levels: interpolatedLevels + } + }; + + const getAllInterpolated = (): Standard[] => { + const metrics: Metrics = state as Metrics; + + const weights = [... new Set(this + .byActivity(activity) + .byGender(metrics.gender) + .getAll().map((s) => s.metrics.weight))]; + + const interpolatedStandards: Standard[] = weights + .map((w) => interpolateByAgeAndWeight({ gender: metrics.gender, age: metrics.age, weight: w })); + + return interpolatedStandards; + }; + + const getOneInterpolated = (): Standard => { + const metrics: Metrics = state as Metrics; + return interpolateByAgeAndWeight(metrics); + }; + + const getMetadata = () => this.activityStandards[activity].metadata; + // QUERY METHODS const byGender = (gender: Gender) => { @@ -351,30 +398,26 @@ export class Standards { const byAge = (age: number) => { state.age = age; - return { byWeight, ...execMethods.exact }; + return { byWeight, ...execMethods.exact, getAllInterpolated }; } const byWeight = (weight: number) => { state.weight = weight; - return { ...execMethods.exact, ...execMethods.interpolated }; + return { ...execMethods.exact, getOneInterpolated }; } const byMetrics = (metrics: Metrics) => { Object.assign(state, metrics); - return { ...execMethods.exact, ...execMethods.interpolated }; + return { ...execMethods.exact, getOneInterpolated }; } - const initialMethods = { byGender, byMetrics, ...execMethods.exact }; + const initialMethods = { byGender, byMetrics, getMetadata, ...execMethods.exact }; return initialMethods; } - getActivityAttribute(activity: Activity): Attribute { - return this.activityStandards[activity].metadata.attribute; - }; - - getAttributeActivities(attribute: Attribute): Activity[] { + public getAttributeActivities(attribute: Attribute): Activity[] { const activities: Activity[] = []; - for (const activity in this.activityStandards) { + for (const activity of Object.keys(this.activityStandards) as Activity[]) { const activityStandard = this.activityStandards[activity] as ActivityStandards[Activity]; if (activityStandard.metadata.attribute === attribute) { activities.push(activity as Activity); diff --git a/calculator/util.ts b/src/services/calculator/util.ts similarity index 64% rename from calculator/util.ts rename to src/services/calculator/util.ts index 9f677b9..821cb57 100644 --- a/calculator/util.ts +++ b/src/services/calculator/util.ts @@ -1,4 +1,4 @@ -import { Metrics } from "./calc"; +import { Metrics } from "../calculator/main"; // ------------------------------------------------------------------------------------------------- // DATA MODELS @@ -37,35 +37,18 @@ export enum Gender { // ------------------------------------------------------------------------------------------------- // Conversion utilities // ------------------------------------------------------------------------------------------------- + +export type StandardUnit = "ms" | "cm" | "kg"; + export const lbToKg = (lb: number | string): number => +lb * 0.453592; export const kgToLb = (kg: number | string): number => +kg * 2.20462; -export const minToMs = (min) => min * 60000; -export const secToMs = (sec) => sec * 1000; +export const minToMs = (min: number) => min * 60000; +export const secToMs = (sec: number) => sec * 1000; +export const msToMin = (ms: number) => ms / 60000; -export const feetToCm = (feet) => feet * 30.48; -export const inchesToCm = (inches) => inches * 2.54; - -export const mphToMtrsPerMs = (mph: number): number => (mph * 0.44704) / 1000; - -export const timeToMs = (time: string): number => { - const [main, decimal = "0"] = time.split("."); - const milliseconds = Number(decimal.padEnd(3, "0").slice(0, 3)); - - const parts = main.split(":").map(Number); - let minutes = 0, - seconds = 0; - - if (parts.length === 1) { - seconds = parts[0]; - } else if (parts.length === 2) { - [minutes, seconds] = parts as [number, number]; - } else { - throw new Error("Invalid time format"); - } - - return (minutes * 60 + seconds) * 1000 + milliseconds; -}; +export const feetToCm = (feet: number) => feet * 30.48; +export const inchesToCm = (inches: number) => inches * 2.54; export const msToTime = (ms: number, includeMs = false): string => { const minutes = Math.floor(ms / 60000); @@ -78,3 +61,7 @@ export const msToTime = (ms: number, includeMs = false): string => { } return formattedTime; }; + +export const range = (length: number) => Array.from({ length: length }, (_, i) => i + 1); + + diff --git a/commerce/printful.ts b/src/services/commerce/printful.ts similarity index 100% rename from commerce/printful.ts rename to src/services/commerce/printful.ts diff --git a/commerce/webflow.ts b/src/services/commerce/webflow.ts similarity index 99% rename from commerce/webflow.ts rename to src/services/commerce/webflow.ts index 16240bb..b57b052 100644 --- a/commerce/webflow.ts +++ b/src/services/commerce/webflow.ts @@ -249,9 +249,9 @@ export namespace Webflow { "skus": webflowVariants.slice(1) }) }); - createSkuResponse = await createSkuResponse.json(); + const createSkuObj = await createSkuResponse.json(); - const responseSkus = [addProductResponse["sku"], ...createSkuResponse["skus"]]; + const responseSkus = [addProductResponse["sku"], ...createSkuObj["skus"]]; // SYNC WEBFLOW/PRINTFUL PRODUCT AND VARIANT IDs let modifyPrintfulProductResponse = await fetch(`${Printful.API_URL}/store/products/${printfulProductId}`, { diff --git a/calculator/test.ts b/src/test/test-calculator.ts similarity index 87% rename from calculator/test.ts rename to src/test/test-calculator.ts index 1274517..552f921 100644 --- a/calculator/test.ts +++ b/src/test/test-calculator.ts @@ -1,5 +1,5 @@ -import { Activity, ActivityPerformance, feetToCm, Gender, inchesToCm, lbToKg, minToMs, Player, secToMs } from "./util"; -import { ActivityStandards, LevelCalculator, Standards } from "./calc.ts"; +import { Activity, ActivityPerformance, feetToCm, Gender, inchesToCm, lbToKg, minToMs, Player, secToMs } from "../services/calculator/util"; +import { ActivityStandards, LevelCalculator, Standards } from "../services/calculator/main" import rawStandards from "../data/standards.json" assert { type: "json" } const player: Player = { @@ -41,11 +41,6 @@ const computedPerformances: ActivityPerformance[] = [ }, ]; -const standards = new Standards(rawStandards as ActivityStandards); -const levelCalculator = new LevelCalculator(standards); - -console.log(levelCalculator.calculate(player, computedPerformances)); - // const newStandards: Standards = { // "Back Squat": [], // "Deadlift": [], diff --git a/src/view/.svelte-kit/ambient.d.ts b/src/view/.svelte-kit/ambient.d.ts new file mode 100644 index 0000000..e5543f8 --- /dev/null +++ b/src/view/.svelte-kit/ambient.d.ts @@ -0,0 +1,271 @@ + +// this file is generated — do not edit it + + +/// + +/** + * Environment variables [loaded by Vite](https://vitejs.dev/guide/env-and-mode.html#env-files) from `.env` files and `process.env`. Like [`$env/dynamic/private`](https://svelte.dev/docs/kit/$env-dynamic-private), this module cannot be imported into client-side code. This module only includes variables that _do not_ begin with [`config.kit.env.publicPrefix`](https://svelte.dev/docs/kit/configuration#env) _and do_ start with [`config.kit.env.privatePrefix`](https://svelte.dev/docs/kit/configuration#env) (if configured). + * + * _Unlike_ [`$env/dynamic/private`](https://svelte.dev/docs/kit/$env-dynamic-private), the values exported from this module are statically injected into your bundle at build time, enabling optimisations like dead code elimination. + * + * ```ts + * import { API_KEY } from '$env/static/private'; + * ``` + * + * Note that all environment variables referenced in your code should be declared (for example in an `.env` file), even if they don't have a value until the app is deployed: + * + * ``` + * MY_FEATURE_FLAG="" + * ``` + * + * You can override `.env` values from the command line like so: + * + * ```sh + * MY_FEATURE_FLAG="enabled" npm run dev + * ``` + */ +declare module '$env/static/private' { + export const IMSETTINGS_INTEGRATE_DESKTOP: string; + export const SHELL: string; + export const npm_command: string; + export const SESSION_MANAGER: string; + export const WINDOWID: string; + export const COLORTERM: string; + export const XDG_CONFIG_DIRS: string; + export const KGLOBALACCELD_PLATFORM: string; + export const XDG_SESSION_PATH: string; + export const HISTCONTROL: string; + export const XDG_MENU_PREFIX: string; + export const HISTSIZE: string; + export const HOSTNAME: string; + export const ICEAUTHORITY: string; + export const LANGUAGE: string; + export const NODE: string; + export const DOTNET_ROOT: string; + export const SSH_AUTH_SOCK: string; + export const FLYCTL_INSTALL: string; + export const SHELL_SESSION_ID: string; + export const MEMORY_PRESSURE_WRITE: string; + export const npm_config_local_prefix: string; + export const XMODIFIERS: string; + export const DESKTOP_SESSION: string; + export const SSH_AGENT_PID: string; + export const GTK_RC_FILES: string; + export const GDK_CORE_DEVICE_EVENTS: string; + export const GPG_TTY: string; + export const EDITOR: string; + export const XDG_SEAT: string; + export const PWD: string; + export const NIX_PROFILES: string; + export const LOGNAME: string; + export const XDG_SESSION_DESKTOP: string; + export const XDG_SESSION_TYPE: string; + export const SYSTEMD_EXEC_PID: string; + export const XAUTHORITY: string; + export const SDL_VIDEO_MINIMIZE_ON_FOCUS_LOSS: string; + export const XKB_DEFAULT_MODEL: string; + export const GTK2_RC_FILES: string; + export const HOME: string; + export const SSH_ASKPASS: string; + export const LANG: string; + export const LS_COLORS: string; + export const XDG_CURRENT_DESKTOP: string; + export const KONSOLE_DBUS_SERVICE: string; + export const MEMORY_PRESSURE_WATCH: string; + export const WAYLAND_DISPLAY: string; + export const NIX_SSL_CERT_FILE: string; + export const KONSOLE_DBUS_SESSION: string; + export const PROFILEHOME: string; + export const XDG_SEAT_PATH: string; + export const INVOCATION_ID: string; + export const KONSOLE_VERSION: string; + export const MANAGERPID: string; + export const IMSETTINGS_MODULE: string; + export const DOTNET_BUNDLE_EXTRACT_BASE_DIR: string; + export const STEAM_FRAME_FORCE_CLOSE: string; + export const KDE_SESSION_UID: string; + export const npm_lifecycle_script: string; + export const MOZ_GMP_PATH: string; + export const NVM_DIR: string; + export const XKB_DEFAULT_LAYOUT: string; + export const XDG_SESSION_CLASS: string; + export const TERM: string; + export const LESSOPEN: string; + export const USER: string; + export const COLORFGBG: string; + export const QT_WAYLAND_RECONNECT: string; + export const KDE_SESSION_VERSION: string; + export const PAM_KWALLET5_LOGIN: string; + export const DISPLAY: string; + export const npm_lifecycle_event: string; + export const SHLVL: string; + export const XDG_VTNR: string; + export const XDG_SESSION_ID: string; + export const npm_config_user_agent: string; + export const npm_execpath: string; + export const XDG_RUNTIME_DIR: string; + export const DEBUGINFOD_URLS: string; + export const npm_package_json: string; + export const BUN_INSTALL: string; + export const DEBUGINFOD_IMA_CERT_PATH: string; + export const KDEDIRS: string; + export const JOURNAL_STREAM: string; + export const XDG_DATA_DIRS: string; + export const KDE_FULL_SESSION: string; + export const PATH: string; + export const DBUS_SESSION_BUS_ADDRESS: string; + export const KDE_APPLICATIONS_AS_SCOPE: string; + export const MAIL: string; + export const npm_node_execpath: string; + export const OLDPWD: string; + export const GOPATH: string; + export const KONSOLE_DBUS_WINDOW: string; + export const _: string; + export const NODE_ENV: string; +} + +/** + * Similar to [`$env/static/private`](https://svelte.dev/docs/kit/$env-static-private), except that it only includes environment variables that begin with [`config.kit.env.publicPrefix`](https://svelte.dev/docs/kit/configuration#env) (which defaults to `PUBLIC_`), and can therefore safely be exposed to client-side code. + * + * Values are replaced statically at build time. + * + * ```ts + * import { PUBLIC_BASE_URL } from '$env/static/public'; + * ``` + */ +declare module '$env/static/public' { + +} + +/** + * This module provides access to runtime environment variables, as defined by the platform you're running on. For example if you're using [`adapter-node`](https://github.com/sveltejs/kit/tree/main/packages/adapter-node) (or running [`vite preview`](https://svelte.dev/docs/kit/cli)), this is equivalent to `process.env`. This module only includes variables that _do not_ begin with [`config.kit.env.publicPrefix`](https://svelte.dev/docs/kit/configuration#env) _and do_ start with [`config.kit.env.privatePrefix`](https://svelte.dev/docs/kit/configuration#env) (if configured). + * + * This module cannot be imported into client-side code. + * + * ```ts + * import { env } from '$env/dynamic/private'; + * console.log(env.DEPLOYMENT_SPECIFIC_VARIABLE); + * ``` + * + * > [!NOTE] In `dev`, `$env/dynamic` always includes environment variables from `.env`. In `prod`, this behavior will depend on your adapter. + */ +declare module '$env/dynamic/private' { + export const env: { + IMSETTINGS_INTEGRATE_DESKTOP: string; + SHELL: string; + npm_command: string; + SESSION_MANAGER: string; + WINDOWID: string; + COLORTERM: string; + XDG_CONFIG_DIRS: string; + KGLOBALACCELD_PLATFORM: string; + XDG_SESSION_PATH: string; + HISTCONTROL: string; + XDG_MENU_PREFIX: string; + HISTSIZE: string; + HOSTNAME: string; + ICEAUTHORITY: string; + LANGUAGE: string; + NODE: string; + DOTNET_ROOT: string; + SSH_AUTH_SOCK: string; + FLYCTL_INSTALL: string; + SHELL_SESSION_ID: string; + MEMORY_PRESSURE_WRITE: string; + npm_config_local_prefix: string; + XMODIFIERS: string; + DESKTOP_SESSION: string; + SSH_AGENT_PID: string; + GTK_RC_FILES: string; + GDK_CORE_DEVICE_EVENTS: string; + GPG_TTY: string; + EDITOR: string; + XDG_SEAT: string; + PWD: string; + NIX_PROFILES: string; + LOGNAME: string; + XDG_SESSION_DESKTOP: string; + XDG_SESSION_TYPE: string; + SYSTEMD_EXEC_PID: string; + XAUTHORITY: string; + SDL_VIDEO_MINIMIZE_ON_FOCUS_LOSS: string; + XKB_DEFAULT_MODEL: string; + GTK2_RC_FILES: string; + HOME: string; + SSH_ASKPASS: string; + LANG: string; + LS_COLORS: string; + XDG_CURRENT_DESKTOP: string; + KONSOLE_DBUS_SERVICE: string; + MEMORY_PRESSURE_WATCH: string; + WAYLAND_DISPLAY: string; + NIX_SSL_CERT_FILE: string; + KONSOLE_DBUS_SESSION: string; + PROFILEHOME: string; + XDG_SEAT_PATH: string; + INVOCATION_ID: string; + KONSOLE_VERSION: string; + MANAGERPID: string; + IMSETTINGS_MODULE: string; + DOTNET_BUNDLE_EXTRACT_BASE_DIR: string; + STEAM_FRAME_FORCE_CLOSE: string; + KDE_SESSION_UID: string; + npm_lifecycle_script: string; + MOZ_GMP_PATH: string; + NVM_DIR: string; + XKB_DEFAULT_LAYOUT: string; + XDG_SESSION_CLASS: string; + TERM: string; + LESSOPEN: string; + USER: string; + COLORFGBG: string; + QT_WAYLAND_RECONNECT: string; + KDE_SESSION_VERSION: string; + PAM_KWALLET5_LOGIN: string; + DISPLAY: string; + npm_lifecycle_event: string; + SHLVL: string; + XDG_VTNR: string; + XDG_SESSION_ID: string; + npm_config_user_agent: string; + npm_execpath: string; + XDG_RUNTIME_DIR: string; + DEBUGINFOD_URLS: string; + npm_package_json: string; + BUN_INSTALL: string; + DEBUGINFOD_IMA_CERT_PATH: string; + KDEDIRS: string; + JOURNAL_STREAM: string; + XDG_DATA_DIRS: string; + KDE_FULL_SESSION: string; + PATH: string; + DBUS_SESSION_BUS_ADDRESS: string; + KDE_APPLICATIONS_AS_SCOPE: string; + MAIL: string; + npm_node_execpath: string; + OLDPWD: string; + GOPATH: string; + KONSOLE_DBUS_WINDOW: string; + _: string; + NODE_ENV: string; + [key: `PUBLIC_${string}`]: undefined; + [key: `${string}`]: string | undefined; + } +} + +/** + * Similar to [`$env/dynamic/private`](https://svelte.dev/docs/kit/$env-dynamic-private), but only includes variables that begin with [`config.kit.env.publicPrefix`](https://svelte.dev/docs/kit/configuration#env) (which defaults to `PUBLIC_`), and can therefore safely be exposed to client-side code. + * + * Note that public dynamic environment variables must all be sent from the server to the client, causing larger network requests — when possible, use `$env/static/public` instead. + * + * ```ts + * import { env } from '$env/dynamic/public'; + * console.log(env.PUBLIC_DEPLOYMENT_SPECIFIC_VARIABLE); + * ``` + */ +declare module '$env/dynamic/public' { + export const env: { + [key: `PUBLIC_${string}`]: string | undefined; + } +} diff --git a/src/view/.svelte-kit/generated/client/app.js b/src/view/.svelte-kit/generated/client/app.js new file mode 100644 index 0000000..c03cfe5 --- /dev/null +++ b/src/view/.svelte-kit/generated/client/app.js @@ -0,0 +1,28 @@ +export { matchers } from './matchers.js'; + +export const nodes = [ + () => import('./nodes/0'), + () => import('./nodes/1'), + () => import('./nodes/2') +]; + +export const server_loads = [0]; + +export const dictionary = { + "/": [2] + }; + +export const hooks = { + handleError: (({ error }) => { console.error(error) }), + + reroute: (() => {}), + transport: {} +}; + +export const decoders = Object.fromEntries(Object.entries(hooks.transport).map(([k, v]) => [k, v.decode])); + +export const hash = false; + +export const decode = (type, value) => decoders[type](value); + +export { default as root } from '../root.js'; \ No newline at end of file diff --git a/src/view/.svelte-kit/generated/client/matchers.js b/src/view/.svelte-kit/generated/client/matchers.js new file mode 100644 index 0000000..f6bd30a --- /dev/null +++ b/src/view/.svelte-kit/generated/client/matchers.js @@ -0,0 +1 @@ +export const matchers = {}; \ No newline at end of file diff --git a/src/view/.svelte-kit/generated/client/nodes/0.js b/src/view/.svelte-kit/generated/client/nodes/0.js new file mode 100644 index 0000000..fed1375 --- /dev/null +++ b/src/view/.svelte-kit/generated/client/nodes/0.js @@ -0,0 +1 @@ +export { default as component } from "../../../../src/routes/+layout.svelte"; \ No newline at end of file diff --git a/src/view/.svelte-kit/generated/client/nodes/1.js b/src/view/.svelte-kit/generated/client/nodes/1.js new file mode 100644 index 0000000..07372a6 --- /dev/null +++ b/src/view/.svelte-kit/generated/client/nodes/1.js @@ -0,0 +1 @@ +export { default as component } from "../../../../../../node_modules/@sveltejs/kit/src/runtime/components/svelte-5/error.svelte"; \ No newline at end of file diff --git a/src/view/.svelte-kit/generated/client/nodes/2.js b/src/view/.svelte-kit/generated/client/nodes/2.js new file mode 100644 index 0000000..1cb4f85 --- /dev/null +++ b/src/view/.svelte-kit/generated/client/nodes/2.js @@ -0,0 +1 @@ +export { default as component } from "../../../../src/routes/+page.svelte"; \ No newline at end of file diff --git a/src/view/.svelte-kit/generated/root.js b/src/view/.svelte-kit/generated/root.js new file mode 100644 index 0000000..4d1e892 --- /dev/null +++ b/src/view/.svelte-kit/generated/root.js @@ -0,0 +1,3 @@ +import { asClassComponent } from 'svelte/legacy'; +import Root from './root.svelte'; +export default asClassComponent(Root); \ No newline at end of file diff --git a/src/view/.svelte-kit/generated/root.svelte b/src/view/.svelte-kit/generated/root.svelte new file mode 100644 index 0000000..acbdd37 --- /dev/null +++ b/src/view/.svelte-kit/generated/root.svelte @@ -0,0 +1,66 @@ + + + + +{#if constructors[1]} + {@const Pyramid_0 = constructors[0]} + + + + + + +{:else} + {@const Pyramid_0 = constructors[0]} + + + +{/if} + +{#if mounted} +
+ {#if navigated} + {title} + {/if} +
+{/if} \ No newline at end of file diff --git a/src/view/.svelte-kit/generated/server/internal.js b/src/view/.svelte-kit/generated/server/internal.js new file mode 100644 index 0000000..452f0cc --- /dev/null +++ b/src/view/.svelte-kit/generated/server/internal.js @@ -0,0 +1,52 @@ + +import root from '../root.js'; +import { set_building, set_prerendering } from '__sveltekit/environment'; +import { set_assets } from '__sveltekit/paths'; +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, + 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" + 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: "hxbxsl" +}; + +export async function get_hooks() { + let handle; + let handleFetch; + let handleError; + let handleValidationError; + let init; + + + 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/src/view/.svelte-kit/non-ambient.d.ts b/src/view/.svelte-kit/non-ambient.d.ts new file mode 100644 index 0000000..705dcff --- /dev/null +++ b/src/view/.svelte-kit/non-ambient.d.ts @@ -0,0 +1,42 @@ + +// 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(): "/" | "/[...slugs]"; + RouteParams(): { + "/[...slugs]": { slugs: string } + }; + LayoutParams(): { + "/": { slugs?: string }; + "/[...slugs]": { slugs: string } + }; + Pathname(): "/" | `/${string}` & {} | `/${string}/` & {}; + ResolvedPathname(): `${"" | `/${string}`}${ReturnType}`; + Asset(): "/robots.txt" | string & {}; + } +} \ No newline at end of file diff --git a/src/view/.svelte-kit/tsconfig.json b/src/view/.svelte-kit/tsconfig.json new file mode 100644 index 0000000..64aad07 --- /dev/null +++ b/src/view/.svelte-kit/tsconfig.json @@ -0,0 +1,52 @@ +{ + "compilerOptions": { + "paths": { + "$lib": [ + "../src/lib" + ], + "$lib/*": [ + "../src/lib/*" + ], + "$app/types": [ + "./types/index.d.ts" + ] + }, + "rootDirs": [ + "..", + "./types" + ], + "verbatimModuleSyntax": true, + "isolatedModules": true, + "lib": [ + "esnext", + "DOM", + "DOM.Iterable" + ], + "moduleResolution": "bundler", + "module": "esnext", + "noEmit": true, + "target": "esnext" + }, + "include": [ + "ambient.d.ts", + "non-ambient.d.ts", + "./types/**/$types.d.ts", + "../vite.config.js", + "../vite.config.ts", + "../src/**/*.js", + "../src/**/*.ts", + "../src/**/*.svelte", + "../tests/**/*.js", + "../tests/**/*.ts", + "../tests/**/*.svelte" + ], + "exclude": [ + "../node_modules/**", + "../src/service-worker.js", + "../src/service-worker/**/*.js", + "../src/service-worker.ts", + "../src/service-worker/**/*.ts", + "../src/service-worker.d.ts", + "../src/service-worker/**/*.d.ts" + ] +} \ No newline at end of file diff --git a/src/view/.svelte-kit/types/route_meta_data.json b/src/view/.svelte-kit/types/route_meta_data.json new file mode 100644 index 0000000..7720ac1 --- /dev/null +++ b/src/view/.svelte-kit/types/route_meta_data.json @@ -0,0 +1,9 @@ +{ + "/": [ + "src/routes/+layout.server.ts", + "src/routes/+layout.server.ts" + ], + "/[...slugs]": [ + "src/routes/[...slugs]/+server.ts" + ] +} \ No newline at end of file diff --git a/src/view/.svelte-kit/types/src/routes/$types.d.ts b/src/view/.svelte-kit/types/src/routes/$types.d.ts new file mode 100644 index 0000000..b06d4c7 --- /dev/null +++ b/src/view/.svelte-kit/types/src/routes/$types.d.ts @@ -0,0 +1,28 @@ +import type * as Kit from '@sveltejs/kit'; + +type Expand = T extends infer O ? { [K in keyof O]: O[K] } : never; +// @ts-ignore +type MatcherParam = M extends (param : string) => param is infer U ? U extends string ? U : string : string; +type RouteParams = { }; +type RouteId = '/'; +type MaybeWithVoid = {} extends T ? T | void : T; +export type RequiredKeys = { [K in keyof T]-?: {} extends { [P in K]: T[K] } ? never : K; }[keyof T]; +type OutputDataShape = MaybeWithVoid> & Partial> & Record> +type EnsureDefined = T extends null | undefined ? {} : T; +type OptionalUnion, A extends keyof U = U extends U ? keyof U : never> = U extends unknown ? { [P in Exclude]?: never } & U : never; +export type Snapshot = Kit.Snapshot; +type PageParentData = EnsureDefined; +type LayoutRouteId = RouteId | "/" | null +type LayoutParams = RouteParams & { } +type LayoutServerParentData = EnsureDefined<{}>; +type LayoutParentData = EnsureDefined<{}>; + +export type PageServerData = null; +export type PageData = Expand; +export type PageProps = { params: RouteParams; data: PageData } +export type LayoutServerLoad = OutputDataShape> = Kit.ServerLoad; +export type LayoutServerLoadEvent = Parameters[0]; +export type LayoutServerData = Expand>>>>>; +export type LayoutData = Expand & EnsureDefined>; +export type LayoutProps = { params: LayoutParams; data: LayoutData; children: import("svelte").Snippet } +export type RequestEvent = Kit.RequestEvent; \ No newline at end of file diff --git a/src/view/.svelte-kit/types/src/routes/[...slugs]/$types.d.ts b/src/view/.svelte-kit/types/src/routes/[...slugs]/$types.d.ts new file mode 100644 index 0000000..7198b54 --- /dev/null +++ b/src/view/.svelte-kit/types/src/routes/[...slugs]/$types.d.ts @@ -0,0 +1,11 @@ +import type * as Kit from '@sveltejs/kit'; + +type Expand = T extends infer O ? { [K in keyof O]: O[K] } : never; +// @ts-ignore +type MatcherParam = M extends (param : string) => param is infer U ? U extends string ? U : string : string; +type RouteParams = { slugs: string }; +type RouteId = '/[...slugs]'; + +export type EntryGenerator = () => Promise> | Array; +export type RequestHandler = Kit.RequestHandler; +export type RequestEvent = Kit.RequestEvent; \ No newline at end of file diff --git a/src/view/.svelte-kit/types/src/routes/proxy+layout.server.ts b/src/view/.svelte-kit/types/src/routes/proxy+layout.server.ts new file mode 100644 index 0000000..342d895 --- /dev/null +++ b/src/view/.svelte-kit/types/src/routes/proxy+layout.server.ts @@ -0,0 +1,12 @@ +// @ts-nocheck +import { api } from "$lib"; +import type { ActivityStandards } from "../../../services/calculator/main"; +import type { LayoutServerLoad } from "./$types"; + +export const load = async ({ }: Parameters[0]) => { + const { data: allStandardsRaw } = await api.data.standards.get(); + + return { + allStandardsRaw: allStandardsRaw as ActivityStandards + }; +}; diff --git a/src/view/src/app.css b/src/view/src/app.css new file mode 100644 index 0000000..a15d485 --- /dev/null +++ b/src/view/src/app.css @@ -0,0 +1,27 @@ +:root { + --bg: #0b0f14; + --fg: #e5e7eb; + --muted: #9ca3af; + --card: #0f141a; + --border: #1f2937; + --accent: #e5e7eb; +} + +* { + box-sizing: border-box; +} + +html, +body { + margin: 0; + padding: 0; + background: var(--bg); + color: var(--fg); + font: + 14px/1.45 system-ui, + -apple-system, + Segoe UI, + Roboto, + Inter, + sans-serif; +} diff --git a/src/view/src/app.d.ts b/src/view/src/app.d.ts new file mode 100644 index 0000000..da08e6d --- /dev/null +++ b/src/view/src/app.d.ts @@ -0,0 +1,13 @@ +// See https://svelte.dev/docs/kit/types#app.d.ts +// for information about these interfaces +declare global { + namespace App { + // interface Error {} + // interface Locals {} + // interface PageData {} + // interface PageState {} + // interface Platform {} + } +} + +export {}; diff --git a/src/view/src/app.html b/src/view/src/app.html new file mode 100644 index 0000000..f273cc5 --- /dev/null +++ b/src/view/src/app.html @@ -0,0 +1,11 @@ + + + + + + %sveltekit.head% + + +
%sveltekit.body%
+ + diff --git a/src/view/src/lib/assets/favicon.svg b/src/view/src/lib/assets/favicon.svg new file mode 100644 index 0000000..cc5dc66 --- /dev/null +++ b/src/view/src/lib/assets/favicon.svg @@ -0,0 +1 @@ +svelte-logo \ No newline at end of file diff --git a/src/view/src/lib/index.ts b/src/view/src/lib/index.ts new file mode 100644 index 0000000..8748f3d --- /dev/null +++ b/src/view/src/lib/index.ts @@ -0,0 +1,6 @@ +import { treaty } from "@elysiajs/eden"; +import { app, type App } from "../../../api"; + +const apiWrapper = treaty(app); +export const api = apiWrapper.api; + diff --git a/src/view/src/routes/+layout.server.ts b/src/view/src/routes/+layout.server.ts new file mode 100644 index 0000000..02974c3 --- /dev/null +++ b/src/view/src/routes/+layout.server.ts @@ -0,0 +1,11 @@ +import { api } from "$lib"; +import type { ActivityStandards } from "../../../services/calculator/main"; +import type { LayoutServerLoad } from "./$types"; + +export const load: LayoutServerLoad = async ({ }) => { + const { data: allStandardsRaw } = await api.data.standards.get(); + + return { + allStandardsRaw: allStandardsRaw as ActivityStandards + }; +}; diff --git a/src/view/src/routes/+layout.svelte b/src/view/src/routes/+layout.svelte new file mode 100644 index 0000000..ec2632a --- /dev/null +++ b/src/view/src/routes/+layout.svelte @@ -0,0 +1,12 @@ + + + + + + +{@render children?.()} diff --git a/src/view/src/routes/+page.svelte b/src/view/src/routes/+page.svelte new file mode 100644 index 0000000..337a6cd --- /dev/null +++ b/src/view/src/routes/+page.svelte @@ -0,0 +1,407 @@ + + +
+
+
+
+ Metrics + + + + + + + + +
+ +
+ Parameters + + +
+
+ + {#if !selected.gender || !selected.age} +

Not enough info entered

+ {:else} + {@render standardsTable( + selected.gender, + selected.age, + selected.weight, + )} + {/if} +
+
+ +{#snippet standardsTable(gender: Gender, age: number, weight: number)} +
+
+
+
+ + + + + {#each range(selected.maxLevel) as lvl} + + {/each} + + + + {#if weight} + {@const standard = allStandards + .byActivity(selected.activity) + .byGender(gender) + .byAge(age) + .byWeight(lbToKg(weight)) + .getOneInterpolated()} + + + + {#each range(selected.maxLevel) as lvl} + + {/each} + + {:else} + {@const standards = allStandards + .byActivity(selected.activity) + .byGender(gender) + .byAge(age) + .getAllInterpolated()} + {#each standards as standard} + + + {#each range(allStandards.cfg.maxLevel) as lvl} + + {/each} + + {/each} + {/if} + +
Body weight{lvl}
{Math.round( + kgToLb(standard.metrics.weight), + )}{getFormattedLevelValue( + selected.activity, + standard, + lvl, + )}
{Math.round( + kgToLb(standard.metrics.weight), + )}{getFormattedLevelValue( + selected.activity, + standard, + lvl, + )}
+
+
+
+
+{/snippet} + + diff --git a/src/view/src/routes/[...slugs]/+server.ts b/src/view/src/routes/[...slugs]/+server.ts new file mode 100644 index 0000000..9c05637 --- /dev/null +++ b/src/view/src/routes/[...slugs]/+server.ts @@ -0,0 +1,4 @@ +import { app } from "../../../../api" + +type RequestHandler = (v: { request: Request }) => Response | Promise +export const fallback: RequestHandler = ({ request }) => app.handle(request) diff --git a/src/view/static/robots.txt b/src/view/static/robots.txt new file mode 100644 index 0000000..b6dd667 --- /dev/null +++ b/src/view/static/robots.txt @@ -0,0 +1,3 @@ +# allow crawling everything by default +User-agent: * +Disallow: diff --git a/src/view/svelte.config.js b/src/view/svelte.config.js new file mode 100644 index 0000000..10419b5 --- /dev/null +++ b/src/view/svelte.config.js @@ -0,0 +1,18 @@ +import adapter from "svelte-adapter-bun"; +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; + +/** @type {import('@sveltejs/kit').Config} */ +const config = { + // Consult https://svelte.dev/docs/kit/integrations + // for more information about preprocessors + preprocess: vitePreprocess(), + + kit: { + // adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list. + // If your environment is not supported, or you settled on a specific environment, switch out the adapter. + // See https://svelte.dev/docs/kit/adapters for more information about adapters. + adapter: adapter(), + } +}; + +export default config; diff --git a/src/view/tsconfig.json b/src/view/tsconfig.json new file mode 100644 index 0000000..5fa220a --- /dev/null +++ b/src/view/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "./.svelte-kit/tsconfig.json", + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "verbatimModuleSyntax": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "moduleResolution": "bundler" + } + // Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias + // except $lib which is handled by https://svelte.dev/docs/kit/configuration#files + // + // To make changes to top-level options such as include and exclude, we recommend extending + // the generated config; see https://svelte.dev/docs/kit/configuration#typescript +} diff --git a/src/view/vite.config.ts b/src/view/vite.config.ts new file mode 100644 index 0000000..bbf8c7d --- /dev/null +++ b/src/view/vite.config.ts @@ -0,0 +1,6 @@ +import { sveltekit } from '@sveltejs/kit/vite'; +import { defineConfig } from 'vite'; + +export default defineConfig({ + plugins: [sveltekit()] +});