An easy-to-host PDS on the ATProtocol, iPhone and MacOS. Maintain control of your keys and data, always.
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(identity-wallet): install vitest and write real deadline utility tests

The previous commit had deadline tests as comments only because vitest
wasn't installed. Install vitest as a dev dependency and write 12 real
tests covering getDeadline, getUrgency, and formatCountdown with
deterministic time inputs.

All 12 tests pass: 1 test file, 12 assertions.

+451 -238
+5 -3
apps/identity-wallet/package.json
··· 8 8 "build": "vite build", 9 9 "preview": "vite preview", 10 10 "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", 11 - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch" 11 + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", 12 + "test": "vitest run" 12 13 }, 13 14 "dependencies": { 14 15 "@tauri-apps/api": "^2", 15 16 "qrcode": "^1.5.4" 16 17 }, 17 18 "devDependencies": { 18 - "@types/qrcode": "^1.5.5", 19 19 "@sveltejs/adapter-static": "^3.0.8", 20 20 "@sveltejs/kit": "^2.20.4", 21 21 "@sveltejs/vite-plugin-svelte": "^5.0.3", 22 22 "@types/node": "^22", 23 + "@types/qrcode": "^1.5.5", 23 24 "svelte": "^5.25.8", 24 25 "svelte-check": "^4.1.5", 25 26 "tslib": "^2.8.1", 26 27 "typescript": "^5.8.2", 27 - "vite": "^6.4.1" 28 + "vite": "^6.4.1", 29 + "vitest": "^4.1.2" 28 30 } 29 31 }
+378 -143
apps/identity-wallet/pnpm-lock.yaml
··· 17 17 devDependencies: 18 18 '@sveltejs/adapter-static': 19 19 specifier: ^3.0.8 20 - version: 3.0.10(@sveltejs/kit@2.55.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.53.12)(vite@6.4.1(@types/node@22.19.15)))(svelte@5.53.12)(typescript@5.9.3)(vite@6.4.1(@types/node@22.19.15))) 20 + version: 3.0.10(@sveltejs/kit@2.55.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.55.1)(vite@6.4.1(@types/node@22.19.15)))(svelte@5.55.1)(typescript@5.9.3)(vite@6.4.1(@types/node@22.19.15))) 21 21 '@sveltejs/kit': 22 22 specifier: ^2.20.4 23 - version: 2.55.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.53.12)(vite@6.4.1(@types/node@22.19.15)))(svelte@5.53.12)(typescript@5.9.3)(vite@6.4.1(@types/node@22.19.15)) 23 + version: 2.55.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.55.1)(vite@6.4.1(@types/node@22.19.15)))(svelte@5.55.1)(typescript@5.9.3)(vite@6.4.1(@types/node@22.19.15)) 24 24 '@sveltejs/vite-plugin-svelte': 25 25 specifier: ^5.0.3 26 - version: 5.1.1(svelte@5.53.12)(vite@6.4.1(@types/node@22.19.15)) 26 + version: 5.1.1(svelte@5.55.1)(vite@6.4.1(@types/node@22.19.15)) 27 27 '@types/node': 28 28 specifier: ^22 29 29 version: 22.19.15 ··· 32 32 version: 1.5.6 33 33 svelte: 34 34 specifier: ^5.25.8 35 - version: 5.53.12 35 + version: 5.55.1 36 36 svelte-check: 37 37 specifier: ^4.1.5 38 - version: 4.4.5(picomatch@4.0.3)(svelte@5.53.12)(typescript@5.9.3) 38 + version: 4.4.5(picomatch@4.0.4)(svelte@5.55.1)(typescript@5.9.3) 39 39 tslib: 40 40 specifier: ^2.8.1 41 41 version: 2.8.1 ··· 45 45 vite: 46 46 specifier: ^6.4.1 47 47 version: 6.4.1(@types/node@22.19.15) 48 + vitest: 49 + specifier: ^4.1.2 50 + version: 4.1.2(@types/node@22.19.15)(vite@6.4.1(@types/node@22.19.15)) 48 51 49 52 packages: 50 53 ··· 223 226 '@polka/url@1.0.0-next.29': 224 227 resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} 225 228 226 - '@rollup/rollup-android-arm-eabi@4.59.0': 227 - resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==} 229 + '@rollup/rollup-android-arm-eabi@4.60.1': 230 + resolution: {integrity: sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==} 228 231 cpu: [arm] 229 232 os: [android] 230 233 231 - '@rollup/rollup-android-arm64@4.59.0': 232 - resolution: {integrity: sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==} 234 + '@rollup/rollup-android-arm64@4.60.1': 235 + resolution: {integrity: sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA==} 233 236 cpu: [arm64] 234 237 os: [android] 235 238 236 - '@rollup/rollup-darwin-arm64@4.59.0': 237 - resolution: {integrity: sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==} 239 + '@rollup/rollup-darwin-arm64@4.60.1': 240 + resolution: {integrity: sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==} 238 241 cpu: [arm64] 239 242 os: [darwin] 240 243 241 - '@rollup/rollup-darwin-x64@4.59.0': 242 - resolution: {integrity: sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==} 244 + '@rollup/rollup-darwin-x64@4.60.1': 245 + resolution: {integrity: sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew==} 243 246 cpu: [x64] 244 247 os: [darwin] 245 248 246 - '@rollup/rollup-freebsd-arm64@4.59.0': 247 - resolution: {integrity: sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==} 249 + '@rollup/rollup-freebsd-arm64@4.60.1': 250 + resolution: {integrity: sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w==} 248 251 cpu: [arm64] 249 252 os: [freebsd] 250 253 251 - '@rollup/rollup-freebsd-x64@4.59.0': 252 - resolution: {integrity: sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==} 254 + '@rollup/rollup-freebsd-x64@4.60.1': 255 + resolution: {integrity: sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g==} 253 256 cpu: [x64] 254 257 os: [freebsd] 255 258 256 - '@rollup/rollup-linux-arm-gnueabihf@4.59.0': 257 - resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==} 259 + '@rollup/rollup-linux-arm-gnueabihf@4.60.1': 260 + resolution: {integrity: sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==} 258 261 cpu: [arm] 259 262 os: [linux] 260 263 261 - '@rollup/rollup-linux-arm-musleabihf@4.59.0': 262 - resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==} 264 + '@rollup/rollup-linux-arm-musleabihf@4.60.1': 265 + resolution: {integrity: sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==} 263 266 cpu: [arm] 264 267 os: [linux] 265 268 266 - '@rollup/rollup-linux-arm64-gnu@4.59.0': 267 - resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==} 269 + '@rollup/rollup-linux-arm64-gnu@4.60.1': 270 + resolution: {integrity: sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==} 268 271 cpu: [arm64] 269 272 os: [linux] 270 273 271 - '@rollup/rollup-linux-arm64-musl@4.59.0': 272 - resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==} 274 + '@rollup/rollup-linux-arm64-musl@4.60.1': 275 + resolution: {integrity: sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==} 273 276 cpu: [arm64] 274 277 os: [linux] 275 278 276 - '@rollup/rollup-linux-loong64-gnu@4.59.0': 277 - resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==} 279 + '@rollup/rollup-linux-loong64-gnu@4.60.1': 280 + resolution: {integrity: sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==} 278 281 cpu: [loong64] 279 282 os: [linux] 280 283 281 - '@rollup/rollup-linux-loong64-musl@4.59.0': 282 - resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==} 284 + '@rollup/rollup-linux-loong64-musl@4.60.1': 285 + resolution: {integrity: sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==} 283 286 cpu: [loong64] 284 287 os: [linux] 285 288 286 - '@rollup/rollup-linux-ppc64-gnu@4.59.0': 287 - resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==} 289 + '@rollup/rollup-linux-ppc64-gnu@4.60.1': 290 + resolution: {integrity: sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==} 288 291 cpu: [ppc64] 289 292 os: [linux] 290 293 291 - '@rollup/rollup-linux-ppc64-musl@4.59.0': 292 - resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==} 294 + '@rollup/rollup-linux-ppc64-musl@4.60.1': 295 + resolution: {integrity: sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==} 293 296 cpu: [ppc64] 294 297 os: [linux] 295 298 296 - '@rollup/rollup-linux-riscv64-gnu@4.59.0': 297 - resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==} 299 + '@rollup/rollup-linux-riscv64-gnu@4.60.1': 300 + resolution: {integrity: sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==} 298 301 cpu: [riscv64] 299 302 os: [linux] 300 303 301 - '@rollup/rollup-linux-riscv64-musl@4.59.0': 302 - resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==} 304 + '@rollup/rollup-linux-riscv64-musl@4.60.1': 305 + resolution: {integrity: sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==} 303 306 cpu: [riscv64] 304 307 os: [linux] 305 308 306 - '@rollup/rollup-linux-s390x-gnu@4.59.0': 307 - resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==} 309 + '@rollup/rollup-linux-s390x-gnu@4.60.1': 310 + resolution: {integrity: sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==} 308 311 cpu: [s390x] 309 312 os: [linux] 310 313 311 - '@rollup/rollup-linux-x64-gnu@4.59.0': 312 - resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==} 314 + '@rollup/rollup-linux-x64-gnu@4.60.1': 315 + resolution: {integrity: sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg==} 313 316 cpu: [x64] 314 317 os: [linux] 315 318 316 - '@rollup/rollup-linux-x64-musl@4.59.0': 317 - resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==} 319 + '@rollup/rollup-linux-x64-musl@4.60.1': 320 + resolution: {integrity: sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w==} 318 321 cpu: [x64] 319 322 os: [linux] 320 323 321 - '@rollup/rollup-openbsd-x64@4.59.0': 322 - resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==} 324 + '@rollup/rollup-openbsd-x64@4.60.1': 325 + resolution: {integrity: sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw==} 323 326 cpu: [x64] 324 327 os: [openbsd] 325 328 326 - '@rollup/rollup-openharmony-arm64@4.59.0': 327 - resolution: {integrity: sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==} 329 + '@rollup/rollup-openharmony-arm64@4.60.1': 330 + resolution: {integrity: sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA==} 328 331 cpu: [arm64] 329 332 os: [openharmony] 330 333 331 - '@rollup/rollup-win32-arm64-msvc@4.59.0': 332 - resolution: {integrity: sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==} 334 + '@rollup/rollup-win32-arm64-msvc@4.60.1': 335 + resolution: {integrity: sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g==} 333 336 cpu: [arm64] 334 337 os: [win32] 335 338 336 - '@rollup/rollup-win32-ia32-msvc@4.59.0': 337 - resolution: {integrity: sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==} 339 + '@rollup/rollup-win32-ia32-msvc@4.60.1': 340 + resolution: {integrity: sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg==} 338 341 cpu: [ia32] 339 342 os: [win32] 340 343 341 - '@rollup/rollup-win32-x64-gnu@4.59.0': 342 - resolution: {integrity: sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==} 344 + '@rollup/rollup-win32-x64-gnu@4.60.1': 345 + resolution: {integrity: sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg==} 343 346 cpu: [x64] 344 347 os: [win32] 345 348 346 - '@rollup/rollup-win32-x64-msvc@4.59.0': 347 - resolution: {integrity: sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==} 349 + '@rollup/rollup-win32-x64-msvc@4.60.1': 350 + resolution: {integrity: sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ==} 348 351 cpu: [x64] 349 352 os: [win32] 350 353 ··· 395 398 '@tauri-apps/api@2.10.1': 396 399 resolution: {integrity: sha512-hKL/jWf293UDSUN09rR69hrToyIXBb8CjGaWC7gfinvnQrBVvnLr08FeFi38gxtugAVyVcTa5/FD/Xnkb1siBw==} 397 400 401 + '@types/chai@5.2.3': 402 + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} 403 + 398 404 '@types/cookie@0.6.0': 399 405 resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} 406 + 407 + '@types/deep-eql@4.0.2': 408 + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} 400 409 401 410 '@types/estree@1.0.8': 402 411 resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} ··· 410 419 '@types/trusted-types@2.0.7': 411 420 resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} 412 421 413 - '@typescript-eslint/types@8.57.0': 414 - resolution: {integrity: sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg==} 422 + '@typescript-eslint/types@8.57.2': 423 + resolution: {integrity: sha512-/iZM6FnM4tnx9csuTxspMW4BOSegshwX5oBDznJ7S4WggL7Vczz5d2W11ecc4vRrQMQHXRSxzrCsyG5EsPPTbA==} 415 424 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 416 425 426 + '@vitest/expect@4.1.2': 427 + resolution: {integrity: sha512-gbu+7B0YgUJ2nkdsRJrFFW6X7NTP44WlhiclHniUhxADQJH5Szt9mZ9hWnJPJ8YwOK5zUOSSlSvyzRf0u1DSBQ==} 428 + 429 + '@vitest/mocker@4.1.2': 430 + resolution: {integrity: sha512-Ize4iQtEALHDttPRCmN+FKqOl2vxTiNUhzobQFFt/BM1lRUTG7zRCLOykG/6Vo4E4hnUdfVLo5/eqKPukcWW7Q==} 431 + peerDependencies: 432 + msw: ^2.4.9 433 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 434 + peerDependenciesMeta: 435 + msw: 436 + optional: true 437 + vite: 438 + optional: true 439 + 440 + '@vitest/pretty-format@4.1.2': 441 + resolution: {integrity: sha512-dwQga8aejqeuB+TvXCMzSQemvV9hNEtDDpgUKDzOmNQayl2OG241PSWeJwKRH3CiC+sESrmoFd49rfnq7T4RnA==} 442 + 443 + '@vitest/runner@4.1.2': 444 + resolution: {integrity: sha512-Gr+FQan34CdiYAwpGJmQG8PgkyFVmARK8/xSijia3eTFgVfpcpztWLuP6FttGNfPLJhaZVP/euvujeNYar36OQ==} 445 + 446 + '@vitest/snapshot@4.1.2': 447 + resolution: {integrity: sha512-g7yfUmxYS4mNxk31qbOYsSt2F4m1E02LFqO53Xpzg3zKMhLAPZAjjfyl9e6z7HrW6LvUdTwAQR3HHfLjpko16A==} 448 + 449 + '@vitest/spy@4.1.2': 450 + resolution: {integrity: sha512-DU4fBnbVCJGNBwVA6xSToNXrkZNSiw59H8tcuUspVMsBDBST4nfvsPsEHDHGtWRRnqBERBQu7TrTKskmjqTXKA==} 451 + 452 + '@vitest/utils@4.1.2': 453 + resolution: {integrity: sha512-xw2/TiX82lQHA06cgbqRKFb5lCAy3axQ4H4SoUFhUsg+wztiet+co86IAMDtF6Vm1hc7J6j09oh/rgDn+JdKIQ==} 454 + 417 455 acorn@8.16.0: 418 456 resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} 419 457 engines: {node: '>=0.4.0'} ··· 430 468 aria-query@5.3.1: 431 469 resolution: {integrity: sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==} 432 470 engines: {node: '>= 0.4'} 471 + 472 + assertion-error@2.0.1: 473 + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} 474 + engines: {node: '>=12'} 433 475 434 476 axobject-query@4.1.0: 435 477 resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} ··· 439 481 resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} 440 482 engines: {node: '>=6'} 441 483 484 + chai@6.2.2: 485 + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} 486 + engines: {node: '>=18'} 487 + 442 488 chokidar@4.0.3: 443 489 resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} 444 490 engines: {node: '>= 14.16.0'} ··· 456 502 457 503 color-name@1.1.4: 458 504 resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 505 + 506 + convert-source-map@2.0.0: 507 + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} 459 508 460 509 cookie@0.6.0: 461 510 resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} ··· 487 536 emoji-regex@8.0.0: 488 537 resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 489 538 539 + es-module-lexer@2.0.0: 540 + resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} 541 + 490 542 esbuild@0.25.12: 491 543 resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} 492 544 engines: {node: '>=18'} ··· 497 549 498 550 esrap@2.2.4: 499 551 resolution: {integrity: sha512-suICpxAmZ9A8bzJjEl/+rLJiDKC0X4gYWUxT6URAWBLvlXmtbZd5ySMu/N2ZGEtMCAmflUDPSehrP9BQcsGcSg==} 552 + 553 + estree-walker@3.0.3: 554 + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} 555 + 556 + expect-type@1.3.0: 557 + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} 558 + engines: {node: '>=12.0.0'} 500 559 501 560 fdir@6.5.0: 502 561 resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} ··· 557 616 engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 558 617 hasBin: true 559 618 619 + obug@2.1.1: 620 + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} 621 + 560 622 p-limit@2.3.0: 561 623 resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} 562 624 engines: {node: '>=6'} ··· 573 635 resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} 574 636 engines: {node: '>=8'} 575 637 638 + pathe@2.0.3: 639 + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} 640 + 576 641 picocolors@1.1.1: 577 642 resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} 578 643 579 - picomatch@4.0.3: 580 - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} 644 + picomatch@4.0.4: 645 + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} 581 646 engines: {node: '>=12'} 582 647 583 648 pngjs@5.0.0: ··· 604 669 require-main-filename@2.0.0: 605 670 resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} 606 671 607 - rollup@4.59.0: 608 - resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==} 672 + rollup@4.60.1: 673 + resolution: {integrity: sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==} 609 674 engines: {node: '>=18.0.0', npm: '>=8.0.0'} 610 675 hasBin: true 611 676 ··· 616 681 set-blocking@2.0.0: 617 682 resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} 618 683 619 - set-cookie-parser@3.0.1: 620 - resolution: {integrity: sha512-n7Z7dXZhJbwuAHhNzkTti6Aw9QDDjZtm3JTpTGATIdNzdQz5GuFs22w90BcvF4INfnrL5xrX3oGsuqO5Dx3A1Q==} 684 + set-cookie-parser@3.1.0: 685 + resolution: {integrity: sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw==} 686 + 687 + siginfo@2.0.0: 688 + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} 621 689 622 690 sirv@3.0.2: 623 691 resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} ··· 627 695 resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} 628 696 engines: {node: '>=0.10.0'} 629 697 698 + stackback@0.0.2: 699 + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} 700 + 701 + std-env@4.0.0: 702 + resolution: {integrity: sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==} 703 + 630 704 string-width@4.2.3: 631 705 resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 632 706 engines: {node: '>=8'} ··· 643 717 svelte: ^4.0.0 || ^5.0.0-next.0 644 718 typescript: '>=5.0.0' 645 719 646 - svelte@5.53.12: 647 - resolution: {integrity: sha512-4x/uk4rQe/d7RhfvS8wemTfNjQ0bJbKvamIzRBfTe2eHHjzBZ7PZicUQrC2ryj83xxEacfA1zHKd1ephD1tAxA==} 720 + svelte@5.55.1: 721 + resolution: {integrity: sha512-QjvU7EFemf6mRzdMGlAFttMWtAAVXrax61SZYHdkD6yoVGQ89VeyKfZD4H1JrV1WLmJBxWhFch9H6ig/87VGjw==} 722 + engines: {node: '>=18'} 723 + 724 + tinybench@2.9.0: 725 + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} 726 + 727 + tinyexec@1.0.4: 728 + resolution: {integrity: sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==} 648 729 engines: {node: '>=18'} 649 730 650 731 tinyglobby@0.2.15: 651 732 resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} 652 733 engines: {node: '>=12.0.0'} 734 + 735 + tinyrainbow@3.1.0: 736 + resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} 737 + engines: {node: '>=14.0.0'} 653 738 654 739 totalist@3.0.1: 655 740 resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} ··· 714 799 vite: 715 800 optional: true 716 801 802 + vitest@4.1.2: 803 + resolution: {integrity: sha512-xjR1dMTVHlFLh98JE3i/f/WePqJsah4A0FK9cc8Ehp9Udk0AZk6ccpIZhh1qJ/yxVWRZ+Q54ocnD8TXmkhspGg==} 804 + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} 805 + hasBin: true 806 + peerDependencies: 807 + '@edge-runtime/vm': '*' 808 + '@opentelemetry/api': ^1.9.0 809 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 810 + '@vitest/browser-playwright': 4.1.2 811 + '@vitest/browser-preview': 4.1.2 812 + '@vitest/browser-webdriverio': 4.1.2 813 + '@vitest/ui': 4.1.2 814 + happy-dom: '*' 815 + jsdom: '*' 816 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 817 + peerDependenciesMeta: 818 + '@edge-runtime/vm': 819 + optional: true 820 + '@opentelemetry/api': 821 + optional: true 822 + '@types/node': 823 + optional: true 824 + '@vitest/browser-playwright': 825 + optional: true 826 + '@vitest/browser-preview': 827 + optional: true 828 + '@vitest/browser-webdriverio': 829 + optional: true 830 + '@vitest/ui': 831 + optional: true 832 + happy-dom: 833 + optional: true 834 + jsdom: 835 + optional: true 836 + 717 837 which-module@2.0.1: 718 838 resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} 839 + 840 + why-is-node-running@2.3.0: 841 + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} 842 + engines: {node: '>=8'} 843 + hasBin: true 719 844 720 845 wrap-ansi@6.2.0: 721 846 resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} ··· 836 961 837 962 '@polka/url@1.0.0-next.29': {} 838 963 839 - '@rollup/rollup-android-arm-eabi@4.59.0': 964 + '@rollup/rollup-android-arm-eabi@4.60.1': 840 965 optional: true 841 966 842 - '@rollup/rollup-android-arm64@4.59.0': 967 + '@rollup/rollup-android-arm64@4.60.1': 843 968 optional: true 844 969 845 - '@rollup/rollup-darwin-arm64@4.59.0': 970 + '@rollup/rollup-darwin-arm64@4.60.1': 846 971 optional: true 847 972 848 - '@rollup/rollup-darwin-x64@4.59.0': 973 + '@rollup/rollup-darwin-x64@4.60.1': 849 974 optional: true 850 975 851 - '@rollup/rollup-freebsd-arm64@4.59.0': 976 + '@rollup/rollup-freebsd-arm64@4.60.1': 852 977 optional: true 853 978 854 - '@rollup/rollup-freebsd-x64@4.59.0': 979 + '@rollup/rollup-freebsd-x64@4.60.1': 855 980 optional: true 856 981 857 - '@rollup/rollup-linux-arm-gnueabihf@4.59.0': 982 + '@rollup/rollup-linux-arm-gnueabihf@4.60.1': 858 983 optional: true 859 984 860 - '@rollup/rollup-linux-arm-musleabihf@4.59.0': 985 + '@rollup/rollup-linux-arm-musleabihf@4.60.1': 861 986 optional: true 862 987 863 - '@rollup/rollup-linux-arm64-gnu@4.59.0': 988 + '@rollup/rollup-linux-arm64-gnu@4.60.1': 864 989 optional: true 865 990 866 - '@rollup/rollup-linux-arm64-musl@4.59.0': 991 + '@rollup/rollup-linux-arm64-musl@4.60.1': 867 992 optional: true 868 993 869 - '@rollup/rollup-linux-loong64-gnu@4.59.0': 994 + '@rollup/rollup-linux-loong64-gnu@4.60.1': 870 995 optional: true 871 996 872 - '@rollup/rollup-linux-loong64-musl@4.59.0': 997 + '@rollup/rollup-linux-loong64-musl@4.60.1': 873 998 optional: true 874 999 875 - '@rollup/rollup-linux-ppc64-gnu@4.59.0': 1000 + '@rollup/rollup-linux-ppc64-gnu@4.60.1': 876 1001 optional: true 877 1002 878 - '@rollup/rollup-linux-ppc64-musl@4.59.0': 1003 + '@rollup/rollup-linux-ppc64-musl@4.60.1': 879 1004 optional: true 880 1005 881 - '@rollup/rollup-linux-riscv64-gnu@4.59.0': 1006 + '@rollup/rollup-linux-riscv64-gnu@4.60.1': 882 1007 optional: true 883 1008 884 - '@rollup/rollup-linux-riscv64-musl@4.59.0': 1009 + '@rollup/rollup-linux-riscv64-musl@4.60.1': 885 1010 optional: true 886 1011 887 - '@rollup/rollup-linux-s390x-gnu@4.59.0': 1012 + '@rollup/rollup-linux-s390x-gnu@4.60.1': 888 1013 optional: true 889 1014 890 - '@rollup/rollup-linux-x64-gnu@4.59.0': 1015 + '@rollup/rollup-linux-x64-gnu@4.60.1': 891 1016 optional: true 892 1017 893 - '@rollup/rollup-linux-x64-musl@4.59.0': 1018 + '@rollup/rollup-linux-x64-musl@4.60.1': 894 1019 optional: true 895 1020 896 - '@rollup/rollup-openbsd-x64@4.59.0': 1021 + '@rollup/rollup-openbsd-x64@4.60.1': 897 1022 optional: true 898 1023 899 - '@rollup/rollup-openharmony-arm64@4.59.0': 1024 + '@rollup/rollup-openharmony-arm64@4.60.1': 900 1025 optional: true 901 1026 902 - '@rollup/rollup-win32-arm64-msvc@4.59.0': 1027 + '@rollup/rollup-win32-arm64-msvc@4.60.1': 903 1028 optional: true 904 1029 905 - '@rollup/rollup-win32-ia32-msvc@4.59.0': 1030 + '@rollup/rollup-win32-ia32-msvc@4.60.1': 906 1031 optional: true 907 1032 908 - '@rollup/rollup-win32-x64-gnu@4.59.0': 1033 + '@rollup/rollup-win32-x64-gnu@4.60.1': 909 1034 optional: true 910 1035 911 - '@rollup/rollup-win32-x64-msvc@4.59.0': 1036 + '@rollup/rollup-win32-x64-msvc@4.60.1': 912 1037 optional: true 913 1038 914 1039 '@standard-schema/spec@1.1.0': {} ··· 917 1042 dependencies: 918 1043 acorn: 8.16.0 919 1044 920 - '@sveltejs/adapter-static@3.0.10(@sveltejs/kit@2.55.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.53.12)(vite@6.4.1(@types/node@22.19.15)))(svelte@5.53.12)(typescript@5.9.3)(vite@6.4.1(@types/node@22.19.15)))': 1045 + '@sveltejs/adapter-static@3.0.10(@sveltejs/kit@2.55.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.55.1)(vite@6.4.1(@types/node@22.19.15)))(svelte@5.55.1)(typescript@5.9.3)(vite@6.4.1(@types/node@22.19.15)))': 921 1046 dependencies: 922 - '@sveltejs/kit': 2.55.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.53.12)(vite@6.4.1(@types/node@22.19.15)))(svelte@5.53.12)(typescript@5.9.3)(vite@6.4.1(@types/node@22.19.15)) 1047 + '@sveltejs/kit': 2.55.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.55.1)(vite@6.4.1(@types/node@22.19.15)))(svelte@5.55.1)(typescript@5.9.3)(vite@6.4.1(@types/node@22.19.15)) 923 1048 924 - '@sveltejs/kit@2.55.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.53.12)(vite@6.4.1(@types/node@22.19.15)))(svelte@5.53.12)(typescript@5.9.3)(vite@6.4.1(@types/node@22.19.15))': 1049 + '@sveltejs/kit@2.55.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.55.1)(vite@6.4.1(@types/node@22.19.15)))(svelte@5.55.1)(typescript@5.9.3)(vite@6.4.1(@types/node@22.19.15))': 925 1050 dependencies: 926 1051 '@standard-schema/spec': 1.1.0 927 1052 '@sveltejs/acorn-typescript': 1.0.9(acorn@8.16.0) 928 - '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.53.12)(vite@6.4.1(@types/node@22.19.15)) 1053 + '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.55.1)(vite@6.4.1(@types/node@22.19.15)) 929 1054 '@types/cookie': 0.6.0 930 1055 acorn: 8.16.0 931 1056 cookie: 0.6.0 ··· 934 1059 kleur: 4.1.5 935 1060 magic-string: 0.30.21 936 1061 mrmime: 2.0.1 937 - set-cookie-parser: 3.0.1 1062 + set-cookie-parser: 3.1.0 938 1063 sirv: 3.0.2 939 - svelte: 5.53.12 1064 + svelte: 5.55.1 940 1065 vite: 6.4.1(@types/node@22.19.15) 941 1066 optionalDependencies: 942 1067 typescript: 5.9.3 943 1068 944 - '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.53.12)(vite@6.4.1(@types/node@22.19.15)))(svelte@5.53.12)(vite@6.4.1(@types/node@22.19.15))': 1069 + '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.55.1)(vite@6.4.1(@types/node@22.19.15)))(svelte@5.55.1)(vite@6.4.1(@types/node@22.19.15))': 945 1070 dependencies: 946 - '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.53.12)(vite@6.4.1(@types/node@22.19.15)) 1071 + '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.55.1)(vite@6.4.1(@types/node@22.19.15)) 947 1072 debug: 4.4.3 948 - svelte: 5.53.12 1073 + svelte: 5.55.1 949 1074 vite: 6.4.1(@types/node@22.19.15) 950 1075 transitivePeerDependencies: 951 1076 - supports-color 952 1077 953 - '@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.53.12)(vite@6.4.1(@types/node@22.19.15))': 1078 + '@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.55.1)(vite@6.4.1(@types/node@22.19.15))': 954 1079 dependencies: 955 - '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.53.12)(vite@6.4.1(@types/node@22.19.15)))(svelte@5.53.12)(vite@6.4.1(@types/node@22.19.15)) 1080 + '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.55.1)(vite@6.4.1(@types/node@22.19.15)))(svelte@5.55.1)(vite@6.4.1(@types/node@22.19.15)) 956 1081 debug: 4.4.3 957 1082 deepmerge: 4.3.1 958 1083 kleur: 4.1.5 959 1084 magic-string: 0.30.21 960 - svelte: 5.53.12 1085 + svelte: 5.55.1 961 1086 vite: 6.4.1(@types/node@22.19.15) 962 1087 vitefu: 1.1.2(vite@6.4.1(@types/node@22.19.15)) 963 1088 transitivePeerDependencies: ··· 965 1090 966 1091 '@tauri-apps/api@2.10.1': {} 967 1092 1093 + '@types/chai@5.2.3': 1094 + dependencies: 1095 + '@types/deep-eql': 4.0.2 1096 + assertion-error: 2.0.1 1097 + 968 1098 '@types/cookie@0.6.0': {} 969 1099 1100 + '@types/deep-eql@4.0.2': {} 1101 + 970 1102 '@types/estree@1.0.8': {} 971 1103 972 1104 '@types/node@22.19.15': ··· 979 1111 980 1112 '@types/trusted-types@2.0.7': {} 981 1113 982 - '@typescript-eslint/types@8.57.0': {} 1114 + '@typescript-eslint/types@8.57.2': {} 1115 + 1116 + '@vitest/expect@4.1.2': 1117 + dependencies: 1118 + '@standard-schema/spec': 1.1.0 1119 + '@types/chai': 5.2.3 1120 + '@vitest/spy': 4.1.2 1121 + '@vitest/utils': 4.1.2 1122 + chai: 6.2.2 1123 + tinyrainbow: 3.1.0 1124 + 1125 + '@vitest/mocker@4.1.2(vite@6.4.1(@types/node@22.19.15))': 1126 + dependencies: 1127 + '@vitest/spy': 4.1.2 1128 + estree-walker: 3.0.3 1129 + magic-string: 0.30.21 1130 + optionalDependencies: 1131 + vite: 6.4.1(@types/node@22.19.15) 1132 + 1133 + '@vitest/pretty-format@4.1.2': 1134 + dependencies: 1135 + tinyrainbow: 3.1.0 1136 + 1137 + '@vitest/runner@4.1.2': 1138 + dependencies: 1139 + '@vitest/utils': 4.1.2 1140 + pathe: 2.0.3 1141 + 1142 + '@vitest/snapshot@4.1.2': 1143 + dependencies: 1144 + '@vitest/pretty-format': 4.1.2 1145 + '@vitest/utils': 4.1.2 1146 + magic-string: 0.30.21 1147 + pathe: 2.0.3 1148 + 1149 + '@vitest/spy@4.1.2': {} 1150 + 1151 + '@vitest/utils@4.1.2': 1152 + dependencies: 1153 + '@vitest/pretty-format': 4.1.2 1154 + convert-source-map: 2.0.0 1155 + tinyrainbow: 3.1.0 983 1156 984 1157 acorn@8.16.0: {} 985 1158 ··· 991 1164 992 1165 aria-query@5.3.1: {} 993 1166 1167 + assertion-error@2.0.1: {} 1168 + 994 1169 axobject-query@4.1.0: {} 995 1170 996 1171 camelcase@5.3.1: {} 1172 + 1173 + chai@6.2.2: {} 997 1174 998 1175 chokidar@4.0.3: 999 1176 dependencies: ··· 1013 1190 1014 1191 color-name@1.1.4: {} 1015 1192 1193 + convert-source-map@2.0.0: {} 1194 + 1016 1195 cookie@0.6.0: {} 1017 1196 1018 1197 debug@4.4.3: ··· 1028 1207 dijkstrajs@1.0.3: {} 1029 1208 1030 1209 emoji-regex@8.0.0: {} 1210 + 1211 + es-module-lexer@2.0.0: {} 1031 1212 1032 1213 esbuild@0.25.12: 1033 1214 optionalDependencies: ··· 1063 1244 esrap@2.2.4: 1064 1245 dependencies: 1065 1246 '@jridgewell/sourcemap-codec': 1.5.5 1066 - '@typescript-eslint/types': 8.57.0 1247 + '@typescript-eslint/types': 8.57.2 1067 1248 1068 - fdir@6.5.0(picomatch@4.0.3): 1249 + estree-walker@3.0.3: 1250 + dependencies: 1251 + '@types/estree': 1.0.8 1252 + 1253 + expect-type@1.3.0: {} 1254 + 1255 + fdir@6.5.0(picomatch@4.0.4): 1069 1256 optionalDependencies: 1070 - picomatch: 4.0.3 1257 + picomatch: 4.0.4 1071 1258 1072 1259 find-up@4.1.0: 1073 1260 dependencies: ··· 1105 1292 1106 1293 nanoid@3.3.11: {} 1107 1294 1295 + obug@2.1.1: {} 1296 + 1108 1297 p-limit@2.3.0: 1109 1298 dependencies: 1110 1299 p-try: 2.2.0 ··· 1117 1306 1118 1307 path-exists@4.0.0: {} 1119 1308 1309 + pathe@2.0.3: {} 1310 + 1120 1311 picocolors@1.1.1: {} 1121 1312 1122 - picomatch@4.0.3: {} 1313 + picomatch@4.0.4: {} 1123 1314 1124 1315 pngjs@5.0.0: {} 1125 1316 ··· 1141 1332 1142 1333 require-main-filename@2.0.0: {} 1143 1334 1144 - rollup@4.59.0: 1335 + rollup@4.60.1: 1145 1336 dependencies: 1146 1337 '@types/estree': 1.0.8 1147 1338 optionalDependencies: 1148 - '@rollup/rollup-android-arm-eabi': 4.59.0 1149 - '@rollup/rollup-android-arm64': 4.59.0 1150 - '@rollup/rollup-darwin-arm64': 4.59.0 1151 - '@rollup/rollup-darwin-x64': 4.59.0 1152 - '@rollup/rollup-freebsd-arm64': 4.59.0 1153 - '@rollup/rollup-freebsd-x64': 4.59.0 1154 - '@rollup/rollup-linux-arm-gnueabihf': 4.59.0 1155 - '@rollup/rollup-linux-arm-musleabihf': 4.59.0 1156 - '@rollup/rollup-linux-arm64-gnu': 4.59.0 1157 - '@rollup/rollup-linux-arm64-musl': 4.59.0 1158 - '@rollup/rollup-linux-loong64-gnu': 4.59.0 1159 - '@rollup/rollup-linux-loong64-musl': 4.59.0 1160 - '@rollup/rollup-linux-ppc64-gnu': 4.59.0 1161 - '@rollup/rollup-linux-ppc64-musl': 4.59.0 1162 - '@rollup/rollup-linux-riscv64-gnu': 4.59.0 1163 - '@rollup/rollup-linux-riscv64-musl': 4.59.0 1164 - '@rollup/rollup-linux-s390x-gnu': 4.59.0 1165 - '@rollup/rollup-linux-x64-gnu': 4.59.0 1166 - '@rollup/rollup-linux-x64-musl': 4.59.0 1167 - '@rollup/rollup-openbsd-x64': 4.59.0 1168 - '@rollup/rollup-openharmony-arm64': 4.59.0 1169 - '@rollup/rollup-win32-arm64-msvc': 4.59.0 1170 - '@rollup/rollup-win32-ia32-msvc': 4.59.0 1171 - '@rollup/rollup-win32-x64-gnu': 4.59.0 1172 - '@rollup/rollup-win32-x64-msvc': 4.59.0 1339 + '@rollup/rollup-android-arm-eabi': 4.60.1 1340 + '@rollup/rollup-android-arm64': 4.60.1 1341 + '@rollup/rollup-darwin-arm64': 4.60.1 1342 + '@rollup/rollup-darwin-x64': 4.60.1 1343 + '@rollup/rollup-freebsd-arm64': 4.60.1 1344 + '@rollup/rollup-freebsd-x64': 4.60.1 1345 + '@rollup/rollup-linux-arm-gnueabihf': 4.60.1 1346 + '@rollup/rollup-linux-arm-musleabihf': 4.60.1 1347 + '@rollup/rollup-linux-arm64-gnu': 4.60.1 1348 + '@rollup/rollup-linux-arm64-musl': 4.60.1 1349 + '@rollup/rollup-linux-loong64-gnu': 4.60.1 1350 + '@rollup/rollup-linux-loong64-musl': 4.60.1 1351 + '@rollup/rollup-linux-ppc64-gnu': 4.60.1 1352 + '@rollup/rollup-linux-ppc64-musl': 4.60.1 1353 + '@rollup/rollup-linux-riscv64-gnu': 4.60.1 1354 + '@rollup/rollup-linux-riscv64-musl': 4.60.1 1355 + '@rollup/rollup-linux-s390x-gnu': 4.60.1 1356 + '@rollup/rollup-linux-x64-gnu': 4.60.1 1357 + '@rollup/rollup-linux-x64-musl': 4.60.1 1358 + '@rollup/rollup-openbsd-x64': 4.60.1 1359 + '@rollup/rollup-openharmony-arm64': 4.60.1 1360 + '@rollup/rollup-win32-arm64-msvc': 4.60.1 1361 + '@rollup/rollup-win32-ia32-msvc': 4.60.1 1362 + '@rollup/rollup-win32-x64-gnu': 4.60.1 1363 + '@rollup/rollup-win32-x64-msvc': 4.60.1 1173 1364 fsevents: 2.3.3 1174 1365 1175 1366 sade@1.8.1: ··· 1178 1369 1179 1370 set-blocking@2.0.0: {} 1180 1371 1181 - set-cookie-parser@3.0.1: {} 1372 + set-cookie-parser@3.1.0: {} 1373 + 1374 + siginfo@2.0.0: {} 1182 1375 1183 1376 sirv@3.0.2: 1184 1377 dependencies: ··· 1187 1380 totalist: 3.0.1 1188 1381 1189 1382 source-map-js@1.2.1: {} 1383 + 1384 + stackback@0.0.2: {} 1385 + 1386 + std-env@4.0.0: {} 1190 1387 1191 1388 string-width@4.2.3: 1192 1389 dependencies: ··· 1198 1395 dependencies: 1199 1396 ansi-regex: 5.0.1 1200 1397 1201 - svelte-check@4.4.5(picomatch@4.0.3)(svelte@5.53.12)(typescript@5.9.3): 1398 + svelte-check@4.4.5(picomatch@4.0.4)(svelte@5.55.1)(typescript@5.9.3): 1202 1399 dependencies: 1203 1400 '@jridgewell/trace-mapping': 0.3.31 1204 1401 chokidar: 4.0.3 1205 - fdir: 6.5.0(picomatch@4.0.3) 1402 + fdir: 6.5.0(picomatch@4.0.4) 1206 1403 picocolors: 1.1.1 1207 1404 sade: 1.8.1 1208 - svelte: 5.53.12 1405 + svelte: 5.55.1 1209 1406 typescript: 5.9.3 1210 1407 transitivePeerDependencies: 1211 1408 - picomatch 1212 1409 1213 - svelte@5.53.12: 1410 + svelte@5.55.1: 1214 1411 dependencies: 1215 1412 '@jridgewell/remapping': 2.3.5 1216 1413 '@jridgewell/sourcemap-codec': 1.5.5 ··· 1229 1426 magic-string: 0.30.21 1230 1427 zimmerframe: 1.1.4 1231 1428 1429 + tinybench@2.9.0: {} 1430 + 1431 + tinyexec@1.0.4: {} 1432 + 1232 1433 tinyglobby@0.2.15: 1233 1434 dependencies: 1234 - fdir: 6.5.0(picomatch@4.0.3) 1235 - picomatch: 4.0.3 1435 + fdir: 6.5.0(picomatch@4.0.4) 1436 + picomatch: 4.0.4 1437 + 1438 + tinyrainbow@3.1.0: {} 1236 1439 1237 1440 totalist@3.0.1: {} 1238 1441 ··· 1245 1448 vite@6.4.1(@types/node@22.19.15): 1246 1449 dependencies: 1247 1450 esbuild: 0.25.12 1248 - fdir: 6.5.0(picomatch@4.0.3) 1249 - picomatch: 4.0.3 1451 + fdir: 6.5.0(picomatch@4.0.4) 1452 + picomatch: 4.0.4 1250 1453 postcss: 8.5.8 1251 - rollup: 4.59.0 1454 + rollup: 4.60.1 1252 1455 tinyglobby: 0.2.15 1253 1456 optionalDependencies: 1254 1457 '@types/node': 22.19.15 ··· 1258 1461 optionalDependencies: 1259 1462 vite: 6.4.1(@types/node@22.19.15) 1260 1463 1464 + vitest@4.1.2(@types/node@22.19.15)(vite@6.4.1(@types/node@22.19.15)): 1465 + dependencies: 1466 + '@vitest/expect': 4.1.2 1467 + '@vitest/mocker': 4.1.2(vite@6.4.1(@types/node@22.19.15)) 1468 + '@vitest/pretty-format': 4.1.2 1469 + '@vitest/runner': 4.1.2 1470 + '@vitest/snapshot': 4.1.2 1471 + '@vitest/spy': 4.1.2 1472 + '@vitest/utils': 4.1.2 1473 + es-module-lexer: 2.0.0 1474 + expect-type: 1.3.0 1475 + magic-string: 0.30.21 1476 + obug: 2.1.1 1477 + pathe: 2.0.3 1478 + picomatch: 4.0.4 1479 + std-env: 4.0.0 1480 + tinybench: 2.9.0 1481 + tinyexec: 1.0.4 1482 + tinyglobby: 0.2.15 1483 + tinyrainbow: 3.1.0 1484 + vite: 6.4.1(@types/node@22.19.15) 1485 + why-is-node-running: 2.3.0 1486 + optionalDependencies: 1487 + '@types/node': 22.19.15 1488 + transitivePeerDependencies: 1489 + - msw 1490 + 1261 1491 which-module@2.0.1: {} 1492 + 1493 + why-is-node-running@2.3.0: 1494 + dependencies: 1495 + siginfo: 2.0.0 1496 + stackback: 0.0.2 1262 1497 1263 1498 wrap-ansi@6.2.0: 1264 1499 dependencies:
+68 -92
apps/identity-wallet/src/lib/utils/deadline.test.ts
··· 1 - /** 2 - * Tests for deadline utilities. 3 - * 4 - * These tests verify: 5 - * - plc-key-management.AC6.3: `getDeadline('2026-03-29T12:00:00.000Z')` returns `Date` exactly 72h later 6 - * - plc-key-management.AC6.5: Urgency thresholds (safe >24h, warning 4-24h, critical <4h, expired <=0) 7 - * - `formatCountdown` edge cases (72h, 0h, 23h 59m remaining) 8 - * 9 - * When vitest is configured, run with: pnpm test src/lib/utils/deadline.test.ts 10 - * 11 - * Test cases: 12 - * 13 - * 1. getDeadline('2026-03-29T12:00:00.000Z') → Date('2026-04-01T12:00:00.000Z') 14 - * - Verifies exactly 72 hours (RECOVERY_WINDOW_MS) is added to createdAt 15 - * 16 - * 2. getUrgency with various remaining times: 17 - * - deadline - 48h (safe): remaining > 24h → 'safe' 18 - * - deadline - 12h (warning): 4h < remaining < 24h → 'warning' 19 - * - deadline - 2h (critical): remaining < 4h → 'critical' 20 - * - deadline + 0h (exactly at): remaining <= 0 → 'expired' 21 - * - deadline + 1h (past): remaining < 0 → 'expired' 22 - * 23 - * 3. formatCountdown edge cases: 24 - * - 72h remaining → '72h 0m remaining' 25 - * - 23h 59m remaining → '23h 59m remaining' 26 - * - 1m remaining → '0h 1m remaining' 27 - * - 0m remaining → 'Expired' 28 - * - past deadline → 'Expired' 29 - */ 1 + import { describe, it, expect } from 'vitest'; 2 + import { getDeadline, getUrgency, formatCountdown, RECOVERY_WINDOW_MS } from './deadline'; 30 3 31 - import { getDeadline, getUrgency, formatCountdown, RECOVERY_WINDOW_MS, type Urgency } from './deadline'; 4 + describe('deadline utils', () => { 5 + describe('getDeadline', () => { 6 + it('returns a date exactly 72 hours after createdAt', () => { 7 + const deadline = getDeadline('2026-03-29T12:00:00.000Z'); 8 + expect(deadline.getTime()).toBe(new Date('2026-04-01T12:00:00.000Z').getTime()); 9 + }); 32 10 33 - // Placeholder for when vitest is available. 34 - // Tests are documented above as acceptance criteria. 11 + it('RECOVERY_WINDOW_MS equals 72 hours in milliseconds', () => { 12 + expect(RECOVERY_WINDOW_MS).toBe(72 * 60 * 60 * 1000); 13 + }); 14 + }); 35 15 36 - // Example test structure (for when vitest is configured): 37 - // 38 - // import { describe, it, expect } from 'vitest'; 39 - // 40 - // describe('deadline utils', () => { 41 - // describe('getDeadline', () => { 42 - // it('should return a date 72 hours after the created time', () => { 43 - // const createdAt = '2026-03-29T12:00:00.000Z'; 44 - // const deadline = getDeadline(createdAt); 45 - // const expected = new Date('2026-04-01T12:00:00.000Z'); 46 - // expect(deadline.getTime()).toBe(expected.getTime()); 47 - // }); 48 - // }); 49 - // 50 - // describe('getUrgency', () => { 51 - // it('should return safe when >24 hours remaining', () => { 52 - // const deadline = new Date('2026-04-01T12:00:00.000Z'); 53 - // const now = new Date('2026-03-29T12:00:00.000Z').getTime(); // 48h before 54 - // expect(getUrgency(deadline, now)).toBe('safe'); 55 - // }); 56 - // 57 - // it('should return warning when 4-24 hours remaining', () => { 58 - // const deadline = new Date('2026-04-01T12:00:00.000Z'); 59 - // const now = new Date('2026-03-31T12:00:00.000Z').getTime(); // 12h before 60 - // expect(getUrgency(deadline, now)).toBe('warning'); 61 - // }); 62 - // 63 - // it('should return critical when <4 hours remaining', () => { 64 - // const deadline = new Date('2026-04-01T12:00:00.000Z'); 65 - // const now = new Date('2026-04-01T10:00:00.000Z').getTime(); // 2h before 66 - // expect(getUrgency(deadline, now)).toBe('critical'); 67 - // }); 68 - // 69 - // it('should return expired when exactly at deadline', () => { 70 - // const deadline = new Date('2026-04-01T12:00:00.000Z'); 71 - // const now = deadline.getTime(); 72 - // expect(getUrgency(deadline, now)).toBe('expired'); 73 - // }); 74 - // 75 - // it('should return expired when past deadline', () => { 76 - // const deadline = new Date('2026-04-01T12:00:00.000Z'); 77 - // const now = new Date('2026-04-01T13:00:00.000Z').getTime(); // 1h after 78 - // expect(getUrgency(deadline, now)).toBe('expired'); 79 - // }); 80 - // }); 81 - // 82 - // describe('formatCountdown', () => { 83 - // it('should format 72 hours as "72h 0m remaining"', () => { 84 - // const deadline = new Date('2026-04-01T12:00:00.000Z'); 85 - // const now = new Date('2026-03-29T12:00:00.000Z').getTime(); 86 - // expect(formatCountdown(deadline, now)).toBe('72h 0m remaining'); 87 - // }); 88 - // 89 - // it('should return "Expired" when time is past deadline', () => { 90 - // const deadline = new Date('2026-04-01T12:00:00.000Z'); 91 - // const now = new Date('2026-04-01T13:00:00.000Z').getTime(); 92 - // expect(formatCountdown(deadline, now)).toBe('Expired'); 93 - // }); 94 - // }); 95 - // }); 16 + describe('getUrgency', () => { 17 + const deadline = new Date('2026-04-01T12:00:00.000Z'); 18 + 19 + it('returns safe when >24 hours remaining', () => { 20 + const now = deadline.getTime() - 48 * 3600_000; // 48h before 21 + expect(getUrgency(deadline, now)).toBe('safe'); 22 + }); 23 + 24 + it('returns warning when 4-24 hours remaining', () => { 25 + const now = deadline.getTime() - 12 * 3600_000; // 12h before 26 + expect(getUrgency(deadline, now)).toBe('warning'); 27 + }); 28 + 29 + it('returns critical when <4 hours remaining', () => { 30 + const now = deadline.getTime() - 2 * 3600_000; // 2h before 31 + expect(getUrgency(deadline, now)).toBe('critical'); 32 + }); 33 + 34 + it('returns expired at exactly the deadline', () => { 35 + expect(getUrgency(deadline, deadline.getTime())).toBe('expired'); 36 + }); 37 + 38 + it('returns expired when past deadline', () => { 39 + const now = deadline.getTime() + 3600_000; // 1h after 40 + expect(getUrgency(deadline, now)).toBe('expired'); 41 + }); 42 + }); 43 + 44 + describe('formatCountdown', () => { 45 + const deadline = new Date('2026-04-01T12:00:00.000Z'); 46 + 47 + it('formats 72 hours remaining', () => { 48 + const now = deadline.getTime() - 72 * 3600_000; 49 + expect(formatCountdown(deadline, now)).toBe('72h 0m remaining'); 50 + }); 51 + 52 + it('formats 23h 59m remaining', () => { 53 + const now = deadline.getTime() - (23 * 3600_000 + 59 * 60_000); 54 + expect(formatCountdown(deadline, now)).toBe('23h 59m remaining'); 55 + }); 56 + 57 + it('formats 0h 1m remaining', () => { 58 + const now = deadline.getTime() - 60_000; 59 + expect(formatCountdown(deadline, now)).toBe('0h 1m remaining'); 60 + }); 61 + 62 + it('returns Expired at exactly the deadline', () => { 63 + expect(formatCountdown(deadline, deadline.getTime())).toBe('Expired'); 64 + }); 65 + 66 + it('returns Expired when past deadline', () => { 67 + const now = deadline.getTime() + 3600_000; 68 + expect(formatCountdown(deadline, now)).toBe('Expired'); 69 + }); 70 + }); 71 + });