49 Commits

Author SHA1 Message Date
5c47b13197 0.0.8
All checks were successful
Publish / lints (push) Successful in 25s
Publish / tests (push) Successful in 1m26s
Publish / Publishing (push) Successful in 1m41s
/ Misc Linters (push) Successful in 23s
/ Build App (push) Successful in 1m43s
2024-08-29 10:45:41 +02:00
7837dec1bd Merge pull request 'chore(deps): update dependency @sveltejs/kit to v2.5.25' (#68) from renovate/sveltejs-kit-2.x-lockfile into main
All checks were successful
/ Misc Linters (push) Successful in 28s
/ Build App (push) Successful in 1m25s
Reviewed-on: #68
2024-08-29 10:39:56 +02:00
15de87432b Typing
All checks were successful
/ Misc Linters (pull_request) Successful in 21s
/ Build App (pull_request) Successful in 1m27s
2024-08-29 10:37:38 +02:00
b177a348b7 Simple tests for timedExecution
Some checks failed
/ Misc Linters (pull_request) Successful in 22s
/ Build App (pull_request) Failing after 27s
2024-08-28 16:13:26 +02:00
29e06fdf91 Our own MaybePromise 2024-08-28 16:13:11 +02:00
c9990e9d30 Simplify 2024-08-28 16:12:38 +02:00
2dce93640d chore(deps): update dependency @sveltejs/kit to v2.5.25
Some checks failed
/ Misc Linters (pull_request) Successful in 22s
/ Build App (pull_request) Failing after 35s
2024-08-28 11:00:59 +02:00
7cf64a0e44 Merge pull request 'chore(deps): update dependency @types/node to v20.16.2' (#69) from renovate/node-20.x-lockfile into main
All checks were successful
/ Misc Linters (push) Successful in 25s
/ Build App (push) Successful in 1m36s
Reviewed-on: #69
2024-08-28 10:59:40 +02:00
6bae271dc9 chore(deps): update dependency @types/node to v20.16.2
All checks were successful
/ Misc Linters (pull_request) Successful in 43s
/ Build App (pull_request) Successful in 1m29s
2024-08-28 01:02:07 +00:00
25ea452d1c Merge pull request 'chore(deps): update dependency typescript-eslint to v8.3.0' (#66) from renovate/typescript-eslint-monorepo into main
All checks were successful
/ Misc Linters (push) Successful in 23s
/ Build App (push) Successful in 1m43s
Reviewed-on: #66
2024-08-27 10:47:21 +02:00
a955bd7b01 chore(deps): update dependency typescript-eslint to v8.3.0
All checks were successful
/ Misc Linters (pull_request) Successful in 1m16s
/ Build App (pull_request) Successful in 2m2s
2024-08-26 19:01:09 +00:00
8738b2372e Merge pull request 'chore(deps): update dependency @types/eslint to v9.6.1' (#65) from renovate/eslint-9.x-lockfile into main
All checks were successful
/ Misc Linters (push) Successful in 29s
/ Build App (push) Successful in 1m44s
Reviewed-on: #65
2024-08-26 18:27:53 +02:00
b7536e64b1 chore(deps): update dependency @types/eslint to v9.6.1
All checks were successful
/ Misc Linters (pull_request) Successful in 23s
/ Build App (pull_request) Successful in 1m34s
2024-08-26 10:01:05 +00:00
c6743ceb28 Merge pull request 'chore(deps): lock file maintenance' (#64) from renovate/lock-file-maintenance into main
All checks were successful
/ Misc Linters (push) Successful in 52s
/ Build App (push) Successful in 2m9s
Reviewed-on: #64
2024-08-24 12:15:37 +02:00
ade8720773 chore(deps): lock file maintenance
All checks were successful
/ Misc Linters (pull_request) Successful in 25s
/ Build App (pull_request) Successful in 1m21s
2024-08-24 12:13:38 +02:00
e1c9126022 Merge pull request 'chore(deps): update dependency eslint to v9.9.1' (#62) from renovate/eslint-monorepo into main
All checks were successful
/ Misc Linters (push) Successful in 36s
/ Build App (push) Successful in 1m33s
Reviewed-on: #62
2024-08-24 12:13:27 +02:00
dc17b3cfb4 chore(deps): update dependency eslint to v9.9.1
All checks were successful
/ Misc Linters (pull_request) Successful in 31s
/ Build App (pull_request) Successful in 1m31s
2024-08-24 12:10:23 +02:00
4e73b160df Merge pull request 'chore(deps): update dependency tslib to v2.7.0' (#63) from renovate/tslib-2.x-lockfile into main
All checks were successful
/ Misc Linters (push) Successful in 31s
/ Build App (push) Successful in 1m43s
Reviewed-on: #63
2024-08-24 12:10:11 +02:00
bd701d6b2e chore(deps): update dependency tslib to v2.7.0
All checks were successful
/ Misc Linters (pull_request) Successful in 19s
/ Build App (pull_request) Successful in 2m16s
2024-08-23 22:01:46 +00:00
0cc24af26b 0.0.7
All checks were successful
Publish / lints (push) Successful in 29s
Publish / tests (push) Successful in 1m24s
Publish / Publishing (push) Successful in 1m41s
/ Misc Linters (push) Successful in 34s
/ Build App (push) Successful in 2m3s
2024-08-23 19:03:33 +02:00
c746f71622 Merge pull request 'chore(deps): update dependency svelte to v4.2.19' (#61) from renovate/svelte-4.x-lockfile into main
All checks were successful
/ Misc Linters (push) Successful in 37s
/ Build App (push) Successful in 1m35s
Reviewed-on: #61
2024-08-23 19:00:23 +02:00
b7e38dca12 chore(deps): update dependency svelte to v4.2.19
All checks were successful
/ Misc Linters (pull_request) Successful in 35s
/ Build App (pull_request) Successful in 1m43s
2024-08-23 16:56:16 +00:00
f098209b66 Merge pull request 'chore(deps): lock file maintenance' (#58) from renovate/lock-file-maintenance into main
All checks were successful
/ Misc Linters (push) Successful in 45s
/ Build App (push) Successful in 1m43s
Reviewed-on: #58
2024-08-23 18:53:20 +02:00
b5db49061e chore(deps): lock file maintenance
All checks were successful
/ Misc Linters (pull_request) Successful in 25s
/ Build App (pull_request) Successful in 1m48s
2024-08-23 18:44:14 +02:00
716799beb2 Merge pull request 'chore(deps): update dependency @sveltejs/vite-plugin-svelte to v3.1.2' (#59) from renovate/sveltejs-vite-plugin-svelte-3.x-lockfile into main
All checks were successful
/ Misc Linters (push) Successful in 30s
/ Build App (push) Successful in 1m49s
Reviewed-on: #59
2024-08-23 18:44:07 +02:00
a8c64f9d74 chore(deps): update dependency @sveltejs/vite-plugin-svelte to v3.1.2
All checks were successful
/ Misc Linters (pull_request) Successful in 30s
/ Build App (pull_request) Successful in 1m45s
2024-08-23 18:35:47 +02:00
fe7e1062d4 Merge pull request 'chore(deps): update dependency svelte-check to v3.8.6' (#60) from renovate/svelte-check-3.x-lockfile into main
All checks were successful
/ Misc Linters (push) Successful in 26s
/ Build App (push) Successful in 1m59s
Reviewed-on: #60
2024-08-23 18:35:38 +02:00
372d2b4253 chore(deps): update dependency svelte-check to v3.8.6
All checks were successful
/ Misc Linters (pull_request) Successful in 31s
/ Build App (pull_request) Successful in 1m37s
2024-08-22 19:02:02 +00:00
ad5705b00c Merge pull request 'chore(deps): update dependency vite to v5.4.2' (#57) from renovate/vite-5.x-lockfile into main
All checks were successful
/ Misc Linters (push) Successful in 24s
/ Build App (push) Successful in 1m39s
Reviewed-on: #57
2024-08-21 08:58:40 +02:00
868a518097 chore(deps): update dependency vite to v5.4.2
All checks were successful
/ Misc Linters (pull_request) Successful in 26s
/ Build App (pull_request) Successful in 1m34s
2024-08-20 16:02:01 +00:00
2836915aeb Merge pull request 'chore(deps): update dependency @sveltejs/kit to v2.5.24' (#55) from renovate/sveltejs-kit-2.x-lockfile into main
All checks were successful
/ Misc Linters (push) Successful in 24s
/ Build App (push) Successful in 1m45s
Reviewed-on: #55
2024-08-20 13:59:22 +02:00
353cc1bf1e Merge pull request 'chore(deps): update dependency typescript-eslint to v8.2.0' (#56) from renovate/typescript-eslint-monorepo into main
Some checks failed
/ Build App (push) Waiting to run
/ Misc Linters (push) Has been cancelled
Reviewed-on: #56
2024-08-20 13:59:12 +02:00
d60c1ddbbd Merge pull request 'chore(deps): update dependency @types/node to v20.16.1' (#54) from renovate/node-20.x-lockfile into main
Some checks failed
/ Build App (push) Has been cancelled
/ Misc Linters (push) Has been cancelled
Reviewed-on: #54
2024-08-20 13:58:58 +02:00
09a1e98afb chore(deps): update dependency typescript-eslint to v8.2.0
All checks were successful
/ Misc Linters (pull_request) Successful in 27s
/ Build App (pull_request) Successful in 1m27s
2024-08-19 19:01:56 +00:00
5c894e1462 chore(deps): update dependency @sveltejs/kit to v2.5.24
All checks were successful
/ Misc Linters (pull_request) Successful in 28s
/ Build App (pull_request) Successful in 1m36s
2024-08-19 13:01:38 +00:00
1eeec1215e chore(deps): update dependency @types/node to v20.16.1
All checks were successful
/ Misc Linters (pull_request) Successful in 18s
/ Build App (pull_request) Successful in 1m32s
2024-08-19 04:01:39 +00:00
d3016c765e Merge pull request 'chore(deps): update dependency @types/node to v20.16.0' (#52) from renovate/node-20.x-lockfile into main
All checks were successful
/ Misc Linters (push) Successful in 22s
/ Build App (push) Successful in 1m36s
Reviewed-on: #52
2024-08-18 16:03:16 +02:00
568da269a1 chore(deps): update dependency @types/node to v20.16.0
All checks were successful
/ Misc Linters (pull_request) Successful in 21s
/ Build App (pull_request) Successful in 1m20s
2024-08-18 15:51:05 +02:00
48b9a4c8fb Merge pull request 'Integration tests for API' (#53) from testing into main
All checks were successful
/ Misc Linters (push) Successful in 39s
/ Build App (push) Successful in 1m34s
Reviewed-on: #53
2024-08-18 15:48:51 +02:00
25ef50f358 Add test for page
All checks were successful
/ Misc Linters (pull_request) Successful in 27s
/ Build App (pull_request) Successful in 1m49s
2024-08-18 15:46:46 +02:00
20920586e0 Formatting
All checks were successful
/ Misc Linters (pull_request) Successful in 23s
/ Build App (pull_request) Successful in 1m21s
2024-08-18 15:38:03 +02:00
56f568634e Implement first integration tests
Some checks failed
/ Misc Linters (pull_request) Successful in 28s
/ Build App (pull_request) Failing after 27s
2024-08-18 15:34:36 +02:00
0fd1f178be Add playwright 2024-08-18 15:34:19 +02:00
da92ed6258 Move request-id header name to $lib 2024-08-18 15:33:56 +02:00
13b1d57e08 Merge pull request 'Healthcheck' (#51) from healthcheck into main
All checks were successful
/ Misc Linters (push) Successful in 31s
/ Build App (push) Successful in 1m8s
Reviewed-on: #51
2024-08-17 18:28:16 +02:00
1f69e739d0 Add healthcheck endpoint
All checks were successful
/ Misc Linters (pull_request) Successful in 18s
/ Build App (pull_request) Successful in 54s
2024-08-17 18:26:57 +02:00
58a65856aa Simplify
All checks were successful
/ Misc Linters (push) Successful in 23s
/ Build App (push) Successful in 52s
/ Misc Linters (pull_request) Successful in 27s
/ Build App (pull_request) Successful in 59s
2024-08-17 17:22:27 +02:00
e2a4335937 Define endpoint in TSy way
All checks were successful
/ Misc Linters (push) Successful in 25s
/ Build App (push) Successful in 52s
2024-08-17 17:12:05 +02:00
3160923f7e Fix typos and define handler in TSy way
All checks were successful
/ Misc Linters (push) Successful in 23s
/ Build App (push) Successful in 52s
2024-08-17 16:49:38 +02:00
12 changed files with 457 additions and 306 deletions

7
.gitignore vendored
View File

@ -20,5 +20,12 @@ Thumbs.db
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
# Playwright
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
/playwright/.auth
uploads
.direnv

562
package-lock.json generated
View File

@ -1,17 +1,18 @@
{
"name": "fotochallenge",
"version": "0.0.6",
"version": "0.0.8",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "fotochallenge",
"version": "0.0.6",
"version": "0.0.8",
"dependencies": {
"bunyan": "^1.8.15",
"uuid": "^10.0.0"
},
"devDependencies": {
"@playwright/test": "^1.46.1",
"@sveltejs/adapter-auto": "^3.0.0",
"@sveltejs/adapter-node": "^5.2.0",
"@sveltejs/kit": "^2.0.0",
@ -486,9 +487,9 @@
}
},
"node_modules/@eslint/config-array": {
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz",
"integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==",
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz",
"integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@ -538,9 +539,9 @@
}
},
"node_modules/@eslint/js": {
"version": "9.9.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.9.0.tgz",
"integrity": "sha512-hhetes6ZHP3BlXLxmd8K2SNgkhNSi+UcecbnwWKwpP7kyi/uC75DJ1lOOBO3xrC4jyojtGE3YxKZPHfk4yrgug==",
"version": "9.9.1",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.9.1.tgz",
"integrity": "sha512-xIDQRsfg5hNBqHz04H1R3scSVwmI+KUbqjsQKHKQ1DAUSaUjYPReZZmS/5PNiKu1fUvzDd6H7DEDKACSEhu+TQ==",
"dev": true,
"license": "MIT",
"engines": {
@ -734,6 +735,22 @@
"node": ">=14"
}
},
"node_modules/@playwright/test": {
"version": "1.46.1",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.46.1.tgz",
"integrity": "sha512-Fq6SwLujA/DOIvNC2EL/SojJnkKf/rAwJ//APpJJHRyMi1PdKrY3Az+4XNQ51N4RTbItbIByQ0jgd1tayq1aeA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"playwright": "1.46.1"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@polka/url": {
"version": "1.0.0-next.25",
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.25.tgz",
@ -838,9 +855,9 @@
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.20.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.20.0.tgz",
"integrity": "sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==",
"version": "4.21.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.0.tgz",
"integrity": "sha512-WTWD8PfoSAJ+qL87lE7votj3syLavxunWhzCnx3XFxFiI/BA/r3X7MUM8dVrH8rb2r4AiO8jJsr3ZjdaftmnfA==",
"cpu": [
"arm"
],
@ -852,9 +869,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.20.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.20.0.tgz",
"integrity": "sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ==",
"version": "4.21.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.0.tgz",
"integrity": "sha512-a1sR2zSK1B4eYkiZu17ZUZhmUQcKjk2/j9Me2IDjk1GHW7LB5Z35LEzj9iJch6gtUfsnvZs1ZNyDW2oZSThrkA==",
"cpu": [
"arm64"
],
@ -866,9 +883,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.20.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.20.0.tgz",
"integrity": "sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q==",
"version": "4.21.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.0.tgz",
"integrity": "sha512-zOnKWLgDld/svhKO5PD9ozmL6roy5OQ5T4ThvdYZLpiOhEGY+dp2NwUmxK0Ld91LrbjrvtNAE0ERBwjqhZTRAA==",
"cpu": [
"arm64"
],
@ -880,9 +897,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.20.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.20.0.tgz",
"integrity": "sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ==",
"version": "4.21.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.0.tgz",
"integrity": "sha512-7doS8br0xAkg48SKE2QNtMSFPFUlRdw9+votl27MvT46vo44ATBmdZdGysOevNELmZlfd+NEa0UYOA8f01WSrg==",
"cpu": [
"x64"
],
@ -894,9 +911,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.20.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.20.0.tgz",
"integrity": "sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA==",
"version": "4.21.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.0.tgz",
"integrity": "sha512-pWJsfQjNWNGsoCq53KjMtwdJDmh/6NubwQcz52aEwLEuvx08bzcy6tOUuawAOncPnxz/3siRtd8hiQ32G1y8VA==",
"cpu": [
"arm"
],
@ -908,9 +925,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.20.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.20.0.tgz",
"integrity": "sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw==",
"version": "4.21.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.0.tgz",
"integrity": "sha512-efRIANsz3UHZrnZXuEvxS9LoCOWMGD1rweciD6uJQIx2myN3a8Im1FafZBzh7zk1RJ6oKcR16dU3UPldaKd83w==",
"cpu": [
"arm"
],
@ -922,9 +939,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.20.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.20.0.tgz",
"integrity": "sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ==",
"version": "4.21.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.0.tgz",
"integrity": "sha512-ZrPhydkTVhyeGTW94WJ8pnl1uroqVHM3j3hjdquwAcWnmivjAwOYjTEAuEDeJvGX7xv3Z9GAvrBkEzCgHq9U1w==",
"cpu": [
"arm64"
],
@ -936,9 +953,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.20.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.20.0.tgz",
"integrity": "sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q==",
"version": "4.21.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.0.tgz",
"integrity": "sha512-cfaupqd+UEFeURmqNP2eEvXqgbSox/LHOyN9/d2pSdV8xTrjdg3NgOFJCtc1vQ/jEke1qD0IejbBfxleBPHnPw==",
"cpu": [
"arm64"
],
@ -950,9 +967,9 @@
]
},
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.20.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.20.0.tgz",
"integrity": "sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw==",
"version": "4.21.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.0.tgz",
"integrity": "sha512-ZKPan1/RvAhrUylwBXC9t7B2hXdpb/ufeu22pG2psV7RN8roOfGurEghw1ySmX/CmDDHNTDDjY3lo9hRlgtaHg==",
"cpu": [
"ppc64"
],
@ -964,9 +981,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.20.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.20.0.tgz",
"integrity": "sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA==",
"version": "4.21.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.0.tgz",
"integrity": "sha512-H1eRaCwd5E8eS8leiS+o/NqMdljkcb1d6r2h4fKSsCXQilLKArq6WS7XBLDu80Yz+nMqHVFDquwcVrQmGr28rg==",
"cpu": [
"riscv64"
],
@ -978,9 +995,9 @@
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.20.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.20.0.tgz",
"integrity": "sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg==",
"version": "4.21.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.0.tgz",
"integrity": "sha512-zJ4hA+3b5tu8u7L58CCSI0A9N1vkfwPhWd/puGXwtZlsB5bTkwDNW/+JCU84+3QYmKpLi+XvHdmrlwUwDA6kqw==",
"cpu": [
"s390x"
],
@ -992,9 +1009,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.20.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.20.0.tgz",
"integrity": "sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew==",
"version": "4.21.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.0.tgz",
"integrity": "sha512-e2hrvElFIh6kW/UNBQK/kzqMNY5mO+67YtEh9OA65RM5IJXYTWiXjX6fjIiPaqOkBthYF1EqgiZ6OXKcQsM0hg==",
"cpu": [
"x64"
],
@ -1006,9 +1023,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.20.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.20.0.tgz",
"integrity": "sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg==",
"version": "4.21.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.0.tgz",
"integrity": "sha512-1vvmgDdUSebVGXWX2lIcgRebqfQSff0hMEkLJyakQ9JQUbLDkEaMsPTLOmyccyC6IJ/l3FZuJbmrBw/u0A0uCQ==",
"cpu": [
"x64"
],
@ -1020,9 +1037,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.20.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.20.0.tgz",
"integrity": "sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==",
"version": "4.21.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.0.tgz",
"integrity": "sha512-s5oFkZ/hFcrlAyBTONFY1TWndfyre1wOMwU+6KCpm/iatybvrRgmZVM+vCFwxmC5ZhdlgfE0N4XorsDpi7/4XQ==",
"cpu": [
"arm64"
],
@ -1034,9 +1051,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.20.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.20.0.tgz",
"integrity": "sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A==",
"version": "4.21.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.0.tgz",
"integrity": "sha512-G9+TEqRnAA6nbpqyUqgTiopmnfgnMkR3kMukFBDsiyy23LZvUCpiUwjTRx6ezYCjJODXrh52rBR9oXvm+Fp5wg==",
"cpu": [
"ia32"
],
@ -1048,9 +1065,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.20.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.20.0.tgz",
"integrity": "sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg==",
"version": "4.21.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.0.tgz",
"integrity": "sha512-2jsCDZwtQvRhejHLfZ1JY6w6kEuEtfF9nzYsZxzSlNVKDX+DpsDJ+Rbjkm74nvg2rdx0gwBS+IMdvwJuq3S9pQ==",
"cpu": [
"x64"
],
@ -1091,9 +1108,9 @@
}
},
"node_modules/@sveltejs/kit": {
"version": "2.5.22",
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.5.22.tgz",
"integrity": "sha512-PQ98baF2WzvG5yiO4cZKJZJG60XjHTZD1jyho3u9Kmthx2ytdGYyVPPvKXgKXpKSq4wwctD9dl0d2blSbJMcOg==",
"version": "2.5.25",
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.5.25.tgz",
"integrity": "sha512-5hBSEN8XEjDZ5+2bHkFh8Z0QyOk0C187cyb12aANe1c8aeKbfu5ZD5XaC2vEH4h0alJFDXPdUkXQBmeeXeMr1A==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@ -1118,15 +1135,15 @@
"node": ">=18.13"
},
"peerDependencies": {
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1",
"svelte": "^4.0.0 || ^5.0.0-next.0",
"vite": "^5.0.3"
}
},
"node_modules/@sveltejs/vite-plugin-svelte": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.1.1.tgz",
"integrity": "sha512-rimpFEAboBBHIlzISibg94iP09k/KYdHgVhJlcsTfn7KMBhc70jFX/GRWkRdFCc2fdnk+4+Bdfej23cMDnJS6A==",
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.1.2.tgz",
"integrity": "sha512-Txsm1tJvtiYeLUVRNqxZGKR/mI+CzuIQuc2gn+YCs9rMTowpNZ2Nqt53JdL8KF9bLhAf2ruR/dr9eZCwdTriRA==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -1182,9 +1199,9 @@
"license": "MIT"
},
"node_modules/@types/eslint": {
"version": "9.6.0",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.0.tgz",
"integrity": "sha512-gi6WQJ7cHRgZxtkQEoyHMppPjq9Kxo5Tjn2prSKDSmZrCz8TZ3jSRCeTJm+WoM+oB0WG37bRqLzaaU3q7JypGg==",
"version": "9.6.1",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz",
"integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -1207,13 +1224,13 @@
"license": "MIT"
},
"node_modules/@types/node": {
"version": "20.15.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.15.0.tgz",
"integrity": "sha512-eQf4OkH6gA9v1W0iEpht/neozCsZKMTK+C4cU6/fv7wtJCCL8LEQ4hie2Ln8ZP/0YYM2xGj7//f8xyqItkJ6QA==",
"version": "20.16.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.2.tgz",
"integrity": "sha512-91s/n4qUPV/wg8eE9KHYW1kouTfDk2FPGjXbBMfRWP/2vg1rCXNQL1OCabwGs0XSdukuK+MwCDXE30QpSeMUhQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.13.0"
"undici-types": "~6.19.2"
}
},
"node_modules/@types/pug": {
@ -1238,17 +1255,17 @@
"license": "MIT"
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.1.0.tgz",
"integrity": "sha512-LlNBaHFCEBPHyD4pZXb35mzjGkuGKXU5eeCA1SxvHfiRES0E82dOounfVpL4DCqYvJEKab0bZIA0gCRpdLKkCw==",
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.3.0.tgz",
"integrity": "sha512-FLAIn63G5KH+adZosDYiutqkOkYEx0nvcwNNfJAf+c7Ae/H35qWwTYvPZUKFj5AS+WfHG/WJJfWnDnyNUlp8UA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/regexpp": "^4.10.0",
"@typescript-eslint/scope-manager": "8.1.0",
"@typescript-eslint/type-utils": "8.1.0",
"@typescript-eslint/utils": "8.1.0",
"@typescript-eslint/visitor-keys": "8.1.0",
"@typescript-eslint/scope-manager": "8.3.0",
"@typescript-eslint/type-utils": "8.3.0",
"@typescript-eslint/utils": "8.3.0",
"@typescript-eslint/visitor-keys": "8.3.0",
"graphemer": "^1.4.0",
"ignore": "^5.3.1",
"natural-compare": "^1.4.0",
@ -1272,16 +1289,16 @@
}
},
"node_modules/@typescript-eslint/parser": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.1.0.tgz",
"integrity": "sha512-U7iTAtGgJk6DPX9wIWPPOlt1gO57097G06gIcl0N0EEnNw8RGD62c+2/DiP/zL7KrkqnnqF7gtFGR7YgzPllTA==",
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.3.0.tgz",
"integrity": "sha512-h53RhVyLu6AtpUzVCYLPhZGL5jzTD9fZL+SYf/+hYOx2bDkyQXztXSc4tbvKYHzfMXExMLiL9CWqJmVz6+78IQ==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"@typescript-eslint/scope-manager": "8.1.0",
"@typescript-eslint/types": "8.1.0",
"@typescript-eslint/typescript-estree": "8.1.0",
"@typescript-eslint/visitor-keys": "8.1.0",
"@typescript-eslint/scope-manager": "8.3.0",
"@typescript-eslint/types": "8.3.0",
"@typescript-eslint/typescript-estree": "8.3.0",
"@typescript-eslint/visitor-keys": "8.3.0",
"debug": "^4.3.4"
},
"engines": {
@ -1301,14 +1318,14 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.1.0.tgz",
"integrity": "sha512-DsuOZQji687sQUjm4N6c9xABJa7fjvfIdjqpSIIVOgaENf2jFXiM9hIBZOL3hb6DHK9Nvd2d7zZnoMLf9e0OtQ==",
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.3.0.tgz",
"integrity": "sha512-mz2X8WcN2nVu5Hodku+IR8GgCOl4C0G/Z1ruaWN4dgec64kDBabuXyPAr+/RgJtumv8EEkqIzf3X2U5DUKB2eg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.1.0",
"@typescript-eslint/visitor-keys": "8.1.0"
"@typescript-eslint/types": "8.3.0",
"@typescript-eslint/visitor-keys": "8.3.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@ -1319,14 +1336,14 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.1.0.tgz",
"integrity": "sha512-oLYvTxljVvsMnldfl6jIKxTaU7ok7km0KDrwOt1RHYu6nxlhN3TIx8k5Q52L6wR33nOwDgM7VwW1fT1qMNfFIA==",
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.3.0.tgz",
"integrity": "sha512-wrV6qh//nLbfXZQoj32EXKmwHf4b7L+xXLrP3FZ0GOUU72gSvLjeWUl5J5Ue5IwRxIV1TfF73j/eaBapxx99Lg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/typescript-estree": "8.1.0",
"@typescript-eslint/utils": "8.1.0",
"@typescript-eslint/typescript-estree": "8.3.0",
"@typescript-eslint/utils": "8.3.0",
"debug": "^4.3.4",
"ts-api-utils": "^1.3.0"
},
@ -1344,9 +1361,9 @@
}
},
"node_modules/@typescript-eslint/types": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.1.0.tgz",
"integrity": "sha512-q2/Bxa0gMOu/2/AKALI0tCKbG2zppccnRIRCW6BaaTlRVaPKft4oVYPp7WOPpcnsgbr0qROAVCVKCvIQ0tbWog==",
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.3.0.tgz",
"integrity": "sha512-y6sSEeK+facMaAyixM36dQ5NVXTnKWunfD1Ft4xraYqxP0lC0POJmIaL/mw72CUMqjY9qfyVfXafMeaUj0noWw==",
"dev": true,
"license": "MIT",
"engines": {
@ -1358,16 +1375,16 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.1.0.tgz",
"integrity": "sha512-NTHhmufocEkMiAord/g++gWKb0Fr34e9AExBRdqgWdVBaKoei2dIyYKD9Q0jBnvfbEA5zaf8plUFMUH6kQ0vGg==",
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.3.0.tgz",
"integrity": "sha512-Mq7FTHl0R36EmWlCJWojIC1qn/ZWo2YiWYc1XVtasJ7FIgjo0MVv9rZWXEE7IK2CGrtwe1dVOxWwqXUdNgfRCA==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"@typescript-eslint/types": "8.1.0",
"@typescript-eslint/visitor-keys": "8.1.0",
"@typescript-eslint/types": "8.3.0",
"@typescript-eslint/visitor-keys": "8.3.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"fast-glob": "^3.3.2",
"is-glob": "^4.0.3",
"minimatch": "^9.0.4",
"semver": "^7.6.0",
@ -1413,16 +1430,16 @@
}
},
"node_modules/@typescript-eslint/utils": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.1.0.tgz",
"integrity": "sha512-ypRueFNKTIFwqPeJBfeIpxZ895PQhNyH4YID6js0UoBImWYoSjBsahUn9KMiJXh94uOjVBgHD9AmkyPsPnFwJA==",
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.3.0.tgz",
"integrity": "sha512-F77WwqxIi/qGkIGOGXNBLV7nykwfjLsdauRB/DOFPdv6LTF3BHHkBpq81/b5iMPSF055oO2BiivDJV4ChvNtXA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
"@typescript-eslint/scope-manager": "8.1.0",
"@typescript-eslint/types": "8.1.0",
"@typescript-eslint/typescript-estree": "8.1.0"
"@typescript-eslint/scope-manager": "8.3.0",
"@typescript-eslint/types": "8.3.0",
"@typescript-eslint/typescript-estree": "8.3.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@ -1436,13 +1453,13 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.1.0.tgz",
"integrity": "sha512-ba0lNI19awqZ5ZNKh6wCModMwoZs457StTebQ0q1NP58zSi2F6MOZRXwfKZy+jB78JNJ/WH8GSh2IQNzXX8Nag==",
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.3.0.tgz",
"integrity": "sha512-RmZwrTbQ9QveF15m/Cl28n0LXD6ea2CjkhH5rQ55ewz3H24w+AMCJHPVYaZ8/0HoG8Z3cLLFFycRXxeO2tz9FA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.1.0",
"@typescript-eslint/types": "8.3.0",
"eslint-visitor-keys": "^3.4.3"
},
"engines": {
@ -1660,16 +1677,6 @@
"dequal": "^2.0.3"
}
},
"node_modules/array-union": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/assertion-error": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
@ -2066,19 +2073,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/dir-glob": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
"integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
"dev": true,
"license": "MIT",
"dependencies": {
"path-type": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/dtrace-provider": {
"version": "0.8.8",
"resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.8.tgz",
@ -2167,17 +2161,17 @@
}
},
"node_modules/eslint": {
"version": "9.9.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.9.0.tgz",
"integrity": "sha512-JfiKJrbx0506OEerjK2Y1QlldtBxkAlLxT5OEcRF8uaQ86noDe2k31Vw9rnSWv+MXZHj7OOUV/dA0AhdLFcyvA==",
"version": "9.9.1",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.9.1.tgz",
"integrity": "sha512-dHvhrbfr4xFQ9/dq+jcVneZMyRYLjggWjk6RVsIiHsP8Rz6yZ8LvZ//iU4TrZF+SXWG+JkNF2OyiZRvzgRDqMg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.11.0",
"@eslint/config-array": "^0.17.1",
"@eslint/config-array": "^0.18.0",
"@eslint/eslintrc": "^3.1.0",
"@eslint/js": "9.9.0",
"@eslint/js": "9.9.1",
"@humanwhocodes/module-importer": "^1.0.1",
"@humanwhocodes/retry": "^0.3.0",
"@nodelib/fs.walk": "^1.2.8",
@ -2572,9 +2566,9 @@
"license": "ISC"
},
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@ -2699,27 +2693,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/globby": {
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
"integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
"dev": true,
"license": "MIT",
"dependencies": {
"array-union": "^2.1.0",
"dir-glob": "^3.0.1",
"fast-glob": "^3.2.9",
"ignore": "^5.2.0",
"merge2": "^1.4.1",
"slash": "^3.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/globrex": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
@ -2878,9 +2851,9 @@
}
},
"node_modules/is-core-module": {
"version": "2.15.0",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz",
"integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==",
"version": "2.15.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz",
"integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -3166,9 +3139,9 @@
}
},
"node_modules/micromatch": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
"integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==",
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -3300,38 +3273,6 @@
"node": ">=0.8.0"
}
},
"node_modules/mv/node_modules/glob": {
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz",
"integrity": "sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==",
"deprecated": "Glob versions prior to v9 are no longer supported",
"license": "ISC",
"optional": true,
"dependencies": {
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "2 || 3",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
}
},
"node_modules/mv/node_modules/rimraf": {
"version": "2.4.5",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz",
"integrity": "sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ==",
"deprecated": "Rimraf versions prior to v4 are no longer supported",
"license": "ISC",
"optional": true,
"dependencies": {
"glob": "^6.0.1"
},
"bin": {
"rimraf": "bin.js"
}
},
"node_modules/nan": {
"version": "2.20.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz",
@ -3564,16 +3505,6 @@
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/path-type": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/pathe": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz",
@ -3643,6 +3574,38 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/playwright": {
"version": "1.46.1",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.46.1.tgz",
"integrity": "sha512-oPcr1yqoXLCkgKtD5eNUPLiN40rYEM39odNpIb6VE6S7/15gJmA1NzVv6zJYusV0e7tzvkU/utBFNa/Kpxmwng==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.46.1"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=18"
},
"optionalDependencies": {
"fsevents": "2.3.2"
}
},
"node_modules/playwright-core": {
"version": "1.46.1",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.46.1.tgz",
"integrity": "sha512-h9LqIQaAv+CYvWzsZ+h3RsrqCStkBHlgo6/TJlFst3cOTlLghBQlJwPOZKQJTKNaD3QIB7aAVQ+gfWbN3NXB7A==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"playwright-core": "cli.js"
},
"engines": {
"node": ">=18"
}
},
"node_modules/postcss": {
"version": "8.4.41",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz",
@ -3881,45 +3844,41 @@
}
},
"node_modules/rimraf": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
"version": "2.4.5",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz",
"integrity": "sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ==",
"deprecated": "Rimraf versions prior to v4 are no longer supported",
"dev": true,
"license": "ISC",
"optional": true,
"dependencies": {
"glob": "^7.1.3"
"glob": "^6.0.1"
},
"bin": {
"rimraf": "bin.js"
}
},
"node_modules/rimraf/node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz",
"integrity": "sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==",
"deprecated": "Glob versions prior to v9 are no longer supported",
"dev": true,
"license": "ISC",
"optional": true,
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.1.1",
"minimatch": "2 || 3",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/rollup": {
"version": "4.20.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.20.0.tgz",
"integrity": "sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw==",
"version": "4.21.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.0.tgz",
"integrity": "sha512-vo+S/lfA2lMS7rZ2Qoubi6I5hwZwzXeUIctILZLbHI+laNtvhhOIon2S1JksA5UEDQ7l3vberd0fxK44lTYjbQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -3933,22 +3892,22 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.20.0",
"@rollup/rollup-android-arm64": "4.20.0",
"@rollup/rollup-darwin-arm64": "4.20.0",
"@rollup/rollup-darwin-x64": "4.20.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.20.0",
"@rollup/rollup-linux-arm-musleabihf": "4.20.0",
"@rollup/rollup-linux-arm64-gnu": "4.20.0",
"@rollup/rollup-linux-arm64-musl": "4.20.0",
"@rollup/rollup-linux-powerpc64le-gnu": "4.20.0",
"@rollup/rollup-linux-riscv64-gnu": "4.20.0",
"@rollup/rollup-linux-s390x-gnu": "4.20.0",
"@rollup/rollup-linux-x64-gnu": "4.20.0",
"@rollup/rollup-linux-x64-musl": "4.20.0",
"@rollup/rollup-win32-arm64-msvc": "4.20.0",
"@rollup/rollup-win32-ia32-msvc": "4.20.0",
"@rollup/rollup-win32-x64-msvc": "4.20.0",
"@rollup/rollup-android-arm-eabi": "4.21.0",
"@rollup/rollup-android-arm64": "4.21.0",
"@rollup/rollup-darwin-arm64": "4.21.0",
"@rollup/rollup-darwin-x64": "4.21.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.21.0",
"@rollup/rollup-linux-arm-musleabihf": "4.21.0",
"@rollup/rollup-linux-arm64-gnu": "4.21.0",
"@rollup/rollup-linux-arm64-musl": "4.21.0",
"@rollup/rollup-linux-powerpc64le-gnu": "4.21.0",
"@rollup/rollup-linux-riscv64-gnu": "4.21.0",
"@rollup/rollup-linux-s390x-gnu": "4.21.0",
"@rollup/rollup-linux-x64-gnu": "4.21.0",
"@rollup/rollup-linux-x64-musl": "4.21.0",
"@rollup/rollup-win32-arm64-msvc": "4.21.0",
"@rollup/rollup-win32-ia32-msvc": "4.21.0",
"@rollup/rollup-win32-x64-msvc": "4.21.0",
"fsevents": "~2.3.2"
}
},
@ -4009,6 +3968,42 @@
"rimraf": "^2.5.2"
}
},
"node_modules/sander/node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"deprecated": "Glob versions prior to v9 are no longer supported",
"dev": true,
"license": "ISC",
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/sander/node_modules/rimraf": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
"deprecated": "Rimraf versions prior to v4 are no longer supported",
"dev": true,
"license": "ISC",
"dependencies": {
"glob": "^7.1.3"
},
"bin": {
"rimraf": "bin.js"
}
},
"node_modules/sass": {
"version": "1.77.8",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.77.8.tgz",
@ -4111,16 +4106,6 @@
"node": ">= 10"
}
},
"node_modules/slash": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/sorcery": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.11.1.tgz",
@ -4324,9 +4309,9 @@
}
},
"node_modules/svelte": {
"version": "4.2.18",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.18.tgz",
"integrity": "sha512-d0FdzYIiAePqRJEb90WlJDkjUEx42xhivxN8muUBmfZnP+tzUgz12DJ2hRJi8sIHCME7jeK1PTMgKPSfTd8JrA==",
"version": "4.2.19",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.19.tgz",
"integrity": "sha512-IY1rnGr6izd10B0A8LqsBfmlT5OILVuZ7XsI0vdGPEvuonFV7NYEUK4dAkm9Zg2q0Um92kYjTpS1CAP3Nh/KWw==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -4350,9 +4335,9 @@
}
},
"node_modules/svelte-check": {
"version": "3.8.5",
"resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-3.8.5.tgz",
"integrity": "sha512-3OGGgr9+bJ/+1nbPgsvulkLC48xBsqsgtc8Wam281H4G9F5v3mYGa2bHRsPuwHC5brKl4AxJH95QF73kmfihGQ==",
"version": "3.8.6",
"resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-3.8.6.tgz",
"integrity": "sha512-ij0u4Lw/sOTREP13BdWZjiXD/BlHE6/e2e34XzmVmsp5IN4kVa3PWP65NM32JAgwjZlwBg/+JtiNV1MM8khu0Q==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -4568,9 +4553,9 @@
"license": "MIT"
},
"node_modules/tinypool": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.0.tgz",
"integrity": "sha512-KIKExllK7jp3uvrNtvRBYBWBOAXSX8ZvoaD8T+7KB/QHIuoJW3Pmr60zucywjAlMb5TeXUkcs/MWeWLu0qvuAQ==",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.1.tgz",
"integrity": "sha512-URZYihUbRPcGv95En+sz6MfghfIc2OJ1sv/RmhWZLouPY0/8Vo80viwPvg3dlaS9fuq7fQMEfgRRK7BBZThBEA==",
"dev": true,
"license": "MIT",
"engines": {
@ -4634,9 +4619,9 @@
}
},
"node_modules/tslib": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
"integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==",
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
"integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==",
"dev": true,
"license": "0BSD"
},
@ -4668,15 +4653,15 @@
}
},
"node_modules/typescript-eslint": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.1.0.tgz",
"integrity": "sha512-prB2U3jXPJLpo1iVLN338Lvolh6OrcCZO+9Yv6AR+tvegPPptYCDBIHiEEUdqRi8gAv2bXNKfMUrgAd2ejn/ow==",
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.3.0.tgz",
"integrity": "sha512-EvWjwWLwwKDIJuBjk2I6UkV8KEQcwZ0VM10nR1rIunRDIP67QJTZAHBXTX0HW/oI1H10YESF8yWie8fRQxjvFA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/eslint-plugin": "8.1.0",
"@typescript-eslint/parser": "8.1.0",
"@typescript-eslint/utils": "8.1.0"
"@typescript-eslint/eslint-plugin": "8.3.0",
"@typescript-eslint/parser": "8.3.0",
"@typescript-eslint/utils": "8.3.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@ -4692,9 +4677,9 @@
}
},
"node_modules/undici-types": {
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.13.0.tgz",
"integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==",
"version": "6.19.8",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
"dev": true,
"license": "MIT"
},
@ -4729,15 +4714,15 @@
}
},
"node_modules/vite": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.1.tgz",
"integrity": "sha512-1oE6yuNXssjrZdblI9AfBbHCC41nnyoVoEZxQnID6yvQZAFBzxxkqoFLtHUMkYunL8hwOLEjgTuxpkRxvba3kA==",
"version": "5.4.2",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.2.tgz",
"integrity": "sha512-dDrQTRHp5C1fTFzcSaMxjk6vdpKvT+2/mIdE07Gw2ykehT49O0z/VHS3zZ8iV/Gh8BJJKHWOe5RjaNrW5xf/GA==",
"dev": true,
"license": "MIT",
"dependencies": {
"esbuild": "^0.21.3",
"postcss": "^8.4.41",
"rollup": "^4.13.0"
"rollup": "^4.20.0"
},
"bin": {
"vite": "bin/vite.js"
@ -4811,6 +4796,21 @@
"url": "https://opencollective.com/vitest"
}
},
"node_modules/vite/node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/vitefu": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz",

