From a5e48e4d63855fdcd94e44e7eae50328629b1064 Mon Sep 17 00:00:00 2001
From: Bradley Shellnut
Date: Mon, 11 Aug 2025 22:38:38 -0700
Subject: [PATCH 1/4] Fixing article errors by adding fetch retry with backoff
and layout level fetches.
---
docker-compose.yaml | 2 +-
package.json | 19 +-
pnpm-lock.yaml | 287 ++++++++++----------
src/lib/api.ts | 302 +++++++++++++--------
src/lib/components/Articles.svelte | 105 ++++---
src/lib/components/ArticlesSkeleton.svelte | 80 ++++++
src/lib/components/ExternalLink.svelte | 34 +--
src/lib/components/Pagination.svelte | 5 +-
src/lib/stores/articleStore.ts | 42 ---
src/lib/util/fetchBandcampAlbums.ts | 6 +-
src/routes/+page.svelte | 2 +-
src/routes/api/articles/+server.ts | 5 +-
src/routes/api/bandcamp/albums/+server.ts | 7 +-
src/routes/articles/+layout.server.ts | 17 ++
src/routes/articles/+layout.svelte | 43 +++
src/routes/articles/[page]/+page.server.ts | 22 +-
src/routes/articles/[page]/+page.svelte | 78 ++++--
svelte.config.js | 2 +
tsconfig.json | 5 +-
19 files changed, 639 insertions(+), 424 deletions(-)
create mode 100644 src/lib/components/ArticlesSkeleton.svelte
delete mode 100644 src/lib/stores/articleStore.ts
create mode 100644 src/routes/articles/+layout.server.ts
create mode 100644 src/routes/articles/+layout.svelte
diff --git a/docker-compose.yaml b/docker-compose.yaml
index 5c6942c..71249aa 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -1,4 +1,3 @@
-version: "3.8"
services:
redis:
image: redis:latest
@@ -7,5 +6,6 @@ services:
- "6379:6379"
volumes:
- redis_data:/data
+ network_mode: host
volumes:
redis_data:
diff --git a/package.json b/package.json
index 0a912bb..9581dc4 100644
--- a/package.json
+++ b/package.json
@@ -18,9 +18,10 @@
},
"devDependencies": {
"@biomejs/biome": "^1.9.4",
- "@playwright/test": "^1.54.1",
+ "@internationalized/date": "^3.8.2",
+ "@playwright/test": "^1.54.2",
"@sveltejs/enhanced-img": "^0.5.1",
- "@sveltejs/kit": "^2.26.1",
+ "@sveltejs/kit": "^2.27.3",
"@sveltejs/vite-plugin-svelte": "^5.1.1",
"@unpic/svelte": "^1.0.0",
"@zerodevx/svelte-img": "^2.1.2",
@@ -33,13 +34,13 @@
"postcss-preset-env": "^10.2.4",
"satori": "^0.12.2",
"satori-html": "^0.3.2",
- "svelte": "^5.37.0",
- "svelte-check": "^4.3.0",
+ "svelte": "^5.38.0",
+ "svelte-check": "^4.3.1",
"svelte-meta-tags": "^4.4.0",
"svelte-preprocess": "^6.0.3",
"svelte-sequential-preprocessor": "^2.0.2",
"tslib": "^2.8.1",
- "typescript": "^5.8.3",
+ "typescript": "^5.9.2",
"vanilla-lazyload": "^19.1.3",
"vite": "^6.3.5",
"vite-imagetools": "^7.1.0",
@@ -47,12 +48,12 @@
},
"dependencies": {
"@resvg/resvg-js": "^2.6.2",
- "@sveltejs/adapter-node": "^5.2.13",
+ "@sveltejs/adapter-node": "^5.2.14",
"@vercel/og": "^0.6.8",
- "bits-ui": "1.4.7",
+ "bits-ui": "2.9.2",
"flexsearch": "^0.8.205",
- "ioredis": "^5.6.1",
- "lucide-svelte": "^0.509.0",
+ "ioredis": "^5.7.0",
+ "lucide-svelte": "^0.539.0",
"scrape-it": "^6.1.11",
"sharp": "^0.34.3",
"svelte-local-storage-store": "^0.6.4"
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index eb53f46..37a48f8 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -12,23 +12,23 @@ importers:
specifier: ^2.6.2
version: 2.6.2
'@sveltejs/adapter-node':
- specifier: ^5.2.13
- version: 5.2.13(@sveltejs/kit@2.26.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.37.0)(vite@6.3.5(yaml@2.7.0)))(svelte@5.37.0)(vite@6.3.5(yaml@2.7.0)))
+ specifier: ^5.2.14
+ version: 5.2.14(@sveltejs/kit@2.27.3(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0)))
'@vercel/og':
specifier: ^0.6.8
version: 0.6.8
bits-ui:
- specifier: 1.4.7
- version: 1.4.7(svelte@5.37.0)
+ specifier: 2.9.2
+ version: 2.9.2(@internationalized/date@3.8.2)(svelte@5.38.0)
flexsearch:
specifier: ^0.8.205
version: 0.8.205
ioredis:
- specifier: ^5.6.1
- version: 5.6.1
+ specifier: ^5.7.0
+ version: 5.7.0
lucide-svelte:
- specifier: ^0.509.0
- version: 0.509.0(svelte@5.37.0)
+ specifier: ^0.539.0
+ version: 0.539.0(svelte@5.38.0)
scrape-it:
specifier: ^6.1.11
version: 6.1.11
@@ -37,29 +37,32 @@ importers:
version: 0.34.3
svelte-local-storage-store:
specifier: ^0.6.4
- version: 0.6.4(svelte@5.37.0)
+ version: 0.6.4(svelte@5.38.0)
devDependencies:
'@biomejs/biome':
specifier: ^1.9.4
version: 1.9.4
+ '@internationalized/date':
+ specifier: ^3.8.2
+ version: 3.8.2
'@playwright/test':
- specifier: ^1.54.1
- version: 1.54.1
+ specifier: ^1.54.2
+ version: 1.54.2
'@sveltejs/enhanced-img':
specifier: ^0.5.1
- version: 0.5.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.37.0)(vite@6.3.5(yaml@2.7.0)))(rollup@4.34.8)(svelte@5.37.0)(vite@6.3.5(yaml@2.7.0))
+ version: 0.5.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0)))(rollup@4.34.8)(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0))
'@sveltejs/kit':
- specifier: ^2.26.1
- version: 2.26.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.37.0)(vite@6.3.5(yaml@2.7.0)))(svelte@5.37.0)(vite@6.3.5(yaml@2.7.0))
+ specifier: ^2.27.3
+ version: 2.27.3(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0))
'@sveltejs/vite-plugin-svelte':
specifier: ^5.1.1
- version: 5.1.1(svelte@5.37.0)(vite@6.3.5(yaml@2.7.0))
+ version: 5.1.1(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0))
'@unpic/svelte':
specifier: ^1.0.0
- version: 1.0.0(svelte@5.37.0)
+ version: 1.0.0(svelte@5.38.0)
'@zerodevx/svelte-img':
specifier: ^2.1.2
- version: 2.1.2(rollup@4.34.8)(svelte@5.37.0)
+ version: 2.1.2(rollup@4.34.8)(svelte@5.38.0)
autoprefixer:
specifier: ^10.4.21
version: 10.4.21(postcss@8.5.6)
@@ -88,17 +91,17 @@ importers:
specifier: ^0.3.2
version: 0.3.2
svelte:
- specifier: ^5.37.0
- version: 5.37.0
+ specifier: ^5.38.0
+ version: 5.38.0
svelte-check:
- specifier: ^4.3.0
- version: 4.3.0(picomatch@4.0.2)(svelte@5.37.0)(typescript@5.8.3)
+ specifier: ^4.3.1
+ version: 4.3.1(picomatch@4.0.2)(svelte@5.38.0)(typescript@5.9.2)
svelte-meta-tags:
specifier: ^4.4.0
- version: 4.4.0(svelte@5.37.0)
+ version: 4.4.0(svelte@5.38.0)
svelte-preprocess:
specifier: ^6.0.3
- version: 6.0.3(postcss-load-config@6.0.1(postcss@8.5.6)(yaml@2.7.0))(postcss@8.5.6)(svelte@5.37.0)(typescript@5.8.3)
+ version: 6.0.3(postcss-load-config@6.0.1(postcss@8.5.6)(yaml@2.7.0))(postcss@8.5.6)(svelte@5.38.0)(typescript@5.9.2)
svelte-sequential-preprocessor:
specifier: ^2.0.2
version: 2.0.2
@@ -106,8 +109,8 @@ importers:
specifier: ^2.8.1
version: 2.8.1
typescript:
- specifier: ^5.8.3
- version: 5.8.3
+ specifier: ^5.9.2
+ version: 5.9.2
vanilla-lazyload:
specifier: ^19.1.3
version: 19.1.3
@@ -594,14 +597,14 @@ packages:
cpu: [x64]
os: [win32]
- '@floating-ui/core@1.7.0':
- resolution: {integrity: sha512-FRdBLykrPPA6P76GGGqlex/e7fbe0F1ykgxHYNXQsH/iTEtjMj/f9bpY5oQqbjt5VgZvgz/uKXbGuROijh3VLA==}
+ '@floating-ui/core@1.7.3':
+ resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==}
- '@floating-ui/dom@1.7.0':
- resolution: {integrity: sha512-lGTor4VlXcesUMh1cupTUTDoCxMb0V6bm3CnxHzQcw8Eaf1jQbgQX4i02fYgT0vJ82tb5MZ4CZk1LRGkktJCzg==}
+ '@floating-ui/dom@1.7.3':
+ resolution: {integrity: sha512-uZA413QEpNuhtb3/iIKoYMSK07keHPYeXF02Zhd6e213j+d1NamLix/mCLxBUDW/Gx52sPH2m+chlUsyaBs/Ag==}
- '@floating-ui/utils@0.2.9':
- resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==}
+ '@floating-ui/utils@0.2.10':
+ resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==}
'@img/sharp-darwin-arm64@0.33.5':
resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==}
@@ -830,11 +833,11 @@ packages:
cpu: [x64]
os: [win32]
- '@internationalized/date@3.8.0':
- resolution: {integrity: sha512-J51AJ0fEL68hE4CwGPa6E0PO6JDaVLd8aln48xFCSy7CZkZc96dGEGmLs2OEEbBxcsVZtfrqkXJwI2/MSG8yKw==}
+ '@internationalized/date@3.8.2':
+ resolution: {integrity: sha512-/wENk7CbvLbkUvX1tu0mwq49CVkkWpkXubGel6birjRPyo6uQ4nQpnq5xZu823zRCwwn82zgHrvgF1vZyvmVgA==}
- '@ioredis/commands@1.2.0':
- resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==}
+ '@ioredis/commands@1.3.0':
+ resolution: {integrity: sha512-M/T6Zewn7sDaBQEqIZ8Rb+i9y8qfGmq+5SDFSf9sA2lUZTmdDLVdOiQaeDp+Q4wElZ9HG1GAX5KhDaidp6LQsQ==}
'@jridgewell/gen-mapping@0.3.8':
resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==}
@@ -854,8 +857,8 @@ packages:
'@jridgewell/trace-mapping@0.3.25':
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
- '@playwright/test@1.54.1':
- resolution: {integrity: sha512-FS8hQ12acieG2dYSksmLOF7BNxnVf2afRJdCuM1eMSxj6QTSE6G4InGF7oApGgDb65MX7AwMVlIkpru0yZA4Xw==}
+ '@playwright/test@1.54.2':
+ resolution: {integrity: sha512-A+znathYxPf+72riFd1r1ovOLqsIIB0jKIoPjyK2kqEIe30/6jF6BC7QNluHuwUmsD2tv1XZVugN8GqfTMOxsA==}
engines: {node: '>=18'}
hasBin: true
@@ -1178,13 +1181,16 @@ packages:
engines: {node: '>= 8.0.0'}
hasBin: true
+ '@standard-schema/spec@1.0.0':
+ resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==}
+
'@sveltejs/acorn-typescript@1.0.5':
resolution: {integrity: sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==}
peerDependencies:
acorn: ^8.9.0
- '@sveltejs/adapter-node@5.2.13':
- resolution: {integrity: sha512-yS2TVFmIrxjGhYaV5/iIUrJ3mJl6zjaYn0lBD70vTLnYvJeqf3cjvLXeXCUCuYinhSBoyF4DpfGla49BnIy7sQ==}
+ '@sveltejs/adapter-node@5.2.14':
+ resolution: {integrity: sha512-TjJvfw0HZlbBGGAW2vFtdGjdKhqpGW3ZDIz0nzy8Zx6Ki6oFmYTjV5Kwn3LWTsyjbsUSXhfFPCuYop3z1iS9qQ==}
peerDependencies:
'@sveltejs/kit': ^2.4.0
@@ -1195,8 +1201,8 @@ packages:
svelte: ^5.0.0
vite: '>= 5.0.0'
- '@sveltejs/kit@2.26.1':
- resolution: {integrity: sha512-FwDhHAoXYUGnYndrrEzEYcKdYWpSoRKq4kli29oMe83hLri4/DOGQk3xUgwjDo0LKpSmj5M/Sj29/Ug3wO0Cbg==}
+ '@sveltejs/kit@2.27.3':
+ resolution: {integrity: sha512-jiG3NGZ8RRpi+ncjVnX+oR7uWEgzy//3YLGcTU5mHtjGraeGyNDr7GJFHlk7z0vi8bMXpXIUkEXj6p70FJmHvw==}
engines: {node: '>=18.13'}
hasBin: true
peerDependencies:
@@ -1331,11 +1337,12 @@ packages:
resolution: {integrity: sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==}
engines: {node: '>= 0.4'}
- bits-ui@1.4.7:
- resolution: {integrity: sha512-oqfSbgB/2Nc3qwOvohkRzw0nQcUKsNPwthD4uzy9E21wSbhc00RDcZqCJmFrrcW336J+aStM1sITsVGQFjT+iw==}
- engines: {node: '>=18', pnpm: '>=8.7.0'}
+ bits-ui@2.9.2:
+ resolution: {integrity: sha512-GGbyr4oVKtHin//Q0AhlygkasmfWt328VjsnmB3sP+h8Sh+Eyghm+1AQ8o+xQMDCYbdL35JZ9UZGTZYTMar4Uw==}
+ engines: {node: '>=20'}
peerDependencies:
- svelte: ^5.11.0
+ '@internationalized/date': ^3.8.1
+ svelte: ^5.33.0
boolbase@1.0.0:
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
@@ -1361,11 +1368,8 @@ packages:
camelize@1.0.1:
resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==}
- caniuse-lite@1.0.30001706:
- resolution: {integrity: sha512-3ZczoTApMAZwPKYWmwVbQMFpXBDds3/0VciVoUwPUbldlYyVLmRVuRs/PcUZtHpbLRpzzDvrvnFuREsGt6lUug==}
-
- caniuse-lite@1.0.30001727:
- resolution: {integrity: sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==}
+ caniuse-lite@1.0.30001731:
+ resolution: {integrity: sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg==}
chai@5.2.0:
resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==}
@@ -1722,8 +1726,8 @@ packages:
inline-style-parser@0.2.4:
resolution: {integrity: sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==}
- ioredis@5.6.1:
- resolution: {integrity: sha512-UxC0Yv1Y4WRJiGQxQkP0hfdL0/5/6YvdfOOClRgJ0qppSarkhneSa6UvkMkms0AkdGimSH3Ikqm+6mkMmX7vGA==}
+ ioredis@5.7.0:
+ resolution: {integrity: sha512-NUcA93i1lukyXU+riqEyPtSEkyFq8tX90uL659J+qpCZ3rEdViB/APC58oAhIh3+bJln2hzdlZbBZsGNrlsR8g==}
engines: {node: '>=12.22.0'}
is-arrayish@0.3.2:
@@ -1780,8 +1784,8 @@ packages:
loupe@3.2.0:
resolution: {integrity: sha512-2NCfZcT5VGVNX9mSZIxLRkEAegDGBpuQZBy13desuHeVORmBDyAET4TkJr4SjqQy3A8JDofMN6LpkK8Xcm/dlw==}
- lucide-svelte@0.509.0:
- resolution: {integrity: sha512-6U83jZ0RKvLYLGdx/hTqZyWcquwApQ2Q1E5bKFELXtOw7g8dk1P0qwbAQqs1fqWAtpNevtXTpgShHv/yWAcbjQ==}
+ lucide-svelte@0.539.0:
+ resolution: {integrity: sha512-p4k3GOje/9Si1eIkg1W1OQUhozeja5Ka5shjVpfyP5X2ye+B7sfyMnX3d5D2et+MYJwUFGrMna5MIYgq6bLfqw==}
peerDependencies:
svelte: ^3 || ^4 || ^5.0.0-next.42
@@ -1878,13 +1882,13 @@ packages:
resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
engines: {node: '>=0.10.0'}
- playwright-core@1.54.1:
- resolution: {integrity: sha512-Nbjs2zjj0htNhzgiy5wu+3w09YetDx5pkrpI/kZotDlDUaYk0HVA5xrBVPdow4SAUIlhgKcJeJg4GRKW6xHusA==}
+ playwright-core@1.54.2:
+ resolution: {integrity: sha512-n5r4HFbMmWsB4twG7tJLDN9gmBUeSPcsBZiWSE4DnYz9mJMAFqr2ID7+eGC9kpEnxExJ1epttwR59LEWCk8mtA==}
engines: {node: '>=18'}
hasBin: true
- playwright@1.54.1:
- resolution: {integrity: sha512-peWpSwIBmSLi6aW2auvrUtf2DqY16YYcCMO8rTVx486jKmDTJg7UAhyrraP98GB8BoPURZP8+nxO7TSd4cPr5g==}
+ playwright@1.54.2:
+ resolution: {integrity: sha512-Hu/BMoA1NAdRUuulyvQC0pEqZ4vQbGfn8f7wPXcnqQmM+zct9UliKxsIkLNmz/ku7LElUNqmaiv1TG/aL5ACsw==}
engines: {node: '>=18'}
hasBin: true
@@ -2112,8 +2116,8 @@ packages:
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
- runed@0.23.4:
- resolution: {integrity: sha512-9q8oUiBYeXIDLWNK5DfCWlkL0EW3oGbk845VdKlPeia28l751VpfesaB/+7pI6rnbx1I6rqoZ2fZxptOJLxILA==}
+ runed@0.29.2:
+ resolution: {integrity: sha512-0cq6cA6sYGZwl/FvVqjx9YN+1xEBu9sDDyuWdDW1yWX7JF2wmvmVKfH+hVCZs+csW+P3ARH92MjI3H9QTagOQA==}
peerDependencies:
svelte: ^5.7.0
@@ -2191,15 +2195,15 @@ packages:
style-object-to-css-string@1.1.3:
resolution: {integrity: sha512-bISQoUsir/qGfo7vY8rw00ia9nnyE1jvYt3zZ2jhdkcXZ6dAEi74inMzQ6On57vFI+I4Fck6wOv5UI9BEwJDgw==}
- style-to-object@1.0.8:
- resolution: {integrity: sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g==}
+ style-to-object@1.0.9:
+ resolution: {integrity: sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw==}
supports-preserve-symlinks-flag@1.0.0:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
- svelte-check@4.3.0:
- resolution: {integrity: sha512-Iz8dFXzBNAM7XlEIsUjUGQhbEE+Pvv9odb9+0+ITTgFWZBGeJRRYqHUUglwe2EkLD5LIsQaAc4IUJyvtKuOO5w==}
+ svelte-check@4.3.1:
+ resolution: {integrity: sha512-lkh8gff5gpHLjxIV+IaApMxQhTGnir2pNUAqcNgeKkvK5bT/30Ey/nzBxNLDlkztCH4dP7PixkMt9SWEKFPBWg==}
engines: {node: '>= 18.0.0'}
hasBin: true
peerDependencies:
@@ -2263,18 +2267,18 @@ packages:
resolution: {integrity: sha512-DIFm0kSNscVxtBmKkBiygAHB5otoqN1aVmJ3t57jZhJfCB7Np/lUSoTtSrvPFjmlBbMeOsb1VQ06cut1+rBYOg==}
engines: {node: '>=16'}
- svelte-toolbelt@0.7.1:
- resolution: {integrity: sha512-HcBOcR17Vx9bjaOceUvxkY3nGmbBmCBBbuWLLEWO6jtmWH8f/QoWmbyUfQZrpDINH39en1b8mptfPQT9VKQ1xQ==}
+ svelte-toolbelt@0.9.3:
+ resolution: {integrity: sha512-HCSWxCtVmv+c6g1ACb8LTwHVbDqLKJvHpo6J8TaqwUme2hj9ATJCpjCPNISR1OCq2Q4U1KT41if9ON0isINQZw==}
engines: {node: '>=18', pnpm: '>=8.7.0'}
peerDependencies:
- svelte: ^5.0.0
+ svelte: ^5.30.2
svelte@4.2.20:
resolution: {integrity: sha512-eeEgGc2DtiUil5ANdtd8vPwt9AgaMdnuUFnPft9F5oMvU/FHu5IHFic+p1dR/UOB7XU2mX2yHW+NcTch4DCh5Q==}
engines: {node: '>=16'}
- svelte@5.37.0:
- resolution: {integrity: sha512-BAHgWdKncZ4F1DVBrkKAvelx2Nv3mR032ca8/yj9Gxf5s9zzK1uGXiZTjCFDvmO2e9KQfcR2lEkVjw+ZxExJow==}
+ svelte@5.38.0:
+ resolution: {integrity: sha512-cWF1Oc2IM/QbktdK89u5lt9MdKxRtQnRKnf2tq6KOhYuhLOd2hbMuTiJ+vWMzAeMDe81AzbCgLd4GVtOJ4fDRg==}
engines: {node: '>=18'}
tabbable@6.2.0:
@@ -2319,8 +2323,8 @@ packages:
tslib@2.8.1:
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
- typescript@5.8.3:
- resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==}
+ typescript@5.9.2:
+ resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==}
engines: {node: '>=14.17'}
hasBin: true
@@ -2853,16 +2857,16 @@ snapshots:
'@esbuild/win32-x64@0.25.4':
optional: true
- '@floating-ui/core@1.7.0':
+ '@floating-ui/core@1.7.3':
dependencies:
- '@floating-ui/utils': 0.2.9
+ '@floating-ui/utils': 0.2.10
- '@floating-ui/dom@1.7.0':
+ '@floating-ui/dom@1.7.3':
dependencies:
- '@floating-ui/core': 1.7.0
- '@floating-ui/utils': 0.2.9
+ '@floating-ui/core': 1.7.3
+ '@floating-ui/utils': 0.2.10
- '@floating-ui/utils@0.2.9': {}
+ '@floating-ui/utils@0.2.10': {}
'@img/sharp-darwin-arm64@0.33.5':
optionalDependencies:
@@ -3025,11 +3029,11 @@ snapshots:
'@img/sharp-win32-x64@0.34.3':
optional: true
- '@internationalized/date@3.8.0':
+ '@internationalized/date@3.8.2':
dependencies:
'@swc/helpers': 0.5.17
- '@ioredis/commands@1.2.0': {}
+ '@ioredis/commands@1.3.0': {}
'@jridgewell/gen-mapping@0.3.8':
dependencies:
@@ -3048,9 +3052,9 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.0
- '@playwright/test@1.54.1':
+ '@playwright/test@1.54.2':
dependencies:
- playwright: 1.54.1
+ playwright: 1.54.2
'@polka/url@1.0.0-next.29': {}
@@ -3265,6 +3269,8 @@ snapshots:
fflate: 0.7.4
string.prototype.codepointat: 0.2.1
+ '@standard-schema/spec@1.0.0': {}
+
'@sveltejs/acorn-typescript@1.0.5(acorn@8.14.1)':
dependencies:
acorn: 8.14.1
@@ -3273,31 +3279,32 @@ snapshots:
dependencies:
acorn: 8.15.0
- '@sveltejs/adapter-node@5.2.13(@sveltejs/kit@2.26.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.37.0)(vite@6.3.5(yaml@2.7.0)))(svelte@5.37.0)(vite@6.3.5(yaml@2.7.0)))':
+ '@sveltejs/adapter-node@5.2.14(@sveltejs/kit@2.27.3(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0)))':
dependencies:
'@rollup/plugin-commonjs': 28.0.2(rollup@4.34.8)
'@rollup/plugin-json': 6.1.0(rollup@4.34.8)
'@rollup/plugin-node-resolve': 16.0.0(rollup@4.34.8)
- '@sveltejs/kit': 2.26.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.37.0)(vite@6.3.5(yaml@2.7.0)))(svelte@5.37.0)(vite@6.3.5(yaml@2.7.0))
+ '@sveltejs/kit': 2.27.3(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0))
rollup: 4.34.8
- '@sveltejs/enhanced-img@0.5.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.37.0)(vite@6.3.5(yaml@2.7.0)))(rollup@4.34.8)(svelte@5.37.0)(vite@6.3.5(yaml@2.7.0))':
+ '@sveltejs/enhanced-img@0.5.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0)))(rollup@4.34.8)(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0))':
dependencies:
- '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.37.0)(vite@6.3.5(yaml@2.7.0))
+ '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0))
magic-string: 0.30.17
sharp: 0.34.3
- svelte: 5.37.0
- svelte-parse-markup: 0.1.5(svelte@5.37.0)
+ svelte: 5.38.0
+ svelte-parse-markup: 0.1.5(svelte@5.38.0)
vite: 6.3.5(yaml@2.7.0)
vite-imagetools: 7.1.0(rollup@4.34.8)
zimmerframe: 1.1.2
transitivePeerDependencies:
- rollup
- '@sveltejs/kit@2.26.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.37.0)(vite@6.3.5(yaml@2.7.0)))(svelte@5.37.0)(vite@6.3.5(yaml@2.7.0))':
+ '@sveltejs/kit@2.27.3(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0))':
dependencies:
+ '@standard-schema/spec': 1.0.0
'@sveltejs/acorn-typescript': 1.0.5(acorn@8.15.0)
- '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.37.0)(vite@6.3.5(yaml@2.7.0))
+ '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0))
'@types/cookie': 0.6.0
acorn: 8.15.0
cookie: 0.6.0
@@ -3309,26 +3316,26 @@ snapshots:
sade: 1.8.1
set-cookie-parser: 2.7.1
sirv: 3.0.1
- svelte: 5.37.0
+ svelte: 5.38.0
vite: 6.3.5(yaml@2.7.0)
- '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.37.0)(vite@6.3.5(yaml@2.7.0)))(svelte@5.37.0)(vite@6.3.5(yaml@2.7.0))':
+ '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0))':
dependencies:
- '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.37.0)(vite@6.3.5(yaml@2.7.0))
+ '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0))
debug: 4.4.1
- svelte: 5.37.0
+ svelte: 5.38.0
vite: 6.3.5(yaml@2.7.0)
transitivePeerDependencies:
- supports-color
- '@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.37.0)(vite@6.3.5(yaml@2.7.0))':
+ '@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0))':
dependencies:
- '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.37.0)(vite@6.3.5(yaml@2.7.0)))(svelte@5.37.0)(vite@6.3.5(yaml@2.7.0))
+ '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0))
debug: 4.4.1
deepmerge: 4.3.1
kleur: 4.1.5
magic-string: 0.30.17
- svelte: 5.37.0
+ svelte: 5.38.0
vite: 6.3.5(yaml@2.7.0)
vitefu: 1.1.1(vite@6.3.5(yaml@2.7.0))
transitivePeerDependencies:
@@ -3356,11 +3363,11 @@ snapshots:
dependencies:
unpic: 4.1.2
- '@unpic/svelte@1.0.0(svelte@5.37.0)':
+ '@unpic/svelte@1.0.0(svelte@5.38.0)':
dependencies:
'@unpic/core': 1.0.1
style-object-to-css-string: 1.1.3
- svelte: 5.37.0
+ svelte: 5.38.0
'@vercel/og@0.6.8':
dependencies:
@@ -3410,9 +3417,9 @@ snapshots:
loupe: 3.2.0
tinyrainbow: 2.0.0
- '@zerodevx/svelte-img@2.1.2(rollup@4.34.8)(svelte@5.37.0)':
+ '@zerodevx/svelte-img@2.1.2(rollup@4.34.8)(svelte@5.38.0)':
dependencies:
- svelte: 5.37.0
+ svelte: 5.38.0
vite-imagetools: 6.2.9(rollup@4.34.8)
transitivePeerDependencies:
- rollup
@@ -3435,7 +3442,7 @@ snapshots:
autoprefixer@10.4.21(postcss@8.5.6):
dependencies:
browserslist: 4.24.4
- caniuse-lite: 1.0.30001706
+ caniuse-lite: 1.0.30001731
fraction.js: 4.3.7
normalize-range: 0.1.2
picocolors: 1.1.1
@@ -3460,29 +3467,29 @@ snapshots:
base64-js@0.0.8: {}
- bits-ui@1.4.7(svelte@5.37.0):
+ bits-ui@2.9.2(@internationalized/date@3.8.2)(svelte@5.38.0):
dependencies:
- '@floating-ui/core': 1.7.0
- '@floating-ui/dom': 1.7.0
- '@internationalized/date': 3.8.0
+ '@floating-ui/core': 1.7.3
+ '@floating-ui/dom': 1.7.3
+ '@internationalized/date': 3.8.2
esm-env: 1.2.2
- runed: 0.23.4(svelte@5.37.0)
- svelte: 5.37.0
- svelte-toolbelt: 0.7.1(svelte@5.37.0)
+ runed: 0.29.2(svelte@5.38.0)
+ svelte: 5.38.0
+ svelte-toolbelt: 0.9.3(svelte@5.38.0)
tabbable: 6.2.0
boolbase@1.0.0: {}
browserslist@4.24.4:
dependencies:
- caniuse-lite: 1.0.30001706
+ caniuse-lite: 1.0.30001731
electron-to-chromium: 1.5.120
node-releases: 2.0.19
update-browserslist-db: 1.1.3(browserslist@4.24.4)
browserslist@4.25.1:
dependencies:
- caniuse-lite: 1.0.30001727
+ caniuse-lite: 1.0.30001731
electron-to-chromium: 1.5.191
node-releases: 2.0.19
update-browserslist-db: 1.1.3(browserslist@4.25.1)
@@ -3496,9 +3503,7 @@ snapshots:
camelize@1.0.1: {}
- caniuse-lite@1.0.30001706: {}
-
- caniuse-lite@1.0.30001727: {}
+ caniuse-lite@1.0.30001731: {}
chai@5.2.0:
dependencies:
@@ -3853,9 +3858,9 @@ snapshots:
inline-style-parser@0.2.4: {}
- ioredis@5.6.1:
+ ioredis@5.7.0:
dependencies:
- '@ioredis/commands': 1.2.0
+ '@ioredis/commands': 1.3.0
cluster-key-slot: 1.1.2
debug: 4.4.0
denque: 2.1.0
@@ -3910,9 +3915,9 @@ snapshots:
loupe@3.2.0: {}
- lucide-svelte@0.509.0(svelte@5.37.0):
+ lucide-svelte@0.539.0(svelte@5.38.0):
dependencies:
- svelte: 5.37.0
+ svelte: 5.38.0
magic-string@0.30.17:
dependencies:
@@ -3990,11 +3995,11 @@ snapshots:
pify@2.3.0: {}
- playwright-core@1.54.1: {}
+ playwright-core@1.54.2: {}
- playwright@1.54.1:
+ playwright@1.54.2:
dependencies:
- playwright-core: 1.54.1
+ playwright-core: 1.54.2
optionalDependencies:
fsevents: 2.3.2
@@ -4311,10 +4316,10 @@ snapshots:
'@rollup/rollup-win32-x64-msvc': 4.40.2
fsevents: 2.3.3
- runed@0.23.4(svelte@5.37.0):
+ runed@0.29.2(svelte@5.38.0):
dependencies:
esm-env: 1.2.2
- svelte: 5.37.0
+ svelte: 5.38.0
sade@1.8.1:
dependencies:
@@ -4450,56 +4455,56 @@ snapshots:
style-object-to-css-string@1.1.3: {}
- style-to-object@1.0.8:
+ style-to-object@1.0.9:
dependencies:
inline-style-parser: 0.2.4
supports-preserve-symlinks-flag@1.0.0: {}
- svelte-check@4.3.0(picomatch@4.0.2)(svelte@5.37.0)(typescript@5.8.3):
+ svelte-check@4.3.1(picomatch@4.0.2)(svelte@5.38.0)(typescript@5.9.2):
dependencies:
'@jridgewell/trace-mapping': 0.3.25
chokidar: 4.0.3
fdir: 6.4.4(picomatch@4.0.2)
picocolors: 1.1.1
sade: 1.8.1
- svelte: 5.37.0
- typescript: 5.8.3
+ svelte: 5.38.0
+ typescript: 5.9.2
transitivePeerDependencies:
- picomatch
- svelte-local-storage-store@0.6.4(svelte@5.37.0):
+ svelte-local-storage-store@0.6.4(svelte@5.38.0):
dependencies:
- svelte: 5.37.0
+ svelte: 5.38.0
- svelte-meta-tags@4.4.0(svelte@5.37.0):
+ svelte-meta-tags@4.4.0(svelte@5.38.0):
dependencies:
schema-dts: 1.1.5
- svelte: 5.37.0
+ svelte: 5.38.0
- svelte-parse-markup@0.1.5(svelte@5.37.0):
+ svelte-parse-markup@0.1.5(svelte@5.38.0):
dependencies:
- svelte: 5.37.0
+ svelte: 5.38.0
- svelte-preprocess@6.0.3(postcss-load-config@6.0.1(postcss@8.5.6)(yaml@2.7.0))(postcss@8.5.6)(svelte@5.37.0)(typescript@5.8.3):
+ svelte-preprocess@6.0.3(postcss-load-config@6.0.1(postcss@8.5.6)(yaml@2.7.0))(postcss@8.5.6)(svelte@5.38.0)(typescript@5.9.2):
dependencies:
- svelte: 5.37.0
+ svelte: 5.38.0
optionalDependencies:
postcss: 8.5.6
postcss-load-config: 6.0.1(postcss@8.5.6)(yaml@2.7.0)
- typescript: 5.8.3
+ typescript: 5.9.2
svelte-sequential-preprocessor@2.0.2:
dependencies:
svelte: 4.2.20
tslib: 2.7.0
- svelte-toolbelt@0.7.1(svelte@5.37.0):
+ svelte-toolbelt@0.9.3(svelte@5.38.0):
dependencies:
clsx: 2.1.1
- runed: 0.23.4(svelte@5.37.0)
- style-to-object: 1.0.8
- svelte: 5.37.0
+ runed: 0.29.2(svelte@5.38.0)
+ style-to-object: 1.0.9
+ svelte: 5.38.0
svelte@4.2.20:
dependencies:
@@ -4518,7 +4523,7 @@ snapshots:
magic-string: 0.30.17
periscopic: 3.1.0
- svelte@5.37.0:
+ svelte@5.38.0:
dependencies:
'@ampproject/remapping': 2.3.0
'@jridgewell/sourcemap-codec': 1.5.0
@@ -4565,7 +4570,7 @@ snapshots:
tslib@2.8.1: {}
- typescript@5.8.3: {}
+ typescript@5.9.2: {}
typpy@2.4.0:
dependencies:
diff --git a/src/lib/api.ts b/src/lib/api.ts
index c3186c5..1b2f3e9 100644
--- a/src/lib/api.ts
+++ b/src/lib/api.ts
@@ -1,144 +1,222 @@
import {
- WALLABAG_CLIENT_ID,
- WALLABAG_CLIENT_SECRET,
- WALLABAG_USERNAME,
- WALLABAG_PASSWORD,
- WALLABAG_URL,
PAGE_SIZE,
USE_REDIS_CACHE,
+ WALLABAG_CLIENT_ID,
+ WALLABAG_CLIENT_SECRET,
+ WALLABAG_PASSWORD,
+ WALLABAG_URL,
+ WALLABAG_USERNAME,
} from "$env/static/private";
-import intersect from "just-intersect";
+import { redis } from "$lib/server/redis";
import type {
Article,
ArticlePageLoad,
WallabagArticle,
} from "$lib/types/article";
import { ArticleTag } from "$lib/types/articleTag";
+import intersect from "just-intersect";
import type { PageQuery } from "./types/pageQuery";
-import { URLSearchParams } from "node:url";
-import { redis } from "$lib/server/redis";
const base: string = WALLABAG_URL;
+// Retry helper with exponential backoff
+async function retryWithBackoff(
+ fn: () => Promise,
+ maxRetries = 3,
+ baseDelay = 500
+): Promise {
+ let lastError: Error | undefined;
+
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
+ try {
+ return await fn();
+ } catch (error) {
+ lastError = error as Error;
+
+ if (attempt === maxRetries) {
+ throw lastError;
+ }
+
+ // Exponential backoff: 500ms, 1s, 2s
+ const delay = baseDelay * (2 ** attempt);
+ console.log(`Attempt ${attempt + 1} failed, retrying in ${delay}ms...`);
+ await new Promise(resolve => setTimeout(resolve, delay));
+ }
+ }
+
+ throw lastError;
+}
+
export async function fetchArticlesApi(
method: string,
resource: string,
queryParams: Record
) {
- let perPage = Number(queryParams?.limit);
- if (perPage > 30) {
- perPage = Number(PAGE_SIZE);
- } else {
- perPage = Number(queryParams?.limit);
- }
-
- const pageQuery: PageQuery = {
- sort: "updated",
- perPage,
- since: 0,
- page: Number(queryParams?.page) || 1,
- tags: "programming",
- content: "metadata",
- };
- const entriesQueryParams = new URLSearchParams({
- ...pageQuery,
- perPage: `${pageQuery.perPage}`,
- since: `${pageQuery.since}`,
- page: `${pageQuery.page}`,
- });
-
- if (USE_REDIS_CACHE) {
- console.log('Using redis cache');
- const cached = await redis.get(entriesQueryParams.toString());
-
- if (cached) {
- console.log("Cache hit!");
- const response = JSON.parse(cached);
- const ttl = await redis.ttl(entriesQueryParams.toString());
-
- console.log(`Response ${JSON.stringify(response)}`);
- console.log(`Returning cached response with ttl of ${ttl} seconds`);
- return { ...response, cacheControl: `max-age=${ttl}` };
+ try {
+ let perPage = Number(queryParams?.limit);
+ if (perPage === undefined || perPage > 30 || perPage < 1) {
+ perPage = Number(PAGE_SIZE);
+ } else {
+ perPage = Number(queryParams?.limit);
}
- }
- const authBody = {
- grant_type: "password",
- client_id: WALLABAG_CLIENT_ID,
- client_secret: WALLABAG_CLIENT_SECRET,
- username: WALLABAG_USERNAME,
- password: WALLABAG_PASSWORD,
- };
+ const pageQuery: PageQuery = {
+ sort: "updated",
+ perPage,
+ since: 0,
+ page: Number(queryParams?.page) || 1,
+ tags: "programming",
+ content: "metadata",
+ };
+ const entriesQueryParams = new URLSearchParams({
+ sort: pageQuery.sort,
+ perPage: `${pageQuery.perPage}`,
+ since: `${pageQuery.since}`,
+ page: `${pageQuery.page}`,
+ tags: pageQuery.tags,
+ content: pageQuery.content,
+ });
- const authResponse = await fetch(`${base}/oauth/v2/token`, {
- method: "POST",
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
- body: new URLSearchParams(authBody),
- });
+ if (USE_REDIS_CACHE === 'true') {
+ console.log('Using redis cache');
+ const cacheKey = entriesQueryParams.toString();
+ console.log(`Cache key: ${cacheKey}`);
+ const cached = await redis.get(cacheKey);
- const auth = await authResponse.json();
+ if (cached) {
+ console.log("Cache hit!");
+ const response = JSON.parse(cached);
+ const ttl = await redis.ttl(cacheKey);
- const pageResponse = await fetch(
- `${WALLABAG_URL}/api/entries.json?${entriesQueryParams}`,
- {
- method: "GET",
- headers: {
- Authorization: `Bearer ${auth.access_token}`,
- },
+ console.log(`Returning cached response for page ${pageQuery.page} with ttl of ${ttl} seconds`);
+ console.log(`Response: ${JSON.stringify(response)}`);
+ return { ...response, cacheControl: `max-age=${ttl}` };
+ }
+ console.log(`Cache miss for page ${pageQuery.page}, fetching from API`);
}
- );
- if (!pageResponse.ok) {
- throw new Error(pageResponse.statusText);
- }
+ const authBody = {
+ grant_type: "password",
+ client_id: WALLABAG_CLIENT_ID,
+ client_secret: WALLABAG_CLIENT_SECRET,
+ username: WALLABAG_USERNAME,
+ password: WALLABAG_PASSWORD,
+ };
- const cacheControl = pageResponse.headers.get("cache-control") || "no-cache";
+ console.log(`Auth body: ${JSON.stringify(authBody)}`);
- const {
- _embedded: favoriteArticles,
- page,
- pages,
- total,
- limit,
- } = await pageResponse.json();
- const articles: Article[] = [];
-
- for (const article of favoriteArticles.items as WallabagArticle[]) {
- const rawTags = article?.tags?.map((tag) => tag.slug);
- if (intersect(rawTags, Object.values(ArticleTag))?.length > 0) {
- const tags = rawTags.map((rawTag) => rawTag as unknown as ArticleTag);
- articles.push({
- tags,
- title: article.title,
- url: new URL(article.url),
- domain_name: article.domain_name?.replace("www.", "") ?? "",
- hashed_url: article.hashed_url,
- reading_time: article.reading_time,
- preview_picture: article.preview_picture,
- created_at: new Date(article.created_at),
- updated_at: new Date(article.updated_at),
- archived_at: article.archived_at ? new Date(article.archived_at) : null,
+ const auth = await retryWithBackoff(async () => {
+ const authResponse = await fetch(`${base}/oauth/v2/token`, {
+ method: "POST",
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
+ body: new URLSearchParams(authBody),
+ signal: AbortSignal.timeout(10000), // 10 second timeout
});
+
+ if (!authResponse.ok) {
+ throw new Error(`Auth failed: ${authResponse.status} ${authResponse.statusText}`);
+ }
+
+ return await authResponse.json();
+ });
+
+ console.log(`Got auth response: ${JSON.stringify(auth)}`);
+
+ const { wallabagResponse, cacheControl } = await retryWithBackoff(async () => {
+ const pageResponse = await fetch(
+ `${WALLABAG_URL}/api/entries.json?${entriesQueryParams}`,
+ {
+ method: "GET",
+ headers: {
+ Authorization: `Bearer ${auth.access_token}`,
+ },
+ signal: AbortSignal.timeout(15000), // 15 second timeout
+ }
+ );
+
+ console.log('pageResponse', pageResponse);
+
+ if (!pageResponse.ok) {
+ console.log('pageResponse not ok', pageResponse);
+ throw new Error(`API request failed: ${pageResponse.status} ${pageResponse.statusText}`);
+ }
+
+ const cacheControl = pageResponse.headers.get("cache-control") || "no-cache";
+ const wallabagResponse = await pageResponse.json();
+
+ return { wallabagResponse, cacheControl };
+ });
+ console.log('wallabagResponse', JSON.stringify(wallabagResponse));
+ const {
+ _embedded: favoriteArticles,
+ page,
+ pages,
+ total,
+ limit,
+ } = wallabagResponse;
+ const articles: Article[] = [];
+
+ console.log('favoriteArticles', JSON.stringify(favoriteArticles));
+ console.log('pages', pages);
+ console.log('page', page);
+ console.log('total', total);
+ console.log('limit', limit);
+
+ for (const article of favoriteArticles.items as WallabagArticle[]) {
+ const rawTags = article?.tags?.map((tag) => tag.slug);
+ if (intersect(rawTags, Object.values(ArticleTag))?.length > 0) {
+ const tags = rawTags.map((rawTag) => rawTag as unknown as ArticleTag);
+ articles.push({
+ tags,
+ title: article.title,
+ url: new URL(article.url),
+ domain_name: article.domain_name?.replace("www.", "") ?? "",
+ hashed_url: article.hashed_url,
+ reading_time: article.reading_time,
+ preview_picture: article.preview_picture,
+ created_at: new Date(article.created_at),
+ updated_at: new Date(article.updated_at),
+ archived_at: article.archived_at ? new Date(article.archived_at) : null,
+ });
+ }
}
+
+ const responseData: ArticlePageLoad = {
+ articles,
+ currentPage: page,
+ totalPages: pages,
+ limit,
+ totalArticles: total,
+ cacheControl,
+ };
+
+ console.log('Response data from API: ', JSON.stringify(responseData))
+
+ if (USE_REDIS_CACHE === 'true' && responseData?.articles?.length > 0) {
+ const cacheKey = entriesQueryParams.toString();
+ console.log(`Storing in cache with key: ${cacheKey} for page ${page}`);
+ redis.set(
+ cacheKey,
+ JSON.stringify(responseData),
+ "EX",
+ 43200
+ );
+ }
+
+ return responseData;
+ } catch (error) {
+ console.error(`Error fetching articles for page ${queryParams?.page}:`, error);
+
+ // Return empty response on error to prevent app crash
+ const fallbackResponse: ArticlePageLoad = {
+ articles: [],
+ currentPage: Number(queryParams?.page) || 1,
+ totalPages: 0,
+ limit: Number(queryParams?.limit) || Number(PAGE_SIZE),
+ totalArticles: 0,
+ cacheControl: 'no-cache',
+ };
+
+ return fallbackResponse;
}
-
- const responseData: ArticlePageLoad = {
- articles,
- currentPage: page,
- totalPages: pages,
- limit,
- totalArticles: total,
- cacheControl,
- };
-
- if (USE_REDIS_CACHE) {
- redis.set(
- entriesQueryParams.toString(),
- JSON.stringify(responseData),
- "EX",
- 43200
- );
- }
-
- return responseData;
}
diff --git a/src/lib/components/Articles.svelte b/src/lib/components/Articles.svelte
index 5844697..729c221 100644
--- a/src/lib/components/Articles.svelte
+++ b/src/lib/components/Articles.svelte
@@ -1,51 +1,78 @@
Favorite Articles
- {#each articles as article (article.hashed_url)}
-
-
-
-
-
- {article.domain_name}
-
-
- Reading time: {article.reading_time} minutes
-
-
-
- {/each}
+
+ {#each articlesData as article (article.hashed_url)}
+
+
+
+
+
+ {article.domain_name}
+
+
+ Reading time: {article.reading_time} minutes
+
+
+
+ {/each}
+
{`${totalArticles} more articles`}
diff --git a/src/lib/components/ArticlesSkeleton.svelte b/src/lib/components/ArticlesSkeleton.svelte
new file mode 100644
index 0000000..2064417
--- /dev/null
+++ b/src/lib/components/ArticlesSkeleton.svelte
@@ -0,0 +1,80 @@
+
+
+
+ {#each placeholders as _, i (i)}
+
+
+ Loading article title...
+ Loading domain...
+
+
+ Loading reading time...
+ Loading tags...
+
+
+ {/each}
+
+
+
diff --git a/src/lib/components/ExternalLink.svelte b/src/lib/components/ExternalLink.svelte
index dfbaa21..8e47dd6 100644
--- a/src/lib/components/ExternalLink.svelte
+++ b/src/lib/components/ExternalLink.svelte
@@ -1,31 +1,25 @@
{#snippet externalLink({ iconData, linkData, textData }: ExternalLinkType)}
diff --git a/src/lib/components/Pagination.svelte b/src/lib/components/Pagination.svelte
index 3d2c5da..07b7642 100644
--- a/src/lib/components/Pagination.svelte
+++ b/src/lib/components/Pagination.svelte
@@ -8,6 +8,7 @@
pageSize: number;
totalCount: number;
currentPage: number;
+ totalPages: number;
base: string;
}
@@ -20,7 +21,7 @@
}: Props = $props();
- goto(`${base}/${page}`)}>
{#snippet children({ pages })}
@@ -31,7 +32,7 @@
...
{:else}
-
+
{page.value}
diff --git a/src/lib/stores/articleStore.ts b/src/lib/stores/articleStore.ts
deleted file mode 100644
index f782b60..0000000
--- a/src/lib/stores/articleStore.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import { writable } from 'svelte/store';
-import type { Article } from '$lib/types/article';
-
-// Custom store
-const state = () => {
- const { subscribe, set, update } = writable([]);
-
- function addAll(articles: Article[]) {
- // console.log(typeof articles);
- for (const article of articles) {
- add(article);
- }
- }
-
- function add(article: Article) {
- update((store) => [...store, article]);
- }
-
- function addSorted(article: Article, index: number) {
- update((store) => {
- store.splice(index, 0, article);
- return store;
- });
- }
-
- function remove(hashed_url: string) {
- update((store) => {
- const newStore = store.filter((item: Article) => item.hashed_url !== hashed_url);
- return [...newStore];
- });
- }
-
- function removeAll() {
- update(() => {
- return [];
- });
- }
-
- return { subscribe, set, update, add, addSorted, addAll, remove, removeAll };
-};
-
-export const articleStore = state();
diff --git a/src/lib/util/fetchBandcampAlbums.ts b/src/lib/util/fetchBandcampAlbums.ts
index a5ee39f..29499a5 100644
--- a/src/lib/util/fetchBandcampAlbums.ts
+++ b/src/lib/util/fetchBandcampAlbums.ts
@@ -6,12 +6,12 @@ import type { Album, BandCampResults } from '../types/album';
export async function fetchBandcampAlbums() {
try {
- if (USE_REDIS_CACHE) {
+ if (USE_REDIS_CACHE === 'true') {
const cached: string | null = await redis.get('bandcampAlbums');
if (cached) {
const response: Album[] = JSON.parse(cached);
- console.log(`Cache hit!`);
+ console.log('Cache hit!');
const ttl = await redis.ttl('bandcampAlbums');
return { ...response, cacheControl: `max-age=${ttl}` };
@@ -46,7 +46,7 @@ export async function fetchBandcampAlbums() {
const albums: Album[] = data?.collectionItems || [];
if (albums && albums?.length > 0) {
- if (USE_REDIS_CACHE) {
+ if (USE_REDIS_CACHE === 'true') {
redis.set('bandcampAlbums', JSON.stringify(albums), 'EX', 43200);
}
return albums;
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte
index 51934b5..042a15a 100644
--- a/src/routes/+page.svelte
+++ b/src/routes/+page.svelte
@@ -63,7 +63,7 @@ const userNames = {
diff --git a/src/routes/api/articles/+server.ts b/src/routes/api/articles/+server.ts
index cbad32e..55550bb 100644
--- a/src/routes/api/articles/+server.ts
+++ b/src/routes/api/articles/+server.ts
@@ -1,6 +1,7 @@
import { json, error } from '@sveltejs/kit';
import { PAGE_SIZE } from '$env/static/private';
import { fetchArticlesApi } from '$lib/api';
+import type { ArticlePageLoad } from '@/lib/types/article.js';
export async function GET({ setHeaders, url }) {
const page = url?.searchParams?.get('page') || '1';
@@ -10,13 +11,11 @@ export async function GET({ setHeaders, url }) {
}
try {
- const response = await fetchArticlesApi('get', 'fetchArticles', {
+ const response: ArticlePageLoad = await fetchArticlesApi('get', 'fetchArticles', {
page,
limit
});
- console.log(`JSON articles response: ${JSON.stringify(response)}`);
-
if (response?.articles) {
if (response?.cacheControl) {
if (!response.cacheControl.includes('no-cache')) {
diff --git a/src/routes/api/bandcamp/albums/+server.ts b/src/routes/api/bandcamp/albums/+server.ts
index e767428..cf41196 100644
--- a/src/routes/api/bandcamp/albums/+server.ts
+++ b/src/routes/api/bandcamp/albums/+server.ts
@@ -1,13 +1,12 @@
import { json, error } from '@sveltejs/kit';
-import { BANDCAMP_USERNAME, PAGE_SIZE, USE_REDIS_CACHE } from '$env/static/private';
-import { fetchArticlesApi } from '$lib/api';
+import { BANDCAMP_USERNAME, USE_REDIS_CACHE } from '$env/static/private';
import { redis } from '$lib/server/redis';
import type { Album, BandCampResults } from '$lib/types/album';
import scrapeIt, { type ScrapeResult } from 'scrape-it';
export async function GET({ setHeaders, url }) {
try {
- if (USE_REDIS_CACHE) {
+ if (USE_REDIS_CACHE === 'true') {
const cached: string | null = await redis.get('bandcampAlbums');
if (cached) {
@@ -51,7 +50,7 @@ export async function GET({ setHeaders, url }) {
const albums: Album[] = data?.collectionItems || [];
if (albums && albums?.length > 0) {
- if (USE_REDIS_CACHE) {
+ if (USE_REDIS_CACHE === 'true') {
redis.set('bandcampAlbums', JSON.stringify(albums), 'EX', 43200);
}
setHeaders({
diff --git a/src/routes/articles/+layout.server.ts b/src/routes/articles/+layout.server.ts
new file mode 100644
index 0000000..fdc96d0
--- /dev/null
+++ b/src/routes/articles/+layout.server.ts
@@ -0,0 +1,17 @@
+import type { LayoutServerLoad } from './$types';
+
+export const load: LayoutServerLoad = async ({ fetch }) => {
+ // Fetch the first page to get common metadata (total articles, total pages, etc.)
+ const resp = await fetch('/api/articles?page=1');
+ const data = await resp.json();
+
+ console.log('Data: ', JSON.stringify(data));
+
+ return {
+ // Common metadata available to all child routes
+ totalArticles: data.totalArticles,
+ totalPages: data.totalPages,
+ limit: data.limit,
+ cacheControl: data.cacheControl
+ };
+};
diff --git a/src/routes/articles/+layout.svelte b/src/routes/articles/+layout.svelte
new file mode 100644
index 0000000..9f815db
--- /dev/null
+++ b/src/routes/articles/+layout.svelte
@@ -0,0 +1,43 @@
+
+
+
+
Favorite Tech Articles
+ {@render children()}
+
+
+
diff --git a/src/routes/articles/[page]/+page.server.ts b/src/routes/articles/[page]/+page.server.ts
index f00a701..c22a66e 100644
--- a/src/routes/articles/[page]/+page.server.ts
+++ b/src/routes/articles/[page]/+page.server.ts
@@ -1,19 +1,11 @@
-import type { MetaTagsProps } from 'svelte-meta-tags';
-import type { PageServerLoad } from './$types';
import { PUBLIC_SITE_URL } from '$env/static/public';
import type { ArticlePageLoad } from '$lib/types/article';
+import type { MetaTagsProps } from 'svelte-meta-tags';
+import type { PageServerLoad } from './$types';
-export const load: PageServerLoad = async ({ fetch, params, setHeaders, url }) => {
+export const load: PageServerLoad = async ({ fetch, params, setHeaders, url, parent }) => {
const { page } = params;
- const resp = await fetch(`/api/articles?page=${page}`);
- const {
- articles,
- currentPage,
- totalPages,
- limit,
- totalArticles,
- cacheControl,
- }: ArticlePageLoad = await resp.json();
+ const { cacheControl } = await parent();
if (cacheControl?.includes('no-cache')) {
setHeaders({
@@ -57,12 +49,12 @@ export const load: PageServerLoad = async ({ fetch, params, setHeaders, url }) =
url: currentPageUrl,
});
+ const articlesData = await fetch(`/api/articles?page=${page}`);
+ const { articles, currentPage } = await articlesData.json();
+
return {
articles,
currentPage,
- totalPages,
- limit,
- totalArticles,
metaTagsChild: metaTags,
};
};
diff --git a/src/routes/articles/[page]/+page.svelte b/src/routes/articles/[page]/+page.svelte
index 02d1f17..fb6a339 100644
--- a/src/routes/articles/[page]/+page.svelte
+++ b/src/routes/articles/[page]/+page.svelte
@@ -1,33 +1,55 @@
-Favorite Tech Articles
-
-
-
\ No newline at end of file
+
+
+
\ No newline at end of file
diff --git a/svelte.config.js b/svelte.config.js
index 3326133..e7facd6 100644
--- a/svelte.config.js
+++ b/svelte.config.js
@@ -15,6 +15,8 @@ const config = {
adapter: adapter(),
alias: {
$: './src',
+ $lib: './src/lib',
+ '@': './src'
}
},
compilerOptions: {
diff --git a/tsconfig.json b/tsconfig.json
index 12f7173..b8eecf0 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -12,10 +12,7 @@
"strict": true,
"moduleResolution": "bundler",
"experimentalDecorators": true,
- "emitDecoratorMetadata": true,
- "paths": {
- "@/*": ["./src/*"]
- }
+ "emitDecoratorMetadata": true
}
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
//
From 5752c125ee7c4545aa7026fecfd4e323202b3757 Mon Sep 17 00:00:00 2001
From: Bradley Shellnut
Date: Tue, 12 Aug 2025 13:43:58 -0700
Subject: [PATCH 2/4] Changing loading indicator to do some animation on
navigate start.
---
biome.json | 144 +++++++------
package.json | 8 +-
pnpm-lock.yaml | 232 ++++++++++++---------
src/lib/util/page_loading_indicator.svelte | 38 +++-
4 files changed, 241 insertions(+), 181 deletions(-)
diff --git a/biome.json b/biome.json
index 7fa7af8..07f187e 100644
--- a/biome.json
+++ b/biome.json
@@ -1,65 +1,83 @@
{
- "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
- "vcs": {
- "enabled": false,
- "clientKind": "git",
- "useIgnoreFile": false
- },
- "files": { "ignoreUnknown": false, "ignore": [] },
- "formatter": {
- "enabled": true,
- "formatWithErrors": false,
- "indentStyle": "space",
- "indentWidth": 2,
- "lineEnding": "lf",
- "lineWidth": 150,
- "attributePosition": "auto",
- "ignore": [
- "**/.DS_Store",
- "**/node_modules",
- "./build",
- "./.svelte-kit",
- "./package",
- "**/.env",
- "**/.env.*",
- "**/pnpm-lock.yaml",
- "**/package-lock.json",
- "**/yarn.lock",
- "**/paraglide/**"
- ]
- },
- "organizeImports": { "enabled": true },
- "linter": { "enabled": true, "rules": { "recommended": true } },
- "javascript": {
- "formatter": {
- "jsxQuoteStyle": "single",
- "quoteProperties": "asNeeded",
- "trailingCommas": "all",
- "indentStyle": "space",
- "lineEnding": "lf",
- "lineWidth": 150,
- "semicolons": "always",
- "arrowParentheses": "always",
- "bracketSpacing": true,
- "bracketSameLine": false,
- "quoteStyle": "single",
- "attributePosition": "auto"
- },
- "parser": {
- "unsafeParameterDecoratorsEnabled": true
- }
- },
- "overrides": [
- {
- "include": ["*.svelte"],
- "linter": {
- "rules": {
- "style": {
- "useConst": "off",
- "useImportType": "off"
- }
- }
- }
- }
- ]
+ "$schema": "https://biomejs.dev/schemas/2.0.0/schema.json",
+ "vcs": {
+ "enabled": false,
+ "clientKind": "git",
+ "useIgnoreFile": false
+ },
+ "files": { "ignoreUnknown": false, "includes": ["**"] },
+ "formatter": {
+ "enabled": true,
+ "formatWithErrors": false,
+ "indentStyle": "space",
+ "indentWidth": 2,
+ "lineEnding": "lf",
+ "lineWidth": 150,
+ "attributePosition": "auto",
+ "includes": [
+ "**",
+ "!**/.DS_Store",
+ "!**/node_modules",
+ "!build",
+ "!.svelte-kit",
+ "!package",
+ "!**/.env",
+ "!**/.env.*",
+ "!**/pnpm-lock.yaml",
+ "!**/package-lock.json",
+ "!**/yarn.lock",
+ "!**/paraglide/**"
+ ]
+ },
+ "assist": { "actions": { "source": { "organizeImports": "on" } } },
+ "linter": {
+ "enabled": true,
+ "rules": {
+ "recommended": true,
+ "style": {
+ "noParameterAssign": "error",
+ "useAsConstAssertion": "error",
+ "useDefaultParameterLast": "error",
+ "useEnumInitializers": "error",
+ "useSelfClosingElements": "error",
+ "useSingleVarDeclarator": "error",
+ "noUnusedTemplateLiteral": "error",
+ "useNumberNamespace": "error",
+ "noInferrableTypes": "error",
+ "noUselessElse": "error"
+ }
+ }
+ },
+ "javascript": {
+ "formatter": {
+ "jsxQuoteStyle": "single",
+ "quoteProperties": "asNeeded",
+ "trailingCommas": "all",
+ "indentStyle": "space",
+ "lineEnding": "lf",
+ "lineWidth": 150,
+ "semicolons": "always",
+ "arrowParentheses": "always",
+ "bracketSpacing": true,
+ "bracketSameLine": false,
+ "quoteStyle": "single",
+ "attributePosition": "auto"
+ },
+ "parser": {
+ "unsafeParameterDecoratorsEnabled": true
+ }
+ },
+ "overrides": [
+ {
+ "includes": ["**/*.svelte"],
+ "linter": {
+ "rules": {
+ "style": {
+ "useConst": "off",
+ "useImportType": "off"
+ }
+ }
+ }
+ }
+ ]
}
diff --git a/package.json b/package.json
index 9581dc4..f2bdae2 100644
--- a/package.json
+++ b/package.json
@@ -17,11 +17,11 @@
"test:unit": "vitest"
},
"devDependencies": {
- "@biomejs/biome": "^1.9.4",
+ "@biomejs/biome": "^2.1.4",
"@internationalized/date": "^3.8.2",
"@playwright/test": "^1.54.2",
"@sveltejs/enhanced-img": "^0.5.1",
- "@sveltejs/kit": "^2.27.3",
+ "@sveltejs/kit": "^2.28.0",
"@sveltejs/vite-plugin-svelte": "^5.1.1",
"@unpic/svelte": "^1.0.0",
"@zerodevx/svelte-img": "^2.1.2",
@@ -34,7 +34,7 @@
"postcss-preset-env": "^10.2.4",
"satori": "^0.12.2",
"satori-html": "^0.3.2",
- "svelte": "^5.38.0",
+ "svelte": "^5.38.1",
"svelte-check": "^4.3.1",
"svelte-meta-tags": "^4.4.0",
"svelte-preprocess": "^6.0.3",
@@ -43,7 +43,7 @@
"typescript": "^5.9.2",
"vanilla-lazyload": "^19.1.3",
"vite": "^6.3.5",
- "vite-imagetools": "^7.1.0",
+ "vite-imagetools": "^7.1.1",
"vitest": "^3.2.4"
},
"dependencies": {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 37a48f8..39ea6fc 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -13,13 +13,13 @@ importers:
version: 2.6.2
'@sveltejs/adapter-node':
specifier: ^5.2.14
- version: 5.2.14(@sveltejs/kit@2.27.3(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0)))
+ version: 5.2.14(@sveltejs/kit@2.28.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))
'@vercel/og':
specifier: ^0.6.8
version: 0.6.8
bits-ui:
specifier: 2.9.2
- version: 2.9.2(@internationalized/date@3.8.2)(svelte@5.38.0)
+ version: 2.9.2(@internationalized/date@3.8.2)(svelte@5.38.1)
flexsearch:
specifier: ^0.8.205
version: 0.8.205
@@ -28,7 +28,7 @@ importers:
version: 5.7.0
lucide-svelte:
specifier: ^0.539.0
- version: 0.539.0(svelte@5.38.0)
+ version: 0.539.0(svelte@5.38.1)
scrape-it:
specifier: ^6.1.11
version: 6.1.11
@@ -37,11 +37,11 @@ importers:
version: 0.34.3
svelte-local-storage-store:
specifier: ^0.6.4
- version: 0.6.4(svelte@5.38.0)
+ version: 0.6.4(svelte@5.38.1)
devDependencies:
'@biomejs/biome':
- specifier: ^1.9.4
- version: 1.9.4
+ specifier: ^2.1.4
+ version: 2.1.4
'@internationalized/date':
specifier: ^3.8.2
version: 3.8.2
@@ -50,19 +50,19 @@ importers:
version: 1.54.2
'@sveltejs/enhanced-img':
specifier: ^0.5.1
- version: 0.5.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0)))(rollup@4.34.8)(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0))
+ version: 0.5.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))(rollup@4.34.8)(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0))
'@sveltejs/kit':
- specifier: ^2.27.3
- version: 2.27.3(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0))
+ specifier: ^2.28.0
+ version: 2.28.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0))
'@sveltejs/vite-plugin-svelte':
specifier: ^5.1.1
- version: 5.1.1(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0))
+ version: 5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0))
'@unpic/svelte':
specifier: ^1.0.0
- version: 1.0.0(svelte@5.38.0)
+ version: 1.0.0(svelte@5.38.1)
'@zerodevx/svelte-img':
specifier: ^2.1.2
- version: 2.1.2(rollup@4.34.8)(svelte@5.38.0)
+ version: 2.1.2(rollup@4.34.8)(svelte@5.38.1)
autoprefixer:
specifier: ^10.4.21
version: 10.4.21(postcss@8.5.6)
@@ -91,17 +91,17 @@ importers:
specifier: ^0.3.2
version: 0.3.2
svelte:
- specifier: ^5.38.0
- version: 5.38.0
+ specifier: ^5.38.1
+ version: 5.38.1
svelte-check:
specifier: ^4.3.1
- version: 4.3.1(picomatch@4.0.2)(svelte@5.38.0)(typescript@5.9.2)
+ version: 4.3.1(picomatch@4.0.2)(svelte@5.38.1)(typescript@5.9.2)
svelte-meta-tags:
specifier: ^4.4.0
- version: 4.4.0(svelte@5.38.0)
+ version: 4.4.0(svelte@5.38.1)
svelte-preprocess:
specifier: ^6.0.3
- version: 6.0.3(postcss-load-config@6.0.1(postcss@8.5.6)(yaml@2.7.0))(postcss@8.5.6)(svelte@5.38.0)(typescript@5.9.2)
+ version: 6.0.3(postcss-load-config@6.0.1(postcss@8.5.6)(yaml@2.7.0))(postcss@8.5.6)(svelte@5.38.1)(typescript@5.9.2)
svelte-sequential-preprocessor:
specifier: ^2.0.2
version: 2.0.2
@@ -118,8 +118,8 @@ importers:
specifier: ^6.3.5
version: 6.3.5(yaml@2.7.0)
vite-imagetools:
- specifier: ^7.1.0
- version: 7.1.0(rollup@4.34.8)
+ specifier: ^7.1.1
+ version: 7.1.1(rollup@4.34.8)
vitest:
specifier: ^3.2.4
version: 3.2.4(yaml@2.7.0)
@@ -130,55 +130,55 @@ packages:
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
engines: {node: '>=6.0.0'}
- '@biomejs/biome@1.9.4':
- resolution: {integrity: sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==}
+ '@biomejs/biome@2.1.4':
+ resolution: {integrity: sha512-QWlrqyxsU0FCebuMnkvBIkxvPqH89afiJzjMl+z67ybutse590jgeaFdDurE9XYtzpjRGTI1tlUZPGWmbKsElA==}
engines: {node: '>=14.21.3'}
hasBin: true
- '@biomejs/cli-darwin-arm64@1.9.4':
- resolution: {integrity: sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==}
+ '@biomejs/cli-darwin-arm64@2.1.4':
+ resolution: {integrity: sha512-sCrNENE74I9MV090Wq/9Dg7EhPudx3+5OiSoQOkIe3DLPzFARuL1dOwCWhKCpA3I5RHmbrsbNSRfZwCabwd8Qg==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [darwin]
- '@biomejs/cli-darwin-x64@1.9.4':
- resolution: {integrity: sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==}
+ '@biomejs/cli-darwin-x64@2.1.4':
+ resolution: {integrity: sha512-gOEICJbTCy6iruBywBDcG4X5rHMbqCPs3clh3UQ+hRKlgvJTk4NHWQAyHOXvaLe+AxD1/TNX1jbZeffBJzcrOw==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [darwin]
- '@biomejs/cli-linux-arm64-musl@1.9.4':
- resolution: {integrity: sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==}
+ '@biomejs/cli-linux-arm64-musl@2.1.4':
+ resolution: {integrity: sha512-nYr7H0CyAJPaLupFE2cH16KZmRC5Z9PEftiA2vWxk+CsFkPZQ6dBRdcC6RuS+zJlPc/JOd8xw3uCCt9Pv41WvQ==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [linux]
- '@biomejs/cli-linux-arm64@1.9.4':
- resolution: {integrity: sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==}
+ '@biomejs/cli-linux-arm64@2.1.4':
+ resolution: {integrity: sha512-juhEkdkKR4nbUi5k/KRp1ocGPNWLgFRD4NrHZSveYrD6i98pyvuzmS9yFYgOZa5JhaVqo0HPnci0+YuzSwT2fw==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [linux]
- '@biomejs/cli-linux-x64-musl@1.9.4':
- resolution: {integrity: sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==}
+ '@biomejs/cli-linux-x64-musl@2.1.4':
+ resolution: {integrity: sha512-lvwvb2SQQHctHUKvBKptR6PLFCM7JfRjpCCrDaTmvB7EeZ5/dQJPhTYBf36BE/B4CRWR2ZiBLRYhK7hhXBCZAg==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [linux]
- '@biomejs/cli-linux-x64@1.9.4':
- resolution: {integrity: sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==}
+ '@biomejs/cli-linux-x64@2.1.4':
+ resolution: {integrity: sha512-Eoy9ycbhpJVYuR+LskV9s3uyaIkp89+qqgqhGQsWnp/I02Uqg2fXFblHJOpGZR8AxdB9ADy87oFVxn9MpFKUrw==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [linux]
- '@biomejs/cli-win32-arm64@1.9.4':
- resolution: {integrity: sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==}
+ '@biomejs/cli-win32-arm64@2.1.4':
+ resolution: {integrity: sha512-3WRYte7orvyi6TRfIZkDN9Jzoogbv+gSvR+b9VOXUg1We1XrjBg6WljADeVEaKTvOcpVdH0a90TwyOQ6ue4fGw==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [win32]
- '@biomejs/cli-win32-x64@1.9.4':
- resolution: {integrity: sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==}
+ '@biomejs/cli-win32-x64@2.1.4':
+ resolution: {integrity: sha512-tBc+W7anBPSFXGAoQW+f/+svkpt8/uXfRwDzN1DvnatkRMt16KIYpEi/iw8u9GahJlFv98kgHcIrSsZHZTR0sw==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [win32]
@@ -839,10 +839,16 @@ packages:
'@ioredis/commands@1.3.0':
resolution: {integrity: sha512-M/T6Zewn7sDaBQEqIZ8Rb+i9y8qfGmq+5SDFSf9sA2lUZTmdDLVdOiQaeDp+Q4wElZ9HG1GAX5KhDaidp6LQsQ==}
+ '@jridgewell/gen-mapping@0.3.13':
+ resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
+
'@jridgewell/gen-mapping@0.3.8':
resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==}
engines: {node: '>=6.0.0'}
+ '@jridgewell/remapping@2.3.5':
+ resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
+
'@jridgewell/resolve-uri@3.1.2':
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
engines: {node: '>=6.0.0'}
@@ -857,6 +863,9 @@ packages:
'@jridgewell/trace-mapping@0.3.25':
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
+ '@jridgewell/trace-mapping@0.3.30':
+ resolution: {integrity: sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==}
+
'@playwright/test@1.54.2':
resolution: {integrity: sha512-A+znathYxPf+72riFd1r1ovOLqsIIB0jKIoPjyK2kqEIe30/6jF6BC7QNluHuwUmsD2tv1XZVugN8GqfTMOxsA==}
engines: {node: '>=18'}
@@ -1201,8 +1210,8 @@ packages:
svelte: ^5.0.0
vite: '>= 5.0.0'
- '@sveltejs/kit@2.27.3':
- resolution: {integrity: sha512-jiG3NGZ8RRpi+ncjVnX+oR7uWEgzy//3YLGcTU5mHtjGraeGyNDr7GJFHlk7z0vi8bMXpXIUkEXj6p70FJmHvw==}
+ '@sveltejs/kit@2.28.0':
+ resolution: {integrity: sha512-qrhygwHV5r6JrvCw4gwNqqxYGDi5YbajocxfKgFXmSFpFo8wQobUvsM0OfakN4h+0LEmXtqHRrC6BcyAkOwyoQ==}
engines: {node: '>=18.13'}
hasBin: true
peerDependencies:
@@ -2277,8 +2286,8 @@ packages:
resolution: {integrity: sha512-eeEgGc2DtiUil5ANdtd8vPwt9AgaMdnuUFnPft9F5oMvU/FHu5IHFic+p1dR/UOB7XU2mX2yHW+NcTch4DCh5Q==}
engines: {node: '>=16'}
- svelte@5.38.0:
- resolution: {integrity: sha512-cWF1Oc2IM/QbktdK89u5lt9MdKxRtQnRKnf2tq6KOhYuhLOd2hbMuTiJ+vWMzAeMDe81AzbCgLd4GVtOJ4fDRg==}
+ svelte@5.38.1:
+ resolution: {integrity: sha512-fO6CLDfJYWHgfo6lQwkQU2vhCiHc2MBl6s3vEhK+sSZru17YL4R5s1v14ndRpqKAIkq8nCz6MTk1yZbESZWeyQ==}
engines: {node: '>=18'}
tabbable@6.2.0:
@@ -2360,8 +2369,8 @@ packages:
resolution: {integrity: sha512-C4ZYhgj2vAj43/TpZ06XlDNP0p/7LIeYbgUYr+xG44nM++4HGX6YZBKAYpiBNgiCFUTJ6eXkRppWBrfPMevgmg==}
engines: {node: '>=12.0.0'}
- vite-imagetools@7.1.0:
- resolution: {integrity: sha512-Mqh1uUY2DEMuBOogFz5Rd7cAs70VP6wsdQh2IShrJ+qGk5f7yQa4pN8w0YMLlGIKYW1JfM8oXrznUwVkhG+qxg==}
+ vite-imagetools@7.1.1:
+ resolution: {integrity: sha512-6Dz0ZD2u1u59dw0ryid4beaDcCNNiTfLXUg6XLxx9n7Qm4BgAAm8TozYUnIH0aT4FDAADZqHsh9ZtISzAs4eKA==}
engines: {node: '>=18.0.0'}
vite-node@3.2.4:
@@ -2476,39 +2485,39 @@ snapshots:
'@jridgewell/gen-mapping': 0.3.8
'@jridgewell/trace-mapping': 0.3.25
- '@biomejs/biome@1.9.4':
+ '@biomejs/biome@2.1.4':
optionalDependencies:
- '@biomejs/cli-darwin-arm64': 1.9.4
- '@biomejs/cli-darwin-x64': 1.9.4
- '@biomejs/cli-linux-arm64': 1.9.4
- '@biomejs/cli-linux-arm64-musl': 1.9.4
- '@biomejs/cli-linux-x64': 1.9.4
- '@biomejs/cli-linux-x64-musl': 1.9.4
- '@biomejs/cli-win32-arm64': 1.9.4
- '@biomejs/cli-win32-x64': 1.9.4
+ '@biomejs/cli-darwin-arm64': 2.1.4
+ '@biomejs/cli-darwin-x64': 2.1.4
+ '@biomejs/cli-linux-arm64': 2.1.4
+ '@biomejs/cli-linux-arm64-musl': 2.1.4
+ '@biomejs/cli-linux-x64': 2.1.4
+ '@biomejs/cli-linux-x64-musl': 2.1.4
+ '@biomejs/cli-win32-arm64': 2.1.4
+ '@biomejs/cli-win32-x64': 2.1.4
- '@biomejs/cli-darwin-arm64@1.9.4':
+ '@biomejs/cli-darwin-arm64@2.1.4':
optional: true
- '@biomejs/cli-darwin-x64@1.9.4':
+ '@biomejs/cli-darwin-x64@2.1.4':
optional: true
- '@biomejs/cli-linux-arm64-musl@1.9.4':
+ '@biomejs/cli-linux-arm64-musl@2.1.4':
optional: true
- '@biomejs/cli-linux-arm64@1.9.4':
+ '@biomejs/cli-linux-arm64@2.1.4':
optional: true
- '@biomejs/cli-linux-x64-musl@1.9.4':
+ '@biomejs/cli-linux-x64-musl@2.1.4':
optional: true
- '@biomejs/cli-linux-x64@1.9.4':
+ '@biomejs/cli-linux-x64@2.1.4':
optional: true
- '@biomejs/cli-win32-arm64@1.9.4':
+ '@biomejs/cli-win32-arm64@2.1.4':
optional: true
- '@biomejs/cli-win32-x64@1.9.4':
+ '@biomejs/cli-win32-x64@2.1.4':
optional: true
'@csstools/cascade-layer-name-parser@2.0.5(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)':
@@ -3035,12 +3044,22 @@ snapshots:
'@ioredis/commands@1.3.0': {}
+ '@jridgewell/gen-mapping@0.3.13':
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.0
+ '@jridgewell/trace-mapping': 0.3.30
+
'@jridgewell/gen-mapping@0.3.8':
dependencies:
'@jridgewell/set-array': 1.2.1
'@jridgewell/sourcemap-codec': 1.5.0
'@jridgewell/trace-mapping': 0.3.25
+ '@jridgewell/remapping@2.3.5':
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.30
+
'@jridgewell/resolve-uri@3.1.2': {}
'@jridgewell/set-array@1.2.1': {}
@@ -3052,6 +3071,11 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.0
+ '@jridgewell/trace-mapping@0.3.30':
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.5.0
+
'@playwright/test@1.54.2':
dependencies:
playwright: 1.54.2
@@ -3279,32 +3303,32 @@ snapshots:
dependencies:
acorn: 8.15.0
- '@sveltejs/adapter-node@5.2.14(@sveltejs/kit@2.27.3(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0)))':
+ '@sveltejs/adapter-node@5.2.14(@sveltejs/kit@2.28.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))':
dependencies:
'@rollup/plugin-commonjs': 28.0.2(rollup@4.34.8)
'@rollup/plugin-json': 6.1.0(rollup@4.34.8)
'@rollup/plugin-node-resolve': 16.0.0(rollup@4.34.8)
- '@sveltejs/kit': 2.27.3(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0))
+ '@sveltejs/kit': 2.28.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0))
rollup: 4.34.8
- '@sveltejs/enhanced-img@0.5.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0)))(rollup@4.34.8)(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0))':
+ '@sveltejs/enhanced-img@0.5.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))(rollup@4.34.8)(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0))':
dependencies:
- '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0))
+ '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0))
magic-string: 0.30.17
sharp: 0.34.3
- svelte: 5.38.0
- svelte-parse-markup: 0.1.5(svelte@5.38.0)
+ svelte: 5.38.1
+ svelte-parse-markup: 0.1.5(svelte@5.38.1)
vite: 6.3.5(yaml@2.7.0)
- vite-imagetools: 7.1.0(rollup@4.34.8)
+ vite-imagetools: 7.1.1(rollup@4.34.8)
zimmerframe: 1.1.2
transitivePeerDependencies:
- rollup
- '@sveltejs/kit@2.27.3(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0))':
+ '@sveltejs/kit@2.28.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0))':
dependencies:
'@standard-schema/spec': 1.0.0
'@sveltejs/acorn-typescript': 1.0.5(acorn@8.15.0)
- '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0))
+ '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0))
'@types/cookie': 0.6.0
acorn: 8.15.0
cookie: 0.6.0
@@ -3316,26 +3340,26 @@ snapshots:
sade: 1.8.1
set-cookie-parser: 2.7.1
sirv: 3.0.1
- svelte: 5.38.0
+ svelte: 5.38.1
vite: 6.3.5(yaml@2.7.0)
- '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0))':
+ '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0))':
dependencies:
- '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0))
+ '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0))
debug: 4.4.1
- svelte: 5.38.0
+ svelte: 5.38.1
vite: 6.3.5(yaml@2.7.0)
transitivePeerDependencies:
- supports-color
- '@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0))':
+ '@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0))':
dependencies:
- '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.0)(vite@6.3.5(yaml@2.7.0))
+ '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0))
debug: 4.4.1
deepmerge: 4.3.1
kleur: 4.1.5
magic-string: 0.30.17
- svelte: 5.38.0
+ svelte: 5.38.1
vite: 6.3.5(yaml@2.7.0)
vitefu: 1.1.1(vite@6.3.5(yaml@2.7.0))
transitivePeerDependencies:
@@ -3363,11 +3387,11 @@ snapshots:
dependencies:
unpic: 4.1.2
- '@unpic/svelte@1.0.0(svelte@5.38.0)':
+ '@unpic/svelte@1.0.0(svelte@5.38.1)':
dependencies:
'@unpic/core': 1.0.1
style-object-to-css-string: 1.1.3
- svelte: 5.38.0
+ svelte: 5.38.1
'@vercel/og@0.6.8':
dependencies:
@@ -3417,9 +3441,9 @@ snapshots:
loupe: 3.2.0
tinyrainbow: 2.0.0
- '@zerodevx/svelte-img@2.1.2(rollup@4.34.8)(svelte@5.38.0)':
+ '@zerodevx/svelte-img@2.1.2(rollup@4.34.8)(svelte@5.38.1)':
dependencies:
- svelte: 5.38.0
+ svelte: 5.38.1
vite-imagetools: 6.2.9(rollup@4.34.8)
transitivePeerDependencies:
- rollup
@@ -3467,15 +3491,15 @@ snapshots:
base64-js@0.0.8: {}
- bits-ui@2.9.2(@internationalized/date@3.8.2)(svelte@5.38.0):
+ bits-ui@2.9.2(@internationalized/date@3.8.2)(svelte@5.38.1):
dependencies:
'@floating-ui/core': 1.7.3
'@floating-ui/dom': 1.7.3
'@internationalized/date': 3.8.2
esm-env: 1.2.2
- runed: 0.29.2(svelte@5.38.0)
- svelte: 5.38.0
- svelte-toolbelt: 0.9.3(svelte@5.38.0)
+ runed: 0.29.2(svelte@5.38.1)
+ svelte: 5.38.1
+ svelte-toolbelt: 0.9.3(svelte@5.38.1)
tabbable: 6.2.0
boolbase@1.0.0: {}
@@ -3915,9 +3939,9 @@ snapshots:
loupe@3.2.0: {}
- lucide-svelte@0.539.0(svelte@5.38.0):
+ lucide-svelte@0.539.0(svelte@5.38.1):
dependencies:
- svelte: 5.38.0
+ svelte: 5.38.1
magic-string@0.30.17:
dependencies:
@@ -4316,10 +4340,10 @@ snapshots:
'@rollup/rollup-win32-x64-msvc': 4.40.2
fsevents: 2.3.3
- runed@0.29.2(svelte@5.38.0):
+ runed@0.29.2(svelte@5.38.1):
dependencies:
esm-env: 1.2.2
- svelte: 5.38.0
+ svelte: 5.38.1
sade@1.8.1:
dependencies:
@@ -4461,34 +4485,34 @@ snapshots:
supports-preserve-symlinks-flag@1.0.0: {}
- svelte-check@4.3.1(picomatch@4.0.2)(svelte@5.38.0)(typescript@5.9.2):
+ svelte-check@4.3.1(picomatch@4.0.2)(svelte@5.38.1)(typescript@5.9.2):
dependencies:
'@jridgewell/trace-mapping': 0.3.25
chokidar: 4.0.3
fdir: 6.4.4(picomatch@4.0.2)
picocolors: 1.1.1
sade: 1.8.1
- svelte: 5.38.0
+ svelte: 5.38.1
typescript: 5.9.2
transitivePeerDependencies:
- picomatch
- svelte-local-storage-store@0.6.4(svelte@5.38.0):
+ svelte-local-storage-store@0.6.4(svelte@5.38.1):
dependencies:
- svelte: 5.38.0
+ svelte: 5.38.1
- svelte-meta-tags@4.4.0(svelte@5.38.0):
+ svelte-meta-tags@4.4.0(svelte@5.38.1):
dependencies:
schema-dts: 1.1.5
- svelte: 5.38.0
+ svelte: 5.38.1
- svelte-parse-markup@0.1.5(svelte@5.38.0):
+ svelte-parse-markup@0.1.5(svelte@5.38.1):
dependencies:
- svelte: 5.38.0
+ svelte: 5.38.1
- svelte-preprocess@6.0.3(postcss-load-config@6.0.1(postcss@8.5.6)(yaml@2.7.0))(postcss@8.5.6)(svelte@5.38.0)(typescript@5.9.2):
+ svelte-preprocess@6.0.3(postcss-load-config@6.0.1(postcss@8.5.6)(yaml@2.7.0))(postcss@8.5.6)(svelte@5.38.1)(typescript@5.9.2):
dependencies:
- svelte: 5.38.0
+ svelte: 5.38.1
optionalDependencies:
postcss: 8.5.6
postcss-load-config: 6.0.1(postcss@8.5.6)(yaml@2.7.0)
@@ -4499,12 +4523,12 @@ snapshots:
svelte: 4.2.20
tslib: 2.7.0
- svelte-toolbelt@0.9.3(svelte@5.38.0):
+ svelte-toolbelt@0.9.3(svelte@5.38.1):
dependencies:
clsx: 2.1.1
- runed: 0.29.2(svelte@5.38.0)
+ runed: 0.29.2(svelte@5.38.1)
style-to-object: 1.0.9
- svelte: 5.38.0
+ svelte: 5.38.1
svelte@4.2.20:
dependencies:
@@ -4523,9 +4547,9 @@ snapshots:
magic-string: 0.30.17
periscopic: 3.1.0
- svelte@5.38.0:
+ svelte@5.38.1:
dependencies:
- '@ampproject/remapping': 2.3.0
+ '@jridgewell/remapping': 2.3.5
'@jridgewell/sourcemap-codec': 1.5.0
'@sveltejs/acorn-typescript': 1.0.5(acorn@8.14.1)
'@types/estree': 1.0.7
@@ -4610,7 +4634,7 @@ snapshots:
transitivePeerDependencies:
- rollup
- vite-imagetools@7.1.0(rollup@4.34.8):
+ vite-imagetools@7.1.1(rollup@4.34.8):
dependencies:
'@rollup/pluginutils': 5.1.4(rollup@4.34.8)
imagetools-core: 7.1.0
diff --git a/src/lib/util/page_loading_indicator.svelte b/src/lib/util/page_loading_indicator.svelte
index 716316f..da2b46b 100644
--- a/src/lib/util/page_loading_indicator.svelte
+++ b/src/lib/util/page_loading_indicator.svelte
@@ -1,5 +1,5 @@
Favorite Articles
-
-
+
+ {#if loadingArticles}
+
+ {:else}
{#each articlesData as article (article.hashed_url)}
{article.domain_name}
@@ -70,22 +78,23 @@
{/each}
-
+ {/if}
-
{`${totalArticles} more articles`}
+ {#if page.url.pathname === "/"}
+
{`${totalArticles} more articles`}
+ {/if}
-
\ No newline at end of file
+
diff --git a/src/lib/components/ArticlesSkeleton.svelte b/src/lib/components/ArticlesSkeleton.svelte
index 2064417..5f0829a 100644
--- a/src/lib/components/ArticlesSkeleton.svelte
+++ b/src/lib/components/ArticlesSkeleton.svelte
@@ -4,42 +4,45 @@
classes?: string[];
}
- let { count = 6, classes = ['columns'] }: Props = $props();
+ let { count = 6, classes = [""] }: Props = $props();
const placeholders = Array.from({ length: count });
-
- {#each placeholders as _, i (i)}
-
-
- Loading article title...
- Loading domain...
-
-
- Loading reading time...
- Loading tags...
-
-
- {/each}
-
+{#each placeholders as _, i (i)}
+
+
+
+ Loading article title...
+
+
+ Loading domain...
+
+
+
+
+ Loading reading time...
+
+
+ Loading tags...
+
+
+
+{/each}
diff --git a/src/lib/util/page_loading_indicator.svelte b/src/lib/util/page_loading_indicator.svelte
index da2b46b..7b07d77 100644
--- a/src/lib/util/page_loading_indicator.svelte
+++ b/src/lib/util/page_loading_indicator.svelte
@@ -1,5 +1,6 @@
@@ -28,8 +29,10 @@
base="/articles"
/>
-
-
+
+
\ No newline at end of file
+
From d18f6b0a9fdd2c38a08ff2e53f1bfb7a93f4e39c Mon Sep 17 00:00:00 2001
From: Bradley Shellnut
Date: Wed, 13 Aug 2025 19:24:57 -0700
Subject: [PATCH 4/4] Fixing most svelte check issues.
---
src/lib/components/ExternalLink.svelte | 6 +++---
src/lib/components/Portfolio.svelte | 6 +++---
src/lib/util/logoIcons.svelte | 4 ++--
src/routes/about/TechListItem.svelte | 6 ++----
src/routes/og/+server.ts | 3 +--
src/routes/portfolio/+page.svelte | 4 ----
src/routes/portfolio/Portfolio.svelte | 2 +-
src/routes/uses/+page.svelte | 10 +++++-----
8 files changed, 17 insertions(+), 24 deletions(-)
diff --git a/src/lib/components/ExternalLink.svelte b/src/lib/components/ExternalLink.svelte
index 8e47dd6..25930b4 100644
--- a/src/lib/components/ExternalLink.svelte
+++ b/src/lib/components/ExternalLink.svelte
@@ -35,7 +35,7 @@
{textData?.text}
{/if}
{#if textData?.showIcon}
- {@render linkIcon?.(iconData ?? {})}
+ {@render linkIcon(iconData ?? {})}
{/if}
{#if textData?.location === "bottom" || (textData?.location === "right" && textData?.text)}
{textData?.text}
@@ -44,7 +44,7 @@
{/snippet}
{#snippet linkIcon({ type, icon, iconClass }: LinkIconType)}
- {#if type === "svg" && icon}
+ {#if type === "svg" && icon && typeof icon === 'function' && icon.length !== undefined}
{:else if type === "icon" && icon}
{@const Icon = icon}
diff --git a/src/lib/components/Portfolio.svelte b/src/lib/components/Portfolio.svelte
index 0c7e64a..86665e2 100644
--- a/src/lib/components/Portfolio.svelte
+++ b/src/lib/components/Portfolio.svelte
@@ -1,7 +1,7 @@
@@ -46,7 +46,7 @@
{/snippet}
-{#snippet lucideIcon(icon)}
+{#snippet lucideIcon(icon: any)}
{@const Icon = icon}
{/snippet}
diff --git a/src/routes/about/TechListItem.svelte b/src/routes/about/TechListItem.svelte
index 58e421b..7508982 100644
--- a/src/routes/about/TechListItem.svelte
+++ b/src/routes/about/TechListItem.svelte
@@ -17,11 +17,9 @@