{"_id":"@chronicstone/vue-route-query","_rev":"4-07bad200ec3eec843375acf7163308f9","name":"@chronicstone/vue-route-query","dist-tags":{"latest":"1.0.3"},"versions":{"1.0.0":{"name":"@chronicstone/vue-route-query","version":"1.0.0","keywords":["vue","vue3","vue-router","query","url","zod","typescript","validation"],"author":{"name":"Your Name"},"license":"MIT","_id":"@chronicstone/vue-route-query@1.0.0","maintainers":[{"name":"chronicstone","email":"cyprienthao@gmail.com"}],"homepage":"https://github.com/chronicstone/vue-route-query#readme","bugs":{"url":"https://github.com/yourusername/vue-route-query/issues"},"dist":{"shasum":"61cee0401ac63395b900679ba9523a324f9264a1","tarball":"https://registry.npmjs.org/@chronicstone/vue-route-query/-/vue-route-query-1.0.0.tgz","fileCount":7,"integrity":"sha512-yDPBjmhI4kmWdF71JZTy+9F8e5EqKPtzeP7oQVcDj7DsDNGqecqX+qst2GoUrHAivyJj70bnaZZLkISTWoyWhQ==","signatures":[{"sig":"MEYCIQC/c3LuwbczYVIzjRAErPa0jNVVb34X5QTZC21Kkmxs1QIhAIStv6F94VAp5xxdD7jjURdhzabMaNIfO8YBrE/LCVqd","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":39074},"main":"./dist/index.mjs","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.cjs"}},"gitHead":"b6ca5d3a1ac7117ab589d33fd0bca11e334e54ab","scripts":{"dev":"unbuild --stub","lint":"biome lint .","test":"vitest","build":"unbuild","start":"esno src/index.ts","release":"npm run lint && npm run typecheck && npm run build && bumpp && npm publish","lint:fix":"biome lint --write .","typecheck":"tsc --noEmit"},"_npmUser":{"name":"chronicstone","email":"cyprienthao@gmail.com"},"repository":{"url":"git+https://github.com/yourusername/vue-route-query.git","type":"git"},"_npmVersion":"10.2.3","description":"Type-safe URL query parameter synchronization for Vue 3 with Zod validation","directories":{},"_nodeVersion":"20.10.0","typesVersions":{"*":{"*":["./dist/*","./dist/index.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"vue":"3.5.13","zod":"3.24.3","bumpp":"^10.1.0","vitest":"^0.34.0","unbuild":"^3.5.0","typescript":"5.8.3","vue-router":"4.5.0","@biomejs/biome":"^1.9.4"},"peerDependencies":{"vue":"^3.0.0","zod":"^3.0.0","vue-router":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/vue-route-query_1.0.0_1745487951447_0.456813908066515","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@chronicstone/vue-route-query","version":"1.0.1","keywords":["vue","vue3","vue-router","query","url","zod","typescript","validation"],"author":{"name":"Your Name"},"license":"MIT","_id":"@chronicstone/vue-route-query@1.0.1","maintainers":[{"name":"chronicstone","email":"cyprienthao@gmail.com"}],"homepage":"https://github.com/chronicstone/vue-route-query#readme","bugs":{"url":"https://github.com/yourusername/vue-route-query/issues"},"dist":{"shasum":"c409852adb6355bb57ac90d70493703cc151d169","tarball":"https://registry.npmjs.org/@chronicstone/vue-route-query/-/vue-route-query-1.0.1.tgz","fileCount":7,"integrity":"sha512-GOsLJECFWxA5T7KnEYxnMXwecjYzj0pFS+Knfy+Z6gUEsm9hMFJPUKB7SrZ6evTs/TuDevQzufcPju9Jx5gi8g==","signatures":[{"sig":"MEQCIDfGIjUJKnjz8Jl+/KDdXNwmI8/7Z5v5CXitufA5EWLDAiAsz4rmKu8q/Vrrkhs/lq4fJLOIFvEZ5+9ysMkYxmwHCg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":38957},"main":"./dist/index.mjs","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.cjs"}},"gitHead":"ac5151e7b79a9cada2bddd3d4c68bdcf8ebd1df9","scripts":{"dev":"unbuild --stub","lint":"biome lint .","test":"vitest","build":"unbuild","start":"esno src/index.ts","release":"npm run lint && npm run typecheck && npm run build && bumpp && npm publish","lint:fix":"biome lint --write .","typecheck":"tsc --noEmit"},"_npmUser":{"name":"chronicstone","email":"cyprienthao@gmail.com"},"repository":{"url":"git+https://github.com/yourusername/vue-route-query.git","type":"git"},"_npmVersion":"10.2.3","description":"Type-safe URL query parameter synchronization for Vue 3 with Zod validation","directories":{},"_nodeVersion":"20.10.0","typesVersions":{"*":{"*":["./dist/*","./dist/index.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"vue":"3.5.13","zod":"3.24.3","bumpp":"^10.1.0","vitest":"^0.34.0","unbuild":"^3.5.0","typescript":"5.8.3","vue-router":"4.5.0","@biomejs/biome":"^1.9.4"},"peerDependencies":{"vue":"^3.0.0","zod":"^3.0.0","vue-router":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/vue-route-query_1.0.1_1745488378885_0.4663718172223199","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@chronicstone/vue-route-query","version":"1.0.2","keywords":["vue","vue3","vue-router","query","url","zod","typescript","validation"],"author":{"name":"Your Name"},"license":"MIT","_id":"@chronicstone/vue-route-query@1.0.2","maintainers":[{"name":"chronicstone","email":"cyprienthao@gmail.com"}],"homepage":"https://github.com/chronicstone/vue-route-query#readme","bugs":{"url":"https://github.com/yourusername/vue-route-query/issues"},"dist":{"shasum":"f6cfebfe17c0a9b344a90f3f1653f8777612d7fe","tarball":"https://registry.npmjs.org/@chronicstone/vue-route-query/-/vue-route-query-1.0.2.tgz","fileCount":7,"integrity":"sha512-W/18+Oa97JttxIJHSDZ9RGPI7AgfmK6I9ZGrBUSjLxNt49EJEIgqKY4bPjIST9J0z/vvfAsOfEAPWUaoebyd1Q==","signatures":[{"sig":"MEQCICgmffJ/cN+OSCAmnihmcHb269FPAJRjhoT31bq0pUv5AiB3s/JApShsIazCNrlJblT8qwYjM1QejDAw3dyKgdn6cA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":51911},"main":"./dist/index.mjs","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.cjs"}},"gitHead":"8872af43e879de2c3e2f9cedca2174b834437c50","scripts":{"dev":"unbuild --stub","lint":"biome lint .","test":"vitest","build":"unbuild","start":"esno src/index.ts","release":"npm run lint && npm run typecheck && npm run build && bumpp && npm publish","lint:fix":"biome lint --write .","typecheck":"tsc --noEmit"},"_npmUser":{"name":"chronicstone","email":"cyprienthao@gmail.com"},"repository":{"url":"git+https://github.com/yourusername/vue-route-query.git","type":"git"},"_npmVersion":"10.2.3","description":"Type-safe URL query parameter synchronization for Vue 3 with Zod validation","directories":{},"_nodeVersion":"20.10.0","typesVersions":{"*":{"*":["./dist/*","./dist/index.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"vue":"3.5.13","zod":"3.24.3","bumpp":"^10.1.0","vitest":"^0.34.0","unbuild":"^3.5.0","typescript":"5.8.3","vue-router":"4.5.0","@biomejs/biome":"^1.9.4"},"peerDependencies":{"vue":"^3.0.0","zod":"^3.0.0","vue-router":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/vue-route-query_1.0.2_1745585743921_0.8366615811989575","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@chronicstone/vue-route-query","version":"1.0.3","description":"Type-safe URL query parameter synchronization for Vue 3 with Zod validation","keywords":["vue","vue3","vue-router","query","url","zod","typescript","validation"],"repository":{"type":"git","url":"git+https://github.com/yourusername/vue-route-query.git"},"license":"MIT","author":{"name":"Your Name"},"bugs":{"url":"https://github.com/yourusername/vue-route-query/issues"},"homepage":"https://github.com/chronicstone/vue-route-query#readme","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.cjs"}},"main":"./dist/index.mjs","module":"./dist/index.mjs","types":"./dist/index.d.ts","typesVersions":{"*":{"*":["./dist/*","./dist/index.d.ts"]}},"scripts":{"build":"unbuild","dev":"unbuild --stub","start":"esno src/index.ts","test":"vitest","typecheck":"tsc --noEmit","lint":"biome lint .","lint:fix":"biome lint --write .","release":"npm run lint && npm run typecheck && npm run build && bumpp && npm publish"},"peerDependencies":{"vue":"^3.0.0","vue-router":"^4.0.0","zod":"^3.0.0"},"devDependencies":{"@biomejs/biome":"^1.9.4","bumpp":"^10.1.0","typescript":"5.8.3","unbuild":"^3.5.0","vitest":"^0.34.0","vue":"3.5.13","vue-router":"4.5.0","zod":"3.24.3"},"_id":"@chronicstone/vue-route-query@1.0.3","gitHead":"6216bfc043a8c63a64bf209b80f181378a20589c","_nodeVersion":"20.10.0","_npmVersion":"10.2.3","dist":{"integrity":"sha512-oWiwyffRu0I3sePESs8DBtoA7+iTTFD3seKk72GMJBL3UIWSrbYWtTmPh1oSoZFmZqwdVKsGoYBKaqlzP+CtEA==","shasum":"0cdd1ca05d9fa9d1a8c9098f1f7ff916dfa1c523","tarball":"https://registry.npmjs.org/@chronicstone/vue-route-query/-/vue-route-query-1.0.3.tgz","fileCount":7,"unpackedSize":53720,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDDkuh8vAABuNO/qXeOu1ybrmQ26mQuen1yKnEhxymhlQIhANOwKan9QrKZSFRVLks1O1arjSMTe5hub25L6jHWkeMu"}]},"_npmUser":{"name":"chronicstone","email":"cyprienthao@gmail.com"},"directories":{},"maintainers":[{"name":"chronicstone","email":"cyprienthao@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/vue-route-query_1.0.3_1745951828987_0.18743653063725385"},"_hasShrinkwrap":false}},"time":{"created":"2025-04-24T09:45:51.338Z","modified":"2025-04-29T18:37:09.466Z","1.0.0":"2025-04-24T09:45:51.647Z","1.0.1":"2025-04-24T09:52:59.092Z","1.0.2":"2025-04-25T12:55:44.098Z","1.0.3":"2025-04-29T18:37:09.279Z"},"bugs":{"url":"https://github.com/yourusername/vue-route-query/issues"},"author":{"name":"Your Name"},"license":"MIT","homepage":"https://github.com/chronicstone/vue-route-query#readme","keywords":["vue","vue3","vue-router","query","url","zod","typescript","validation"],"repository":{"type":"git","url":"git+https://github.com/yourusername/vue-route-query.git"},"description":"Type-safe URL query parameter synchronization for Vue 3 with Zod validation","maintainers":[{"name":"chronicstone","email":"cyprienthao@gmail.com"}],"readme":"# @chronicstone/vue-route-query\n\n[![npm version](https://img.shields.io/npm/v/@chronicstone/vue-route-query.svg)](https://www.npmjs.com/package/@chronicstone/vue-route-query)\n[![npm downloads](https://img.shields.io/npm/dm/@chronicstone/vue-route-query.svg)](https://www.npmjs.com/package/@chronicstone/vue-route-query)\n[![bundle size](https://img.shields.io/bundlephobia/minzip/@chronicstone/vue-route-query)](https://bundlephobia.com/package/@chronicstone/vue-route-query)\n[![license](https://img.shields.io/npm/l/@chronicstone/vue-route-query.svg)](https://github.com/chronicstone/vue-route-query/blob/main/LICENSE)\n[![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)\n\nA powerful Vue 3 composable for type-safe URL query parameter synchronization with Zod validation, automatic state management, and intelligent default handling.\n\n## Features\n\n- 🔒 **Type-safe**: Full TypeScript support with Zod schema validation\n- 🔄 **Bidirectional sync**: Automatic synchronization between component state and URL\n- 🎯 **Deep object support**: Handles nested objects and arrays with proper serialization\n- ⚡ **Performance optimized**: Batched updates with async processing\n- 🧹 **Smart cleanup**: Automatically removes default values from URL\n- 🔌 **Vue Router integration**: Seamless integration with Vue Router\n- 🎨 **Flexible API**: Support for single values or complex objects\n- 🔗 **Nested path support**: Deep object structures automatically transformed to dot notation\n- 🔄 **Instance sync**: Multiple instances with the same key stay synchronized\n- 📜 **History control**: Choose between push and replace modes for router navigation\n\n## Table of Contents\n\n- [@chronicstone/vue-route-query](#chronicstonevue-route-query)\n  - [Features](#features)\n  - [Table of Contents](#table-of-contents)\n  - [Installation](#installation)\n  - [Basic Usage](#basic-usage)\n    - [Single Value](#single-value)\n    - [Object Schema](#object-schema)\n    - [Object Schema with Root Key](#object-schema-with-root-key)\n    - [Nullable Schema](#nullable-schema)\n  - [API Reference](#api-reference)\n    - [`useRouteQuery<Schema, Nullable, Output>(config)`](#useroutequeryschema-nullable-outputconfig)\n      - [Parameters](#parameters)\n      - [Returns](#returns)\n      - [Important Behavior Notes](#important-behavior-notes)\n  - [Advanced Usage](#advanced-usage)\n    - [Navigation Mode Control](#navigation-mode-control)\n    - [Object Schema with Root Key Prefix](#object-schema-with-root-key-prefix)\n    - [Complex Filtering System](#complex-filtering-system)\n    - [Sortable Table with Nullable State](#sortable-table-with-nullable-state)\n    - [Dynamic Schema with Persistence Control](#dynamic-schema-with-persistence-control)\n    - [Pagination with Type Safety](#pagination-with-type-safety)\n  - [Under the Hood](#under-the-hood)\n    - [State Management Lifecycle](#state-management-lifecycle)\n    - [URL Transformation Rules](#url-transformation-rules)\n    - [Global Query Manager](#global-query-manager)\n  - [Performance Considerations](#performance-considerations)\n  - [Browser Support](#browser-support)\n  - [TypeScript Support](#typescript-support)\n  - [Common Patterns](#common-patterns)\n    - [Resetting to Defaults](#resetting-to-defaults)\n    - [Conditional Parameters](#conditional-parameters)\n    - [Synchronized Instances](#synchronized-instances)\n  - [Troubleshooting](#troubleshooting)\n    - [Common Issues](#common-issues)\n    - [Debug Mode](#debug-mode)\n  - [License](#license)\n  - [Contributing](#contributing)\n\n## Installation\n\n```bash\n# npm\nnpm install @chronicstone/vue-route-query zod vue-router\n\n# yarn\nyarn add @chronicstone/vue-route-query zod vue-router\n\n# pnpm\npnpm add @chronicstone/vue-route-query zod vue-router\n\n# bun\nbun add @chronicstone/vue-route-query zod vue-router\n```\n\n## Basic Usage\n\n### Single Value\n\n```typescript\nimport { useRouteQuery } from '@chronicstone/vue-route-query'\nimport { z } from 'zod'\n\n// Single value with key\nconst activeLayout = useRouteQuery({\n  key: 'layout',\n  schema: z.enum(['table', 'grid']),\n  default: 'table'  // Won't appear in URL when value is 'table'\n})\n\n// Type: Ref<'table' | 'grid'>\n```\n\n### Object Schema\n\n```typescript\nconst filters = useRouteQuery({\n  schema: {\n    search: z.string(),\n    status: z.array(z.string()),\n    date: z.object({\n      from: z.string(),\n      to: z.string()\n    })\n  },\n  default: {\n    search: '',\n    status: [],\n    date: { from: '', to: '' }\n  }\n})\n\n// Type: Ref<{ search: string; status: string[]; date: { from: string; to: string } }>\n```\n\n### Object Schema with Root Key\n\n```typescript\nconst userSettings = useRouteQuery({\n  key: 'settings',  // Optional for object schemas - adds root prefix to all properties\n  schema: {\n    theme: z.string(),\n    notifications: z.boolean()\n  },\n  default: {\n    theme: 'light',\n    notifications: true\n  }\n})\n\n// URL: ?settings.theme=dark&settings.notifications=false\n// Without key: ?theme=dark&notifications=false\n```\n\n### Nullable Schema\n\n```typescript\nconst sort = useRouteQuery({\n  schema: {\n    key: z.string(),\n    dir: z.enum(['asc', 'desc'])\n  },\n  default: { key: 'id', dir: 'asc' },\n  nullable: true  // Allows the entire object to be null\n})\n\n// Type: Ref<{ key: string; dir: 'asc' | 'desc' } | null>\n```\n\n## API Reference\n\n### `useRouteQuery<Schema, Nullable, Output>(config)`\n\nThe main composable for managing URL query parameters.\n\n#### Parameters\n\n| Parameter  | Type                                     | Required                   | Description                                                             |\n| ---------- | ---------------------------------------- | -------------------------- | ----------------------------------------------------------------------- |\n| `schema`   | `z.ZodType \\| Record<string, z.ZodType>` | Yes                        | Zod schema for validation                                               |\n| `default`  | `NonNullable<Output>`                    | Yes                        | Default value (won't appear in URL when active)                         |\n| `key`      | `string`                                 | Required for single values | Root key for single value schemas or optional prefix for object schemas |\n| `nullable` | `boolean`                                | No                         | Whether the entire value can be null                                    |\n| `enabled`  | `boolean`                                | No                         | Enable/disable URL synchronization                                      |\n| `debug`    | `boolean`                                | No                         | Enable debug logging                                                    |\n| `mode`     | `'push' \\| 'replace'`                    | No                         | Navigation mode (default: 'replace')                                    |\n\n#### Returns\n\n`Ref<Output>` - A reactive reference to the synchronized state\n\n#### Important Behavior Notes\n\n1. **Default Values**: Default values are never shown in the URL. A parameter only appears in the URL when its value differs from the default.\n\n2. **Root Keys for Object Schemas**: When using a `key` with object schemas, it acts as a prefix for all properties:\n\n   ```typescript\n   // With key\n   useRouteQuery({ key: 'user', schema: { name: z.string() }, default: { name: '' } })\n   // URL: ?user.name=John\n   \n   // Without key\n   useRouteQuery({ schema: { name: z.string() }, default: { name: '' } })\n   // URL: ?name=John\n   ```\n\n3. **Nested Objects**: Deep object structures are automatically flattened using dot notation:\n\n   ```typescript\n   // State\n   { filters: { date: { from: '2024-01-01' } } }\n   \n   // URL\n   ?filters.date.from=2024-01-01\n   ```\n\n4. **Arrays**: Arrays are JSON stringified in the URL:\n\n   ```typescript\n   // State\n   { tags: ['vue', 'typescript'] }\n   \n   // URL\n   ?tags=[\"vue\",\"typescript\"]\n   ```\n\n5. **Multiple Instances**: Multiple `useRouteQuery` instances with the same key will stay synchronized. However, ensure they use compatible schemas to avoid conflicts.\n\n6. **Schema Validation**: Don't use Zod's `.default()` function - use the `default` parameter instead.\n\n7. **Navigation Mode**: The `mode` parameter controls how router navigation occurs:\n   - `'replace'` (default): Updates the URL without creating a new history entry\n   - `'push'`: Creates a new history entry for each update\n\n   When multiple instances update simultaneously, if any instance uses `'push'`, the router will use push mode for that batch of updates.\n\n## Advanced Usage\n\n### Navigation Mode Control\n\n```typescript\n// Using push mode for filters to enable browser back/forward navigation\nconst filters = useRouteQuery({\n  schema: {\n    category: z.string(),\n    priceRange: z.object({\n      min: z.number(),\n      max: z.number()\n    })\n  },\n  default: {\n    category: '',\n    priceRange: { min: 0, max: 1000 }\n  },\n  mode: 'push'  // Each filter change creates a history entry\n})\n\n// Using replace mode for preferences (default)\nconst preferences = useRouteQuery({\n  schema: {\n    view: z.enum(['list', 'grid']),\n    density: z.enum(['compact', 'comfortable'])\n  },\n  default: {\n    view: 'list',\n    density: 'comfortable'\n  }\n  // mode: 'replace' is the default\n})\n\n// If both update simultaneously and filters uses 'push',\n// the router will use push for that update\n```\n\n### Object Schema with Root Key Prefix\n\n```typescript\nconst accountSettings = useRouteQuery({\n  key: 'account',  // All properties will be prefixed with 'account.'\n  schema: {\n    profile: z.object({\n      name: z.string(),\n      email: z.string()\n    }),\n    preferences: z.object({\n      theme: z.enum(['light', 'dark']),\n      notifications: z.boolean()\n    })\n  },\n  default: {\n    profile: { name: '', email: '' },\n    preferences: { theme: 'light', notifications: true }\n  }\n})\n\n// URL structure:\n// ?account.profile.name=John&account.profile.email=john@example.com&account.preferences.theme=dark\n// Without the key, it would be:\n// ?profile.name=John&profile.email=john@example.com&preferences.theme=dark\n```\n\n### Complex Filtering System\n\n```typescript\nconst filters = useRouteQuery({\n  schema: {\n    searchQuery: z.string().optional(),\n    filters: z.object({\n      statuses: z.array(z.string()),\n      categories: z.array(z.string()),\n      authorizationLabels: z.boolean(),\n      startDate: z.object({\n        from: z.string(),\n        to: z.string()\n      })\n    }),\n    quickFilters: z.record(z.string(), z.any())\n  },\n  default: {\n    searchQuery: '',\n    filters: {\n      statuses: [],\n      categories: [],\n      authorizationLabels: false,\n      startDate: { from: '', to: '' }\n    },\n    quickFilters: {}\n  }\n})\n\n// URL when changed from default:\n// ?searchQuery=test&filters.statuses=[\"TO_CHECK_EP\",\"VALIDATED\"]&filters.categories=[\"19KZisAzakz3WESKnUy_C\"]&filters.authorizationLabels=true&filters.startDate.from=2025-04-23&filters.startDate.to=2025-04-24\n```\n\n### Sortable Table with Nullable State\n\n```typescript\nconst sort = useRouteQuery({\n  schema: {\n    key: z.string(),\n    dir: z.enum(['asc', 'desc'])\n  },\n  default: { key: 'createdAt', dir: 'desc' },\n  nullable: true\n})\n\n// Can be set to null to disable sorting\nsort.value = null\n\n// URL when null: parameters removed\n// URL when default: parameters removed\n// URL when custom: ?key=name&dir=asc\n```\n\n### Dynamic Schema with Persistence Control\n\n```typescript\nconst userPreferences = useRouteQuery({\n  schema: {\n    theme: z.enum(['light', 'dark', 'system']),\n    density: z.enum(['compact', 'comfortable', 'spacious']),\n    notifications: z.object({\n      email: z.boolean(),\n      push: z.boolean(),\n      frequency: z.enum(['instant', 'daily', 'weekly'])\n    })\n  },\n  default: {\n    theme: 'system',\n    density: 'comfortable',\n    notifications: {\n      email: true,\n      push: false,\n      frequency: 'daily'\n    }\n  },\n  enabled: shouldPersistPreferences.value // Conditionally enable URL sync\n})\n```\n\n### Pagination with Type Safety\n\n```typescript\nconst pagination = useRouteQuery({\n  schema: {\n    pageSize: z.number(),\n    pageIndex: z.number()\n  },\n  default: {\n    pageSize: 20,\n    pageIndex: 1\n  },\n  mode: 'push'  // Enable history for pagination\n})\n\n// Only appears in URL when different from default\n// ?pageSize=50&pageIndex=3\n```\n\n## Under the Hood\n\n### State Management Lifecycle\n\n1. **Initialization**: The composable initializes with either URL values (if present) or default values\n2. **Synchronization**: Changes to the ref automatically update the URL, and URL changes update the ref\n3. **Cleanup**: When values match defaults, they're removed from the URL\n4. **Batching**: Multiple rapid updates are batched and processed in the next tick\n\n### URL Transformation Rules\n\n1. **Objects**: Nested objects use dot notation\n\n   ```typescript\n   { user: { settings: { theme: 'dark' } } }\n   // Becomes: ?user.settings.theme=dark\n   ```\n\n2. **Arrays**: Arrays are JSON stringified\n\n   ```typescript\n   { tags: ['vue', 'ts'] }\n   // Becomes: ?tags=[\"vue\",\"ts\"]\n   ```\n\n3. **Booleans**: Represented as string values\n\n   ```typescript\n   { active: true }\n   // Becomes: ?active=true\n   ```\n\n4. **Numbers**: Preserved as numeric strings\n\n   ```typescript\n   { count: 42 }\n   // Becomes: ?count=42\n   ```\n\n5. **Null/Undefined**: Removed from URL entirely\n\n### Global Query Manager\n\nThe library uses a singleton `GlobalQueryManager` that:\n\n- Batches multiple updates to prevent race conditions\n- Processes all updates in the next tick\n- Ensures consistent state across all instances\n- Handles cleanup of removed properties\n- Intelligently combines navigation modes (push if any instance requests push)\n\n## Performance Considerations\n\n1. **Batching**: All updates are batched to minimize router operations\n2. **Shallow Comparison**: Uses shallow comparison for primitives\n3. **Deep Comparison**: Uses recursive comparison for objects only when needed\n4. **URL Size**: Be mindful of browser URL length limits with large data structures\n\n## Browser Support\n\nWorks in all modern browsers that support:\n\n- Vue 3\n- URLSearchParams API\n- ES2015+\n\n## TypeScript Support\n\nThe library is written in TypeScript and provides full type inference:\n\n```typescript\n// Inferred type based on schema\nconst data = useRouteQuery({\n  schema: {\n    name: z.string(),\n    age: z.number().optional()\n  },\n  default: { name: '', age: undefined }\n})\n\n// data is Ref<{ name: string; age?: number }>\n```\n\n## Common Patterns\n\n### Resetting to Defaults\n\n```typescript\nconst filters = useRouteQuery({...})\n\n// Reset to default (removes from URL)\nfilters.value = { ...defaultFilters }\n```\n\n### Conditional Parameters\n\n```typescript\nconst config = useRouteQuery({\n  schema: {\n    advanced: z.boolean(),\n    // Only used when advanced is true\n    customSettings: z.object({...}).optional()\n  },\n  default: {\n    advanced: false,\n    customSettings: undefined\n  }\n})\n```\n\n### Synchronized Instances\n\n```typescript\n// Both instances stay in sync\nconst userSettings1 = useRouteQuery({\n  key: 'settings',\n  schema: z.object({...}),\n  default: {...}\n})\n\nconst userSettings2 = useRouteQuery({\n  key: 'settings',  // Same key\n  schema: z.object({...}),  // Must be compatible\n  default: {...}\n})\n```\n\n## Troubleshooting\n\n### Common Issues\n\n1. **Schema Mismatch**: Ensure multiple instances with the same key use compatible schemas\n2. **Default Values**: Remember that default values never appear in the URL\n3. **Type Errors**: Use proper TypeScript types when working with refs\n4. **Performance**: For large data structures, consider pagination or filtering\n5. **Navigation Conflicts**: When using mixed modes, push takes precedence over replace\n\n### Debug Mode\n\nEnable debug mode to see internal operations:\n\n```typescript\nconst data = useRouteQuery({\n  // ... other options\n  debug: true\n})\n```\n\n## License\n\nMIT\n\n## Contributing\n\nContributions are welcome! Please read our [contributing guidelines](CONTRIBUTING.md) before submitting a PR.\n","readmeFilename":"README.md"}