View File

@ -1,18 +1,21 @@
{
"name": "fotochallenge",
"version": "0.0.6",
"version": "0.0.8",
"private": true,
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"test": "vitest",
"test": "npm run test:integration && npm run test:unit",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --check . && eslint .",
"format": "prettier --write ."
"format": "prettier --write .",
"test:integration": "playwright test",
"test:unit": "vitest"
},
"devDependencies": {
"@playwright/test": "^1.46.1",
"@sveltejs/adapter-auto": "^3.0.0",
"@sveltejs/adapter-node": "^5.2.0",
"@sveltejs/kit": "^2.0.0",

12
playwright.config.ts Normal file
View File

@ -0,0 +1,12 @@
import type { PlaywrightTestConfig } from '@playwright/test';
const config: PlaywrightTestConfig = {
webServer: {
command: 'npm run build && npm run preview',
port: 4173,
},
testDir: 'tests',
testMatch: /(.+\.)?(test|spec)\.[jt]s/,
};
export default config;

View File

@ -1,11 +1,9 @@
import { log, timedExecution } from '$lib';
import { log, timedExecution, requestIdHeader } from '$lib';
import { validate, v7 as uuidv7 } from 'uuid';
import type { Handle } from '@sveltejs/kit';
const requestIdHeader = 'x-request-id';
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
// use incomming requestId, if it is a valid uuid, else generate one
export const handle: Handle = async ({ event, resolve }) => {
// use incoming requestId, if it is a valid uuid, else generate one
const reqIdFromRequest = event.request.headers.get(requestIdHeader);
const { requestId, fromRequest } =
reqIdFromRequest && validate(reqIdFromRequest)
@ -20,15 +18,15 @@ export async function handle({ event, resolve }) {
clientIP: event.getClientAddress(),
};
if (fromRequest) {
log.trace(context, 'using incomming request-id');
log.trace(context, 'using incoming request-id');
}
// make requestId available to handlers
event.locals.requestId = requestId;
const { executionTime, result: response } = await timedExecution(async () => {
return await resolve(event);
});
const { executionTime, result: response } = await timedExecution(
async () => await resolve(event)
);
response.headers.set(requestIdHeader, requestId);
log.info(
@ -42,4 +40,4 @@ export async function handle({ event, resolve }) {
);
return response;
}
};

View File

@ -1,4 +1,4 @@
import safePath from '$lib';
import safePath, { timedExecution } from '$lib';
import { describe, it, expect } from 'vitest';
describe('safe path', () => {
@ -30,3 +30,21 @@ describe('safe path', () => {
expect(safePath('./uplodas', '..foobar..')).toBe(true);
});
});
describe('timedExecution', () => {
const asyncIdentity = async <T>(v: T): Promise<T> => v;
const identity = <T>(v: T): T => v;
it('works with async', async () => {
const { executionTime, result } = await timedExecution(() => asyncIdentity(5));
expect(result).toBe(5);
// execution time is always positive
expect(executionTime).toBeGreaterThanOrEqual(0);
});
it('works with sync', async () => {
const { executionTime, result } = await timedExecution(() => identity(5));
expect(result).toBe(5);
// execution time is always positive
expect(executionTime).toBeGreaterThanOrEqual(0);
});
});

View File

@ -1,7 +1,6 @@
// place files you want to import through the `$lib` alias in this folder.
import path from 'path';
import bunyan from 'bunyan';
import type { MaybePromise } from '@sveltejs/kit';
export const log = bunyan.createLogger({
name: 'fotochallenge',
@ -9,7 +8,7 @@ export const log = bunyan.createLogger({
src: true,
});
function safePath(basePath: string, name: string): boolean {
const safePath = (basePath: string, name: string): boolean => {
const fullPath = `${basePath}/${name}`;
const relative = path.relative(basePath, fullPath);
return (
@ -21,7 +20,9 @@ function safePath(basePath: string, name: string): boolean {
// result is not an absolute path
!path.isAbsolute(relative)
);
}
};
export default safePath;
const defaultPath: string = './uploads';
if (!('STORAGE_PATH' in process.env)) {
@ -29,7 +30,9 @@ if (!('STORAGE_PATH' in process.env)) {
}
export const storagePath: string = process.env.STORAGE_PATH ?? defaultPath;
export default safePath;
export const requestIdHeader = 'x-request-id';
export type MaybePromise<T> = T | Promise<T>;
export async function timedExecution<T>(
fn: () => MaybePromise<T>

View File

@ -0,0 +1,50 @@
import { storagePath } from '$lib';
import { json } from '@sveltejs/kit';
import { stat, access, constants } from 'fs/promises';
import type { RequestHandler } from './$types';
type Status = 'OK' | 'ERROR';
type Result = { status: Status; checks: Checks };
type Checks = { [key: string]: CheckResult };
type CheckResult = true | string;
const fileExists = async (path: string) => !!(await stat(path).catch(() => false));
const isDirectory = async (path: string) =>
!!(await stat(path)
.then((s) => s.isDirectory())
.catch(() => false));
const isWritable = async (path: string) =>
await access(path, constants.W_OK)
.then(() => true)
.catch(() => false);
const checkStoragePath = async (path: string): Promise<CheckResult> => {
if (!fileExists(path)) {
return '`STORAGE_PATH` does not exist';
} else if (!isDirectory(path)) {
return '`STORAGE_PATH` is not a directory';
} else if (!isWritable(path)) {
return '`STORAGE_PATH` is not writable';
}
return true;
};
export const GET: RequestHandler = async () => {
const storagePathResult = await checkStoragePath(storagePath);
const checks: Checks = {
storagePath: storagePathResult,
};
const healthy = Object.values(checks)
.map((r) => (r === true ? true : false))
.reduce((prev, next) => prev && next, true);
const status = healthy ? 'OK' : 'ERROR';
const result: Result = { status, checks };
const httpStatus = healthy ? 200 : 500;
return json(result, { status: httpStatus, headers: { healthy: healthy.toString() } });
};

View File

@ -1,12 +1,12 @@
import { storagePath } from '$lib';
import { json } from '@sveltejs/kit';
import { readdirSync, statSync } from 'fs';
import type { RequestHandler } from './$types';
export function GET() {
const names = readdirSync(storagePath).filter((f) =>
statSync(`${storagePath}/${f}`).isDirectory()
);
names.sort();
export const GET: RequestHandler = () => {
const names = readdirSync(storagePath)
.filter((f) => statSync(`${storagePath}/${f}`).isDirectory())
.toSorted();
return json(names);
}
};

13
tests/health.test.ts Normal file
View File

@ -0,0 +1,13 @@
import { expect, test } from '@playwright/test';
test('healthy test', async ({ playwright }) => {
const context = await playwright.request.newContext();
const response = await context.get('health');
await expect(response.status()).toBe(200);
await expect(response.headers()).toHaveProperty('healthy');
await expect(response.headers()['healthy']).toBe('true');
const body = await response.json();
await expect(body).toHaveProperty('status');
await expect(body['status']).toBe('OK');
});

10
tests/page.test.ts Normal file
View File

@ -0,0 +1,10 @@
import { expect, test } from '@playwright/test';
test('contains header text', async ({ playwright }) => {
const context = await playwright.request.newContext();
const response = await context.get('');
await expect(response.status()).toBe(200);
const body = (await response.body()).toString();
await expect(body).toContain('Gabi und Hannes Fotochallenge');
});

37
tests/requestid.test.ts Normal file
View File

@ -0,0 +1,37 @@
import { expect, test } from '@playwright/test';
import { validate, NIL } from 'uuid';
import { requestIdHeader } from '$lib';
test('response contains request-id header', async ({ playwright }) => {
const context = await playwright.request.newContext();
const response = await context.get('health');
const headers = response.headers();
await expect(headers).toHaveProperty(requestIdHeader);
});
test('request-id is valid uuid', async ({ playwright }) => {
const context = await playwright.request.newContext();
const response = await context.get('health');
const headers = response.headers();
const requestId = headers[requestIdHeader];
await expect(validate(requestId)).toBe(true);
});
test('reuse valid incoming uuid', async ({ playwright }) => {
const context = await playwright.request.newContext();
const response = await context.get('health', { headers: { [requestIdHeader]: NIL } });
const headers = response.headers();
const requestId = headers[requestIdHeader];
await expect(requestId).toBe(NIL);
});
test('ignore invalid incoming uuid', async ({ playwright }) => {
const invalid = '00000000-0000-0000-0000-00000000000z';
const context = await playwright.request.newContext();
const response = await context.get('health', { headers: { [requestIdHeader]: invalid } });
const headers = response.headers();
const requestId = headers[requestIdHeader];
await expect(requestId).not.toBe(invalid);
});