A simple to-do app focused on tasks that can be completed within a specific time span.
0
fork

Configure Feed

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

sending messages works

+349 -1
+65
app/pages/index.vue
··· 24 24 }); 25 25 26 26 const { isMobile } = useDevice(); 27 + 28 + onMounted(async () => { 29 + if ("serviceWorker" in navigator) { 30 + try { 31 + const reg = await navigator.serviceWorker.register("/sw.js"); 32 + 33 + await navigator.serviceWorker.ready; 34 + 35 + console.log("SW ist bereit und aktiv:", reg.active); 36 + } catch (err) { 37 + console.error("SW registration failed", err); 38 + } 39 + } 40 + }); 41 + 42 + async function send() { 43 + const permission = await Notification.requestPermission(); 44 + 45 + if (permission !== "granted") return; 46 + 47 + const reg = await navigator.serviceWorker.ready; 48 + 49 + const sub = await reg.pushManager.subscribe({ 50 + userVisibleOnly: true, 51 + applicationServerKey: 52 + "BKkvpMKOQ3wvNUpoohpuZmTUCNe8rH4bZwCbTeLW16F1ZeUm9DDEavdpXOfXIR6PWZpPswiCYte1KMveWMFvslY", 53 + }); 54 + 55 + const fetch = useRequestFetch(); 56 + 57 + const response = await fetch(`/api/subscription/`, { 58 + method: "POST", 59 + body: sub.toJSON(), 60 + ...useFetchOptions(), 61 + }).catch(async (err) => { 62 + //todo - show in toast 63 + console.warn(err); 64 + // await this.fetch(); 65 + }); 66 + 67 + console.log(response) 68 + } 69 + 70 + async function msg() { 71 + const fetch = useRequestFetch(); 72 + 73 + await fetch(`/api/subscription/sendNotification`, { 74 + method: "POST", 75 + ...useFetchOptions(), 76 + }).catch(async (err) => { 77 + //todo - show in toast 78 + console.warn(err); 79 + // await this.fetch(); 80 + }); 81 + } 27 82 </script> 28 83 <template> 29 84 <div> ··· 31 86 <SettingsSheet v-model:is-open="isSettingsSheetOpen" /> 32 87 <EditTodoSheet /> 33 88 <NewTodoSheet v-model:is-open="isNewSheetOpen" /> 89 + 90 + <div> 91 + <h1>testing begin</h1> 92 + 93 + <button @click="send()">send</button> 94 + <br></br> 95 + <button @click="msg()">message</button> 96 + 97 + <h1>testing end</h1> 98 + </div> 34 99 35 100 <div v-if="!isMobile"> 36 101 <SplitterGroup direction="horizontal">
+2 -1
package.json
··· 22 22 "@iconify-json/material-symbols": "^1.2.64", 23 23 "@internationalized/date": "^3.12.0", 24 24 "@nuxt/icon": "^2.2.1", 25 - "@nuxtjs/i18n": "^10.2.4", 26 25 "@nuxtjs/device": "^4.0.0", 26 + "@nuxtjs/i18n": "^10.2.4", 27 27 "@nuxtjs/tailwindcss": "^7.0.0-beta.1", 28 28 "@pinia/nuxt": "^0.11.3", 29 29 "@upstash/redis": "^1.37.0", ··· 40 40 "vaul-vue": "^0.4.1", 41 41 "vue": "^3.5.31", 42 42 "vue-router": "^5.0.4", 43 + "web-push": "^3.6.7", 43 44 "zod": "^4.3.6" 44 45 }, 45 46 "devDependencies": {
+154
pnpm-lock.yaml
··· 74 74 vue-router: 75 75 specifier: ^5.0.4 76 76 version: 5.0.4(@vue/compiler-sfc@3.5.30)(pinia@3.0.4(typescript@6.0.2)(vue@3.5.31(typescript@6.0.2)))(vue@3.5.31(typescript@6.0.2)) 77 + web-push: 78 + specifier: ^3.6.7 79 + version: 3.6.7 77 80 zod: 78 81 specifier: ^4.3.6 79 82 version: 4.3.6 ··· 338 341 engines: {node: '>=14.21.3'} 339 342 cpu: [arm64] 340 343 os: [linux] 344 + libc: [musl] 341 345 342 346 '@biomejs/cli-linux-arm64@2.4.10': 343 347 resolution: {integrity: sha512-7MH1CMW5uuxQ/s7FLST63qF8B3Hgu2HRdZ7tA1X1+mk+St4JOuIrqdhIBnnyqeyWJNI+Bww7Es5QZ0wIc1Cmkw==} 344 348 engines: {node: '>=14.21.3'} 345 349 cpu: [arm64] 346 350 os: [linux] 351 + libc: [glibc] 347 352 348 353 '@biomejs/cli-linux-x64-musl@2.4.10': 349 354 resolution: {integrity: sha512-kDTi3pI6PBN6CiczsWYOyP2zk0IJI08EWEQyDMQWW221rPaaEz6FvjLhnU07KMzLv8q3qSuoB93ua6inSQ55Tw==} 350 355 engines: {node: '>=14.21.3'} 351 356 cpu: [x64] 352 357 os: [linux] 358 + libc: [musl] 353 359 354 360 '@biomejs/cli-linux-x64@2.4.10': 355 361 resolution: {integrity: sha512-tZLvEEi2u9Xu1zAqRjTcpIDGVtldigVvzug2fTuPG0ME/g8/mXpRPcNgLB22bGn6FvLJpHHnqLnwliOu8xjYrg==} 356 362 engines: {node: '>=14.21.3'} 357 363 cpu: [x64] 358 364 os: [linux] 365 + libc: [glibc] 359 366 360 367 '@biomejs/cli-win32-arm64@2.4.10': 361 368 resolution: {integrity: sha512-umwQU6qPzH+ISTf/eHyJ/QoQnJs3V9Vpjz2OjZXe9MVBZ7prgGafMy7yYeRGnlmDAn87AKTF3Q6weLoMGpeqdQ==} ··· 1153 1160 engines: {node: ^20.19.0 || >=22.12.0} 1154 1161 cpu: [arm64] 1155 1162 os: [linux] 1163 + libc: [glibc] 1156 1164 1157 1165 '@oxc-minify/binding-linux-arm64-musl@0.117.0': 1158 1166 resolution: {integrity: sha512-C3zapJconWpl2Y7LR3GkRkH6jxpuV2iVUfkFcHT5Ffn4Zu7l88mZa2dhcfdULZDybN1Phka/P34YUzuskUUrXw==} 1159 1167 engines: {node: ^20.19.0 || >=22.12.0} 1160 1168 cpu: [arm64] 1161 1169 os: [linux] 1170 + libc: [musl] 1162 1171 1163 1172 '@oxc-minify/binding-linux-ppc64-gnu@0.117.0': 1164 1173 resolution: {integrity: sha512-2T/Bm+3/qTfuNS4gKSzL8qbiYk+ErHW2122CtDx+ilZAzvWcJ8IbqdZIbEWOlwwe03lESTxPwTBLFqVgQU2OeQ==} 1165 1174 engines: {node: ^20.19.0 || >=22.12.0} 1166 1175 cpu: [ppc64] 1167 1176 os: [linux] 1177 + libc: [glibc] 1168 1178 1169 1179 '@oxc-minify/binding-linux-riscv64-gnu@0.117.0': 1170 1180 resolution: {integrity: sha512-MKLjpldYkeoB4T+yAi4aIAb0waifxUjLcKkCUDmYAY3RqBJTvWK34KtfaKZL0IBMIXfD92CbKkcxQirDUS9Xcg==} 1171 1181 engines: {node: ^20.19.0 || >=22.12.0} 1172 1182 cpu: [riscv64] 1173 1183 os: [linux] 1184 + libc: [glibc] 1174 1185 1175 1186 '@oxc-minify/binding-linux-riscv64-musl@0.117.0': 1176 1187 resolution: {integrity: sha512-UFVcbPvKUStry6JffriobBp8BHtjmLLPl4bCY+JMxIn/Q3pykCpZzRwFTcDurG/kY8tm+uSNfKKdRNa5Nh9A7g==} 1177 1188 engines: {node: ^20.19.0 || >=22.12.0} 1178 1189 cpu: [riscv64] 1179 1190 os: [linux] 1191 + libc: [musl] 1180 1192 1181 1193 '@oxc-minify/binding-linux-s390x-gnu@0.117.0': 1182 1194 resolution: {integrity: sha512-B9GyPQ1NKbvpETVAMyJMfRlD3c6UJ7kiuFUAlx9LTYiQL+YIyT6vpuRlq1zgsXxavZluVrfeJv6x0owV4KDx4Q==} 1183 1195 engines: {node: ^20.19.0 || >=22.12.0} 1184 1196 cpu: [s390x] 1185 1197 os: [linux] 1198 + libc: [glibc] 1186 1199 1187 1200 '@oxc-minify/binding-linux-x64-gnu@0.117.0': 1188 1201 resolution: {integrity: sha512-fXfhtr+WWBGNy4M5GjAF5vu/lpulR4Me34FjTyaK9nDrTZs7LM595UDsP1wliksqp4hD/KdoqHGmbCrC+6d4vA==} 1189 1202 engines: {node: ^20.19.0 || >=22.12.0} 1190 1203 cpu: [x64] 1191 1204 os: [linux] 1205 + libc: [glibc] 1192 1206 1193 1207 '@oxc-minify/binding-linux-x64-musl@0.117.0': 1194 1208 resolution: {integrity: sha512-jFBgGbx1oLadb83ntJmy1dWlAHSQanXTS21G4PgkxyONmxZdZ/UMKr7KsADzMuoPsd2YhJHxzRpwJd9U+4BFBw==} 1195 1209 engines: {node: ^20.19.0 || >=22.12.0} 1196 1210 cpu: [x64] 1197 1211 os: [linux] 1212 + libc: [musl] 1198 1213 1199 1214 '@oxc-minify/binding-openharmony-arm64@0.117.0': 1200 1215 resolution: {integrity: sha512-nxPd9vx1vYz8IlIMdl9HFdOK/ood1H5hzbSFsyO8JU55tkcJoBL8TLCbuFf9pHpOy27l2gcPyV6z3p4eAcTH5Q==} ··· 1314 1329 engines: {node: ^20.19.0 || >=22.12.0} 1315 1330 cpu: [arm64] 1316 1331 os: [linux] 1332 + libc: [glibc] 1317 1333 1318 1334 '@oxc-parser/binding-linux-arm64-gnu@0.117.0': 1319 1335 resolution: {integrity: sha512-jBxD7DtlHQ36ivjjZdH0noQJgWNouenzpLmXNKnYaCsBfo3jY95m5iyjYQEiWkvkhJ3TJUAs7tQ1/kEpY7x/Kg==} 1320 1336 engines: {node: ^20.19.0 || >=22.12.0} 1321 1337 cpu: [arm64] 1322 1338 os: [linux] 1339 + libc: [glibc] 1323 1340 1324 1341 '@oxc-parser/binding-linux-arm64-musl@0.112.0': 1325 1342 resolution: {integrity: sha512-3R0iqjM3xYOZCnwgcxOQXH7hrz64/USDIuLbNTM1kZqQzRqaR4w7SwoWKU934zABo8d0op2oSwOp+CV3hZnM7A==} 1326 1343 engines: {node: ^20.19.0 || >=22.12.0} 1327 1344 cpu: [arm64] 1328 1345 os: [linux] 1346 + libc: [musl] 1329 1347 1330 1348 '@oxc-parser/binding-linux-arm64-musl@0.117.0': 1331 1349 resolution: {integrity: sha512-QagKTDF4lrz8bCXbUi39Uq5xs7C7itAseKm51f33U+Dyar9eJY/zGKqfME9mKLOiahX7Fc1J3xMWVS0AdDXLPg==} 1332 1350 engines: {node: ^20.19.0 || >=22.12.0} 1333 1351 cpu: [arm64] 1334 1352 os: [linux] 1353 + libc: [musl] 1335 1354 1336 1355 '@oxc-parser/binding-linux-ppc64-gnu@0.112.0': 1337 1356 resolution: {integrity: sha512-lAQf8PQxfgy7h0bmcfSVE3hg3qMueshPYULFsCrHM+8KefGZ9W+ZMvRyU33gLrB4w1O3Fz1orR0hmKMCRxXNrQ==} 1338 1357 engines: {node: ^20.19.0 || >=22.12.0} 1339 1358 cpu: [ppc64] 1340 1359 os: [linux] 1360 + libc: [glibc] 1341 1361 1342 1362 '@oxc-parser/binding-linux-ppc64-gnu@0.117.0': 1343 1363 resolution: {integrity: sha512-RPddpcE/0xxWaommWy0c5i/JdrXcXAkxBS2GOrAUh5LKmyCh03hpJedOAWszG4ADsKQwoUQQ1/tZVGRhZIWtKA==} 1344 1364 engines: {node: ^20.19.0 || >=22.12.0} 1345 1365 cpu: [ppc64] 1346 1366 os: [linux] 1367 + libc: [glibc] 1347 1368 1348 1369 '@oxc-parser/binding-linux-riscv64-gnu@0.112.0': 1349 1370 resolution: {integrity: sha512-2QlvQBUhHuAE3ezD4X3CAEKMXdfgInggQ5Bj/7gb5NcYP3GyfLTj7c+mMu+BRwfC9B3AXBNyqHWbqEuuUvZyRQ==} 1350 1371 engines: {node: ^20.19.0 || >=22.12.0} 1351 1372 cpu: [riscv64] 1352 1373 os: [linux] 1374 + libc: [glibc] 1353 1375 1354 1376 '@oxc-parser/binding-linux-riscv64-gnu@0.117.0': 1355 1377 resolution: {integrity: sha512-ur/WVZF9FSOiZGxyP+nfxZzuv6r5OJDYoVxJnUR7fM/hhXLh4V/be6rjbzm9KLCDBRwYCEKJtt+XXNccwd06IA==} 1356 1378 engines: {node: ^20.19.0 || >=22.12.0} 1357 1379 cpu: [riscv64] 1358 1380 os: [linux] 1381 + libc: [glibc] 1359 1382 1360 1383 '@oxc-parser/binding-linux-riscv64-musl@0.112.0': 1361 1384 resolution: {integrity: sha512-v06iu0osHszgqJ1dLQRb6leWFU1sjG/UQk4MoVBtE6ZPewgfTkby6G9II1SpEAf2onnAuQceVYxQH9iuU3NJqw==} 1362 1385 engines: {node: ^20.19.0 || >=22.12.0} 1363 1386 cpu: [riscv64] 1364 1387 os: [linux] 1388 + libc: [musl] 1365 1389 1366 1390 '@oxc-parser/binding-linux-riscv64-musl@0.117.0': 1367 1391 resolution: {integrity: sha512-ujGcAx8xAMvhy7X5sBFi3GXML1EtyORuJZ5z2T6UV3U416WgDX/4OCi3GnoteeenvxIf6JgP45B+YTHpt71vpA==} 1368 1392 engines: {node: ^20.19.0 || >=22.12.0} 1369 1393 cpu: [riscv64] 1370 1394 os: [linux] 1395 + libc: [musl] 1371 1396 1372 1397 '@oxc-parser/binding-linux-s390x-gnu@0.112.0': 1373 1398 resolution: {integrity: sha512-+5HhNHtxsdcd7+ljXFnn9FOoCNXJX3UPgIfIE6vdwS1HqdGNH6eAcVobuqGOp54l8pvcxDQA6F4cPswCgLrQfQ==} 1374 1399 engines: {node: ^20.19.0 || >=22.12.0} 1375 1400 cpu: [s390x] 1376 1401 os: [linux] 1402 + libc: [glibc] 1377 1403 1378 1404 '@oxc-parser/binding-linux-s390x-gnu@0.117.0': 1379 1405 resolution: {integrity: sha512-hbsfKjUwRjcMZZvvmpZSc+qS0bHcHRu8aV/I3Ikn9BzOA0ZAgUE7ctPtce5zCU7bM8dnTLi4sJ1Pi9YHdx6Urw==} 1380 1406 engines: {node: ^20.19.0 || >=22.12.0} 1381 1407 cpu: [s390x] 1382 1408 os: [linux] 1409 + libc: [glibc] 1383 1410 1384 1411 '@oxc-parser/binding-linux-x64-gnu@0.112.0': 1385 1412 resolution: {integrity: sha512-jKwO7ZLNkjxwg7FoCLw+fJszooL9yXRZsDN0AQ1AQUTWq1l8GH/2e44k68N3fcP19jl8O8jGpqLAZcQTYk6skA==} 1386 1413 engines: {node: ^20.19.0 || >=22.12.0} 1387 1414 cpu: [x64] 1388 1415 os: [linux] 1416 + libc: [glibc] 1389 1417 1390 1418 '@oxc-parser/binding-linux-x64-gnu@0.117.0': 1391 1419 resolution: {integrity: sha512-1QrTrf8rige7UPJrYuDKJLQOuJlgkt+nRSJLBMHWNm9TdivzP48HaK3f4q18EjNlglKtn03lgjMu4fryDm8X4A==} 1392 1420 engines: {node: ^20.19.0 || >=22.12.0} 1393 1421 cpu: [x64] 1394 1422 os: [linux] 1423 + libc: [glibc] 1395 1424 1396 1425 '@oxc-parser/binding-linux-x64-musl@0.112.0': 1397 1426 resolution: {integrity: sha512-TYqnuKV/p3eOc+N61E0961nA7DC+gaCeJ3+V2LcjJdTwFMdikqWL6uVk1jlrpUCBrozHDATVUKDZYH7r4FQYjQ==} 1398 1427 engines: {node: ^20.19.0 || >=22.12.0} 1399 1428 cpu: [x64] 1400 1429 os: [linux] 1430 + libc: [musl] 1401 1431 1402 1432 '@oxc-parser/binding-linux-x64-musl@0.117.0': 1403 1433 resolution: {integrity: sha512-gRvK6HPzF5ITRL68fqb2WYYs/hGviPIbkV84HWCgiJX+LkaOpp+HIHQl3zVZdyKHwopXToTbXbtx/oFjDjl8pg==} 1404 1434 engines: {node: ^20.19.0 || >=22.12.0} 1405 1435 cpu: [x64] 1406 1436 os: [linux] 1437 + libc: [musl] 1407 1438 1408 1439 '@oxc-parser/binding-openharmony-arm64@0.112.0': 1409 1440 resolution: {integrity: sha512-ZhrVmWFifVEFQX4XPwLoVFDHw9tAWH9p9vHsHFH+5uCKdfVR+jje4WxVo6YrokWCboGckoOzHq5KKMOcPZfkRg==} ··· 1558 1589 engines: {node: ^20.19.0 || >=22.12.0} 1559 1590 cpu: [arm64] 1560 1591 os: [linux] 1592 + libc: [glibc] 1561 1593 1562 1594 '@oxc-transform/binding-linux-arm64-gnu@0.117.0': 1563 1595 resolution: {integrity: sha512-mXbDfvDN0RZVg7v4LohNzU0kK3fMAZgkUKTkpFVgxEvzibEG5VpSznkypUwHI4a8U8pz+K6mGaLetX3Xt+CvvA==} 1564 1596 engines: {node: ^20.19.0 || >=22.12.0} 1565 1597 cpu: [arm64] 1566 1598 os: [linux] 1599 + libc: [glibc] 1567 1600 1568 1601 '@oxc-transform/binding-linux-arm64-musl@0.112.0': 1569 1602 resolution: {integrity: sha512-Lg6VOuSd3oXv7J0eGywgqh/086h+qQzIBOD+47pYKMTTJcbDe+f3h/RgGoMKJE5HhiwT5sH1aGEJfIfaYUiVSw==} 1570 1603 engines: {node: ^20.19.0 || >=22.12.0} 1571 1604 cpu: [arm64] 1572 1605 os: [linux] 1606 + libc: [musl] 1573 1607 1574 1608 '@oxc-transform/binding-linux-arm64-musl@0.117.0': 1575 1609 resolution: {integrity: sha512-ykxpPQp0eAcSmhy0Y3qKvdanHY4d8THPonDfmCoktUXb6r0X6qnjpJB3V+taN1wevW55bOEZd97kxtjTKjqhmg==} 1576 1610 engines: {node: ^20.19.0 || >=22.12.0} 1577 1611 cpu: [arm64] 1578 1612 os: [linux] 1613 + libc: [musl] 1579 1614 1580 1615 '@oxc-transform/binding-linux-ppc64-gnu@0.112.0': 1581 1616 resolution: {integrity: sha512-PXzmj82o1moA4IGphYImTRgc2youTi4VRfyFX3CHwLjxPcQ5JtcsgbDt4QUdOzXZ+zC07s5jf2ZzhRapEOlj2w==} 1582 1617 engines: {node: ^20.19.0 || >=22.12.0} 1583 1618 cpu: [ppc64] 1584 1619 os: [linux] 1620 + libc: [glibc] 1585 1621 1586 1622 '@oxc-transform/binding-linux-ppc64-gnu@0.117.0': 1587 1623 resolution: {integrity: sha512-Rvspti4Kr7eq6zSrURK5WjscfWQPvmy/KjJZV45neRKW8RLonE3r9+NgrwSLGoHvQ3F24fbqlkplox1RtlhH5A==} 1588 1624 engines: {node: ^20.19.0 || >=22.12.0} 1589 1625 cpu: [ppc64] 1590 1626 os: [linux] 1627 + libc: [glibc] 1591 1628 1592 1629 '@oxc-transform/binding-linux-riscv64-gnu@0.112.0': 1593 1630 resolution: {integrity: sha512-vhJsMsVH/6xwa3bt1LGts33FXUkGjaEGDwsRyp4lIfOjSfQVWMtCmWMFNaA0dW9FVWdD2Gt2fSFBSZ+azDxlpg==} 1594 1631 engines: {node: ^20.19.0 || >=22.12.0} 1595 1632 cpu: [riscv64] 1596 1633 os: [linux] 1634 + libc: [glibc] 1597 1635 1598 1636 '@oxc-transform/binding-linux-riscv64-gnu@0.117.0': 1599 1637 resolution: {integrity: sha512-Dr2ZW9ZZ4l1eQ5JUEUY3smBh4JFPCPuybWaDZTLn3ADZjyd8ZtNXEjeMT8rQbbhbgSL9hEgbwaqraole3FNThQ==} 1600 1638 engines: {node: ^20.19.0 || >=22.12.0} 1601 1639 cpu: [riscv64] 1602 1640 os: [linux] 1641 + libc: [glibc] 1603 1642 1604 1643 '@oxc-transform/binding-linux-riscv64-musl@0.112.0': 1605 1644 resolution: {integrity: sha512-cXWFb7z+2IjFUEcXtRwluq9oEG5qnyFCjiu3SWrgYNcWwPdHusv3I/7K5/CTbbi4StoZ5txbi7/iSfDHNyWuRw==} 1606 1645 engines: {node: ^20.19.0 || >=22.12.0} 1607 1646 cpu: [riscv64] 1608 1647 os: [linux] 1648 + libc: [musl] 1609 1649 1610 1650 '@oxc-transform/binding-linux-riscv64-musl@0.117.0': 1611 1651 resolution: {integrity: sha512-oD1Bnes1bIC3LVBSrWEoSUBj6fvatESPwAVWfJVGVQlqWuOs/ZBn1e4Nmbipo3KGPHK7DJY75r/j7CQCxhrOFQ==} 1612 1652 engines: {node: ^20.19.0 || >=22.12.0} 1613 1653 cpu: [riscv64] 1614 1654 os: [linux] 1655 + libc: [musl] 1615 1656 1616 1657 '@oxc-transform/binding-linux-s390x-gnu@0.112.0': 1617 1658 resolution: {integrity: sha512-eEFu4SRqJTJ20/88KRWmp+jpHKAw0Y1DsnSgpEeXyBIIcsOaLIUMU/TfYWUmqRbvbMV9rmOmI3kp5xWYUq6kSQ==} 1618 1659 engines: {node: ^20.19.0 || >=22.12.0} 1619 1660 cpu: [s390x] 1620 1661 os: [linux] 1662 + libc: [glibc] 1621 1663 1622 1664 '@oxc-transform/binding-linux-s390x-gnu@0.117.0': 1623 1665 resolution: {integrity: sha512-qT//IAPLvse844t99Kff5j055qEbXfwzWgvCMb0FyjisnB8foy25iHZxZIocNBe6qwrCYWUP1M8rNrB/WyfS1Q==} 1624 1666 engines: {node: ^20.19.0 || >=22.12.0} 1625 1667 cpu: [s390x] 1626 1668 os: [linux] 1669 + libc: [glibc] 1627 1670 1628 1671 '@oxc-transform/binding-linux-x64-gnu@0.112.0': 1629 1672 resolution: {integrity: sha512-ST1MDT+TlOyZ1c5btrGinRSUW2Jf4Pa+0gdKwsyjDSOC3dxy2ZNkN3mosTf4ywc3J+mxfYKqtjs7zSwHz03ILA==} 1630 1673 engines: {node: ^20.19.0 || >=22.12.0} 1631 1674 cpu: [x64] 1632 1675 os: [linux] 1676 + libc: [glibc] 1633 1677 1634 1678 '@oxc-transform/binding-linux-x64-gnu@0.117.0': 1635 1679 resolution: {integrity: sha512-2YEO5X+KgNzFqRVO5dAkhjcI5gwxus4NSWVl/+cs2sI6P0MNPjqE3VWPawl4RTC11LvetiiZdHcujUCPM8aaUw==} 1636 1680 engines: {node: ^20.19.0 || >=22.12.0} 1637 1681 cpu: [x64] 1638 1682 os: [linux] 1683 + libc: [glibc] 1639 1684 1640 1685 '@oxc-transform/binding-linux-x64-musl@0.112.0': 1641 1686 resolution: {integrity: sha512-ISQoA3pD4cyTGpf9sXXeerH6pL2L6EIpdy6oAy2ttkswyVFDyQNVOVIGIdLZDgbpmqGljxZnWqt/J/N68pQaig==} 1642 1687 engines: {node: ^20.19.0 || >=22.12.0} 1643 1688 cpu: [x64] 1644 1689 os: [linux] 1690 + libc: [musl] 1645 1691 1646 1692 '@oxc-transform/binding-linux-x64-musl@0.117.0': 1647 1693 resolution: {integrity: sha512-3wqWbTSaIFZvDr1aqmTul4cg8PRWYh6VC52E8bLI7ytgS/BwJLW+sDUU2YaGIds4sAf/1yKeJRmudRCDPW9INg==} 1648 1694 engines: {node: ^20.19.0 || >=22.12.0} 1649 1695 cpu: [x64] 1650 1696 os: [linux] 1697 + libc: [musl] 1651 1698 1652 1699 '@oxc-transform/binding-openharmony-arm64@0.112.0': 1653 1700 resolution: {integrity: sha512-UOGVrGIv7yLJovyEXEyUTADuLq98vd/cbMHFLJweRXD+11I8Tn4jASi4WzdsN8C3BVYGRHrXH2NlSBmhz33a4g==} ··· 1736 1783 engines: {node: '>= 10.0.0'} 1737 1784 cpu: [arm] 1738 1785 os: [linux] 1786 + libc: [glibc] 1739 1787 1740 1788 '@parcel/watcher-linux-arm-musl@2.5.6': 1741 1789 resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==} 1742 1790 engines: {node: '>= 10.0.0'} 1743 1791 cpu: [arm] 1744 1792 os: [linux] 1793 + libc: [musl] 1745 1794 1746 1795 '@parcel/watcher-linux-arm64-glibc@2.5.6': 1747 1796 resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==} 1748 1797 engines: {node: '>= 10.0.0'} 1749 1798 cpu: [arm64] 1750 1799 os: [linux] 1800 + libc: [glibc] 1751 1801 1752 1802 '@parcel/watcher-linux-arm64-musl@2.5.6': 1753 1803 resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==} 1754 1804 engines: {node: '>= 10.0.0'} 1755 1805 cpu: [arm64] 1756 1806 os: [linux] 1807 + libc: [musl] 1757 1808 1758 1809 '@parcel/watcher-linux-x64-glibc@2.5.6': 1759 1810 resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==} 1760 1811 engines: {node: '>= 10.0.0'} 1761 1812 cpu: [x64] 1762 1813 os: [linux] 1814 + libc: [glibc] 1763 1815 1764 1816 '@parcel/watcher-linux-x64-musl@2.5.6': 1765 1817 resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==} 1766 1818 engines: {node: '>= 10.0.0'} 1767 1819 cpu: [x64] 1768 1820 os: [linux] 1821 + libc: [musl] 1769 1822 1770 1823 '@parcel/watcher-wasm@2.5.6': 1771 1824 resolution: {integrity: sha512-byAiBZ1t3tXQvc8dMD/eoyE7lTXYorhn+6uVW5AC+JGI1KtJC/LvDche5cfUE+qiefH+Ybq0bUCJU0aB1cSHUA==} ··· 1942 1995 resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==} 1943 1996 cpu: [arm] 1944 1997 os: [linux] 1998 + libc: [glibc] 1945 1999 1946 2000 '@rollup/rollup-linux-arm-musleabihf@4.59.0': 1947 2001 resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==} 1948 2002 cpu: [arm] 1949 2003 os: [linux] 2004 + libc: [musl] 1950 2005 1951 2006 '@rollup/rollup-linux-arm64-gnu@4.59.0': 1952 2007 resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==} 1953 2008 cpu: [arm64] 1954 2009 os: [linux] 2010 + libc: [glibc] 1955 2011 1956 2012 '@rollup/rollup-linux-arm64-musl@4.59.0': 1957 2013 resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==} 1958 2014 cpu: [arm64] 1959 2015 os: [linux] 2016 + libc: [musl] 1960 2017 1961 2018 '@rollup/rollup-linux-loong64-gnu@4.59.0': 1962 2019 resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==} 1963 2020 cpu: [loong64] 1964 2021 os: [linux] 2022 + libc: [glibc] 1965 2023 1966 2024 '@rollup/rollup-linux-loong64-musl@4.59.0': 1967 2025 resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==} 1968 2026 cpu: [loong64] 1969 2027 os: [linux] 2028 + libc: [musl] 1970 2029 1971 2030 '@rollup/rollup-linux-ppc64-gnu@4.59.0': 1972 2031 resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==} 1973 2032 cpu: [ppc64] 1974 2033 os: [linux] 2034 + libc: [glibc] 1975 2035 1976 2036 '@rollup/rollup-linux-ppc64-musl@4.59.0': 1977 2037 resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==} 1978 2038 cpu: [ppc64] 1979 2039 os: [linux] 2040 + libc: [musl] 1980 2041 1981 2042 '@rollup/rollup-linux-riscv64-gnu@4.59.0': 1982 2043 resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==} 1983 2044 cpu: [riscv64] 1984 2045 os: [linux] 2046 + libc: [glibc] 1985 2047 1986 2048 '@rollup/rollup-linux-riscv64-musl@4.59.0': 1987 2049 resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==} 1988 2050 cpu: [riscv64] 1989 2051 os: [linux] 2052 + libc: [musl] 1990 2053 1991 2054 '@rollup/rollup-linux-s390x-gnu@4.59.0': 1992 2055 resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==} 1993 2056 cpu: [s390x] 1994 2057 os: [linux] 2058 + libc: [glibc] 1995 2059 1996 2060 '@rollup/rollup-linux-x64-gnu@4.59.0': 1997 2061 resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==} 1998 2062 cpu: [x64] 1999 2063 os: [linux] 2064 + libc: [glibc] 2000 2065 2001 2066 '@rollup/rollup-linux-x64-musl@4.59.0': 2002 2067 resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==} 2003 2068 cpu: [x64] 2004 2069 os: [linux] 2070 + libc: [musl] 2005 2071 2006 2072 '@rollup/rollup-openbsd-x64@4.59.0': 2007 2073 resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==} ··· 2088 2154 engines: {node: '>= 20'} 2089 2155 cpu: [arm64] 2090 2156 os: [linux] 2157 + libc: [glibc] 2091 2158 2092 2159 '@tailwindcss/oxide-linux-arm64-musl@4.2.1': 2093 2160 resolution: {integrity: sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==} 2094 2161 engines: {node: '>= 20'} 2095 2162 cpu: [arm64] 2096 2163 os: [linux] 2164 + libc: [musl] 2097 2165 2098 2166 '@tailwindcss/oxide-linux-x64-gnu@4.2.1': 2099 2167 resolution: {integrity: sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==} 2100 2168 engines: {node: '>= 20'} 2101 2169 cpu: [x64] 2102 2170 os: [linux] 2171 + libc: [glibc] 2103 2172 2104 2173 '@tailwindcss/oxide-linux-x64-musl@4.2.1': 2105 2174 resolution: {integrity: sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==} 2106 2175 engines: {node: '>= 20'} 2107 2176 cpu: [x64] 2108 2177 os: [linux] 2178 + libc: [musl] 2109 2179 2110 2180 '@tailwindcss/oxide-wasm32-wasi@4.2.1': 2111 2181 resolution: {integrity: sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==} ··· 2493 2563 resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} 2494 2564 engines: {node: '>=10'} 2495 2565 2566 + asn1.js@5.4.1: 2567 + resolution: {integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==} 2568 + 2496 2569 assertion-error@2.0.1: 2497 2570 resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} 2498 2571 engines: {node: '>=12'} ··· 2658 2731 birpc@4.0.0: 2659 2732 resolution: {integrity: sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==} 2660 2733 2734 + bn.js@4.12.3: 2735 + resolution: {integrity: sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==} 2736 + 2661 2737 boolbase@1.0.0: 2662 2738 resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} 2663 2739 ··· 2685 2761 resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} 2686 2762 engines: {node: '>=8.0.0'} 2687 2763 2764 + buffer-equal-constant-time@1.0.1: 2765 + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} 2766 + 2688 2767 buffer-from@1.1.2: 2689 2768 resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} 2690 2769 ··· 2984 3063 2985 3064 eastasianwidth@0.2.0: 2986 3065 resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} 3066 + 3067 + ecdsa-sig-formatter@1.0.11: 3068 + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} 2987 3069 2988 3070 editorconfig@1.0.7: 2989 3071 resolution: {integrity: sha512-e0GOtq/aTQhVdNyDU9e02+wz9oDDM+SIOQxWME2QRjzRX5yyLAuHDE+0aE8vHb9XRC8XD37eO2u57+F09JqFhw==} ··· 3320 3402 http-shutdown@1.2.2: 3321 3403 resolution: {integrity: sha512-S9wWkJ/VSY9/k4qcjG318bqJNruzE4HySUhFYknwmu6LBP97KLLfwNf+n4V1BHurvFNkSKLFnK/RsuUnRTf9Vw==} 3322 3404 engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} 3405 + 3406 + http_ece@1.2.0: 3407 + resolution: {integrity: sha512-JrF8SSLVmcvc5NducxgyOrKXe3EsyHMgBFgSaIUGmArKe+rwr0uphRkRXvwiom3I+fpIfoItveHrfudL8/rxuA==} 3408 + engines: {node: '>=16'} 3323 3409 3324 3410 https-proxy-agent@7.0.6: 3325 3411 resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} ··· 3505 3591 resolution: {integrity: sha512-1e4qoRgnn448pRuMvKGsFFymUCquZV0mpGgOyIKNgD3JVDTsVJyRBGH/Fm0tBb8WsWGgmB1mDe6/yJMQM37DUA==} 3506 3592 engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 3507 3593 3594 + jwa@2.0.1: 3595 + resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} 3596 + 3597 + jws@4.0.1: 3598 + resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} 3599 + 3508 3600 keyv@4.5.4: 3509 3601 resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} 3510 3602 ··· 3569 3661 engines: {node: '>= 12.0.0'} 3570 3662 cpu: [arm64] 3571 3663 os: [linux] 3664 + libc: [glibc] 3572 3665 3573 3666 lightningcss-linux-arm64-musl@1.31.1: 3574 3667 resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==} 3575 3668 engines: {node: '>= 12.0.0'} 3576 3669 cpu: [arm64] 3577 3670 os: [linux] 3671 + libc: [musl] 3578 3672 3579 3673 lightningcss-linux-x64-gnu@1.31.1: 3580 3674 resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==} 3581 3675 engines: {node: '>= 12.0.0'} 3582 3676 cpu: [x64] 3583 3677 os: [linux] 3678 + libc: [glibc] 3584 3679 3585 3680 lightningcss-linux-x64-musl@1.31.1: 3586 3681 resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==} 3587 3682 engines: {node: '>= 12.0.0'} 3588 3683 cpu: [x64] 3589 3684 os: [linux] 3685 + libc: [musl] 3590 3686 3591 3687 lightningcss-win32-arm64-msvc@1.31.1: 3592 3688 resolution: {integrity: sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==} ··· 3700 3796 resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} 3701 3797 engines: {node: '>=12'} 3702 3798 3799 + minimalistic-assert@1.0.1: 3800 + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} 3801 + 3703 3802 minimatch@10.2.4: 3704 3803 resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} 3705 3804 engines: {node: 18 || 20 || >=22} ··· 3711 3810 minimatch@9.0.9: 3712 3811 resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} 3713 3812 engines: {node: '>=16 || 14 >=14.17'} 3813 + 3814 + minimist@1.2.8: 3815 + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} 3714 3816 3715 3817 minipass@7.1.3: 3716 3818 resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} ··· 4332 4434 safe-buffer@5.2.1: 4333 4435 resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} 4334 4436 4437 + safer-buffer@2.1.2: 4438 + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} 4439 + 4335 4440 sax@1.5.0: 4336 4441 resolution: {integrity: sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==} 4337 4442 engines: {node: '>=11.0.0'} ··· 4974 5079 peerDependenciesMeta: 4975 5080 typescript: 4976 5081 optional: true 5082 + 5083 + web-push@3.6.7: 5084 + resolution: {integrity: sha512-OpiIUe8cuGjrj3mMBFWY+e4MMIkW3SVT+7vEIjvD9kejGUypv8GPDf84JdPWskK8zMRIJ6xYGm+Kxr8YkPyA0A==} 5085 + engines: {node: '>= 16'} 5086 + hasBin: true 4977 5087 4978 5088 webidl-conversions@3.0.1: 4979 5089 resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} ··· 7416 7526 dependencies: 7417 7527 tslib: 2.8.1 7418 7528 7529 + asn1.js@5.4.1: 7530 + dependencies: 7531 + bn.js: 4.12.3 7532 + inherits: 2.0.4 7533 + minimalistic-assert: 1.0.1 7534 + safer-buffer: 2.1.2 7535 + 7419 7536 assertion-error@2.0.1: {} 7420 7537 7421 7538 ast-kit@2.2.0: ··· 7528 7645 7529 7646 birpc@4.0.0: {} 7530 7647 7648 + bn.js@4.12.3: {} 7649 + 7531 7650 boolbase@1.0.0: {} 7532 7651 7533 7652 brace-expansion@2.0.2: ··· 7554 7673 optional: true 7555 7674 7556 7675 buffer-crc32@1.0.0: {} 7676 + 7677 + buffer-equal-constant-time@1.0.1: {} 7557 7678 7558 7679 buffer-from@1.1.2: {} 7559 7680 ··· 7833 7954 7834 7955 eastasianwidth@0.2.0: {} 7835 7956 7957 + ecdsa-sig-formatter@1.0.11: 7958 + dependencies: 7959 + safe-buffer: 5.2.1 7960 + 7836 7961 editorconfig@1.0.7: 7837 7962 dependencies: 7838 7963 '@one-ini/wasm': 0.1.1 ··· 8238 8363 8239 8364 http-shutdown@1.2.2: {} 8240 8365 8366 + http_ece@1.2.0: {} 8367 + 8241 8368 https-proxy-agent@7.0.6: 8242 8369 dependencies: 8243 8370 agent-base: 7.1.4 ··· 8393 8520 espree: 9.6.1 8394 8521 semver: 7.7.4 8395 8522 8523 + jwa@2.0.1: 8524 + dependencies: 8525 + buffer-equal-constant-time: 1.0.1 8526 + ecdsa-sig-formatter: 1.0.11 8527 + safe-buffer: 5.2.1 8528 + 8529 + jws@4.0.1: 8530 + dependencies: 8531 + jwa: 2.0.1 8532 + safe-buffer: 5.2.1 8533 + 8396 8534 keyv@4.5.4: 8397 8535 dependencies: 8398 8536 json-buffer: 3.0.1 ··· 8571 8709 8572 8710 mimic-fn@4.0.0: {} 8573 8711 8712 + minimalistic-assert@1.0.1: {} 8713 + 8574 8714 minimatch@10.2.4: 8575 8715 dependencies: 8576 8716 brace-expansion: 5.0.4 ··· 8582 8722 minimatch@9.0.9: 8583 8723 dependencies: 8584 8724 brace-expansion: 2.0.2 8725 + 8726 + minimist@1.2.8: {} 8585 8727 8586 8728 minipass@7.1.3: {} 8587 8729 ··· 9469 9611 9470 9612 safe-buffer@5.2.1: {} 9471 9613 9614 + safer-buffer@2.1.2: {} 9615 + 9472 9616 sax@1.5.0: {} 9473 9617 9474 9618 scule@1.3.0: {} ··· 10094 10238 '@vue/shared': 3.5.31 10095 10239 optionalDependencies: 10096 10240 typescript: 6.0.2 10241 + 10242 + web-push@3.6.7: 10243 + dependencies: 10244 + asn1.js: 5.4.1 10245 + http_ece: 1.2.0 10246 + https-proxy-agent: 7.0.6 10247 + jws: 4.0.1 10248 + minimist: 1.2.8 10249 + transitivePeerDependencies: 10250 + - supports-color 10097 10251 10098 10252 webidl-conversions@3.0.1: {} 10099 10253
+9
public/sw.js
··· 1 + self.addEventListener("push", function (event) { 2 + const data = event.data.json(); 3 + 4 + event.waitUntil( 5 + self.registration.showNotification(data.title, { 6 + body: data.body, 7 + }), 8 + ); 9 + });
+7
server/api/subscription/.get.ts
··· 1 + import type { PushSubscriptionJSON } from "~~/shared/types"; 2 + 3 + export default defineAuthenticatedEventHandler( 4 + async (_event, userId): Promise<PushSubscriptionJSON[]> => { 5 + return await Subscriptions.getAll(userId); 6 + }, 7 + );
+17
server/api/subscription/.post.ts
··· 1 + import { SubscriptionEventStream } from "~~/server/utils/sse"; 2 + import { PushSubscriptionJSON } from "~~/shared/types"; 3 + 4 + export default defineAuthenticatedEventHandler( 5 + async (event, userId): Promise<PushSubscriptionJSON> => { 6 + const body = await readValidatedBody(event, PushSubscriptionJSON.parse); 7 + 8 + const subscription = await Subscriptions.updateOrAdd( 9 + userId, 10 + body, 11 + ); 12 + if (subscription instanceof Error) throw subscription; 13 + 14 + SubscriptionEventStream.sendUpdate(userId); 15 + return subscription; 16 + }, 17 + );
+5
server/api/subscription/sendNotification.post.ts
··· 1 + export default defineAuthenticatedEventHandler( 2 + async (event, userId) => { 3 + await Subscriptions.sendNotification(userId); 4 + }, 5 + );
+14
server/plugins/storage.ts
··· 51 51 fsDriver({ 52 52 base: ".data/categories", 53 53 }), 54 + ); 55 + storage.mount( 56 + "subscriptions", 57 + fsDriver({ 58 + base: ".data/subscriptions", 59 + }), 54 60 ); 55 61 } 56 62 ··· 79 85 url: useRuntimeConfig().upstash.url, 80 86 token: useRuntimeConfig().upstash.token, 81 87 base: "categories", 88 + }), 89 + ); 90 + storage.mount( 91 + "subscriptions", 92 + upstashDriver({ 93 + url: useRuntimeConfig().upstash.url, 94 + token: useRuntimeConfig().upstash.token, 95 + base: "subscriptions", 82 96 }), 83 97 ); 84 98 }
+1
server/types/web-push.d.ts
··· 1 + declare module "web-push";
+55
server/utils/db/subscription.ts
··· 1 + import type { NuxtError } from "nuxt/app"; 2 + import type { PushSubscriptionJSON } from "~~/shared/types"; 3 + import webpush from "web-push"; 4 + 5 + function getKey(userId: string): string { 6 + return `subscriptions:${userId}`; 7 + } 8 + 9 + webpush.setVapidDetails( 10 + "mailto:you@example.com", 11 + "BKkvpMKOQ3wvNUpoohpuZmTUCNe8rH4bZwCbTeLW16F1ZeUm9DDEavdpXOfXIR6PWZpPswiCYte1KMveWMFvslY", 12 + "wGiryLM_sL1fRZfWhcYeJ_ZgSucqtOn1S_A60lBThnc", 13 + ); 14 + 15 + export const Subscriptions = { 16 + async getAll(userId: string): Promise<PushSubscriptionJSON[]> { 17 + const storage = useStorage(); 18 + return (await storage.get<PushSubscriptionJSON[]>(getKey(userId))) ?? []; 19 + }, 20 + async updateOrAdd( 21 + userId: string, 22 + subscription: PushSubscriptionJSON, 23 + ): Promise<PushSubscriptionJSON | NuxtError> { 24 + const storage = useStorage(); 25 + const subscriptions = await Subscriptions.getAll(userId); 26 + 27 + const exists = subscriptions.find(s => s.endpoint === subscription.endpoint); 28 + 29 + if (!exists) { 30 + subscriptions.push(subscription); 31 + await storage.set(getKey(userId), subscriptions); 32 + return subscription; 33 + } 34 + 35 + return createError({ 36 + status: 409, 37 + statusMessage: "Conflict", 38 + message: `Subscription already exists`, 39 + }); 40 + }, 41 + async sendNotification(userId: string) { 42 + const subscriptions = await Subscriptions.getAll(userId); 43 + 44 + const payload = JSON.stringify({ title: "Erinnerung", body: "Zeit für XYZ" }); 45 + 46 + for (const sub of subscriptions) { 47 + try { 48 + await webpush.sendNotification(sub, payload); 49 + } catch (err) { 50 + console.error("Push failed", err); 51 + } 52 + } 53 + 54 + } 55 + }
+10
server/utils/sse.ts
··· 31 31 }, 32 32 }; 33 33 34 + export const SubscriptionEventStream = { 35 + addStream(userId: string, eventStream: EventStream) { 36 + addEventStream(userId, subscriptionsEventStreams, eventStream); 37 + }, 38 + async sendUpdate(userId: string) { 39 + await publish(userId, subscriptionsEventStreams, await Subscriptions.getAll(userId)); 40 + }, 41 + }; 42 + 34 43 const todosEventStreams: Map<string, EventStream[]> = new Map(); 35 44 const tagsEventStreams: Map<string, EventStream[]> = new Map(); 36 45 const categoriesEventStreams: Map<string, EventStream[]> = new Map(); 46 + const subscriptionsEventStreams: Map<string, EventStream[]> = new Map(); 37 47 38 48 function addEventStream( 39 49 key: string,
+10
shared/types.ts
··· 43 43 ]); 44 44 export type Time = z.infer<typeof Time>; 45 45 46 + export const PushSubscriptionJSON = z.object({ 47 + endpoint: z.string(), 48 + expirationTime: z.number().nullable().optional(), 49 + keys: z.object({ 50 + auth: z.string(), 51 + p256dh: z.string(), 52 + }) 53 + }); 54 + export type PushSubscriptionJSON = z.infer<typeof PushSubscriptionJSON>; 55 + 46 56 export const Todo = z.object({ 47 57 uuid: z.uuid(), 48 58 title: z.string().min(1),