From 7cb64d2e3944c95c3f2a31a297e917f352674d47 Mon Sep 17 00:00:00 2001 From: DivDE Date: Sun, 28 Jan 2024 00:18:03 +0100 Subject: [PATCH] Initial import --- .github/workflows/ci.yml | 20 + .github/workflows/ghpages.yml | 33 + .gitignore | 24 + .vscode/extensions.json | 3 + README.md | 5 + index.html | 12 + package-lock.json | 1883 +++++++++++++++++++++++++++++++++ package.json | 29 + src/App.svelte | 87 ++ src/Graph.svelte | 68 ++ src/data.ts | 62 ++ src/main.ts | 8 + src/readUSBData.ts | 845 +++++++++++++++ src/storeUtils.ts | 41 + src/vite-env.d.ts | 2 + svelte.config.js | 7 + tsconfig.json | 20 + tsconfig.node.json | 9 + vite.config.ts | 7 + 19 files changed, 3165 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/ghpages.yml create mode 100644 .gitignore create mode 100644 .vscode/extensions.json create mode 100644 README.md create mode 100644 index.html create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 src/App.svelte create mode 100644 src/Graph.svelte create mode 100644 src/data.ts create mode 100644 src/main.ts create mode 100644 src/readUSBData.ts create mode 100644 src/storeUtils.ts create mode 100644 src/vite-env.d.ts create mode 100644 svelte.config.js create mode 100644 tsconfig.json create mode 100644 tsconfig.node.json create mode 100644 vite.config.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..41a2c44 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,20 @@ +# cf https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions +name: ci +on: + push: + branches: [master] + tags: ["*"] + pull_request: + branches: [master] +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set Node.js version + uses: actions/setup-node@v4 + with: + node-version: 20.x + cache: npm + - run: npm ci + - run: npm run ci diff --git a/.github/workflows/ghpages.yml b/.github/workflows/ghpages.yml new file mode 100644 index 0000000..6100dbe --- /dev/null +++ b/.github/workflows/ghpages.yml @@ -0,0 +1,33 @@ +name: ghpages +on: + push: + branches: [master] +jobs: + release: + runs-on: ubuntu-latest + permissions: + contents: write + pages: write + id-token: write + concurrency: + group: "release" + cancel-in-progress: false + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - uses: actions/checkout@v4 + - name: Set Node.js version + uses: actions/setup-node@v4 + with: + node-version: 20.x + cache: npm + - run: npm ci + - run: npm run ci + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: "dist" + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..bdef820 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["svelte.svelte-vscode"] +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..94fce88 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# accucheck + +Ce programme permet d'extraire les données de glycémie mesurées par un appareil [Accu-Chek](https://www.accu-chek.fr/lecteurs-de-glycemie/guide) et de les afficher sous forme graphique et sous forme de liste de mesures, avec la possibilité de les enregistrer au format JSON ou CSV. + +Le code du fichier [readUSBData](src/readUSBData.ts) provient en grande partie de [Tidepool uploader](https://github.com/tidepool-org/uploader) sous license BSD-2-Clause. Merci à eux! diff --git a/index.html b/index.html new file mode 100644 index 0000000..80185d8 --- /dev/null +++ b/index.html @@ -0,0 +1,12 @@ + + + + + + Accu-Chek device display + + +
+ + + diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..3943d1f --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1883 @@ +{ + "name": "accuchek", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "accuchek", + "license": "BSD-2-Clause", + "devDependencies": { + "@amadeus-it-group/tansu": "^1.0.0", + "@sveltejs/vite-plugin-svelte": "^3.0.1", + "@tsconfig/svelte": "^5.0.2", + "@types/w3c-web-usb": "^1.0.10", + "bootstrap": "^5.3.2", + "chart.js": "^4.4.1", + "chartjs-adapter-date-fns": "^3.0.0", + "chartjs-plugin-zoom": "^2.0.1", + "date-fns": "^3.3.1", + "svelte": "^4.2.8", + "svelte-check": "^3.6.2", + "tslib": "^2.6.2", + "typescript": "^5.2.2", + "vite": "^5.0.8" + } + }, + "node_modules/@amadeus-it-group/tansu": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@amadeus-it-group/tansu/-/tansu-1.0.0.tgz", + "integrity": "sha512-JXR89NVtWT8rn7prB9j7/x/n/IxiWJEXhRWztyocrzb+M9hEhvIESeIE3mpSbrWRmDTyWvdpDCnOvKJ5/W8APQ==", + "dev": true + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", + "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", + "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", + "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", + "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", + "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", + "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", + "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", + "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", + "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", + "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", + "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", + "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", + "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", + "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", + "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", + "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", + "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", + "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", + "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", + "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", + "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", + "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", + "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", + "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@kurkle/color": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", + "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==", + "dev": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "dev": true, + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.9.6", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.6.tgz", + "integrity": "sha512-MVNXSSYN6QXOulbHpLMKYi60ppyO13W9my1qogeiAqtjb2yR4LSmfU2+POvDkLzhjYLXz9Rf9+9a3zFHW1Lecg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.9.6", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.6.tgz", + "integrity": "sha512-T14aNLpqJ5wzKNf5jEDpv5zgyIqcpn1MlwCrUXLrwoADr2RkWA0vOWP4XxbO9aiO3dvMCQICZdKeDrFl7UMClw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.9.6", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.6.tgz", + "integrity": "sha512-CqNNAyhRkTbo8VVZ5R85X73H3R5NX9ONnKbXuHisGWC0qRbTTxnF1U4V9NafzJbgGM0sHZpdO83pLPzq8uOZFw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.9.6", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.6.tgz", + "integrity": "sha512-zRDtdJuRvA1dc9Mp6BWYqAsU5oeLixdfUvkTHuiYOHwqYuQ4YgSmi6+/lPvSsqc/I0Omw3DdICx4Tfacdzmhog==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.9.6", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.6.tgz", + "integrity": "sha512-oNk8YXDDnNyG4qlNb6is1ojTOGL/tRhbbKeE/YuccItzerEZT68Z9gHrY3ROh7axDc974+zYAPxK5SH0j/G+QQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.9.6", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.6.tgz", + "integrity": "sha512-Z3O60yxPtuCYobrtzjo0wlmvDdx2qZfeAWTyfOjEDqd08kthDKexLpV97KfAeUXPosENKd8uyJMRDfFMxcYkDQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.9.6", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.6.tgz", + "integrity": "sha512-gpiG0qQJNdYEVad+1iAsGAbgAnZ8j07FapmnIAQgODKcOTjLEWM9sRb+MbQyVsYCnA0Im6M6QIq6ax7liws6eQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.9.6", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.6.tgz", + "integrity": "sha512-+uCOcvVmFUYvVDr27aiyun9WgZk0tXe7ThuzoUTAukZJOwS5MrGbmSlNOhx1j80GdpqbOty05XqSl5w4dQvcOA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.9.6", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.6.tgz", + "integrity": "sha512-HUNqM32dGzfBKuaDUBqFB7tP6VMN74eLZ33Q9Y1TBqRDn+qDonkAUyKWwF9BR9unV7QUzffLnz9GrnKvMqC/fw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.9.6", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.6.tgz", + "integrity": "sha512-ch7M+9Tr5R4FK40FHQk8VnML0Szi2KRujUgHXd/HjuH9ifH72GUmw6lStZBo3c3GB82vHa0ZoUfjfcM7JiiMrQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.9.6", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.6.tgz", + "integrity": "sha512-VD6qnR99dhmTQ1mJhIzXsRcTBvTjbfbGGwKAHcu+52cVl15AC/kplkhxzW/uT0Xl62Y/meBKDZvoJSJN+vTeGA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.9.6", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.6.tgz", + "integrity": "sha512-J9AFDq/xiRI58eR2NIDfyVmTYGyIZmRcvcAoJ48oDld/NTR8wyiPUu2X/v1navJ+N/FGg68LEbX3Ejd6l8B7MQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.9.6", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.6.tgz", + "integrity": "sha512-jqzNLhNDvIZOrt69Ce4UjGRpXJBzhUBzawMwnaDAwyHriki3XollsewxWzOzz+4yOFDkuJHtTsZFwMxhYJWmLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sveltejs/vite-plugin-svelte": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.0.1.tgz", + "integrity": "sha512-CGURX6Ps+TkOovK6xV+Y2rn8JKa8ZPUHPZ/NKgCxAmgBrXReavzFl8aOSCj3kQ1xqT7yGJj53hjcV/gqwDAaWA==", + "dev": true, + "dependencies": { + "@sveltejs/vite-plugin-svelte-inspector": "^2.0.0-next.0 || ^2.0.0", + "debug": "^4.3.4", + "deepmerge": "^4.3.1", + "kleur": "^4.1.5", + "magic-string": "^0.30.5", + "svelte-hmr": "^0.15.3", + "vitefu": "^0.2.5" + }, + "engines": { + "node": "^18.0.0 || >=20" + }, + "peerDependencies": { + "svelte": "^4.0.0 || ^5.0.0-next.0", + "vite": "^5.0.0" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte-inspector": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-2.0.0.tgz", + "integrity": "sha512-gjr9ZFg1BSlIpfZ4PRewigrvYmHWbDrq2uvvPB1AmTWKuM+dI1JXQSUu2pIrYLb/QncyiIGkFDFKTwJ0XqQZZg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.0.0 || >=20" + }, + "peerDependencies": { + "@sveltejs/vite-plugin-svelte": "^3.0.0", + "svelte": "^4.0.0 || ^5.0.0-next.0", + "vite": "^5.0.0" + } + }, + "node_modules/@tsconfig/svelte": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@tsconfig/svelte/-/svelte-5.0.2.tgz", + "integrity": "sha512-BRbo1fOtyVbhfLyuCWw6wAWp+U8UQle+ZXu84MYYWzYSEB28dyfnRBIE99eoG+qdAC0po6L2ScIEivcT07UaMA==", + "dev": true + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/pug": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.10.tgz", + "integrity": "sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==", + "dev": true + }, + "node_modules/@types/w3c-web-usb": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@types/w3c-web-usb/-/w3c-web-usb-1.0.10.tgz", + "integrity": "sha512-CHgUI5kTc/QLMP8hODUHhge0D4vx+9UiAwIGiT0sTy/B2XpdX1U5rJt6JSISgr6ikRT7vxV9EVAFeYZqUnl1gQ==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/axobject-query": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz", + "integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==", + "dev": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bootstrap": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.2.tgz", + "integrity": "sha512-D32nmNWiQHo94BKHLmOrdjlL05q1c8oxbtBphQFb9Z5to6eGRDCm0QgeaZ4zFBHzfg2++rqa2JkqCcxDy0sH0g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "peerDependencies": { + "@popperjs/core": "^2.11.8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chart.js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.1.tgz", + "integrity": "sha512-C74QN1bxwV1v2PEujhmKjOZ7iUM4w6BWs23Md/6aOZZSlwMzeCIDGuZay++rBgChYru7/+QFeoQW0fQoP534Dg==", + "dev": true, + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=7" + } + }, + "node_modules/chartjs-adapter-date-fns": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chartjs-adapter-date-fns/-/chartjs-adapter-date-fns-3.0.0.tgz", + "integrity": "sha512-Rs3iEB3Q5pJ973J93OBTpnP7qoGwvq3nUnoMdtxO+9aoJof7UFcRbWcIDteXuYd1fgAvct/32T9qaLyLuZVwCg==", + "dev": true, + "peerDependencies": { + "chart.js": ">=2.8.0", + "date-fns": ">=2.0.0" + } + }, + "node_modules/chartjs-plugin-zoom": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/chartjs-plugin-zoom/-/chartjs-plugin-zoom-2.0.1.tgz", + "integrity": "sha512-ogOmLu6e+Q7E1XWOCOz9YwybMslz9qNfGV2a+qjfmqJYpsw5ZMoRHZBUyW+NGhkpQ5PwwPA/+rikHpBZb7PZuA==", + "dev": true, + "dependencies": { + "hammerjs": "^2.0.8" + }, + "peerDependencies": { + "chart.js": ">=3.2.0" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/code-red": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz", + "integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15", + "@types/estree": "^1.0.1", + "acorn": "^8.10.0", + "estree-walker": "^3.0.3", + "periscopic": "^3.1.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/date-fns": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.3.1.tgz", + "integrity": "sha512-y8e109LYGgoQDveiEBD3DYXKba1jWf5BA8YU1FL5Tvm0BTdEfy54WLCwnuYWZNnzzvALy/QQ4Hov+Q9RVRv+Zw==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/es6-promise": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", + "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", + "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.19.12", + "@esbuild/android-arm": "0.19.12", + "@esbuild/android-arm64": "0.19.12", + "@esbuild/android-x64": "0.19.12", + "@esbuild/darwin-arm64": "0.19.12", + "@esbuild/darwin-x64": "0.19.12", + "@esbuild/freebsd-arm64": "0.19.12", + "@esbuild/freebsd-x64": "0.19.12", + "@esbuild/linux-arm": "0.19.12", + "@esbuild/linux-arm64": "0.19.12", + "@esbuild/linux-ia32": "0.19.12", + "@esbuild/linux-loong64": "0.19.12", + "@esbuild/linux-mips64el": "0.19.12", + "@esbuild/linux-ppc64": "0.19.12", + "@esbuild/linux-riscv64": "0.19.12", + "@esbuild/linux-s390x": "0.19.12", + "@esbuild/linux-x64": "0.19.12", + "@esbuild/netbsd-x64": "0.19.12", + "@esbuild/openbsd-x64": "0.19.12", + "@esbuild/sunos-x64": "0.19.12", + "@esbuild/win32-arm64": "0.19.12", + "@esbuild/win32-ia32": "0.19.12", + "@esbuild/win32-x64": "0.19.12" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.0.tgz", + "integrity": "sha512-zGygtijUMT7jnk3h26kUms3BkSDp4IfIKjmnqI2tvx6nuBfiF1UqOxbnLfzdv+apBy+53oaImsKtMw/xYbW+1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/hammerjs": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz", + "integrity": "sha512-tSQXBXS/MWQOn/RKckawJ61vvsDpCom87JgxiYdGwHdOa0ht0vzUWDlfioofFCRU0L+6NGDt6XzbgoJvZkMeRQ==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-reference": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", + "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/locate-character": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", + "dev": true + }, + "node_modules/magic-string": { + "version": "0.30.5", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", + "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/periscopic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", + "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^3.0.0", + "is-reference": "^3.0.0" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.4.33", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", + "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/rollup": { + "version": "4.9.6", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.6.tgz", + "integrity": "sha512-05lzkCS2uASX0CiLFybYfVkwNbKZG5NFQ6Go0VWyogFTXXbR039UVsegViTntkk4OglHBdF54ccApXRRuXRbsg==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.9.6", + "@rollup/rollup-android-arm64": "4.9.6", + "@rollup/rollup-darwin-arm64": "4.9.6", + "@rollup/rollup-darwin-x64": "4.9.6", + "@rollup/rollup-linux-arm-gnueabihf": "4.9.6", + "@rollup/rollup-linux-arm64-gnu": "4.9.6", + "@rollup/rollup-linux-arm64-musl": "4.9.6", + "@rollup/rollup-linux-riscv64-gnu": "4.9.6", + "@rollup/rollup-linux-x64-gnu": "4.9.6", + "@rollup/rollup-linux-x64-musl": "4.9.6", + "@rollup/rollup-win32-arm64-msvc": "4.9.6", + "@rollup/rollup-win32-ia32-msvc": "4.9.6", + "@rollup/rollup-win32-x64-msvc": "4.9.6", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dev": true, + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/sander": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/sander/-/sander-0.5.1.tgz", + "integrity": "sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==", + "dev": true, + "dependencies": { + "es6-promise": "^3.1.2", + "graceful-fs": "^4.1.3", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.2" + } + }, + "node_modules/sorcery": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.11.0.tgz", + "integrity": "sha512-J69LQ22xrQB1cIFJhPfgtLuI6BpWRiWu1Y3vSsIwK/eAScqJxd/+CJlUuHQRdX2C9NGFamq+KqNywGgaThwfHw==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.14", + "buffer-crc32": "^0.2.5", + "minimist": "^1.2.0", + "sander": "^0.5.0" + }, + "bin": { + "sorcery": "bin/sorcery" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/svelte": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.9.tgz", + "integrity": "sha512-hsoB/WZGEPFXeRRLPhPrbRz67PhP6sqYgvwcAs+gWdSQSvNDw+/lTeUJSWe5h2xC97Fz/8QxAOqItwBzNJPU8w==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.1", + "@jridgewell/sourcemap-codec": "^1.4.15", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/estree": "^1.0.1", + "acorn": "^8.9.0", + "aria-query": "^5.3.0", + "axobject-query": "^4.0.0", + "code-red": "^1.0.3", + "css-tree": "^2.3.1", + "estree-walker": "^3.0.3", + "is-reference": "^3.0.1", + "locate-character": "^3.0.0", + "magic-string": "^0.30.4", + "periscopic": "^3.1.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/svelte-check": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-3.6.3.tgz", + "integrity": "sha512-Q2nGnoysxUnB9KjnjpQLZwdjK62DHyW6nuH/gm2qteFnDk0lCehe/6z8TsIvYeKjC6luKaWxiNGyOcWiLLPSwA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.17", + "chokidar": "^3.4.1", + "fast-glob": "^3.2.7", + "import-fresh": "^3.2.1", + "picocolors": "^1.0.0", + "sade": "^1.7.4", + "svelte-preprocess": "^5.1.0", + "typescript": "^5.0.3" + }, + "bin": { + "svelte-check": "bin/svelte-check" + }, + "peerDependencies": { + "svelte": "^3.55.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0" + } + }, + "node_modules/svelte-hmr": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.3.tgz", + "integrity": "sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ==", + "dev": true, + "engines": { + "node": "^12.20 || ^14.13.1 || >= 16" + }, + "peerDependencies": { + "svelte": "^3.19.0 || ^4.0.0" + } + }, + "node_modules/svelte-preprocess": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.1.3.tgz", + "integrity": "sha512-xxAkmxGHT+J/GourS5mVJeOXZzne1FR5ljeOUAMXUkfEhkLEllRreXpbl3dIYJlcJRfL1LO1uIAPpBpBfiqGPw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@types/pug": "^2.0.6", + "detect-indent": "^6.1.0", + "magic-string": "^0.30.5", + "sorcery": "^0.11.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">= 16.0.0", + "pnpm": "^8.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.10.2", + "coffeescript": "^2.5.1", + "less": "^3.11.3 || ^4.0.0", + "postcss": "^7 || ^8", + "postcss-load-config": "^2.1.0 || ^3.0.0 || ^4.0.0 || ^5.0.0", + "pug": "^3.0.0", + "sass": "^1.26.8", + "stylus": "^0.55.0", + "sugarss": "^2.0.0 || ^3.0.0 || ^4.0.0", + "svelte": "^3.23.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0", + "typescript": ">=3.9.5 || ^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "coffeescript": { + "optional": true + }, + "less": { + "optional": true + }, + "postcss": { + "optional": true + }, + "postcss-load-config": { + "optional": true + }, + "pug": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/vite": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.12.tgz", + "integrity": "sha512-4hsnEkG3q0N4Tzf1+t6NdN9dg/L3BM+q8SWgbSPnJvrgH2kgdyzfVJwbR1ic69/4uMJJ/3dqDZZE5/WwqW8U1w==", + "dev": true, + "dependencies": { + "esbuild": "^0.19.3", + "postcss": "^8.4.32", + "rollup": "^4.2.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vitefu": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz", + "integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==", + "dev": true, + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..a8657ec --- /dev/null +++ b/package.json @@ -0,0 +1,29 @@ +{ + "name": "accuchek", + "private": true, + "type": "module", + "license": "BSD-2-Clause", + "scripts": { + "ci": "npm run build && npm run check", + "dev": "vite", + "build": "vite build", + "preview": "vite preview", + "check": "svelte-check --tsconfig ./tsconfig.json" + }, + "devDependencies": { + "@amadeus-it-group/tansu": "^1.0.0", + "@sveltejs/vite-plugin-svelte": "^3.0.1", + "@tsconfig/svelte": "^5.0.2", + "@types/w3c-web-usb": "^1.0.10", + "bootstrap": "^5.3.2", + "chart.js": "^4.4.1", + "chartjs-adapter-date-fns": "^3.0.0", + "chartjs-plugin-zoom": "^2.0.1", + "date-fns": "^3.3.1", + "svelte": "^4.2.8", + "svelte-check": "^3.6.2", + "tslib": "^2.6.2", + "typescript": "^5.2.2", + "vite": "^5.0.8" + } +} diff --git a/src/App.svelte b/src/App.svelte new file mode 100644 index 0000000..763c95a --- /dev/null +++ b/src/App.svelte @@ -0,0 +1,87 @@ + + +
+
+ + +
+ + {#if navigator.usb} + + {/if} + + {#if $data$} + Enregistrer au format JSON + Enregistrer au format CSV + +
+
Nom de modèle:
+
{$data$.config.modelName}
+
Numéro de modèle:
+
{$data$.config.modelNumber}
+
Numéro de série:
+
{$data$.config.serialNumber}
+
Heure du périphérique:
+
{formatDate($data$.config.deviceTime)}
+
Heure du système:
+
{formatDate($data$.config.systemTime)}
+
+ + + + + + + {#each $data$.data as measure} + + {/each} + +
DateGlycémie
{formatDate(measure.timestamp)}{measure.value}
+ {/if} +
+ Le code source de ce programme + est disponible. +
+
diff --git a/src/Graph.svelte b/src/Graph.svelte new file mode 100644 index 0000000..a4a67f7 --- /dev/null +++ b/src/Graph.svelte @@ -0,0 +1,68 @@ + + + + +{#key data} + +{/key} diff --git a/src/data.ts b/src/data.ts new file mode 100644 index 0000000..5592545 --- /dev/null +++ b/src/data.ts @@ -0,0 +1,62 @@ +import { computed, writable } from "@amadeus-it-group/tansu"; +import { readFromDevice } from "./readUSBData"; +import { resolveStorePromise, toBlobURL } from "./storeUtils"; + +const dataPromise$ = writable | undefined>( + undefined +); + +export const data$ = resolveStorePromise(dataPromise$); +export const jsonBlob$ = computed( + () => + new Blob([JSON.stringify(data$(), null, " ")], { + type: "application/json", + }) +); +export const jsonBlobURL$ = toBlobURL(jsonBlob$); +export const csvBlob$ = computed( + () => + new Blob( + [ + `Date\tValue\tStatus\n${ + data$() + ?.data.map((a) => `${a.timestamp}\t${a.value}\t${a.status}`) + .join("\n") ?? "" + }`, + ], + { type: "text/csv" } + ) +); +export const csvBlobURL$ = toBlobURL(csvBlob$); +export const fileName$ = computed(() => { + const data = data$(); + return data + ? `${data.config.modelName}-${data.config.serialNumber}-${data.config.systemTime}` + : ""; +}); + +export async function callReadFromDevice() { + dataPromise$.set(readFromDevice()); +} + +const readFile = (file: File) => + new Promise((resolve, reject) => { + const fileReader = new FileReader(); + fileReader.onload = () => { + resolve(fileReader.result as string); + }; + fileReader.onerror = reject; + fileReader.readAsText(file); + }); + +const asyncOpenFile = async (file: File | null) => { + if (!file) { + return null; + } + const fileContent = await readFile(file); + return JSON.parse(fileContent); +}; + +export function callReadFromFile(file: File | null) { + dataPromise$.set(asyncOpenFile(file)); +} diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..9e4306d --- /dev/null +++ b/src/main.ts @@ -0,0 +1,8 @@ +import "bootstrap/dist/css/bootstrap.min.css"; +import App from "./App.svelte"; + +const app = new App({ + target: document.getElementById("app")!, +}); + +export default app; diff --git a/src/readUSBData.ts b/src/readUSBData.ts new file mode 100644 index 0000000..d971e86 --- /dev/null +++ b/src/readUSBData.ts @@ -0,0 +1,845 @@ +// The code in this file originally comes +// from https://github.com/tidepool-org/uploader/blob/master/lib/drivers/roche/utils.js +// and https://github.com/tidepool-org/uploader/blob/master/lib/drivers/roche/accuChekUSB.js +// and https://github.com/tidepool-org/uploader/blob/master/lib/commonFunctions.js +// and contains additional modifications + +/* + * == BSD2 LICENSE == + * Copyright (c) 2019, Tidepool Project + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the associated License, which is identical to the BSD 2-Clause + * License as published by the Open Source Initiative at opensource.org. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the License for more details. + * + * You should have received a copy of the License along with this program; if + * not, you can obtain one from Tidepool Project at tidepool.org. + * == BSD2 LICENSE == + */ + +const debug = console.log; + +const bytes2hex = (bytes: Uint8Array) => { + var message = ""; + for (var i in bytes) { + var hex = bytes[i].toString(16).toUpperCase(); + if (hex.length === 1) { + message += "0"; + } + message += hex; + } + return message; +}; + +const formatTimestamp = (str: string): string => + `${str.substring(0, 4)}-${str.substring(4, 6)}-${str.substring( + 6, + 8 + )}T${str.substring(8, 10)}:${str.substring(10, 12)}` as any; + +const models = [ + { + name: "Aviva Connect", + numbers: [483, 484, 497, 498, 499, 500, 502, 685], + }, + { name: "Performa Connect", numbers: [479, 501, 503, 765] }, + { name: "Guide", numbers: [921, 922, 923, 925, 926, 929, 930, 932] }, + { + name: "Instant (single-button)", + numbers: [958, 959, 960, 961, 963, 964, 965], + }, + { name: "Guide Me", numbers: [897, 898, 901, 902, 903, 904, 905] }, + { + name: "Instant (two-button)", + numbers: [972, 973, 975, 976, 977, 978, 979, 980], + }, + { + name: "Instant S (single-button)", + numbers: [966, 967, 968, 969, 970, 971], + }, + { name: "ReliOn Platinum", numbers: [982] }, +]; + +const getModelName = (number: number) => { + // eslint-disable-next-line no-restricted-syntax + for (const i in models) { + if (models[i].numbers.indexOf(number) >= 0) { + return models[i].name; + } + } + return `Unknown model ${number}`; +}; + +const APDU_TYPE = { + ASSOCIATION_REQUEST: 0xe200, + ASSOCIATION_RESPONSE: 0xe300, + ASSOCIATION_RELEASE_REQUEST: 0xe400, + ASSOCIATION_RELEASE_RESPONSE: 0xe500, + ASSOCIATION_ABORT: 0xe600, + PRESENTATION_APDU: 0xe700, +}; + +const EVENT_TYPE = { + MDC_NOTI_CONFIG: 0x0d1c, + MDC_NOTI_SEGMENT_DATA: 0x0d21, +}; + +const ACTION_TYPE = { + MDC_ACT_SEG_GET_INFO: 0x0c0d, + MDC_ACT_SEG_GET_ID_LIST: 0x0c1e, + MDC_ACT_SEG_TRIG_XFER: 0x0c1c, + MDC_ACT_SEG_SET_TIME: 0x0c17, +}; + +const DATA_ADPU = { + INVOKE_GET: 0x0103, + INVOKE_CONFIRMED_ACTION: 0x0107, + RESPONSE_CONFIRMED_EVENT_REPORT: 0x0201, + RESPONSE_GET: 0x0203, + RESPONSE_CONFIRMED_ACTION: 0x0207, +}; + +const DATA_RESPONSE = { + 0: "Transfer successful", + 1: "No such segment", + 2: "Try again later", + 3: "Segment is empty", + 512: "Failed to retrieve segment", +}; + +const MDC_PART_OBJ = { + MDC_MOC_VMO_METRIC: 4, + MDC_MOC_VMO_METRIC_ENUM: 5, + MDC_MOC_VMO_METRIC_NU: 6, + MDC_MOC_VMO_METRIC_SA_RT: 9, + MDC_MOC_SCAN: 16, + MDC_MOC_SCAN_CFG: 17, + MDC_MOC_SCAN_CFG_EPI: 18, + MDC_MOC_SCAN_CFG_PERI: 19, + MDC_MOC_VMS_MDS_SIMP: 37, + MDC_MOC_VMO_PMSTORE: 61, + MDC_MOC_PM_SEGMENT: 62, + MDC_ATTR_CONFIRM_MODE: 2323, + MDC_ATTR_CONFIRM_TIMEOUT: 2324, + MDC_ATTR_TRANSPORT_TIMEOUT: 2694, + MDC_ATTR_ID_HANDLE: 2337, + MDC_ATTR_ID_INSTNO: 2338, + MDC_ATTR_ID_LABEL_STRING: 2343, + MDC_ATTR_ID_MODEL: 2344, + MDC_ATTR_ID_PHYSIO: 2347, + MDC_ATTR_ID_PROD_SPECN: 2349, + MDC_ATTR_ID_TYPE: 2351, + MDC_ATTR_METRIC_STORE_CAPAC_CNT: 2369, + MDC_ATTR_METRIC_STORE_SAMPLE_ALG: 2371, + MDC_ATTR_METRIC_STORE_USAGE_CNT: 2372, + MDC_ATTR_MSMT_STAT: 2375, + MDC_ATTR_NU_ACCUR_MSMT: 2378, + MDC_ATTR_NU_CMPD_VAL_OBS: 2379, + MDC_ATTR_NU_VAL_OBS: 2384, + MDC_ATTR_NUM_SEG: 2385, + MDC_ATTR_OP_STAT: 2387, + MDC_ATTR_POWER_STAT: 2389, + MDC_ATTR_SA_SPECN: 2413, + MDC_ATTR_SCALE_SPECN_I16: 2415, + MDC_ATTR_SCALE_SPECN_I32: 2416, + MDC_ATTR_SCALE_SPECN_I8: 2417, + MDC_ATTR_SCAN_REP_PD: 2421, + MDC_ATTR_SEG_USAGE_CNT: 2427, + MDC_ATTR_SYS_ID: 2436, + MDC_ATTR_SYS_TYPE: 2438, + MDC_ATTR_TIME_ABS: 2439, + MDC_ATTR_TIME_BATT_REMAIN: 2440, + MDC_ATTR_TIME_END_SEG: 2442, + MDC_ATTR_TIME_PD_SAMP: 2445, + MDC_ATTR_TIME_REL: 2447, + MDC_ATTR_TIME_STAMP_ABS: 2448, + MDC_ATTR_TIME_STAMP_REL: 2449, + MDC_ATTR_TIME_START_SEG: 2450, + MDC_ATTR_TX_WIND: 2453, + MDC_ATTR_UNIT_CODE: 2454, + MDC_ATTR_UNIT_LABEL_STRING: 2457, + MDC_ATTR_VAL_BATT_CHARGE: 2460, + MDC_ATTR_VAL_ENUM_OBS: 2462, + MDC_ATTR_TIME_REL_HI_RES: 2536, + MDC_ATTR_TIME_STAMP_REL_HI_RES: 2537, + MDC_ATTR_DEV_CONFIG_ID: 2628, + MDC_ATTR_MDS_TIME_INFO: 2629, + MDC_ATTR_METRIC_SPEC_SMALL: 2630, + MDC_ATTR_SOURCE_HANDLE_REF: 2631, + MDC_ATTR_SIMP_SA_OBS_VAL: 2632, + MDC_ATTR_ENUM_OBS_VAL_SIMP_OID: 2633, + MDC_ATTR_ENUM_OBS_VAL_SIMP_STR: 2634, + MDC_REG_CERT_DATA_LIST: 2635, + MDC_ATTR_NU_VAL_OBS_BASIC: 2636, + MDC_ATTR_PM_STORE_CAPAB: 2637, + MDC_ATTR_PM_SEG_MAP: 2638, + MDC_ATTR_PM_SEG_PERSON_ID: 2639, + MDC_ATTR_SEG_STATS: 2640, + MDC_ATTR_SEG_FIXED_DATA: 2641, + MDC_ATTR_SCAN_HANDLE_ATTR_VAL_MAP: 2643, + MDC_ATTR_SCAN_REP_PD_MIN: 2644, + MDC_ATTR_ATTRIBUTE_VAL_MAP: 2645, + MDC_ATTR_NU_VAL_OBS_SIMP: 2646, + MDC_ATTR_PM_STORE_LABEL_STRING: 2647, + MDC_ATTR_PM_SEG_LABEL_STRING: 2648, + MDC_ATTR_TIME_PD_MSMT_ACTIVE: 2649, + MDC_ATTR_SYS_TYPE_SPEC_LIST: 2650, + MDC_ATTR_METRIC_ID_PART: 2655, + MDC_ATTR_ENUM_OBS_VAL_PART: 2656, + MDC_ATTR_SUPPLEMENTAL_TYPES: 2657, + MDC_ATTR_TIME_ABS_ADJUST: 2658, + MDC_ATTR_CLEAR_TIMEOUT: 2659, + MDC_ATTR_TRANSFER_TIMEOUT: 2660, + MDC_ATTR_ENUM_OBS_VAL_SIMP_BIT_STR: 2661, + MDC_ATTR_ENUM_OBS_VAL_BASIC_BIT_STR: 2662, + MDC_ATTR_METRIC_STRUCT_SMALL: 2675, + MDC_ATTR_NU_CMPD_VAL_OBS_SIMP: 2676, + MDC_ATTR_NU_CMPD_VAL_OBS_BASIC: 2677, + MDC_ATTR_ID_PHYSIO_LIST: 2678, + MDC_ATTR_SCAN_HANDLE_LIST: 2679, + MDC_ATTR_TIME_BO: 2689, + MDC_ATTR_TIME_STAMP_BO: 2690, + MDC_ATTR_TIME_START_SEG_BO: 2691, + MDC_ATTR_TIME_END_SEG_BO: 2692, +}; + +const PROD_SPEC_ENTRY = [ + "unspecified", + "serial-number", + "part-number", + "hw-revision", + "sw-revision", + "fw-revision", + "protocol-revision", + "prod-spec-gmdn", +]; + +const getObject = (bytes: DataView, type: number) => { + let offset = 28; + const count = bytes.getUint16(24); + + for (let i = 0; i < count; i++) { + const objClass = bytes.getUint16(offset); + const handle = bytes.getUint16(offset + 2); + const attributeCount = bytes.getUint16(offset + 4); + const length = bytes.getUint16(offset + 6); + + offset += length + 8; + + if (type === objClass) { + return { + handle, + attributeCount, + bytes: new DataView(bytes.buffer.slice(offset - length, offset)), + }; + } + } + + return null; +}; + +const getAttributeList = (bytes: DataView) => { + let offset = 14; + + const attributeCount = bytes.getUint16(offset); + const length = bytes.getUint16(offset + 2); + offset += 4; + return { + attributeCount, + bytes: new DataView(bytes.buffer.slice(offset, offset + length)), + }; +}; + +const getProductionSpecEntry = (bytes: DataView, entry: string) => { + let offset = 0; + const count = bytes.getUint16(offset); + + for (let i = 0; i < count; i++) { + const type = PROD_SPEC_ENTRY[bytes.getUint16(offset + 4)]; + const length = bytes.getUint16(offset + 8); + offset += length + 10; + + if (entry === type) { + return new DataView(bytes.buffer.slice(offset - length, offset)); + } + } + + return null; +}; + +const getAttribute = ( + obj: { attributeCount: number; bytes: DataView }, + type: number +) => { + let offset = 0; + + for (let i = 0; i < obj.attributeCount; i++) { + const attributeId = obj.bytes.getUint16(offset); + const length = obj.bytes.getUint16(offset + 2); + + offset += length + 4; + + if (type === attributeId) { + return new DataView(obj.bytes.buffer.slice(offset - length, offset)); + } + } + + return null; +}; + +const timeout = (delay = 5000) => + new Promise((resolve, reject) => + setTimeout(reject, delay, new Error("Timeout error")) + ); + +interface USBDeviceAndConfig { + usbDevice: USBDevice; + outEPnum: number; + inEPnum: number; +} + +const openDevice = async (usbDevice: USBDevice) => { + await usbDevice.open(); + + if (usbDevice.configuration == null) { + debug("Selecting configuration 1"); + await usbDevice.selectConfiguration(1); + } + + if (usbDevice.configuration?.interfaces == null) { + throw new Error("Please unplug device and retry."); + } + + const [iface] = usbDevice.configuration.interfaces; + + debug("Claiming interface", iface.interfaceNumber); + await usbDevice.claimInterface(iface.interfaceNumber); + + const epOut = iface.alternate.endpoints.find((ep) => ep.direction === "out")!; + const epIn = iface.alternate.endpoints.find((ep) => ep.direction === "in")!; + + const usbconfig: USBDeviceAndConfig = { + usbDevice, + outEPnum: epOut.endpointNumber, + inEPnum: epIn.endpointNumber, + }; + + await usbDevice.controlTransferIn( + { + requestType: "standard", + recipient: "device", + request: 0x00, + value: 0x00, + index: 0x00, + }, + 2 + ); + + const incoming = await Promise.race([ + timeout(), + usbDevice.transferIn(usbconfig.inEPnum, 1024), + ]); + + debug("Status:", incoming.status); + + if (incoming.status === "babble") { + throw new Error("Device left plugged in for too long."); + } + + debug( + "Received association request:", + bytes2hex(new Uint8Array(incoming.data!.buffer)) + ); + + await usbDevice.transferOut(usbconfig.outEPnum, buildAssociationResponse()); + + return usbconfig; +}; + +interface ConfigData { + extendedConfig: DataView; + pmStoreHandle: number; + numberOfSegments: number; + deviceDetails: DataView; + pmStoreConfig: DataView; + lastInvokeId: number; +} + +const getConfig = async ( + usbConfig: USBDeviceAndConfig +): Promise => { + const data: Partial = {}; + let incoming: USBInTransferResult; + + async function getPMStore() { + incoming = await Promise.race([ + timeout(), + usbConfig.usbDevice.transferIn(usbConfig.inEPnum, 1024), + ]); + debug( + "Received extended config:", + bytes2hex(new Uint8Array(incoming.data!.buffer)) + ); + data.extendedConfig = incoming.data!; + + if (incoming == null) { + throw Error("Could not retrieve config. Please retry."); + } + + return getObject(incoming.data!, MDC_PART_OBJ.MDC_MOC_VMO_PMSTORE); + } + + let pmStoreDetails = await getPMStore(); + + if (pmStoreDetails == null) { + debug("Invalid config, trying again..."); + + await usbConfig.usbDevice.transferOut( + usbConfig.outEPnum, + buildAssociationResponse() + ); + + pmStoreDetails = await getPMStore(); + + if (pmStoreDetails == null) { + throw Error("Could not parse config. Please retry."); + } + } + data.pmStoreHandle = pmStoreDetails.handle; + data.numberOfSegments = getAttribute( + pmStoreDetails, + MDC_PART_OBJ.MDC_ATTR_NUM_SEG + )!.getUint16(0); + + let invokeId = incoming!.data!.getUint16(6); + await usbConfig.usbDevice.transferOut( + usbConfig.outEPnum, + buildConfigResponse(invokeId) + ); + + await usbConfig.usbDevice.transferOut( + usbConfig.outEPnum, + buildMDSAttributeRequest(invokeId) + ); + incoming = await usbConfig.usbDevice.transferIn(usbConfig.inEPnum, 1024); + debug( + "Received MDS attribute response:", + bytes2hex(new Uint8Array(incoming.data!.buffer)) + ); + invokeId = incoming.data!.getUint16(6); + data.deviceDetails = incoming.data!; + + await usbConfig.usbDevice.transferOut( + usbConfig.outEPnum, + buildActionRequest(invokeId, data.pmStoreHandle) + ); + incoming = await usbConfig.usbDevice.transferIn(usbConfig.inEPnum, 1024); + debug( + "Received action request response:", + bytes2hex(new Uint8Array(incoming.data!.buffer)) + ); + data.pmStoreConfig = incoming.data!; + + data.lastInvokeId = incoming.data!.getUint16(6); + + return data as any; +}; + +const setTime = async ( + usbConfig: USBDeviceAndConfig, + invokeId: number, + timestamp: bigint +) => { + await usbConfig.usbDevice.transferOut( + usbConfig.outEPnum, + buildSetTimeRequest(invokeId, timestamp) + ); + const incoming = await usbConfig.usbDevice.transferIn( + usbConfig.inEPnum, + 1024 + ); + const lastInvokeId = incoming.data!.getUint16(6); + debug( + "Received set time response:", + bytes2hex(new Uint8Array(incoming.data!.buffer)) + ); + + return lastInvokeId; +}; + +const getData = async ( + usbConfig: USBDeviceAndConfig, + invokeId: number, + pmStoreHandle: number +) => { + const pages: DataView[] = []; + let done = false; + const segment = 0; + + // these requests need to be sequential + // eslint-disable-next-line no-await-in-loop + await usbConfig.usbDevice.transferOut( + usbConfig.outEPnum, + buildDataTransferRequest(invokeId, pmStoreHandle, segment) + ); + + // these requests need to be sequential + // eslint-disable-next-line no-await-in-loop + const incoming = await usbConfig.usbDevice.transferIn( + usbConfig.inEPnum, + 1024 + ); + debug( + "Received data transfer request response:", + bytes2hex(new Uint8Array(incoming.data!.buffer)) + ); + + if (incoming.data!.byteLength === 22 && incoming.data!.getUint16(20)) { + const dataResponse = incoming.data!.getUint16(20); + if (dataResponse === 3) { + debug("Segment was empty"); + } else { + throw new Error( + `Could not retrieve data: ${(DATA_RESPONSE as any)[dataResponse]}` + ); + } + } else if ( + incoming.data!.byteLength < 22 || + incoming.data!.getUint16(14) !== ACTION_TYPE.MDC_ACT_SEG_TRIG_XFER + ) { + throw new Error("Unexpected response"); + } else { + while (!done) { + // these requests need to be sequential + // eslint-disable-next-line no-await-in-loop + const { data } = await usbConfig.usbDevice.transferIn( + usbConfig.inEPnum, + 1024 + ); + debug("Data:", bytes2hex(new Uint8Array(data!.buffer))); + pages.push(data!); + + const dataInvokeId = data!.getUint16(6); + const segmentDataResult = new DataView(data!.buffer.slice(22, 32)); + const status = data!.getUint8(32); + + /* eslint-disable-next-line no-bitwise */ + if (status & 0x40) { + // the second bit of the status field indicates if it's the last one + done = true; + } + + // these requests need to be sequential + // eslint-disable-next-line no-await-in-loop + await usbConfig.usbDevice.transferOut( + usbConfig.outEPnum, + buildDataTransferConfirmation( + dataInvokeId, + pmStoreHandle, + segmentDataResult + ) + ); + } + } + + return pages; +}; + +export interface Measurement { + timestamp: string; + value: number; + status: number; +} + +const parseData = (pages: DataView[]) => { + const records: Measurement[] = []; + + pages.forEach((page) => { + let offset = 30; + const entries = page.getUint16(offset); + + for (let i = 0; i < entries; i++) { + const timestamp = page.buffer.slice(offset + 6, offset + 12); + const record: Measurement = { + timestamp: formatTimestamp(bytes2hex(new Uint8Array(timestamp))), + value: page.getUint16(offset + 14), + status: page.getUint16(offset + 16), + }; + offset += 12; + records.push(record); + } + }); + + return records; +}; + +const buildAssociationResponse = () => { + const buf = new ArrayBuffer(48); + const buffer = new DataView(buf); + + buffer.setUint16(0, APDU_TYPE.ASSOCIATION_RESPONSE); + buffer.setUint16(2, 44); // Length (excludes initial 4 bytes) + buffer.setUint16(4, 0x0003); // accepted-unknown-config + buffer.setUint16(6, 20601); // data-proto-id + buffer.setUint16(8, 38); // data-proto-info length + buffer.setUint32(10, 0x80000002); // protocolVersion + buffer.setUint16(14, 0x8000); // encoding-rules = MDER + buffer.setUint32(16, 0x80000000); // nomenclatureVersion + buffer.setUint32(20, 0); // functionalUnits = normal association + buffer.setUint32(24, 0x80000000); // systemType = sys-type-manager + buffer.setUint16(28, 8); // system-id length + buffer.setUint32(30, 0x12345678); // system-id high + buffer.setUint32(34, 0x87654321); // system-id low + // rest of bytes should always be 0x00 for manager response + + debug("Association response:", bytes2hex(new Uint8Array(buf))); + + return buffer.buffer; +}; + +const buildAssociationReleaseRequest = () => { + const buf = new ArrayBuffer(6); + const buffer = new DataView(buf); + + buffer.setUint16(0, APDU_TYPE.ASSOCIATION_RELEASE_REQUEST); + buffer.setUint16(2, 2); // length = 2 + buffer.setUint16(4, 0x0000); // normal + + debug("Association release:", bytes2hex(new Uint8Array(buf))); + + return buffer.buffer; +}; + +const buildConfigResponse = (invokeId: number) => { + const buf = new ArrayBuffer(26); + const buffer = new DataView(buf); + + buffer.setUint16(0, APDU_TYPE.PRESENTATION_APDU); + buffer.setUint16(2, 22); // length + buffer.setUint16(4, 20); // octet stringlength + buffer.setUint16(6, invokeId); // invoke-id from config + buffer.setUint16(8, DATA_ADPU.RESPONSE_CONFIRMED_EVENT_REPORT); + buffer.setUint16(10, 14); // length + buffer.setUint16(12, 0); // obj-handle = 0 + buffer.setUint32(14, 0); // currentTime = 0 + buffer.setUint16(18, EVENT_TYPE.MDC_NOTI_CONFIG); // event-type + buffer.setUint16(20, 4); // length + buffer.setUint16(22, 0x4000); // config-report-id = extended-config-start + buffer.setUint16(24, 0); // config-result = accepted-config + + debug("Config response:", bytes2hex(new Uint8Array(buf))); + + return buffer.buffer; +}; + +const buildMDSAttributeRequest = (invokeId: number) => { + const buf = new ArrayBuffer(18); + const buffer = new DataView(buf); + + buffer.setUint16(0, APDU_TYPE.PRESENTATION_APDU); + buffer.setUint16(2, 14); // length + buffer.setUint16(4, 12); // octet string length + buffer.setUint16(6, invokeId + 1); // to differentiate from previous + buffer.setUint16(8, DATA_ADPU.INVOKE_GET); + buffer.setUint16(10, 6); // length + buffer.setUint16(12, 0); // handle 0 + buffer.setUint16(14, 0); // attribute-id-list.count = 0 (get all attributes) + buffer.setUint16(16, 0); // attribute-id-list.length = 0 + + debug("MDS request:", bytes2hex(new Uint8Array(buf))); + + return buffer.buffer; +}; + +const buildActionRequest = (invokeId: number, pmStoreHandle: number) => { + const buf = new ArrayBuffer(24); + const buffer = new DataView(buf); + + buffer.setUint16(0, APDU_TYPE.PRESENTATION_APDU); + buffer.setUint16(2, 20); // length + buffer.setUint16(4, 18); // octet string length + buffer.setUint16(6, invokeId + 1); // invoke-id + buffer.setUint16(8, DATA_ADPU.INVOKE_CONFIRMED_ACTION); + buffer.setUint16(12, pmStoreHandle); + buffer.setUint16(14, ACTION_TYPE.MDC_ACT_SEG_GET_INFO); + buffer.setUint16(16, 6); // length + buffer.setUint16(18, 1); // all-segments + buffer.setUint16(20, 2); // length + buffer.setUint16(22, 0); + + debug("Action request:", bytes2hex(new Uint8Array(buf))); + + return buffer.buffer; +}; + +const buildSetTimeRequest = (invokeId: number, timestamp: bigint) => { + const buf = new ArrayBuffer(30); + const buffer = new DataView(buf); + + buffer.setUint16(0, APDU_TYPE.PRESENTATION_APDU); + buffer.setUint16(2, 26); // length + buffer.setUint16(4, 24); // octet string length + buffer.setUint16(6, invokeId + 1); // invoke-id + buffer.setUint16(8, DATA_ADPU.INVOKE_CONFIRMED_ACTION); + buffer.setUint16(10, 18); // length + buffer.setUint16(12, 0); + buffer.setUint16(14, ACTION_TYPE.MDC_ACT_SEG_SET_TIME); + buffer.setUint16(16, 12); // length + buffer.setBigUint64(18, timestamp); // AbsoluteTime + buffer.setUint32(26, 0); // accuracy (FLOAT-type, set to zero) + + debug("Set time request:", bytes2hex(new Uint8Array(buf))); + + return buffer.buffer; +}; + +const buildDataTransferRequest = ( + invokeId: number, + pmStoreHandle: number, + segment: number +) => { + const buf = new ArrayBuffer(20); + const buffer = new DataView(buf); + + buffer.setUint16(0, APDU_TYPE.PRESENTATION_APDU); + buffer.setUint16(2, 16); // length + buffer.setUint16(4, 14); // octet string length + buffer.setUint16(6, invokeId + 1); // invoke-id + buffer.setUint16(8, DATA_ADPU.INVOKE_CONFIRMED_ACTION); + buffer.setUint16(10, 8); // length + buffer.setUint16(12, pmStoreHandle); + buffer.setUint16(14, ACTION_TYPE.MDC_ACT_SEG_TRIG_XFER); + buffer.setUint16(16, 2); // length + buffer.setUint16(18, segment); // segment + + debug("Data transfer request:", bytes2hex(new Uint8Array(buf))); + + return buffer.buffer; +}; + +const buildDataTransferConfirmation = ( + invokeId: number, + pmStoreHandle: number, + segmentDataResult: DataView +) => { + const buf = new ArrayBuffer(34); + const buffer = new DataView(buf); + + buffer.setUint16(0, APDU_TYPE.PRESENTATION_APDU); + buffer.setUint16(2, 30); // length + buffer.setUint16(4, 28); // octet string length + buffer.setUint16(6, invokeId); + buffer.setUint16(8, DATA_ADPU.RESPONSE_CONFIRMED_EVENT_REPORT); + buffer.setUint16(10, 22); // length + buffer.setUint16(12, pmStoreHandle); + buffer.setUint32(14, 0xffffffff); // relative time + buffer.setUint16(18, EVENT_TYPE.MDC_NOTI_SEGMENT_DATA); + buffer.setUint16(20, 12); // length + buffer.setUint32(22, segmentDataResult.getUint32(0)); + buffer.setUint32(26, segmentDataResult.getUint32(4)); + buffer.setUint16(30, segmentDataResult.getUint16(8)); // number of entries + buffer.setUint16(32, 0x0080); // confirmed + + debug("Data transfer confirmation:", bytes2hex(new Uint8Array(buf))); + + return buffer.buffer; +}; + +const release = async (usbConfig: USBDeviceAndConfig) => { + try { + await usbConfig.usbDevice.transferOut( + usbConfig.outEPnum, + buildAssociationReleaseRequest() + ); + const incoming = await usbConfig.usbDevice.transferIn( + usbConfig.inEPnum, + 1024 + ); + debug( + "Release response:", + bytes2hex(new Uint8Array(incoming.data!.buffer)) + ); + } catch (error) { + debug("Could not release device successfully."); + } +}; + +const close = async (usbDevice: USBDevice) => { + await usbDevice.releaseInterface(0); + await usbDevice.close(); +}; + +const f2 = (t: number) => (t < 10 ? `0${t}` : `${t}`); +const formatDateObject = (date: Date) => + `${date.getFullYear()}-${f2(date.getMonth() + 1)}-${f2(date.getDate())}T${f2( + date.getHours() + )}:${f2(date.getMinutes())}`; + +const parseConfig = (result: ConfigData) => { + const decoder = new TextDecoder(); + + const deviceDetails = getAttributeList(result.deviceDetails); + const modelStr = decoder.decode( + getAttribute(deviceDetails, MDC_PART_OBJ.MDC_ATTR_ID_MODEL)! + ); + + const re = /(\d+)/g; + const modelNumber = re.exec(modelStr)![0]; + const modelName = getModelName(+modelNumber); // for metrics + debug("Detected as:", modelName); + + const productionSpec = getAttribute( + deviceDetails, + MDC_PART_OBJ.MDC_ATTR_ID_PROD_SPECN + ); + const serialNumberStr = decoder.decode( + getProductionSpecEntry(productionSpec!, "serial-number")! + ); + + const serialNumber = re.exec(serialNumberStr)![0]; + + const timestamp = getAttribute(deviceDetails, MDC_PART_OBJ.MDC_ATTR_TIME_ABS); + const deviceTime = formatTimestamp( + bytes2hex(new Uint8Array(timestamp!.buffer)) + ); + return { + modelNumber, + modelName, + serialNumber, + deviceTime, + systemTime: formatDateObject(new Date()), + }; +}; + +// SUBSYSTEM=="usb", SYSFS{idVendor}=="173a", SYSFS{idProduct}=="21d5", ACTION=="add", MODE="0666" + +/** Supported device ids */ +const filters = [{ vendorId: 0x173a, productId: 0x21d5 }]; + +export const readFromDevice = async () => { + const usbDevice = await navigator.usb.requestDevice({ + filters, + }); + const usbConfig = await openDevice(usbDevice); + try { + const config = await getConfig(usbConfig); + const parsedConfig = parseConfig(config); + const pages = await getData( + usbConfig, + config.lastInvokeId, + config.pmStoreHandle + ); + const parsedData = parseData(pages); + return { + config: parsedConfig, + data: parsedData, + }; + } finally { + await release(usbConfig); + await close(usbDevice); + } +}; diff --git a/src/storeUtils.ts b/src/storeUtils.ts new file mode 100644 index 0000000..5ab04f4 --- /dev/null +++ b/src/storeUtils.ts @@ -0,0 +1,41 @@ +import type { ReadableSignal } from "@amadeus-it-group/tansu"; +import { derived } from "@amadeus-it-group/tansu"; + +export const resolveStorePromise = ( + promiseStore$: ReadableSignal | null | undefined> +) => + derived( + promiseStore$, + (promise, set) => { + set(null); + if (!promise) { + return; + } + let destroyed = false; + promise.then((resolved) => { + if (destroyed) return; + set(resolved); + }); + return () => { + destroyed = true; + }; + }, + null as null | T + ); + +export const toBlobURL = (blob$: ReadableSignal) => + derived( + blob$, + (value, set) => { + if (!value) { + set(null); + return; + } + const url = URL.createObjectURL(value); + set(url); + return () => { + URL.revokeObjectURL(url); + }; + }, + null as string | null + ); diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts new file mode 100644 index 0000000..4078e74 --- /dev/null +++ b/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte.config.js b/svelte.config.js new file mode 100644 index 0000000..b0683fd --- /dev/null +++ b/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..5fb548f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..494bfe0 --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..d701969 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte()], +})