├── .gitignore ├── .vscode └── extensions.json ├── README.md ├── cover.jpg ├── package.json ├── partykit.json ├── playground ├── index.html ├── public │ ├── pk.png │ └── vite.svg └── src │ ├── App.vue │ ├── assets │ └── vue.svg │ ├── components │ ├── CheckboxExample.vue │ └── CountExample.vue │ ├── main.ts │ ├── style.css │ └── vite-env.d.ts ├── pnpm-lock.yaml ├── server └── src │ └── main.ts ├── src ├── index.ts └── usePartyRef.ts ├── tsconfig.json └── vite.config.ts /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | .partykit/* 26 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["Vue.volar"] 3 | } 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # usePartyRef 2 | 3 | ![usePartyRef](https://github.com/marchantweb/usePartyRef/raw/main/cover.jpg) 4 | 5 | `usePartyRef()` is a Vue 3 composable that extends the functionality of the standard `ref()` to enable real-time, 6 | synchronized state across multiple clients globally. 7 | 8 | It transforms local reactive state into a shared state across all connected clients, allowing you to 9 | build multiplayer interactive experiences using the Vue lifecycle hooks you're familiar with. The composable returns a `Ref`, so you 10 | can `watch` it, bind it to inputs, run a `computed` on it, etc. 11 | 12 | Under the hood, it's using [PartyKit](https://www.partykit.io/) stateful servers and websockets, based 13 | on [CloudFlare Durable Objects](https://developers.cloudflare.com/durable-objects/), to keep values in sync and persist them beyond the life of the browser window. The library is written in TypeScript and is fully type-safe. 14 | 15 | ## 📦 Installation 16 | 17 | Install `usePartyRef` via npm by running: 18 | 19 | ```bash 20 | npm install usepartyref 21 | ``` 22 | 23 | --- 24 | 25 | ## 🚀 Usage 26 | 27 | Below is a comparison of using Vue's native `ref()` versus `usePartyRef()` to illustrate how you can seamlessly use 28 | globally shared state as easily as using a normal ref: 29 | 30 | ```ts 31 | // Use Vue's native ref() for local state 32 | const count: Ref = ref(0) 33 | 34 | // Use usePartyRef() for shared state 35 | const sharedCount: Ref = usePartyRef({ 36 | namespace: 'my-project', // Choose something unique 37 | key: "count", 38 | defaultValue: 0 39 | }) 40 | 41 | // Computed, watch, and other reactive utilities work just like a normal ref 42 | const doubled = computed(() => sharedCount.value * 2) 43 | ``` 44 | 45 | With `usePartyRef()`, the count state is synchronized in real time across all clients that subscribe to it. That might 46 | be two browser tabs on your local machine, or thousands of users all over the world. 47 | 48 | ### Ready State 49 | 50 | A special note here is that the ref returned by `usePartyRef` is actually a `PartyRef` type. This type extends `Ref` adding a `ready` property that is a `Ref`. This property is `true` when the connection is established and the value is ready to be used, and `false` when the connection closes. 51 | 52 | You can watch this property to know when the value is ready to be used: 53 | 54 | ```ts 55 | // If you need to know when the connection is established 56 | const isReady: ComputedRef = computed(() => sharedCount.ready.value) 57 | ```` 58 | 59 | Note that trying to access this property in a template will fail, as Vue automatically unwraps the value - so instead use a computed variable such as `isReady` above. 60 | 61 | --- 62 | 63 | ## 🎈 Managed vs. Self-Hosting 64 | 65 | `usePartyRef` is built on top of [PartyKit](https://www.partykit.io/), a managed service that handles the real-time 66 | synchronization of state across clients. This means you don't need to worry about setting up your own server or managing 67 | the infrastructure. 68 | 69 | By default, `usePartyRef` uses the PartyKit server hosted on the package author's account that requires no setup on your part. This is great for getting started quickly and for small projects, but it's not recommended for production use. Under heavy traffic it may be rate limited, and there's a greater chance of namespace conflicts with other users. 70 | 71 | ### Self-host on your own PartyKit account: 72 | 73 | 1. Fork this repo 74 | 2. Run `server:deploy` and follow the prompts to authenticate with your own GitHub account to PartyKit 75 | 3. Configuring the `usePartyRef` composable to point at your own account by setting the `host` option: 76 | 77 | ```ts 78 | const count: Ref = usePartyRef({ 79 | namespace: 'my-project', 80 | key: "count", 81 | defaultValue: 0, 82 | host: '[projectname].[username].partykit.dev' // server:deploy will give you this URL 83 | }) 84 | ``` 85 | Forking it and hosting on your own account also has the benefit of providing a level of privacy and control over your data. You can modify the PartySocket connection and the server to use your own authentication approaches along with any business logic you need - although at that point you may want to consider using PartyKit directly. 86 | 87 | You can also go as far as actually **self-hosting on CloudFlare**. For that, see 88 | the [PartyKit documentation](https://docs.partykit.io/guides/deploy-to-cloudflare/). 89 | 90 | --- 91 | 92 | ## What about Y-PartyKit / Yjs? 93 | 94 | [Y-PartyKit](https://docs.partykit.io/reference/y-partykit-api/) is a similar project that uses [Yjs](https://yjs.dev/) for real-time collaboration around shared data types. Both `usePartyRef` and `Y-PartyKit` are built on top of PartyKit, but they have different use cases and levels of involvement/complexity. 95 | 96 | `usePartyRef` is designed to be a drop-in replacement for Vue's `ref()` that allows you to share reactive state across clients. It's a simple, high-level API that removes the need for you to worry about the underlying data structures and synchronization logic. It just works out of the box with no setup required. 97 | 98 | `Y-PartyKit` is a more complex, lower-level API that allows you to share any data type across clients. It's built on top of Yjs, which is a CRDT library that allows for more complex data structures like maps, arrays, and text. It's great for more complex data structures and collaborative editing. 99 | 100 | If you're looking for a simple way to share reactive state across clients, `usePartyRef` is the way to go. If you need more complex data structures or collaborative editing, `Y-PartyKit` might be a better fit. 101 | 102 | --- 103 | 104 | ## 📚 Contributions 105 | 106 | Contributions are welcome! Feel free to open an issue or submit a pull request if you have any ideas or improvements. 107 | 108 | --- 109 | 110 | ## 🔗 Links 111 | 112 | - [PartyKit](https://partykit.io/) 113 | - [Follow on Twitter](https://twitter.com/marchantweb) 114 | - [Chat on Discord](https://discordapp.com/users/1165287468568944640) 115 | 116 | --- 117 | 118 | ## 📄 License 119 | 120 | Copyright (c) 2024 Simon Le Marchant _(Marchant Web, LLC.)_ 121 | 122 | `usePartyRef` is licensed under the [MIT License](https://github.com/vuexyz/vuexyz/blob/main/LICENSE). Licensed works, 123 | modifications, and larger works may be distributed under different terms and without source code. 124 | -------------------------------------------------------------------------------- /cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marchantweb/usePartyRef/f385def6a003be7388a121beb6360f5d5b8fccb1/cover.jpg -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "usepartyref", 3 | "version": "1.0.53", 4 | "license": "MIT", 5 | "author": "Simon Le Marchant", 6 | "homepage": "https://usepartyref.pages.dev/", 7 | "repository": "https://github.com/marchantweb/usePartyRef", 8 | "sideEffects": false, 9 | "type": "module", 10 | "files": [ 11 | "dist" 12 | ], 13 | "main": "./dist/index.js", 14 | "module": "./dist/index.js", 15 | "types": "./dist/index.d.ts", 16 | "exports": { 17 | ".": { 18 | "import": "./dist/index.js", 19 | "types": "./dist/index.d.ts" 20 | } 21 | }, 22 | "scripts": { 23 | "dev": "concurrently npm:server:dev npm:dev:playground", 24 | "dev:playground": "vite --host --open", 25 | "build": "vite build", 26 | "preview": "vite preview", 27 | "build:lib": "vite build --mode library", 28 | "publish:lib": "npm run build:lib && npm publish --access public", 29 | "server:dev": "partykit dev --live", 30 | "server:deploy": "partykit deploy" 31 | }, 32 | "dependencies": { 33 | "partykit": "^0.0.107", 34 | "partysocket": "^1.0.1", 35 | "rate-limiter-flexible": "^5.0.3", 36 | "vue": "^3.4.29" 37 | }, 38 | "devDependencies": { 39 | "@types/node": "^20.14.9", 40 | "@vitejs/plugin-vue": "^5.0.5", 41 | "concurrently": "^8.2.2", 42 | "typescript": "^5.2.2", 43 | "vite": "^5.3.1", 44 | "vite-plugin-dts": "^3.9.1", 45 | "vue-tsc": "^2.0.21" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /partykit.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://www.partykit.io/schema.json", 3 | "name": "usepartyref", 4 | "main": "server/src/main.ts", 5 | "compatibilityDate": "2024-06-29" 6 | } 7 | -------------------------------------------------------------------------------- /playground/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | usePartyRef | Playground 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /playground/public/pk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marchantweb/usePartyRef/f385def6a003be7388a121beb6360f5d5b8fccb1/playground/public/pk.png -------------------------------------------------------------------------------- /playground/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /playground/src/App.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 19 | 20 | 36 | -------------------------------------------------------------------------------- /playground/src/assets/vue.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /playground/src/components/CheckboxExample.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 27 | 28 | 40 | -------------------------------------------------------------------------------- /playground/src/components/CountExample.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 23 | 24 | 27 | -------------------------------------------------------------------------------- /playground/src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import './style.css' 3 | import App from './App.vue' 4 | 5 | createApp(App).mount('#app') 6 | -------------------------------------------------------------------------------- /playground/src/style.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | 16 | a { 17 | font-weight: 500; 18 | color: #646cff; 19 | text-decoration: inherit; 20 | } 21 | 22 | a:hover { 23 | color: #535bf2; 24 | } 25 | 26 | body { 27 | margin: 0; 28 | display: flex; 29 | place-items: center; 30 | min-width: 320px; 31 | min-height: 100vh; 32 | } 33 | 34 | h1 { 35 | font-size: 3.2em; 36 | line-height: 1.1; 37 | } 38 | 39 | button { 40 | border-radius: 8px; 41 | border: 1px solid transparent; 42 | padding: 0.6em 1.2em; 43 | font-size: 1em; 44 | font-weight: 500; 45 | font-family: inherit; 46 | background-color: #1a1a1a; 47 | cursor: pointer; 48 | transition: border-color 0.25s; 49 | } 50 | 51 | button:hover { 52 | border-color: #646cff; 53 | } 54 | 55 | button:focus, 56 | button:focus-visible { 57 | outline: 4px auto -webkit-focus-ring-color; 58 | } 59 | 60 | .card { 61 | padding: 2em; 62 | } 63 | 64 | #app { 65 | max-width: 1280px; 66 | margin: 0 auto; 67 | padding: 2rem; 68 | text-align: center; 69 | } 70 | 71 | p { 72 | margin-top: 40px; 73 | width: 600px; 74 | max-width: 100%; 75 | text-wrap: balance; 76 | } 77 | 78 | @media (prefers-color-scheme: light) { 79 | :root { 80 | color: #213547; 81 | background-color: #ffffff; 82 | } 83 | 84 | a:hover { 85 | color: #747bff; 86 | } 87 | 88 | button { 89 | background-color: #f9f9f9; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /playground/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | dependencies: 8 | partykit: 9 | specifier: ^0.0.107 10 | version: 0.0.107 11 | partysocket: 12 | specifier: ^1.0.1 13 | version: 1.0.1 14 | rate-limiter-flexible: 15 | specifier: ^5.0.3 16 | version: 5.0.3 17 | vue: 18 | specifier: ^3.4.29 19 | version: 3.4.30(typescript@5.5.2) 20 | 21 | devDependencies: 22 | '@types/node': 23 | specifier: ^20.14.9 24 | version: 20.14.9 25 | '@vitejs/plugin-vue': 26 | specifier: ^5.0.5 27 | version: 5.0.5(vite@5.3.1)(vue@3.4.30) 28 | concurrently: 29 | specifier: ^8.2.2 30 | version: 8.2.2 31 | typescript: 32 | specifier: ^5.2.2 33 | version: 5.5.2 34 | vite: 35 | specifier: ^5.3.1 36 | version: 5.3.1(@types/node@20.14.9) 37 | vite-plugin-dts: 38 | specifier: ^3.9.1 39 | version: 3.9.1(@types/node@20.14.9)(typescript@5.5.2)(vite@5.3.1) 40 | vue-tsc: 41 | specifier: ^2.0.21 42 | version: 2.0.22(typescript@5.5.2) 43 | 44 | packages: 45 | 46 | /@babel/helper-string-parser@7.24.7: 47 | resolution: {integrity: sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==} 48 | engines: {node: '>=6.9.0'} 49 | 50 | /@babel/helper-validator-identifier@7.24.7: 51 | resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} 52 | engines: {node: '>=6.9.0'} 53 | 54 | /@babel/parser@7.24.7: 55 | resolution: {integrity: sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==} 56 | engines: {node: '>=6.0.0'} 57 | hasBin: true 58 | dependencies: 59 | '@babel/types': 7.24.7 60 | 61 | /@babel/runtime@7.24.7: 62 | resolution: {integrity: sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==} 63 | engines: {node: '>=6.9.0'} 64 | dependencies: 65 | regenerator-runtime: 0.14.1 66 | dev: true 67 | 68 | /@babel/types@7.24.7: 69 | resolution: {integrity: sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==} 70 | engines: {node: '>=6.9.0'} 71 | dependencies: 72 | '@babel/helper-string-parser': 7.24.7 73 | '@babel/helper-validator-identifier': 7.24.7 74 | to-fast-properties: 2.0.0 75 | 76 | /@cloudflare/workerd-darwin-64@1.20240610.1: 77 | resolution: {integrity: sha512-YanZ1iXgMGaUWlleB5cswSE6qbzyjQ8O7ENWZcPAcZZ6BfuL7q3CWi0t9iM1cv2qx92rRztsRTyjcfq099++XQ==} 78 | engines: {node: '>=16'} 79 | cpu: [x64] 80 | os: [darwin] 81 | requiresBuild: true 82 | dev: false 83 | optional: true 84 | 85 | /@cloudflare/workerd-darwin-arm64@1.20240610.1: 86 | resolution: {integrity: sha512-bRe/y/LKjIgp3L2EHjc+CvoCzfHhf4aFTtOBkv2zW+VToNJ4KlXridndf7LvR9urfsFRRo9r4TXCssuKaU+ypQ==} 87 | engines: {node: '>=16'} 88 | cpu: [arm64] 89 | os: [darwin] 90 | requiresBuild: true 91 | dev: false 92 | optional: true 93 | 94 | /@cloudflare/workerd-linux-64@1.20240610.1: 95 | resolution: {integrity: sha512-2zDcadR7+Gs9SjcMXmwsMji2Xs+yASGNA2cEHDuFc4NMUup+eL1mkzxc/QzvFjyBck98e92rBjMZt2dVscpGKg==} 96 | engines: {node: '>=16'} 97 | cpu: [x64] 98 | os: [linux] 99 | requiresBuild: true 100 | dev: false 101 | optional: true 102 | 103 | /@cloudflare/workerd-linux-arm64@1.20240610.1: 104 | resolution: {integrity: sha512-7y41rPi5xmIYJN8CY+t3RHnjLL0xx/WYmaTd/j552k1qSr02eTE2o/TGyWZmGUC+lWnwdPQJla0mXbvdqgRdQg==} 105 | engines: {node: '>=16'} 106 | cpu: [arm64] 107 | os: [linux] 108 | requiresBuild: true 109 | dev: false 110 | optional: true 111 | 112 | /@cloudflare/workerd-windows-64@1.20240610.1: 113 | resolution: {integrity: sha512-B0LyT3DB6rXHWNptnntYHPaoJIy0rXnGfeDBM3nEVV8JIsQrx8MEFn2F2jYioH1FkUVavsaqKO/zUosY3tZXVA==} 114 | engines: {node: '>=16'} 115 | cpu: [x64] 116 | os: [win32] 117 | requiresBuild: true 118 | dev: false 119 | optional: true 120 | 121 | /@cloudflare/workers-types@4.20240614.0: 122 | resolution: {integrity: sha512-fnV3uXD1Hpq5EWnY7XYb+smPcjzIoUFiZpTSV/Tk8qKL3H+w6IqcngZwXQBZ/2U/DwYkDilXHW3FfPhnyD7FZA==} 123 | dev: false 124 | 125 | /@cspotcode/source-map-support@0.8.1: 126 | resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} 127 | engines: {node: '>=12'} 128 | dependencies: 129 | '@jridgewell/trace-mapping': 0.3.9 130 | dev: false 131 | 132 | /@esbuild/aix-ppc64@0.21.5: 133 | resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} 134 | engines: {node: '>=12'} 135 | cpu: [ppc64] 136 | os: [aix] 137 | requiresBuild: true 138 | optional: true 139 | 140 | /@esbuild/android-arm64@0.21.5: 141 | resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} 142 | engines: {node: '>=12'} 143 | cpu: [arm64] 144 | os: [android] 145 | requiresBuild: true 146 | optional: true 147 | 148 | /@esbuild/android-arm@0.21.5: 149 | resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} 150 | engines: {node: '>=12'} 151 | cpu: [arm] 152 | os: [android] 153 | requiresBuild: true 154 | optional: true 155 | 156 | /@esbuild/android-x64@0.21.5: 157 | resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} 158 | engines: {node: '>=12'} 159 | cpu: [x64] 160 | os: [android] 161 | requiresBuild: true 162 | optional: true 163 | 164 | /@esbuild/darwin-arm64@0.21.5: 165 | resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} 166 | engines: {node: '>=12'} 167 | cpu: [arm64] 168 | os: [darwin] 169 | requiresBuild: true 170 | optional: true 171 | 172 | /@esbuild/darwin-x64@0.21.5: 173 | resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} 174 | engines: {node: '>=12'} 175 | cpu: [x64] 176 | os: [darwin] 177 | requiresBuild: true 178 | optional: true 179 | 180 | /@esbuild/freebsd-arm64@0.21.5: 181 | resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} 182 | engines: {node: '>=12'} 183 | cpu: [arm64] 184 | os: [freebsd] 185 | requiresBuild: true 186 | optional: true 187 | 188 | /@esbuild/freebsd-x64@0.21.5: 189 | resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} 190 | engines: {node: '>=12'} 191 | cpu: [x64] 192 | os: [freebsd] 193 | requiresBuild: true 194 | optional: true 195 | 196 | /@esbuild/linux-arm64@0.21.5: 197 | resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} 198 | engines: {node: '>=12'} 199 | cpu: [arm64] 200 | os: [linux] 201 | requiresBuild: true 202 | optional: true 203 | 204 | /@esbuild/linux-arm@0.21.5: 205 | resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} 206 | engines: {node: '>=12'} 207 | cpu: [arm] 208 | os: [linux] 209 | requiresBuild: true 210 | optional: true 211 | 212 | /@esbuild/linux-ia32@0.21.5: 213 | resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} 214 | engines: {node: '>=12'} 215 | cpu: [ia32] 216 | os: [linux] 217 | requiresBuild: true 218 | optional: true 219 | 220 | /@esbuild/linux-loong64@0.21.5: 221 | resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} 222 | engines: {node: '>=12'} 223 | cpu: [loong64] 224 | os: [linux] 225 | requiresBuild: true 226 | optional: true 227 | 228 | /@esbuild/linux-mips64el@0.21.5: 229 | resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} 230 | engines: {node: '>=12'} 231 | cpu: [mips64el] 232 | os: [linux] 233 | requiresBuild: true 234 | optional: true 235 | 236 | /@esbuild/linux-ppc64@0.21.5: 237 | resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} 238 | engines: {node: '>=12'} 239 | cpu: [ppc64] 240 | os: [linux] 241 | requiresBuild: true 242 | optional: true 243 | 244 | /@esbuild/linux-riscv64@0.21.5: 245 | resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} 246 | engines: {node: '>=12'} 247 | cpu: [riscv64] 248 | os: [linux] 249 | requiresBuild: true 250 | optional: true 251 | 252 | /@esbuild/linux-s390x@0.21.5: 253 | resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} 254 | engines: {node: '>=12'} 255 | cpu: [s390x] 256 | os: [linux] 257 | requiresBuild: true 258 | optional: true 259 | 260 | /@esbuild/linux-x64@0.21.5: 261 | resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} 262 | engines: {node: '>=12'} 263 | cpu: [x64] 264 | os: [linux] 265 | requiresBuild: true 266 | optional: true 267 | 268 | /@esbuild/netbsd-x64@0.21.5: 269 | resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} 270 | engines: {node: '>=12'} 271 | cpu: [x64] 272 | os: [netbsd] 273 | requiresBuild: true 274 | optional: true 275 | 276 | /@esbuild/openbsd-x64@0.21.5: 277 | resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} 278 | engines: {node: '>=12'} 279 | cpu: [x64] 280 | os: [openbsd] 281 | requiresBuild: true 282 | optional: true 283 | 284 | /@esbuild/sunos-x64@0.21.5: 285 | resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} 286 | engines: {node: '>=12'} 287 | cpu: [x64] 288 | os: [sunos] 289 | requiresBuild: true 290 | optional: true 291 | 292 | /@esbuild/win32-arm64@0.21.5: 293 | resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} 294 | engines: {node: '>=12'} 295 | cpu: [arm64] 296 | os: [win32] 297 | requiresBuild: true 298 | optional: true 299 | 300 | /@esbuild/win32-ia32@0.21.5: 301 | resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} 302 | engines: {node: '>=12'} 303 | cpu: [ia32] 304 | os: [win32] 305 | requiresBuild: true 306 | optional: true 307 | 308 | /@esbuild/win32-x64@0.21.5: 309 | resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} 310 | engines: {node: '>=12'} 311 | cpu: [x64] 312 | os: [win32] 313 | requiresBuild: true 314 | optional: true 315 | 316 | /@fastify/busboy@2.1.1: 317 | resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} 318 | engines: {node: '>=14'} 319 | dev: false 320 | 321 | /@jridgewell/resolve-uri@3.1.2: 322 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} 323 | engines: {node: '>=6.0.0'} 324 | dev: false 325 | 326 | /@jridgewell/sourcemap-codec@1.4.15: 327 | resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} 328 | 329 | /@jridgewell/trace-mapping@0.3.9: 330 | resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} 331 | dependencies: 332 | '@jridgewell/resolve-uri': 3.1.2 333 | '@jridgewell/sourcemap-codec': 1.4.15 334 | dev: false 335 | 336 | /@microsoft/api-extractor-model@7.28.13(@types/node@20.14.9): 337 | resolution: {integrity: sha512-39v/JyldX4MS9uzHcdfmjjfS6cYGAoXV+io8B5a338pkHiSt+gy2eXQ0Q7cGFJ7quSa1VqqlMdlPrB6sLR/cAw==} 338 | dependencies: 339 | '@microsoft/tsdoc': 0.14.2 340 | '@microsoft/tsdoc-config': 0.16.2 341 | '@rushstack/node-core-library': 4.0.2(@types/node@20.14.9) 342 | transitivePeerDependencies: 343 | - '@types/node' 344 | dev: true 345 | 346 | /@microsoft/api-extractor@7.43.0(@types/node@20.14.9): 347 | resolution: {integrity: sha512-GFhTcJpB+MI6FhvXEI9b2K0snulNLWHqC/BbcJtyNYcKUiw7l3Lgis5ApsYncJ0leALX7/of4XfmXk+maT111w==} 348 | hasBin: true 349 | dependencies: 350 | '@microsoft/api-extractor-model': 7.28.13(@types/node@20.14.9) 351 | '@microsoft/tsdoc': 0.14.2 352 | '@microsoft/tsdoc-config': 0.16.2 353 | '@rushstack/node-core-library': 4.0.2(@types/node@20.14.9) 354 | '@rushstack/rig-package': 0.5.2 355 | '@rushstack/terminal': 0.10.0(@types/node@20.14.9) 356 | '@rushstack/ts-command-line': 4.19.1(@types/node@20.14.9) 357 | lodash: 4.17.21 358 | minimatch: 3.0.8 359 | resolve: 1.22.8 360 | semver: 7.5.4 361 | source-map: 0.6.1 362 | typescript: 5.4.2 363 | transitivePeerDependencies: 364 | - '@types/node' 365 | dev: true 366 | 367 | /@microsoft/tsdoc-config@0.16.2: 368 | resolution: {integrity: sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==} 369 | dependencies: 370 | '@microsoft/tsdoc': 0.14.2 371 | ajv: 6.12.6 372 | jju: 1.4.0 373 | resolve: 1.19.0 374 | dev: true 375 | 376 | /@microsoft/tsdoc@0.14.2: 377 | resolution: {integrity: sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==} 378 | dev: true 379 | 380 | /@rollup/pluginutils@5.1.0: 381 | resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==} 382 | engines: {node: '>=14.0.0'} 383 | peerDependencies: 384 | rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 385 | peerDependenciesMeta: 386 | rollup: 387 | optional: true 388 | dependencies: 389 | '@types/estree': 1.0.5 390 | estree-walker: 2.0.2 391 | picomatch: 2.3.1 392 | dev: true 393 | 394 | /@rollup/rollup-android-arm-eabi@4.18.0: 395 | resolution: {integrity: sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==} 396 | cpu: [arm] 397 | os: [android] 398 | requiresBuild: true 399 | dev: true 400 | optional: true 401 | 402 | /@rollup/rollup-android-arm64@4.18.0: 403 | resolution: {integrity: sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==} 404 | cpu: [arm64] 405 | os: [android] 406 | requiresBuild: true 407 | dev: true 408 | optional: true 409 | 410 | /@rollup/rollup-darwin-arm64@4.18.0: 411 | resolution: {integrity: sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==} 412 | cpu: [arm64] 413 | os: [darwin] 414 | requiresBuild: true 415 | dev: true 416 | optional: true 417 | 418 | /@rollup/rollup-darwin-x64@4.18.0: 419 | resolution: {integrity: sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==} 420 | cpu: [x64] 421 | os: [darwin] 422 | requiresBuild: true 423 | dev: true 424 | optional: true 425 | 426 | /@rollup/rollup-linux-arm-gnueabihf@4.18.0: 427 | resolution: {integrity: sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==} 428 | cpu: [arm] 429 | os: [linux] 430 | requiresBuild: true 431 | dev: true 432 | optional: true 433 | 434 | /@rollup/rollup-linux-arm-musleabihf@4.18.0: 435 | resolution: {integrity: sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==} 436 | cpu: [arm] 437 | os: [linux] 438 | requiresBuild: true 439 | dev: true 440 | optional: true 441 | 442 | /@rollup/rollup-linux-arm64-gnu@4.18.0: 443 | resolution: {integrity: sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==} 444 | cpu: [arm64] 445 | os: [linux] 446 | requiresBuild: true 447 | dev: true 448 | optional: true 449 | 450 | /@rollup/rollup-linux-arm64-musl@4.18.0: 451 | resolution: {integrity: sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==} 452 | cpu: [arm64] 453 | os: [linux] 454 | requiresBuild: true 455 | dev: true 456 | optional: true 457 | 458 | /@rollup/rollup-linux-powerpc64le-gnu@4.18.0: 459 | resolution: {integrity: sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==} 460 | cpu: [ppc64] 461 | os: [linux] 462 | requiresBuild: true 463 | dev: true 464 | optional: true 465 | 466 | /@rollup/rollup-linux-riscv64-gnu@4.18.0: 467 | resolution: {integrity: sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==} 468 | cpu: [riscv64] 469 | os: [linux] 470 | requiresBuild: true 471 | dev: true 472 | optional: true 473 | 474 | /@rollup/rollup-linux-s390x-gnu@4.18.0: 475 | resolution: {integrity: sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==} 476 | cpu: [s390x] 477 | os: [linux] 478 | requiresBuild: true 479 | dev: true 480 | optional: true 481 | 482 | /@rollup/rollup-linux-x64-gnu@4.18.0: 483 | resolution: {integrity: sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==} 484 | cpu: [x64] 485 | os: [linux] 486 | requiresBuild: true 487 | dev: true 488 | optional: true 489 | 490 | /@rollup/rollup-linux-x64-musl@4.18.0: 491 | resolution: {integrity: sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==} 492 | cpu: [x64] 493 | os: [linux] 494 | requiresBuild: true 495 | dev: true 496 | optional: true 497 | 498 | /@rollup/rollup-win32-arm64-msvc@4.18.0: 499 | resolution: {integrity: sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==} 500 | cpu: [arm64] 501 | os: [win32] 502 | requiresBuild: true 503 | dev: true 504 | optional: true 505 | 506 | /@rollup/rollup-win32-ia32-msvc@4.18.0: 507 | resolution: {integrity: sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==} 508 | cpu: [ia32] 509 | os: [win32] 510 | requiresBuild: true 511 | dev: true 512 | optional: true 513 | 514 | /@rollup/rollup-win32-x64-msvc@4.18.0: 515 | resolution: {integrity: sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==} 516 | cpu: [x64] 517 | os: [win32] 518 | requiresBuild: true 519 | dev: true 520 | optional: true 521 | 522 | /@rushstack/node-core-library@4.0.2(@types/node@20.14.9): 523 | resolution: {integrity: sha512-hyES82QVpkfQMeBMteQUnrhASL/KHPhd7iJ8euduwNJG4mu2GSOKybf0rOEjOm1Wz7CwJEUm9y0yD7jg2C1bfg==} 524 | peerDependencies: 525 | '@types/node': '*' 526 | peerDependenciesMeta: 527 | '@types/node': 528 | optional: true 529 | dependencies: 530 | '@types/node': 20.14.9 531 | fs-extra: 7.0.1 532 | import-lazy: 4.0.0 533 | jju: 1.4.0 534 | resolve: 1.22.8 535 | semver: 7.5.4 536 | z-schema: 5.0.5 537 | dev: true 538 | 539 | /@rushstack/rig-package@0.5.2: 540 | resolution: {integrity: sha512-mUDecIJeH3yYGZs2a48k+pbhM6JYwWlgjs2Ca5f2n1G2/kgdgP9D/07oglEGf6mRyXEnazhEENeYTSNDRCwdqA==} 541 | dependencies: 542 | resolve: 1.22.8 543 | strip-json-comments: 3.1.1 544 | dev: true 545 | 546 | /@rushstack/terminal@0.10.0(@types/node@20.14.9): 547 | resolution: {integrity: sha512-UbELbXnUdc7EKwfH2sb8ChqNgapUOdqcCIdQP4NGxBpTZV2sQyeekuK3zmfQSa/MN+/7b4kBogl2wq0vpkpYGw==} 548 | peerDependencies: 549 | '@types/node': '*' 550 | peerDependenciesMeta: 551 | '@types/node': 552 | optional: true 553 | dependencies: 554 | '@rushstack/node-core-library': 4.0.2(@types/node@20.14.9) 555 | '@types/node': 20.14.9 556 | supports-color: 8.1.1 557 | dev: true 558 | 559 | /@rushstack/ts-command-line@4.19.1(@types/node@20.14.9): 560 | resolution: {integrity: sha512-J7H768dgcpG60d7skZ5uSSwyCZs/S2HrWP1Ds8d1qYAyaaeJmpmmLr9BVw97RjFzmQPOYnoXcKA4GkqDCkduQg==} 561 | dependencies: 562 | '@rushstack/terminal': 0.10.0(@types/node@20.14.9) 563 | '@types/argparse': 1.0.38 564 | argparse: 1.0.10 565 | string-argv: 0.3.2 566 | transitivePeerDependencies: 567 | - '@types/node' 568 | dev: true 569 | 570 | /@types/argparse@1.0.38: 571 | resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==} 572 | dev: true 573 | 574 | /@types/estree@1.0.5: 575 | resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} 576 | dev: true 577 | 578 | /@types/node@20.14.9: 579 | resolution: {integrity: sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg==} 580 | dependencies: 581 | undici-types: 5.26.5 582 | dev: true 583 | 584 | /@vitejs/plugin-vue@5.0.5(vite@5.3.1)(vue@3.4.30): 585 | resolution: {integrity: sha512-LOjm7XeIimLBZyzinBQ6OSm3UBCNVCpLkxGC0oWmm2YPzVZoxMsdvNVimLTBzpAnR9hl/yn1SHGuRfe6/Td9rQ==} 586 | engines: {node: ^18.0.0 || >=20.0.0} 587 | peerDependencies: 588 | vite: ^5.0.0 589 | vue: ^3.2.25 590 | dependencies: 591 | vite: 5.3.1(@types/node@20.14.9) 592 | vue: 3.4.30(typescript@5.5.2) 593 | dev: true 594 | 595 | /@volar/language-core@1.11.1: 596 | resolution: {integrity: sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==} 597 | dependencies: 598 | '@volar/source-map': 1.11.1 599 | dev: true 600 | 601 | /@volar/language-core@2.3.2: 602 | resolution: {integrity: sha512-tx2BCWPpSNEW5fbE4XfERqgTtESHfsh8zoRDtpf3fsiDAPJI+2emqlxz2Dqcb4O0kFZzVnWINDOx/j6j1H3Vgw==} 603 | dependencies: 604 | '@volar/source-map': 2.3.2 605 | dev: true 606 | 607 | /@volar/source-map@1.11.1: 608 | resolution: {integrity: sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg==} 609 | dependencies: 610 | muggle-string: 0.3.1 611 | dev: true 612 | 613 | /@volar/source-map@2.3.2: 614 | resolution: {integrity: sha512-YGQ5UFNj+ngpklp3SNzTHzaq7e5Rqlcb01ym+oR8mtu7BfkfBxmtCv8YNXEVZ/oU6MF8s3cibpZhOn696MRsYg==} 615 | dev: true 616 | 617 | /@volar/typescript@1.11.1: 618 | resolution: {integrity: sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==} 619 | dependencies: 620 | '@volar/language-core': 1.11.1 621 | path-browserify: 1.0.1 622 | dev: true 623 | 624 | /@volar/typescript@2.3.2: 625 | resolution: {integrity: sha512-HJ1mjiEU/R1Wg3lrBp9jqNZvMOkNLA8+ryHhrzHAjV7pv214mQT/mB/1msu3mduh1Q2iDETU4Vttl5RA7ZPezg==} 626 | dependencies: 627 | '@volar/language-core': 2.3.2 628 | path-browserify: 1.0.1 629 | vscode-uri: 3.0.8 630 | dev: true 631 | 632 | /@vue/compiler-core@3.4.30: 633 | resolution: {integrity: sha512-ZL8y4Xxdh8O6PSwfdZ1IpQ24PjTAieOz3jXb/MDTfDtANcKBMxg1KLm6OX2jofsaQGYfIVzd3BAG22i56/cF1w==} 634 | dependencies: 635 | '@babel/parser': 7.24.7 636 | '@vue/shared': 3.4.30 637 | entities: 4.5.0 638 | estree-walker: 2.0.2 639 | source-map-js: 1.2.0 640 | 641 | /@vue/compiler-dom@3.4.30: 642 | resolution: {integrity: sha512-+16Sd8lYr5j/owCbr9dowcNfrHd+pz+w2/b5Lt26Oz/kB90C9yNbxQ3bYOvt7rI2bxk0nqda39hVcwDFw85c2Q==} 643 | dependencies: 644 | '@vue/compiler-core': 3.4.30 645 | '@vue/shared': 3.4.30 646 | 647 | /@vue/compiler-sfc@3.4.30: 648 | resolution: {integrity: sha512-8vElKklHn/UY8+FgUFlQrYAPbtiSB2zcgeRKW7HkpSRn/JjMRmZvuOtwDx036D1aqKNSTtXkWRfqx53Qb+HmMg==} 649 | dependencies: 650 | '@babel/parser': 7.24.7 651 | '@vue/compiler-core': 3.4.30 652 | '@vue/compiler-dom': 3.4.30 653 | '@vue/compiler-ssr': 3.4.30 654 | '@vue/shared': 3.4.30 655 | estree-walker: 2.0.2 656 | magic-string: 0.30.10 657 | postcss: 8.4.38 658 | source-map-js: 1.2.0 659 | 660 | /@vue/compiler-ssr@3.4.30: 661 | resolution: {integrity: sha512-ZJ56YZGXJDd6jky4mmM0rNaNP6kIbQu9LTKZDhcpddGe/3QIalB1WHHmZ6iZfFNyj5mSypTa4+qDJa5VIuxMSg==} 662 | dependencies: 663 | '@vue/compiler-dom': 3.4.30 664 | '@vue/shared': 3.4.30 665 | 666 | /@vue/language-core@1.8.27(typescript@5.5.2): 667 | resolution: {integrity: sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==} 668 | peerDependencies: 669 | typescript: '*' 670 | peerDependenciesMeta: 671 | typescript: 672 | optional: true 673 | dependencies: 674 | '@volar/language-core': 1.11.1 675 | '@volar/source-map': 1.11.1 676 | '@vue/compiler-dom': 3.4.30 677 | '@vue/shared': 3.4.30 678 | computeds: 0.0.1 679 | minimatch: 9.0.4 680 | muggle-string: 0.3.1 681 | path-browserify: 1.0.1 682 | typescript: 5.5.2 683 | vue-template-compiler: 2.7.16 684 | dev: true 685 | 686 | /@vue/language-core@2.0.22(typescript@5.5.2): 687 | resolution: {integrity: sha512-dNTAAtEOuMiz7N1s5tKpypnVVCtawxVSF5BukD0ELcYSw+DSbrSlYYSw8GuwvurodCeYFSHsmslE+c2sYDNoiA==} 688 | peerDependencies: 689 | typescript: '*' 690 | peerDependenciesMeta: 691 | typescript: 692 | optional: true 693 | dependencies: 694 | '@volar/language-core': 2.3.2 695 | '@vue/compiler-dom': 3.4.30 696 | '@vue/shared': 3.4.30 697 | computeds: 0.0.1 698 | minimatch: 9.0.4 699 | muggle-string: 0.4.1 700 | path-browserify: 1.0.1 701 | typescript: 5.5.2 702 | vue-template-compiler: 2.7.16 703 | dev: true 704 | 705 | /@vue/reactivity@3.4.30: 706 | resolution: {integrity: sha512-bVJurnCe3LS0JII8PPoAA63Zd2MBzcKrEzwdQl92eHCcxtIbxD2fhNwJpa+KkM3Y/A4T5FUnmdhgKwOf6BfbcA==} 707 | dependencies: 708 | '@vue/shared': 3.4.30 709 | 710 | /@vue/runtime-core@3.4.30: 711 | resolution: {integrity: sha512-qaFEbnNpGz+tlnkaualomogzN8vBLkgzK55uuWjYXbYn039eOBZrWxyXWq/7qh9Bz2FPifZqGjVDl/FXiq9L2g==} 712 | dependencies: 713 | '@vue/reactivity': 3.4.30 714 | '@vue/shared': 3.4.30 715 | 716 | /@vue/runtime-dom@3.4.30: 717 | resolution: {integrity: sha512-tV6B4YiZRj5QsaJgw2THCy5C1H+2UeywO9tqgWEc21tn85qHEERndHN/CxlyXvSBFrpmlexCIdnqPuR9RM9thw==} 718 | dependencies: 719 | '@vue/reactivity': 3.4.30 720 | '@vue/runtime-core': 3.4.30 721 | '@vue/shared': 3.4.30 722 | csstype: 3.1.3 723 | 724 | /@vue/server-renderer@3.4.30(vue@3.4.30): 725 | resolution: {integrity: sha512-TBD3eqR1DeDc0cMrXS/vEs/PWzq1uXxnvjoqQuDGFIEHFIwuDTX/KWAQKIBjyMWLFHEeTDGYVsYci85z2UbTDg==} 726 | peerDependencies: 727 | vue: 3.4.30 728 | dependencies: 729 | '@vue/compiler-ssr': 3.4.30 730 | '@vue/shared': 3.4.30 731 | vue: 3.4.30(typescript@5.5.2) 732 | 733 | /@vue/shared@3.4.30: 734 | resolution: {integrity: sha512-CLg+f8RQCHQnKvuHY9adMsMaQOcqclh6Z5V9TaoMgy0ut0tz848joZ7/CYFFyF/yZ5i2yaw7Fn498C+CNZVHIg==} 735 | 736 | /acorn-walk@8.3.3: 737 | resolution: {integrity: sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==} 738 | engines: {node: '>=0.4.0'} 739 | dependencies: 740 | acorn: 8.12.0 741 | dev: false 742 | 743 | /acorn@8.12.0: 744 | resolution: {integrity: sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==} 745 | engines: {node: '>=0.4.0'} 746 | hasBin: true 747 | dev: false 748 | 749 | /ajv@6.12.6: 750 | resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} 751 | dependencies: 752 | fast-deep-equal: 3.1.3 753 | fast-json-stable-stringify: 2.1.0 754 | json-schema-traverse: 0.4.1 755 | uri-js: 4.4.1 756 | dev: true 757 | 758 | /ansi-regex@5.0.1: 759 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 760 | engines: {node: '>=8'} 761 | dev: true 762 | 763 | /ansi-styles@4.3.0: 764 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 765 | engines: {node: '>=8'} 766 | dependencies: 767 | color-convert: 2.0.1 768 | dev: true 769 | 770 | /argparse@1.0.10: 771 | resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} 772 | dependencies: 773 | sprintf-js: 1.0.3 774 | dev: true 775 | 776 | /as-table@1.0.55: 777 | resolution: {integrity: sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==} 778 | dependencies: 779 | printable-characters: 1.0.42 780 | dev: false 781 | 782 | /balanced-match@1.0.2: 783 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 784 | dev: true 785 | 786 | /brace-expansion@1.1.11: 787 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} 788 | dependencies: 789 | balanced-match: 1.0.2 790 | concat-map: 0.0.1 791 | dev: true 792 | 793 | /brace-expansion@2.0.1: 794 | resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} 795 | dependencies: 796 | balanced-match: 1.0.2 797 | dev: true 798 | 799 | /capnp-ts@0.7.0: 800 | resolution: {integrity: sha512-XKxXAC3HVPv7r674zP0VC3RTXz+/JKhfyw94ljvF80yynK6VkTnqE3jMuN8b3dUVmmc43TjyxjW4KTsmB3c86g==} 801 | dependencies: 802 | debug: 4.3.5 803 | tslib: 2.6.3 804 | transitivePeerDependencies: 805 | - supports-color 806 | dev: false 807 | 808 | /chalk@4.1.2: 809 | resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} 810 | engines: {node: '>=10'} 811 | dependencies: 812 | ansi-styles: 4.3.0 813 | supports-color: 7.2.0 814 | dev: true 815 | 816 | /clipboardy@4.0.0: 817 | resolution: {integrity: sha512-5mOlNS0mhX0707P2I0aZ2V/cmHUEO/fL7VFLqszkhUsxt7RwnmrInf/eEQKlf5GzvYeHIjT+Ov1HRfNmymlG0w==} 818 | engines: {node: '>=18'} 819 | dependencies: 820 | execa: 8.0.1 821 | is-wsl: 3.1.0 822 | is64bit: 2.0.0 823 | dev: false 824 | 825 | /cliui@8.0.1: 826 | resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} 827 | engines: {node: '>=12'} 828 | dependencies: 829 | string-width: 4.2.3 830 | strip-ansi: 6.0.1 831 | wrap-ansi: 7.0.0 832 | dev: true 833 | 834 | /color-convert@2.0.1: 835 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 836 | engines: {node: '>=7.0.0'} 837 | dependencies: 838 | color-name: 1.1.4 839 | dev: true 840 | 841 | /color-name@1.1.4: 842 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 843 | dev: true 844 | 845 | /commander@9.5.0: 846 | resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} 847 | engines: {node: ^12.20.0 || >=14} 848 | requiresBuild: true 849 | dev: true 850 | optional: true 851 | 852 | /computeds@0.0.1: 853 | resolution: {integrity: sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==} 854 | dev: true 855 | 856 | /concat-map@0.0.1: 857 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} 858 | dev: true 859 | 860 | /concurrently@8.2.2: 861 | resolution: {integrity: sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==} 862 | engines: {node: ^14.13.0 || >=16.0.0} 863 | hasBin: true 864 | dependencies: 865 | chalk: 4.1.2 866 | date-fns: 2.30.0 867 | lodash: 4.17.21 868 | rxjs: 7.8.1 869 | shell-quote: 1.8.1 870 | spawn-command: 0.0.2 871 | supports-color: 8.1.1 872 | tree-kill: 1.2.2 873 | yargs: 17.7.2 874 | dev: true 875 | 876 | /cookie@0.5.0: 877 | resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} 878 | engines: {node: '>= 0.6'} 879 | dev: false 880 | 881 | /cross-spawn@7.0.3: 882 | resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} 883 | engines: {node: '>= 8'} 884 | dependencies: 885 | path-key: 3.1.1 886 | shebang-command: 2.0.0 887 | which: 2.0.2 888 | dev: false 889 | 890 | /csstype@3.1.3: 891 | resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} 892 | 893 | /data-uri-to-buffer@2.0.2: 894 | resolution: {integrity: sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==} 895 | dev: false 896 | 897 | /date-fns@2.30.0: 898 | resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} 899 | engines: {node: '>=0.11'} 900 | dependencies: 901 | '@babel/runtime': 7.24.7 902 | dev: true 903 | 904 | /de-indent@1.0.2: 905 | resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} 906 | dev: true 907 | 908 | /debug@4.3.5: 909 | resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==} 910 | engines: {node: '>=6.0'} 911 | peerDependencies: 912 | supports-color: '*' 913 | peerDependenciesMeta: 914 | supports-color: 915 | optional: true 916 | dependencies: 917 | ms: 2.1.2 918 | 919 | /emoji-regex@8.0.0: 920 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 921 | dev: true 922 | 923 | /entities@4.5.0: 924 | resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} 925 | engines: {node: '>=0.12'} 926 | 927 | /esbuild@0.21.5: 928 | resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} 929 | engines: {node: '>=12'} 930 | hasBin: true 931 | requiresBuild: true 932 | optionalDependencies: 933 | '@esbuild/aix-ppc64': 0.21.5 934 | '@esbuild/android-arm': 0.21.5 935 | '@esbuild/android-arm64': 0.21.5 936 | '@esbuild/android-x64': 0.21.5 937 | '@esbuild/darwin-arm64': 0.21.5 938 | '@esbuild/darwin-x64': 0.21.5 939 | '@esbuild/freebsd-arm64': 0.21.5 940 | '@esbuild/freebsd-x64': 0.21.5 941 | '@esbuild/linux-arm': 0.21.5 942 | '@esbuild/linux-arm64': 0.21.5 943 | '@esbuild/linux-ia32': 0.21.5 944 | '@esbuild/linux-loong64': 0.21.5 945 | '@esbuild/linux-mips64el': 0.21.5 946 | '@esbuild/linux-ppc64': 0.21.5 947 | '@esbuild/linux-riscv64': 0.21.5 948 | '@esbuild/linux-s390x': 0.21.5 949 | '@esbuild/linux-x64': 0.21.5 950 | '@esbuild/netbsd-x64': 0.21.5 951 | '@esbuild/openbsd-x64': 0.21.5 952 | '@esbuild/sunos-x64': 0.21.5 953 | '@esbuild/win32-arm64': 0.21.5 954 | '@esbuild/win32-ia32': 0.21.5 955 | '@esbuild/win32-x64': 0.21.5 956 | 957 | /escalade@3.1.2: 958 | resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} 959 | engines: {node: '>=6'} 960 | dev: true 961 | 962 | /estree-walker@2.0.2: 963 | resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} 964 | 965 | /event-target-shim@6.0.2: 966 | resolution: {integrity: sha512-8q3LsZjRezbFZ2PN+uP+Q7pnHUMmAOziU2vA2OwoFaKIXxlxl38IylhSSgUorWu/rf4er67w0ikBqjBFk/pomA==} 967 | engines: {node: '>=10.13.0'} 968 | dev: false 969 | 970 | /execa@8.0.1: 971 | resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} 972 | engines: {node: '>=16.17'} 973 | dependencies: 974 | cross-spawn: 7.0.3 975 | get-stream: 8.0.1 976 | human-signals: 5.0.0 977 | is-stream: 3.0.0 978 | merge-stream: 2.0.0 979 | npm-run-path: 5.3.0 980 | onetime: 6.0.0 981 | signal-exit: 4.1.0 982 | strip-final-newline: 3.0.0 983 | dev: false 984 | 985 | /exit-hook@2.2.1: 986 | resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==} 987 | engines: {node: '>=6'} 988 | dev: false 989 | 990 | /fast-deep-equal@3.1.3: 991 | resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} 992 | dev: true 993 | 994 | /fast-json-stable-stringify@2.1.0: 995 | resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} 996 | dev: true 997 | 998 | /fs-extra@7.0.1: 999 | resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} 1000 | engines: {node: '>=6 <7 || >=8'} 1001 | dependencies: 1002 | graceful-fs: 4.2.11 1003 | jsonfile: 4.0.0 1004 | universalify: 0.1.2 1005 | dev: true 1006 | 1007 | /fsevents@2.3.3: 1008 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 1009 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 1010 | os: [darwin] 1011 | requiresBuild: true 1012 | optional: true 1013 | 1014 | /function-bind@1.1.2: 1015 | resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} 1016 | dev: true 1017 | 1018 | /get-caller-file@2.0.5: 1019 | resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} 1020 | engines: {node: 6.* || 8.* || >= 10.*} 1021 | dev: true 1022 | 1023 | /get-source@2.0.12: 1024 | resolution: {integrity: sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==} 1025 | dependencies: 1026 | data-uri-to-buffer: 2.0.2 1027 | source-map: 0.6.1 1028 | dev: false 1029 | 1030 | /get-stream@8.0.1: 1031 | resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} 1032 | engines: {node: '>=16'} 1033 | dev: false 1034 | 1035 | /glob-to-regexp@0.4.1: 1036 | resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} 1037 | dev: false 1038 | 1039 | /graceful-fs@4.2.11: 1040 | resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} 1041 | dev: true 1042 | 1043 | /has-flag@4.0.0: 1044 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 1045 | engines: {node: '>=8'} 1046 | dev: true 1047 | 1048 | /hasown@2.0.2: 1049 | resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} 1050 | engines: {node: '>= 0.4'} 1051 | dependencies: 1052 | function-bind: 1.1.2 1053 | dev: true 1054 | 1055 | /he@1.2.0: 1056 | resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} 1057 | hasBin: true 1058 | dev: true 1059 | 1060 | /human-signals@5.0.0: 1061 | resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} 1062 | engines: {node: '>=16.17.0'} 1063 | dev: false 1064 | 1065 | /import-lazy@4.0.0: 1066 | resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} 1067 | engines: {node: '>=8'} 1068 | dev: true 1069 | 1070 | /is-core-module@2.14.0: 1071 | resolution: {integrity: sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==} 1072 | engines: {node: '>= 0.4'} 1073 | dependencies: 1074 | hasown: 2.0.2 1075 | dev: true 1076 | 1077 | /is-docker@3.0.0: 1078 | resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} 1079 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1080 | hasBin: true 1081 | dev: false 1082 | 1083 | /is-fullwidth-code-point@3.0.0: 1084 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 1085 | engines: {node: '>=8'} 1086 | dev: true 1087 | 1088 | /is-inside-container@1.0.0: 1089 | resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} 1090 | engines: {node: '>=14.16'} 1091 | hasBin: true 1092 | dependencies: 1093 | is-docker: 3.0.0 1094 | dev: false 1095 | 1096 | /is-stream@3.0.0: 1097 | resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} 1098 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1099 | dev: false 1100 | 1101 | /is-wsl@3.1.0: 1102 | resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} 1103 | engines: {node: '>=16'} 1104 | dependencies: 1105 | is-inside-container: 1.0.0 1106 | dev: false 1107 | 1108 | /is64bit@2.0.0: 1109 | resolution: {integrity: sha512-jv+8jaWCl0g2lSBkNSVXdzfBA0npK1HGC2KtWM9FumFRoGS94g3NbCCLVnCYHLjp4GrW2KZeeSTMo5ddtznmGw==} 1110 | engines: {node: '>=18'} 1111 | dependencies: 1112 | system-architecture: 0.1.0 1113 | dev: false 1114 | 1115 | /isexe@2.0.0: 1116 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 1117 | dev: false 1118 | 1119 | /jju@1.4.0: 1120 | resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} 1121 | dev: true 1122 | 1123 | /json-schema-traverse@0.4.1: 1124 | resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} 1125 | dev: true 1126 | 1127 | /jsonfile@4.0.0: 1128 | resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} 1129 | optionalDependencies: 1130 | graceful-fs: 4.2.11 1131 | dev: true 1132 | 1133 | /kolorist@1.8.0: 1134 | resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} 1135 | dev: true 1136 | 1137 | /lodash.get@4.4.2: 1138 | resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} 1139 | dev: true 1140 | 1141 | /lodash.isequal@4.5.0: 1142 | resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} 1143 | dev: true 1144 | 1145 | /lodash@4.17.21: 1146 | resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} 1147 | dev: true 1148 | 1149 | /lru-cache@6.0.0: 1150 | resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} 1151 | engines: {node: '>=10'} 1152 | dependencies: 1153 | yallist: 4.0.0 1154 | dev: true 1155 | 1156 | /magic-string@0.30.10: 1157 | resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==} 1158 | dependencies: 1159 | '@jridgewell/sourcemap-codec': 1.4.15 1160 | 1161 | /merge-stream@2.0.0: 1162 | resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} 1163 | dev: false 1164 | 1165 | /mimic-fn@4.0.0: 1166 | resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} 1167 | engines: {node: '>=12'} 1168 | dev: false 1169 | 1170 | /miniflare@3.20240610.0: 1171 | resolution: {integrity: sha512-J6aXmkII5gcq+kC4TurxKiR4rC++apPST/K8P/YjqoQQgrJ+NRPacBhf6iVh8R3ujnXYXaq+Ae+gm+LM0XHK/w==} 1172 | engines: {node: '>=16.13'} 1173 | hasBin: true 1174 | dependencies: 1175 | '@cspotcode/source-map-support': 0.8.1 1176 | acorn: 8.12.0 1177 | acorn-walk: 8.3.3 1178 | capnp-ts: 0.7.0 1179 | exit-hook: 2.2.1 1180 | glob-to-regexp: 0.4.1 1181 | stoppable: 1.1.0 1182 | undici: 5.28.4 1183 | workerd: 1.20240610.1 1184 | ws: 8.17.1 1185 | youch: 3.3.3 1186 | zod: 3.23.8 1187 | transitivePeerDependencies: 1188 | - bufferutil 1189 | - supports-color 1190 | - utf-8-validate 1191 | dev: false 1192 | 1193 | /minimatch@3.0.8: 1194 | resolution: {integrity: sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==} 1195 | dependencies: 1196 | brace-expansion: 1.1.11 1197 | dev: true 1198 | 1199 | /minimatch@9.0.4: 1200 | resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==} 1201 | engines: {node: '>=16 || 14 >=14.17'} 1202 | dependencies: 1203 | brace-expansion: 2.0.1 1204 | dev: true 1205 | 1206 | /ms@2.1.2: 1207 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} 1208 | 1209 | /muggle-string@0.3.1: 1210 | resolution: {integrity: sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==} 1211 | dev: true 1212 | 1213 | /muggle-string@0.4.1: 1214 | resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} 1215 | dev: true 1216 | 1217 | /mustache@4.2.0: 1218 | resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} 1219 | hasBin: true 1220 | dev: false 1221 | 1222 | /nanoid@3.3.7: 1223 | resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} 1224 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 1225 | hasBin: true 1226 | 1227 | /npm-run-path@5.3.0: 1228 | resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} 1229 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1230 | dependencies: 1231 | path-key: 4.0.0 1232 | dev: false 1233 | 1234 | /onetime@6.0.0: 1235 | resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} 1236 | engines: {node: '>=12'} 1237 | dependencies: 1238 | mimic-fn: 4.0.0 1239 | dev: false 1240 | 1241 | /partykit@0.0.107: 1242 | resolution: {integrity: sha512-MRSXRRuJXFC3RlBqVHpR7vYj3cDHNjJzrwjOKG3eidg4sADTmlaTNsz/8iKAPVY1WOhADtx/XMYNi4JbK/bahA==} 1243 | hasBin: true 1244 | dependencies: 1245 | '@cloudflare/workers-types': 4.20240614.0 1246 | clipboardy: 4.0.0 1247 | esbuild: 0.21.5 1248 | miniflare: 3.20240610.0 1249 | yoga-wasm-web: 0.3.3 1250 | optionalDependencies: 1251 | fsevents: 2.3.3 1252 | transitivePeerDependencies: 1253 | - bufferutil 1254 | - supports-color 1255 | - utf-8-validate 1256 | dev: false 1257 | 1258 | /partysocket@1.0.1: 1259 | resolution: {integrity: sha512-sSnLf9X0Oaxw0wXp0liKho0QQqStDJB5I4ViaqmtI4nHm6cpb2kUealErPrcQpYUF6zgTHzLQhIO++2tcJc59A==} 1260 | dependencies: 1261 | event-target-shim: 6.0.2 1262 | dev: false 1263 | 1264 | /path-browserify@1.0.1: 1265 | resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} 1266 | dev: true 1267 | 1268 | /path-key@3.1.1: 1269 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 1270 | engines: {node: '>=8'} 1271 | dev: false 1272 | 1273 | /path-key@4.0.0: 1274 | resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} 1275 | engines: {node: '>=12'} 1276 | dev: false 1277 | 1278 | /path-parse@1.0.7: 1279 | resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} 1280 | dev: true 1281 | 1282 | /picocolors@1.0.1: 1283 | resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} 1284 | 1285 | /picomatch@2.3.1: 1286 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 1287 | engines: {node: '>=8.6'} 1288 | dev: true 1289 | 1290 | /postcss@8.4.38: 1291 | resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} 1292 | engines: {node: ^10 || ^12 || >=14} 1293 | dependencies: 1294 | nanoid: 3.3.7 1295 | picocolors: 1.0.1 1296 | source-map-js: 1.2.0 1297 | 1298 | /printable-characters@1.0.42: 1299 | resolution: {integrity: sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==} 1300 | dev: false 1301 | 1302 | /punycode@2.3.1: 1303 | resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} 1304 | engines: {node: '>=6'} 1305 | dev: true 1306 | 1307 | /rate-limiter-flexible@5.0.3: 1308 | resolution: {integrity: sha512-lWx2y8NBVlTOLPyqs+6y7dxfEpT6YFqKy3MzWbCy95sTTOhOuxufP2QvRyOHpfXpB9OUJPbVLybw3z3AVAS5fA==} 1309 | dev: false 1310 | 1311 | /regenerator-runtime@0.14.1: 1312 | resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} 1313 | dev: true 1314 | 1315 | /require-directory@2.1.1: 1316 | resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} 1317 | engines: {node: '>=0.10.0'} 1318 | dev: true 1319 | 1320 | /resolve@1.19.0: 1321 | resolution: {integrity: sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==} 1322 | dependencies: 1323 | is-core-module: 2.14.0 1324 | path-parse: 1.0.7 1325 | dev: true 1326 | 1327 | /resolve@1.22.8: 1328 | resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} 1329 | hasBin: true 1330 | dependencies: 1331 | is-core-module: 2.14.0 1332 | path-parse: 1.0.7 1333 | supports-preserve-symlinks-flag: 1.0.0 1334 | dev: true 1335 | 1336 | /rollup@4.18.0: 1337 | resolution: {integrity: sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==} 1338 | engines: {node: '>=18.0.0', npm: '>=8.0.0'} 1339 | hasBin: true 1340 | dependencies: 1341 | '@types/estree': 1.0.5 1342 | optionalDependencies: 1343 | '@rollup/rollup-android-arm-eabi': 4.18.0 1344 | '@rollup/rollup-android-arm64': 4.18.0 1345 | '@rollup/rollup-darwin-arm64': 4.18.0 1346 | '@rollup/rollup-darwin-x64': 4.18.0 1347 | '@rollup/rollup-linux-arm-gnueabihf': 4.18.0 1348 | '@rollup/rollup-linux-arm-musleabihf': 4.18.0 1349 | '@rollup/rollup-linux-arm64-gnu': 4.18.0 1350 | '@rollup/rollup-linux-arm64-musl': 4.18.0 1351 | '@rollup/rollup-linux-powerpc64le-gnu': 4.18.0 1352 | '@rollup/rollup-linux-riscv64-gnu': 4.18.0 1353 | '@rollup/rollup-linux-s390x-gnu': 4.18.0 1354 | '@rollup/rollup-linux-x64-gnu': 4.18.0 1355 | '@rollup/rollup-linux-x64-musl': 4.18.0 1356 | '@rollup/rollup-win32-arm64-msvc': 4.18.0 1357 | '@rollup/rollup-win32-ia32-msvc': 4.18.0 1358 | '@rollup/rollup-win32-x64-msvc': 4.18.0 1359 | fsevents: 2.3.3 1360 | dev: true 1361 | 1362 | /rxjs@7.8.1: 1363 | resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} 1364 | dependencies: 1365 | tslib: 2.6.3 1366 | dev: true 1367 | 1368 | /semver@7.5.4: 1369 | resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} 1370 | engines: {node: '>=10'} 1371 | hasBin: true 1372 | dependencies: 1373 | lru-cache: 6.0.0 1374 | dev: true 1375 | 1376 | /semver@7.6.2: 1377 | resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} 1378 | engines: {node: '>=10'} 1379 | hasBin: true 1380 | dev: true 1381 | 1382 | /shebang-command@2.0.0: 1383 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 1384 | engines: {node: '>=8'} 1385 | dependencies: 1386 | shebang-regex: 3.0.0 1387 | dev: false 1388 | 1389 | /shebang-regex@3.0.0: 1390 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 1391 | engines: {node: '>=8'} 1392 | dev: false 1393 | 1394 | /shell-quote@1.8.1: 1395 | resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==} 1396 | dev: true 1397 | 1398 | /signal-exit@4.1.0: 1399 | resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} 1400 | engines: {node: '>=14'} 1401 | dev: false 1402 | 1403 | /source-map-js@1.2.0: 1404 | resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} 1405 | engines: {node: '>=0.10.0'} 1406 | 1407 | /source-map@0.6.1: 1408 | resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} 1409 | engines: {node: '>=0.10.0'} 1410 | 1411 | /spawn-command@0.0.2: 1412 | resolution: {integrity: sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==} 1413 | dev: true 1414 | 1415 | /sprintf-js@1.0.3: 1416 | resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} 1417 | dev: true 1418 | 1419 | /stacktracey@2.1.8: 1420 | resolution: {integrity: sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==} 1421 | dependencies: 1422 | as-table: 1.0.55 1423 | get-source: 2.0.12 1424 | dev: false 1425 | 1426 | /stoppable@1.1.0: 1427 | resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==} 1428 | engines: {node: '>=4', npm: '>=6'} 1429 | dev: false 1430 | 1431 | /string-argv@0.3.2: 1432 | resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} 1433 | engines: {node: '>=0.6.19'} 1434 | dev: true 1435 | 1436 | /string-width@4.2.3: 1437 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 1438 | engines: {node: '>=8'} 1439 | dependencies: 1440 | emoji-regex: 8.0.0 1441 | is-fullwidth-code-point: 3.0.0 1442 | strip-ansi: 6.0.1 1443 | dev: true 1444 | 1445 | /strip-ansi@6.0.1: 1446 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 1447 | engines: {node: '>=8'} 1448 | dependencies: 1449 | ansi-regex: 5.0.1 1450 | dev: true 1451 | 1452 | /strip-final-newline@3.0.0: 1453 | resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} 1454 | engines: {node: '>=12'} 1455 | dev: false 1456 | 1457 | /strip-json-comments@3.1.1: 1458 | resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} 1459 | engines: {node: '>=8'} 1460 | dev: true 1461 | 1462 | /supports-color@7.2.0: 1463 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 1464 | engines: {node: '>=8'} 1465 | dependencies: 1466 | has-flag: 4.0.0 1467 | dev: true 1468 | 1469 | /supports-color@8.1.1: 1470 | resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} 1471 | engines: {node: '>=10'} 1472 | dependencies: 1473 | has-flag: 4.0.0 1474 | dev: true 1475 | 1476 | /supports-preserve-symlinks-flag@1.0.0: 1477 | resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} 1478 | engines: {node: '>= 0.4'} 1479 | dev: true 1480 | 1481 | /system-architecture@0.1.0: 1482 | resolution: {integrity: sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA==} 1483 | engines: {node: '>=18'} 1484 | dev: false 1485 | 1486 | /to-fast-properties@2.0.0: 1487 | resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} 1488 | engines: {node: '>=4'} 1489 | 1490 | /tree-kill@1.2.2: 1491 | resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} 1492 | hasBin: true 1493 | dev: true 1494 | 1495 | /tslib@2.6.3: 1496 | resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} 1497 | 1498 | /typescript@5.4.2: 1499 | resolution: {integrity: sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==} 1500 | engines: {node: '>=14.17'} 1501 | hasBin: true 1502 | dev: true 1503 | 1504 | /typescript@5.5.2: 1505 | resolution: {integrity: sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew==} 1506 | engines: {node: '>=14.17'} 1507 | hasBin: true 1508 | 1509 | /undici-types@5.26.5: 1510 | resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} 1511 | dev: true 1512 | 1513 | /undici@5.28.4: 1514 | resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==} 1515 | engines: {node: '>=14.0'} 1516 | dependencies: 1517 | '@fastify/busboy': 2.1.1 1518 | dev: false 1519 | 1520 | /universalify@0.1.2: 1521 | resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} 1522 | engines: {node: '>= 4.0.0'} 1523 | dev: true 1524 | 1525 | /uri-js@4.4.1: 1526 | resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} 1527 | dependencies: 1528 | punycode: 2.3.1 1529 | dev: true 1530 | 1531 | /validator@13.12.0: 1532 | resolution: {integrity: sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==} 1533 | engines: {node: '>= 0.10'} 1534 | dev: true 1535 | 1536 | /vite-plugin-dts@3.9.1(@types/node@20.14.9)(typescript@5.5.2)(vite@5.3.1): 1537 | resolution: {integrity: sha512-rVp2KM9Ue22NGWB8dNtWEr+KekN3rIgz1tWD050QnRGlriUCmaDwa7qA5zDEjbXg5lAXhYMSBJtx3q3hQIJZSg==} 1538 | engines: {node: ^14.18.0 || >=16.0.0} 1539 | peerDependencies: 1540 | typescript: '*' 1541 | vite: '*' 1542 | peerDependenciesMeta: 1543 | vite: 1544 | optional: true 1545 | dependencies: 1546 | '@microsoft/api-extractor': 7.43.0(@types/node@20.14.9) 1547 | '@rollup/pluginutils': 5.1.0 1548 | '@vue/language-core': 1.8.27(typescript@5.5.2) 1549 | debug: 4.3.5 1550 | kolorist: 1.8.0 1551 | magic-string: 0.30.10 1552 | typescript: 5.5.2 1553 | vite: 5.3.1(@types/node@20.14.9) 1554 | vue-tsc: 1.8.27(typescript@5.5.2) 1555 | transitivePeerDependencies: 1556 | - '@types/node' 1557 | - rollup 1558 | - supports-color 1559 | dev: true 1560 | 1561 | /vite@5.3.1(@types/node@20.14.9): 1562 | resolution: {integrity: sha512-XBmSKRLXLxiaPYamLv3/hnP/KXDai1NDexN0FpkTaZXTfycHvkRHoenpgl/fvuK/kPbB6xAgoyiryAhQNxYmAQ==} 1563 | engines: {node: ^18.0.0 || >=20.0.0} 1564 | hasBin: true 1565 | peerDependencies: 1566 | '@types/node': ^18.0.0 || >=20.0.0 1567 | less: '*' 1568 | lightningcss: ^1.21.0 1569 | sass: '*' 1570 | stylus: '*' 1571 | sugarss: '*' 1572 | terser: ^5.4.0 1573 | peerDependenciesMeta: 1574 | '@types/node': 1575 | optional: true 1576 | less: 1577 | optional: true 1578 | lightningcss: 1579 | optional: true 1580 | sass: 1581 | optional: true 1582 | stylus: 1583 | optional: true 1584 | sugarss: 1585 | optional: true 1586 | terser: 1587 | optional: true 1588 | dependencies: 1589 | '@types/node': 20.14.9 1590 | esbuild: 0.21.5 1591 | postcss: 8.4.38 1592 | rollup: 4.18.0 1593 | optionalDependencies: 1594 | fsevents: 2.3.3 1595 | dev: true 1596 | 1597 | /vscode-uri@3.0.8: 1598 | resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} 1599 | dev: true 1600 | 1601 | /vue-template-compiler@2.7.16: 1602 | resolution: {integrity: sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==} 1603 | dependencies: 1604 | de-indent: 1.0.2 1605 | he: 1.2.0 1606 | dev: true 1607 | 1608 | /vue-tsc@1.8.27(typescript@5.5.2): 1609 | resolution: {integrity: sha512-WesKCAZCRAbmmhuGl3+VrdWItEvfoFIPXOvUJkjULi+x+6G/Dy69yO3TBRJDr9eUlmsNAwVmxsNZxvHKzbkKdg==} 1610 | hasBin: true 1611 | peerDependencies: 1612 | typescript: '*' 1613 | dependencies: 1614 | '@volar/typescript': 1.11.1 1615 | '@vue/language-core': 1.8.27(typescript@5.5.2) 1616 | semver: 7.6.2 1617 | typescript: 5.5.2 1618 | dev: true 1619 | 1620 | /vue-tsc@2.0.22(typescript@5.5.2): 1621 | resolution: {integrity: sha512-lMBIwPBO0sxCcmvu45yt1b035AaQ8/XSXQDk8m75y4j0jSXY/y/XzfEtssQ9JMS47lDaR10O3/926oCs8OeGUw==} 1622 | hasBin: true 1623 | peerDependencies: 1624 | typescript: '*' 1625 | dependencies: 1626 | '@volar/typescript': 2.3.2 1627 | '@vue/language-core': 2.0.22(typescript@5.5.2) 1628 | semver: 7.6.2 1629 | typescript: 5.5.2 1630 | dev: true 1631 | 1632 | /vue@3.4.30(typescript@5.5.2): 1633 | resolution: {integrity: sha512-NcxtKCwkdf1zPsr7Y8+QlDBCGqxvjLXF2EX+yi76rV5rrz90Y6gK1cq0olIhdWGgrlhs9ElHuhi9t3+W5sG5Xw==} 1634 | peerDependencies: 1635 | typescript: '*' 1636 | peerDependenciesMeta: 1637 | typescript: 1638 | optional: true 1639 | dependencies: 1640 | '@vue/compiler-dom': 3.4.30 1641 | '@vue/compiler-sfc': 3.4.30 1642 | '@vue/runtime-dom': 3.4.30 1643 | '@vue/server-renderer': 3.4.30(vue@3.4.30) 1644 | '@vue/shared': 3.4.30 1645 | typescript: 5.5.2 1646 | 1647 | /which@2.0.2: 1648 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 1649 | engines: {node: '>= 8'} 1650 | hasBin: true 1651 | dependencies: 1652 | isexe: 2.0.0 1653 | dev: false 1654 | 1655 | /workerd@1.20240610.1: 1656 | resolution: {integrity: sha512-Rtut5GrsODQMh6YU43b9WZ980Wd05Ov1/ds88pT/SoetmXFBvkBzdRfiHiATv+azmGX8KveE0i/Eqzk/yI01ug==} 1657 | engines: {node: '>=16'} 1658 | hasBin: true 1659 | requiresBuild: true 1660 | optionalDependencies: 1661 | '@cloudflare/workerd-darwin-64': 1.20240610.1 1662 | '@cloudflare/workerd-darwin-arm64': 1.20240610.1 1663 | '@cloudflare/workerd-linux-64': 1.20240610.1 1664 | '@cloudflare/workerd-linux-arm64': 1.20240610.1 1665 | '@cloudflare/workerd-windows-64': 1.20240610.1 1666 | dev: false 1667 | 1668 | /wrap-ansi@7.0.0: 1669 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} 1670 | engines: {node: '>=10'} 1671 | dependencies: 1672 | ansi-styles: 4.3.0 1673 | string-width: 4.2.3 1674 | strip-ansi: 6.0.1 1675 | dev: true 1676 | 1677 | /ws@8.17.1: 1678 | resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} 1679 | engines: {node: '>=10.0.0'} 1680 | peerDependencies: 1681 | bufferutil: ^4.0.1 1682 | utf-8-validate: '>=5.0.2' 1683 | peerDependenciesMeta: 1684 | bufferutil: 1685 | optional: true 1686 | utf-8-validate: 1687 | optional: true 1688 | dev: false 1689 | 1690 | /y18n@5.0.8: 1691 | resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} 1692 | engines: {node: '>=10'} 1693 | dev: true 1694 | 1695 | /yallist@4.0.0: 1696 | resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} 1697 | dev: true 1698 | 1699 | /yargs-parser@21.1.1: 1700 | resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} 1701 | engines: {node: '>=12'} 1702 | dev: true 1703 | 1704 | /yargs@17.7.2: 1705 | resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} 1706 | engines: {node: '>=12'} 1707 | dependencies: 1708 | cliui: 8.0.1 1709 | escalade: 3.1.2 1710 | get-caller-file: 2.0.5 1711 | require-directory: 2.1.1 1712 | string-width: 4.2.3 1713 | y18n: 5.0.8 1714 | yargs-parser: 21.1.1 1715 | dev: true 1716 | 1717 | /yoga-wasm-web@0.3.3: 1718 | resolution: {integrity: sha512-N+d4UJSJbt/R3wqY7Coqs5pcV0aUj2j9IaQ3rNj9bVCLld8tTGKRa2USARjnvZJWVx1NDmQev8EknoczaOQDOA==} 1719 | dev: false 1720 | 1721 | /youch@3.3.3: 1722 | resolution: {integrity: sha512-qSFXUk3UZBLfggAW3dJKg0BMblG5biqSF8M34E06o5CSsZtH92u9Hqmj2RzGiHDi64fhe83+4tENFP2DB6t6ZA==} 1723 | dependencies: 1724 | cookie: 0.5.0 1725 | mustache: 4.2.0 1726 | stacktracey: 2.1.8 1727 | dev: false 1728 | 1729 | /z-schema@5.0.5: 1730 | resolution: {integrity: sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==} 1731 | engines: {node: '>=8.0.0'} 1732 | hasBin: true 1733 | dependencies: 1734 | lodash.get: 4.4.2 1735 | lodash.isequal: 4.5.0 1736 | validator: 13.12.0 1737 | optionalDependencies: 1738 | commander: 9.5.0 1739 | dev: true 1740 | 1741 | /zod@3.23.8: 1742 | resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} 1743 | dev: false 1744 | -------------------------------------------------------------------------------- /server/src/main.ts: -------------------------------------------------------------------------------- 1 | import type * as Party from "partykit/server" 2 | import RateLimiterMemory from "rate-limiter-flexible/lib/RateLimiterMemory.js" 3 | 4 | // Set the maximum message size to 128 KB 5 | const MAX_MESSAGE_SIZE = 1024 * 512 6 | 7 | // Rate limit the server to 20 requests/sec per client, as the average over 2 minute intervals 8 | const RATE_LIMITER_OPTS = { 9 | points: 1200, 10 | duration: 60, 11 | } 12 | 13 | export default class UsePartyRefServer implements Party.Server { 14 | options: Party.ServerOptions = { 15 | hibernate: true 16 | } 17 | private rateLimiter: RateLimiterMemory 18 | 19 | constructor(readonly room: Party.Room) { 20 | this.room = room 21 | this.rateLimiter = new RateLimiterMemory(RATE_LIMITER_OPTS) 22 | } 23 | 24 | /** 25 | * Handle writing and reading data to and from the storage 26 | * @param message 27 | * @param sender 28 | */ 29 | async onMessage(message: string, sender: Party.Connection) { 30 | this.rateLimiter.consume(sender.id, 1) 31 | .then(async () => { 32 | if (message.length > MAX_MESSAGE_SIZE) { 33 | sender.send(JSON.stringify({error: "Message too large"})) 34 | return 35 | } 36 | 37 | let messageData: { operation: string, key: string, data?: any } 38 | try { 39 | messageData = JSON.parse(message) 40 | } catch (error) { 41 | sender.send(JSON.stringify({error: "Invalid JSON"})) 42 | return 43 | } 44 | 45 | if (!this.isValidOperation(messageData)) { 46 | sender.send(JSON.stringify({error: "Invalid operation"})) 47 | return 48 | } 49 | 50 | const sanitizedKey = this.sanitizeKey(messageData.key) 51 | 52 | if (messageData.operation === "write") { 53 | await this.handleWrite(sanitizedKey, messageData.data, sender) 54 | } else if (messageData.operation === "read") { 55 | if ([...this.room.getConnections()].length === 1) { 56 | await this.handleWrite(sanitizedKey, messageData.data, sender) 57 | } else { 58 | await this.handleRead(sanitizedKey, messageData.data, sender) 59 | } 60 | } 61 | }) 62 | .catch((rateLimiterRes) => { 63 | sender.send(JSON.stringify({error: `Too many requests, please wait ${rateLimiterRes.msBeforeNext}ms`})) 64 | return 65 | }) 66 | } 67 | 68 | /** 69 | * Store a key-value pair in the storage and broadcast the change to all other connections 70 | * @param key 71 | * @param data 72 | * @param sender 73 | * @private 74 | */ 75 | private async handleWrite(key: string, data: any, sender: Party.Connection) { 76 | const localData = await this.room.storage.get(key) 77 | if ((JSON.stringify(localData) === JSON.stringify(data))) return 78 | await this.room.storage.put(key, data) 79 | this.room.broadcast(JSON.stringify({ 80 | key, 81 | data 82 | }), [sender.id]) 83 | } 84 | 85 | /** 86 | * Retrieve a key-value pair from the storage and send it back to the requesting client 87 | * @param key 88 | * @param clientData 89 | * @param sender 90 | * @private 91 | */ 92 | private async handleRead(key: string, clientData: any, sender: Party.Connection) { 93 | const remoteData = await this.room.storage.get(key) 94 | if (remoteData !== undefined && JSON.stringify(remoteData) !== JSON.stringify(clientData)) { 95 | sender.send(JSON.stringify({ 96 | key, 97 | data: remoteData 98 | })) 99 | } 100 | } 101 | 102 | /** 103 | * Check if the message is a valid operation (read or write) 104 | * @param data 105 | * @private 106 | */ 107 | private isValidOperation(data: any): boolean { 108 | return ( 109 | data && 110 | typeof data.operation === "string" && 111 | ["read", "write"].includes(data.operation) && 112 | typeof data.key === "string" && 113 | (data.operation === "read" || data.data !== undefined) 114 | ) 115 | } 116 | 117 | /** 118 | * Sanitize input keys 119 | * @param key 120 | * @private 121 | */ 122 | private sanitizeKey = (key: string) => key.replace(/[^\w.-]/g, '_').substr(0, 2047) 123 | } 124 | 125 | UsePartyRefServer satisfies Party.Worker 126 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { usePartyRef } from './usePartyRef' 2 | export type { PartyRef, PartyRefConfig } from './usePartyRef' 3 | -------------------------------------------------------------------------------- /src/usePartyRef.ts: -------------------------------------------------------------------------------- 1 | import {onBeforeMount, onUnmounted, ref, Ref, UnwrapRef, watch} from "vue" 2 | import PartySocket from "partysocket" 3 | 4 | export interface PartyRefConfig { 5 | 6 | // Creates a namespace to keep your data separate from other projects, such as "my-project". Try to make this as unique as possible to avoid conflicts with other projects. 7 | namespace: string, 8 | 9 | // The name of the variable, such as "count". 10 | key: string, 11 | 12 | // The initial value of the ref, if it's never been set before. 13 | defaultValue: T 14 | 15 | // Self-hosting? Where is the PK server? 16 | host?: string 17 | } 18 | 19 | export interface PartyRef extends Ref { 20 | 21 | /** 22 | * The status of the connection to the PK server. 23 | */ 24 | ready: Ref 25 | } 26 | 27 | function isDevelopment(): boolean { 28 | // Vite 29 | // @ts-ignore 30 | if (import.meta.env?.MODE === 'development') { 31 | return true; 32 | } 33 | // Node 34 | if (typeof process !== 'undefined' && process.env.NODE_ENV === 'development') { 35 | return true; 36 | } 37 | // Webpack 38 | if (process.env.NODE_ENV === 'development') { 39 | return true; 40 | } 41 | return false; 42 | } 43 | 44 | /** 45 | * A Vue 3 ref that syncs in real-time with other clients using PartyKit. 46 | * @docs https://github.com/marchantweb/usePartyRef 47 | */ 48 | export function usePartyRef(config: PartyRefConfig): PartyRef { 49 | 50 | let connection: PartySocket | null 51 | let localData: PartyRef> = ref(config.defaultValue) as PartyRef> 52 | localData.ready = ref(false) 53 | const lastReceivedData: Ref | Ref = ref(null) 54 | 55 | onBeforeMount(() => { 56 | 57 | // Initialize the connection 58 | connection = new PartySocket({ 59 | host: config.host ?? (isDevelopment() ? "localhost:1999" : "https://usepartyref.marchantweb.partykit.dev"), 60 | room: config.namespace 61 | }) 62 | 63 | // Request the current state from the server, or reset it if we're the first client 64 | connection.send(JSON.stringify({ 65 | operation: "read", 66 | key: config.key, 67 | data: config.defaultValue 68 | })) 69 | 70 | // When the connection opens, set the ready status to true 71 | connection.addEventListener("open", () => { 72 | localData.ready.value = true 73 | }) 74 | 75 | // Listen for incoming updates from other clients 76 | connection.addEventListener("message", (event) => { 77 | const {key, data, error} = JSON.parse(event.data) 78 | if (key !== config.key) return 79 | if (localData.value === data) return 80 | if (!error) { 81 | lastReceivedData.value = structuredClone(data) 82 | localData.value = structuredClone(data) 83 | return 84 | } 85 | console.error(error) 86 | }) 87 | 88 | // Watch for the connection to close 89 | connection.addEventListener("close", () => { 90 | localData.ready.value = false 91 | }) 92 | 93 | // Watch the local data for changes and send it to other clients 94 | watch(localData, (newValue) => { 95 | if (connection && (JSON.stringify(newValue) !== JSON.stringify(lastReceivedData.value))) { 96 | connection.send(JSON.stringify({ 97 | operation: "write", 98 | key: config.key, 99 | data: newValue 100 | })) 101 | } 102 | }, {deep: true}) 103 | }) 104 | 105 | onUnmounted(() => { 106 | if (connection) { 107 | connection.close() 108 | } 109 | }) 110 | 111 | return localData as PartyRef 112 | } 113 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 7 | "skipLibCheck": true, 8 | "moduleResolution": "bundler", 9 | "resolveJsonModule": true, 10 | "isolatedModules": true, 11 | "moduleDetection": "force", 12 | "jsx": "preserve", 13 | "strict": true, 14 | "noUnusedLocals": true, 15 | "noUnusedParameters": true, 16 | "noFallthroughCasesInSwitch": true, 17 | "esModuleInterop": true, 18 | "declaration": true, 19 | "declarationMap": true, 20 | "outDir": "./dist" 21 | }, 22 | "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.vue"], 23 | "exclude": ["node_modules", "dist", "playground"] 24 | } 25 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import {defineConfig} from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | import {resolve} from 'path' 4 | import dts from 'vite-plugin-dts' 5 | 6 | 7 | export default defineConfig(({command, mode}) => { 8 | const isLibrary = mode === 'library' 9 | 10 | return { 11 | plugins: [ 12 | vue(), 13 | isLibrary && dts({ 14 | entryRoot: 'src', 15 | outDir: 'dist', 16 | tsconfigPath: resolve(__dirname, 'tsconfig.json'), 17 | }), 18 | ], 19 | root: isLibrary ? undefined : 'playground', 20 | build: isLibrary ? { 21 | lib: { 22 | entry: resolve(__dirname, 'src/index.ts'), 23 | name: 'usePartyRef', 24 | fileName: 'index', 25 | formats: ['es'], 26 | }, 27 | rollupOptions: { 28 | external: ['vue'], 29 | }, 30 | } : undefined, 31 | resolve: { 32 | alias: { 33 | '@': resolve(__dirname, 'src'), 34 | }, 35 | }, 36 | } 37 | }) 38 | --------------------------------------------------------------------------------