├── .npmrc ├── playground ├── .npmrc ├── src │ ├── lib │ │ └── index.ts │ ├── routes │ │ ├── +layout.svelte │ │ ├── debounce │ │ │ └── +page.svelte │ │ ├── default │ │ │ └── +page.svelte │ │ ├── equalityFn │ │ │ └── +page.svelte │ │ ├── queryparameters │ │ │ └── +page.svelte │ │ └── +page.svelte │ ├── app.d.ts │ └── app.html ├── static │ └── favicon.png ├── vite.config.ts ├── .gitignore ├── tsconfig.json ├── svelte.config.js ├── package.json ├── README.md └── pnpm-lock.yaml ├── src ├── routes │ ├── +layout.server.ts │ ├── BrowserWindow.svelte │ └── +page.svelte ├── lib │ ├── index.ts │ ├── plugin.ts │ ├── lz-string │ │ └── index.js │ └── sveltekit-search-params.ts ├── app.html ├── app.d.ts └── assets │ └── fonts.css ├── .github ├── FUNDING.yml ├── workflows │ ├── run-tests.yml │ └── release.yml └── ISSUE_TEMPLATE │ ├── feature_request.yaml │ └── bug_report.yaml ├── static ├── favicon.png ├── Segoe UI.woff └── Segoe UI Bold.woff ├── .gitignore ├── .eslintignore ├── vite.config.ts ├── .prettierrc.json ├── .changeset ├── config.json └── README.md ├── playwright.config.ts ├── svelte.config.js ├── .eslintrc.cjs ├── tsconfig.json ├── LICENSE ├── tests ├── extends.ts └── index.test.ts ├── CHANGELOG.md ├── package.json ├── CODE_OF_CONDUCT.md └── README.md /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /playground/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /src/routes/+layout.server.ts: -------------------------------------------------------------------------------- 1 | export const prerender = true; 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: paoloricciuti 4 | -------------------------------------------------------------------------------- /static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoR/sveltekit-search-params/master/static/favicon.png -------------------------------------------------------------------------------- /playground/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | // place files you want to import through the `$lib` alias in this folder. 2 | -------------------------------------------------------------------------------- /static/Segoe UI.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoR/sveltekit-search-params/master/static/Segoe UI.woff -------------------------------------------------------------------------------- /static/Segoe UI Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoR/sveltekit-search-params/master/static/Segoe UI Bold.woff -------------------------------------------------------------------------------- /playground/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoR/sveltekit-search-params/master/playground/static/favicon.png -------------------------------------------------------------------------------- /src/lib/index.ts: -------------------------------------------------------------------------------- 1 | // Reexport your entry components here 2 | export { ssp, queryParameters, queryParam } from './sveltekit-search-params.js'; 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Local Netlify folder 11 | .netlify 12 | test-results -------------------------------------------------------------------------------- /playground/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | import { defineConfig } from 'vite'; 3 | 4 | export default defineConfig({ 5 | plugins: [sveltekit()], 6 | }); 7 | -------------------------------------------------------------------------------- /playground/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | vite.config.js.timestamp-* 10 | vite.config.ts.timestamp-* 11 | -------------------------------------------------------------------------------- /playground/src/routes/+layout.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | import { defineConfig } from 'vitest/config'; 3 | 4 | export default defineConfig({ 5 | plugins: [sveltekit()], 6 | test: { 7 | include: ['src/**/*.{test,spec}.{js,ts}'], 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "tabWidth": 4, 4 | "useTabs": true, 5 | "semi": true, 6 | "singleQuote": true, 7 | "plugins": ["prettier-plugin-svelte"], 8 | "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] 9 | } 10 | -------------------------------------------------------------------------------- /playground/src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://kit.svelte.dev/docs/types#app 2 | // for information about these interfaces 3 | declare global { 4 | namespace App { 5 | // interface Error {} 6 | // interface Locals {} 7 | // interface PageData {} 8 | // interface Platform {} 9 | } 10 | } 11 | 12 | export {}; 13 | -------------------------------------------------------------------------------- /src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %sveltekit.head% 8 | 9 | 10 |
%sveltekit.body%
11 | 12 | 13 | -------------------------------------------------------------------------------- /src/app.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | // See https://kit.svelte.dev/docs/types#app 4 | // for information about these interfaces 5 | // and what to do when importing types 6 | declare namespace App { 7 | // interface Locals {} 8 | // interface PageData {} 9 | // interface Error {} 10 | // interface Platform {} 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/plugin.ts: -------------------------------------------------------------------------------- 1 | import type { Plugin } from 'vite'; 2 | 3 | export function ssp(): Plugin { 4 | return { 5 | name: 'vite-plugin-sveltekit-search-params', 6 | config: () => ({ 7 | optimizeDeps: { 8 | exclude: ['sveltekit-search-params'], 9 | }, 10 | ssr: { 11 | noExternal: ['sveltekit-search-params'], 12 | }, 13 | }), 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /playground/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %sveltekit.head% 8 | 9 | 10 |
%sveltekit.body%
11 | 12 | 13 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json", 3 | "changelog": [ 4 | "@svitejs/changesets-changelog-github-compact", 5 | { "repo": "paoloricciuti/sveltekit-search-params" } 6 | ], 7 | "commit": false, 8 | "fixed": [], 9 | "linked": [], 10 | "access": "public", 11 | "baseBranch": "master", 12 | "updateInternalDependencies": "patch", 13 | "ignore": [] 14 | } 15 | -------------------------------------------------------------------------------- /playwright.config.ts: -------------------------------------------------------------------------------- 1 | import type { PlaywrightTestConfig } from '@playwright/test'; 2 | 3 | const config: PlaywrightTestConfig = { 4 | webServer: { 5 | command: 6 | 'pnpm run build && pnpm run build:playground && pnpm run preview:playground', 7 | port: 4173, 8 | stderr: 'pipe', 9 | stdout: 'pipe', 10 | }, 11 | testDir: 'tests', 12 | testMatch: /(.+\.)?(test|spec)\.[jt]s/, 13 | }; 14 | 15 | export default config; 16 | -------------------------------------------------------------------------------- /svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-static'; 2 | import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; 3 | 4 | /** @type {import('@sveltejs/kit').Config} */ 5 | const config = { 6 | // Consult https://github.com/sveltejs/svelte-preprocess 7 | // for more information about preprocessors 8 | preprocess: vitePreprocess(), 9 | 10 | kit: { 11 | adapter: adapter(), 12 | }, 13 | }; 14 | 15 | export default config; 16 | -------------------------------------------------------------------------------- /src/assets/fonts.css: -------------------------------------------------------------------------------- 1 | /* #### Generated By: http://www.cufonfonts.com #### */ 2 | 3 | @font-face { 4 | font-family: 'Segoe UI Regular'; 5 | font-style: normal; 6 | font-weight: normal; 7 | src: 8 | local('Segoe UI Regular'), 9 | url('Segoe UI.woff') format('woff'); 10 | } 11 | 12 | @font-face { 13 | font-family: 'Segoe UI Bold'; 14 | font-style: normal; 15 | font-weight: normal; 16 | src: 17 | local('Segoe UI Bold'), 18 | url('Segoe UI Bold.woff') format('woff'); 19 | } 20 | -------------------------------------------------------------------------------- /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: '@typescript-eslint/parser', 4 | extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], 5 | plugins: ['svelte3', '@typescript-eslint'], 6 | ignorePatterns: ['*.cjs'], 7 | overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }], 8 | settings: { 9 | 'svelte3/typescript': () => require('typescript'), 10 | }, 11 | parserOptions: { 12 | sourceType: 'module', 13 | ecmaVersion: 2020, 14 | }, 15 | env: { 16 | browser: true, 17 | es2017: true, 18 | node: true, 19 | }, 20 | }; 21 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": true, 12 | "ignoreDeprecations": "5.0" 13 | } 14 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias 15 | // 16 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes 17 | // from the referenced tsconfig.json - TypeScript does not merge them in 18 | } 19 | -------------------------------------------------------------------------------- /playground/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": true, 12 | "moduleResolution": "bundler" 13 | } 14 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias 15 | // 16 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes 17 | // from the referenced tsconfig.json - TypeScript does not merge them in 18 | } 19 | -------------------------------------------------------------------------------- /playground/svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-auto'; 2 | import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; 3 | 4 | /** @type {import('@sveltejs/kit').Config} */ 5 | const config = { 6 | // Consult https://kit.svelte.dev/docs/integrations#preprocessors 7 | // for more information about preprocessors 8 | preprocess: vitePreprocess(), 9 | 10 | kit: { 11 | // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. 12 | // If your environment is not supported or you settled on a specific environment, switch out the adapter. 13 | // See https://kit.svelte.dev/docs/adapters for more information about adapters. 14 | adapter: adapter(), 15 | }, 16 | }; 17 | 18 | export default config; 19 | -------------------------------------------------------------------------------- /playground/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "playground", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vite dev", 7 | "build": "vite build", 8 | "preview": "vite preview", 9 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", 10 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch" 11 | }, 12 | "devDependencies": { 13 | "@sveltejs/adapter-auto": "^3.1.1", 14 | "@sveltejs/kit": "^2.5.0", 15 | "@sveltejs/vite-plugin-svelte": "^3.0.2", 16 | "svelte": "^4.2.11", 17 | "svelte-check": "^3.6.4", 18 | "tslib": "^2.6.2", 19 | "typescript": "^5.3.3", 20 | "vite": "^5.1.3" 21 | }, 22 | "type": "module", 23 | "dependencies": { 24 | "sveltekit-search-params": "link:.." 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.github/workflows/run-tests.yml: -------------------------------------------------------------------------------- 1 | name: Playwright Tests 2 | on: 3 | push: 4 | branches: [ master ] 5 | pull_request: 6 | branches: [ master ] 7 | jobs: 8 | test: 9 | timeout-minutes: 60 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v3 13 | - uses: pnpm/action-setup@v2 14 | with: 15 | version: 8 16 | - uses: actions/setup-node@v3 17 | with: 18 | node-version: 18 19 | - name: Install dependencies 20 | run: pnpm install --frozen-lockfile 21 | - name: Install Playwright Browsers 22 | run: npx playwright install --with-deps 23 | - name: Run Playwright tests 24 | run: npx playwright test 25 | - uses: actions/upload-artifact@v3 26 | if: always() 27 | with: 28 | name: playwright-report 29 | path: playwright-report/ 30 | retention-days: 30 31 | -------------------------------------------------------------------------------- /playground/src/routes/debounce/+page.svelte: -------------------------------------------------------------------------------- 1 | 15 | 16 | 17 |
{$str}
18 | 19 | 20 |
{$params.str2}
21 | 22 | 28 | 29 | 36 | -------------------------------------------------------------------------------- /playground/src/routes/default/+page.svelte: -------------------------------------------------------------------------------- 1 | 18 | 19 | {$str} 20 | 21 | {$str_no_show} 22 | 23 | {$num} 24 | 25 | {$store.str2} 26 | 27 | {$store_no_show['str2-no-show']} 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yaml: -------------------------------------------------------------------------------- 1 | name: "\U0001F4A1 Feature Request" 2 | description: Request a new feature 3 | body: 4 | - type: markdown 5 | attributes: 6 | value: | 7 | Thank you for taking the time to propose a new idea 8 | - type: textarea 9 | id: problem 10 | attributes: 11 | label: Describe the problem 12 | description: Please provide a clear and concise description the problem this feature would solve. The more information you can provide here, the better. 13 | placeholder: I would like to... 14 | validations: 15 | required: true 16 | - type: textarea 17 | id: solution 18 | attributes: 19 | label: Describe the proposed solution 20 | description: Try to provide a description of the API you would like to see implemented 21 | placeholder: I would like to see... 22 | validations: 23 | required: true 24 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | on: 3 | push: 4 | branches: 5 | - 'master' 6 | 7 | concurrency: ${{ github.workflow }}-${{ github.ref }} 8 | 9 | jobs: 10 | publish: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | - uses: pnpm/action-setup@v2 15 | with: 16 | version: 8 17 | - uses: actions/setup-node@v3 18 | with: 19 | node-version: 20.x 20 | cache: 'pnpm' 21 | 22 | - run: pnpm install --frozen-lockfile 23 | - name: Create Release Pull Request or Publish 24 | id: changesets 25 | uses: changesets/action@v1 26 | with: 27 | publish: pnpm run publish 28 | env: 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 30 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 31 | -------------------------------------------------------------------------------- /playground/src/routes/equalityFn/+page.svelte: -------------------------------------------------------------------------------- 1 | 32 | 33 | {#if $obj} 34 | 35 |
{$obj.str}
36 | {/if} 37 | 38 |
{$params.str2}
39 | 40 |

{obj_changes}

41 |

{store_changes}

42 | -------------------------------------------------------------------------------- /playground/README.md: -------------------------------------------------------------------------------- 1 | # create-svelte 2 | 3 | Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte). 4 | 5 | ## Creating a project 6 | 7 | If you're seeing this, you've probably already done this step. Congrats! 8 | 9 | ```bash 10 | # create a new project in the current directory 11 | npm create svelte@latest 12 | 13 | # create a new project in my-app 14 | npm create svelte@latest my-app 15 | ``` 16 | 17 | ## Developing 18 | 19 | Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: 20 | 21 | ```bash 22 | npm run dev 23 | 24 | # or start the server and open the app in a new browser tab 25 | npm run dev -- --open 26 | ``` 27 | 28 | ## Building 29 | 30 | To create a production version of your app: 31 | 32 | ```bash 33 | npm run build 34 | ``` 35 | 36 | You can preview the production build with `npm run preview`. 37 | 38 | > To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment. 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Paolo Ricciuti 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/extends.ts: -------------------------------------------------------------------------------- 1 | import { test as base } from '@playwright/test'; 2 | 3 | export const test = base.extend({ 4 | page: async ({ page, javaScriptEnabled, context }, use, testInfo) => { 5 | // automatically wait for kit started event after navigation functions if js is enabled 6 | const page_navigation_functions = ['goto', 'goBack', 'reload'] as const; 7 | page_navigation_functions.forEach((fn) => { 8 | const pageFn = page[fn]; 9 | if (!pageFn) { 10 | throw new Error(`function does not exist on page: ${fn}`); 11 | } 12 | // substitute the actual function with a new function that waits 13 | // for the selector that we've set in +layout.svelte 14 | page[fn] = async function (...args: Parameters) { 15 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 16 | // @ts-expect-error 17 | const res = await pageFn.call(page, ...args); 18 | if ( 19 | javaScriptEnabled && 20 | (args[1] as { waitForStarted: boolean })?.waitForStarted !== 21 | false 22 | ) { 23 | await page.waitForSelector('body[data-kit-started]', { 24 | timeout: 15000, 25 | }); 26 | } 27 | return res; 28 | }; 29 | }); 30 | await use(page); 31 | }, 32 | }); 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yaml: -------------------------------------------------------------------------------- 1 | name: "\U0001F41E Bug report" 2 | description: Report an issue 3 | body: 4 | - type: markdown 5 | attributes: 6 | value: | 7 | First thing first, thanks for reporting! 8 | - type: textarea 9 | id: bug-description 10 | attributes: 11 | label: Describe the bug 12 | description: A clear and concise description of what the bug is. If you intend to submit a PR for this issue, tell us in the description. Thanks! 13 | placeholder: Bug description 14 | validations: 15 | required: true 16 | - type: textarea 17 | id: reproduction 18 | attributes: 19 | label: Reproduction 20 | description: Please provide a link to a repo or better a stackblitz/replit that can reproduce the problem you ran into. This will speed up the fixing. 21 | placeholder: Reproduction 22 | validations: 23 | required: true 24 | - type: textarea 25 | id: logs 26 | attributes: 27 | label: Logs 28 | description: 'Please include browser console and server logs around the time this bug occurred. Optional if provided reproduction. Please try not to insert an image but copy paste the log text.' 29 | render: shell 30 | -------------------------------------------------------------------------------- /playground/src/routes/queryparameters/+page.svelte: -------------------------------------------------------------------------------- 1 | 29 | 30 | 31 |
{$store.str}
32 | 33 | 41 | 42 | 43 | 44 | {#if $store.obj} 45 | 46 |
{JSON.stringify($store.obj)}
47 | {/if} 48 | 49 | 59 |
    60 | {#each $store.arr ?? [] as num} 61 |
  • {num}
  • 62 | {/each} 63 |
64 | 65 | 77 |
    78 | {#each $unordered_store['arr-unordered'] ?? [] as num} 79 |
  • {num}
  • 80 | {/each} 81 |
82 | 83 | 84 |
{$store.lz}
85 | 86 | 93 | 94 |

{change_in_store}

95 | -------------------------------------------------------------------------------- /playground/src/routes/+page.svelte: -------------------------------------------------------------------------------- 1 | 32 | 33 | 34 |
{$str}
35 | 36 | 44 | 45 | 46 | 47 | {#if $obj} 48 | 49 |
{JSON.stringify($obj)}
50 | {/if} 51 | 52 | 62 |
    63 | {#each $arr ?? [] as num} 64 |
  • {num}
  • 65 | {/each} 66 |
67 | 68 | 78 |
    79 | {#each $arr_unordered ?? [] as num} 80 |
  • {num}
  • 81 | {/each} 82 |
83 | 84 | 85 |
{$lz}
86 | 87 | 94 | 95 |

{obj_changes}

96 |

{arr_changes}

97 |

{lz_changes}

98 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # sveltekit-search-params 2 | 3 | ## 2.1.2 4 | 5 | ### Patch Changes 6 | 7 | - Fix the override setting to allow for false values ([#74](https://github.com/paoloricciuti/sveltekit-search-params/pull/74)) 8 | 9 | ## 2.1.1 10 | 11 | ### Patch Changes 12 | 13 | - fix: allow building the app in prerendering by faking the page store during building ([#68](https://github.com/paoloricciuti/sveltekit-search-params/pull/68)) 14 | 15 | ## 2.1.0 16 | 17 | ### Minor Changes 18 | 19 | - feat: add equalityFn option for complex objects and array ([#64](https://github.com/paoloricciuti/sveltekit-search-params/pull/64)) 20 | 21 | ## 2.0.0 22 | 23 | ### Major Changes 24 | 25 | - breaking: remove double navigation, debounce navigate after timeout ([#60](https://github.com/paoloricciuti/sveltekit-search-params/pull/60)) 26 | feat: add showDefaults option to chose wether to show the defaults or not in the URL 27 | 28 | ## 1.1.1 29 | 30 | ### Patch Changes 31 | 32 | - fde7148: fix: rework how defaults works 33 | 34 | ## 1.1.0 35 | 36 | ### Minor Changes 37 | 38 | - 7a99cd8: feat: sorting search params before navigating 39 | 40 | ## 1.0.18 41 | 42 | ### Patch Changes 43 | 44 | - ac0a8c3: extend peer dep sveltekit to 2.0 45 | 46 | ## 1.0.17 47 | 48 | ### Patch Changes 49 | 50 | - cc1ad2a: rework the library to use a derived store to solve some issue 51 | 52 | ## 1.0.16 53 | 54 | ### Patch Changes 55 | 56 | - b606180: fix: type ssp array 57 | 58 | ## 1.0.15 59 | 60 | ### Patch Changes 61 | 62 | - 2e7f889: Allow returning undefined from encode to remove param from URL 63 | 64 | ## 1.0.14 65 | 66 | ### Patch Changes 67 | 68 | - a81535c: Fix undefined not removing params (#31) 69 | 70 | ## 1.0.13 71 | 72 | ### Patch Changes 73 | 74 | - 8924160: feat: support svelte 4 75 | 76 | ## 1.0.12 77 | 78 | ### Patch Changes 79 | 80 | - 901d9c7: Add client side check before invoking goto 81 | 82 | ## 1.0.11 83 | 84 | ### Patch Changes 85 | 86 | - 6f78e87: removed changesets as dependency and add it as dev dependency 87 | 88 | ## 1.0.10 89 | 90 | ### Patch Changes 91 | 92 | - 33276b7: fixing changeset 93 | 94 | ## 1.0.8 95 | 96 | ### Patch Changes 97 | 98 | - b0b4b0a: replublish 99 | 100 | ## 1.0.7 101 | 102 | ### Patch Changes 103 | 104 | - 34a1e1b: the hash of the url now doesn't get's erased when the search params update 105 | -------------------------------------------------------------------------------- /src/routes/BrowserWindow.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 |
8 |
9 |
14 |
15 |
16 | 17 | {url} 18 |
19 |
20 |
21 | 22 |
23 |
24 | 25 | 118 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sveltekit-search-params", 3 | "version": "2.1.2", 4 | "repository": "git+https://github.com/paoloricciuti/sveltekit-search-params.git", 5 | "author": "Paolo Ricciuti", 6 | "license": "MIT", 7 | "homepage": "https://sveltekit-search-params.netlify.app", 8 | "keywords": [ 9 | "sveltekit", 10 | "svelte", 11 | "reactive", 12 | "search-params", 13 | "search params", 14 | "search-parameters", 15 | "search parameters", 16 | "query", 17 | "query parameters", 18 | "query-parameters", 19 | "query params", 20 | "query-params" 21 | ], 22 | "scripts": { 23 | "dev": "vite dev", 24 | "version:patch": "npm version patch", 25 | "version:minor": "npm version minor", 26 | "version:major": "npm version major", 27 | "build:landing": "vite build", 28 | "build": "svelte-kit sync && svelte-package -o package", 29 | "build:playground": "cd playground && pnpm install --frozen-lockfile && pnpm run build", 30 | "preview:playground": "cd playground && pnpm run preview", 31 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", 32 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", 33 | "lint": "eslint .", 34 | "format": "prettier --write .", 35 | "publish": "pnpm run build && changeset publish", 36 | "test": "npm run test:integration && npm run test:unit", 37 | "test:integration:ui": "playwright test --ui", 38 | "test:integration": "playwright test", 39 | "test:unit": "vitest", 40 | "changeset": "changeset" 41 | }, 42 | "devDependencies": { 43 | "@changesets/cli": "^2.27.1", 44 | "@playwright/test": "^1.41.2", 45 | "@sveltejs/adapter-static": "^3.0.1", 46 | "@sveltejs/kit": "^2.5.0", 47 | "@sveltejs/package": "^2.2.6", 48 | "@svitejs/changesets-changelog-github-compact": "^1.1.0", 49 | "@typescript-eslint/eslint-plugin": "^7.0.2", 50 | "@typescript-eslint/parser": "^7.0.2", 51 | "eslint": "^8.56.0", 52 | "eslint-plugin-svelte": "^2.35.1", 53 | "prettier": "^3.2.5", 54 | "prettier-plugin-svelte": "^3.2.1", 55 | "svelte": "^4.2.11", 56 | "svelte-check": "^3.6.4", 57 | "svelte-material-icons": "^3.0.5", 58 | "svelte-typewriter-store": "^0.0.5", 59 | "tslib": "^2.6.2", 60 | "typescript": "^4.9.5", 61 | "vite": "^5.1.3", 62 | "vitest": "^1.3.1" 63 | }, 64 | "type": "module", 65 | "peerDependencies": { 66 | "@sveltejs/kit": "^1.0.0 || ^2.0.0", 67 | "svelte": "^3.55.0 || ^4.0.0 || ^5.0.0" 68 | }, 69 | "exports": { 70 | "./package.json": "./package.json", 71 | ".": "./package/index.js", 72 | "./lz-string": "./package/lz-string/index.js", 73 | "./plugin": "./package/plugin.js", 74 | "./sveltekit-search-params": "./package/sveltekit-search-params.js" 75 | }, 76 | "files": [ 77 | "package" 78 | ], 79 | "typesVersions": { 80 | ">4.0": { 81 | "index": [ 82 | "./package/index.d.ts" 83 | ], 84 | "lz-string": [ 85 | "./package/lz-string/index.d.ts" 86 | ], 87 | "plugin": [ 88 | "./package/plugin.d.ts" 89 | ], 90 | "sveltekit-search-params": [ 91 | "./package/sveltekit-search-params.d.ts" 92 | ] 93 | } 94 | }, 95 | "dependencies": { 96 | "@sveltejs/vite-plugin-svelte": "^3.0.2" 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/routes/+page.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | sveltekit-search-params 10 | 11 |

sveltekit-search-params

12 |

the fastest way to read and write search parameters.

13 |

14 | docs and repo 15 | @paoloricciuti/sveltekit-search-params 20 | 32 | 33 |

34 |
35 | npm i sveltekit-search-params -D 36 |
37 |
38 | 39 |
40 |
41 | Your username is {$store} 42 |
43 |
44 |
45 | 46 | 103 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | - Demonstrating empathy and kindness toward other people 21 | - Being respectful of differing opinions, viewpoints, and experiences 22 | - Giving and gracefully accepting constructive feedback 23 | - Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | - Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | - The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | - Trolling, insulting or derogatory comments, and personal or political attacks 33 | - Public or private harassment 34 | - Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | - Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | ricciutipaolo@gmail.com. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /src/lib/lz-string/index.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013 Pieroxy 2 | // This work is free. You can redistribute it and/or modify it 3 | // under the terms of the WTFPL, Version 2 4 | // For more information see LICENSE.txt or http://www.wtfpl.net/ 5 | // 6 | // For more information, the home page: 7 | // http://pieroxy.net/blog/pages/lz-string/testing.html 8 | // 9 | // LZ-based compression algorithm, version 1.4.4 10 | 11 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 12 | // @ts-ignore 13 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 14 | let f = String.fromCharCode, 15 | keyStrUriSafe = 16 | 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$', 17 | baseReverseDic = {}; 18 | function getBaseValue(o, e) { 19 | if (!baseReverseDic[o]) { 20 | baseReverseDic[o] = {}; 21 | for (let r = 0; r < o.length; r++) baseReverseDic[o][o.charAt(r)] = r; 22 | } 23 | return baseReverseDic[o][e]; 24 | } 25 | function compressToEncodedURIComponent(o) { 26 | return null == o 27 | ? '' 28 | : _compress(o, 6, function (o) { 29 | return keyStrUriSafe.charAt(o); 30 | }); 31 | } 32 | function decompressFromEncodedURIComponent(o) { 33 | return null == o 34 | ? '' 35 | : '' == o 36 | ? null 37 | : _decompress((o = o.replace(/ /g, '+')).length, 32, function (e) { 38 | return getBaseValue(keyStrUriSafe, o.charAt(e)); 39 | }); 40 | } 41 | function _compress(o, e, r) { 42 | if (null == o) return ''; 43 | let i, 44 | t, 45 | s = {}, 46 | n = {}, 47 | $ = '', 48 | _ = '', 49 | p = '', 50 | a = 2, 51 | l = 3, 52 | c = 2, 53 | u = [], 54 | h = 0, 55 | d = 0, 56 | v; 57 | for (v = 0; v < o.length; v += 1) 58 | if ( 59 | (($ = o.charAt(v)), 60 | Object.prototype.hasOwnProperty.call(s, $) || 61 | ((s[$] = l++), (n[$] = !0)), 62 | (_ = p + $), 63 | Object.prototype.hasOwnProperty.call(s, _)) 64 | ) 65 | p = _; 66 | else { 67 | if (Object.prototype.hasOwnProperty.call(n, p)) { 68 | if (256 > p.charCodeAt(0)) { 69 | for (i = 0; i < c; i++) 70 | (h <<= 1), 71 | d == e - 1 ? ((d = 0), u.push(r(h)), (h = 0)) : d++; 72 | for (i = 0, t = p.charCodeAt(0); i < 8; i++) 73 | (h = (h << 1) | (1 & t)), 74 | d == e - 1 ? ((d = 0), u.push(r(h)), (h = 0)) : d++, 75 | (t >>= 1); 76 | } else { 77 | for (i = 0, t = 1; i < c; i++) 78 | (h = (h << 1) | t), 79 | d == e - 1 ? ((d = 0), u.push(r(h)), (h = 0)) : d++, 80 | (t = 0); 81 | for (i = 0, t = p.charCodeAt(0); i < 16; i++) 82 | (h = (h << 1) | (1 & t)), 83 | d == e - 1 ? ((d = 0), u.push(r(h)), (h = 0)) : d++, 84 | (t >>= 1); 85 | } 86 | 0 == --a && ((a = Math.pow(2, c)), c++), delete n[p]; 87 | } else 88 | for (i = 0, t = s[p]; i < c; i++) 89 | (h = (h << 1) | (1 & t)), 90 | d == e - 1 ? ((d = 0), u.push(r(h)), (h = 0)) : d++, 91 | (t >>= 1); 92 | 0 == --a && ((a = Math.pow(2, c)), c++), 93 | (s[_] = l++), 94 | (p = String($)); 95 | } 96 | if ('' !== p) { 97 | if (Object.prototype.hasOwnProperty.call(n, p)) { 98 | if (256 > p.charCodeAt(0)) { 99 | for (i = 0; i < c; i++) 100 | (h <<= 1), 101 | d == e - 1 ? ((d = 0), u.push(r(h)), (h = 0)) : d++; 102 | for (i = 0, t = p.charCodeAt(0); i < 8; i++) 103 | (h = (h << 1) | (1 & t)), 104 | d == e - 1 ? ((d = 0), u.push(r(h)), (h = 0)) : d++, 105 | (t >>= 1); 106 | } else { 107 | for (i = 0, t = 1; i < c; i++) 108 | (h = (h << 1) | t), 109 | d == e - 1 ? ((d = 0), u.push(r(h)), (h = 0)) : d++, 110 | (t = 0); 111 | for (i = 0, t = p.charCodeAt(0); i < 16; i++) 112 | (h = (h << 1) | (1 & t)), 113 | d == e - 1 ? ((d = 0), u.push(r(h)), (h = 0)) : d++, 114 | (t >>= 1); 115 | } 116 | 0 == --a && ((a = Math.pow(2, c)), c++), delete n[p]; 117 | } else 118 | for (i = 0, t = s[p]; i < c; i++) 119 | (h = (h << 1) | (1 & t)), 120 | d == e - 1 ? ((d = 0), u.push(r(h)), (h = 0)) : d++, 121 | (t >>= 1); 122 | 0 == --a && ((a = Math.pow(2, c)), c++); 123 | } 124 | for (i = 0, t = 2; i < c; i++) 125 | (h = (h << 1) | (1 & t)), 126 | d == e - 1 ? ((d = 0), u.push(r(h)), (h = 0)) : d++, 127 | (t >>= 1); 128 | for (;;) { 129 | if (((h <<= 1), d == e - 1)) { 130 | u.push(r(h)); 131 | break; 132 | } 133 | d++; 134 | } 135 | return u.join(''); 136 | } 137 | function _decompress(o, e, r) { 138 | let i = [], 139 | t, 140 | s = 4, 141 | n = 4, 142 | $ = 3, 143 | _ = '', 144 | p = [], 145 | a, 146 | l, 147 | c, 148 | u, 149 | h, 150 | d, 151 | v, 152 | m = { val: r(0), position: e, index: 1 }; 153 | for (a = 0; a < 3; a += 1) i[a] = a; 154 | for (c = 0, h = 4, d = 1; d != h; ) 155 | (u = m.val & m.position), 156 | (m.position >>= 1), 157 | 0 == m.position && ((m.position = e), (m.val = r(m.index++))), 158 | (c |= (u > 0 ? 1 : 0) * d), 159 | (d <<= 1); 160 | switch ((t = c)) { 161 | case 0: 162 | for (c = 0, h = 256, d = 1; d != h; ) 163 | (u = m.val & m.position), 164 | (m.position >>= 1), 165 | 0 == m.position && 166 | ((m.position = e), (m.val = r(m.index++))), 167 | (c |= (u > 0 ? 1 : 0) * d), 168 | (d <<= 1); 169 | v = f(c); 170 | break; 171 | case 1: 172 | for (c = 0, h = 65536, d = 1; d != h; ) 173 | (u = m.val & m.position), 174 | (m.position >>= 1), 175 | 0 == m.position && 176 | ((m.position = e), (m.val = r(m.index++))), 177 | (c |= (u > 0 ? 1 : 0) * d), 178 | (d <<= 1); 179 | v = f(c); 180 | break; 181 | case 2: 182 | return ''; 183 | } 184 | for (i[3] = v, l = v, p.push(v); ; ) { 185 | if (m.index > o) return ''; 186 | for (c = 0, h = Math.pow(2, $), d = 1; d != h; ) 187 | (u = m.val & m.position), 188 | (m.position >>= 1), 189 | 0 == m.position && ((m.position = e), (m.val = r(m.index++))), 190 | (c |= (u > 0 ? 1 : 0) * d), 191 | (d <<= 1); 192 | switch ((v = c)) { 193 | case 0: 194 | for (c = 0, h = 256, d = 1; d != h; ) 195 | (u = m.val & m.position), 196 | (m.position >>= 1), 197 | 0 == m.position && 198 | ((m.position = e), (m.val = r(m.index++))), 199 | (c |= (u > 0 ? 1 : 0) * d), 200 | (d <<= 1); 201 | (i[n++] = f(c)), (v = n - 1), s--; 202 | break; 203 | case 1: 204 | for (c = 0, h = 65536, d = 1; d != h; ) 205 | (u = m.val & m.position), 206 | (m.position >>= 1), 207 | 0 == m.position && 208 | ((m.position = e), (m.val = r(m.index++))), 209 | (c |= (u > 0 ? 1 : 0) * d), 210 | (d <<= 1); 211 | (i[n++] = f(c)), (v = n - 1), s--; 212 | break; 213 | case 2: 214 | return p.join(''); 215 | } 216 | if ((0 == s && ((s = Math.pow(2, $)), $++), i[v])) _ = i[v]; 217 | else { 218 | if (v !== n) return null; 219 | _ = l + l.charAt(0); 220 | } 221 | p.push(_), 222 | (i[n++] = l + _.charAt(0)), 223 | s--, 224 | (l = _), 225 | 0 == s && ((s = Math.pow(2, $)), $++); 226 | } 227 | } 228 | export { compressToEncodedURIComponent, decompressFromEncodedURIComponent }; 229 | -------------------------------------------------------------------------------- /src/lib/sveltekit-search-params.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-empty-function */ 2 | /* eslint-disable @typescript-eslint/no-explicit-any */ 3 | import { browser, building } from '$app/environment'; 4 | import { goto } from '$app/navigation'; 5 | import { page as page_store } from '$app/stores'; 6 | import type { Page } from '@sveltejs/kit'; 7 | import { 8 | derived, 9 | get, 10 | writable, 11 | type Updater, 12 | type Writable, 13 | type Readable, 14 | readable, 15 | } from 'svelte/store'; 16 | import { 17 | compressToEncodedURIComponent, 18 | decompressFromEncodedURIComponent, 19 | } from './lz-string/index.js'; 20 | 21 | // during building we fake the page store with an URL with no search params 22 | // as it should be during prerendering. This allow the application to still build 23 | // and the client side behavior is still persisted after the build 24 | let page: Readable>; 25 | if (building) { 26 | page = readable({ 27 | url: new URL( 28 | 'https://github.com/paoloricciuti/sveltekit-search-params', 29 | ), 30 | }); 31 | } else { 32 | page = page_store; 33 | } 34 | 35 | const GOTO_OPTIONS = { 36 | keepFocus: true, 37 | noScroll: true, 38 | replaceState: true, 39 | }; 40 | 41 | const GOTO_OPTIONS_PUSH = { 42 | keepFocus: true, 43 | noScroll: true, 44 | replaceState: false, 45 | }; 46 | 47 | export type EncodeAndDecodeOptions = { 48 | encode: (value: T) => string | undefined; 49 | decode: (value: string | null) => T | null; 50 | defaultValue?: T; 51 | }; 52 | 53 | export type StoreOptions = { 54 | debounceHistory?: number; 55 | pushHistory?: boolean; 56 | sort?: boolean; 57 | showDefaults?: boolean; 58 | equalityFn?: T extends object 59 | ? (current: T | null, next: T | null) => boolean 60 | : never; 61 | }; 62 | 63 | type LooseAutocomplete = { 64 | [K in keyof T]: T[K]; 65 | } & { 66 | [K: string]: any; 67 | }; 68 | 69 | type Options = { 70 | [Key in keyof T]: EncodeAndDecodeOptions | boolean; 71 | }; 72 | 73 | type Overrides = { 74 | [Key in keyof T]?: T[Key] | null; 75 | }; 76 | 77 | function mixSearchAndOptions( 78 | searchParams: URLSearchParams, 79 | overrides: Overrides, 80 | options?: Options, 81 | ): [LooseAutocomplete, boolean] { 82 | const uniqueKeys = Array.from( 83 | new Set( 84 | Array.from(searchParams?.keys?.() || []).concat( 85 | Object.keys(options ?? {}), 86 | ), 87 | ), 88 | ); 89 | let anyDefaultedParam = false; 90 | return [ 91 | Object.fromEntries( 92 | uniqueKeys.map((key) => { 93 | if ((overrides as any)[key] != undefined) { 94 | return [key, (overrides as any)[key]]; 95 | } 96 | let fnToCall: EncodeAndDecodeOptions['decode'] = (value) => 97 | value; 98 | const optionsKey = (options as any)?.[key]; 99 | if ( 100 | typeof optionsKey !== 'boolean' && 101 | typeof optionsKey?.decode === 'function' 102 | ) { 103 | fnToCall = optionsKey.decode; 104 | } 105 | const value = searchParams?.get(key); 106 | let actualValue; 107 | if ( 108 | value == undefined && 109 | optionsKey?.defaultValue != undefined 110 | ) { 111 | actualValue = optionsKey.defaultValue; 112 | anyDefaultedParam = true; 113 | } else { 114 | actualValue = fnToCall(value); 115 | } 116 | return [key, actualValue]; 117 | }), 118 | ) as unknown as LooseAutocomplete, 119 | anyDefaultedParam, 120 | ]; 121 | } 122 | 123 | function isComplexEqual( 124 | current: T, 125 | next: T, 126 | equalityFn: (current: T, next: T) => boolean = (current, next) => 127 | JSON.stringify(current) === JSON.stringify(next), 128 | ) { 129 | return ( 130 | typeof current === 'object' && 131 | typeof next === 'object' && 132 | equalityFn(current, next) 133 | ); 134 | } 135 | 136 | export const ssp = { 137 | object: (defaultValue?: T) => ({ 138 | encode: (value: T) => JSON.stringify(value), 139 | decode: (value: string | null): T | null => { 140 | if (value === null) return null; 141 | try { 142 | return JSON.parse(value); 143 | } catch (e) { 144 | return null; 145 | } 146 | }, 147 | defaultValue, 148 | }), 149 | array: (defaultValue?: T[]) => ({ 150 | encode: (value: T[]) => JSON.stringify(value), 151 | decode: (value: string | null): T[] | null => { 152 | if (value === null) return null; 153 | try { 154 | return JSON.parse(value); 155 | } catch (e) { 156 | return null; 157 | } 158 | }, 159 | defaultValue, 160 | }), 161 | number: (defaultValue?: number) => ({ 162 | encode: (value: number) => value.toString(), 163 | decode: (value: string | null) => (value ? parseFloat(value) : null), 164 | defaultValue, 165 | }), 166 | boolean: (defaultValue?: boolean) => ({ 167 | encode: (value: boolean) => value + '', 168 | decode: (value: string | null) => value !== null && value !== 'false', 169 | defaultValue, 170 | }), 171 | string: (defaultValue?: string) => ({ 172 | encode: (value: string | null) => value ?? '', 173 | decode: (value: string | null) => value, 174 | defaultValue, 175 | }), 176 | lz: (defaultValue?: T) => ({ 177 | encode: (value: T) => 178 | compressToEncodedURIComponent(JSON.stringify(value)), 179 | decode: (value: string | null): T | null => { 180 | if (!value) return null; 181 | try { 182 | return JSON.parse( 183 | decompressFromEncodedURIComponent(value) ?? '', 184 | ); 185 | } catch (e) { 186 | return null; 187 | } 188 | }, 189 | defaultValue, 190 | }), 191 | } satisfies Record EncodeAndDecodeOptions>; 192 | 193 | type SetTimeout = ReturnType; 194 | 195 | const batchedUpdates = new Set<(query: URLSearchParams) => void>(); 196 | 197 | let batchTimeout: number; 198 | 199 | const debouncedTimeouts = new Map(); 200 | 201 | export function queryParameters( 202 | options?: Options, 203 | { 204 | debounceHistory = 0, 205 | pushHistory = true, 206 | sort = true, 207 | showDefaults = true, 208 | equalityFn, 209 | }: StoreOptions = {}, 210 | ): Writable> { 211 | const overrides = writable>({}); 212 | let currentValue: T; 213 | let firstTime = true; 214 | 215 | function _set(value: T, changeImmediately?: boolean) { 216 | if (!browser) return; 217 | firstTime = false; 218 | const hash = window.location.hash; 219 | const query = new URLSearchParams(window.location.search); 220 | const toBatch = (query: URLSearchParams) => { 221 | for (const field of Object.keys(value)) { 222 | if ((value as any)[field] == undefined) { 223 | query.delete(field); 224 | continue; 225 | } 226 | let fnToCall: EncodeAndDecodeOptions['encode'] = (value) => 227 | value.toString(); 228 | const optionsKey = (options as any)?.[field as string]; 229 | if ( 230 | typeof optionsKey !== 'boolean' && 231 | typeof optionsKey?.encode === 'function' 232 | ) { 233 | fnToCall = optionsKey.encode; 234 | } 235 | const newValue = fnToCall((value as any)[field]); 236 | if (newValue == undefined) { 237 | query.delete(field as string); 238 | } else { 239 | query.set(field as string, newValue); 240 | } 241 | } 242 | }; 243 | batchedUpdates.add(toBatch); 244 | clearTimeout(batchTimeout); 245 | batchTimeout = setTimeout(async () => { 246 | batchedUpdates.forEach((batched) => { 247 | batched(query); 248 | }); 249 | clearTimeout(debouncedTimeouts.get('queryParameters')); 250 | if (browser) { 251 | overrides.set(value); 252 | // eslint-disable-next-line no-inner-declarations 253 | async function navigate() { 254 | if (sort) { 255 | query.sort(); 256 | } 257 | await goto( 258 | `?${query}${hash}`, 259 | pushHistory ? GOTO_OPTIONS_PUSH : GOTO_OPTIONS, 260 | ); 261 | overrides.set({}); 262 | } 263 | if (changeImmediately || debounceHistory === 0) { 264 | navigate(); 265 | } else { 266 | debouncedTimeouts.set( 267 | 'queryParameters', 268 | setTimeout(navigate, debounceHistory), 269 | ); 270 | } 271 | } 272 | batchedUpdates.clear(); 273 | }); 274 | } 275 | const { subscribe } = derived<[typeof page, typeof overrides], T>( 276 | [page, overrides], 277 | ([$page, $overrides], set) => { 278 | const [valueToSet, anyDefaultedParam] = mixSearchAndOptions( 279 | $page?.url?.searchParams, 280 | $overrides, 281 | options, 282 | ); 283 | if (anyDefaultedParam && showDefaults) { 284 | _set(valueToSet, firstTime); 285 | } 286 | if (isComplexEqual(currentValue, valueToSet, equalityFn)) { 287 | return; 288 | } 289 | currentValue = structuredClone(valueToSet); 290 | return set(valueToSet); 291 | }, 292 | ); 293 | return { 294 | set(newValue) { 295 | _set(newValue); 296 | }, 297 | subscribe, 298 | update: (updater: Updater>) => { 299 | const currentValue = get({ subscribe }); 300 | const newValue = updater(currentValue); 301 | _set(newValue); 302 | }, 303 | }; 304 | } 305 | 306 | const DEFAULT_ENCODER_DECODER: EncodeAndDecodeOptions = { 307 | encode: (value) => value.toString(), 308 | decode: (value: string | null) => (value ? value.toString() : null), 309 | }; 310 | 311 | export function queryParam( 312 | name: string, 313 | { 314 | encode: encode = DEFAULT_ENCODER_DECODER.encode, 315 | decode: decode = DEFAULT_ENCODER_DECODER.decode, 316 | defaultValue, 317 | }: EncodeAndDecodeOptions = DEFAULT_ENCODER_DECODER, 318 | { 319 | debounceHistory = 0, 320 | pushHistory = true, 321 | sort = true, 322 | showDefaults = true, 323 | equalityFn, 324 | }: StoreOptions = {}, 325 | ): Writable { 326 | const override = writable(null); 327 | let firstTime = true; 328 | let currentValue: T | null; 329 | function _set(value: T | null, changeImmediately?: boolean) { 330 | if (!browser) return; 331 | firstTime = false; 332 | const hash = window.location.hash; 333 | const toBatch = (query: URLSearchParams) => { 334 | if (value == undefined) { 335 | query.delete(name); 336 | } else { 337 | const newValue = encode(value); 338 | if (newValue == undefined) { 339 | query.delete(name); 340 | } else { 341 | query.set(name, newValue); 342 | } 343 | } 344 | }; 345 | batchedUpdates.add(toBatch); 346 | clearTimeout(batchTimeout); 347 | const query = new URLSearchParams(window.location.search); 348 | batchTimeout = setTimeout(async () => { 349 | batchedUpdates.forEach((batched) => { 350 | batched(query); 351 | }); 352 | clearTimeout(debouncedTimeouts.get(name)); 353 | if (browser) { 354 | override.set(value); 355 | // eslint-disable-next-line no-inner-declarations 356 | async function navigate() { 357 | if (sort) { 358 | query.sort(); 359 | } 360 | await goto( 361 | `?${query}${hash}`, 362 | pushHistory ? GOTO_OPTIONS_PUSH : GOTO_OPTIONS, 363 | ); 364 | override.set(null); 365 | } 366 | if (changeImmediately || debounceHistory === 0) { 367 | navigate(); 368 | } else { 369 | debouncedTimeouts.set( 370 | name, 371 | setTimeout(navigate, debounceHistory), 372 | ); 373 | } 374 | } 375 | batchedUpdates.clear(); 376 | }); 377 | } 378 | 379 | const { subscribe } = derived<[typeof page, typeof override], T | null>( 380 | [page, override], 381 | ([$page, $override], set) => { 382 | if ($override != undefined) { 383 | if (isComplexEqual(currentValue, $override, equalityFn)) { 384 | return; 385 | } 386 | currentValue = structuredClone($override); 387 | return set($override); 388 | } 389 | const actualParam = $page?.url?.searchParams?.get?.(name); 390 | if (actualParam == undefined && defaultValue != undefined) { 391 | if (showDefaults) { 392 | _set(defaultValue, firstTime); 393 | } 394 | if (isComplexEqual(currentValue, defaultValue, equalityFn)) { 395 | return; 396 | } 397 | currentValue = structuredClone(defaultValue); 398 | return set(defaultValue); 399 | } 400 | const retval = decode(actualParam); 401 | if (isComplexEqual(currentValue, retval, equalityFn)) { 402 | return; 403 | } 404 | currentValue = structuredClone(retval); 405 | return set(retval); 406 | }, 407 | ); 408 | return { 409 | set(newValue) { 410 | _set(newValue); 411 | }, 412 | subscribe, 413 | update: (updater: Updater) => { 414 | const newValue = updater(currentValue); 415 | _set(newValue); 416 | }, 417 | }; 418 | } 419 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sveltekit-search-params 2 | 3 | The fastest way to read **AND WRITE** from query search params in [sveltekit](https://github.com/sveltejs/kit). 4 | 5 | > **Warning** 6 | > 7 | > This package is meant to be used with Svelte-Kit as the name suggest. Because it uses api that are **only** present in Svelte-Kit it will not work in your normal svelte project. 8 | 9 | [![MIT License](https://img.shields.io/badge/License-MIT-green.svg)](https://choosealicense.com/licenses/mit/) 10 | 11 | ![npm](https://img.shields.io/npm/v/sveltekit-search-params) 12 | 13 | ![npm](https://img.shields.io/npm/dt/sveltekit-search-params) 14 | 15 | ![GitHub last commit](https://img.shields.io/github/last-commit/paoloricciuti/sveltekit-search-params) 16 | 17 | ## Contributing 18 | 19 | Contributions are always welcome! 20 | 21 | For the moment there's no code of conduct neither a contributing guideline but if you found a problem or have an idea feel free to [open an issue](https://github.com/paoloricciuti/sveltekit-search-params/issues/new) 22 | 23 | If you want the fastest way to open a PR try out Codeflow 24 | 25 | [![Open in Codeflow](https://developer.stackblitz.com/img/open_in_codeflow.svg)](https://pr.new/paoloricciuti/sveltekit-search-params/) 26 | 27 | ## Authors 28 | 29 | - [@paoloricciuti](https://www.github.com/paoloricciuti) 30 | 31 | ## Installation 32 | 33 | Install sveltekit-search-params with npm 34 | 35 | ```bash 36 | npm install sveltekit-search-params@latest -D 37 | ``` 38 | 39 | ## Usage/Examples 40 | 41 | ### Simple case (single parameter) 42 | 43 | The simplest and most effective way to use this library is by importing the method `queryParam`. You can invoke this method with a string that represent the search parameters you are looking for in the URL. 44 | 45 | ```svelte 46 | 51 | 52 | Your username is {$username} 53 | ``` 54 | 55 | the function returns a store so make sure to use it with the `$` prepended to handle auto-subscriprion. In case there's not a query parameter with the chosen name it will simply be null. 56 | 57 | ### Writing to the store (single parameter) 58 | 59 | Reading query parameters is cool but you know what is even cooler? Writing query parameters! With this library you can treat your store just like normal state in svelte. To update the state and conseguentely the url you can just do this 60 | 61 | ```svelte 62 | 67 | 68 | Your username is {$username} 69 | 70 | ``` 71 | 72 | or if you prefer 73 | 74 | ```svelte 75 | 80 | 81 | Your username is {$username} 82 | { 85 | $username = e.target.value; 86 | }} 87 | /> 88 | ``` 89 | 90 | ### Encoding and decoding 91 | 92 | By default query parameters are strings but more often than not tho we are not working with strings. We are dealing with numbers, boolean, arrays and complex abjects. During the creation of the store you can specify an object containing an encode and a decode property that will be used to transform your data from and to the type you need. 93 | 94 | ```svelte 95 | 103 | 104 | The count is {$count} 105 | 106 | ``` 107 | 108 | this time $count would be of type number and the deconding function it's what's used to update the url when you write to the store. 109 | 110 | ### Default values 111 | 112 | Sometimes when we want to create a new variable we like to pass a default value. You can do this by passing a third field, `defaultValue`, in the second argument of the query param object. 113 | 114 | ```svelte 115 | 124 | 125 | The count is {$count} 126 | 127 | ``` 128 | 129 | this will make the query parameter change as soon as the page is rendered on the browser (the query parameter will change only if it's not already present and only the first time the application render). 130 | 131 | > **Warning** 132 | > 133 | > You can't run `goto` on the server so if the page is server side rendered it will still have the null value (this is to say don't relay on the assumption that the store will always be not null). 134 | 135 | ### Helpers encodings and decodings 136 | 137 | Write an encode and decode function may seem trivial but it's tedious for sure. `sveltekit-search-params` provide with a set of helpers for better readability and to avoid the hassle of writing common transforms. You can find those helpers exported in a ssp variable from the same package. 138 | 139 | ```svelte 140 | 145 | 146 | The count is {$count} 147 | 148 | ``` 149 | 150 | this code will produce the same output as the code written above but far more readable and easier to read. You can find all the exports documented in the section [ssp - Helpers](#ssp---helpers). 151 | 152 | You can also pass a default value to the function that will be the defaultValue of the object. 153 | 154 | ```svelte 155 | 160 | 161 | The count is {$count} 162 | 163 | ``` 164 | 165 | ### Simple case (all parameters) 166 | 167 | You can use the function queryParameters to get an object containing all the present search params. 168 | 169 | ```svelte 170 | 175 | 176 |
177 |     {JSON.stringify($store, null, 2)}
178 | 
179 | ``` 180 | 181 | assuming the page is `/?framework=svelte&isCool=true` the above code will show 182 | 183 | ```json 184 | { 185 | "framework": "svelte", 186 | "isCool": "true" 187 | } 188 | ``` 189 | 190 | by default all query parameters are string. 191 | 192 | ### Writing to the store (all parameters) 193 | 194 | Just like with the single parameter case you can just update the store and the URL at the same time by doing this 195 | 196 | ```svelte 197 | 202 | 203 |
204 |     {JSON.stringify($store, null, 2)}
205 | 
206 | { 209 | $store.username = e.target.value; 210 | }} 211 | /> 212 | ``` 213 | 214 | writing in the input will update the state and the URL at the same time. 215 | 216 | ### Expecting some parameters 217 | 218 | Most of the times if you need to read from query parameters you are expecting some parameters to be present. You can define the parameters you are expecting during the store creating and those will be merged with the actual query parameters despite the fact that they are present or not. 219 | 220 | ```svelte 221 | 228 | 229 |
230 |     {JSON.stringify($store, null, 2)}
231 | 
232 | ``` 233 | 234 | assuming the page is `/?framework=svelte&isCool=true` the above code will show 235 | 236 | ```json 237 | { 238 | "framework": "svelte", 239 | "isCool": "true", 240 | "username": null 241 | } 242 | ``` 243 | 244 | if we add username to the URL like this `/?framework=svelte&isCool=true&username=paoloricciuti` we will get 245 | 246 | ```json 247 | { 248 | "framework": "svelte", 249 | "isCool": "true", 250 | "username": "paoloricciuti" 251 | } 252 | ``` 253 | 254 | ### Encoding and Decoding 255 | 256 | The parameter passed to `queryParameters` can aslo be used to specify the encoding and decoding just like the `queryParam` method. 257 | 258 | ```svelte 259 | 272 | 273 |
274 |     {JSON.stringify($store, null, 2)}
275 | 
276 | ``` 277 | 278 | assuming the page is `/?framework=svelte&isCool=true&username=paoloricciuti` the above code will show 279 | 280 | ```json 281 | { 282 | "framework": "svelte", 283 | "isCool": true, 284 | "username": null 285 | } 286 | ``` 287 | 288 | notice that this time isCool it's a boolean and not a string anymore. With this particular transformation we've assured that if the url is the following `/?framework=svelte&isCool=false&username=paoloricciuti` or if the isCool parameter is completely missing like this `/?framework=svelte&username=paoloricciuti` we will get 289 | 290 | ```json 291 | { 292 | "framework": "svelte", 293 | "isCool": false, 294 | "username": null 295 | } 296 | ``` 297 | 298 | ### Helpers encodings and decodings 299 | 300 | Obviously also in this case you can use the helpers functions provided inside `ssp`. 301 | 302 | ```svelte 303 | 311 | 312 |
313 |     {JSON.stringify($store, null, 2)}
314 | 
315 | ``` 316 | 317 | ## ssp - Helpers 318 | 319 | There are six helpers all exported as functions on the object ssp. To each one of them you can pass a parameter that will be the default value for that query param. 320 | 321 | #### object 322 | 323 | To map from a query parameter to an object. An url like this `/?obj={"isComplex":%20true,%20"nested":%20{"field":%20"value"}}` will be mapped to 324 | 325 | ```typescript 326 | $store.obj.isComplex; //true 327 | $store.obj.nested; // {field: "value"} 328 | $store.obj.nested.value; // "value" 329 | ``` 330 | 331 | #### array 332 | 333 | To map from a query parameter to an array. An url like this `/?arr=[1,2,3,4]` will be mapped to 334 | 335 | ```typescript 336 | $store.arr[0]; //1 337 | $store.arr[1]; //2 338 | $store.arr[2]; //3 339 | $store.arr[3]; //4 340 | ``` 341 | 342 | #### number 343 | 344 | To map from a query parameter to a number. An url like this `/?num=1` will be mapped to 345 | 346 | ```typescript 347 | $store.num; //1 348 | ``` 349 | 350 | #### boolean 351 | 352 | To map from a query parameter to a boolean. An url like this `/?bool=true` will be mapped to 353 | 354 | ```typescript 355 | $store.bool; //true 356 | ``` 357 | 358 | as we've seen an url like this `/?bool=false` will be mapped to 359 | 360 | ```typescript 361 | $store.bool; //false 362 | ``` 363 | 364 | just like an url like this `/` 365 | 366 | #### string 367 | 368 | This is exported mainly for readability since all query parameters are already strings. 369 | 370 | #### lz 371 | 372 | To map any JSON serializable state to his lz-string representation. This is a common way to store state in query parameters that will prevent the link to directly show the state. 373 | 374 | An url like this `/?state=N4IgbghgNgrgpiAXCAsgTwAQGMD2OoYCO8ATpgA4QkQC2cALnCSAL5A` will map to 375 | 376 | ```typescript 377 | $store.state.value; //My cool query parameter 378 | ``` 379 | 380 | ## Store options 381 | 382 | Both functions accept a configuration object that contains the following properties: 383 | 384 | ### debounceHistory 385 | 386 | The number of milliseconds to delay the writing of the history when the state changes. This is to avoid cluttering the history of the user especially when a store is bound to an input text (every keystroke would cause a new history entry). It defaults to 0. If set a new entry in the history will be added only after `debounceHistory` seconds of "inactivity". 387 | 388 | ### pushHistory 389 | 390 | A boolean defining if the history have to be written at all. If set to false no new history entries will be written to the history stack (the URL will still update but the user will not be able to go back with the browser). 391 | 392 | ### sort 393 | 394 | Whenever you interact with a store, it navigates for you. By default the search params are sorted to allow for better cache-ability. You can disable this behavior by passing `false` to this option. Keep in mind that this is a per-store settings. This mean that if you interact with a store that has this option set to `false` and than interact with one that has this option set to `true` (the default) the resulting URL will still have the search params sorted. 395 | 396 | ### showDefaults 397 | 398 | If you specify a default value for the search param and it's not present by default the library will immediately navigate to the url that contains the default search param. For example if you have this code 399 | 400 | ```svelte 401 | 406 | ``` 407 | 408 | and you navigate to `/` as soon as the page load it will be redirected to `/?pageNum=0`. If you prefer not to show the defaults in the URL you can set the `showDefaults` option to false. 409 | 410 | ```svelte 411 | 418 | ``` 419 | 420 | By doing so the store will still have a value of 0 if the search param is not present but the user will not be redirected to `/?pageNum=0`. 421 | 422 | ### equalityFn 423 | 424 | While this is not a problem for primitive values if your store has a complex object or an array (or if you are using `queryParameters`) as a value even if the reference is the same svelte will trigger reactivity for it. To provide you with optimistic updates there's the possibility that the store will change multiple times during a single navigation. To fix this problem by default we check if the value of the store is the same by using `JSON.stringify` so that if the overall shape of your store is the same we avoid triggering the reactivity. 425 | 426 | This is fine for most cases and you will likely never touch this option but if you have some use case not covered by `JSON.stringify` you can specify the option `equalityFn`. This option is a function that takes the `current` value and the `next` value as parameters and need to return a `boolean`. You should return `true` from this function when the value of the store is unchanged (according to your own logic). This will not trigger reactivity (note that the navigation will still happen). 427 | 428 | For `queryParameters` the equality function applies to the entire store (so make sure to check that every query parameter is exactly the same before returning `true`). 429 | 430 | ```svelte 431 | 440 | ``` 441 | 442 | NOTE: the equality function will not be used on primitive values, hence you can't pass the equality function to stores that have a primitive type. 443 | 444 | ### How to use it 445 | 446 | To set the configuration object you can pass it as a third parameter in case of `queryParam` or the second in case of `queryParameters`. 447 | 448 | ```svelte 449 | 467 | ``` 468 | 469 | ## Vite dependecies error 470 | 471 | If you ran into issues with vite you need to update your `vite.config.ts` or `vite.config.js` file to include the plugin exported from `sveltekit-search-params/plugin`. It's as simple as 472 | 473 | ```javascript 474 | import { sveltekit } from '@sveltejs/kit/vite'; 475 | import { ssp } from 'sveltekit-search-params/plugin'; 476 | 477 | /** @type {import('vite').UserConfig} */ 478 | const config = { 479 | plugins: [ssp(), sveltekit()], 480 | }; 481 | 482 | export default config; 483 | ``` 484 | 485 | > **Warning** 486 | > 487 | > This step is required if you are running on an old version of vite/sveltekit 488 | -------------------------------------------------------------------------------- /tests/index.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from '@playwright/test'; 2 | import { test } from './extends'; 3 | 4 | test.describe('queryParam', () => { 5 | test('works as expected with strings', async ({ page }) => { 6 | await page.goto('/'); 7 | const input = page.getByTestId('str-input'); 8 | await input.fill('str'); 9 | const str = page.getByTestId('str'); 10 | await expect(str).toHaveText('str'); 11 | const url = new URL(page.url()); 12 | expect(url.searchParams.get('str')).toBe('str'); 13 | }); 14 | 15 | test('works as expected with numbers', async ({ page }) => { 16 | await page.goto('/?num=0'); 17 | const btn = page.getByTestId('num'); 18 | await expect(btn).toHaveText('0'); 19 | btn.click(); 20 | await expect(btn).toHaveText('1'); 21 | const url = new URL(page.url()); 22 | expect(url.searchParams.get('num')).toBe('1'); 23 | }); 24 | 25 | test('works as expected with bools', async ({ page }) => { 26 | await page.goto('/'); 27 | let input = page.getByTestId('bools'); 28 | await expect(input).not.toBeChecked(); 29 | input.click(); 30 | await expect(input).toBeChecked(); 31 | const url = new URL(page.url()); 32 | expect(url.searchParams.get('bools')).toBe('true'); 33 | await page.goto('/?bools=true'); 34 | input = page.getByTestId('bools'); 35 | await expect(input).toBeChecked(); 36 | await page.goto('/?bools=other'); 37 | input = page.getByTestId('bools'); 38 | await expect(input).toBeChecked(); 39 | await page.goto('/?bools=false'); 40 | input = page.getByTestId('bools'); 41 | await expect(input).not.toBeChecked(); 42 | }); 43 | 44 | test('works as expected with objects', async ({ page }) => { 45 | await page.goto('/?obj=%7B%22str%22%3A%22%22%7D'); 46 | const input = page.getByTestId('obj-input'); 47 | await input.fill('str'); 48 | const obj = page.getByTestId('obj'); 49 | await expect(obj).toHaveText('{"str":"str"}'); 50 | const url = new URL(page.url()); 51 | expect(url.searchParams.get('obj')).toBe('{"str":"str"}'); 52 | }); 53 | 54 | test("changing an object doesn't trigger reactivity multiple times", async ({ 55 | page, 56 | }) => { 57 | await page.goto('/?obj=%7B%22str%22%3A%22%22%7D'); 58 | const input = page.getByTestId('obj-input'); 59 | await input.fill('s'); 60 | const obj_changes = page.getByTestId('how-many-obj-changes'); 61 | await expect(obj_changes).toHaveText('2'); 62 | }); 63 | 64 | test('works as expected with array', async ({ page }) => { 65 | await page.goto('/'); 66 | const input = page.getByTestId('arr-input'); 67 | await input.click(); 68 | let arr = page.getByTestId('arr'); 69 | expect(await arr.count()).toBe(1); 70 | let url = new URL(page.url()); 71 | expect(url.searchParams.get('arr')).toBe('[0]'); 72 | await input.click(); 73 | arr = page.getByTestId('arr'); 74 | expect(await arr.count()).toBe(2); 75 | url = new URL(page.url()); 76 | expect(url.searchParams.get('arr')).toBe('[0,1]'); 77 | }); 78 | 79 | test("changing an array doesn't trigger reactivity multiple times", async ({ 80 | page, 81 | }) => { 82 | await page.goto('/'); 83 | const input = page.getByTestId('arr-input'); 84 | await input.click(); 85 | const arr_changes = page.getByTestId('how-many-arr-changes'); 86 | await expect(arr_changes).toHaveText('2'); 87 | }); 88 | 89 | test('works as expected with lz', async ({ page }) => { 90 | await page.goto('/'); 91 | const input = page.getByTestId('lz-input'); 92 | await input.fill('lz'); 93 | const str = page.getByTestId('lz'); 94 | await expect(str).toHaveText('lz'); 95 | const url = new URL(page.url()); 96 | expect(url.searchParams.get('lz')).toBe('EQGwXsQ'); 97 | }); 98 | 99 | test("changing an lz doesn't trigger reactivity multiple times", async ({ 100 | page, 101 | }) => { 102 | await page.goto('/'); 103 | const input = page.getByTestId('lz-input'); 104 | await input.fill('l'); 105 | const lz_changes = page.getByTestId('how-many-lz-changes'); 106 | await expect(lz_changes).toHaveText('2'); 107 | }); 108 | 109 | test("changing one parameter doesn't interfere with the rest", async ({ 110 | page, 111 | }) => { 112 | await page.goto('/?something=else&lz=EQGwXsQ'); 113 | const str = page.getByTestId('lz'); 114 | await expect(str).toHaveText('lz'); 115 | const input = page.getByTestId('lz-input'); 116 | await input.fill('lz changed'); 117 | await expect(str).toHaveText('lz changed'); 118 | const url = new URL(page.url()); 119 | expect(url.searchParams.get('lz')).toBe('EQGwXgBAxgFghgOwOYFMAmwg'); 120 | expect(url.searchParams.get('something')).toBe('else'); 121 | }); 122 | 123 | test("changing one parameter doesn't interfere with the hash", async ({ 124 | page, 125 | }) => { 126 | await page.goto('/#test-hash'); 127 | const input = page.getByTestId('str-input'); 128 | await input.fill('str'); 129 | const str = page.getByTestId('str'); 130 | await expect(str).toHaveText('str'); 131 | const url = new URL(page.url()); 132 | expect(url.searchParams.get('str')).toBe('str'); 133 | expect(url.hash).toBe('#test-hash'); 134 | }); 135 | 136 | test("changing two parameters in the same function doesn't negate", async ({ 137 | page, 138 | }) => { 139 | await page.goto('/'); 140 | const btn = page.getByTestId('change-two'); 141 | await btn.click(); 142 | const str = page.getByTestId('str'); 143 | const num = page.getByTestId('num'); 144 | await expect(str).toHaveText('one'); 145 | await expect(num).toHaveText('42'); 146 | const url = new URL(page.url()); 147 | expect(url.searchParams.get('str')).toBe('one'); 148 | expect(url.searchParams.get('num')).toBe('42'); 149 | }); 150 | 151 | test('parameters are kept in alphabetical order by default', async ({ 152 | page, 153 | }) => { 154 | await page.goto('/?num=0'); 155 | const arr_btn = page.getByTestId('arr-input'); 156 | const btn = page.getByTestId('num'); 157 | await btn.click(); 158 | await arr_btn.click(); 159 | const url = new URL(page.url()); 160 | expect(url.search).toBe('?arr=%5B0%5D&num=1'); 161 | }); 162 | 163 | test('parameters are not ordered if updated through a store that has specifically set sort to false', async ({ 164 | page, 165 | }) => { 166 | await page.goto('/'); 167 | const input = page.getByTestId('str-input'); 168 | const str = page.getByTestId('str'); 169 | await input.fill('str'); 170 | const btn = page.getByTestId('arr-unordered-input'); 171 | await btn.click(); 172 | const arr = page.getByTestId('arr-unordered'); 173 | expect(await arr.count()).toBe(1); 174 | await expect(str).toHaveText('str'); 175 | let url = new URL(page.url()); 176 | expect(url.searchParams.get('arr-unordered')).toBe('[0]'); 177 | expect(url.searchParams.get('str')).toBe('str'); 178 | expect(url.search).toBe('?str=str&arr-unordered=%5B0%5D'); 179 | 180 | // expect them to be ordered if you access an ordered store 181 | await input.fill('string'); 182 | await expect(str).toHaveText('string'); 183 | url = new URL(page.url()); 184 | expect(url.searchParams.get('arr-unordered')).toBe('[0]'); 185 | expect(url.searchParams.get('str')).toBe('string'); 186 | expect(url.search).toBe('?arr-unordered=%5B0%5D&str=string'); 187 | }); 188 | }); 189 | 190 | test.describe('queryParameters', () => { 191 | test('works as expected with strings', async ({ page }) => { 192 | await page.goto('/queryparameters'); 193 | const input = page.getByTestId('str-input'); 194 | await input.fill('str'); 195 | const str = page.getByTestId('str'); 196 | await expect(str).toHaveText('str'); 197 | const url = new URL(page.url()); 198 | expect(url.searchParams.get('str')).toBe('str'); 199 | }); 200 | 201 | test('works as expected with numbers', async ({ page }) => { 202 | await page.goto('/queryparameters?num=0'); 203 | const btn = page.getByTestId('num'); 204 | await expect(btn).toHaveText('0'); 205 | btn.click(); 206 | await expect(btn).toHaveText('1'); 207 | const url = new URL(page.url()); 208 | expect(url.searchParams.get('num')).toBe('1'); 209 | }); 210 | 211 | test('works as expected with bools', async ({ page }) => { 212 | await page.goto('/queryparameters'); 213 | let input = page.getByTestId('bools'); 214 | await expect(input).not.toBeChecked(); 215 | input.click(); 216 | await expect(input).toBeChecked(); 217 | const url = new URL(page.url()); 218 | expect(url.searchParams.get('bools')).toBe('true'); 219 | await page.goto('/queryparameters?bools=true'); 220 | input = page.getByTestId('bools'); 221 | await expect(input).toBeChecked(); 222 | await page.goto('/queryparameters?bools=other'); 223 | input = page.getByTestId('bools'); 224 | await expect(input).toBeChecked(); 225 | await page.goto('/queryparameters?bools=false'); 226 | input = page.getByTestId('bools'); 227 | await expect(input).not.toBeChecked(); 228 | }); 229 | 230 | test('works as expected with objects', async ({ page }) => { 231 | await page.goto('/queryparameters?obj=%7B%22str%22%3A%22%22%7D'); 232 | const input = page.getByTestId('obj-input'); 233 | await input.fill('str'); 234 | const obj = page.getByTestId('obj'); 235 | await expect(obj).toHaveText('{"str":"str"}'); 236 | const url = new URL(page.url()); 237 | expect(url.searchParams.get('obj')).toBe('{"str":"str"}'); 238 | }); 239 | 240 | test('works as expected with array', async ({ page }) => { 241 | await page.goto('/queryparameters'); 242 | const input = page.getByTestId('arr-input'); 243 | await input.click(); 244 | let arr = page.getByTestId('arr'); 245 | expect(await arr.count()).toBe(1); 246 | let url = new URL(page.url()); 247 | expect(url.searchParams.get('arr')).toBe('[0]'); 248 | await input.click(); 249 | arr = page.getByTestId('arr'); 250 | expect(await arr.count()).toBe(2); 251 | url = new URL(page.url()); 252 | expect(url.searchParams.get('arr')).toBe('[0,1]'); 253 | }); 254 | 255 | test('works as expected with lz', async ({ page }) => { 256 | await page.goto('/queryparameters'); 257 | const input = page.getByTestId('lz-input'); 258 | await input.fill('lz'); 259 | const str = page.getByTestId('lz'); 260 | await expect(str).toHaveText('lz'); 261 | const url = new URL(page.url()); 262 | expect(url.searchParams.get('lz')).toBe('EQGwXsQ'); 263 | }); 264 | 265 | test("changes to the store doesn't trigger reactivity multiple times", async ({ 266 | page, 267 | }) => { 268 | await page.goto('/queryparameters?bools=false'); 269 | const input = page.getByTestId('str-input'); 270 | await input.fill('s'); 271 | const store_changes = page.getByTestId('how-many-store-changes'); 272 | await expect(store_changes).toHaveText('2'); 273 | }); 274 | 275 | test("changing one parameter doesn't interfere with the rest", async ({ 276 | page, 277 | }) => { 278 | await page.goto('/queryparameters?something=else&lz=EQGwXsQ'); 279 | const str = page.getByTestId('lz'); 280 | await expect(str).toHaveText('lz'); 281 | const input = page.getByTestId('lz-input'); 282 | await input.fill('lz changed'); 283 | await expect(str).toHaveText('lz changed'); 284 | const url = new URL(page.url()); 285 | expect(url.searchParams.get('lz')).toBe('EQGwXgBAxgFghgOwOYFMAmwg'); 286 | expect(url.searchParams.get('something')).toBe('else'); 287 | }); 288 | 289 | test("changing one parameter doesn't interfere with the hash", async ({ 290 | page, 291 | }) => { 292 | await page.goto('/queryparameters#test-hash'); 293 | const input = page.getByTestId('str-input'); 294 | await input.fill('str'); 295 | const str = page.getByTestId('str'); 296 | await expect(str).toHaveText('str'); 297 | const url = new URL(page.url()); 298 | expect(url.searchParams.get('str')).toBe('str'); 299 | expect(url.hash).toBe('#test-hash'); 300 | }); 301 | 302 | test("changing two parameters in the same function doesn't negate", async ({ 303 | page, 304 | }) => { 305 | await page.goto('/queryparameters'); 306 | const btn = page.getByTestId('change-two'); 307 | await btn.click(); 308 | const str = page.getByTestId('str'); 309 | const num = page.getByTestId('num'); 310 | await expect(str).toHaveText('one'); 311 | await expect(num).toHaveText('42'); 312 | const url = new URL(page.url()); 313 | expect(url.searchParams.get('str')).toBe('one'); 314 | expect(url.searchParams.get('num')).toBe('42'); 315 | }); 316 | 317 | test('parameters are kept in alphabetical order by default', async ({ 318 | page, 319 | }) => { 320 | await page.goto('/queryparameters?num=0'); 321 | const arr_btn = page.getByTestId('arr-input'); 322 | const btn = page.getByTestId('num'); 323 | await btn.click(); 324 | await arr_btn.click(); 325 | const url = new URL(page.url()); 326 | expect(url.search).toBe('?arr=%5B0%5D&bools=false&num=1'); 327 | }); 328 | 329 | test('parameters are not ordered if updated through a store that has specifically set sort to false', async ({ 330 | page, 331 | }) => { 332 | await page.goto('/queryparameters'); 333 | const input = page.getByTestId('str-input'); 334 | const str = page.getByTestId('str'); 335 | await input.fill('str'); 336 | const btn = page.getByTestId('arr-unordered-input'); 337 | await btn.click(); 338 | const arr = page.getByTestId('arr-unordered'); 339 | expect(await arr.count()).toBe(1); 340 | await expect(str).toHaveText('str'); 341 | let url = new URL(page.url()); 342 | expect(url.searchParams.get('arr-unordered')).toBe('[0]'); 343 | expect(url.searchParams.get('str')).toBe('str'); 344 | expect(url.search).toBe('?bools=false&str=str&arr-unordered=%5B0%5D'); 345 | 346 | // expect them to be ordered if you access an ordered store 347 | await input.fill('string'); 348 | await expect(str).toHaveText('string'); 349 | url = new URL(page.url()); 350 | expect(url.searchParams.get('arr-unordered')).toBe('[0]'); 351 | expect(url.searchParams.get('str')).toBe('string'); 352 | expect(url.search).toBe( 353 | '?arr-unordered=%5B0%5D&bools=false&str=string', 354 | ); 355 | }); 356 | }); 357 | 358 | test.describe('default values', () => { 359 | test("defaults redirect immediately to the correct url if js is enabled but it doesn't show the paramaters where showDefaults is false", async ({ 360 | page, 361 | }) => { 362 | await page.goto('/default'); 363 | await page.waitForURL((url) => { 364 | return ( 365 | url.searchParams.get('str') === 'def' && 366 | url.searchParams.get('num') === '42' && 367 | url.searchParams.get('str2') === 'str2' 368 | ); 369 | }); 370 | const str = page.getByTestId('str'); 371 | const str_no_show = page.getByTestId('str-no-show'); 372 | const num = page.getByTestId('num'); 373 | const str2 = page.getByTestId('str2'); 374 | const str2_no_show = page.getByTestId('str2-no-show'); 375 | await expect(str).toHaveText('def'); 376 | await expect(num).toHaveText('42'); 377 | await expect(str2).toHaveText('str2'); 378 | const url = new URL(page.url()); 379 | await expect(str_no_show).toHaveText('no-show'); 380 | await expect(str2_no_show).toHaveText('str2-no-show'); 381 | expect(url.searchParams.get('str-no-show')).toBeNull(); 382 | expect(url.searchParams.get('str2-no-show')).toBeNull(); 383 | }); 384 | }); 385 | 386 | test.describe('debounce history entry', () => { 387 | test('debounce update the url only after 1000ms (set on the store)', async ({ 388 | page, 389 | }) => { 390 | await page.goto('/debounce?num=0'); 391 | const str = page.getByTestId('str'); 392 | const input = page.getByTestId('str-input'); 393 | await input.fill('str'); 394 | let url = new URL(page.url()); 395 | await expect(str).toHaveText('str'); 396 | expect(url.searchParams.get('str')).toBeNull(); 397 | await new Promise((r) => setTimeout(r, 1100)); 398 | url = new URL(page.url()); 399 | expect(url.searchParams.get('str')).toBe('str'); 400 | 401 | const num = page.getByTestId('num'); 402 | await num.click(); 403 | url = new URL(page.url()); 404 | await expect(num).toHaveText('1'); 405 | expect(url.searchParams.get('num')).toBe('0'); 406 | await new Promise((r) => setTimeout(r, 1100)); 407 | url = new URL(page.url()); 408 | expect(url.searchParams.get('num')).toBe('1'); 409 | 410 | const str2 = page.getByTestId('str2'); 411 | const str2_input = page.getByTestId('str2-input'); 412 | await str2_input.fill('str2'); 413 | url = new URL(page.url()); 414 | await expect(str2).toHaveText('str2'); 415 | expect(url.searchParams.get('str2')).toBeNull(); 416 | await new Promise((r) => setTimeout(r, 1100)); 417 | url = new URL(page.url()); 418 | expect(url.searchParams.get('str2')).toBe('str2'); 419 | 420 | const change_both = page.getByTestId('change-both'); 421 | await change_both.click(); 422 | url = new URL(page.url()); 423 | await expect(str2).toHaveText('changed'); 424 | await expect(num).toHaveText('2'); 425 | expect(url.searchParams.get('str2')).toBe('str2'); 426 | expect(url.searchParams.get('num')).toBe('1'); 427 | await new Promise((r) => setTimeout(r, 1100)); 428 | url = new URL(page.url()); 429 | expect(url.searchParams.get('str2')).toBe('changed'); 430 | expect(url.searchParams.get('num')).toBe('2'); 431 | }); 432 | }); 433 | 434 | test.describe('default values during ssr', () => { 435 | test.use({ 436 | javaScriptEnabled: false, 437 | }); 438 | 439 | test("defaults don't redirect but the value is still present", async ({ 440 | page, 441 | }) => { 442 | await page.goto('/default'); 443 | const str = page.getByTestId('str'); 444 | const num = page.getByTestId('num'); 445 | const str2 = page.getByTestId('str2'); 446 | await expect(str).toHaveText('def'); 447 | await expect(num).toHaveText('42'); 448 | await expect(str2).toHaveText('str2'); 449 | }); 450 | }); 451 | 452 | test.describe('equalityFn to specify when the store is the same as before (not triggering reactivity but still navigating)', () => { 453 | test('equalityFn impact the amount of rerenders with queryParam', async ({ 454 | page, 455 | }) => { 456 | await page.goto('/equalityFn?obj={"str": ""}&str2='); 457 | const str_input = page.getByTestId('str-input'); 458 | str_input.fill('s'); 459 | const obj_changes = page.getByTestId('how-many-obj-changes'); 460 | await expect(obj_changes).toHaveText('4'); 461 | }); 462 | 463 | test('equalityFn impact the amount of rerenders with queryParameters', async ({ 464 | page, 465 | }) => { 466 | await page.goto('/equalityFn?obj={"str": ""}&str2='); 467 | const str_input = page.getByTestId('str2-input'); 468 | str_input.fill('s'); 469 | const obj_changes = page.getByTestId('how-many-store-changes'); 470 | await expect(obj_changes).toHaveText('4'); 471 | }); 472 | }); 473 | -------------------------------------------------------------------------------- /playground/pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | dependencies: 8 | sveltekit-search-params: 9 | specifier: link:.. 10 | version: link:.. 11 | 12 | devDependencies: 13 | '@sveltejs/adapter-auto': 14 | specifier: ^3.1.1 15 | version: 3.1.1(@sveltejs/kit@2.5.0) 16 | '@sveltejs/kit': 17 | specifier: ^2.5.0 18 | version: 2.5.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.11)(vite@5.1.3) 19 | '@sveltejs/vite-plugin-svelte': 20 | specifier: ^3.0.2 21 | version: 3.0.2(svelte@4.2.11)(vite@5.1.3) 22 | svelte: 23 | specifier: ^4.2.11 24 | version: 4.2.11 25 | svelte-check: 26 | specifier: ^3.6.4 27 | version: 3.6.4(svelte@4.2.11) 28 | tslib: 29 | specifier: ^2.6.2 30 | version: 2.6.2 31 | typescript: 32 | specifier: ^5.3.3 33 | version: 5.3.3 34 | vite: 35 | specifier: ^5.1.3 36 | version: 5.1.3 37 | 38 | packages: 39 | 40 | /@ampproject/remapping@2.2.1: 41 | resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} 42 | engines: {node: '>=6.0.0'} 43 | dependencies: 44 | '@jridgewell/gen-mapping': 0.3.3 45 | '@jridgewell/trace-mapping': 0.3.22 46 | dev: true 47 | 48 | /@esbuild/aix-ppc64@0.19.12: 49 | resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} 50 | engines: {node: '>=12'} 51 | cpu: [ppc64] 52 | os: [aix] 53 | requiresBuild: true 54 | dev: true 55 | optional: true 56 | 57 | /@esbuild/android-arm64@0.19.12: 58 | resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==} 59 | engines: {node: '>=12'} 60 | cpu: [arm64] 61 | os: [android] 62 | requiresBuild: true 63 | dev: true 64 | optional: true 65 | 66 | /@esbuild/android-arm@0.19.12: 67 | resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==} 68 | engines: {node: '>=12'} 69 | cpu: [arm] 70 | os: [android] 71 | requiresBuild: true 72 | dev: true 73 | optional: true 74 | 75 | /@esbuild/android-x64@0.19.12: 76 | resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==} 77 | engines: {node: '>=12'} 78 | cpu: [x64] 79 | os: [android] 80 | requiresBuild: true 81 | dev: true 82 | optional: true 83 | 84 | /@esbuild/darwin-arm64@0.19.12: 85 | resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==} 86 | engines: {node: '>=12'} 87 | cpu: [arm64] 88 | os: [darwin] 89 | requiresBuild: true 90 | dev: true 91 | optional: true 92 | 93 | /@esbuild/darwin-x64@0.19.12: 94 | resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==} 95 | engines: {node: '>=12'} 96 | cpu: [x64] 97 | os: [darwin] 98 | requiresBuild: true 99 | dev: true 100 | optional: true 101 | 102 | /@esbuild/freebsd-arm64@0.19.12: 103 | resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==} 104 | engines: {node: '>=12'} 105 | cpu: [arm64] 106 | os: [freebsd] 107 | requiresBuild: true 108 | dev: true 109 | optional: true 110 | 111 | /@esbuild/freebsd-x64@0.19.12: 112 | resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==} 113 | engines: {node: '>=12'} 114 | cpu: [x64] 115 | os: [freebsd] 116 | requiresBuild: true 117 | dev: true 118 | optional: true 119 | 120 | /@esbuild/linux-arm64@0.19.12: 121 | resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==} 122 | engines: {node: '>=12'} 123 | cpu: [arm64] 124 | os: [linux] 125 | requiresBuild: true 126 | dev: true 127 | optional: true 128 | 129 | /@esbuild/linux-arm@0.19.12: 130 | resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==} 131 | engines: {node: '>=12'} 132 | cpu: [arm] 133 | os: [linux] 134 | requiresBuild: true 135 | dev: true 136 | optional: true 137 | 138 | /@esbuild/linux-ia32@0.19.12: 139 | resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==} 140 | engines: {node: '>=12'} 141 | cpu: [ia32] 142 | os: [linux] 143 | requiresBuild: true 144 | dev: true 145 | optional: true 146 | 147 | /@esbuild/linux-loong64@0.19.12: 148 | resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==} 149 | engines: {node: '>=12'} 150 | cpu: [loong64] 151 | os: [linux] 152 | requiresBuild: true 153 | dev: true 154 | optional: true 155 | 156 | /@esbuild/linux-mips64el@0.19.12: 157 | resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==} 158 | engines: {node: '>=12'} 159 | cpu: [mips64el] 160 | os: [linux] 161 | requiresBuild: true 162 | dev: true 163 | optional: true 164 | 165 | /@esbuild/linux-ppc64@0.19.12: 166 | resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==} 167 | engines: {node: '>=12'} 168 | cpu: [ppc64] 169 | os: [linux] 170 | requiresBuild: true 171 | dev: true 172 | optional: true 173 | 174 | /@esbuild/linux-riscv64@0.19.12: 175 | resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==} 176 | engines: {node: '>=12'} 177 | cpu: [riscv64] 178 | os: [linux] 179 | requiresBuild: true 180 | dev: true 181 | optional: true 182 | 183 | /@esbuild/linux-s390x@0.19.12: 184 | resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==} 185 | engines: {node: '>=12'} 186 | cpu: [s390x] 187 | os: [linux] 188 | requiresBuild: true 189 | dev: true 190 | optional: true 191 | 192 | /@esbuild/linux-x64@0.19.12: 193 | resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==} 194 | engines: {node: '>=12'} 195 | cpu: [x64] 196 | os: [linux] 197 | requiresBuild: true 198 | dev: true 199 | optional: true 200 | 201 | /@esbuild/netbsd-x64@0.19.12: 202 | resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==} 203 | engines: {node: '>=12'} 204 | cpu: [x64] 205 | os: [netbsd] 206 | requiresBuild: true 207 | dev: true 208 | optional: true 209 | 210 | /@esbuild/openbsd-x64@0.19.12: 211 | resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==} 212 | engines: {node: '>=12'} 213 | cpu: [x64] 214 | os: [openbsd] 215 | requiresBuild: true 216 | dev: true 217 | optional: true 218 | 219 | /@esbuild/sunos-x64@0.19.12: 220 | resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==} 221 | engines: {node: '>=12'} 222 | cpu: [x64] 223 | os: [sunos] 224 | requiresBuild: true 225 | dev: true 226 | optional: true 227 | 228 | /@esbuild/win32-arm64@0.19.12: 229 | resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==} 230 | engines: {node: '>=12'} 231 | cpu: [arm64] 232 | os: [win32] 233 | requiresBuild: true 234 | dev: true 235 | optional: true 236 | 237 | /@esbuild/win32-ia32@0.19.12: 238 | resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==} 239 | engines: {node: '>=12'} 240 | cpu: [ia32] 241 | os: [win32] 242 | requiresBuild: true 243 | dev: true 244 | optional: true 245 | 246 | /@esbuild/win32-x64@0.19.12: 247 | resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==} 248 | engines: {node: '>=12'} 249 | cpu: [x64] 250 | os: [win32] 251 | requiresBuild: true 252 | dev: true 253 | optional: true 254 | 255 | /@jridgewell/gen-mapping@0.3.3: 256 | resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} 257 | engines: {node: '>=6.0.0'} 258 | dependencies: 259 | '@jridgewell/set-array': 1.1.2 260 | '@jridgewell/sourcemap-codec': 1.4.15 261 | '@jridgewell/trace-mapping': 0.3.22 262 | dev: true 263 | 264 | /@jridgewell/resolve-uri@3.1.2: 265 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} 266 | engines: {node: '>=6.0.0'} 267 | dev: true 268 | 269 | /@jridgewell/set-array@1.1.2: 270 | resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} 271 | engines: {node: '>=6.0.0'} 272 | dev: true 273 | 274 | /@jridgewell/sourcemap-codec@1.4.15: 275 | resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} 276 | dev: true 277 | 278 | /@jridgewell/trace-mapping@0.3.22: 279 | resolution: {integrity: sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==} 280 | dependencies: 281 | '@jridgewell/resolve-uri': 3.1.2 282 | '@jridgewell/sourcemap-codec': 1.4.15 283 | dev: true 284 | 285 | /@nodelib/fs.scandir@2.1.5: 286 | resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} 287 | engines: {node: '>= 8'} 288 | dependencies: 289 | '@nodelib/fs.stat': 2.0.5 290 | run-parallel: 1.2.0 291 | dev: true 292 | 293 | /@nodelib/fs.stat@2.0.5: 294 | resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} 295 | engines: {node: '>= 8'} 296 | dev: true 297 | 298 | /@nodelib/fs.walk@1.2.8: 299 | resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} 300 | engines: {node: '>= 8'} 301 | dependencies: 302 | '@nodelib/fs.scandir': 2.1.5 303 | fastq: 1.17.1 304 | dev: true 305 | 306 | /@polka/url@1.0.0-next.24: 307 | resolution: {integrity: sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==} 308 | dev: true 309 | 310 | /@rollup/rollup-android-arm-eabi@4.12.0: 311 | resolution: {integrity: sha512-+ac02NL/2TCKRrJu2wffk1kZ+RyqxVUlbjSagNgPm94frxtr+XDL12E5Ll1enWskLrtrZ2r8L3wED1orIibV/w==} 312 | cpu: [arm] 313 | os: [android] 314 | requiresBuild: true 315 | dev: true 316 | optional: true 317 | 318 | /@rollup/rollup-android-arm64@4.12.0: 319 | resolution: {integrity: sha512-OBqcX2BMe6nvjQ0Nyp7cC90cnumt8PXmO7Dp3gfAju/6YwG0Tj74z1vKrfRz7qAv23nBcYM8BCbhrsWqO7PzQQ==} 320 | cpu: [arm64] 321 | os: [android] 322 | requiresBuild: true 323 | dev: true 324 | optional: true 325 | 326 | /@rollup/rollup-darwin-arm64@4.12.0: 327 | resolution: {integrity: sha512-X64tZd8dRE/QTrBIEs63kaOBG0b5GVEd3ccoLtyf6IdXtHdh8h+I56C2yC3PtC9Ucnv0CpNFJLqKFVgCYe0lOQ==} 328 | cpu: [arm64] 329 | os: [darwin] 330 | requiresBuild: true 331 | dev: true 332 | optional: true 333 | 334 | /@rollup/rollup-darwin-x64@4.12.0: 335 | resolution: {integrity: sha512-cc71KUZoVbUJmGP2cOuiZ9HSOP14AzBAThn3OU+9LcA1+IUqswJyR1cAJj3Mg55HbjZP6OLAIscbQsQLrpgTOg==} 336 | cpu: [x64] 337 | os: [darwin] 338 | requiresBuild: true 339 | dev: true 340 | optional: true 341 | 342 | /@rollup/rollup-linux-arm-gnueabihf@4.12.0: 343 | resolution: {integrity: sha512-a6w/Y3hyyO6GlpKL2xJ4IOh/7d+APaqLYdMf86xnczU3nurFTaVN9s9jOXQg97BE4nYm/7Ga51rjec5nfRdrvA==} 344 | cpu: [arm] 345 | os: [linux] 346 | requiresBuild: true 347 | dev: true 348 | optional: true 349 | 350 | /@rollup/rollup-linux-arm64-gnu@4.12.0: 351 | resolution: {integrity: sha512-0fZBq27b+D7Ar5CQMofVN8sggOVhEtzFUwOwPppQt0k+VR+7UHMZZY4y+64WJ06XOhBTKXtQB/Sv0NwQMXyNAA==} 352 | cpu: [arm64] 353 | os: [linux] 354 | requiresBuild: true 355 | dev: true 356 | optional: true 357 | 358 | /@rollup/rollup-linux-arm64-musl@4.12.0: 359 | resolution: {integrity: sha512-eTvzUS3hhhlgeAv6bfigekzWZjaEX9xP9HhxB0Dvrdbkk5w/b+1Sxct2ZuDxNJKzsRStSq1EaEkVSEe7A7ipgQ==} 360 | cpu: [arm64] 361 | os: [linux] 362 | requiresBuild: true 363 | dev: true 364 | optional: true 365 | 366 | /@rollup/rollup-linux-riscv64-gnu@4.12.0: 367 | resolution: {integrity: sha512-ix+qAB9qmrCRiaO71VFfY8rkiAZJL8zQRXveS27HS+pKdjwUfEhqo2+YF2oI+H/22Xsiski+qqwIBxVewLK7sw==} 368 | cpu: [riscv64] 369 | os: [linux] 370 | requiresBuild: true 371 | dev: true 372 | optional: true 373 | 374 | /@rollup/rollup-linux-x64-gnu@4.12.0: 375 | resolution: {integrity: sha512-TenQhZVOtw/3qKOPa7d+QgkeM6xY0LtwzR8OplmyL5LrgTWIXpTQg2Q2ycBf8jm+SFW2Wt/DTn1gf7nFp3ssVA==} 376 | cpu: [x64] 377 | os: [linux] 378 | requiresBuild: true 379 | dev: true 380 | optional: true 381 | 382 | /@rollup/rollup-linux-x64-musl@4.12.0: 383 | resolution: {integrity: sha512-LfFdRhNnW0zdMvdCb5FNuWlls2WbbSridJvxOvYWgSBOYZtgBfW9UGNJG//rwMqTX1xQE9BAodvMH9tAusKDUw==} 384 | cpu: [x64] 385 | os: [linux] 386 | requiresBuild: true 387 | dev: true 388 | optional: true 389 | 390 | /@rollup/rollup-win32-arm64-msvc@4.12.0: 391 | resolution: {integrity: sha512-JPDxovheWNp6d7AHCgsUlkuCKvtu3RB55iNEkaQcf0ttsDU/JZF+iQnYcQJSk/7PtT4mjjVG8N1kpwnI9SLYaw==} 392 | cpu: [arm64] 393 | os: [win32] 394 | requiresBuild: true 395 | dev: true 396 | optional: true 397 | 398 | /@rollup/rollup-win32-ia32-msvc@4.12.0: 399 | resolution: {integrity: sha512-fjtuvMWRGJn1oZacG8IPnzIV6GF2/XG+h71FKn76OYFqySXInJtseAqdprVTDTyqPxQOG9Exak5/E9Z3+EJ8ZA==} 400 | cpu: [ia32] 401 | os: [win32] 402 | requiresBuild: true 403 | dev: true 404 | optional: true 405 | 406 | /@rollup/rollup-win32-x64-msvc@4.12.0: 407 | resolution: {integrity: sha512-ZYmr5mS2wd4Dew/JjT0Fqi2NPB/ZhZ2VvPp7SmvPZb4Y1CG/LRcS6tcRo2cYU7zLK5A7cdbhWnnWmUjoI4qapg==} 408 | cpu: [x64] 409 | os: [win32] 410 | requiresBuild: true 411 | dev: true 412 | optional: true 413 | 414 | /@sveltejs/adapter-auto@3.1.1(@sveltejs/kit@2.5.0): 415 | resolution: {integrity: sha512-6LeZft2Fo/4HfmLBi5CucMYmgRxgcETweQl/yQoZo/895K3S9YWYN4Sfm/IhwlIpbJp3QNvhKmwCHbsqQNYQpw==} 416 | peerDependencies: 417 | '@sveltejs/kit': ^2.0.0 418 | dependencies: 419 | '@sveltejs/kit': 2.5.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.11)(vite@5.1.3) 420 | import-meta-resolve: 4.0.0 421 | dev: true 422 | 423 | /@sveltejs/kit@2.5.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.11)(vite@5.1.3): 424 | resolution: {integrity: sha512-1uyXvzC2Lu1FZa30T4y5jUAC21R309ZMRG0TPt+PPPbNUoDpy8zSmSNVWYaBWxYDqLGQ5oPNWvjvvF2IjJ1jmA==} 425 | engines: {node: '>=18.13'} 426 | hasBin: true 427 | requiresBuild: true 428 | peerDependencies: 429 | '@sveltejs/vite-plugin-svelte': ^3.0.0 430 | svelte: ^4.0.0 || ^5.0.0-next.0 431 | vite: ^5.0.3 432 | dependencies: 433 | '@sveltejs/vite-plugin-svelte': 3.0.2(svelte@4.2.11)(vite@5.1.3) 434 | '@types/cookie': 0.6.0 435 | cookie: 0.6.0 436 | devalue: 4.3.2 437 | esm-env: 1.0.0 438 | import-meta-resolve: 4.0.0 439 | kleur: 4.1.5 440 | magic-string: 0.30.7 441 | mrmime: 2.0.0 442 | sade: 1.8.1 443 | set-cookie-parser: 2.6.0 444 | sirv: 2.0.4 445 | svelte: 4.2.11 446 | tiny-glob: 0.2.9 447 | vite: 5.1.3 448 | dev: true 449 | 450 | /@sveltejs/vite-plugin-svelte-inspector@2.0.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.11)(vite@5.1.3): 451 | resolution: {integrity: sha512-gjr9ZFg1BSlIpfZ4PRewigrvYmHWbDrq2uvvPB1AmTWKuM+dI1JXQSUu2pIrYLb/QncyiIGkFDFKTwJ0XqQZZg==} 452 | engines: {node: ^18.0.0 || >=20} 453 | peerDependencies: 454 | '@sveltejs/vite-plugin-svelte': ^3.0.0 455 | svelte: ^4.0.0 || ^5.0.0-next.0 456 | vite: ^5.0.0 457 | dependencies: 458 | '@sveltejs/vite-plugin-svelte': 3.0.2(svelte@4.2.11)(vite@5.1.3) 459 | debug: 4.3.4 460 | svelte: 4.2.11 461 | vite: 5.1.3 462 | transitivePeerDependencies: 463 | - supports-color 464 | dev: true 465 | 466 | /@sveltejs/vite-plugin-svelte@3.0.2(svelte@4.2.11)(vite@5.1.3): 467 | resolution: {integrity: sha512-MpmF/cju2HqUls50WyTHQBZUV3ovV/Uk8k66AN2gwHogNAG8wnW8xtZDhzNBsFJJuvmq1qnzA5kE7YfMJNFv2Q==} 468 | engines: {node: ^18.0.0 || >=20} 469 | peerDependencies: 470 | svelte: ^4.0.0 || ^5.0.0-next.0 471 | vite: ^5.0.0 472 | dependencies: 473 | '@sveltejs/vite-plugin-svelte-inspector': 2.0.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.11)(vite@5.1.3) 474 | debug: 4.3.4 475 | deepmerge: 4.3.1 476 | kleur: 4.1.5 477 | magic-string: 0.30.7 478 | svelte: 4.2.11 479 | svelte-hmr: 0.15.3(svelte@4.2.11) 480 | vite: 5.1.3 481 | vitefu: 0.2.5(vite@5.1.3) 482 | transitivePeerDependencies: 483 | - supports-color 484 | dev: true 485 | 486 | /@types/cookie@0.6.0: 487 | resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} 488 | dev: true 489 | 490 | /@types/estree@1.0.5: 491 | resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} 492 | dev: true 493 | 494 | /@types/pug@2.0.10: 495 | resolution: {integrity: sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==} 496 | dev: true 497 | 498 | /acorn@8.11.3: 499 | resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} 500 | engines: {node: '>=0.4.0'} 501 | hasBin: true 502 | dev: true 503 | 504 | /anymatch@3.1.3: 505 | resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} 506 | engines: {node: '>= 8'} 507 | dependencies: 508 | normalize-path: 3.0.0 509 | picomatch: 2.3.1 510 | dev: true 511 | 512 | /aria-query@5.3.0: 513 | resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} 514 | dependencies: 515 | dequal: 2.0.3 516 | dev: true 517 | 518 | /axobject-query@4.0.0: 519 | resolution: {integrity: sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==} 520 | dependencies: 521 | dequal: 2.0.3 522 | dev: true 523 | 524 | /balanced-match@1.0.2: 525 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 526 | dev: true 527 | 528 | /binary-extensions@2.2.0: 529 | resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} 530 | engines: {node: '>=8'} 531 | dev: true 532 | 533 | /brace-expansion@1.1.11: 534 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} 535 | dependencies: 536 | balanced-match: 1.0.2 537 | concat-map: 0.0.1 538 | dev: true 539 | 540 | /braces@3.0.2: 541 | resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} 542 | engines: {node: '>=8'} 543 | dependencies: 544 | fill-range: 7.0.1 545 | dev: true 546 | 547 | /buffer-crc32@0.2.13: 548 | resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} 549 | dev: true 550 | 551 | /callsites@3.1.0: 552 | resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} 553 | engines: {node: '>=6'} 554 | dev: true 555 | 556 | /chokidar@3.6.0: 557 | resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} 558 | engines: {node: '>= 8.10.0'} 559 | dependencies: 560 | anymatch: 3.1.3 561 | braces: 3.0.2 562 | glob-parent: 5.1.2 563 | is-binary-path: 2.1.0 564 | is-glob: 4.0.3 565 | normalize-path: 3.0.0 566 | readdirp: 3.6.0 567 | optionalDependencies: 568 | fsevents: 2.3.3 569 | dev: true 570 | 571 | /code-red@1.0.4: 572 | resolution: {integrity: sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==} 573 | dependencies: 574 | '@jridgewell/sourcemap-codec': 1.4.15 575 | '@types/estree': 1.0.5 576 | acorn: 8.11.3 577 | estree-walker: 3.0.3 578 | periscopic: 3.1.0 579 | dev: true 580 | 581 | /concat-map@0.0.1: 582 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} 583 | dev: true 584 | 585 | /cookie@0.6.0: 586 | resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} 587 | engines: {node: '>= 0.6'} 588 | dev: true 589 | 590 | /css-tree@2.3.1: 591 | resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} 592 | engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} 593 | dependencies: 594 | mdn-data: 2.0.30 595 | source-map-js: 1.0.2 596 | dev: true 597 | 598 | /debug@4.3.4: 599 | resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} 600 | engines: {node: '>=6.0'} 601 | peerDependencies: 602 | supports-color: '*' 603 | peerDependenciesMeta: 604 | supports-color: 605 | optional: true 606 | dependencies: 607 | ms: 2.1.2 608 | dev: true 609 | 610 | /deepmerge@4.3.1: 611 | resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} 612 | engines: {node: '>=0.10.0'} 613 | dev: true 614 | 615 | /dequal@2.0.3: 616 | resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} 617 | engines: {node: '>=6'} 618 | dev: true 619 | 620 | /detect-indent@6.1.0: 621 | resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} 622 | engines: {node: '>=8'} 623 | dev: true 624 | 625 | /devalue@4.3.2: 626 | resolution: {integrity: sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg==} 627 | dev: true 628 | 629 | /es6-promise@3.3.1: 630 | resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==} 631 | dev: true 632 | 633 | /esbuild@0.19.12: 634 | resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==} 635 | engines: {node: '>=12'} 636 | hasBin: true 637 | requiresBuild: true 638 | optionalDependencies: 639 | '@esbuild/aix-ppc64': 0.19.12 640 | '@esbuild/android-arm': 0.19.12 641 | '@esbuild/android-arm64': 0.19.12 642 | '@esbuild/android-x64': 0.19.12 643 | '@esbuild/darwin-arm64': 0.19.12 644 | '@esbuild/darwin-x64': 0.19.12 645 | '@esbuild/freebsd-arm64': 0.19.12 646 | '@esbuild/freebsd-x64': 0.19.12 647 | '@esbuild/linux-arm': 0.19.12 648 | '@esbuild/linux-arm64': 0.19.12 649 | '@esbuild/linux-ia32': 0.19.12 650 | '@esbuild/linux-loong64': 0.19.12 651 | '@esbuild/linux-mips64el': 0.19.12 652 | '@esbuild/linux-ppc64': 0.19.12 653 | '@esbuild/linux-riscv64': 0.19.12 654 | '@esbuild/linux-s390x': 0.19.12 655 | '@esbuild/linux-x64': 0.19.12 656 | '@esbuild/netbsd-x64': 0.19.12 657 | '@esbuild/openbsd-x64': 0.19.12 658 | '@esbuild/sunos-x64': 0.19.12 659 | '@esbuild/win32-arm64': 0.19.12 660 | '@esbuild/win32-ia32': 0.19.12 661 | '@esbuild/win32-x64': 0.19.12 662 | dev: true 663 | 664 | /esm-env@1.0.0: 665 | resolution: {integrity: sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==} 666 | dev: true 667 | 668 | /estree-walker@3.0.3: 669 | resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} 670 | dependencies: 671 | '@types/estree': 1.0.5 672 | dev: true 673 | 674 | /fast-glob@3.3.2: 675 | resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} 676 | engines: {node: '>=8.6.0'} 677 | dependencies: 678 | '@nodelib/fs.stat': 2.0.5 679 | '@nodelib/fs.walk': 1.2.8 680 | glob-parent: 5.1.2 681 | merge2: 1.4.1 682 | micromatch: 4.0.5 683 | dev: true 684 | 685 | /fastq@1.17.1: 686 | resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} 687 | dependencies: 688 | reusify: 1.0.4 689 | dev: true 690 | 691 | /fill-range@7.0.1: 692 | resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} 693 | engines: {node: '>=8'} 694 | dependencies: 695 | to-regex-range: 5.0.1 696 | dev: true 697 | 698 | /fs.realpath@1.0.0: 699 | resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} 700 | dev: true 701 | 702 | /fsevents@2.3.3: 703 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 704 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 705 | os: [darwin] 706 | requiresBuild: true 707 | dev: true 708 | optional: true 709 | 710 | /glob-parent@5.1.2: 711 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 712 | engines: {node: '>= 6'} 713 | dependencies: 714 | is-glob: 4.0.3 715 | dev: true 716 | 717 | /glob@7.2.3: 718 | resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} 719 | dependencies: 720 | fs.realpath: 1.0.0 721 | inflight: 1.0.6 722 | inherits: 2.0.4 723 | minimatch: 3.1.2 724 | once: 1.4.0 725 | path-is-absolute: 1.0.1 726 | dev: true 727 | 728 | /globalyzer@0.1.0: 729 | resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==} 730 | dev: true 731 | 732 | /globrex@0.1.2: 733 | resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} 734 | dev: true 735 | 736 | /graceful-fs@4.2.11: 737 | resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} 738 | dev: true 739 | 740 | /import-fresh@3.3.0: 741 | resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} 742 | engines: {node: '>=6'} 743 | dependencies: 744 | parent-module: 1.0.1 745 | resolve-from: 4.0.0 746 | dev: true 747 | 748 | /import-meta-resolve@4.0.0: 749 | resolution: {integrity: sha512-okYUR7ZQPH+efeuMJGlq4f8ubUgO50kByRPyt/Cy1Io4PSRsPjxME+YlVaCOx+NIToW7hCsZNFJyTPFFKepRSA==} 750 | dev: true 751 | 752 | /inflight@1.0.6: 753 | resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} 754 | dependencies: 755 | once: 1.4.0 756 | wrappy: 1.0.2 757 | dev: true 758 | 759 | /inherits@2.0.4: 760 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 761 | dev: true 762 | 763 | /is-binary-path@2.1.0: 764 | resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} 765 | engines: {node: '>=8'} 766 | dependencies: 767 | binary-extensions: 2.2.0 768 | dev: true 769 | 770 | /is-extglob@2.1.1: 771 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 772 | engines: {node: '>=0.10.0'} 773 | dev: true 774 | 775 | /is-glob@4.0.3: 776 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 777 | engines: {node: '>=0.10.0'} 778 | dependencies: 779 | is-extglob: 2.1.1 780 | dev: true 781 | 782 | /is-number@7.0.0: 783 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 784 | engines: {node: '>=0.12.0'} 785 | dev: true 786 | 787 | /is-reference@3.0.2: 788 | resolution: {integrity: sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==} 789 | dependencies: 790 | '@types/estree': 1.0.5 791 | dev: true 792 | 793 | /kleur@4.1.5: 794 | resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} 795 | engines: {node: '>=6'} 796 | dev: true 797 | 798 | /locate-character@3.0.0: 799 | resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} 800 | dev: true 801 | 802 | /magic-string@0.30.7: 803 | resolution: {integrity: sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==} 804 | engines: {node: '>=12'} 805 | dependencies: 806 | '@jridgewell/sourcemap-codec': 1.4.15 807 | dev: true 808 | 809 | /mdn-data@2.0.30: 810 | resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} 811 | dev: true 812 | 813 | /merge2@1.4.1: 814 | resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} 815 | engines: {node: '>= 8'} 816 | dev: true 817 | 818 | /micromatch@4.0.5: 819 | resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} 820 | engines: {node: '>=8.6'} 821 | dependencies: 822 | braces: 3.0.2 823 | picomatch: 2.3.1 824 | dev: true 825 | 826 | /min-indent@1.0.1: 827 | resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} 828 | engines: {node: '>=4'} 829 | dev: true 830 | 831 | /minimatch@3.1.2: 832 | resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} 833 | dependencies: 834 | brace-expansion: 1.1.11 835 | dev: true 836 | 837 | /minimist@1.2.8: 838 | resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} 839 | dev: true 840 | 841 | /mkdirp@0.5.6: 842 | resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} 843 | hasBin: true 844 | dependencies: 845 | minimist: 1.2.8 846 | dev: true 847 | 848 | /mri@1.2.0: 849 | resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} 850 | engines: {node: '>=4'} 851 | dev: true 852 | 853 | /mrmime@2.0.0: 854 | resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==} 855 | engines: {node: '>=10'} 856 | dev: true 857 | 858 | /ms@2.1.2: 859 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} 860 | dev: true 861 | 862 | /nanoid@3.3.7: 863 | resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} 864 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 865 | hasBin: true 866 | dev: true 867 | 868 | /normalize-path@3.0.0: 869 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} 870 | engines: {node: '>=0.10.0'} 871 | dev: true 872 | 873 | /once@1.4.0: 874 | resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} 875 | dependencies: 876 | wrappy: 1.0.2 877 | dev: true 878 | 879 | /parent-module@1.0.1: 880 | resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} 881 | engines: {node: '>=6'} 882 | dependencies: 883 | callsites: 3.1.0 884 | dev: true 885 | 886 | /path-is-absolute@1.0.1: 887 | resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} 888 | engines: {node: '>=0.10.0'} 889 | dev: true 890 | 891 | /periscopic@3.1.0: 892 | resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==} 893 | dependencies: 894 | '@types/estree': 1.0.5 895 | estree-walker: 3.0.3 896 | is-reference: 3.0.2 897 | dev: true 898 | 899 | /picocolors@1.0.0: 900 | resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} 901 | dev: true 902 | 903 | /picomatch@2.3.1: 904 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 905 | engines: {node: '>=8.6'} 906 | dev: true 907 | 908 | /postcss@8.4.35: 909 | resolution: {integrity: sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==} 910 | engines: {node: ^10 || ^12 || >=14} 911 | dependencies: 912 | nanoid: 3.3.7 913 | picocolors: 1.0.0 914 | source-map-js: 1.0.2 915 | dev: true 916 | 917 | /queue-microtask@1.2.3: 918 | resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} 919 | dev: true 920 | 921 | /readdirp@3.6.0: 922 | resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} 923 | engines: {node: '>=8.10.0'} 924 | dependencies: 925 | picomatch: 2.3.1 926 | dev: true 927 | 928 | /resolve-from@4.0.0: 929 | resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} 930 | engines: {node: '>=4'} 931 | dev: true 932 | 933 | /reusify@1.0.4: 934 | resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} 935 | engines: {iojs: '>=1.0.0', node: '>=0.10.0'} 936 | dev: true 937 | 938 | /rimraf@2.7.1: 939 | resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} 940 | hasBin: true 941 | dependencies: 942 | glob: 7.2.3 943 | dev: true 944 | 945 | /rollup@4.12.0: 946 | resolution: {integrity: sha512-wz66wn4t1OHIJw3+XU7mJJQV/2NAfw5OAk6G6Hoo3zcvz/XOfQ52Vgi+AN4Uxoxi0KBBwk2g8zPrTDA4btSB/Q==} 947 | engines: {node: '>=18.0.0', npm: '>=8.0.0'} 948 | hasBin: true 949 | dependencies: 950 | '@types/estree': 1.0.5 951 | optionalDependencies: 952 | '@rollup/rollup-android-arm-eabi': 4.12.0 953 | '@rollup/rollup-android-arm64': 4.12.0 954 | '@rollup/rollup-darwin-arm64': 4.12.0 955 | '@rollup/rollup-darwin-x64': 4.12.0 956 | '@rollup/rollup-linux-arm-gnueabihf': 4.12.0 957 | '@rollup/rollup-linux-arm64-gnu': 4.12.0 958 | '@rollup/rollup-linux-arm64-musl': 4.12.0 959 | '@rollup/rollup-linux-riscv64-gnu': 4.12.0 960 | '@rollup/rollup-linux-x64-gnu': 4.12.0 961 | '@rollup/rollup-linux-x64-musl': 4.12.0 962 | '@rollup/rollup-win32-arm64-msvc': 4.12.0 963 | '@rollup/rollup-win32-ia32-msvc': 4.12.0 964 | '@rollup/rollup-win32-x64-msvc': 4.12.0 965 | fsevents: 2.3.3 966 | dev: true 967 | 968 | /run-parallel@1.2.0: 969 | resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} 970 | dependencies: 971 | queue-microtask: 1.2.3 972 | dev: true 973 | 974 | /sade@1.8.1: 975 | resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} 976 | engines: {node: '>=6'} 977 | dependencies: 978 | mri: 1.2.0 979 | dev: true 980 | 981 | /sander@0.5.1: 982 | resolution: {integrity: sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==} 983 | dependencies: 984 | es6-promise: 3.3.1 985 | graceful-fs: 4.2.11 986 | mkdirp: 0.5.6 987 | rimraf: 2.7.1 988 | dev: true 989 | 990 | /set-cookie-parser@2.6.0: 991 | resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==} 992 | dev: true 993 | 994 | /sirv@2.0.4: 995 | resolution: {integrity: sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==} 996 | engines: {node: '>= 10'} 997 | dependencies: 998 | '@polka/url': 1.0.0-next.24 999 | mrmime: 2.0.0 1000 | totalist: 3.0.1 1001 | dev: true 1002 | 1003 | /sorcery@0.11.0: 1004 | resolution: {integrity: sha512-J69LQ22xrQB1cIFJhPfgtLuI6BpWRiWu1Y3vSsIwK/eAScqJxd/+CJlUuHQRdX2C9NGFamq+KqNywGgaThwfHw==} 1005 | hasBin: true 1006 | dependencies: 1007 | '@jridgewell/sourcemap-codec': 1.4.15 1008 | buffer-crc32: 0.2.13 1009 | minimist: 1.2.8 1010 | sander: 0.5.1 1011 | dev: true 1012 | 1013 | /source-map-js@1.0.2: 1014 | resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} 1015 | engines: {node: '>=0.10.0'} 1016 | dev: true 1017 | 1018 | /strip-indent@3.0.0: 1019 | resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} 1020 | engines: {node: '>=8'} 1021 | dependencies: 1022 | min-indent: 1.0.1 1023 | dev: true 1024 | 1025 | /svelte-check@3.6.4(svelte@4.2.11): 1026 | resolution: {integrity: sha512-mY/dqucqm46p72M8yZmn81WPZx9mN6uuw8UVfR3ZKQeLxQg5HDGO3HHm5AZuWZPYNMLJ+TRMn+TeN53HfQ/vsw==} 1027 | hasBin: true 1028 | peerDependencies: 1029 | svelte: ^3.55.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0 1030 | dependencies: 1031 | '@jridgewell/trace-mapping': 0.3.22 1032 | chokidar: 3.6.0 1033 | fast-glob: 3.3.2 1034 | import-fresh: 3.3.0 1035 | picocolors: 1.0.0 1036 | sade: 1.8.1 1037 | svelte: 4.2.11 1038 | svelte-preprocess: 5.1.3(svelte@4.2.11)(typescript@5.3.3) 1039 | typescript: 5.3.3 1040 | transitivePeerDependencies: 1041 | - '@babel/core' 1042 | - coffeescript 1043 | - less 1044 | - postcss 1045 | - postcss-load-config 1046 | - pug 1047 | - sass 1048 | - stylus 1049 | - sugarss 1050 | dev: true 1051 | 1052 | /svelte-hmr@0.15.3(svelte@4.2.11): 1053 | resolution: {integrity: sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ==} 1054 | engines: {node: ^12.20 || ^14.13.1 || >= 16} 1055 | peerDependencies: 1056 | svelte: ^3.19.0 || ^4.0.0 1057 | dependencies: 1058 | svelte: 4.2.11 1059 | dev: true 1060 | 1061 | /svelte-preprocess@5.1.3(svelte@4.2.11)(typescript@5.3.3): 1062 | resolution: {integrity: sha512-xxAkmxGHT+J/GourS5mVJeOXZzne1FR5ljeOUAMXUkfEhkLEllRreXpbl3dIYJlcJRfL1LO1uIAPpBpBfiqGPw==} 1063 | engines: {node: '>= 16.0.0', pnpm: ^8.0.0} 1064 | requiresBuild: true 1065 | peerDependencies: 1066 | '@babel/core': ^7.10.2 1067 | coffeescript: ^2.5.1 1068 | less: ^3.11.3 || ^4.0.0 1069 | postcss: ^7 || ^8 1070 | postcss-load-config: ^2.1.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 1071 | pug: ^3.0.0 1072 | sass: ^1.26.8 1073 | stylus: ^0.55.0 1074 | sugarss: ^2.0.0 || ^3.0.0 || ^4.0.0 1075 | svelte: ^3.23.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0 1076 | typescript: '>=3.9.5 || ^4.0.0 || ^5.0.0' 1077 | peerDependenciesMeta: 1078 | '@babel/core': 1079 | optional: true 1080 | coffeescript: 1081 | optional: true 1082 | less: 1083 | optional: true 1084 | postcss: 1085 | optional: true 1086 | postcss-load-config: 1087 | optional: true 1088 | pug: 1089 | optional: true 1090 | sass: 1091 | optional: true 1092 | stylus: 1093 | optional: true 1094 | sugarss: 1095 | optional: true 1096 | typescript: 1097 | optional: true 1098 | dependencies: 1099 | '@types/pug': 2.0.10 1100 | detect-indent: 6.1.0 1101 | magic-string: 0.30.7 1102 | sorcery: 0.11.0 1103 | strip-indent: 3.0.0 1104 | svelte: 4.2.11 1105 | typescript: 5.3.3 1106 | dev: true 1107 | 1108 | /svelte@4.2.11: 1109 | resolution: {integrity: sha512-YIQk3J4X89wOLhjsqIW8tqY3JHPuBdtdOIkASP2PZeAMcSW9RsIjQzMesCrxOF3gdWYC0mKknlKF7OqmLM+Zqg==} 1110 | engines: {node: '>=16'} 1111 | dependencies: 1112 | '@ampproject/remapping': 2.2.1 1113 | '@jridgewell/sourcemap-codec': 1.4.15 1114 | '@jridgewell/trace-mapping': 0.3.22 1115 | '@types/estree': 1.0.5 1116 | acorn: 8.11.3 1117 | aria-query: 5.3.0 1118 | axobject-query: 4.0.0 1119 | code-red: 1.0.4 1120 | css-tree: 2.3.1 1121 | estree-walker: 3.0.3 1122 | is-reference: 3.0.2 1123 | locate-character: 3.0.0 1124 | magic-string: 0.30.7 1125 | periscopic: 3.1.0 1126 | dev: true 1127 | 1128 | /tiny-glob@0.2.9: 1129 | resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==} 1130 | dependencies: 1131 | globalyzer: 0.1.0 1132 | globrex: 0.1.2 1133 | dev: true 1134 | 1135 | /to-regex-range@5.0.1: 1136 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 1137 | engines: {node: '>=8.0'} 1138 | dependencies: 1139 | is-number: 7.0.0 1140 | dev: true 1141 | 1142 | /totalist@3.0.1: 1143 | resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} 1144 | engines: {node: '>=6'} 1145 | dev: true 1146 | 1147 | /tslib@2.6.2: 1148 | resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} 1149 | dev: true 1150 | 1151 | /typescript@5.3.3: 1152 | resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} 1153 | engines: {node: '>=14.17'} 1154 | hasBin: true 1155 | dev: true 1156 | 1157 | /vite@5.1.3: 1158 | resolution: {integrity: sha512-UfmUD36DKkqhi/F75RrxvPpry+9+tTkrXfMNZD+SboZqBCMsxKtO52XeGzzuh7ioz+Eo/SYDBbdb0Z7vgcDJew==} 1159 | engines: {node: ^18.0.0 || >=20.0.0} 1160 | hasBin: true 1161 | peerDependencies: 1162 | '@types/node': ^18.0.0 || >=20.0.0 1163 | less: '*' 1164 | lightningcss: ^1.21.0 1165 | sass: '*' 1166 | stylus: '*' 1167 | sugarss: '*' 1168 | terser: ^5.4.0 1169 | peerDependenciesMeta: 1170 | '@types/node': 1171 | optional: true 1172 | less: 1173 | optional: true 1174 | lightningcss: 1175 | optional: true 1176 | sass: 1177 | optional: true 1178 | stylus: 1179 | optional: true 1180 | sugarss: 1181 | optional: true 1182 | terser: 1183 | optional: true 1184 | dependencies: 1185 | esbuild: 0.19.12 1186 | postcss: 8.4.35 1187 | rollup: 4.12.0 1188 | optionalDependencies: 1189 | fsevents: 2.3.3 1190 | dev: true 1191 | 1192 | /vitefu@0.2.5(vite@5.1.3): 1193 | resolution: {integrity: sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==} 1194 | peerDependencies: 1195 | vite: ^3.0.0 || ^4.0.0 || ^5.0.0 1196 | peerDependenciesMeta: 1197 | vite: 1198 | optional: true 1199 | dependencies: 1200 | vite: 5.1.3 1201 | dev: true 1202 | 1203 | /wrappy@1.0.2: 1204 | resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} 1205 | dev: true 1206 | --------------------------------------------------------------------------------