Big changes. Added Sentry at least for now for error tracking to get this up. Moved prisma client generation to the server hooks and passing in locals. Refactor to use prisma in locals. Creating expansions and linking while displaying on Game page.

This commit is contained in:
Bradley Shellnut 2023-10-17 22:28:53 +13:00
parent 9ce5458dc8
commit 7d334f9cb7
31 changed files with 787 additions and 329 deletions

5
.gitignore vendored
View file

@ -9,4 +9,7 @@ node_modules
.vercel
.output
.idea
.fleet
.fleet
# Sentry Config File
.sentryclirc

View file

@ -83,6 +83,7 @@
"@melt-ui/svelte": "^0.50.1",
"@paralleldrive/cuid2": "^2.2.2",
"@prisma/client": "^5.4.2",
"@sentry/sveltekit": "^7.74.0",
"@types/feather-icons": "^4.29.1",
"@vercel/og": "^0.5.13",
"bits-ui": "^0.0.27",

View file

@ -35,6 +35,9 @@ dependencies:
'@prisma/client':
specifier: ^5.4.2
version: 5.4.2(prisma@5.4.2)
'@sentry/sveltekit':
specifier: ^7.74.0
version: 7.74.0(@sveltejs/kit@1.25.2)(svelte@4.2.1)
'@types/feather-icons':
specifier: ^4.29.1
version: 4.29.1
@ -258,6 +261,24 @@ packages:
- debug
dev: false
/@babel/helper-string-parser@7.22.5:
resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==}
engines: {node: '>=6.9.0'}
dev: false
/@babel/helper-validator-identifier@7.22.20:
resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==}
engines: {node: '>=6.9.0'}
dev: false
/@babel/parser@7.23.0:
resolution: {integrity: sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==}
engines: {node: '>=6.0.0'}
hasBin: true
dependencies:
'@babel/types': 7.23.0
dev: false
/@babel/runtime@7.23.2:
resolution: {integrity: sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==}
engines: {node: '>=6.9.0'}
@ -265,6 +286,15 @@ packages:
regenerator-runtime: 0.14.0
dev: false
/@babel/types@7.23.0:
resolution: {integrity: sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/helper-string-parser': 7.22.5
'@babel/helper-validator-identifier': 7.22.20
to-fast-properties: 2.0.0
dev: false
/@colors/colors@1.6.0:
resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==}
engines: {node: '>=0.1.90'}
@ -1472,6 +1502,173 @@ packages:
estree-walker: 2.0.2
picomatch: 2.3.1
/@sentry-internal/tracing@7.74.0:
resolution: {integrity: sha512-JK6IRGgdtZjswGfaGIHNWIThffhOHzVIIaGmglui+VFIzOsOqePjoxaDV0MEvzafxXZD7eWqGE5RGuZ0n6HFVg==}
engines: {node: '>=8'}
dependencies:
'@sentry/core': 7.74.0
'@sentry/types': 7.74.0
'@sentry/utils': 7.74.0
tslib: 2.6.1
dev: false
/@sentry/browser@7.74.0:
resolution: {integrity: sha512-Njr8216Z1dFUcl6NqBOk20dssK9SjoVddY74Xq+Q4p3NfXBG3lkMcACXor7SFoJRZXq8CZWGS13Cc5KwViRw4g==}
engines: {node: '>=8'}
dependencies:
'@sentry-internal/tracing': 7.74.0
'@sentry/core': 7.74.0
'@sentry/replay': 7.74.0
'@sentry/types': 7.74.0
'@sentry/utils': 7.74.0
tslib: 2.6.1
dev: false
/@sentry/bundler-plugin-core@0.6.1:
resolution: {integrity: sha512-EecCJKp9ERM7J93DNDJTvkY78UiD/IfOjBdXWnaUVE0n619O7LfMVjwlXzxRJKl2x05dBE3lDraILLDGxCf6fg==}
engines: {node: '>= 10'}
dependencies:
'@sentry/cli': 2.21.2
'@sentry/node': 7.74.0
'@sentry/tracing': 7.74.0
find-up: 5.0.0
glob: 9.3.2
magic-string: 0.27.0
unplugin: 1.0.1
webpack-sources: 3.2.3
transitivePeerDependencies:
- encoding
- supports-color
dev: false
/@sentry/cli@2.21.2:
resolution: {integrity: sha512-X1nye89zl+QV3FSuQDGItfM51tW9PQ7ce0TtV/12DgGgTVEgnVp5uvO3wX5XauHvulQzRPzwUL3ZK+yS5bAwCw==}
engines: {node: '>= 10'}
hasBin: true
requiresBuild: true
dependencies:
https-proxy-agent: 5.0.1
node-fetch: 2.6.7
progress: 2.0.3
proxy-from-env: 1.1.0
which: 2.0.2
transitivePeerDependencies:
- encoding
- supports-color
dev: false
/@sentry/core@7.74.0:
resolution: {integrity: sha512-83NRuqn7nDZkSVBN5yJQqcpXDG4yMYiB7TkYUKrGTzBpRy6KUOrkCdybuKk0oraTIGiGSe5WEwCFySiNgR9FzA==}
engines: {node: '>=8'}
dependencies:
'@sentry/types': 7.74.0
'@sentry/utils': 7.74.0
tslib: 2.6.1
dev: false
/@sentry/integrations@7.74.0:
resolution: {integrity: sha512-O4UyxiV5wzXSDnEd9Z/SIt/5M12URWNtIJPPJjowlllzw8X9e3zBcnXmjMOLZ+mZWjQmRDjOoz3lPPQ17f7fvw==}
engines: {node: '>=8'}
dependencies:
'@sentry/core': 7.74.0
'@sentry/types': 7.74.0
'@sentry/utils': 7.74.0
localforage: 1.10.0
tslib: 2.6.1
dev: false
/@sentry/node@7.74.0:
resolution: {integrity: sha512-uBmW2/z0cz/WFIG74ZF7lSipO0XNzMf9yrdqnZXnGDYsUZE4I4QiqDN0hNi6fkTgf9MYRC8uFem2OkAvyPJ74Q==}
engines: {node: '>=8'}
dependencies:
'@sentry-internal/tracing': 7.74.0
'@sentry/core': 7.74.0
'@sentry/types': 7.74.0
'@sentry/utils': 7.74.0
cookie: 0.5.0
https-proxy-agent: 5.0.1
lru_map: 0.3.3
tslib: 2.6.1
transitivePeerDependencies:
- supports-color
dev: false
/@sentry/replay@7.74.0:
resolution: {integrity: sha512-GoYa3cHTTFVI/J1cnZ0i4X128mf/JljaswO3PWNTe2k3lSHq/LM5aV0keClRvwM0W8hlix8oOTT06nnenOUmmw==}
engines: {node: '>=12'}
dependencies:
'@sentry/core': 7.74.0
'@sentry/types': 7.74.0
'@sentry/utils': 7.74.0
dev: false
/@sentry/svelte@7.74.0(svelte@4.2.1):
resolution: {integrity: sha512-dIbNOGs6wOp7QrRjDvYtuNDWeQjXRSWBWJWQVxHLpnzLoWW6isj1Iyrbm9po38CBGdmv5jcQz69Lf5GFRckgFw==}
engines: {node: '>=8'}
peerDependencies:
svelte: 3.x || 4.x
dependencies:
'@sentry/browser': 7.74.0
'@sentry/types': 7.74.0
'@sentry/utils': 7.74.0
magic-string: 0.30.0
svelte: 4.2.1
tslib: 2.6.1
dev: false
/@sentry/sveltekit@7.74.0(@sveltejs/kit@1.25.2)(svelte@4.2.1):
resolution: {integrity: sha512-Ijdc/5lcvpwL0owkCkZP36YzcU32Fc8/38PrqU1rXsNglBB1KyZ0zAbsCevN+Y9sv5BLVGut8uIsJ7Fc0j6iFQ==}
engines: {node: '>=16'}
peerDependencies:
'@sveltejs/kit': 1.x
dependencies:
'@sentry-internal/tracing': 7.74.0
'@sentry/core': 7.74.0
'@sentry/integrations': 7.74.0
'@sentry/node': 7.74.0
'@sentry/svelte': 7.74.0(svelte@4.2.1)
'@sentry/types': 7.74.0
'@sentry/utils': 7.74.0
'@sentry/vite-plugin': 0.6.1
'@sveltejs/kit': 1.25.2(svelte@4.2.1)(vite@4.4.9)
magicast: 0.2.8
sorcery: 0.11.0
transitivePeerDependencies:
- encoding
- supports-color
- svelte
dev: false
/@sentry/tracing@7.74.0:
resolution: {integrity: sha512-rSFJADhh3J3zmkzJ1EXCOwS3h7F6o/lSKu7CWZSZ6k5kBvbCJ5AXvGQadhPdWPJMMcPFzCJaOyTKEPcwL4tbCw==}
engines: {node: '>=8'}
dependencies:
'@sentry-internal/tracing': 7.74.0
dev: false
/@sentry/types@7.74.0:
resolution: {integrity: sha512-rI5eIRbUycWjn6s6o3yAjjWtIvYSxZDdnKv5je2EZINfLKcMPj1dkl6wQd2F4y7gLfD/N6Y0wZYIXC3DUdJQQg==}
engines: {node: '>=8'}
dev: false
/@sentry/utils@7.74.0:
resolution: {integrity: sha512-k3np8nuTPtx5KDODPtULfFln4UXdE56MZCcF19Jv6Ljxf+YN/Ady1+0Oi3e0XoSvFpWNyWnglauT7M65qCE6kg==}
engines: {node: '>=8'}
dependencies:
'@sentry/types': 7.74.0
tslib: 2.6.1
dev: false
/@sentry/vite-plugin@0.6.1:
resolution: {integrity: sha512-qkvKaSOcNhNWcdxRXLSs+8cF3ey0XIRmEzTl8U7sTTcZwuOMHsJB+HsYij6aTGaqsKfP8w1ozVt9szBAiL4//w==}
engines: {node: '>= 10'}
dependencies:
'@sentry/bundler-plugin-core': 0.6.1
transitivePeerDependencies:
- encoding
- supports-color
dev: false
/@shuding/opentype.js@1.4.0-beta.0:
resolution: {integrity: sha512-3NgmNyH3l/Hv6EvsWJbsvpcpUba6R8IREQ83nH83cyakCw7uM1arZKNfHwv1Wz6jgqrF/j4x5ELvR6PnK9nTcA==}
engines: {node: '>= 8.0.0'}
@ -1920,10 +2117,27 @@ packages:
engines: {node: '>=8'}
dev: true
/assert@2.1.0:
resolution: {integrity: sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==}
dependencies:
call-bind: 1.0.2
is-nan: 1.3.2
object-is: 1.1.5
object.assign: 4.1.4
util: 0.12.5
dev: false
/assertion-error@1.1.0:
resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==}
dev: true
/ast-types@0.16.1:
resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==}
engines: {node: '>=4'}
dependencies:
tslib: 2.6.1
dev: false
/async-sema@3.1.1:
resolution: {integrity: sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==}
@ -1947,6 +2161,11 @@ packages:
postcss-value-parser: 4.2.0
dev: true
/available-typed-arrays@1.0.5:
resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==}
engines: {node: '>= 0.4'}
dev: false
/axios-retry@3.8.0:
resolution: {integrity: sha512-CfIsQyWNc5/AE7x/UEReRUadiBmQeoBpSEC+4QyGLJMswTsP1tz0GW2YYPnE7w9+ESMef5zOgLDFpHynNyEZ1w==}
dependencies:
@ -2024,6 +2243,12 @@ packages:
balanced-match: 1.0.2
concat-map: 0.0.1
/brace-expansion@2.0.1:
resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
dependencies:
balanced-match: 1.0.2
dev: false
/braces@3.0.2:
resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
engines: {node: '>=8'}
@ -2054,7 +2279,6 @@ packages:
/buffer-crc32@0.2.13:
resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==}
dev: true
/busboy@1.6.0:
resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
@ -2062,6 +2286,13 @@ packages:
dependencies:
streamsearch: 1.1.0
/call-bind@1.0.2:
resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==}
dependencies:
function-bind: 1.1.1
get-intrinsic: 1.2.1
dev: false
/callsites@3.1.0:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'}
@ -2287,6 +2518,24 @@ packages:
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
engines: {node: '>=0.10.0'}
/define-data-property@1.1.1:
resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==}
engines: {node: '>= 0.4'}
dependencies:
get-intrinsic: 1.2.1
gopd: 1.0.1
has-property-descriptors: 1.0.0
dev: false
/define-properties@1.2.1:
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
engines: {node: '>= 0.4'}
dependencies:
define-data-property: 1.1.1
has-property-descriptors: 1.0.0
object-keys: 1.1.1
dev: false
/delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
@ -2347,7 +2596,6 @@ packages:
/es6-promise@3.3.1:
resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==}
dev: true
/esbuild@0.16.8:
resolution: {integrity: sha512-RKxRaLYAI5b/IVJ5k8jK3bO2G7cch2ZIZFbfKHbBzpwsWt9+VChcBEndNISBBZ5c3WwekFfkfl11/2QfIGHgDw==}
@ -2537,6 +2785,12 @@ packages:
eslint-visitor-keys: 3.4.3
dev: true
/esprima@4.0.1:
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
engines: {node: '>=4'}
hasBin: true
dev: false
/esquery@1.5.0:
resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==}
engines: {node: '>=0.10'}
@ -2655,7 +2909,6 @@ packages:
dependencies:
locate-path: 6.0.0
path-exists: 4.0.0
dev: true
/flat-cache@3.0.4:
resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==}
@ -2690,6 +2943,12 @@ packages:
optional: true
dev: false
/for-each@0.3.3:
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
dependencies:
is-callable: 1.2.7
dev: false
/form-data@4.0.0:
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
engines: {node: '>= 6'}
@ -2760,6 +3019,15 @@ packages:
resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==}
dev: true
/get-intrinsic@1.2.1:
resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==}
dependencies:
function-bind: 1.1.1
has: 1.0.3
has-proto: 1.0.1
has-symbols: 1.0.3
dev: false
/glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
@ -2792,6 +3060,16 @@ packages:
once: 1.4.0
path-is-absolute: 1.0.1
/glob@9.3.2:
resolution: {integrity: sha512-BTv/JhKXFEHsErMte/AnfiSv8yYOLLiyH2lTg8vn02O21zWFgHPTfxtgn1QRe7NRgggUhC8hacR2Re94svHqeA==}
engines: {node: '>=16 || 14 >=14.17'}
dependencies:
fs.realpath: 1.0.0
minimatch: 7.4.6
minipass: 4.2.8
path-scurry: 1.10.1
dev: false
/globals@13.19.0:
resolution: {integrity: sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==}
engines: {node: '>=8'}
@ -2817,6 +3095,12 @@ packages:
/globrex@0.1.2:
resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==}
/gopd@1.0.1:
resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
dependencies:
get-intrinsic: 1.2.1
dev: false
/graceful-fs@4.2.10:
resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==}
@ -2829,6 +3113,29 @@ packages:
engines: {node: '>=8'}
dev: true
/has-property-descriptors@1.0.0:
resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==}
dependencies:
get-intrinsic: 1.2.1
dev: false
/has-proto@1.0.1:
resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==}
engines: {node: '>= 0.4'}
dev: false
/has-symbols@1.0.3:
resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
engines: {node: '>= 0.4'}
dev: false
/has-tostringtag@1.0.0:
resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==}
engines: {node: '>= 0.4'}
dependencies:
has-symbols: 1.0.3
dev: false
/has-unicode@2.0.1:
resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==}
@ -2871,6 +3178,10 @@ packages:
engines: {node: '>= 4'}
dev: true
/immediate@3.0.6:
resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==}
dev: false
/immutable@4.1.0:
resolution: {integrity: sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==}
@ -2900,12 +3211,25 @@ packages:
/inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
/is-arguments@1.1.1:
resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==}
engines: {node: '>= 0.4'}
dependencies:
call-bind: 1.0.2
has-tostringtag: 1.0.0
dev: false
/is-binary-path@2.1.0:
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
engines: {node: '>=8'}
dependencies:
binary-extensions: 2.2.0
/is-callable@1.2.7:
resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
engines: {node: '>= 0.4'}
dev: false
/is-core-module@2.12.1:
resolution: {integrity: sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==}
dependencies:
@ -2919,12 +3243,27 @@ packages:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
/is-generator-function@1.0.10:
resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==}
engines: {node: '>= 0.4'}
dependencies:
has-tostringtag: 1.0.0
dev: false
/is-glob@4.0.3:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
dependencies:
is-extglob: 2.1.1
/is-nan@1.3.2:
resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==}
engines: {node: '>= 0.4'}
dependencies:
call-bind: 1.0.2
define-properties: 1.2.1
dev: false
/is-number@7.0.0:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
@ -2944,9 +3283,15 @@ packages:
engines: {node: '>=10'}
dev: false
/is-typed-array@1.1.12:
resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==}
engines: {node: '>= 0.4'}
dependencies:
which-typed-array: 1.1.11
dev: false
/isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
dev: true
/isomorphic-unfetch@3.1.0:
resolution: {integrity: sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==}
@ -3017,6 +3362,12 @@ packages:
type-check: 0.4.0
dev: true
/lie@3.1.1:
resolution: {integrity: sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==}
dependencies:
immediate: 3.0.6
dev: false
/lilconfig@2.0.6:
resolution: {integrity: sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==}
engines: {node: '>=10'}
@ -3043,6 +3394,12 @@ packages:
engines: {node: '>=14'}
dev: true
/localforage@1.10.0:
resolution: {integrity: sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==}
dependencies:
lie: 3.1.1
dev: false
/locate-character@3.0.0:
resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==}
@ -3051,7 +3408,6 @@ packages:
engines: {node: '>=10'}
dependencies:
p-locate: 5.0.0
dev: true
/lodash.clone@4.5.0:
resolution: {integrity: sha512-GhrVeweiTD6uTmmn5hV/lzgCQhccwReIVRLHp7LT4SopOjqEZ5BbX8b5WWEtAKasjmy8hR7ZPwsYlxRCku5odg==}
@ -3083,12 +3439,21 @@ packages:
get-func-name: 2.0.0
dev: true
/lru-cache@10.0.1:
resolution: {integrity: sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==}
engines: {node: 14 || >=16.14}
dev: false
/lru-cache@6.0.0:
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
engines: {node: '>=10'}
dependencies:
yallist: 4.0.0
/lru_map@0.3.3:
resolution: {integrity: sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==}
dev: false
/lucia@2.7.1:
resolution: {integrity: sha512-EHDTajS1YWA7Q37jd29Far1l4nfZgsWLp4hDQeaQhVpJd2WKQqA3626kJYmOj1CTweVMkE54xFi5JIph+agZkQ==}
dev: false
@ -3106,7 +3471,6 @@ packages:
engines: {node: '>=12'}
dependencies:
'@jridgewell/sourcemap-codec': 1.4.15
dev: true
/magic-string@0.30.0:
resolution: {integrity: sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==}
@ -3114,6 +3478,14 @@ packages:
dependencies:
'@jridgewell/sourcemap-codec': 1.4.15
/magicast@0.2.8:
resolution: {integrity: sha512-zEnqeb3E6TfMKYXGyHv3utbuHNixr04o3/gVGviSzVQkbFiU46VZUd+Ea/1npKfvEsEWxBYuIksKzoztTDPg0A==}
dependencies:
'@babel/parser': 7.23.0
'@babel/types': 7.23.0
recast: 0.23.4
dev: false
/make-dir@3.1.0:
resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}
engines: {node: '>=8'}
@ -3169,9 +3541,15 @@ packages:
dependencies:
brace-expansion: 1.1.11
/minimatch@7.4.6:
resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==}
engines: {node: '>=10'}
dependencies:
brace-expansion: 2.0.1
dev: false
/minimist@1.2.7:
resolution: {integrity: sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==}
dev: true
/minipass@3.3.6:
resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==}
@ -3185,6 +3563,16 @@ packages:
dependencies:
yallist: 4.0.0
/minipass@4.2.8:
resolution: {integrity: sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==}
engines: {node: '>=8'}
dev: false
/minipass@7.0.4:
resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==}
engines: {node: '>=16 || 14 >=14.17'}
dev: false
/minizlib@2.1.2:
resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==}
engines: {node: '>= 8'}
@ -3197,7 +3585,6 @@ packages:
hasBin: true
dependencies:
minimist: 1.2.7
dev: true
/mkdirp@1.0.4:
resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
@ -3291,6 +3678,29 @@ packages:
resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
engines: {node: '>= 6'}
/object-is@1.1.5:
resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==}
engines: {node: '>= 0.4'}
dependencies:
call-bind: 1.0.2
define-properties: 1.2.1
dev: false
/object-keys@1.1.1:
resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
engines: {node: '>= 0.4'}
dev: false
/object.assign@4.1.4:
resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==}
engines: {node: '>= 0.4'}
dependencies:
call-bind: 1.0.2
define-properties: 1.2.1
has-symbols: 1.0.3
object-keys: 1.1.1
dev: false
/once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
dependencies:
@ -3317,14 +3727,12 @@ packages:
engines: {node: '>=10'}
dependencies:
yocto-queue: 0.1.0
dev: true
/p-locate@5.0.0:
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
engines: {node: '>=10'}
dependencies:
p-limit: 3.1.0
dev: true
/pako@0.2.9:
resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==}
@ -3345,7 +3753,6 @@ packages:
/path-exists@4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
dev: true
/path-is-absolute@1.0.1:
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
@ -3359,6 +3766,14 @@ packages:
/path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
/path-scurry@1.10.1:
resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==}
engines: {node: '>=16 || 14 >=14.17'}
dependencies:
lru-cache: 10.0.1
minipass: 7.0.4
dev: false
/path-type@4.0.0:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'}
@ -3855,6 +4270,11 @@ packages:
dependencies:
'@prisma/engines': 5.4.2
/progress@2.0.3:
resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==}
engines: {node: '>=0.4.0'}
dev: false
/proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
dev: false
@ -3897,6 +4317,17 @@ packages:
dependencies:
picomatch: 2.3.1
/recast@0.23.4:
resolution: {integrity: sha512-qtEDqIZGVcSZCHniWwZWbRy79Dc6Wp3kT/UmDA2RJKBPg7+7k51aQBZirHmUGn5uvHf2rg8DkjizrN26k61ATw==}
engines: {node: '>= 4'}
dependencies:
assert: 2.1.0
ast-types: 0.16.1
esprima: 4.0.1
source-map: 0.6.1
tslib: 2.6.1
dev: false
/reflect-metadata@0.1.13:
resolution: {integrity: sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==}
dev: false
@ -3939,7 +4370,6 @@ packages:
hasBin: true
dependencies:
glob: 7.2.3
dev: true
/rimraf@3.0.2:
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
@ -3980,7 +4410,6 @@ packages:
graceful-fs: 4.2.10
mkdirp: 0.5.6
rimraf: 2.7.1
dev: true
/sass@1.65.1:
resolution: {integrity: sha512-9DINwtHmA41SEd36eVPQ9BJKpn7eKDQmUHmpI0y5Zv2Rcorrh0zS+cFrt050hdNbmmCNKTW3hV5mWfuegNRsEA==}
@ -4098,7 +4527,6 @@ packages:
buffer-crc32: 0.2.13
minimist: 1.2.7
sander: 0.5.1
dev: true
/source-map-js@1.0.2:
resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
@ -4107,7 +4535,6 @@ packages:
/source-map@0.6.1:
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
engines: {node: '>=0.10.0'}
dev: true
/streamsearch@1.1.0:
resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
@ -4466,6 +4893,11 @@ packages:
engines: {node: '>=14.0.0'}
dev: true
/to-fast-properties@2.0.0:
resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
engines: {node: '>=4'}
dev: false
/to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
@ -4529,7 +4961,6 @@ packages:
/tslib@2.6.1:
resolution: {integrity: sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==}
dev: true
/tsutils@3.21.0(typescript@5.1.6):
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
@ -4589,6 +5020,15 @@ packages:
'@types/unist': 3.0.0
dev: false
/unplugin@1.0.1:
resolution: {integrity: sha512-aqrHaVBWW1JVKBHmGo33T5TxeL0qWzfvjWokObHA9bYmN7eNDkwOxmLjhioHl9878qDFMAaT51XNroRyuz7WxA==}
dependencies:
acorn: 8.10.0
chokidar: 3.5.3
webpack-sources: 3.2.3
webpack-virtual-modules: 0.5.0
dev: false
/update-browserslist-db@1.0.11(browserslist@4.21.10):
resolution: {integrity: sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==}
hasBin: true
@ -4620,6 +5060,16 @@ packages:
/util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
/util@0.12.5:
resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==}
dependencies:
inherits: 2.0.4
is-arguments: 1.1.1
is-generator-function: 1.0.10
is-typed-array: 1.1.12
which-typed-array: 1.1.11
dev: false
/v8-compile-cache-lib@3.0.1:
resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
@ -4726,19 +5176,38 @@ packages:
/webidl-conversions@3.0.1:
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
/webpack-sources@3.2.3:
resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==}
engines: {node: '>=10.13.0'}
dev: false
/webpack-virtual-modules@0.5.0:
resolution: {integrity: sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==}
dev: false
/whatwg-url@5.0.0:
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
dependencies:
tr46: 0.0.3
webidl-conversions: 3.0.1
/which-typed-array@1.1.11:
resolution: {integrity: sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==}
engines: {node: '>= 0.4'}
dependencies:
available-typed-arrays: 1.0.5
call-bind: 1.0.2
for-each: 0.3.3
gopd: 1.0.1
has-tostringtag: 1.0.0
dev: false
/which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
hasBin: true
dependencies:
isexe: 2.0.0
dev: true
/wide-align@1.1.5:
resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==}
@ -4776,7 +5245,6 @@ packages:
/yocto-queue@0.1.0:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
dev: true
/yoga-wasm-web@0.3.3:
resolution: {integrity: sha512-N+d4UJSJbt/R3wqY7Coqs5pcV0aUj2j9IaQ3rNj9bVCLld8tTGKRa2USARjnvZJWVx1NDmQev8EknoczaOQDOA==}

