diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..ed8cf37 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# http://editorconfig.org + +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[{package.json,*.yml,*.js}] +indent_style = space +indent_size = 2 diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000..5b441ce --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,32 @@ +/** @type {import('eslint').Linter.Config} */ +module.exports = { + root: true, + env: { + browser: true, + es2022: true, + node: true, + }, + extends: [ + 'eslint:recommended', + 'plugin:svelte/recommended', + 'prettier', + ], + overrides: [ + { + files: ['*.svelte'], + processor: 'svelte3/svelte3', + }, + ], + plugins: ['svelte'], + settings: { + // Let ESLint understand Svelte + 'svelte3/ignore-styles': () => true, + }, + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + }, + rules: { + // Customize your rules here + }, +}; diff --git a/.forgejo/workflows/deploy.yml b/.forgejo/workflows/deploy.yml index d07b49b..3c18941 100644 --- a/.forgejo/workflows/deploy.yml +++ b/.forgejo/workflows/deploy.yml @@ -18,23 +18,19 @@ jobs: with: node-version: 19 - - name: Install rsync - run: | - apt-get update - apt-get install -y rsync + env: + SSH_PRIVATE_KEY: ${{secrets.SSH_KEY}} + SSH_KNOWN_HOSTS: ${{secrets.SSH_KNOWN_HOSTS}} - - name: Install dependencies - run: npm install - - - name: Build app - run: npm run build + - name: Install PM2 + run: npm i -g pm2 - name: Add Deploy Key to SSH run: | - mkdir ~/.ssh - echo "${{ secrets.SSH_KEY }}" >> ~/.ssh/id_ed25519_embroideryviewer - chmod 400 ~/.ssh/id_ed25519_embroideryviewer - echo -e "Host embroideryviewer\n\tUser embroideryviewer\n\tHostname 45.76.5.44\n\tIdentityFile ~/.ssh/id_ed25519_embroideryviewer\n\tStrictHostKeyChecking No" >> ~/.ssh/config + mkdir -p ~/.ssh + echo "${{ secrets.SSH_KEY }}" >> ./deploy.key + sudo chmod 600 ./deploy.key + echo "${{ secrets.SSH_KNOWN_HOSTS}}" > ~/.ssh/known_hosts - - name: Upload changes to server - run: rsync -avz --progress dist/ embroideryviewer:web/prod \ No newline at end of file + - name: Deploy + run: pm2 deploy ecosystem.config.cjs production diff --git a/.gitignore b/.gitignore index 9ecd2f6..6635cf5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,25 +1,10 @@ -# 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? -/.vscode +node_modules +/build +/.svelte-kit +/package +.env +.env.* +!.env.example +vite.config.js.timestamp-* +vite.config.ts.timestamp-* diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..13a9c1e --- /dev/null +++ b/.prettierignore @@ -0,0 +1,22 @@ +# Ignore node_modules +node_modules/ + +# Build output +.build/ +.svelte-kit/ +dist/ + +# Ignore lock files +package-lock.json +pnpm-lock.yaml +yarn.lock + +# Ignore environment files +.env +.env.*.local + +# VSCode settings +.vscode/ + +# Ignore output from lint or test tools +coverage/ diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..91d4d7c --- /dev/null +++ b/.prettierrc @@ -0,0 +1,10 @@ +{ + "singleQuote": true, + "useTabs": false, + "tabWidth": 2, + "trailingComma": "all", + "printWidth": 80, + "semi": true, + "bracketSpacing": true, + "arrowParens": "always" +} diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 4fba23b..0000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2022 Leonardo Murça - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/README.md b/README.md index 50904b3..b5b2950 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,38 @@ -# Embroidery Viewer +# sv -A free online tool to view embroidery files. -Available at https://embroideryviewer.xyz. +Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli). -![Demo](/demo.gif) +## Creating a project -Current supported formats: **.pes, .dst, .pec, .jef and .exp**. +If you're seeing this, you've probably already done this step. Congrats! -Inspired by https://github.com/redteam316/html5-embroidery.git. +```bash +# create a new project in the current directory +npx sv create + +# create a new project in my-app +npx sv create my-app +``` + +## Developing + +Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: + +```bash +npm run dev + +# or start the server and open the app in a new browser tab +npm run dev -- --open +``` + +## Building + +To create a production version of your app: + +```bash +npm run build +``` + +You can preview the production build with `npm run preview`. + +> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment. diff --git a/demo.gif b/demo.gif deleted file mode 100644 index e90c575..0000000 Binary files a/demo.gif and /dev/null differ diff --git a/ecosystem.config.cjs b/ecosystem.config.cjs new file mode 100644 index 0000000..38a4b89 --- /dev/null +++ b/ecosystem.config.cjs @@ -0,0 +1,34 @@ +module.exports = { + apps: [ + { + name: 'embroidery-viewer', + script: './build/index.js', + time: true, + instances: 1, + autorestart: true, + max_restarts: 50, + watch: false, + max_memory_restart: '1G', + env: { + NODE_ENV: 'production', + }, + }, + ], + deploy: { + production: { + user: 'deployer', + host: '45.76.5.44', + key: 'deploy.key', + ref: 'origin/main', + repo: 'git@git.leomurca.xyz:leomurca/embroidery-viewer.git', + path: '/home/deployer/embroidery-viewer', + 'pre-deploy': 'rm package-lock.json && npm i', + 'post-deploy': + 'npm run build && pm2 reload ecosystem.config.cjs --only acelera-alagoas-prod --env production && pm2 save', + env: { + PORT: 7017, + NODE_ENV: 'production', + }, + }, + }, +}; diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..81b0525 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,26 @@ +import prettier from 'eslint-config-prettier'; +import js from '@eslint/js'; +import { includeIgnoreFile } from '@eslint/compat'; +import svelte from 'eslint-plugin-svelte'; +import globals from 'globals'; +import { fileURLToPath } from 'node:url'; +import svelteConfig from './svelte.config.js'; + +const gitignorePath = fileURLToPath(new URL('./.gitignore', import.meta.url)); + +export default [ + includeIgnoreFile(gitignorePath), + js.configs.recommended, + ...svelte.configs.recommended, + prettier, + ...svelte.configs.prettier, + { + languageOptions: { + globals: { ...globals.browser, ...globals.node } + } + }, + { + files: ['**/*.svelte', '**/*.svelte.js'], + languageOptions: { parserOptions: { svelteConfig } } + } +]; diff --git a/index.html b/index.html deleted file mode 100644 index df63184..0000000 --- a/index.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - -
- - - - \ No newline at end of file diff --git a/jsconfig.json b/jsconfig.json index e596c58..0b2d886 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -1,33 +1,19 @@ { - "compilerOptions": { - "moduleResolution": "Node", - "target": "ESNext", - "module": "ESNext", - /** - * svelte-preprocess cannot figure out whether you have - * a value or a type, so tell TypeScript to enforce using - * `import type` instead of `import` for Types. - */ - "importsNotUsedAsValues": "error", - "isolatedModules": true, - "resolveJsonModule": true, - /** - * To have warnings / errors of the Svelte compiler at the - * correct position, enable source maps by default. - */ - "sourceMap": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable this if you'd like to use dynamic types. - */ - "checkJs": true - }, - /** - * Use global.d.ts instead of compilerOptions.types - * to avoid limiting type declarations. - */ - "include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte"] + "extends": "./.svelte-kit/tsconfig.json", + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "moduleResolution": "bundler" + } + // Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias + // except $lib which is handled by https://svelte.dev/docs/kit/configuration#files + // + // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes + // from the referenced tsconfig.json - TypeScript does not merge them in } diff --git a/package-lock.json b/package-lock.json index 59e799c..ed889ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,23 +1,38 @@ { "name": "embroidery-viewer", - "version": "1.2.5", + "version": "0.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "embroidery-viewer", - "version": "1.2.5", + "version": "0.0.1", + "dependencies": { + "accept-language-parser": "^1.5.0", + "sveltekit-i18n": "^2.4.2" + }, "devDependencies": { - "@sveltejs/vite-plugin-svelte": "^5.0.3", - "svelte": "^5.23.3", - "vite": "^6.2.3" + "@eslint/compat": "^1.2.5", + "@eslint/js": "^9.18.0", + "@sveltejs/adapter-auto": "^6.0.0", + "@sveltejs/kit": "^2.16.0", + "@sveltejs/vite-plugin-svelte": "^5.0.0", + "eslint": "^9.28.0", + "eslint-config-prettier": "^10.0.1", + "eslint-plugin-svelte": "^3.9.1", + "globals": "^16.0.0", + "prettier": "^3.5.3", + "prettier-plugin-svelte": "^3.3.3", + "svelte": "^5.0.0", + "svelte-check": "^4.0.0", + "typescript": "^5.0.0", + "vite": "^6.2.6" } }, "node_modules/@ampproject/remapping": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -28,9 +43,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz", - "integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz", + "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==", "cpu": [ "ppc64" ], @@ -45,9 +60,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz", - "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz", + "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==", "cpu": [ "arm" ], @@ -62,9 +77,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz", - "integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz", + "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==", "cpu": [ "arm64" ], @@ -79,9 +94,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz", - "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz", + "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==", "cpu": [ "x64" ], @@ -96,9 +111,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz", - "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz", + "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==", "cpu": [ "arm64" ], @@ -113,9 +128,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz", - "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz", + "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==", "cpu": [ "x64" ], @@ -130,9 +145,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz", - "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz", + "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==", "cpu": [ "arm64" ], @@ -147,9 +162,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz", - "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz", + "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==", "cpu": [ "x64" ], @@ -164,9 +179,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz", - "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz", + "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==", "cpu": [ "arm" ], @@ -181,9 +196,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz", - "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz", + "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==", "cpu": [ "arm64" ], @@ -198,9 +213,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz", - "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz", + "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==", "cpu": [ "ia32" ], @@ -215,9 +230,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz", - "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz", + "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==", "cpu": [ "loong64" ], @@ -232,9 +247,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz", - "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz", + "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==", "cpu": [ "mips64el" ], @@ -249,9 +264,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz", - "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz", + "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==", "cpu": [ "ppc64" ], @@ -266,9 +281,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz", - "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz", + "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==", "cpu": [ "riscv64" ], @@ -283,9 +298,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz", - "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz", + "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==", "cpu": [ "s390x" ], @@ -300,9 +315,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz", - "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz", + "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==", "cpu": [ "x64" ], @@ -317,9 +332,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz", - "integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz", + "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==", "cpu": [ "arm64" ], @@ -334,9 +349,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz", - "integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz", + "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==", "cpu": [ "x64" ], @@ -351,9 +366,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz", - "integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz", + "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==", "cpu": [ "arm64" ], @@ -368,9 +383,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz", - "integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz", + "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==", "cpu": [ "x64" ], @@ -385,9 +400,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz", - "integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz", + "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==", "cpu": [ "x64" ], @@ -402,9 +417,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz", - "integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz", + "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==", "cpu": [ "arm64" ], @@ -419,9 +434,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz", - "integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz", + "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==", "cpu": [ "ia32" ], @@ -436,9 +451,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz", - "integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz", + "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==", "cpu": [ "x64" ], @@ -452,11 +467,248 @@ "node": ">=18" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/compat": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.2.9.tgz", + "integrity": "sha512-gCdSY54n7k+driCadyMNv8JSPzYLeDVM/ikZRtvtROBpRdFSkS8W9A82MqsaY7lZuwL0wiapgD0NT1xT0hyJsA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": "^9.10.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/config-array": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz", + "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.2.tgz", + "integrity": "sha512-+GPzk8PlG0sPpzdU5ZvIRMPidzAnZDl/s9L+y13iodqvb8leL53bTannOrQ/Im7UkpsmFU5Ily5U60LWixnmLg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz", + "integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.28.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.28.0.tgz", + "integrity": "sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.1.tgz", + "integrity": "sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.14.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", @@ -471,7 +723,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -481,7 +732,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -491,24 +741,29 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true, + "license": "MIT" + }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.38.0.tgz", - "integrity": "sha512-ldomqc4/jDZu/xpYU+aRxo3V4mGCV9HeTgUBANI3oIQMOL+SsxB+S2lxMpkFp5UamSS3XuTMQVbsS24R4J4Qjg==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.1.tgz", + "integrity": "sha512-NELNvyEWZ6R9QMkiytB4/L4zSEaBC03KIXEghptLGLZWJ6VPrL63ooZQCOnlx36aQPGhzuOMwDerC1Eb2VmrLw==", "cpu": [ "arm" ], @@ -520,9 +775,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.38.0.tgz", - "integrity": "sha512-VUsgcy4GhhT7rokwzYQP+aV9XnSLkkhlEJ0St8pbasuWO/vwphhZQxYEKUP3ayeCYLhk6gEtacRpYP/cj3GjyQ==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.41.1.tgz", + "integrity": "sha512-DXdQe1BJ6TK47ukAoZLehRHhfKnKg9BjnQYUu9gzhI8Mwa1d2fzxA1aw2JixHVl403bwp1+/o/NhhHtxWJBgEA==", "cpu": [ "arm64" ], @@ -534,9 +789,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.38.0.tgz", - "integrity": "sha512-buA17AYXlW9Rn091sWMq1xGUvWQFOH4N1rqUxGJtEQzhChxWjldGCCup7r/wUnaI6Au8sKXpoh0xg58a7cgcpg==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.1.tgz", + "integrity": "sha512-5afxvwszzdulsU2w8JKWwY8/sJOLPzf0e1bFuvcW5h9zsEg+RQAojdW0ux2zyYAz7R8HvvzKCjLNJhVq965U7w==", "cpu": [ "arm64" ], @@ -548,9 +803,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.38.0.tgz", - "integrity": "sha512-Mgcmc78AjunP1SKXl624vVBOF2bzwNWFPMP4fpOu05vS0amnLcX8gHIge7q/lDAHy3T2HeR0TqrriZDQS2Woeg==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.41.1.tgz", + "integrity": "sha512-egpJACny8QOdHNNMZKf8xY0Is6gIMz+tuqXlusxquWu3F833DcMwmGM7WlvCO9sB3OsPjdC4U0wHw5FabzCGZg==", "cpu": [ "x64" ], @@ -562,9 +817,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.38.0.tgz", - "integrity": "sha512-zzJACgjLbQTsscxWqvrEQAEh28hqhebpRz5q/uUd1T7VTwUNZ4VIXQt5hE7ncs0GrF+s7d3S4on4TiXUY8KoQA==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.41.1.tgz", + "integrity": "sha512-DBVMZH5vbjgRk3r0OzgjS38z+atlupJ7xfKIDJdZZL6sM6wjfDNo64aowcLPKIx7LMQi8vybB56uh1Ftck/Atg==", "cpu": [ "arm64" ], @@ -576,9 +831,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.38.0.tgz", - "integrity": "sha512-hCY/KAeYMCyDpEE4pTETam0XZS4/5GXzlLgpi5f0IaPExw9kuB+PDTOTLuPtM10TlRG0U9OSmXJ+Wq9J39LvAg==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.41.1.tgz", + "integrity": "sha512-3FkydeohozEskBxNWEIbPfOE0aqQgB6ttTkJ159uWOFn42VLyfAiyD9UK5mhu+ItWzft60DycIN1Xdgiy8o/SA==", "cpu": [ "x64" ], @@ -590,9 +845,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.38.0.tgz", - "integrity": "sha512-mimPH43mHl4JdOTD7bUMFhBdrg6f9HzMTOEnzRmXbOZqjijCw8LA5z8uL6LCjxSa67H2xiLFvvO67PT05PRKGg==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.41.1.tgz", + "integrity": "sha512-wC53ZNDgt0pqx5xCAgNunkTzFE8GTgdZ9EwYGVcg+jEjJdZGtq9xPjDnFgfFozQI/Xm1mh+D9YlYtl+ueswNEg==", "cpu": [ "arm" ], @@ -604,9 +859,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.38.0.tgz", - "integrity": "sha512-tPiJtiOoNuIH8XGG8sWoMMkAMm98PUwlriOFCCbZGc9WCax+GLeVRhmaxjJtz6WxrPKACgrwoZ5ia/uapq3ZVg==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.41.1.tgz", + "integrity": "sha512-jwKCca1gbZkZLhLRtsrka5N8sFAaxrGz/7wRJ8Wwvq3jug7toO21vWlViihG85ei7uJTpzbXZRcORotE+xyrLA==", "cpu": [ "arm" ], @@ -618,9 +873,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.38.0.tgz", - "integrity": "sha512-wZco59rIVuB0tjQS0CSHTTUcEde+pXQWugZVxWaQFdQQ1VYub/sTrNdY76D1MKdN2NB48JDuGABP6o6fqos8mA==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.41.1.tgz", + "integrity": "sha512-g0UBcNknsmmNQ8V2d/zD2P7WWfJKU0F1nu0k5pW4rvdb+BIqMm8ToluW/eeRmxCared5dD76lS04uL4UaNgpNA==", "cpu": [ "arm64" ], @@ -632,9 +887,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.38.0.tgz", - "integrity": "sha512-fQgqwKmW0REM4LomQ+87PP8w8xvU9LZfeLBKybeli+0yHT7VKILINzFEuggvnV9M3x1Ed4gUBmGUzCo/ikmFbQ==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.41.1.tgz", + "integrity": "sha512-XZpeGB5TKEZWzIrj7sXr+BEaSgo/ma/kCgrZgL0oo5qdB1JlTzIYQKel/RmhT6vMAvOdM2teYlAaOGJpJ9lahg==", "cpu": [ "arm64" ], @@ -646,9 +901,9 @@ ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.38.0.tgz", - "integrity": "sha512-hz5oqQLXTB3SbXpfkKHKXLdIp02/w3M+ajp8p4yWOWwQRtHWiEOCKtc9U+YXahrwdk+3qHdFMDWR5k+4dIlddg==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.41.1.tgz", + "integrity": "sha512-bkCfDJ4qzWfFRCNt5RVV4DOw6KEgFTUZi2r2RuYhGWC8WhCA8lCAJhDeAmrM/fdiAH54m0mA0Vk2FGRPyzI+tw==", "cpu": [ "loong64" ], @@ -660,9 +915,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.38.0.tgz", - "integrity": "sha512-NXqygK/dTSibQ+0pzxsL3r4Xl8oPqVoWbZV9niqOnIHV/J92fe65pOir0xjkUZDRSPyFRvu+4YOpJF9BZHQImw==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.41.1.tgz", + "integrity": "sha512-3mr3Xm+gvMX+/8EKogIZSIEF0WUu0HL9di+YWlJpO8CQBnoLAEL/roTCxuLncEdgcfJcvA4UMOf+2dnjl4Ut1A==", "cpu": [ "ppc64" ], @@ -674,9 +929,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.38.0.tgz", - "integrity": "sha512-GEAIabR1uFyvf/jW/5jfu8gjM06/4kZ1W+j1nWTSSB3w6moZEBm7iBtzwQ3a1Pxos2F7Gz+58aVEnZHU295QTg==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.41.1.tgz", + "integrity": "sha512-3rwCIh6MQ1LGrvKJitQjZFuQnT2wxfU+ivhNBzmxXTXPllewOF7JR1s2vMX/tWtUYFgphygxjqMl76q4aMotGw==", "cpu": [ "riscv64" ], @@ -688,9 +943,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.38.0.tgz", - "integrity": "sha512-9EYTX+Gus2EGPbfs+fh7l95wVADtSQyYw4DfSBcYdUEAmP2lqSZY0Y17yX/3m5VKGGJ4UmIH5LHLkMJft3bYoA==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.41.1.tgz", + "integrity": "sha512-LdIUOb3gvfmpkgFZuccNa2uYiqtgZAz3PTzjuM5bH3nvuy9ty6RGc/Q0+HDFrHrizJGVpjnTZ1yS5TNNjFlklw==", "cpu": [ "riscv64" ], @@ -702,9 +957,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.38.0.tgz", - "integrity": "sha512-Mpp6+Z5VhB9VDk7RwZXoG2qMdERm3Jw07RNlXHE0bOnEeX+l7Fy4bg+NxfyN15ruuY3/7Vrbpm75J9QHFqj5+Q==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.1.tgz", + "integrity": "sha512-oIE6M8WC9ma6xYqjvPhzZYk6NbobIURvP/lEbh7FWplcMO6gn7MM2yHKA1eC/GvYwzNKK/1LYgqzdkZ8YFxR8g==", "cpu": [ "s390x" ], @@ -716,9 +971,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.38.0.tgz", - "integrity": "sha512-vPvNgFlZRAgO7rwncMeE0+8c4Hmc+qixnp00/Uv3ht2x7KYrJ6ERVd3/R0nUtlE6/hu7/HiiNHJ/rP6knRFt1w==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.1.tgz", + "integrity": "sha512-cWBOvayNvA+SyeQMp79BHPK8ws6sHSsYnK5zDcsC3Hsxr1dgTABKjMnMslPq1DvZIp6uO7kIWhiGwaTdR4Og9A==", "cpu": [ "x64" ], @@ -730,9 +985,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.38.0.tgz", - "integrity": "sha512-q5Zv+goWvQUGCaL7fU8NuTw8aydIL/C9abAVGCzRReuj5h30TPx4LumBtAidrVOtXnlB+RZkBtExMsfqkMfb8g==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.41.1.tgz", + "integrity": "sha512-y5CbN44M+pUCdGDlZFzGGBSKCA4A/J2ZH4edTYSSxFg7ce1Xt3GtydbVKWLlzL+INfFIZAEg1ZV6hh9+QQf9YQ==", "cpu": [ "x64" ], @@ -744,9 +999,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.38.0.tgz", - "integrity": "sha512-u/Jbm1BU89Vftqyqbmxdq14nBaQjQX1HhmsdBWqSdGClNaKwhjsg5TpW+5Ibs1mb8Es9wJiMdl86BcmtUVXNZg==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.1.tgz", + "integrity": "sha512-lZkCxIrjlJlMt1dLO/FbpZbzt6J/A8p4DnqzSa4PWqPEUUUnzXLeki/iyPLfV0BmHItlYgHUqJe+3KiyydmiNQ==", "cpu": [ "arm64" ], @@ -758,9 +1013,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.38.0.tgz", - "integrity": "sha512-mqu4PzTrlpNHHbu5qleGvXJoGgHpChBlrBx/mEhTPpnAL1ZAYFlvHD7rLK839LLKQzqEQMFJfGrrOHItN4ZQqA==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.1.tgz", + "integrity": "sha512-+psFT9+pIh2iuGsxFYYa/LhS5MFKmuivRsx9iPJWNSGbh2XVEjk90fmpUEjCnILPEPJnikAU6SFDiEUyOv90Pg==", "cpu": [ "ia32" ], @@ -772,9 +1027,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.38.0.tgz", - "integrity": "sha512-jjqy3uWlecfB98Psxb5cD6Fny9Fupv9LrDSPTQZUROqjvZmcCqNu4UMl7qqhlUUGpwiAkotj6GYu4SZdcr/nLw==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.1.tgz", + "integrity": "sha512-Wq2zpapRYLfi4aKxf2Xff0tN+7slj2d4R87WEzqw7ZLsVvO5zwYCIuEGSZYiK41+GlwUo1HiR+GdkLEJnCKTCw==", "cpu": [ "x64" ], @@ -789,12 +1044,53 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.5.tgz", "integrity": "sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==", - "dev": true, "license": "MIT", "peerDependencies": { "acorn": "^8.9.0" } }, + "node_modules/@sveltejs/adapter-auto": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-6.0.1.tgz", + "integrity": "sha512-mcWud3pYGPWM2Pphdj8G9Qiq24nZ8L4LB7coCUckUEy5Y7wOWGJ/enaZ4AtJTcSm5dNK1rIkBRoqt+ae4zlxcQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@sveltejs/kit": "^2.0.0" + } + }, + "node_modules/@sveltejs/kit": { + "version": "2.21.1", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.21.1.tgz", + "integrity": "sha512-vLbtVwtDcK8LhJKnFkFYwM0uCdFmzioQnif0bjEYH1I24Arz22JPr/hLUiXGVYAwhu8INKx5qrdvr4tHgPwX6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sveltejs/acorn-typescript": "^1.0.5", + "@types/cookie": "^0.6.0", + "acorn": "^8.14.1", + "cookie": "^0.6.0", + "devalue": "^5.1.0", + "esm-env": "^1.2.2", + "kleur": "^4.1.5", + "magic-string": "^0.30.5", + "mrmime": "^2.0.0", + "sade": "^1.8.1", + "set-cookie-parser": "^2.6.0", + "sirv": "^3.0.0" + }, + "bin": { + "svelte-kit": "svelte-kit.js" + }, + "engines": { + "node": ">=18.13" + }, + "peerDependencies": { + "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0", + "svelte": "^4.0.0 || ^5.0.0-next.0", + "vite": "^5.0.3 || ^6.0.0" + } + }, "node_modules/@sveltejs/vite-plugin-svelte": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-5.0.3.tgz", @@ -835,18 +1131,51 @@ "vite": "^6.0.0" } }, + "node_modules/@sveltekit-i18n/base": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/@sveltekit-i18n/base/-/base-1.3.7.tgz", + "integrity": "sha512-kg1kql1/ro/lIudwFiWrv949Q07gmweln87tflUZR51MNdXXzK4fiJQv5Mw50K/CdQ5BOk/dJ0WOH2vOtBI6yw==", + "license": "MIT", + "peerDependencies": { + "svelte": ">=3.49.0" + } + }, + "node_modules/@sveltekit-i18n/parser-default": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@sveltekit-i18n/parser-default/-/parser-default-1.1.1.tgz", + "integrity": "sha512-/gtzLlqm/sox7EoPKD56BxGZktK/syGc79EbJAPWY5KVitQD9SM0TP8yJCqDxTVPk7Lk0WJhrBGUE2Nn0f5M1w==", + "license": "MIT" + }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true, "license": "MIT" }, + "node_modules/accept-language-parser": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/accept-language-parser/-/accept-language-parser-1.5.0.tgz", + "integrity": "sha512-QhyTbMLYo0BBGg1aWbeMG4ekWtds/31BrEU+DONOg/7ax23vxpL03Pb7/zBmha2v7vdD3AyzZVWBVGEZxKOXWw==", + "license": "MIT" + }, "node_modules/acorn": { "version": "8.14.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", - "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -855,11 +1184,60 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, "node_modules/aria-query": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">= 0.4" @@ -869,26 +1247,150 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">= 0.4" } }, - "node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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, "license": "MIT", "engines": { "node": ">=6" } }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "dev": true, "license": "MIT", "dependencies": { @@ -903,6 +1405,13 @@ } } }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -913,10 +1422,17 @@ "node": ">=0.10.0" } }, + "node_modules/devalue": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.1.1.tgz", + "integrity": "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==", + "dev": true, + "license": "MIT" + }, "node_modules/esbuild": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz", - "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz", + "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -927,50 +1443,353 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.1", - "@esbuild/android-arm": "0.25.1", - "@esbuild/android-arm64": "0.25.1", - "@esbuild/android-x64": "0.25.1", - "@esbuild/darwin-arm64": "0.25.1", - "@esbuild/darwin-x64": "0.25.1", - "@esbuild/freebsd-arm64": "0.25.1", - "@esbuild/freebsd-x64": "0.25.1", - "@esbuild/linux-arm": "0.25.1", - "@esbuild/linux-arm64": "0.25.1", - "@esbuild/linux-ia32": "0.25.1", - "@esbuild/linux-loong64": "0.25.1", - "@esbuild/linux-mips64el": "0.25.1", - "@esbuild/linux-ppc64": "0.25.1", - "@esbuild/linux-riscv64": "0.25.1", - "@esbuild/linux-s390x": "0.25.1", - "@esbuild/linux-x64": "0.25.1", - "@esbuild/netbsd-arm64": "0.25.1", - "@esbuild/netbsd-x64": "0.25.1", - "@esbuild/openbsd-arm64": "0.25.1", - "@esbuild/openbsd-x64": "0.25.1", - "@esbuild/sunos-x64": "0.25.1", - "@esbuild/win32-arm64": "0.25.1", - "@esbuild/win32-ia32": "0.25.1", - "@esbuild/win32-x64": "0.25.1" + "@esbuild/aix-ppc64": "0.25.5", + "@esbuild/android-arm": "0.25.5", + "@esbuild/android-arm64": "0.25.5", + "@esbuild/android-x64": "0.25.5", + "@esbuild/darwin-arm64": "0.25.5", + "@esbuild/darwin-x64": "0.25.5", + "@esbuild/freebsd-arm64": "0.25.5", + "@esbuild/freebsd-x64": "0.25.5", + "@esbuild/linux-arm": "0.25.5", + "@esbuild/linux-arm64": "0.25.5", + "@esbuild/linux-ia32": "0.25.5", + "@esbuild/linux-loong64": "0.25.5", + "@esbuild/linux-mips64el": "0.25.5", + "@esbuild/linux-ppc64": "0.25.5", + "@esbuild/linux-riscv64": "0.25.5", + "@esbuild/linux-s390x": "0.25.5", + "@esbuild/linux-x64": "0.25.5", + "@esbuild/netbsd-arm64": "0.25.5", + "@esbuild/netbsd-x64": "0.25.5", + "@esbuild/openbsd-arm64": "0.25.5", + "@esbuild/openbsd-x64": "0.25.5", + "@esbuild/sunos-x64": "0.25.5", + "@esbuild/win32-arm64": "0.25.5", + "@esbuild/win32-ia32": "0.25.5", + "@esbuild/win32-x64": "0.25.5" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.28.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.28.0.tgz", + "integrity": "sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.20.0", + "@eslint/config-helpers": "^0.2.1", + "@eslint/core": "^0.14.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.28.0", + "@eslint/plugin-kit": "^0.3.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.3.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-prettier": { + "version": "10.1.5", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.5.tgz", + "integrity": "sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-svelte": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-3.9.1.tgz", + "integrity": "sha512-mXFulSdD/0/p+zwENjPNsiVwAqmSRp90sy5zvVQBX1yAXhJbdhIn6C/tn8BZYjU94Ia7Y87d1Xdbvi49DeWyHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.6.1", + "@jridgewell/sourcemap-codec": "^1.5.0", + "esutils": "^2.0.3", + "globals": "^16.0.0", + "known-css-properties": "^0.36.0", + "postcss": "^8.4.49", + "postcss-load-config": "^3.1.4", + "postcss-safe-parser": "^7.0.0", + "semver": "^7.6.3", + "svelte-eslint-parser": "^1.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "eslint": "^8.57.1 || ^9.0.0", + "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "svelte": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", + "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/esm-env": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", - "dev": true, "license": "MIT" }, - "node_modules/esrap": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/esrap/-/esrap-1.4.5.tgz", - "integrity": "sha512-CjNMjkBWWZeHn+VX+gS8YvFwJ5+NDhg8aWZBSFJPR8qQduDNjbJodA2WcwCm7uQa5Rjqj+nZvVmceg1RbHFB9g==", + "node_modules/espree": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.14.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrap": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/esrap/-/esrap-1.4.6.tgz", + "integrity": "sha512-F/D2mADJ9SHY3IwksD4DAXjTt7qt7GWUf3/8RhCNWmC/67tyb55dpimHmy7EplakFaflV0R/PC+fdSPqrRHAQw==", "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" } }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.5.tgz", + "integrity": "sha512-4BG7puHpVsIYxZUbiUE3RqGloLaSSwzYie5jvasC4LWuBWzZawynvYouhjbQKw2JuIGYdm0DzIxl8iVidKlUEw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -986,16 +1805,162 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.2.0.tgz", + "integrity": "sha512-O+7l9tPdHCU320IigZZPj5zmRCFG9xHmx9cU8FqU2Rp+JN714seHV+2S9+JslCpY4gJwU2vOGox0wzgae/MCEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-reference": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", - "dev": true, "license": "MIT", "dependencies": { "@types/estree": "^1.0.6" } }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/kleur": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", @@ -1006,10 +1971,63 @@ "node": ">=6" } }, + "node_modules/known-css-properties": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.36.0.tgz", + "integrity": "sha512-A+9jP+IUmuQsNdsLdcg6Yt7voiMF/D4K83ew0OpJtpu+l34ef7LaohWV0Rc6KNvzw6ZDizkqfyB5JznZnzuKQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "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==", + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true, "license": "MIT" }, @@ -1017,12 +2035,44 @@ "version": "0.30.17", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, + "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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -1049,6 +2099,96 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -1056,10 +2196,23 @@ "dev": true, "license": "ISC" }, + "node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/postcss": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", - "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.4.tgz", + "integrity": "sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==", "dev": true, "funding": [ { @@ -1077,7 +2230,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.8", + "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -1085,10 +2238,189 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-load-config": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", + "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lilconfig": "^2.0.5", + "yaml": "^1.10.2" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-load-config/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss-safe-parser": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz", + "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-scss": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.9.tgz", + "integrity": "sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-scss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.4.29" + } + }, + "node_modules/postcss-selector-parser": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-plugin-svelte": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.4.0.tgz", + "integrity": "sha512-pn1ra/0mPObzqoIQn/vUTR3ZZI6UuZ0sHqMK5x2jMLGrs53h0sXhkVuDcrlssHwIMk7FYrMjHBPoUSyyEEDlBQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "prettier": "^3.0.0", + "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/rollup": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.38.0.tgz", - "integrity": "sha512-5SsIRtJy9bf1ErAOiFMFzl64Ex9X5V7bnJ+WlFMb+zmP459OSWCEG7b0ERZ+PEU7xPt4OG3RHbrp1LJlXxYTrw==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.41.1.tgz", + "integrity": "sha512-cPmwD3FnFv8rKMBc1MxWCwVQFxwf1JEmSX3iQXrRVVG15zerAIXRjMFVWnd5Q5QvgKF7Aj+5ykXFhUl+QGnyOw==", "dev": true, "license": "MIT", "dependencies": { @@ -1102,29 +2434,100 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.38.0", - "@rollup/rollup-android-arm64": "4.38.0", - "@rollup/rollup-darwin-arm64": "4.38.0", - "@rollup/rollup-darwin-x64": "4.38.0", - "@rollup/rollup-freebsd-arm64": "4.38.0", - "@rollup/rollup-freebsd-x64": "4.38.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.38.0", - "@rollup/rollup-linux-arm-musleabihf": "4.38.0", - "@rollup/rollup-linux-arm64-gnu": "4.38.0", - "@rollup/rollup-linux-arm64-musl": "4.38.0", - "@rollup/rollup-linux-loongarch64-gnu": "4.38.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.38.0", - "@rollup/rollup-linux-riscv64-gnu": "4.38.0", - "@rollup/rollup-linux-riscv64-musl": "4.38.0", - "@rollup/rollup-linux-s390x-gnu": "4.38.0", - "@rollup/rollup-linux-x64-gnu": "4.38.0", - "@rollup/rollup-linux-x64-musl": "4.38.0", - "@rollup/rollup-win32-arm64-msvc": "4.38.0", - "@rollup/rollup-win32-ia32-msvc": "4.38.0", - "@rollup/rollup-win32-x64-msvc": "4.38.0", + "@rollup/rollup-android-arm-eabi": "4.41.1", + "@rollup/rollup-android-arm64": "4.41.1", + "@rollup/rollup-darwin-arm64": "4.41.1", + "@rollup/rollup-darwin-x64": "4.41.1", + "@rollup/rollup-freebsd-arm64": "4.41.1", + "@rollup/rollup-freebsd-x64": "4.41.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.41.1", + "@rollup/rollup-linux-arm-musleabihf": "4.41.1", + "@rollup/rollup-linux-arm64-gnu": "4.41.1", + "@rollup/rollup-linux-arm64-musl": "4.41.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.41.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.41.1", + "@rollup/rollup-linux-riscv64-gnu": "4.41.1", + "@rollup/rollup-linux-riscv64-musl": "4.41.1", + "@rollup/rollup-linux-s390x-gnu": "4.41.1", + "@rollup/rollup-linux-x64-gnu": "4.41.1", + "@rollup/rollup-linux-x64-musl": "4.41.1", + "@rollup/rollup-win32-arm64-msvc": "4.41.1", + "@rollup/rollup-win32-ia32-msvc": "4.41.1", + "@rollup/rollup-win32-x64-msvc": "4.41.1", "fsevents": "~2.3.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, + "license": "MIT", + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/sirv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.1.tgz", + "integrity": "sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -1135,12 +2538,37 @@ "node": ">=0.10.0" } }, - "node_modules/svelte": { - "version": "5.25.3", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.25.3.tgz", - "integrity": "sha512-J9rcZ/xVJonAoESqVGHHZhrNdVbrCfkdB41BP6eiwHMoFShD9it3yZXApVYMHdGfCshBsZCKsajwJeBbS/M1zg==", + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/svelte": { + "version": "5.33.13", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.33.13.tgz", + "integrity": "sha512-uT3BAPpHGaJqpOgdwJwIK7P4JkBkSS0vylbaRXxQjt1gr+DZ9BiPkhmbZw3ql8LJofUyz5XyrzzQDgQQdfP86Q==", + "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.3.0", "@jridgewell/sourcemap-codec": "^1.5.0", @@ -1151,7 +2579,7 @@ "axobject-query": "^4.1.0", "clsx": "^2.1.1", "esm-env": "^1.2.1", - "esrap": "^1.4.3", + "esrap": "^1.4.6", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", @@ -1161,16 +2589,159 @@ "node": ">=18" } }, + "node_modules/svelte-check": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.2.1.tgz", + "integrity": "sha512-e49SU1RStvQhoipkQ/aonDhHnG3qxHSBtNfBRb9pxVXoa+N7qybAo32KgA9wEb2PCYFNaDg7bZCdhLD1vHpdYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "chokidar": "^4.0.1", + "fdir": "^6.2.0", + "picocolors": "^1.0.0", + "sade": "^1.7.4" + }, + "bin": { + "svelte-check": "bin/svelte-check" + }, + "engines": { + "node": ">= 18.0.0" + }, + "peerDependencies": { + "svelte": "^4.0.0 || ^5.0.0-next.0", + "typescript": ">=5.0.0" + } + }, + "node_modules/svelte-eslint-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-1.2.0.tgz", + "integrity": "sha512-mbPtajIeuiyU80BEyGvwAktBeTX7KCr5/0l+uRGLq1dafwRNrjfM5kHGJScEBlPG3ipu6dJqfW/k0/fujvIEVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.0.0", + "postcss": "^8.4.49", + "postcss-scss": "^4.0.9", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "svelte": { + "optional": true + } + } + }, + "node_modules/sveltekit-i18n": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/sveltekit-i18n/-/sveltekit-i18n-2.4.2.tgz", + "integrity": "sha512-hjRWn4V4DBL8JQKJoJa3MRvn6d32Zo+rWkoSP5bsQ/XIAguPdQUZJ8LMe6Nc1rST8WEVdu9+vZI3aFdKYGR3+Q==", + "license": "MIT", + "workspaces": [ + "./examples/*/" + ], + "dependencies": { + "@sveltekit-i18n/base": "~1.3.0", + "@sveltekit-i18n/parser-default": "~1.1.0" + }, + "peerDependencies": { + "svelte": ">=3.49.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, "node_modules/vite": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.3.tgz", - "integrity": "sha512-IzwM54g4y9JA/xAeBPNaDXiBF8Jsgl3VBQ2YQ/wOY6fyW3xMdSoltIV3Bo59DErdqdE6RxUfv8W69DvUorE4Eg==", + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", + "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", "dev": true, "license": "MIT", "dependencies": { "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", "postcss": "^8.5.3", - "rollup": "^4.30.1" + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" }, "bin": { "vite": "bin/vite.js" @@ -1252,11 +2823,64 @@ } } }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yaml": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", + "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", + "dev": true, + "license": "ISC", + "optional": true, + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/zimmerframe": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.2.tgz", "integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==", - "dev": true, "license": "MIT" } } diff --git a/package.json b/package.json index 43dc5d5..7e54a73 100644 --- a/package.json +++ b/package.json @@ -1,17 +1,37 @@ { "name": "embroidery-viewer", "private": true, - "version": "2.0.3", + "version": "0.0.1", "type": "module", "scripts": { - "dev": "vite", + "dev": "vite dev", "build": "vite build", "preview": "vite preview", - "postbuild": "npx svelte-sitemap --domain https://embroideryviewer.xyz -o dist" + "prepare": "svelte-kit sync || echo ''", + "check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --watch", + "format": "prettier --write .", + "lint": "prettier --check . && eslint ." }, "devDependencies": { - "@sveltejs/vite-plugin-svelte": "^5.0.3", - "svelte": "^5.23.3", - "vite": "^6.2.3" + "@eslint/compat": "^1.2.5", + "@eslint/js": "^9.18.0", + "@sveltejs/adapter-auto": "^6.0.0", + "@sveltejs/kit": "^2.16.0", + "@sveltejs/vite-plugin-svelte": "^5.0.0", + "eslint": "^9.28.0", + "eslint-config-prettier": "^10.0.1", + "eslint-plugin-svelte": "^3.9.1", + "globals": "^16.0.0", + "prettier": "^3.5.3", + "prettier-plugin-svelte": "^3.3.3", + "svelte": "^5.0.0", + "svelte-check": "^4.0.0", + "typescript": "^5.0.0", + "vite": "^6.2.6" + }, + "dependencies": { + "accept-language-parser": "^1.5.0", + "sveltekit-i18n": "^2.4.2" } } diff --git a/public/ads.txt b/public/ads.txt deleted file mode 100644 index 48c2eb0..0000000 --- a/public/ads.txt +++ /dev/null @@ -1 +0,0 @@ -google.com, pub-5761689301112420, DIRECT, f08c47fec0942fa0 \ No newline at end of file diff --git a/src/App.svelte b/src/App.svelte deleted file mode 100644 index 352f62d..0000000 --- a/src/App.svelte +++ /dev/null @@ -1,11 +0,0 @@ - - - -
-
-
- \ No newline at end of file + diff --git a/src/lib/MediaQuery.svelte b/src/lib/components/MediaQuery.svelte similarity index 75% rename from src/lib/MediaQuery.svelte rename to src/lib/components/MediaQuery.svelte index cfd20ec..7e64d7b 100644 --- a/src/lib/MediaQuery.svelte +++ b/src/lib/components/MediaQuery.svelte @@ -1,9 +1,15 @@ - - diff --git a/src/lib/components/Seo.svelte b/src/lib/components/Seo.svelte new file mode 100644 index 0000000..1aa2d6d --- /dev/null +++ b/src/lib/components/Seo.svelte @@ -0,0 +1,61 @@ + + + + {$t(title)} + + + + + + + + + + + + + + + + diff --git a/src/lib/file-renderer/index.js b/src/lib/file-renderer/index.js new file mode 100644 index 0000000..6f201b1 --- /dev/null +++ b/src/lib/file-renderer/index.js @@ -0,0 +1,141 @@ +import { supportedFormats } from '$lib/format-readers'; +import { jDataView } from './jdataview'; +import { Pattern } from './pattern'; + +/** + * Render the embroidery pattern file to the provided canvas and update views. + * @param {string} filename - The name of the file. + * @param {ProgressEvent} evt - The file load event. + * @param {HTMLCanvasElement} canvas - Canvas to render the pattern. + * @param {HTMLElement} colorView - Element to display colors. + * @param {HTMLElement} stitchesView - Element to display stitch count. + * @param {HTMLElement} sizeView - Element to display size. + * @param {{stitches: string, dimensions: string}} localizedStrings - Localized labels. + */ +function renderFile( + filename, + evt, + canvas, + colorView, + stitchesView, + sizeView, + localizedStrings, +) { + const fileExtension = filename.toLowerCase().split('.').pop(); + const arrayBuffer = evt.target?.result; + + if (!(fileExtension && arrayBuffer)) { + throw new Error('Invalid file extension or file data'); + } + + const view = new jDataView(arrayBuffer, 0, evt.total || 0); + const pattern = new Pattern(); + + const formatReader = supportedFormats[fileExtension]; + if (!formatReader || typeof formatReader.read !== 'function') { + throw new Error(`Unsupported file format: ${fileExtension}`); + } + + // @ts-ignore + formatReader.read(view, pattern); + + pattern.moveToPositive(); + pattern.drawShapeTo(canvas); + pattern.drawColorsTo(colorView); + pattern.drawStitchesCountTo(stitchesView, localizedStrings.stitches); + pattern.drawSizeValuesTo(sizeView, localizedStrings.dimensions); +} + +/** + * Display a generic abort message. + * @param {HTMLElement} errorMessageRef - Element to display the message. + */ +function renderAbortMessage(errorMessageRef) { + errorMessageRef.textContent = 'Render aborted!'; +} + +/** + * Display a detailed error message based on error type. + * @param {string} errorName - The name of the error. + * @param {HTMLElement} errorMessageRef - Element to display the message. + */ +function renderErrorMessage(errorName, errorMessageRef) { + /** @type {string} */ + let message; + + switch (errorName) { + case 'NotFoundError': + message = + 'The file could not be found at the time the read was processed.'; + break; + case 'SecurityError': + message = + '

A file security error occurred. This can be due to:

' + + ''; + break; + case 'NotReadableError': + message = + 'The file cannot be read. This can occur if the file is open in another application.'; + break; + case 'EncodingError': + message = 'The length of the data URL for the file is too long.'; + break; + default: + message = 'Something went wrong!'; + break; + } + + errorMessageRef.innerHTML = message; +} + +/** + * Read a file and render its pattern to canvas with error handling. + * @param {File} fileObject - The file to read. + * @param {HTMLCanvasElement} canvas - The canvas to render on. + * @param {HTMLElement} errorMessageRef - Element to show error messages. + * @param {HTMLElement} colorView - Element to display colors. + * @param {HTMLElement} stitchesView - Element to display stitch count. + * @param {HTMLElement} sizeView - Element to display size. + * @param {{stitches: string, dimensions: string}} localizedStrings - Localized strings. + * @returns {string} Empty string after starting file read. + */ +export default function renderFileToCanvas( + fileObject, + canvas, + errorMessageRef, + colorView, + stitchesView, + sizeView, + localizedStrings, +) { + const reader = new FileReader(); + + reader.onloadend = (evt) => + renderFile( + fileObject.name, + evt, + canvas, + colorView, + stitchesView, + sizeView, + localizedStrings, + ); + + reader.onabort = () => renderAbortMessage(errorMessageRef); + reader.onerror = (evt) => + renderErrorMessage( + // @ts-ignore + evt.target.error?.name || 'UnknownError', + errorMessageRef, + ); + + if (fileObject) { + reader.readAsArrayBuffer(fileObject); + } + + return ''; +} diff --git a/src/file-renderer/jdataview.js b/src/lib/file-renderer/jdataview.js similarity index 87% rename from src/file-renderer/jdataview.js rename to src/lib/file-renderer/jdataview.js index cba667a..e1c68f4 100644 --- a/src/file-renderer/jdataview.js +++ b/src/lib/file-renderer/jdataview.js @@ -1,5 +1,7 @@ +/* eslint-disable no-unused-vars */ +/* eslint-disable no-undef */ // @ts-nocheck -// +import { browser } from '$app/environment'; // jDataView by Vjeux - Jan 2010 // Continued by RReverser - Feb 2013 // @@ -9,22 +11,22 @@ var compatibility = { // NodeJS Buffer in v0.5.5 and newer - NodeBuffer: "Buffer" in globalThis && "readInt16LE" in Buffer.prototype, + NodeBuffer: 'Buffer' in globalThis && 'readInt16LE' in Buffer.prototype, DataView: - "DataView" in globalThis && - ("getFloat64" in DataView.prototype || // Chrome - "getFloat64" in new DataView(new ArrayBuffer(1))), // Node - ArrayBuffer: "ArrayBuffer" in globalThis, + 'DataView' in globalThis && + ('getFloat64' in DataView.prototype || // Chrome + 'getFloat64' in new DataView(new ArrayBuffer(1))), // Node + ArrayBuffer: 'ArrayBuffer' in globalThis, PixelData: - "CanvasPixelArray" in globalThis && - "ImageData" in globalThis && - "document" in globalThis, + 'CanvasPixelArray' in globalThis && + 'ImageData' in globalThis && + 'document' in globalThis, }; var createPixelData = function (byteLength, buffer) { var data = createPixelData.context2d.createImageData( (byteLength + 3) / 4, - 1 + 1, ).data; data.byteLength = byteLength; if (buffer !== undefined) { @@ -34,7 +36,8 @@ var createPixelData = function (byteLength, buffer) { } return data; }; -createPixelData.context2d = document.createElement("canvas").getContext("2d"); +createPixelData.context2d = + browser ?? document.createElement('canvas').getContext('2d'); var dataTypes = { Int8: 1, @@ -48,14 +51,14 @@ var dataTypes = { }; var nodeNaming = { - Int8: "Int8", - Int16: "Int16", - Int32: "Int32", - Uint8: "UInt8", - Uint16: "UInt16", - Uint32: "UInt32", - Float32: "Float", - Float64: "Double", + Int8: 'Int8', + Int16: 'Int16', + Int32: 'Int32', + Uint8: 'UInt8', + Uint16: 'UInt16', + Uint32: 'UInt32', + Float32: 'Float', + Float64: 'Double', }; function arrayFrom(arrayLike, forceCopy) { @@ -98,13 +101,13 @@ export function jDataView(buffer, byteOffset, byteLength, littleEndian) { !this._isPixelData && !(buffer instanceof Array) ) { - throw new TypeError("jDataView buffer has an incompatible type"); + throw new TypeError('jDataView buffer has an incompatible type'); } // Default Values this._littleEndian = !!littleEndian; - var bufferLength = "byteLength" in buffer ? buffer.byteLength : buffer.length; + var bufferLength = 'byteLength' in buffer ? buffer.byteLength : buffer.length; this.byteOffset = byteOffset = defined(byteOffset, 0); this.byteLength = byteLength = defined(byteLength, bufferLength - byteOffset); @@ -119,15 +122,15 @@ export function jDataView(buffer, byteOffset, byteLength, littleEndian) { this._engineAction = this._isDataView ? this._dataViewAction : this._isNodeBuffer - ? this._nodeBufferAction - : this._isArrayBuffer - ? this._arrayBufferAction - : this._arrayAction; + ? this._nodeBufferAction + : this._isArrayBuffer + ? this._arrayBufferAction + : this._arrayAction; } function getCharCodes(string) { if (compatibility.NodeBuffer) { - return new Buffer(string, "binary"); + return new Buffer(string, 'binary'); } var Type = compatibility.ArrayBuffer ? Uint8Array : Array, @@ -142,7 +145,7 @@ function getCharCodes(string) { // mostly internal function for wrapping any supported input (String or Array-like) to best suitable buffer format jDataView.wrapBuffer = function (buffer) { switch (typeof buffer) { - case "number": + case 'number': if (compatibility.NodeBuffer) { buffer = new Buffer(buffer); buffer.fill(0); @@ -158,12 +161,12 @@ jDataView.wrapBuffer = function (buffer) { } return buffer; - case "string": + case 'string': buffer = getCharCodes(buffer); /* falls through */ default: if ( - "length" in buffer && + 'length' in buffer && !( (compatibility.NodeBuffer && buffer instanceof Buffer) || (compatibility.ArrayBuffer && buffer instanceof ArrayBuffer) || @@ -230,7 +233,7 @@ function Int64(lo, hi) { jDataView.Int64 = Int64; Int64.prototype = - "create" in Object ? Object.create(Uint64.prototype) : new Uint64(); + 'create' in Object ? Object.create(Uint64.prototype) : new Uint64(); Int64.prototype.valueOf = function () { if (this.hi < pow2(31)) { @@ -261,20 +264,20 @@ jDataView.prototype = { _checkBounds: function (byteOffset, byteLength, maxLength) { // Do additional checks to simulate DataView - if (typeof byteOffset !== "number") { - throw new TypeError("Offset is not a number."); + if (typeof byteOffset !== 'number') { + throw new TypeError('Offset is not a number.'); } - if (typeof byteLength !== "number") { - throw new TypeError("Size is not a number."); + if (typeof byteLength !== 'number') { + throw new TypeError('Size is not a number.'); } if (byteLength < 0) { - throw new RangeError("Length is negative."); + throw new RangeError('Length is negative.'); } if ( byteOffset < 0 || byteOffset + byteLength > defined(maxLength, this.byteLength) ) { - throw new RangeError("Offsets are out of bounds."); + throw new RangeError('Offsets are out of bounds.'); } }, @@ -284,7 +287,7 @@ jDataView.prototype = { isReadAction, defined(byteOffset, this._offset), defined(littleEndian, this._littleEndian), - value + value, ); }, @@ -293,13 +296,13 @@ jDataView.prototype = { isReadAction, byteOffset, littleEndian, - value + value, ) { // Move the internal offset forward this._offset = byteOffset + dataTypes[type]; return isReadAction - ? this._view["get" + type](byteOffset, littleEndian) - : this._view["set" + type](byteOffset, value, littleEndian); + ? this._view['get' + type](byteOffset, littleEndian) + : this._view['set' + type](byteOffset, value, littleEndian); }, _nodeBufferAction: function ( @@ -307,17 +310,17 @@ jDataView.prototype = { isReadAction, byteOffset, littleEndian, - value + value, ) { // Move the internal offset forward this._offset = byteOffset + dataTypes[type]; var nodeName = nodeNaming[type] + - (type === "Int8" || type === "Uint8" ? "" : littleEndian ? "LE" : "BE"); + (type === 'Int8' || type === 'Uint8' ? '' : littleEndian ? 'LE' : 'BE'); byteOffset += this.byteOffset; return isReadAction - ? this.buffer["read" + nodeName](byteOffset) - : this.buffer["write" + nodeName](value, byteOffset); + ? this.buffer['read' + nodeName](byteOffset) + : this.buffer['write' + nodeName](value, byteOffset); }, _arrayBufferAction: function ( @@ -325,10 +328,10 @@ jDataView.prototype = { isReadAction, byteOffset, littleEndian, - value + value, ) { var size = dataTypes[type], - TypedArray = globalThis[type + "Array"], + TypedArray = globalThis[type + 'Array'], typedArray; littleEndian = defined(littleEndian, this._littleEndian); @@ -345,7 +348,7 @@ jDataView.prototype = { var bytes = new Uint8Array( isReadAction ? this.getBytes(size, byteOffset, littleEndian, true) - : size + : size, ); typedArray = new TypedArray(bytes.buffer, 0, 1); @@ -360,8 +363,8 @@ jDataView.prototype = { _arrayAction: function (type, isReadAction, byteOffset, littleEndian, value) { return isReadAction - ? this["_get" + type](byteOffset, littleEndian) - : this["_set" + type](byteOffset, value, littleEndian); + ? this['_get' + type](byteOffset, littleEndian) + : this['_set' + type](byteOffset, value, littleEndian); }, // Helpers @@ -382,7 +385,7 @@ jDataView.prototype = { : (this.buffer.slice || Array.prototype.slice).call( this.buffer, byteOffset, - byteOffset + length + byteOffset + length, ); return littleEndian || length <= 1 ? result : arrayFrom(result).reverse(); @@ -393,7 +396,7 @@ jDataView.prototype = { var result = this._getBytes( length, byteOffset, - defined(littleEndian, true) + defined(littleEndian, true), ); return toArray ? arrayFrom(result) : result; }, @@ -445,18 +448,18 @@ jDataView.prototype = { this._offset = byteOffset + byteLength; return this.buffer.toString( - encoding || "binary", + encoding || 'binary', this.byteOffset + byteOffset, - this.byteOffset + this._offset + this.byteOffset + this._offset, ); } var bytes = this._getBytes(byteLength, byteOffset, true), - string = ""; + string = ''; byteLength = bytes.length; for (var i = 0; i < byteLength; i++) { string += String.fromCharCode(bytes[i]); } - if (encoding === "utf8") { + if (encoding === 'utf8') { string = decodeURIComponent(escape(string)); } return string; @@ -471,11 +474,11 @@ jDataView.prototype = { this.buffer.write( subString, this.byteOffset + byteOffset, - encoding || "binary" + encoding || 'binary', ); return; } - if (encoding === "utf8") { + if (encoding === 'utf8') { subString = unescape(encodeURIComponent(subString)); } this._setBytes(byteOffset, getCharCodes(subString), true); @@ -516,13 +519,13 @@ jDataView.prototype = { this.getBytes(end - start, start, true, true), undefined, undefined, - this._littleEndian + this._littleEndian, ) : new jDataView( this.buffer, this.byteOffset + start, end - start, - this._littleEndian + this._littleEndian, ); }, @@ -679,7 +682,7 @@ jDataView.prototype = { value, mantSize, expSize, - littleEndian + littleEndian, ) { var signBit = value < 0 ? 1 : 0, exponent, @@ -751,7 +754,7 @@ jDataView.prototype = { this.setUint32( byteOffset + parts[partName], value[partName], - littleEndian + littleEndian, ); } @@ -770,7 +773,7 @@ jDataView.prototype = { this._setBytes( byteOffset, [value & 0xff, (value >>> 8) & 0xff, (value >>> 16) & 0xff, value >>> 24], - littleEndian + littleEndian, ); }, @@ -778,7 +781,7 @@ jDataView.prototype = { this._setBytes( byteOffset, [value & 0xff, (value >>> 8) & 0xff], - littleEndian + littleEndian, ); }, @@ -808,10 +811,10 @@ var proto = jDataView.prototype; for (var type in dataTypes) { (function (type) { - proto["get" + type] = function (byteOffset, littleEndian) { + proto['get' + type] = function (byteOffset, littleEndian) { return this._action(type, true, byteOffset, littleEndian); }; - proto["set" + type] = function (byteOffset, value, littleEndian) { + proto['set' + type] = function (byteOffset, value, littleEndian) { this._action(type, false, byteOffset, littleEndian, value); }; })(type); @@ -823,19 +826,19 @@ proto._setInt8 = proto._setUint8; proto.setSigned = proto.setUnsigned; for (var method in proto) { - if (method.slice(0, 3) === "set") { + if (method.slice(0, 3) === 'set') { (function (type) { - proto["write" + type] = function () { + proto['write' + type] = function () { Array.prototype.unshift.call(arguments, undefined); - this["set" + type].apply(this, arguments); + this['set' + type].apply(this, arguments); }; })(method.slice(3)); } } -if (typeof module !== "undefined" && typeof module.exports === "object") { +if (typeof module !== 'undefined' && typeof module.exports === 'object') { module.exports = jDataView; -} else if (typeof define === "function" && define.amd) { +} else if (typeof define === 'function' && define.amd) { define([], function () { return jDataView; }); diff --git a/src/lib/file-renderer/pattern.js b/src/lib/file-renderer/pattern.js new file mode 100644 index 0000000..6c819f1 --- /dev/null +++ b/src/lib/file-renderer/pattern.js @@ -0,0 +1,331 @@ +import { rgbToHex } from '$lib/utils/rgbToHex'; +import { shadeColor } from '$lib/utils/shadeColor'; + +/** + * Represents a single stitch in the pattern. + * @param {number} x - The absolute x position of the stitch. + * @param {number} y - The absolute y position of the stitch. + * @param {number} flags - Stitch flags (e.g. jump, trim). + * @param {number} color - Index of the stitch color. + * @constructor + */ +function Stitch(x, y, flags, color) { + this.x = x; + this.y = y; + this.flags = flags; + this.color = color; +} + +/** + * Represents a color with RGB components and an optional description. + * @param {number} r - Red component (0-255). + * @param {number} g - Green component (0-255). + * @param {number} b - Blue component (0-255). + * @param {string} description - Color description. + * @constructor + */ +function Color(r, g, b, description) { + this.r = r; + this.g = g; + this.b = b; + this.description = description; +} + +/** + * Stitch type bit flags. + * @readonly + * @enum {number} + */ +const stitchTypes = { + normal: 0, + jump: 1, + trim: 2, + stop: 4, + end: 8, +}; + +/** + * Represents an embroidery pattern containing stitches and colors. + * @constructor + */ +function Pattern() { + /** @type {Color[]} */ + this.colors = []; + + /** @type {Stitch[]} */ + this.stitches = []; + + /** Hoop info (not typed, depends on implementation) */ + this.hoop = {}; + + /** Last stitch position for relative moves */ + this.lastX = 0; + this.lastY = 0; + + /** Bounding box */ + this.top = 0; + this.bottom = 0; + this.left = 0; + this.right = 0; + + /** Current color index used for new stitches */ + this.currentColorIndex = 0; +} + +/** + * Adds a color by RGB values. + * @param {number} r + * @param {number} g + * @param {number} b + * @param {string} description + */ +Pattern.prototype.addColorRgb = function (r, g, b, description) { + this.colors.push(new Color(r, g, b, description)); +}; + +/** + * Adds an existing Color instance. + * @param {Color} color + */ +Pattern.prototype.addColor = function (color) { + this.colors.push(color); +}; + +/** + * Adds a stitch at absolute coordinates. + * @param {number} x - Absolute X coordinate. + * @param {number} y - Absolute Y coordinate. + * @param {number} flags - Stitch flags. + * @param {boolean} isAutoColorIndex - Whether to automatically increment color on stop. + */ +Pattern.prototype.addStitchAbs = function (x, y, flags, isAutoColorIndex) { + if ((flags & stitchTypes.end) === stitchTypes.end) { + this.calculateBoundingBox(); + this.fixColorCount(); + } + if ( + (flags & stitchTypes.stop) === stitchTypes.stop && + this.stitches.length === 0 + ) { + return; + } + if ((flags & stitchTypes.stop) === stitchTypes.stop && isAutoColorIndex) { + this.currentColorIndex += 1; + } + this.stitches.push(new Stitch(x, y, flags, this.currentColorIndex)); +}; + +/** + * Adds a stitch relative to the last stitch. + * @param {number} dx - Delta X from last stitch. + * @param {number} dy - Delta Y from last stitch. + * @param {number} flags - Stitch flags. + * @param {boolean} [isAutoColorIndex=false] - Whether to automatically increment color on stop. Optional. + */ +Pattern.prototype.addStitchRel = function (dx, dy, flags, isAutoColorIndex) { + if (typeof isAutoColorIndex === 'undefined') { + isAutoColorIndex = false; + } + + if (this.stitches.length !== 0) { + const nx = this.lastX + dx; + const ny = this.lastY + dy; + this.lastX = nx; + this.lastY = ny; + this.addStitchAbs(nx, ny, flags, isAutoColorIndex); + } else { + this.addStitchAbs(dx, dy, flags, isAutoColorIndex); + } +}; + +/** + * Calculates the bounding box of all stitches, excluding trims. + */ +Pattern.prototype.calculateBoundingBox = function () { + const stitchCount = this.stitches.length; + if (stitchCount === 0) { + this.bottom = 1; + this.right = 1; + return; + } + this.left = Infinity; + this.top = Infinity; + this.right = -Infinity; + this.bottom = -Infinity; + + for (let i = 0; i < stitchCount; i++) { + const pt = this.stitches[i]; + if (!(pt.flags & stitchTypes.trim)) { + if (pt.x < this.left) this.left = pt.x; + if (pt.y < this.top) this.top = pt.y; + if (pt.x > this.right) this.right = pt.x; + if (pt.y > this.bottom) this.bottom = pt.y; + } + } +}; + +/** + * Moves all stitches so the pattern is positioned at positive coordinates. + */ +Pattern.prototype.moveToPositive = function () { + const stitchCount = this.stitches.length; + for (let i = 0; i < stitchCount; i++) { + this.stitches[i].x -= this.left; + this.stitches[i].y -= this.top; + } + this.right -= this.left; + this.left = 0; + this.bottom -= this.top; + this.top = 0; +}; + +/** + * Flips the pattern vertically. + */ +Pattern.prototype.invertPatternVertical = function () { + const stitchCount = this.stitches.length; + const tempTop = -this.top; + for (let i = 0; i < stitchCount; i++) { + this.stitches[i].y = -this.stitches[i].y; + } + this.top = -this.bottom; + this.bottom = tempTop; +}; + +/** + * Adds a random color to the pattern. + */ +Pattern.prototype.addColorRandom = function () { + this.colors.push( + new Color( + Math.round(Math.random() * 256), + Math.round(Math.random() * 256), + Math.round(Math.random() * 256), + 'random', + ), + ); +}; + +/** + * Fixes the color count so colors match used indices in stitches. + */ +Pattern.prototype.fixColorCount = function () { + let maxColorIndex = 0; + const stitchCount = this.stitches.length; + + for (let i = 0; i < stitchCount; i++) { + if (this.stitches[i].color > maxColorIndex) { + maxColorIndex = this.stitches[i].color; + } + } + + while (this.colors.length <= maxColorIndex) { + this.addColorRandom(); + } + + // Remove extra colors beyond max used index + this.colors.splice(maxColorIndex + 1); +}; + +/** + * Draws the stitch pattern to a canvas element. + * @param {HTMLCanvasElement} canvas + */ +Pattern.prototype.drawShapeTo = function (canvas) { + canvas.width = this.right; + canvas.height = this.bottom; + + let gradient, tx, ty; + let lastStitch = this.stitches[0]; + let gWidth = 100; + + if (canvas.getContext) { + const ctx = canvas.getContext('2d'); + if (!ctx) { + // If context is null, just return or handle accordingly + return; + } + + ctx.lineWidth = 3; + ctx.lineJoin = 'round'; + + let color = this.colors[this.stitches[0].color]; + for (let i = 0; i < this.stitches.length; i++) { + const currentStitch = this.stitches[i]; + if (i > 0) lastStitch = this.stitches[i - 1]; + tx = currentStitch.x - lastStitch.x; + ty = currentStitch.y - lastStitch.y; + + gWidth = Math.sqrt(tx * tx + ty * ty); + gradient = ctx.createRadialGradient( + currentStitch.x - tx, + currentStitch.y - ty, + 0, + currentStitch.x - tx, + currentStitch.y - ty, + gWidth * 1.4, + ); + + gradient.addColorStop(0, shadeColor(rgbToHex(color), -60)); + gradient.addColorStop(0.05, rgbToHex(color)); + gradient.addColorStop(0.5, shadeColor(rgbToHex(color), 60)); + gradient.addColorStop(0.9, rgbToHex(color)); + gradient.addColorStop(1.0, shadeColor(rgbToHex(color), -60)); + + ctx.strokeStyle = gradient; + if ( + currentStitch.flags === stitchTypes.jump || + currentStitch.flags === stitchTypes.trim || + currentStitch.flags === stitchTypes.stop + ) { + color = this.colors[currentStitch.color]; + ctx.beginPath(); + ctx.strokeStyle = + 'rgba(' + color.r + ',' + color.g + ',' + color.b + ',0)'; + ctx.moveTo(currentStitch.x, currentStitch.y); + ctx.stroke(); + } + ctx.beginPath(); + ctx.moveTo(lastStitch.x, lastStitch.y); + ctx.lineTo(currentStitch.x, currentStitch.y); + ctx.stroke(); + lastStitch = currentStitch; + } + } +}; + +/** + * Draws color swatches into a container element. + * @param {HTMLElement} colorContainer + */ +Pattern.prototype.drawColorsTo = function (colorContainer) { + this.colors.forEach((color) => { + colorContainer.innerHTML += `
`; + }); +}; + +/** + * Displays the stitch count in a container element. + * @param {HTMLElement} stitchesContainer + * @param {string} stitchesString - Label for stitches count. + */ +Pattern.prototype.drawStitchesCountTo = function ( + stitchesContainer, + stitchesString, +) { + stitchesContainer.innerHTML += `
${stitchesString}: ${this.stitches.length}
`; +}; + +/** + * Displays pattern dimensions in a container element. + * @param {HTMLElement} sizeContainer + * @param {string} dimensionsString - Label for dimensions. + */ +Pattern.prototype.drawSizeValuesTo = function ( + sizeContainer, + dimensionsString, +) { + sizeContainer.innerHTML += `
${dimensionsString}: ${Math.round(this.right / 10)}mm x ${Math.round(this.bottom / 10)}mm
`; +}; + +export { Pattern, Color, stitchTypes }; diff --git a/src/lib/format-readers/dst.js b/src/lib/format-readers/dst.js new file mode 100644 index 0000000..63e7ca5 --- /dev/null +++ b/src/lib/format-readers/dst.js @@ -0,0 +1,89 @@ +import { stitchTypes } from '$lib/file-renderer/pattern'; + +/** + * Decodes stitch flags from the 3rd byte of a DST stitch command. + * + * @param {number} b2 The third byte of the stitch command. + * @returns {number} Bitmask representing stitch types. + */ +function decodeExp(b2) { + if (b2 === 0xf3) { + return stitchTypes.end; + } + if ((b2 & 0xc3) === 0xc3) { + return stitchTypes.trim | stitchTypes.stop; + } + + let returnCode = 0; + if (b2 & 0x80) { + returnCode |= stitchTypes.trim; + } + if (b2 & 0x40) { + returnCode |= stitchTypes.stop; + } + return returnCode; +} + +/** + * Reads a DST embroidery file and populates the pattern object. + * + * + * @param {EmbroideryFileView} file + * @param {EmbroideryPattern} pattern + */ +export function dstRead(file, pattern) { + let prevJump = false; + const byteCount = file.byteLength; + + file.seek(512); // Skip DST header + + while (file.tell() < byteCount - 3) { + /** @type {number[]} */ + const b = [file.getUint8(), file.getUint8(), file.getUint8()]; + + let x = 0; + let y = 0; + + // Decode X movements + if (b[0] & 0x01) x += 1; + if (b[0] & 0x02) x -= 1; + if (b[0] & 0x04) x += 9; + if (b[0] & 0x08) x -= 9; + + if (b[1] & 0x01) x += 3; + if (b[1] & 0x02) x -= 3; + if (b[1] & 0x04) x += 27; + if (b[1] & 0x08) x -= 27; + + if (b[2] & 0x04) x += 81; + if (b[2] & 0x08) x -= 81; + + // Decode Y movements + if (b[0] & 0x80) y += 1; + if (b[0] & 0x40) y -= 1; + if (b[0] & 0x20) y += 9; + if (b[0] & 0x10) y -= 9; + + if (b[1] & 0x80) y += 3; + if (b[1] & 0x40) y -= 3; + if (b[1] & 0x20) y += 27; + if (b[1] & 0x10) y -= 27; + + if (b[2] & 0x20) y += 81; + if (b[2] & 0x10) y -= 81; + + let flags = decodeExp(b[2]); + const thisJump = (flags & stitchTypes.jump) !== 0; + + if (prevJump) { + flags |= stitchTypes.jump; + } + + pattern.addStitchRel(x, y, flags, true); + + prevJump = thisJump; + } + + pattern.addStitchRel(0, 0, stitchTypes.end, true); + pattern.invertPatternVertical(); +} diff --git a/src/lib/format-readers/exp.js b/src/lib/format-readers/exp.js new file mode 100644 index 0000000..baf5690 --- /dev/null +++ b/src/lib/format-readers/exp.js @@ -0,0 +1,56 @@ +import { stitchTypes } from '$lib/file-renderer/pattern'; + +/** + * Decodes a single byte with EXP format rules. + * Values above 128 are negative numbers encoded with bitwise operations. + * + * @param {number} input - A signed 8-bit integer (-128 to 127). + * @returns {number} - Decoded signed integer. + */ +function expDecode(input) { + return input > 128 ? -(~input & 0xff) - 1 : input; +} + +/** + * Reads an EXP format file and adds stitches to the given pattern. + * + * @param {EmbroideryFileView} file - A DataView representing the binary EXP file content. + * @param {EmbroideryPattern} pattern - The pattern object with addStitchRel and invertPatternVertical methods. + * @returns {void} + */ +export function expRead(file, pattern) { + let index = 0; + const byteCount = file.byteLength; + + while (index < byteCount) { + let flags = stitchTypes.normal; + let b0 = file.getInt8(index++); + let b1 = file.getInt8(index++); + + if (b0 === -128) { + if (b1 & 1) { + b0 = file.getInt8(index++); + b1 = file.getInt8(index++); + flags = stitchTypes.stop; + } else if (b1 === 2 || b1 === 4) { + b0 = file.getInt8(index++); + b1 = file.getInt8(index++); + flags = stitchTypes.trim; + } else if (b1 === -128) { + b0 = file.getInt8(index++); + b1 = file.getInt8(index++); + b0 = 0; + b1 = 0; + flags = stitchTypes.trim; + } + } + + const dx = expDecode(b0); + const dy = expDecode(b1); + + pattern.addStitchRel(dx, dy, flags, true); + } + + pattern.addStitchRel(0, 0, stitchTypes.end); + pattern.invertPatternVertical(); +} diff --git a/src/lib/format-readers/index.js b/src/lib/format-readers/index.js new file mode 100644 index 0000000..0e5e798 --- /dev/null +++ b/src/lib/format-readers/index.js @@ -0,0 +1,19 @@ +import { dstRead } from './dst'; +import { expRead } from './exp'; +import { jefRead } from './jef'; +import { pecRead } from './pec'; +import { pesRead } from './pes'; + +/** + * Supported embroidery file formats. + * @type {SupportedFormats} + */ +const supportedFormats = { + pes: { ext: '.pes', read: pesRead }, + dst: { ext: '.dst', read: dstRead }, + pec: { ext: '.pec', read: pecRead }, + jef: { ext: '.jef', read: jefRead }, + exp: { ext: '.exp', read: expRead }, +}; + +export { supportedFormats }; diff --git a/src/lib/format-readers/jef.js b/src/lib/format-readers/jef.js new file mode 100644 index 0000000..778737c --- /dev/null +++ b/src/lib/format-readers/jef.js @@ -0,0 +1,212 @@ +import { Color, stitchTypes } from '$lib/file-renderer/pattern'; + +/** @type {Color[]} */ +const colors = [ + new Color(0, 0, 0, 'Black'), + new Color(0, 0, 0, 'Black'), + new Color(255, 255, 255, 'White'), + new Color(255, 255, 23, 'Yellow'), + new Color(250, 160, 96, 'Orange'), + new Color(92, 118, 73, 'Olive Green'), + new Color(64, 192, 48, 'Green'), + new Color(101, 194, 200, 'Sky'), + new Color(172, 128, 190, 'Purple'), + new Color(245, 188, 203, 'Pink'), + new Color(255, 0, 0, 'Red'), + new Color(192, 128, 0, 'Brown'), + new Color(0, 0, 240, 'Blue'), + new Color(228, 195, 93, 'Gold'), + new Color(165, 42, 42, 'Dark Brown'), + new Color(213, 176, 212, 'Pale Violet'), + new Color(252, 242, 148, 'Pale Yellow'), + new Color(240, 208, 192, 'Pale Pink'), + new Color(255, 192, 0, 'Peach'), + new Color(201, 164, 128, 'Beige'), + new Color(155, 61, 75, 'Wine Red'), + new Color(160, 184, 204, 'Pale Sky'), + new Color(127, 194, 28, 'Yellow Green'), + new Color(185, 185, 185, 'Silver Grey'), + new Color(160, 160, 160, 'Grey'), + new Color(152, 214, 189, 'Pale Aqua'), + new Color(184, 240, 240, 'Baby Blue'), + new Color(54, 139, 160, 'Powder Blue'), + new Color(79, 131, 171, 'Bright Blue'), + new Color(56, 106, 145, 'Slate Blue'), + new Color(0, 32, 107, 'Nave Blue'), + new Color(229, 197, 202, 'Salmon Pink'), + new Color(249, 103, 107, 'Coral'), + new Color(227, 49, 31, 'Burnt Orange'), + new Color(226, 161, 136, 'Cinnamon'), + new Color(181, 148, 116, 'Umber'), + new Color(228, 207, 153, 'Blonde'), + new Color(225, 203, 0, 'Sunflower'), + new Color(225, 173, 212, 'Orchid Pink'), + new Color(195, 0, 126, 'Peony Purple'), + new Color(128, 0, 75, 'Burgundy'), + new Color(160, 96, 176, 'Royal Purple'), + new Color(192, 64, 32, 'Cardinal Red'), + new Color(202, 224, 192, 'Opal Green'), + new Color(137, 152, 86, 'Moss Green'), + new Color(0, 170, 0, 'Meadow Green'), + new Color(33, 138, 33, 'Dark Green'), + new Color(93, 174, 148, 'Aquamarine'), + new Color(76, 191, 143, 'Emerald Green'), + new Color(0, 119, 114, 'Peacock Green'), + new Color(112, 112, 112, 'Dark Grey'), + new Color(242, 255, 255, 'Ivory White'), + new Color(177, 88, 24, 'Hazel'), + new Color(203, 138, 7, 'Toast'), + new Color(247, 146, 123, 'Salmon'), + new Color(152, 105, 45, 'Cocoa Brown'), + new Color(162, 113, 72, 'Sienna'), + new Color(123, 85, 74, 'Sepia'), + new Color(79, 57, 70, 'Dark Sepia'), + new Color(82, 58, 151, 'Violet Blue'), + new Color(0, 0, 160, 'Blue Ink'), + new Color(0, 150, 222, 'Solar Blue'), + new Color(178, 221, 83, 'Green Dust'), + new Color(250, 143, 187, 'Crimson'), + new Color(222, 100, 158, 'Floral Pink'), + new Color(181, 80, 102, 'Wine'), + new Color(94, 87, 71, 'Olive Drab'), + new Color(76, 136, 31, 'Meadow'), + new Color(228, 220, 121, 'Mustard'), + new Color(203, 138, 26, 'Yellow Ochre'), + new Color(198, 170, 66, 'Old Gold'), + new Color(236, 176, 44, 'Honeydew'), + new Color(248, 128, 64, 'Tangerine'), + new Color(255, 229, 5, 'Canary Yellow'), + new Color(250, 122, 122, 'Vermillion'), + new Color(107, 224, 0, 'Bright Green'), + new Color(56, 108, 174, 'Ocean Blue'), + new Color(227, 196, 180, 'Beige Grey'), + new Color(227, 172, 129, 'Bamboo'), +]; + +/** + * Decode a single byte for JEF stitch data (signed int8-like with special encoding). + * @param {number} byte + * @returns {number} + */ +const jefDecode = (byte) => (byte >= 0x80 ? -(~byte & 0xff) - 1 : byte); + +/** + * Check if a byte represents a special stitch (0x80). + * @param {number} byte + * @returns {boolean} + */ +const isSpecialStitch = (byte) => byte === 0x80; + +/** + * Check if a byte represents a stop or trim command. + * @param {number} byte + * @returns {boolean} + */ +const isStopOrTrim = (byte) => + (byte & 0x01) !== 0 || byte === 0x02 || byte === 0x04; + +/** + * Check if a byte indicates end of pattern. + * @param {number} byte + * @returns {boolean} + */ +const isEndOfPattern = (byte) => byte === 0x10; + +/** + * Check if a byte indicates a stop command. + * @param {number} byte + * @returns {boolean} + */ +const isStop = (byte) => (byte & 0x01) !== 0; + +/** + * Read two stitch data bytes from the file. + * @param {EmbroideryFileView} file + * @returns {{ byte1: number, byte2: number }} + */ +const readStitchData = (file) => ({ + byte1: file.getUint8(), + byte2: file.getUint8(), +}); + +/** + * Add colors from file data to the pattern. + * @param {EmbroideryFileView} file + * @param {EmbroideryPattern} pattern + * @param {number} colorCount + */ +const addColorsToPattern = (file, pattern, colorCount) => { + for (let i = 0; i < colorCount; i++) { + const colorIndex = file.getUint32(file.tell(), true) % colors.length; + pattern.addColor(colors[colorIndex]); + } +}; + +/** + * Determine the stitch type and potentially read additional bytes. + * @param {EmbroideryFileView} file + * @param {number} byte1 + * @param {number} byte2 + * @returns {{ type: number, byte1: number, byte2: number, end?: boolean }} + */ +const determineStitchType = (file, byte1, byte2) => { + if (isSpecialStitch(byte1)) { + if (isStopOrTrim(byte2)) { + return { + type: isStop(byte2) ? stitchTypes.stop : stitchTypes.trim, + byte1: file.getUint8(), + byte2: file.getUint8(), + }; + } else if (isEndOfPattern(byte2)) { + return { type: stitchTypes.end, byte1: 0, byte2: 0, end: true }; + } + } + return { type: stitchTypes.normal, byte1, byte2 }; +}; + +/** + * Process stitches in the file and add them to the pattern. + * @param {EmbroideryFileView} file + * @param {EmbroideryPattern} pattern + * @param {number} stitchCount + */ +const processStitches = (file, pattern, stitchCount) => { + let stitchesProcessed = 0; + while (stitchesProcessed < stitchCount + 100) { + const { byte1, byte2 } = readStitchData(file); + const { + type, + byte1: decodedByte1, + byte2: decodedByte2, + end, + } = determineStitchType(file, byte1, byte2); + pattern.addStitchRel( + jefDecode(decodedByte1), + jefDecode(decodedByte2), + type, + true, + ); + if (end) break; + stitchesProcessed++; + } +}; + +/** + * Reads a JEF file and adds stitches and colors to the pattern. + * @param {EmbroideryFileView} file + * @param {EmbroideryPattern} pattern + */ +export function jefRead(file, pattern) { + file.seek(24); + const colorCount = file.getInt32(file.tell(), true); + const stitchCount = file.getInt32(file.tell(), true); + file.seek(file.tell() + 84); + + addColorsToPattern(file, pattern, colorCount); + file.seek(file.tell() + (6 - colorCount) * 4); + + processStitches(file, pattern, stitchCount); + pattern.invertPatternVertical(); +} + +export const jefColors = colors; diff --git a/src/format-readers/pec.js b/src/lib/format-readers/pec.js similarity index 67% rename from src/format-readers/pec.js rename to src/lib/format-readers/pec.js index 402e613..0595e97 100644 --- a/src/format-readers/pec.js +++ b/src/lib/format-readers/pec.js @@ -1,5 +1,10 @@ -import { pecColors, pecReadStitches } from "./pes"; +import { pecColors, pecReadStitches } from './pes'; +/** + * + * @param {EmbroideryFileView} file + * @param {EmbroideryPattern} pattern + */ export function pecRead(file, pattern) { let colorChanges, i; file.seek(0x38); diff --git a/src/lib/format-readers/pes.js b/src/lib/format-readers/pes.js new file mode 100644 index 0000000..3d6b797 --- /dev/null +++ b/src/lib/format-readers/pes.js @@ -0,0 +1,192 @@ +import { Color, stitchTypes } from '$lib/file-renderer/pattern'; + +/** + * Array of predefined embroidery colors used in PEC files. + * @type {Color[]} + */ +export const pecColors = [ + new Color(0, 0, 0, 'Unknown'), + new Color(14, 31, 124, 'Prussian Blue'), + new Color(10, 85, 163, 'Blue'), + new Color(0, 135, 119, 'Teal Green'), + new Color(75, 107, 175, 'Cornflower Blue'), + new Color(237, 23, 31, 'Red'), + new Color(209, 92, 0, 'Reddish Brown'), + new Color(145, 54, 151, 'Magenta'), + new Color(228, 154, 203, 'Light Lilac'), + new Color(145, 95, 172, 'Lilac'), + new Color(158, 214, 125, 'Mint Green'), + new Color(232, 169, 0, 'Deep Gold'), + new Color(254, 186, 53, 'Orange'), + new Color(255, 255, 0, 'Yellow'), + new Color(112, 188, 31, 'Lime Green'), + new Color(186, 152, 0, 'Brass'), + new Color(168, 168, 168, 'Silver'), + new Color(125, 111, 0, 'Russet Brown'), + new Color(255, 255, 179, 'Cream Brown'), + new Color(79, 85, 86, 'Pewter'), + new Color(0, 0, 0, 'Black'), + new Color(11, 61, 145, 'Ultramarine'), + new Color(119, 1, 118, 'Royal Purple'), + new Color(41, 49, 51, 'Dark Gray'), + new Color(42, 19, 1, 'Dark Brown'), + new Color(246, 74, 138, 'Deep Rose'), + new Color(178, 118, 36, 'Light Brown'), + new Color(252, 187, 197, 'Salmon Pink'), + new Color(254, 55, 15, 'Vermillion'), + new Color(240, 240, 240, 'White'), + new Color(106, 28, 138, 'Violet'), + new Color(168, 221, 196, 'Seacrest'), + new Color(37, 132, 187, 'Sky Blue'), + new Color(254, 179, 67, 'Pumpkin'), + new Color(255, 243, 107, 'Cream Yellow'), + new Color(208, 166, 96, 'Khaki'), + new Color(209, 84, 0, 'Clay Brown'), + new Color(102, 186, 73, 'Leaf Green'), + new Color(19, 74, 70, 'Peacock Blue'), + new Color(135, 135, 135, 'Gray'), + new Color(216, 204, 198, 'Warm Gray'), + new Color(67, 86, 7, 'Dark Olive'), + new Color(253, 217, 222, 'Flesh Pink'), + new Color(249, 147, 188, 'Pink'), + new Color(0, 56, 34, 'Deep Green'), + new Color(178, 175, 212, 'Lavender'), + new Color(104, 106, 176, 'Wisteria Violet'), + new Color(239, 227, 185, 'Beige'), + new Color(247, 56, 102, 'Carmine'), + new Color(181, 75, 100, 'Amber Red'), + new Color(19, 43, 26, 'Olive Green'), + new Color(199, 1, 86, 'Dark Fuschia'), + new Color(254, 158, 50, 'Tangerine'), + new Color(168, 222, 235, 'Light Blue'), + new Color(0, 103, 62, 'Emerald Green'), + new Color(78, 41, 144, 'Purple'), + new Color(47, 126, 32, 'Moss Green'), + new Color(255, 204, 204, 'Flesh Pink'), + new Color(255, 217, 17, 'Harvest Gold'), + new Color(9, 91, 166, 'Electric Blue'), + new Color(240, 249, 112, 'Lemon Yellow'), + new Color(227, 243, 91, 'Fresh Green'), + new Color(255, 153, 0, 'Orange'), + new Color(255, 240, 141, 'Cream Yellow'), + new Color(255, 200, 200, 'Applique'), +]; + +/** + * Reads stitch data from a PEC embroidery file and adds it to the pattern. + * @param {EmbroideryFileView} file + * @param {EmbroideryPattern} pattern - The pattern to populate. + */ +function readPecStitches(file, pattern) { + let stitchNumber = 0; + const byteCount = file.byteLength; + + while (file.tell() < byteCount) { + let [xOffset, yOffset] = [file.getUint8(), file.getUint8()]; + let stitchType = stitchTypes.normal; + + if (isEndStitch(xOffset, yOffset)) { + pattern.addStitchRel(0, 0, stitchTypes.end, true); + break; + } + + if (isStopStitch(xOffset, yOffset)) { + file.getInt8(); // Skip extra byte + pattern.addStitchRel(0, 0, stitchTypes.stop, true); + stitchNumber++; + continue; + } + + stitchType = determineStitchType(xOffset, yOffset); + [xOffset, yOffset] = decodeCoordinates(xOffset, yOffset, file); + + pattern.addStitchRel(xOffset, yOffset, stitchType, true); + // eslint-disable-next-line no-unused-vars + stitchNumber++; + } +} + +/** + * Determines whether the stitch is an "end" stitch. + * @param {number} xOffset + * @param {number} yOffset + * @returns {boolean} + */ +function isEndStitch(xOffset, yOffset) { + return xOffset === 0xff && yOffset === 0x00; +} + +/** + * Determines whether the stitch is a "stop" stitch. + * @param {number} xOffset + * @param {number} yOffset + * @returns {boolean} + */ +function isStopStitch(xOffset, yOffset) { + return xOffset === 0xfe && yOffset === 0xb0; +} + +/** + * Infers the stitch type from byte flags. + * @param {number} xOffset + * @param {number} yOffset + * @returns {number} + */ +function determineStitchType(xOffset, yOffset) { + if (xOffset & 0x80) { + if (xOffset & 0x20) return stitchTypes.trim; + if (xOffset & 0x10) return stitchTypes.jump; + } + if (yOffset & 0x80) { + if (yOffset & 0x20) return stitchTypes.trim; + if (yOffset & 0x10) return stitchTypes.jump; + } + return stitchTypes.normal; +} + +/** + * Decodes 12-bit signed coordinates from PEC format. + * @param {number} xOffset + * @param {number} yOffset + * @param {DataView & { tell: () => number, seek: (pos: number) => void, getUint8: () => number, getInt8: () => number }} file + * @returns {[number, number]} - Decoded [x, y] coordinates. + */ +function decodeCoordinates(xOffset, yOffset, file) { + if (xOffset & 0x80) { + xOffset = ((xOffset & 0x0f) << 8) + yOffset; + if (xOffset & 0x800) xOffset -= 0x1000; + yOffset = file.getUint8(); + } else if (xOffset >= 0x40) { + xOffset -= 0x80; + } + + if (yOffset & 0x80) { + yOffset = ((yOffset & 0x0f) << 8) + file.getUint8(); + if (yOffset & 0x800) yOffset -= 0x1000; + } else if (yOffset > 0x3f) { + yOffset -= 0x80; + } + + return [xOffset, yOffset]; +} + +/** + * Parses a PES file and adds stitch and color data to the pattern. + * @param {DataView & { tell: () => number, seek: (pos: number) => void, getUint8: () => number, getInt8: () => number }} file + * @param {EmbroideryPattern} pattern - The pattern to populate. + */ +export function pesRead(file, pattern) { + const pecStart = file.getInt32(8, true); + file.seek(pecStart + 48); + + const numColors = file.getInt8() + 1; + for (let i = 0; i < numColors; i++) { + pattern.addColor(pecColors[file.getInt8()]); + } + + file.seek(pecStart + 532); + readPecStitches(file, pattern); + pattern.addStitchRel(0, 0, stitchTypes.end); +} + +export const pecReadStitches = readPecStitches; diff --git a/src/lib/format-readers/types.js b/src/lib/format-readers/types.js new file mode 100644 index 0000000..c9300a8 --- /dev/null +++ b/src/lib/format-readers/types.js @@ -0,0 +1,31 @@ +/** + * A custom DataView with embroidery reader-specific helper methods. + * @typedef {DataView & { + * tell: () => number; + * seek: (pos: number) => void; + * getUint8: () => number; + * getInt8: () => number; + * getInt32: (pos: number, littleEndian: boolean) => number; + * }} EmbroideryFileView + */ + +/** + * A Pattern extended with optional embroidery reader methods. + * @typedef {import('$lib/file-renderer/pattern').Pattern & { + * addColor?: (color: import('$lib/file-renderer/pattern').Color) => void; + * addStitchRel: (dx: number, dy: number, stitchType: string, autoAdvance?: boolean) => void; + * invertPatternVertical?: () => void; + * }} EmbroideryPattern + */ + +/** + * Represents a reader for a specific embroidery file format. + * @typedef {Object} FormatReader + * @property {string} ext - File extension (e.g., '.pes', '.dst'). + * @property {(view: EmbroideryFileView, pattern: EmbroideryPattern) => void} read - Function to parse the embroidery format and populate the pattern. + */ + +/** + * A map of supported embroidery file formats keyed by format name (e.g., "pes", "dst"). + * @typedef {Object.} SupportedFormats + */ diff --git a/src/lib/pages/About.svelte b/src/lib/pages/About.svelte deleted file mode 100644 index 8aa2d11..0000000 --- a/src/lib/pages/About.svelte +++ /dev/null @@ -1,29 +0,0 @@ - -
-

{$t('about.title')}

- - {@html $t("about.content")} - -
- - \ No newline at end of file diff --git a/src/lib/pages/Donate.svelte b/src/lib/pages/Donate.svelte deleted file mode 100644 index 12886f6..0000000 --- a/src/lib/pages/Donate.svelte +++ /dev/null @@ -1,195 +0,0 @@ - - -
-

{$t("donate.title")}

- -

- {@html $t("donate.description")} -

-
-
-

{$t("donate.ways")}

-
-
- Bitcoin QR code -

Bitcoin

-

{$t("donate.bitcoin.description")}

- -
- - -
- Monero QR code -

Monero

-

{$t("donate.monero.description")}

- -
- - -
-
- - \ No newline at end of file diff --git a/src/lib/pages/Home.svelte b/src/lib/pages/Home.svelte deleted file mode 100644 index 1103bfb..0000000 --- a/src/lib/pages/Home.svelte +++ /dev/null @@ -1,60 +0,0 @@ - - -
- -
-

{$t("home.main.title")}

- {@html $t("home.main.description")} -
- -
-

{$t("home.features.title")}

- {@html $t("home.features.list")} -
- -
-

{$t("home.howtouse.title")}

- {@html $t("home.howtouse.list")} -
- -
-

{$t("home.testimonials.title")}

- {@html $t("home.testimonials.description")} -
- -
-

{$t("home.donation.title")}

- {@html $t("home.donation.description")} -

onNavigateTo(e, "/donate")} class="button">{$t("home.donation.cta")} – {$t("home.donation.cta.description")}

-
- - -
-

{$t("home.cta.title")}

-

onNavigateTo(e, "/viewer")} class="button">{$t("home.cta.cta")} – {@html $t("home.cta.cta.description")}

-
-
- - - - diff --git a/src/lib/pages/NotFound.svelte b/src/lib/pages/NotFound.svelte deleted file mode 100644 index a4c98be..0000000 --- a/src/lib/pages/NotFound.svelte +++ /dev/null @@ -1,2 +0,0 @@ -

404 - Not Found

-

Oops! That route does not exist.

\ No newline at end of file diff --git a/src/lib/pages/PrivacyPolicy.svelte b/src/lib/pages/PrivacyPolicy.svelte deleted file mode 100644 index 342c868..0000000 --- a/src/lib/pages/PrivacyPolicy.svelte +++ /dev/null @@ -1,25 +0,0 @@ - -
-

{$t('privacy.policy.title')}

-

{$t('privacy.policy.last.update')}

- - {@html $t('privacy.policy.content')} -
- - \ No newline at end of file diff --git a/src/lib/pages/TermsOfService.svelte b/src/lib/pages/TermsOfService.svelte deleted file mode 100644 index 0c53cb2..0000000 --- a/src/lib/pages/TermsOfService.svelte +++ /dev/null @@ -1,26 +0,0 @@ - - -
-

{$t('terms.of.service.title')}

-

{$t('terms.of.service.update')}

- - {@html $t('terms.of.service.content')} -
- - \ No newline at end of file diff --git a/src/lib/pages/Viewer.svelte b/src/lib/pages/Viewer.svelte deleted file mode 100644 index 6c33d10..0000000 --- a/src/lib/pages/Viewer.svelte +++ /dev/null @@ -1,4 +0,0 @@ - - \ No newline at end of file diff --git a/src/lib/sections/Head.svelte b/src/lib/sections/Head.svelte deleted file mode 100644 index 75d761f..0000000 --- a/src/lib/sections/Head.svelte +++ /dev/null @@ -1,16 +0,0 @@ - - - {$t("head.title")} - - - - - - - - \ No newline at end of file diff --git a/src/lib/sections/Main.svelte b/src/lib/sections/Main.svelte deleted file mode 100644 index 34ba389..0000000 --- a/src/lib/sections/Main.svelte +++ /dev/null @@ -1,14 +0,0 @@ - -
- -
- - diff --git a/src/lib/translations/en-US/about.json b/src/lib/translations/en-US/about.json new file mode 100644 index 0000000..65c7755 --- /dev/null +++ b/src/lib/translations/en-US/about.json @@ -0,0 +1,9 @@ +{ + "title": "ℹ About Embroidery Viewer", + "content": "

Hi there! 👋

⭐️ Embroidery Viewer was born out of a simple need — helping someone I care about. 💖

My girlfriend loves embroidery, but she often struggled to find an easy and free way to preview her embroidery design files before stitching them. Most tools she tried were either paid, overly complex, or required technical knowledge — and she’s not a techie.

So, to make things easier for her (and others like her), I decided to build this web application.

Over the course of a few weeks, I created Embroidery Viewer — a lightweight, fast, and free tool that lets you view embroidery files directly in your browser. No installation, no setup, and no tech hurdles. Just upload your file and see your design.

It’s not a super sophisticated tool, but it solves the problem it was meant to solve: making embroidery file previews accessible to everyone.

If this tool has helped you too, that makes me really happy! I plan to continue improving it based on feedback from users like you.

Thanks for stopping by — and happy stitching! 🧵✨

", + "seo.title": "ℹ About Embroidery Viewer – The Story Behind the Tool", + "seo.description": "Learn the story behind Embroidery Viewer — a free, online tool created to make embroidery file previews simple, fast, and accessible to everyone.", + "seo.keywords": "about embroidery viewer, embroidery viewer story, free embroidery viewer, why embroidery viewer was created, who created embroidery viewer, online embroidery viewer, free embroidery tool, embroidery viewer about", + "seo.url": "https://embroideryviewer.xyz/about", + "seo.image": "https://embroideryviewer.xyz/og/about.png" +} diff --git a/src/lib/translations/en-US/donate.json b/src/lib/translations/en-US/donate.json new file mode 100644 index 0000000..cd06fcc --- /dev/null +++ b/src/lib/translations/en-US/donate.json @@ -0,0 +1,18 @@ +{ + "title": "💖 Donate", + "subtitle": "Help support Embroidery Viewer and its development!", + "description": "⭐️ Embroidery Viewer is free to use. If you find this tool helpful, please consider making a donation to keep it running and fund future improvements.", + "ways": "💸 Ways to Donate", + "bitcoin.description": "Scan or copy the address", + "copy": "Copy Address", + "copied": "Copied to Clipboard!", + "copy.failed": "Copy Failed!", + "monero.description": "Private and secure donation option.", + "paypal.description": "Want to show support in a friendly way?", + "paypal.link": "Open Donation link", + "seo.title": "💖 Donate – Support Embroidery Viewer", + "seo.description": "Help keep Embroidery Viewer free and improving by making a donation. Choose from Bitcoin, Monero, PayPal, or other secure options to support ongoing development and hosting.", + "keywords": "donate embroidery viewer, support embroidery viewer, embroidery viewer donations, help embroidery viewer, fund embroidery viewer, bitcoin donation embroidery, monero donation embroidery, paypal donation embroidery", + "url": "https://embroideryviewer.xyz/donate", + "image": "https://embroideryviewer.xyz/og/donate.png" +} diff --git a/src/lib/translations/en-US/footer.json b/src/lib/translations/en-US/footer.json new file mode 100644 index 0000000..358478a --- /dev/null +++ b/src/lib/translations/en-US/footer.json @@ -0,0 +1,7 @@ +{ + "about": "ℹ About", + "privacy.policy": "🔐 Privacy Policy", + "terms.of.service": "📝 Terms of Service", + "copyright": "Copyright © {{year}} Leonardo Murça.
All rights reserved.", + "version": "🧵 Version: {{version}}" +} diff --git a/src/lib/translations/en-US/header.json b/src/lib/translations/en-US/header.json new file mode 100644 index 0000000..9ad8c6c --- /dev/null +++ b/src/lib/translations/en-US/header.json @@ -0,0 +1,7 @@ +{ + "languageSwitch": "🇧🇷", + "homeNav": "🏠 Home", + "aboutNav": "ℹ About", + "viewerNav": "🧵 Viewer", + "donateNav": "💖 Donate" +} diff --git a/src/lib/translations/en-US/home.json b/src/lib/translations/en-US/home.json new file mode 100644 index 0000000..79ff19f --- /dev/null +++ b/src/lib/translations/en-US/home.json @@ -0,0 +1,22 @@ +{ + "main.title": "🧵 Free Online Embroidery File Viewer", + "main.description": "

✨Upload and preview your embroidery designs instantly – no software needed.

Embroidery Viewer is a free, browser-based tool that supports multiple embroidery file formats. View your designs quickly and securely, right in your browser.

", + "features.title": "🚀 Features", + "features.list": "
  • 📂 Supports Multiple Formats: DST, PES, JEF, EXP, VP3, and more
  • Quick Previews: See your embroidery files rendered as images
  • 🧷 Multiple Files at Once: Upload several designs and view them side-by-side
  • 🔒 No Upload to Server: Your files stay private – all processing happens locally
  • ⬇️ Download as Image: Save each embroidery design preview as a PNG
  • 💸 Fast & Free: No installations, no sign-ups – just open and use
", + "howtouse.title": "📘 How to Use", + "howtouse.list": "
  1. 📁 Click the upload button or drag and drop your embroidery files into the drop area
  2. 🧵 Select one or more embroidery files
  3. ▶️ Click the “Render files” button to preview your designs
  4. 👀 Instantly view your designs right in your browser – it’s that simple
", + "testimonials.title": "❤️ Loved by Hobbyists and Professionals", + "testimonials.description": "

Whether you're a hobbyist working on your next DIY project or a professional digitizer reviewing client files, Embroidery Viewer gives you a no-fuss, instant way to visualize your work.

", + "donation.title": "💖 Help Keep It Free", + "donation.description": "

Embroidery Viewer is completely free for everyone to use.

If you find it useful and want to support ongoing development and hosting costs, please consider making a small donation.

", + "donation.cta": "🙌 Donate Now", + "donation.cta.description": "every little bit helps!", + "cta.title": "🚀 Try It Now", + "cta.cta": "🧵 Open Viewer", + "cta.cta.description": "the fastest Free Online Embroidery File Viewer.", + "seo.title": "🏠 Free Online Embroidery File Viewer - Fast, Private & No Signup", + "seo.description": "Upload and preview embroidery files instantly with Embroidery Viewer. Supports DST, PES, JEF, EXP, VP3 and more. No installs, no uploads – 100% browser-based and free.", + "seo.keywords": "embroidery viewer, online embroidery viewer, embroidery file preview, DST viewer, PES viewer, free embroidery tool, JEF viewer, EXP embroidery, VP3 embroidery viewer, embroidery preview tool, browser embroidery renderer, convert embroidery to PNG", + "seo.url": "https://embroideryviewer.xyz", + "seo.image": "https://embroideryviewer.xyz/og/" +} diff --git a/src/lib/translations/en-US/privacy-policy.json b/src/lib/translations/en-US/privacy-policy.json new file mode 100644 index 0000000..299c535 --- /dev/null +++ b/src/lib/translations/en-US/privacy-policy.json @@ -0,0 +1,10 @@ +{ + "title": "🔐 Privacy Policy", + "last.update": "Last updated: May 9, 2025", + "content": "

At Embroidery Viewer (embroideryviewer.xyz), we respect your privacy and are committed to protecting any information you share while using our service.

1. Personal Information

Embroidery Viewer does not collect or store any personal information. You do not need to create an account, and we do not ask for your name, email address, or any identifying details.

2. File Uploads

When you upload an embroidery file to the viewer, the file is processed in your browser or temporarily on our server (if required) for preview purposes only. No uploaded files are stored, saved, or shared.

Please avoid uploading any copyrighted or sensitive material unless you have permission to use it.

3. Analytics

We use Umami to collect anonymous usage statistics about our website, such as the number of visitors, page views, device types, and referral sources. This data helps us understand how the site is being used and improve it over time.

Umami is a privacy-friendly, cookie-free analytics tool. It does not track users across sites, collect personal data, or use cookies. All data is aggregated and anonymized.

4. Cookies

Embroidery Viewer does not use cookies or other tracking mechanisms in your browser.

5. Third-Party Services

We do not use third-party advertising, embed external trackers, or share data with third parties.

6. Changes to This Policy

We may update this Privacy Policy from time to time. All updates will be posted on this page with the updated date.

7. Contact

If you have any questions about this Privacy Policy, you can reach us at leo@leomurca.xyz.

", + "seo.title": "🔐 Privacy Policy - Embroidery Viewer", + "seo.description": "Learn how Embroidery Viewer respects your privacy. No personal data collected, files processed locally or temporarily, anonymous analytics only, no cookies or trackers used.", + "seo.keywords": "privacy policy, data protection, embroidery viewer privacy, file uploads privacy, anonymous analytics, no cookies, user privacy, privacy-friendly analytics, data security, embroideryviewer.xyz", + "seo.url": "https://embroideryviewer.xyz/privacy-policy", + "seo.image": "https://embroideryviewer.xyz/og/privacy-policy.png" +} diff --git a/src/lib/translations/en-US/terms-of-service.json b/src/lib/translations/en-US/terms-of-service.json new file mode 100644 index 0000000..e9ddbda --- /dev/null +++ b/src/lib/translations/en-US/terms-of-service.json @@ -0,0 +1,10 @@ +{ + "title": "📝 Terms of Service", + "update": "May 9, 2025", + "content": "

Welcome to Embroidery Viewer (embroideryviewer.xyz). By accessing or using this website, you agree to be bound by the following Terms of Service. If you do not agree with any part of these terms, please do not use the site.

1. Description of Service

Embroidery Viewer is a free, browser-based tool that allows users to preview embroidery design files online. The service is intended for personal, non-commercial use.

2. Use of the Service

You agree to use the service only for lawful purposes. You are solely responsible for any content (including embroidery files) you upload, and you confirm that you have the legal right to use, view, and process those files.

You agree not to upload any files that are illegal, offensive, infringe on intellectual property rights, or contain malicious code.

3. File Processing

Files uploaded to Embroidery Viewer are processed either directly in your browser or temporarily on our servers. Files are not stored permanently, shared, or backed up.

While we aim to keep your content secure, you acknowledge that no system is 100% secure and you use the service at your own risk.

4. No Warranty

This service is provided \"as is\" and \"as available\" without any warranties, express or implied. We do not guarantee that the service will be uninterrupted, secure, or error-free.

5. Limitation of Liability

Embroidery Viewer shall not be held liable for any damages resulting from the use or inability to use the service, including but not limited to loss of data, loss of profits, or other incidental or consequential damages.

6. Modifications to the Service

We reserve the right to modify, suspend, or discontinue the service at any time without notice. We may also update these Terms of Service from time to time. Continued use of the service after changes constitutes your acceptance of the new terms.

7. Governing Law

These Terms shall be governed by and interpreted in accordance with the laws of Brazil, without regard to its conflict of law principles.

8. Contact

If you have any questions about these Terms of Service, feel free to contact us at leo@leomurca.xyz.

", + "seo.title": "📝 Terms of Service - Embroidery Viewer", + "seo.description": "Read the Terms of Service for Embroidery Viewer. Personal use, upload rules, file processing, warranty disclaimers, liability limitations, and governing law.", + "seo.keywords": "terms of service, terms of use, personal use, file upload, file processing, warranty disclaimer, liability limitation, Brazilian law, embroideryviewer.xyz", + "seo.url": "https://embroideryviewer.xyz/terms-of-service", + "seo.image": "https://embroideryviewer.xyz/og/terms-of-service.png" +} diff --git a/src/lib/translations/en-US/viewer.json b/src/lib/translations/en-US/viewer.json new file mode 100644 index 0000000..e5aca5d --- /dev/null +++ b/src/lib/translations/en-US/viewer.json @@ -0,0 +1,19 @@ +{ + "title": "Upload files", + "fileSize": "Max file size is {{fileSize}}MB.", + "supportedFormats": "Accepted formats: {{supportedFormats}}.", + "render": "Render files", + "dropzone": "Choose files
or drag and drop them here", + "browse": "Browse", + "selected": "Selected files", + "rejected": "Rejected files", + "stitches": "Stitches", + "dimensions": "Dimensions (x, y)", + "download": "Download image", + "warning.copyright": "Do not upload copyrighted material you do not own or have rights to.", + "seo.title": "🧵 Free Online Embroidery File Viewer – Fast, Private & No Signup", + "seo.description": "Upload and preview your embroidery files instantly with Embroidery Viewer. Supports DST, PES, JEF, EXP, VP3, and more. No installs, no uploads – 100% browser-based and free.", + "seo.keywords": "embroidery viewer, online embroidery viewer, embroidery file preview, DST viewer, PES viewer, free embroidery tool, JEF viewer, EXP embroidery, VP3 embroidery viewer, embroidery preview tool, browser embroidery renderer, convert embroidery to PNG", + "seo.url": "https://embroideryviewer.xyz/viewer", + "seo.image": "https://embroideryviewer.xyz/og/viewer.png" +} diff --git a/src/lib/translations/index.js b/src/lib/translations/index.js new file mode 100644 index 0000000..c7f0e62 --- /dev/null +++ b/src/lib/translations/index.js @@ -0,0 +1,133 @@ +import i18n from 'sveltekit-i18n'; + +/** + * A frozen object mapping locale identifiers to their respective locale codes. + * + * These values represent the supported languages in the application. + * Used for validating user preferences and loading the correct translations. + * + * @readonly + * @enum {string} + */ +export const SUPPORTED_LOCALES = Object.freeze({ + EN_US: 'en-US', + PT_BR: 'pt-BR', +}); + +/** @type {import('sveltekit-i18n').Config} */ +const config = { + initLocale: navigator.language, + fallbackLocale: SUPPORTED_LOCALES.EN_US, + loaders: [ + { + locale: SUPPORTED_LOCALES.EN_US, + key: 'header', + loader: async () => (await import('./en-US/header.json')).default, + }, + { + locale: SUPPORTED_LOCALES.EN_US, + key: 'footer', + loader: async () => (await import('./en-US/footer.json')).default, + }, + { + locale: SUPPORTED_LOCALES.EN_US, + key: 'home', + routes: ['/'], + loader: async () => (await import('./en-US/home.json')).default, + }, + { + locale: SUPPORTED_LOCALES.EN_US, + key: 'about', + routes: ['/about'], + loader: async () => (await import('./en-US/about.json')).default, + }, + { + locale: SUPPORTED_LOCALES.EN_US, + key: 'donate', + routes: ['/donate'], + loader: async () => (await import('./en-US/donate.json')).default, + }, + { + locale: SUPPORTED_LOCALES.EN_US, + key: 'privacy.policy', + routes: ['/privacy-policy'], + loader: async () => (await import('./en-US/privacy-policy.json')).default, + }, + { + locale: SUPPORTED_LOCALES.EN_US, + key: 'terms.of.service', + routes: ['/terms-of-service'], + loader: async () => + (await import('./en-US/terms-of-service.json')).default, + }, + { + locale: SUPPORTED_LOCALES.EN_US, + key: 'viewer', + routes: ['/viewer'], + loader: async () => (await import('./en-US/viewer.json')).default, + }, + { + locale: SUPPORTED_LOCALES.PT_BR, + key: 'header', + loader: async () => (await import('./pt-BR/header.json')).default, + }, + { + locale: SUPPORTED_LOCALES.PT_BR, + key: 'footer', + loader: async () => (await import('./pt-BR/footer.json')).default, + }, + { + locale: SUPPORTED_LOCALES.PT_BR, + key: 'home', + routes: ['/'], + loader: async () => (await import('./pt-BR/home.json')).default, + }, + { + locale: SUPPORTED_LOCALES.PT_BR, + key: 'about', + routes: ['/about'], + loader: async () => (await import('./pt-BR/about.json')).default, + }, + { + locale: SUPPORTED_LOCALES.PT_BR, + key: 'donate', + routes: ['/donate'], + loader: async () => (await import('./pt-BR/donate.json')).default, + }, + { + locale: SUPPORTED_LOCALES.PT_BR, + key: 'privacy.policy', + routes: ['/privacy-policy'], + loader: async () => (await import('./pt-BR/privacy-policy.json')).default, + }, + { + locale: SUPPORTED_LOCALES.PT_BR, + key: 'terms.of.service', + routes: ['/terms-of-service'], + loader: async () => + (await import('./pt-BR/terms-of-service.json')).default, + }, + { + locale: SUPPORTED_LOCALES.PT_BR, + key: 'viewer', + routes: ['/viewer'], + loader: async () => (await import('./pt-BR/viewer.json')).default, + }, + ], +}; + +export const { + t, + locale, + locales, + loading, + loadTranslations, + setRoute, + setLocale, +} = new i18n(config); + +locale.subscribe(($locale) => { + if (typeof document !== 'undefined') { + document.cookie = `locale=${$locale}; path=/; SameSite=Strict;`; + } +}); diff --git a/src/lib/translations/pt-BR/about.json b/src/lib/translations/pt-BR/about.json new file mode 100644 index 0000000..f958e8f --- /dev/null +++ b/src/lib/translations/pt-BR/about.json @@ -0,0 +1,9 @@ +{ + "title": "ℹ Sobre o Embroidery Viewer", + "content": "

Oi! 👋

⭐️ Embroidery Viewer nasceu de uma necessidade simples — ajudar alguém que eu amo. 💖

Minha namorada adora bordado, mas ela sempre teve dificuldades para encontrar uma maneira fácil e gratuita de visualizar os arquivos de design de bordado antes de começar a costurar. A maioria das ferramentas que ela tentou eram pagas, muito complexas ou exigiam conhecimento técnico — e ela não é da área de tecnologia.

Então, para facilitar a vida dela (e de outras pessoas como ela), decidi criar este aplicativo web.

Ao longo de algumas semanas, criei o Embroidery Viewer — uma ferramenta leve, rápida e gratuita que permite visualizar arquivos de bordado diretamente no navegador. Sem instalação, sem configuração e sem obstáculos técnicos. Basta enviar o arquivo e ver o design.

Não é uma ferramenta super sofisticada, mas resolve o problema para o qual foi criada: tornar a visualização de arquivos de bordado acessível para todos.

Se essa ferramenta também te ajudou, isso me deixa muito feliz! Pretendo continuar melhorando com base no feedback de usuários como você.

Obrigado por visitar — e bons bordados! 🧵✨

", + "seo.title": "ℹSobre o Embroidery Viewer - Por que esta ferramenta foi criada", + "seo.description": "Conheça a história por trás do Embroidery Viewer — uma ferramenta gratuita e online criada para tornar a visualização de arquivos de bordado simples, rápida e acessível a todos.", + "seo.keywords": "sobre embroidery viewer, história do embroidery viewer, visualizador de bordado gratuito, motivo da criação do embroidery viewer, quem criou o embroidery viewer, visualizador online de bordado, ferramenta gratuita para bordado, embroidery viewer sobre", + "seo.url": "https://embroideryviewer.xyz/about", + "seo.image": "https://embroideryviewer.xyz/og/about.png" +} diff --git a/src/lib/translations/pt-BR/donate.json b/src/lib/translations/pt-BR/donate.json new file mode 100644 index 0000000..2457d3a --- /dev/null +++ b/src/lib/translations/pt-BR/donate.json @@ -0,0 +1,18 @@ +{ + "title": "💖 Doe", + "subtitle": "Ajude a apoiar o Embroidery Viewer e seu desenvolvimento!", + "description": "⭐️ O Embroidery Viewer é gratuito. Se você achar esta ferramenta útil, considere fazer uma doação para mantê-la funcionando e financiar melhorias futuras.", + "ways": "💸 Formas de doar", + "bitcoin.description": "Escaneie ou copie o endereço", + "copy": "Copiar Endereço", + "copied": "Copiado para a área de transferência!", + "copy.failed": "Falha na Cópia!", + "monero.description": "Opção de doação privada e segura.", + "paypal.description": "Quer demonstrar apoio de uma forma amigável?", + "paypal.link": "Abrir Link de Doação", + "seo.title": "💖 Doe – Apoie o Embroidery Viewer", + "seo.description": "Ajude a manter o Embroidery Viewer gratuito e em constante melhoria fazendo uma doação. Escolha entre Bitcoin, Monero, PayPal ou outras opções seguras para apoiar o desenvolvimento e hospedagem.", + "seo.keywords": "doar embroidery viewer, apoie embroidery viewer, doações embroidery viewer, ajudar embroidery viewer, financiar embroidery viewer, doação bitcoin embroidery, doação monero embroidery, doação paypal embroidery", + "url": "https://embroideryviewer.xyz/doar", + "image": "https://embroideryviewer.xyz/og/doar.png" +} diff --git a/src/lib/translations/pt-BR/footer.json b/src/lib/translations/pt-BR/footer.json new file mode 100644 index 0000000..922d643 --- /dev/null +++ b/src/lib/translations/pt-BR/footer.json @@ -0,0 +1,7 @@ +{ + "about": "ℹ Sobre", + "privacy.policy": "🔐 Política de Privacidade", + "terms.of.service": "📝 Termos de Serviço", + "copyright": "Copyright © {{year}} Leonardo Murça.
Todos os direitos reservados.", + "version": "🧵 Versão: {{version}}" +} diff --git a/src/lib/translations/pt-BR/header.json b/src/lib/translations/pt-BR/header.json new file mode 100644 index 0000000..b47bfff --- /dev/null +++ b/src/lib/translations/pt-BR/header.json @@ -0,0 +1,7 @@ +{ + "languageSwitch": "🇺🇸", + "homeNav": "🏠 Página Inicial", + "aboutNav": "ℹ Sobre", + "viewerNav": "🧵 Visualizador", + "donateNav": "💖 Doe" +} diff --git a/src/lib/translations/pt-BR/home.json b/src/lib/translations/pt-BR/home.json new file mode 100644 index 0000000..08cca9a --- /dev/null +++ b/src/lib/translations/pt-BR/home.json @@ -0,0 +1,22 @@ +{ + "main.title": "🧵 Visualizador de arquivos de bordado online gratuito", + "main.description": "

✨Carregue e visualize seus desenhos de bordado instantaneamente – sem necessidade de software

Embroidery Viewer é uma ferramenta gratuita para navegador que suporta diversos formatos de arquivo de bordado. Visualize seus designs de forma rápida e segura, diretamente no seu navegador.

", + "features.title": "🚀 Funcionalidades", + "features.list": "
  • 📂 Suporta vários formatos: DST, PES, JEF, EXP, VP3 e mais
  • Visualizações rápidas: Veja seus arquivos de bordado renderizados como imagens
  • 🧷 Vários arquivos de uma só vez: Carregue vários designs e visualize-os lado a lado
  • 🔒 Sem upload para o servidor: Seus arquivos permanecem privados – todo o processamento acontece localmente
  • ⬇️ Baixar como imagem: Salve cada pré-visualização do desenho do bordado como um PNG
  • 💸 Rápido e gratuito: Sem instalações, sem cadastros – basta abrir e usar
", + "howtouse.title": "📘 Como usar", + "howtouse.list": "
  1. 📁 Clique no botão de upload ou arraste e solte seus arquivos de bordado na área de soltar
  2. 🧵 Selecione um ou mais arquivos de bordado
  3. ▶️ Clique no botão “Renderizar arquivos” para visualizar seus designs
  4. 👀 Visualize seus designs instantaneamente no seu navegador – é simples assim
", + "testimonials.title": "❤️ Amado por Hobbyistas e Profissionais", + "testimonials.description": "

Seja você um amador trabalhando em seu próximo projeto \"faça você mesmo\" ou um digitalizador profissional revisando arquivos de clientes, o Embroidery Viewer oferece uma maneira fácil e instantânea de visualizar seu trabalho.

", + "donation.title": "💖 Ajude a mantê-lo gratuito", + "donation.description": "

O Embroidery Viewer é totalmente gratuito para todos usarem.

Se você o achar útil e quiser apoiar o desenvolvimento contínuo e os custos de hospedagem, considere fazer uma pequena doação.

", + "donation.cta": "🙌 Doe agora", + "donation.cta.description": "cada pequena ajuda é bem-vinda!", + "cta.title": "🚀 Experimente agora", + "cta.cta": "🧵 Abrir visualizador", + "cta.cta.description": "o visualizador de arquivos de bordado online gratuito mais rápido.", + "seo.title": "🏠 Visualizador de Bordado Online Grátis - Rápido, Privado e Sem Cadastro", + "seo.description": "Envie e visualize arquivos de bordado instantaneamente com o Embroidery Viewer. Compatível com DST, PES, JEF, EXP, VP3 e mais. Sem instalações, sem uploads – 100% no navegador e gratuito.", + "seo.keywords": "visualizador de bordado, visualizador online de bordado, visualizar arquivos de bordado, visualizar DST, visualizar PES, ferramenta gratuita de bordado, visualizador JEF, bordado EXP, visualizador VP3, pré-visualização de bordado, renderizador de bordado no navegador, converter bordado em PNG", + "seo.url": "https://embroideryviewer.xyz", + "seo.image": "https://embroideryviewer.xyz/og/" +} diff --git a/src/lib/translations/pt-BR/privacy-policy.json b/src/lib/translations/pt-BR/privacy-policy.json new file mode 100644 index 0000000..fcf0247 --- /dev/null +++ b/src/lib/translations/pt-BR/privacy-policy.json @@ -0,0 +1,10 @@ +{ + "title": "🔐 Política de Privacidade", + "last.update": "Última atualização: 9 de maio de 2025", + "content": "

No Embroidery Viewer (embroideryviewer.xyz), respeitamos sua privacidade e estamos comprometidos em proteger qualquer informação que você compartilhe ao usar nosso serviço.

1. Informações Pessoais

O Embroidery Viewer não coleta nem armazena informações pessoais. Você não precisa criar uma conta e não pedimos seu nome, e-mail ou qualquer dado identificável.

2. Envio de Arquivos

Quando você envia um arquivo de bordado para o visualizador, o arquivo é processado no seu navegador ou temporariamente em nosso servidor (se necessário) apenas para fins de visualização. Nenhum arquivo enviado é armazenado, salvo ou compartilhado.

Evite enviar materiais sensíveis ou protegidos por direitos autorais, a menos que tenha permissão para usá-los.

3. Análises

Utilizamos o Umami para coletar estatísticas anônimas de uso do site, como número de visitantes, visualizações de página, tipos de dispositivo e fontes de acesso. Esses dados nos ajudam a entender como o site está sendo utilizado e melhorá-lo com o tempo.

O Umami é uma ferramenta de análise que respeita a privacidade, não usa cookies e não rastreia os usuários entre sites. Todos os dados são agregados e anonimizados.

4. Cookies

O Embroidery Viewer não utiliza cookies ou outros mecanismos de rastreamento em seu navegador.

5. Serviços de Terceiros

Não utilizamos publicidade de terceiros, nem incorporamos rastreadores externos, nem compartilhamos dados com terceiros.

6. Alterações nesta Política

Podemos atualizar esta Política de Privacidade ocasionalmente. Todas as atualizações serão publicadas nesta página com a data de modificação.

7. Contato

Se você tiver dúvidas sobre esta Política de Privacidade, entre em contato pelo e-mail leo@leomurca.xyz.

", + "seo.title": "🔐 Política de Privacidade - Embroidery Viewer", + "seo.description": "Saiba como o Embroidery Viewer respeita sua privacidade. Nenhum dado pessoal é coletado, arquivos processados localmente ou temporariamente, análises anônimas, sem cookies ou rastreadores.", + "seo.keywords": "política de privacidade, proteção de dados, privacidade embroidery viewer, upload de arquivos, análises anônimas, sem cookies, privacidade do usuário, análises que respeitam a privacidade, segurança de dados, embroideryviewer.xyz", + "seo.url": "https://embroideryviewer.xyz/privacy-policy", + "seo.image": "https://embroideryviewer.xyz/og/privacy-policy.png" +} diff --git a/src/lib/translations/pt-BR/terms-of-service.json b/src/lib/translations/pt-BR/terms-of-service.json new file mode 100644 index 0000000..07e4914 --- /dev/null +++ b/src/lib/translations/pt-BR/terms-of-service.json @@ -0,0 +1,10 @@ +{ + "title": "📝 Termos de Serviço", + "update": "Última atualização: 9 de maio de 2025", + "content": "

Bem-vindo ao Embroidery Viewer (embroideryviewer.xyz). Ao acessar ou utilizar este site, você concorda em estar vinculado aos seguintes Termos de Serviço. Se você não concordar com qualquer parte destes termos, por favor, não utilize o site.

1. Descrição do Serviço

O Embroidery Viewer é uma ferramenta gratuita baseada em navegador que permite aos usuários visualizar arquivos de design de bordado online. O serviço é destinado ao uso pessoal e não comercial.

2. Uso do Serviço

Você concorda em usar o serviço apenas para fins legais. Você é o único responsável por qualquer conteúdo (incluindo arquivos de bordado) que enviar, e confirma que tem o direito legal de usar, visualizar e processar esses arquivos.

Você concorda em não enviar arquivos que sejam ilegais, ofensivos, infrinjam direitos de propriedade intelectual ou contenham código malicioso.

3. Processamento de Arquivos

Os arquivos enviados para o Embroidery Viewer são processados diretamente em seu navegador ou temporariamente em nossos servidores. Os arquivos não são armazenados permanentemente, compartilhados ou backupados.

Embora tenhamos o objetivo de manter seu conteúdo seguro, você reconhece que nenhum sistema é 100% seguro e você utiliza o serviço por sua conta e risco.

4. Sem Garantia

Este serviço é fornecido \"como está\" e \"como disponível\", sem quaisquer garantias, expressas ou implícitas. Não garantimos que o serviço será ininterrupto, seguro ou sem erros.

5. Limitação de Responsabilidade

O Embroidery Viewer não será responsabilizado por quaisquer danos resultantes do uso ou da impossibilidade de usar o serviço, incluindo, mas não se limitando a, perda de dados, perda de lucros ou outros danos incidentais ou consequenciais.

6. Modificações no Serviço

Reservamo-nos o direito de modificar, suspender ou descontinuar o serviço a qualquer momento, sem aviso prévio. Podemos também atualizar estes Termos de Serviço de tempos em tempos. O uso contínuo do serviço após as mudanças constitui sua aceitação dos novos termos.

7. Lei Aplicável

Estes Termos serão regidos e interpretados de acordo com as leis do Brasil, sem levar em consideração seus princípios de conflitos de leis.

8. Contato

Se você tiver qualquer dúvida sobre estes Termos de Serviço, sinta-se à vontade para entrar em contato conosco pelo e-mail leo@leomurca.xyz.

", + "seo.title": "📝 Termos de Serviço - Embroidery Viewer", + "seo.description": "Leia os Termos de Serviço do Embroidery Viewer. Uso pessoal, regras de upload, processamento de arquivos, isenção de garantias, limitações de responsabilidade e legislação aplicável.", + "seo.keywords": "termos de serviço, condições de uso, uso pessoal, upload de arquivos, processamento de arquivos, isenção de garantias, limitações de responsabilidade, legislação brasileira, embroideryviewer.xyz", + "seo.url": "https://embroideryviewer.xyz/termos-de-servico", + "seo.image": "https://embroideryviewer.xyz/og/termos-de-servico.png" +} diff --git a/src/lib/translations/pt-BR/viewer.json b/src/lib/translations/pt-BR/viewer.json new file mode 100644 index 0000000..8571678 --- /dev/null +++ b/src/lib/translations/pt-BR/viewer.json @@ -0,0 +1,19 @@ +{ + "title": "Carregar arquivos", + "languageSwitch": "🇺🇸", + "fileSize": "O tamanho máximo de cada arquivo é {{fileSize}}MB.", + "supportedFormats": "Formatos aceitos: {{supportedFormats}}.", + "render": "Renderizar arquivos", + "dropzone": "Selecione arquivos
ou arraste e solte-os aqui", + "browse": "Selecionar arquivos", + "selected": "Arquivos selecionados", + "rejected": "Arquivos recusados", + "stitches": "Pontos", + "download": "Baixar imagem", + "warning.copyright": "Não carregue material protegido por direitos autorais que você não possui ou sobre os quais não tenha direitos.", + "seo.title": "🧵 Visualizador Online Gratuito de Arquivos de Bordado – Rápido, Privado e Sem Cadastro", + "seo.description": "Faça upload e visualize seus arquivos de bordado instantaneamente com o Embroidery Viewer. Suporta DST, PES, JEF, EXP, VP3 e muito mais. Sem instalações, sem upload para servidor – 100% baseado no navegador e gratuito.", + "seo.keywords": "visualizador de bordado, visualizador online de bordado, pré-visualização de arquivos de bordado, visualizador DST, visualizador PES, ferramenta gratuita de bordado, visualizador JEF, bordado EXP, visualizador VP3, ferramenta de pré-visualização de bordado, renderizador de bordado no navegador, converter bordado para PNG", + "seo.url": "https://embroideryviewer.xyz/viewer", + "seo.image": "https://embroideryviewer.xyz/og/viewer.png" +} diff --git a/src/utils/env.js b/src/lib/utils/env.js similarity index 73% rename from src/utils/env.js rename to src/lib/utils/env.js index 9734172..5dde7bb 100644 --- a/src/utils/env.js +++ b/src/lib/utils/env.js @@ -1,5 +1,6 @@ // @ts-nocheck function appVersion() { + /* eslint-disable no-undef */ return APP_VERSION; } diff --git a/src/lib/utils/filterFiles.js b/src/lib/utils/filterFiles.js new file mode 100644 index 0000000..2ab97f1 --- /dev/null +++ b/src/lib/utils/filterFiles.js @@ -0,0 +1,47 @@ +/** + * Returns the lowercase file extension (including dot) of a filename. + * @param {string} name - The name of the file. + * @returns {string} The file extension, e.g., ".png" + */ +const formattedFilenameExt = (name) => { + const parts = typeof name === 'string' ? name.split('.') : []; + const ext = parts.length > 1 ? parts.pop() : ''; + return ext ? `.${ext.toLowerCase()}` : ''; +}; + +/** + * Checks whether a file meets the size and format requirements. + * @param {{ maxSize: number, supportedFormats: string[] }} requirements + * @param {File} file + * @returns {boolean} + */ +const areRequirementsFulfilled = (requirements, file) => { + return ( + file.size <= requirements.maxSize && + requirements.supportedFormats.includes(formattedFilenameExt(file.name)) + ); +}; + +/** + * Filters a list of files into accepted and rejected based on requirements. + * @param {FileList | File[]} files - The list of files to filter. + * @param {{ maxSize: number, supportedFormats: string[] }} requirements + * @returns {{ accepted: File[], rejected: File[] }} + */ +export function filterFiles(files, requirements) { + /** @type {File[]} */ + const accepted = []; + + /** @type {File[]} */ + const rejected = []; + + for (const file of Array.from(files)) { + if (file && areRequirementsFulfilled(requirements, file)) { + accepted.push(file); + } else { + rejected.push(file); + } + } + + return { accepted, rejected }; +} diff --git a/src/lib/utils/rgbToHex.js b/src/lib/utils/rgbToHex.js new file mode 100644 index 0000000..a429cbc --- /dev/null +++ b/src/lib/utils/rgbToHex.js @@ -0,0 +1,25 @@ +/** + * Converts a single color component to a 2-digit hexadecimal string. + * @param {number} c - A number between 0 and 255. + * @returns {string} The 2-digit hex representation. + */ +const componentToHex = (c) => { + const hex = c.toString(16); + return hex.length === 1 ? '0' + hex : hex; +}; + +/** + * Converts an RGB object to a hexadecimal color string. + * @param {{ r: number, g: number, b: number }} color - An object with r, g, and b properties (0–255). + * @returns {string} The hex color string (e.g., "#ffcc00"). + */ +const rgbToHex = (color) => { + return ( + '#' + + componentToHex(color.r) + + componentToHex(color.g) + + componentToHex(color.b) + ); +}; + +export { rgbToHex }; diff --git a/src/lib/utils/shadeColor.js b/src/lib/utils/shadeColor.js new file mode 100644 index 0000000..d92345c --- /dev/null +++ b/src/lib/utils/shadeColor.js @@ -0,0 +1,27 @@ +/** + * Shades a hex color by a given percentage. + * Positive values lighten the color, negative values darken it. + * + * @param {string} color - A 7-character hex color string (e.g. "#ffcc00"). + * @param {number} percent - A percentage from -100 to 100 to adjust brightness. + * @returns {string} - The adjusted hex color string. + */ +function shadeColor(color, percent) { + const num = parseInt(color.slice(1), 16); + const amt = Math.round(2.55 * percent); + + let r = (num >> 16) + amt; + let g = ((num >> 8) & 0xff) + amt; + let b = (num & 0xff) + amt; + + // Clamp each component between 0 and 255 + r = Math.min(255, Math.max(0, r)); + g = Math.min(255, Math.max(0, g)); + b = Math.min(255, Math.max(0, b)); + + const shaded = (1 << 24) + (r << 16) + (g << 8) + b; + + return `#${shaded.toString(16).slice(1)}`; +} + +export { shadeColor }; diff --git a/src/main.js b/src/main.js deleted file mode 100644 index 990889d..0000000 --- a/src/main.js +++ /dev/null @@ -1,9 +0,0 @@ -import { mount } from 'svelte'; -import App from './App.svelte'; -import "./app.css"; - -const app = mount(App, { - target: document.getElementById('app'), -}); - -export default app; \ No newline at end of file diff --git a/src/routes/+layout.js b/src/routes/+layout.js new file mode 100644 index 0000000..89b2c80 --- /dev/null +++ b/src/routes/+layout.js @@ -0,0 +1,17 @@ +import { setLocale, setRoute } from '$lib/translations'; + +/** + * @typedef {Object} LayoutData + * @property {string} route + * @property {string} language + */ + +/** @type {import('@sveltejs/kit').Load} */ +export const load = async ({ data }) => { + const { route, language } = data ?? {}; + + if (route) await setRoute(route); + if (language) await setLocale(language); + + return data ?? {}; +}; diff --git a/src/routes/+layout.server.js b/src/routes/+layout.server.js new file mode 100644 index 0000000..195496e --- /dev/null +++ b/src/routes/+layout.server.js @@ -0,0 +1,54 @@ +import { parse } from 'accept-language-parser'; +import { loadTranslations, setLocale, setRoute } from '$lib/translations'; +import { SUPPORTED_LOCALES } from '$lib/translations'; + +/** + * A set of all supported locale codes, used to validate and match against + * user preferences from cookies or Accept-Language headers. We're using a + * Set for better performance in lookup. + * + * Example values: "en-US", "pt-BR" + * @type {Set} + */ +const SUPPORTED_LOCALE_SET = new Set(Object.values(SUPPORTED_LOCALES)); + +/** + * Returns a valid locale from cookies, or null if not valid/found. + * @param {{ get: (cookies: string) => any; }} cookies + */ +function localeFromCookies(cookies) { + const locale = cookies.get('locale'); + return locale && SUPPORTED_LOCALE_SET.has(locale) ? locale : null; +} + +/** + * Parses the Accept-Language header and returns the best matching locale. + * @param {string | null | undefined} header + */ +function localeFromHeader(header) { + if (!header) return null; + + const parsedLanguages = parse(header); + for (const { code, region } of parsedLanguages) { + const locale = region ? `${code}-${region}` : code; + if (SUPPORTED_LOCALE_SET.has(locale)) { + return locale; + } + } + + return null; +} + +/** @type {import('@sveltejs/kit').ServerLoad}*/ +export async function load({ url, request, cookies }) { + const cookieLocale = localeFromCookies(cookies); + const headerLocale = localeFromHeader(request.headers.get('accept-language')); + const language = cookieLocale || headerLocale || SUPPORTED_LOCALES.EN_US; + const route = url.pathname; + + await loadTranslations(language, route); + setLocale(language); + setRoute(route); + + return { language, route }; +} diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte new file mode 100644 index 0000000..324a7d4 --- /dev/null +++ b/src/routes/+layout.svelte @@ -0,0 +1,18 @@ + + +
+
+ +
+