View file

@ -175,7 +175,8 @@ model Game {
publishers Publisher[]
artists Artist[]
names GameName[]
expansions Expansion[]
expansions Expansion[] @relation("BaseToExpansion")
expansion_of Expansion[] @relation("ExpansionToBase")
collection_items CollectionItem[]
wishlist_items WishlistItem[]
list_items ListItem[]
@ -269,8 +270,9 @@ model Artist {
model Expansion {
id String @id @default(cuid())
base_game Game @relation(fields: [base_game_id], references: [id])
base_game Game @relation(name: "BaseToExpansion", fields: [base_game_id], references: [id])
base_game_id String
game Game @relation(name: "ExpansionToBase", fields: [game_id], references: [id])
game_id String
created_at DateTime @default(now()) @db.Timestamp(6)
updated_at DateTime @updatedAt @db.Timestamp(6)

4
src/app.d.ts vendored
View file

@ -22,6 +22,10 @@ declare global {
errorStackTrace: string;
message: unknown;
track: unknown;
session: {
ip: string,
country: string
}
}
interface Error {
code?: string;

23
src/hooks.client.ts Normal file
View file

@ -0,0 +1,23 @@
import { dev } from '$app/environment';
import { handleErrorWithSentry, Replay } from '@sentry/sveltekit';
import * as Sentry from '@sentry/sveltekit';
Sentry.init({
dsn: 'https://742e43279df93a3c4a4a78c12eb1f879@o4506057768632320.ingest.sentry.io/4506057770401792',
tracesSampleRate: 1.0,
// This sets the sample rate to be 10%. You may want this to be 100% while
// in development and sample at a lower rate in production
replaysSessionSampleRate: 0.1,
// If the entire session is not sampled, use the below sample rate to sample
// sessions when an error occurs.
replaysOnErrorSampleRate: 1.0,
// If you don't want to use Session Replay, just remove the line below:
integrations: [new Replay()],
environment: dev ? 'development' : 'production'
});
// If you have a custom error handler, pass it to `handleErrorWithSentry`
export const handleError = handleErrorWithSentry();

View file

@ -1,34 +1,19 @@
import * as Sentry from '@sentry/sveltekit';
import { sequence } from '@sveltejs/kit/hooks';
import { type HandleServerError, type Handle } from '@sveltejs/kit';
import { dev } from '$app/environment';
import { PrismaClient } from '@prisma/client';
import type { Handle } from '@sveltejs/kit';
import { auth } from '$lib/server/lucia';
import log from '$lib/server/log';
import { dev } from '$app/environment';
export const handleError: HandleServerError = async ({ error, event }) => {
const errorId = crypto.randomUUID();
Sentry.init({
dsn: 'https://742e43279df93a3c4a4a78c12eb1f879@o4506057768632320.ingest.sentry.io/4506057770401792',
tracesSampleRate: 1,
environment: dev ? 'development' : 'production'
});
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
event.locals.error = error?.toString() || undefined;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
event.locals.errorStackTrace = error?.stack || undefined;
event.locals.errorId = errorId;
if (!dev) {
log(500, event);
}
return {
message: 'An unexpected error occurred.',
errorId
};
};
// export const prismaClient: Handle = async function ({ event, resolve }) {
// event.locals.prisma = prisma;
// const response = await resolve(event);
// return response;
// };
// * START UP
// RUNS ONCE ON FILE LOAD
export const prisma_client = new PrismaClient();
export const authentication: Handle = async function ({ event, resolve }) {
const startTimer = Date.now();
@ -52,8 +37,22 @@ export const authentication: Handle = async function ({ event, resolve }) {
console.log('auth empty');
}
return await resolve(event);
};
// This hook is used to pass our prisma instance to each action, load, and endpoint
export const prisma: Handle = async function ({ event, resolve }) {
const ip = event.request.headers.get('x-forwarded-for') as string;
const country = event.request.headers.get('x-vercel-ip-country') as string;
event.locals.prisma = prisma_client;
event.locals.session = {
...event.locals.session,
ip,
country
};
const response = await resolve(event);
return response;
};
export const handle = sequence(authentication);
export const handle = sequence(sequence(Sentry.sentryHandle(), authentication, prisma));
export const handleError = Sentry.handleErrorWithSentry();

View file

@ -85,20 +85,20 @@
<div class="search">
<fieldset class="text-search" aria-busy={submitting} disabled={submitting}>
<Label for="label">Search</Label>
<Input type="text" id="q" class={$errors.q && "outline outline-destructive"} name="search" placeholder="Search board games" data-invalid={$errors.q} bind:value={$form.q} />
<Input type="text" id="q" class={$errors.q && "outline outline-destructive"} name="q" placeholder="Search board games" data-invalid={$errors.q} bind:value={$form.q} />
{#if $errors.q}
<p class="text-sm text-destructive">{$errors.q}</p>
{/if}
<input id="skip" type="hidden" name="skip" bind:value={$form.skip} />
<input id="limit" type="hidden" name="limit" bind:value={$form.limit} />
</fieldset>
{#if advancedSearch}
<!-- {#if advancedSearch} -->
<!-- <Disclosure> -->
<!-- <DisclosureButton
class="disclosure-button"
on:click={() => (disclosureOpen = !disclosureOpen)}
> -->
<span>Advanced Search?</span>
<!-- <span>Advanced Search?</span> -->
<!-- <ChevronRightIcon
class="icon disclosure-icon"
style={disclosureOpen
@ -107,19 +107,19 @@
/> -->
<!-- </DisclosureButton> -->
{#if disclosureOpen}
<div transition:fade|global>
<!-- {#if disclosureOpen}
<div transition:fade|global> -->
<!-- Using `static`, `DisclosurePanel` is always rendered,
and ignores the `open` state -->
<!-- <DisclosurePanel static> -->
{#if disclosureOpen}
<!-- {#if disclosureOpen}
<AdvancedSearch {form} {errors} {constraints} />
{/if}
{/if} -->
<!-- </DisclosurePanel> -->
</div>
{/if}
<!-- </div> -->
<!-- {/if} -->
<!-- </Disclosure> -->
{/if}
<!-- {/if} -->
</div>
{#if showButton}
<Button type="submit">Submit</Button>

View file

@ -1,5 +0,0 @@
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
export default prisma;

View file

@ -1,4 +0,0 @@
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
export default prisma;

View file

@ -1,70 +0,0 @@
import { Client } from '@axiomhq/axiom-node';
import { AXIOM_TOKEN, AXIOM_ORG_ID, AXIOM_DATASET } from '$env/static/private';
import getAllUrlParams from '$lib/utils/getAllUrlParams';
import parseTrack from '$lib/utils/parseTrack';
import parseMessage from '$lib/utils/parseMessage';
import { DOMAIN } from '$lib/config/constants';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
export default async function log(statusCode: number, event) {
try {
let level = 'info';
if (statusCode >= 400) {
level = 'error';
}
const error = event?.locals?.error || undefined;
const errorId = event?.locals?.errorId || undefined;
const errorStackTrace = event?.locals?.errorStackTrace || undefined;
let urlParams = {};
if (event?.url?.search) {
urlParams = await getAllUrlParams(event?.url?.search);
}
let messageEvents = {};
if (event?.locals?.message) {
messageEvents = await parseMessage(event?.locals?.message);
}
let trackEvents = {};
if (event?.locals?.track) {
trackEvents = await parseTrack(event?.locals?.track);
}
let referer = event.request.headers.get('referer');
if (referer) {
const refererUrl = await new URL(referer);
const refererHostname = refererUrl.hostname;
if (refererHostname === 'localhost' || refererHostname === DOMAIN) {
referer = refererUrl.pathname;
}
} else {
referer = undefined;
}
const logData: object = {
level: level,
method: event.request.method,
path: event.url.pathname,
status: statusCode,
timeInMs: Date.now() - event?.locals?.startTimer,
user: event?.locals?.user?.email,
userId: event?.locals?.user?.userId,
referer: referer,
error: error,
errorId: errorId,
errorStackTrace: errorStackTrace,
...urlParams,
...messageEvents,
...trackEvents
};
console.log('log: ', JSON.stringify(logData));
if (!AXIOM_TOKEN || !AXIOM_ORG_ID || !AXIOM_DATASET) {
return;
}
const client = new Client({
token: AXIOM_TOKEN,
orgId: AXIOM_ORG_ID
});
await client.ingestEvents(AXIOM_DATASET, [logData]);
} catch (err) {
throw new Error(`Error Logger: ${JSON.stringify(err)}`);
}
}

View file

@ -2,15 +2,13 @@
import { lucia } from 'lucia';
import { sveltekit } from 'lucia/middleware';
import { prisma } from '@lucia-auth/adapter-prisma';
import { PrismaClient } from '@prisma/client';
import { dev } from '$app/environment';
const client = new PrismaClient();
import { PrismaClient } from '@prisma/client';
export const auth = lucia({
adapter: prisma(client),
env: dev ? 'DEV' : 'PROD',
middleware: sveltekit(),
adapter: prisma(new PrismaClient()),
getUserAttributes: (databaseUser) => {
return {
username: databaseUser.username,

View file

@ -1,22 +1,7 @@
import { Prisma } from '@prisma/client';
import type { SvelteComponent } from 'svelte';
export type Message = { status: 'error' | 'success' | 'warning' | 'info'; text: string };
export const gameInclude = Prisma.validator<Prisma.CollectionItemInclude>()({
game: {
select: {
id: true,
name: true,
thumb_url: true
}
}
});
export type CollectionItemWithGame = Prisma.CollectionItemGetPayload<{
include: typeof gameInclude;
}>;
export type Dialog = {
isOpen: boolean;
content?: typeof SvelteComponent<any>;

View file

@ -1,13 +1,11 @@
import type { Game } from '@prisma/client';
import kebabCase from 'just-kebab-case';
import type { BggLinkDto } from 'boardgamegeekclient/dist/esm/dto/concrete/subdto';
import prisma from '$lib/prisma';
import type { GameType } from '$lib/types';
import { mapAPIGameToBoredGame } from './gameMapper';
export async function createArtist(externalArtist: BggLinkDto) {
export async function createArtist(locals: App.Locals, externalArtist: BggLinkDto) {
try {
let dbArtist = await prisma.artist.findFirst({
let dbArtist = await locals.prisma.artist.findFirst({
where: {
external_id: externalArtist.id
},
@ -19,10 +17,11 @@ export async function createArtist(externalArtist: BggLinkDto) {
}
});
if (dbArtist) {
console.log('Artist already exists', dbArtist.name);
return dbArtist;
}
console.log('Creating artist', JSON.stringify(externalArtist, null, 2));
let artist = await prisma.artist.create({
let artist = await locals.prisma.artist.create({
data: {
name: externalArtist.value,
external_id: externalArtist.id,
@ -44,9 +43,9 @@ export async function createArtist(externalArtist: BggLinkDto) {
}
}
export async function createDesigner(externalDesigner: BggLinkDto) {
export async function createDesigner(locals: App.Locals, externalDesigner: BggLinkDto) {
try {
let dbDesigner = await prisma.designer.findFirst({
let dbDesigner = await locals.prisma.designer.findFirst({
where: {
external_id: externalDesigner.id
},
@ -58,10 +57,11 @@ export async function createDesigner(externalDesigner: BggLinkDto) {
}
});
if (dbDesigner) {
console.log('Designer already exists', dbDesigner.name);
return dbDesigner;
}
console.log('Creating designer', JSON.stringify(externalDesigner, null, 2));
let designer = await prisma.designer.create({
let designer = await locals.prisma.designer.create({
data: {
name: externalDesigner.value,
external_id: externalDesigner.id,
@ -83,9 +83,9 @@ export async function createDesigner(externalDesigner: BggLinkDto) {
}
}
export async function createPublisher(externalPublisher: BggLinkDto) {
export async function createPublisher(locals: App.Locals, externalPublisher: BggLinkDto) {
try {
let dbPublisher = await prisma.publisher.findFirst({
let dbPublisher = await locals.prisma.publisher.findFirst({
where: {
external_id: externalPublisher.id
},
@ -97,10 +97,11 @@ export async function createPublisher(externalPublisher: BggLinkDto) {
}
});
if (dbPublisher) {
console.log('Publisher already exists', dbPublisher.name);
return dbPublisher;
}
console.log('Creating publisher', JSON.stringify(externalPublisher, null, 2));
let publisher = await prisma.publisher.create({
let publisher = await locals.prisma.publisher.create({
data: {
name: externalPublisher.value,
external_id: externalPublisher.id,
@ -122,9 +123,9 @@ export async function createPublisher(externalPublisher: BggLinkDto) {
}
}
export async function createCategory(externalCategory: BggLinkDto) {
export async function createCategory(locals: App.Locals, externalCategory: BggLinkDto) {
try {
let dbCategory = await prisma.category.findFirst({
let dbCategory = await locals.prisma.category.findFirst({
where: {
external_id: externalCategory.id
},
@ -136,10 +137,11 @@ export async function createCategory(externalCategory: BggLinkDto) {
}
});
if (dbCategory) {
console.log('Category already exists', dbCategory.name);
return dbCategory;
}
console.log('Creating category', JSON.stringify(externalCategory, null, 2));
let category = await prisma.category.create({
let category = await locals.prisma.category.create({
data: {
name: externalCategory.value,
external_id: externalCategory.id,
@ -162,9 +164,9 @@ export async function createCategory(externalCategory: BggLinkDto) {
}
}
export async function createMechanic(externalMechanic: BggLinkDto) {
export async function createMechanic(locals: App.Locals, externalMechanic: BggLinkDto) {
try {
let dbMechanic = await prisma.mechanic.findFirst({
let dbMechanic = await locals.prisma.mechanic.findFirst({
where: {
external_id: externalMechanic.id
},
@ -176,10 +178,11 @@ export async function createMechanic(externalMechanic: BggLinkDto) {
}
});
if (dbMechanic) {
console.log('Mechanic already exists', dbMechanic.name);
return dbMechanic;
}
console.log('Creating mechanic', JSON.stringify(externalMechanic, null, 2));
let mechanic = await prisma.mechanic.upsert({
let mechanic = await locals.prisma.mechanic.upsert({
where: {
external_id: externalMechanic.id
},
@ -204,13 +207,14 @@ export async function createMechanic(externalMechanic: BggLinkDto) {
}
export async function createExpansion(
locals: App.Locals,
game: Game,
externalExpansion: BggLinkDto,
gameIsExpansion: boolean,
eventFetch: Function
) {
try {
let dbExpansionGame = await prisma.game.findUnique({
let dbExpansionGame = await locals.prisma.game.findUnique({
where: {
external_id: externalExpansion.id
}
@ -224,7 +228,7 @@ export async function createExpansion(
const externalGame = await externalGameResponse.json();
console.log('externalGame', externalGame);
let boredGame = mapAPIGameToBoredGame(externalGame);
dbExpansionGame = await createOrUpdateGameMinimal(boredGame);
dbExpansionGame = await createOrUpdateGameMinimal(locals, boredGame);
} else {
throw new Error(
`${gameIsExpansion ? 'Base game' : 'Expansion game'} not found and failed to create.`
@ -240,7 +244,7 @@ export async function createExpansion(
'External expansion is expansion. Looking for base game',
JSON.stringify(game, null, 2)
);
dbExpansion = await prisma.expansion.findFirst({
dbExpansion = await locals.prisma.expansion.findFirst({
where: {
game_id: dbExpansionGame.id
},
@ -257,7 +261,7 @@ export async function createExpansion(
'External Expansion is base game. Looking for expansion',
JSON.stringify(game, null, 2)
);
dbExpansion = await prisma.expansion.findFirst({
dbExpansion = await locals.prisma.expansion.findFirst({
where: {
base_game_id: dbExpansionGame.id
},
@ -277,7 +281,7 @@ export async function createExpansion(
}
console.log(`Creating expansion. baseGameId: ${baseGameId}, gameId: ${gameId}`);
let expansion = await prisma.expansion.create({
let expansion = await locals.prisma.expansion.create({
data: {
base_game_id: baseGameId,
game_id: gameId
@ -286,6 +290,36 @@ export async function createExpansion(
console.log('Created expansion', JSON.stringify(expansion, null, 2));
if (gameIsExpansion) {
console.log('Connecting current game to expansion');
await locals.prisma.game.update({
where: {
id: gameId
},
data: {
expansions: {
connect: {
id: expansion.id
}
}
}
});
} else {
console.log('Connecting current game to base game');
await locals.prisma.game.update({
where: {
external_id: baseGameId
},
data: {
expansions: {
connect: {
id: expansion.id
}
}
}
});
}
return expansion;
} catch (e) {
console.error(e);
@ -293,10 +327,10 @@ export async function createExpansion(
}
}
export async function createOrUpdateGameMinimal(game: GameType) {
export async function createOrUpdateGameMinimal(locals: App.Locals, game: Game) {
console.log('Creating or updating minimal game data', JSON.stringify(game, null, 2));
const externalUrl = `https://boardgamegeek.com/boardgame/${game.external_id}`;
return await prisma.game.upsert({
return await locals.prisma.game.upsert({
where: {
external_id: game.external_id
},
@ -333,18 +367,18 @@ export async function createOrUpdateGameMinimal(game: GameType) {
});
}
export async function createOrUpdateGame(game: GameType) {
export async function createOrUpdateGame(locals: App.Locals, game: Game) {
console.log('Creating or updating game', JSON.stringify(game, null, 2));
const categoryIds = game.categories;
const mechanicIds = game.mechanics;
const publisherIds = game.publishers;
const designerIds = game.designers;
const artistIds = game.artists;
const expansionIds = game.expansions;
// const expansionIds = game.expansions;
const externalUrl = `https://boardgamegeek.com/boardgame/${game.external_id}`;
console.log('categoryIds', categoryIds);
console.log('mechanicIds', mechanicIds);
return await prisma.game.upsert({
return await locals.prisma.game.upsert({
include: {
mechanics: true,
publishers: true,
@ -384,9 +418,6 @@ export async function createOrUpdateGame(game: GameType) {
},
artists: {
connect: artistIds
},
expansions: {
connect: expansionIds
}
},
update: {
@ -418,9 +449,6 @@ export async function createOrUpdateGame(game: GameType) {
},
artists: {
connect: artistIds
},
expansions: {
connect: expansionIds
}
}
});

View file

@ -1,4 +1,5 @@
import type { GameType, SavedGameType } from '$lib/types';
import type { Game } from '@prisma/client';
import kebabCase from 'just-kebab-case';
export function convertToSavedGame(game: GameType | SavedGameType): SavedGameType {
@ -42,7 +43,7 @@ export function mapSavedGameToGame(game: SavedGameType): GameType {
};
}
export function mapAPIGameToBoredGame(game: GameType): GameType {
export function mapAPIGameToBoredGame(game: GameType): Game {
// TODO: Fix types
return {
external_id: game.external_id,

View file

@ -1,9 +1,7 @@
import { error, fail, redirect } from '@sveltejs/kit';
import { setError, superValidate } from 'sveltekit-superforms/server';
import { superValidate } from 'sveltekit-superforms/server';
import type { PageServerLoad } from '../../$types.js';
import prisma from '$lib/prisma';
import { modifyListGameSchema, type ListGame } from '$lib/config/zod-schemas.js';
import type { CollectionItemWithGame } from '$lib/types.js';
import { search_schema } from '$lib/zodValidation.js';
export const load: PageServerLoad = async ({ fetch, url, locals }) => {
@ -29,7 +27,7 @@ export const load: PageServerLoad = async ({ fetch, url, locals }) => {
const listManageForm = await superValidate(modifyListGameSchema);
try {
let collection = await prisma.collection.findUnique({
let collection = await locals.prisma.collection.findUnique({
where: {
user_id: session.user.userId
}
@ -39,14 +37,14 @@ export const load: PageServerLoad = async ({ fetch, url, locals }) => {
if (!collection) {
console.log('Collection was not found');
return fail(404, {});
// collection = await prisma.collection.create({
// collection = await locals.prisma.collection.create({
// data: {
// user_id: session.userId
// }
// });
}
let collection_items: CollectionItemWithGame[] = await prisma.collectionItem.findMany({
let collection_items = await locals.prisma.collectionItem.findMany({
where: {
collection_id: collection.id
},
@ -110,14 +108,14 @@ export const actions = {
throw redirect(302, '/login');
}
let game = await prisma.game.findUnique({
let game = await locals.prisma.game.findUnique({
where: {
id: form.data.id
}
});
if (!game) {
// game = await prisma.game.create({
// game = await locals.prisma.game.create({
// data: {
// name: form.name
// }
@ -127,7 +125,7 @@ export const actions = {
}
if (game) {
const collection = await prisma.collection.findUnique({
const collection = await locals.prisma.collection.findUnique({
where: {
user_id: session.user.userId
}
@ -138,7 +136,7 @@ export const actions = {
return error(404, 'Wishlist not found');
}
await prisma.collectionItem.create({
await locals.prisma.collectionItem.create({
data: {
game_id: game.id,
collection_id: collection.id,
@ -182,14 +180,14 @@ export const actions = {
throw redirect(302, '/login');
}
let game = await prisma.game.findUnique({
let game = await locals.prisma.game.findUnique({
where: {
id: form.data.id
}
});
if (!game) {
// game = await prisma.game.create({
// game = await locals.prisma.game.create({
// data: {
// name: form.name
// }
@ -199,7 +197,7 @@ export const actions = {
}
if (game) {
const collection = await prisma.collection.findUnique({
const collection = await locals.prisma.collection.findUnique({
where: {
user_id: session.user.userId
}
@ -210,7 +208,7 @@ export const actions = {
return error(404, 'Wishlist not found');
}
await prisma.collectionItem.delete({
await locals.prisma.collectionItem.delete({
where: {
collection_id: collection.id,
game_id: game.id

View file

@ -1,21 +1,20 @@
import prisma from '$lib/prisma';
import { redirect } from '@sveltejs/kit';
export async function load({ params, locals }) {
export async function load({ locals }) {
const session = await locals.auth.validate();
if (!session) {
throw redirect(302, '/login');
}
try {
let wishlists = await prisma.wishlist.findMany({
let wishlists = await locals.prisma.wishlist.findMany({
where: {
user_id: session.userId
}
});
if (wishlists.length === 0) {
const wishlist = await prisma.wishlist.create({
const wishlist = await locals.prisma.wishlist.create({
data: {
user_id: session.userId
}

View file

@ -1,7 +1,5 @@
import { fail, redirect } from '@sveltejs/kit';
import { superValidate } from 'sveltekit-superforms/server';
import prisma from '$lib/prisma';
import { list_game_request_schema } from '$lib/zodValidation';
export async function load({ params, locals }) {
const session = await locals.auth.validate();
@ -10,7 +8,7 @@ export async function load({ params, locals }) {
}
try {
let wishlist = await prisma.wishlist.findUnique({
let wishlist = await locals.prisma.wishlist.findUnique({
where: {
id: params.id,
AND: {
@ -52,14 +50,14 @@ export const actions = {
throw redirect(302, '/login');
}
let game = await prisma.game.findUnique({
let game = await locals.prisma.game.findUnique({
where: {
id: form.id
}
});
if (!game) {
// game = await prisma.game.create({
// game = await locals.prisma.game.create({
// data: {
// name: form.name
// }
@ -69,7 +67,7 @@ export const actions = {
});
}
const wishlist = await prisma.wishlist.findUnique({
const wishlist = await locals.prisma.wishlist.findUnique({
where: {
id: params.id
}
@ -85,7 +83,7 @@ export const actions = {
throw redirect(302, '/404');
}
const wishlistItem = await prisma.wishlistItem.create({
const wishlistItem = await locals.prisma.wishlistItem.create({
data: {
game_id: game.id,
wishlist_id: wishlist.id

View file

@ -61,7 +61,7 @@ export const actions = {
if (user.email !== form.data.email) {
// auth.update
// await prisma.key.update({
// await locals.prisma.key.update({
// where: {
// id: 'emailpassword:' + user.email
// },

View file

@ -1,6 +1,5 @@
import { error, redirect } from '@sveltejs/kit';
import { superValidate } from 'sveltekit-superforms/server';
import prisma from '$lib/prisma';
import { modifyListGameSchema } from '$lib/config/zod-schemas.js';
export async function load({ params, locals }) {
@ -12,7 +11,7 @@ export async function load({ params, locals }) {
console.log('Wishlist load User id', session.user);
try {
let wishlist = await prisma.wishlist.findUnique({
let wishlist = await locals.prisma.wishlist.findUnique({
where: {
user_id: session?.user?.userId
},
@ -58,14 +57,14 @@ export const actions = {
throw redirect(302, '/login');
}
let game = await prisma.game.findUnique({
let game = await locals.prisma.game.findUnique({
where: {
id: form.data.id
}
});
if (!game) {
// game = await prisma.game.create({
// game = await locals.prisma.game.create({
// data: {
// name: form.name
// }
@ -75,7 +74,7 @@ export const actions = {
}
if (game) {
const wishlist = await prisma.wishlist.findUnique({
const wishlist = await locals.prisma.wishlist.findUnique({
where: {
user_id: session.user.userId
}
@ -86,7 +85,7 @@ export const actions = {
return error(404, 'Wishlist not found');
}
await prisma.wishlistItem.create({
await locals.prisma.wishlistItem.create({
data: {
game_id: game.id,
wishlist_id: wishlist.id
@ -129,14 +128,14 @@ export const actions = {
throw redirect(302, '/login');
}
let game = await prisma.game.findUnique({
let game = await locals.prisma.game.findUnique({
where: {
id: form.data.id
}
});
if (!game) {
// game = await prisma.game.create({
// game = await locals.prisma.game.create({
// data: {
// name: form.name
// }
@ -146,7 +145,7 @@ export const actions = {
}
if (game) {
const wishlist = await prisma.wishlist.findUnique({
const wishlist = await locals.prisma.wishlist.findUnique({
where: {
user_id: session.user.userId
}
@ -157,7 +156,7 @@ export const actions = {
return error(404, 'Wishlist not found');
}
await prisma.wishlistItem.delete({
await locals.prisma.wishlistItem.delete({
where: {
wishlist_id: wishlist.id,
game_id: game.id

View file

@ -1,5 +1,4 @@
import { error } from '@sveltejs/kit';
import prisma from '$lib/prisma';
import {
createArtist,
createCategory,
@ -12,11 +11,11 @@ import {
import { mapAPIGameToBoredGame } from '$lib/utils/gameMapper.js';
import type { Game } from '@prisma/client';
export const load = async ({ params, setHeaders, locals, fetch }) => {
export const load = async ({ params, locals, fetch }) => {
try {
const { user } = locals;
const { id } = params;
const game = await prisma.game.findUnique({
const game = await locals.prisma.game.findUnique({
where: {
id
},
@ -28,7 +27,22 @@ export const load = async ({ params, setHeaders, locals, fetch }) => {
categories: true,
expansions: {
include: {
base_game: true
game: {
select: {
id: true,
name: true
}
}
}
},
expansion_of: {
include: {
base_game: {
select: {
id: true,
name: true
}
}
}
}
}
@ -44,13 +58,13 @@ export const load = async ({ params, setHeaders, locals, fetch }) => {
game.last_sync_at === null ||
currentDate.getDate() - game.last_sync_at.getDate() > 7 * 24 * 60 * 60 * 1000
) {
await syncGameAndConnectedData(game, fetch);
await syncGameAndConnectedData(locals, game, fetch);
}
let wishlist;
let collection;
if (user) {
wishlist = await prisma.wishlist.findUnique({
wishlist = await locals.prisma.wishlist.findUnique({
where: {
user_id: user.userId
},
@ -63,7 +77,7 @@ export const load = async ({ params, setHeaders, locals, fetch }) => {
}
});
collection = await prisma.collection.findUnique({
collection = await locals.prisma.collection.findUnique({
where: {
user_id: user.userId
},
@ -94,7 +108,7 @@ export const load = async ({ params, setHeaders, locals, fetch }) => {
throw error(404, 'not found');
};
async function syncGameAndConnectedData(game: Game, eventFetch: Function) {
async function syncGameAndConnectedData(locals: App.Locals, game: Game, eventFetch: Function) {
console.log(
`Retrieving full external game details for external id: ${game.external_id} with name ${game.name}`
);
@ -107,50 +121,35 @@ async function syncGameAndConnectedData(game: Game, eventFetch: Function) {
let artists = [];
let designers = [];
let publishers = [];
let expansions = [];
for (const externalCategory of externalGame.categories) {
const category = await createCategory(externalCategory);
const category = await createCategory(locals, externalCategory);
categories.push({
id: category.id
});
}
for (const externalMechanic of externalGame.mechanics) {
const mechanic = await createMechanic(externalMechanic);
const mechanic = await createMechanic(locals, externalMechanic);
mechanics.push({ id: mechanic.id });
}
for (const externalArtist of externalGame.artists) {
const artist = await createArtist(externalArtist);
const artist = await createArtist(locals, externalArtist);
artists.push({ id: artist.id });
}
for (const externalDesigner of externalGame.designers) {
const designer = await createDesigner(externalDesigner);
const designer = await createDesigner(locals, externalDesigner);
designers.push({ id: designer.id });
}
for (const externalPublisher of externalGame.publishers) {
const publisher = await createPublisher(externalPublisher);
const publisher = await createPublisher(locals, externalPublisher);
publishers.push({ id: publisher.id });
}
for (const externalExpansion of externalGame.expansions) {
let expansion;
console.log('Inbound?', externalExpansion.inbound);
if (externalExpansion?.inbound === true) {
expansion = await createExpansion(game, externalExpansion, false, eventFetch);
await prisma.game.update({
where: {
external_id: externalExpansion.id
},
data: {
expansions: {
connect: {
id: expansion.id
}
}
}
})
createExpansion(locals, game, externalExpansion, false, eventFetch);
} else {
expansion = await createExpansion(game, externalExpansion, true, eventFetch);
expansions.push({ id: expansion.id });
createExpansion(locals, game, externalExpansion, true, eventFetch);
}
}
@ -161,7 +160,7 @@ async function syncGameAndConnectedData(game: Game, eventFetch: Function) {
boredGame.designers = designers;
boredGame.artists = artists;
boredGame.publishers = publishers;
boredGame.expansions = expansions;
return createOrUpdateGame(boredGame);
// boredGame.expansions = expansions;
return createOrUpdateGame(locals, boredGame);
}
}

View file

@ -79,12 +79,6 @@
<span>{mechanic.name}</span>
{/each}
</section>
<section>
<p>Expansions</p>
{#each game?.expansions as expansions}
<span>{expansions?.base_game?.name}</span>
{/each}
</section>
<section class="description" class:show={seeMore} class:hide={!seeMore} style="margin-top: 2rem;">
{@html game?.description}
</section>
@ -98,6 +92,30 @@
<MinusIcon width="24" height="24" />
{/if}
</button>
<section>
<p>Expansion Of</p>
<ul style="display: flex; flex-wrap: wrap; gap: 0.75rem;">
{#each game?.expansion_of as expansion}
<li>
<a href={`/game/${expansion?.base_game?.id}`}>
{expansion?.base_game?.name}
</a>
</li>
{/each}
</ul>
</section>
<section>
<p>Expansions</p>
<ul style="display: flex; flex-wrap: wrap; gap: 0.75rem;">
{#each game?.expansions as expansion}
<li>
<a href={`/game/${expansion?.game?.id}`}>
{expansion?.game?.name}
</a>
</li>
{/each}
</ul>
</section>
<style lang="scss">
h2 {

View file

@ -30,7 +30,11 @@ import {
* an array of all the games fetched. If any error occurred during the operation, it returns an object with totalCount as 0 and games as empty array.
* @throws will throw an error if the response received from fetching games operation is not OK (200).
*/
async function searchForGames(urlQueryParams: SearchQuery, eventFetch: Function) {
async function searchForGames(
locals: App.Locals,
eventFetch: Function,
urlQueryParams: SearchQuery
) {
try {
console.log('urlQueryParams search games', urlQueryParams);
@ -50,11 +54,7 @@ async function searchForGames(urlQueryParams: SearchQuery, eventFetch: Function)
throw error(response.status);
}
let games = [];
if (response.ok) {
games = await response.json();
}
let games = await response.json();
console.log('games from DB', games);
const gameNameSearch = urlQueryParams.get('q');
@ -95,7 +95,7 @@ async function searchForGames(urlQueryParams: SearchQuery, eventFetch: Function)
const externalGame = await externalGameResponse.json();
console.log('externalGame', externalGame);
let boredGame = mapAPIGameToBoredGame(externalGame);
games.push(createOrUpdateGameMinimal(boredGame));
games.push(createOrUpdateGameMinimal(locals, boredGame));
}
}
}
@ -115,7 +115,7 @@ async function searchForGames(urlQueryParams: SearchQuery, eventFetch: Function)
};
}
export const load: PageServerLoad = async ({ fetch, url }) => {
export const load: PageServerLoad = async ({ locals, fetch, url }) => {
const defaults = {
limit: 10,
skip: 0,
@ -179,7 +179,7 @@ export const load: PageServerLoad = async ({ fetch, url }) => {
}
const urlQueryParams = new URLSearchParams(newQueryParams);
const searchData = await searchForGames(urlQueryParams, fetch);
const searchData = await searchForGames(locals, fetch, urlQueryParams);
return {
form,
@ -201,7 +201,7 @@ export const load: PageServerLoad = async ({ fetch, url }) => {
};
export const actions = {
random: async ({ request }): Promise<any> => {
random: async ({ request, locals, fetch }): Promise<any> => {
const form = await superValidate(request, search_schema);
const queryParams: SearchQuery = {
order_by: 'rank',
@ -220,7 +220,7 @@ export const actions = {
return {
form,
searchData: await searchForGames(urlQueryParams)
searchData: await searchForGames(locals, fetch, urlQueryParams)
};
}
};

View file

@ -2,7 +2,6 @@ import { fail } from '@sveltejs/kit';
import { setError, superValidate } from 'sveltekit-superforms/server';
import { redirect } from 'sveltekit-flash-message/server';
import { auth } from '$lib/server/lucia';
import prisma from '$lib/prisma';
import { userSchema } from '$lib/config/zod-schemas';
const signInSchema = userSchema.pick({
@ -25,6 +24,7 @@ export const load = async (event) => {
export const actions = {
default: async (event) => {
const { locals } = event;
const form = await superValidate(event, signInSchema);
if (!form.valid) {
@ -42,7 +42,7 @@ export const actions = {
});
event.locals.auth.setSession(session);
const user = await prisma.user.findUnique({
const user = await locals.prisma.user.findUnique({
where: {
id: session.user.userId
},
@ -55,7 +55,7 @@ export const actions = {
}
});
if (user) {
await prisma.collection.upsert({
await locals.prisma.collection.upsert({
where: {
user_id: user.id
},
@ -66,7 +66,7 @@ export const actions = {
user_id: user.id
}
});
await prisma.wishlist.upsert({
await locals.prisma.wishlist.upsert({
where: {
user_id: user.id
},

View file

@ -1,12 +1,9 @@
import { fail, redirect, error } from '@sveltejs/kit';
import { setError, superValidate } from 'sveltekit-superforms/server';
import { redirect as flashRedirect } from 'sveltekit-flash-message/server';
import { superValidate } from 'sveltekit-superforms/server';
import { LuciaError } from 'lucia';
import { auth } from '$lib/server/lucia';
import { userSchema } from '$lib/config/zod-schemas';
import { add_user_to_role } from '$server/roles';
import prisma from '$lib/prisma';
import { Schema } from 'zod';
import type { Message } from '$lib/types.js';
const signUpSchema = userSchema
@ -81,12 +78,12 @@ export const actions = {
});
console.log('signup user', user);
add_user_to_role(user.userId, 'user');
await prisma.collection.create({
await locals.prisma.collection.create({
data: {
user_id: user.userId
}
});
await prisma.wishlist.create({
await locals.prisma.wishlist.create({
data: {
user_id: user.userId
}

View file

@ -1,6 +1,4 @@
import { error, json } from '@sveltejs/kit';
import prisma from '$lib/prisma';
import type { CollectionItemWithGame } from '$lib/types.js';
// Search a user's collection
export async function GET({ url, locals, params }) {
@ -19,7 +17,7 @@ export async function GET({ url, locals, params }) {
throw error(401, { message: 'Unauthorized' });
}
let collection = await prisma.collection.findUnique({
let collection = await locals.prisma.collection.findUnique({
where: {
user_id: locals.user.userId
}
@ -33,7 +31,7 @@ export async function GET({ url, locals, params }) {
try {
const orderBy = { [sort]: order };
let collection_items: CollectionItemWithGame[] = await prisma.collectionItem.findMany({
let collection_items = await locals.prisma.collectionItem.findMany({
where: {
collection_id,
AND: [

View file

@ -1,43 +1,54 @@
import { error, json } from '@sveltejs/kit';
import { Prisma } from '@prisma/client';
import prisma from '$lib/prisma';
import type { Prisma } from '@prisma/client';
import kebabCase from 'just-kebab-case';
// Search a user's collection
export const GET = async ({ url }) => {
export const GET = async ({ url, locals }) => {
const searchParams = Object.fromEntries(url.searchParams);
const q = searchParams?.q || '';
const q = searchParams?.q?.trim() || '';
const limit = parseInt(searchParams?.limit) || 10;
const skip = parseInt(searchParams?.skip) || 0;
const order: Prisma.SortOrder = <Prisma.SortOrder>searchParams?.order || 'desc';
const exact = searchParams?.exact === 'true';
console.log(`q: ${q}, limit: ${limit}, skip: ${skip}, order: ${order}`);
// const sort : Prisma.GameOrderByRelevanceFieldEnum = <Prisma.GameOrderByRelevanceFieldEnum>searchParams?.sort || 'name';
// console.log('url', url);
try {
let games = await prisma.game.findMany({
where: {
name: {
search: q
let games = [];
if (exact) {
games = await locals.prisma.game.findFirst({
where: {
name: {
equals: q
}
},
select: {
id: true,
name: true,
slug: true,
thumb_url: true
}
},
orderBy: {
_relevance: {
fields: ['name'],
search: q,
sort: order
});
} else {
games = await locals.prisma.game.findMany({
orderBy: {
_relevance: {
fields: ['name'],
search: q,
sort: order
}
},
select: {
id: true,
name: true,
slug: true,
thumb_url: true
}
},
select: {
id: true,
name: true,
slug: true,
thumb_url: true
},
skip,
take: limit
});
});
}
if (!games) {
if (!games || games.length === 0) {
throw error(404, { message: 'No games found' });
}

View file

@ -1,6 +1,4 @@
import { error, json } from '@sveltejs/kit';
import prisma from '$lib/prisma';
import type { CollectionItemWithGame } from '$lib/types.js';
// Search a user's collection
export async function GET({ url, locals, params }) {
@ -19,7 +17,7 @@ export async function GET({ url, locals, params }) {
throw error(401, { message: 'Unauthorized' });
}
let collection = await prisma.collection.findUnique({
let collection = await locals.prisma.collection.findUnique({
where: {
user_id: locals.user.userId
}
@ -33,7 +31,7 @@ export async function GET({ url, locals, params }) {
try {
const orderBy = { [sort]: order };
let collection_items: CollectionItemWithGame[] = await prisma.collectionItem.findMany({
let collection_items = await locals.prisma.collectionItem.findMany({
where: {
collection_id,
AND: [

View file

@ -1,8 +1,8 @@
import prisma from '$lib/prisma';
import { prisma_client } from "../hooks.server";
export async function add_user_to_role(user_id: string, role_name: string) {
// Find the role by its name
const role = await prisma.role.findUnique({
const role = await prisma_client.role.findUnique({
where: {
name: role_name
}
@ -13,7 +13,7 @@ export async function add_user_to_role(user_id: string, role_name: string) {
}
// Create a UserRole entry linking the user and the role
const userRole = await prisma.userRole.create({
const userRole = await prisma_client.userRole.create({
data: {
user: {
connect: {

View file

@ -1,10 +1,9 @@
import { auth } from '$lib/server/lucia';
import prisma from '$lib/prisma';
import type { User } from '@prisma/client';
import { prisma_client } from '../hooks.server';
import { add_user_to_role } from './roles';
export function create_user(user: User) {
return prisma.user.create({
return prisma_client.user.create({
data: {
username: user.username
}
@ -12,7 +11,7 @@ export function create_user(user: User) {
}
export async function find_or_create_user(user: User) {
const existing_user = await prisma.user.findUnique({
const existing_user = await prisma_client.user.findUnique({
where: {
username: user.username
}
@ -27,7 +26,7 @@ export async function find_or_create_user(user: User) {
}
export async function find_user_with_roles(user_id: string) {
const user_with_roles = await prisma.user.findUnique({
const user_with_roles = await prisma_client.user.findUnique({
where: {
id: user_id
},

View file

@ -1,9 +1,20 @@
import { sentrySvelteKit } from "@sentry/sveltekit";
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
import fs from 'fs';
export default defineConfig({
plugins: [sveltekit(), rawFonts(['.ttf'])],
plugins: [
sentrySvelteKit({
sourceMapsUploadOptions: {
org: process.env.SENTRY_ORG,
project: process.env.SENTRY_PROJECT,
authToken: process.env.SENTRY_AUTH_TOKEN,
cleanArtifacts: true,
}
}),
sveltekit(), rawFonts(['.ttf'])
],
test: {
include: ['src/**/*.{test,spec}.{js,ts}']
},
@ -42,4 +53,4 @@ function rawFonts(ext) {
}
}
};
}
}