├── .gitignore ├── LICENSE ├── README.md ├── babel.config.js ├── examples └── react │ ├── .gitignore │ ├── index.html │ ├── index.js │ ├── package.json │ └── yarn.lock ├── package.json ├── src ├── index.ts ├── store.ts ├── sync-queue.ts ├── transaction.ts ├── transactions-manager.ts └── types.ts ├── tsconfig.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .DS_Store 4 | .env 5 | yarn-error.log 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Webstudio 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | The core idea is to use [patches](https://immerjs.github.io/immer/patches) to keep the UI in sync between client and server, multiple clients, or multiple windows. 6 | 7 | It uses [Immer](https://immerjs.github.io/immer/) as an interface for state mutations and provides a convenient way to group mutations into a single transaction, and enables undo/redo out of the box. 8 | 9 | [Play with it on Codesandbox](https://codesandbox.io/s/github/webstudio-is/immerhin/tree/main/examples/react) 10 | 11 | [Read the article](https://dev.to/oleg008/synchronized-immutable-state-with-time-travel-2c6o) 12 | 13 | ## Features 14 | 15 | 1. Sync application state using [patches](https://immerjs.github.io/immer/patches) 16 | 1. Get undo/redo for free 17 | 1. Sync to the server 18 | 1. Server agnostic 19 | 1. State management libraries agnostic (a container interface) 20 | 1. Small bundle size 21 | 1. Sync between iframes (not implemented yet) 22 | 1. Sync between tabs (not implemented yet) 23 | 1. Resolve conflicts (not implemented yet) 24 | 1. Provide server handler (not implemented yet) 25 | 26 | ## Example 27 | 28 | ```js 29 | import store, { sync } from "immerhin"; 30 | 31 | // Create containers for each state. Sync engine only cares that the result has a "get()" and a "set(newValue)" 32 | const container1 = atom(initialValue); 33 | const container2 = atom(initialValue); 34 | 35 | // - Explicitely enable containers for transactions 36 | // - Define a namespace for each container, so that server knows which object it has to patch. 37 | store.register("container1", container1); 38 | store.register("container2", container2); 39 | 40 | // Creating the actual transaction that will: 41 | // - generate patches 42 | // - update states 43 | // - inform all subscribers 44 | // - register a transaction for potential undo/redo and sync calls 45 | store.createTransaction( 46 | [container1, container2, ...rest], 47 | (value1, value2, ...rest) => { 48 | mutateValue(value1); 49 | mutateValue(value2); 50 | // ... 51 | } 52 | ); 53 | 54 | // Setup periodic sync with a fetch, or do this with Websocket 55 | setInterval(async () => { 56 | const entries = sync(); 57 | await fetch("/patch", { method: "POST", payload: JSON.stringify(entries) }); 58 | }, 1000); 59 | 60 | // Undo/redo 61 | 62 | store.undo(); 63 | store.redo(); 64 | ``` 65 | 66 | ## How it works 67 | 68 | ### Containers 69 | 70 | A container is an interface that implements `.get()` and `.set(value)` methods so that a value can be updated and propagated to all consumers. 71 | 72 | You can use anything to create containers, it could be a Redux store, could be an observable, a [nano state](https://github.com/kof/react-nano-state) or [nanostores](https://github.com/nanostores/nanostores). 73 | 74 | You can use the same container instance to subscribe to the changes across the entire application. 75 | 76 | Example using nano state: 77 | 78 | ```js 79 | import { atom } from "nanostores"; 80 | import { useStore } from "@nanostores/react"; 81 | const myContainer = atom(initialValue); 82 | 83 | // I can call a set from anywhere 84 | myContainer.set(newValue); 85 | 86 | // I can subscribe to updates in React 87 | const Component = () => { 88 | const value = useStore(myContainer); 89 | }; 90 | ``` 91 | 92 | ### Container registration 93 | 94 | We register containers for two reasons: 95 | 96 | 1. To define a namespace for each container so that whoever consumes the changes knows which object to apply the patches to. 97 | 2. Ensure that the container was intentionally registered to be synced to the server and be part of undo/redo transactions. You may not want this for every container since you can use them for ephemeral states. 98 | 99 | Example 100 | 101 | ```js 102 | store.register("myName", myContainer); 103 | ``` 104 | 105 | ### Creating a transaction 106 | 107 | A transaction is a set of changes applied to a set of states. When you apply changes to the states inside a transaction, you are essentially telling the engine which changes are associated with the same user action so that undo/redo can use that as a single step to work with. 108 | 109 | A call into `store.createTransaction()`does all of this: 110 | 111 | - generate patches (using Immer) 112 | - update states and inform all subscribers (by calling `container.set(newValue)`) 113 | - register a transaction for potential undo/redo and calls 114 | 115 | Example 116 | 117 | ```js 118 | store.createTransaction( 119 | [container1, container2, ...rest], 120 | (value1, value2, ...rest) => { 121 | mutateValue(value1); 122 | mutateValue(value2); 123 | // ... 124 | } 125 | ); 126 | ``` 127 | 128 | ### Undo/redo 129 | 130 | Calling undo() and redo() functions will essentially apply the right patch for the value and dispatch the update. 131 | 132 | ### Sync 133 | 134 | The `sync(`) function returns you all changes queued up for a sync since the last call. 135 | With the return from `sync(),` you can do anything you want, for example, send it to your server. 136 | 137 | Example 138 | 139 | ```js 140 | // Setup periodic sync with a fetch, or do this with Websocket 141 | setInterval(async () => { 142 | const entries = sync(); 143 | await fetch("/patch", { method: "POST", payload: JSON.stringify(entries) }); 144 | }, 1000); 145 | ``` 146 | 147 | Example entries: 148 | 149 | ```json 150 | [ 151 | { 152 | "transactionId": "6243062b469f516835327f65", 153 | "changes": [ 154 | { 155 | "namespace": "root", 156 | "patches": [ 157 | { 158 | "op": "replace", 159 | "path": ["children", 1], 160 | "value": { 161 | "component": "Box", 162 | "id": "6241f55791596f2467df9c2a", 163 | "style": {}, 164 | "children": [] 165 | } 166 | }, 167 | { 168 | "op": "replace", 169 | "path": ["children", 2], 170 | "value": { 171 | "component": "Box", 172 | "id": "6241f55a91596f2467df9c36", 173 | "style": {}, 174 | "children": [] 175 | } 176 | }, 177 | { 178 | "op": "replace", 179 | "path": ["children", "length"], 180 | "value": 3 181 | } 182 | ] 183 | } 184 | ] 185 | } 186 | ] 187 | ``` 188 | 189 | ## Create a new store 190 | 191 | If you want to have multiple separate undoable states, create a separate store for each. They add to the same sync queue in the end. 192 | 193 | ```js 194 | import { Store } from "immerhin"; 195 | 196 | const store = new Store(); 197 | ``` 198 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ["@babel/preset-typescript"], 3 | }; 4 | -------------------------------------------------------------------------------- /examples/react/.gitignore: -------------------------------------------------------------------------------- 1 | .parcel-cache -------------------------------------------------------------------------------- /examples/react/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /examples/react/index.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from "react"; 2 | import { createRoot } from "react-dom/client"; 3 | import { atom } from 'nanostores'; 4 | import { useStore } from '@nanostores/react' 5 | import store, { sync } from "immerhin"; 6 | 7 | const itemsContainer = atom([]); 8 | 9 | store.register("items", itemsContainer); 10 | 11 | const List = () => { 12 | const items = useStore(itemsContainer); 13 | return ( 14 | 19 | ); 20 | }; 21 | 22 | const App = () => { 23 | return ( 24 | 25 |
{ 27 | event.preventDefault(); 28 | const data = new FormData(event.target); 29 | event.target.reset(); 30 | const value = data.get("item"); 31 | store.createTransaction([itemsContainer], (items) => { 32 | items.push({ value }); 33 | }); 34 | }} 35 | > 36 |

37 | Add items, then try redo/redo. 38 |
39 | Notice that the 2 lists are synced. 40 |

41 | 42 | 43 | 51 | 59 | 67 |
68 | 69 |
70 | 71 | 72 |
73 |
74 | ); 75 | }; 76 | 77 | createRoot(document.body.appendChild(document.createElement("div"))).render( 78 | 79 | ); 80 | -------------------------------------------------------------------------------- /examples/react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "immerhin-basic-example", 3 | "version": "0.1.0", 4 | "scripts": { 5 | "start": "yarn parcel index.html" 6 | }, 7 | "dependencies": { 8 | "@nanostores/react": "^0.4.1", 9 | "immerhin": "link:../../", 10 | "nanostores": "^0.7.1", 11 | "react": ">=16.8", 12 | "react-dom": ">=16.8" 13 | }, 14 | "main": "index.js", 15 | "alias": { 16 | "process": false 17 | }, 18 | "devDependencies": { 19 | "parcel": "^2.4.1", 20 | "process": "^0.11.10" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/react/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@babel/code-frame@^7.0.0": 6 | version "7.16.7" 7 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" 8 | integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== 9 | dependencies: 10 | "@babel/highlight" "^7.16.7" 11 | 12 | "@babel/helper-validator-identifier@^7.16.7": 13 | version "7.16.7" 14 | resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" 15 | integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== 16 | 17 | "@babel/highlight@^7.16.7": 18 | version "7.16.10" 19 | resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" 20 | integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== 21 | dependencies: 22 | "@babel/helper-validator-identifier" "^7.16.7" 23 | chalk "^2.0.0" 24 | js-tokens "^4.0.0" 25 | 26 | "@nanostores/react@^0.4.1": 27 | version "0.4.1" 28 | resolved "https://registry.yarnpkg.com/@nanostores/react/-/react-0.4.1.tgz#209c6726c0b42a1d21d9f7aa8f5276cdb0ad40d8" 29 | integrity sha512-lsv0CYrMxczbXtoV/mxFVEoL/uVjEjseoP89srO/5yNAOkJka+dSFS7LYyWEbuvCPO7EgbtkvRpO5V+OztKQOw== 30 | dependencies: 31 | use-sync-external-store "^1.2.0" 32 | 33 | "@parcel/bundler-default@2.4.1": 34 | version "2.4.1" 35 | resolved "https://registry.yarnpkg.com/@parcel/bundler-default/-/bundler-default-2.4.1.tgz#a158fe63d99e38865db8353132bd1b2ff62ab47a" 36 | integrity sha512-PTfBOuoiiYdfwyoPFeBTOinyl1RL4qaoyAQ0PCe01C1i4NcRWCY1w7zRvwJW/OhU3Ka+LtioGmfxu5/drdXzLg== 37 | dependencies: 38 | "@parcel/diagnostic" "2.4.1" 39 | "@parcel/hash" "2.4.1" 40 | "@parcel/plugin" "2.4.1" 41 | "@parcel/utils" "2.4.1" 42 | nullthrows "^1.1.1" 43 | 44 | "@parcel/cache@2.4.1": 45 | version "2.4.1" 46 | resolved "https://registry.yarnpkg.com/@parcel/cache/-/cache-2.4.1.tgz#94322d6de5b9ccb18d58585c267022f47a6315d3" 47 | integrity sha512-2N5ly++p/yefmPdK39X1QIoA2e6NtS1aYSsxrIC9EX92Kjd7SfSceqUJhlJWB49omJSheEJLd1qM3EJG9EvICQ== 48 | dependencies: 49 | "@parcel/fs" "2.4.1" 50 | "@parcel/logger" "2.4.1" 51 | "@parcel/utils" "2.4.1" 52 | lmdb "2.2.4" 53 | 54 | "@parcel/codeframe@2.4.1": 55 | version "2.4.1" 56 | resolved "https://registry.yarnpkg.com/@parcel/codeframe/-/codeframe-2.4.1.tgz#57dcedb0326ca120241d2f272b84019009350b20" 57 | integrity sha512-m3WDeEpWvgqekCqsHfPMJrSQquahdIgSR1x1RDCqQ1YelvW0fQiGgu42MXI5tjoBrHC1l1mF01UDb+xMSxz1DA== 58 | dependencies: 59 | chalk "^4.1.0" 60 | 61 | "@parcel/compressor-raw@2.4.1": 62 | version "2.4.1" 63 | resolved "https://registry.yarnpkg.com/@parcel/compressor-raw/-/compressor-raw-2.4.1.tgz#0bd2cb6fe02ae910e4e25f4db7b08ec1c1a52395" 64 | integrity sha512-cEOOOzIK7glxCqJX0OfBFBZE/iT7tmjEOXswRY3CnqY9FGoY3NYDAsOLm7A73RuIdNaZfYVxVUy3g7OLpbKL+g== 65 | dependencies: 66 | "@parcel/plugin" "2.4.1" 67 | 68 | "@parcel/config-default@2.4.1": 69 | version "2.4.1" 70 | resolved "https://registry.yarnpkg.com/@parcel/config-default/-/config-default-2.4.1.tgz#4b498b916dd9e47d49d4ad414a4139846a3e11bd" 71 | integrity sha512-yGA4Mx/KDzVOPm8IYb4Id+zlz1TaIM7s472pxA4tUV1qcEtBInY0aeO9R/GsLKC2+3QPHURZld9WI9EMXRUBBA== 72 | dependencies: 73 | "@parcel/bundler-default" "2.4.1" 74 | "@parcel/compressor-raw" "2.4.1" 75 | "@parcel/namer-default" "2.4.1" 76 | "@parcel/optimizer-css" "2.4.1" 77 | "@parcel/optimizer-htmlnano" "2.4.1" 78 | "@parcel/optimizer-image" "2.4.1" 79 | "@parcel/optimizer-svgo" "2.4.1" 80 | "@parcel/optimizer-terser" "2.4.1" 81 | "@parcel/packager-css" "2.4.1" 82 | "@parcel/packager-html" "2.4.1" 83 | "@parcel/packager-js" "2.4.1" 84 | "@parcel/packager-raw" "2.4.1" 85 | "@parcel/packager-svg" "2.4.1" 86 | "@parcel/reporter-dev-server" "2.4.1" 87 | "@parcel/resolver-default" "2.4.1" 88 | "@parcel/runtime-browser-hmr" "2.4.1" 89 | "@parcel/runtime-js" "2.4.1" 90 | "@parcel/runtime-react-refresh" "2.4.1" 91 | "@parcel/runtime-service-worker" "2.4.1" 92 | "@parcel/transformer-babel" "2.4.1" 93 | "@parcel/transformer-css" "2.4.1" 94 | "@parcel/transformer-html" "2.4.1" 95 | "@parcel/transformer-image" "2.4.1" 96 | "@parcel/transformer-js" "2.4.1" 97 | "@parcel/transformer-json" "2.4.1" 98 | "@parcel/transformer-postcss" "2.4.1" 99 | "@parcel/transformer-posthtml" "2.4.1" 100 | "@parcel/transformer-raw" "2.4.1" 101 | "@parcel/transformer-react-refresh-wrap" "2.4.1" 102 | "@parcel/transformer-svg" "2.4.1" 103 | 104 | "@parcel/core@2.4.1": 105 | version "2.4.1" 106 | resolved "https://registry.yarnpkg.com/@parcel/core/-/core-2.4.1.tgz#436b219769f273af299deb81f576be5b528c7e27" 107 | integrity sha512-h2FvqLA75ZQdIXX1y+ylGjIIi7YtbAUJyIapxaO081h3EsYG2jr9sRL4sym5ECgmvbyua/DEgtMLX3eGYn09FA== 108 | dependencies: 109 | "@parcel/cache" "2.4.1" 110 | "@parcel/diagnostic" "2.4.1" 111 | "@parcel/events" "2.4.1" 112 | "@parcel/fs" "2.4.1" 113 | "@parcel/graph" "2.4.1" 114 | "@parcel/hash" "2.4.1" 115 | "@parcel/logger" "2.4.1" 116 | "@parcel/package-manager" "2.4.1" 117 | "@parcel/plugin" "2.4.1" 118 | "@parcel/source-map" "^2.0.0" 119 | "@parcel/types" "2.4.1" 120 | "@parcel/utils" "2.4.1" 121 | "@parcel/workers" "2.4.1" 122 | abortcontroller-polyfill "^1.1.9" 123 | base-x "^3.0.8" 124 | browserslist "^4.6.6" 125 | clone "^2.1.1" 126 | dotenv "^7.0.0" 127 | dotenv-expand "^5.1.0" 128 | json-source-map "^0.6.1" 129 | json5 "^2.2.0" 130 | msgpackr "^1.5.4" 131 | nullthrows "^1.1.1" 132 | semver "^5.7.1" 133 | 134 | "@parcel/css-darwin-arm64@1.7.4": 135 | version "1.7.4" 136 | resolved "https://registry.yarnpkg.com/@parcel/css-darwin-arm64/-/css-darwin-arm64-1.7.4.tgz#9d173f8d9a3f6dec34e49999654ba091121f1f22" 137 | integrity sha512-fA+aBZAAgXSV7jUQFRYuKpJr5EEqNq++mFu4o/pU/lBFMJhL6Z11aqzrBecC1JziWT3t/BgryWdznf1QkNtM4w== 138 | 139 | "@parcel/css-darwin-x64@1.7.4": 140 | version "1.7.4" 141 | resolved "https://registry.yarnpkg.com/@parcel/css-darwin-x64/-/css-darwin-x64-1.7.4.tgz#e36f8a4c941c9059d6fc96e1f52c8022f04c32ef" 142 | integrity sha512-qx/+vEXSmed7eeBgVvV/1lrEjk8KnKUiAN+CCes8d6ddJJzK5evTKQsWkywe1jNdHC33d2mlLlhLFmC2+2IPOw== 143 | 144 | "@parcel/css-linux-arm-gnueabihf@1.7.4": 145 | version "1.7.4" 146 | resolved "https://registry.yarnpkg.com/@parcel/css-linux-arm-gnueabihf/-/css-linux-arm-gnueabihf-1.7.4.tgz#783407f8179164e6555c9498436bc0e8d1c6c4e3" 147 | integrity sha512-+Qf+j8dqJ+t7V/w9LnyWBzNcMG/GnlzjlWNQhiUkt1aYFYPr5i/eRWuWLYxVlz8EGQOUbYlinDGLXTUJDt31gA== 148 | 149 | "@parcel/css-linux-arm64-gnu@1.7.4": 150 | version "1.7.4" 151 | resolved "https://registry.yarnpkg.com/@parcel/css-linux-arm64-gnu/-/css-linux-arm64-gnu-1.7.4.tgz#34ed91540fe31001a835f7f5dfc86c90419fb2db" 152 | integrity sha512-ITP0HZT/Ay6JCgH3W7JpoRUYfciW+jBVBTjglZjYgyYPLLWk2J1kXB+qC3jHp5XCeH4feh7eFB1pyQcE7kqCjA== 153 | 154 | "@parcel/css-linux-arm64-musl@1.7.4": 155 | version "1.7.4" 156 | resolved "https://registry.yarnpkg.com/@parcel/css-linux-arm64-musl/-/css-linux-arm64-musl-1.7.4.tgz#3937fdadb0581e96b9f76a37713241b35a3250fa" 157 | integrity sha512-or61QRhhpsDlHfrc73KP4bPwnnVZWni1jkuRv1mCi+0SzYzoaO190JEaj7VWh/boUvjGiIl//FsLoZleQIWKNA== 158 | 159 | "@parcel/css-linux-x64-gnu@1.7.4": 160 | version "1.7.4" 161 | resolved "https://registry.yarnpkg.com/@parcel/css-linux-x64-gnu/-/css-linux-x64-gnu-1.7.4.tgz#ee883af8a97b99519c581cb2971c414e962a6ae1" 162 | integrity sha512-GHGsM06F26FAkvPcnsGw7NHxPVD7TQvg7OC7cVAYmETccO8mqs9DyRzBTevk+1kl7EQXNnHDojn7VpVN6q+phg== 163 | 164 | "@parcel/css-linux-x64-musl@1.7.4": 165 | version "1.7.4" 166 | resolved "https://registry.yarnpkg.com/@parcel/css-linux-x64-musl/-/css-linux-x64-musl-1.7.4.tgz#fd14e88683026665543bc48dee138edc553fcf75" 167 | integrity sha512-H/9wvQ7LNqng9yIwulpfUUhs6zm9+vLCzri2qnC4vm8geyTjA0W0H5fphV8IlzNJ/DfHmoesJ+TXw5NG+QC9hg== 168 | 169 | "@parcel/css-win32-x64-msvc@1.7.4": 170 | version "1.7.4" 171 | resolved "https://registry.yarnpkg.com/@parcel/css-win32-x64-msvc/-/css-win32-x64-msvc-1.7.4.tgz#ed6dfb63600610ba555124262d84fa537ee7e6a4" 172 | integrity sha512-xmg18iISCn1f9IyYUif6yR8FuEmi93qzH55oUiri5vZWuCY8xfraHsRA6i8yLWnxgDmVeHyiN0IICl7rgZo10A== 173 | 174 | "@parcel/css@^1.7.4": 175 | version "1.7.4" 176 | resolved "https://registry.yarnpkg.com/@parcel/css/-/css-1.7.4.tgz#87b522681a5527ad38baec4193a26a94fde37a5e" 177 | integrity sha512-K1N9mxEkWQQmSINMNuGvlyPq7yCY+AtHskGxWav97lhu2i8GMMXRV9kc8/x/jkZh5KDBWO5vHhdQiujRBrgR8g== 178 | dependencies: 179 | detect-libc "^1.0.3" 180 | optionalDependencies: 181 | "@parcel/css-darwin-arm64" "1.7.4" 182 | "@parcel/css-darwin-x64" "1.7.4" 183 | "@parcel/css-linux-arm-gnueabihf" "1.7.4" 184 | "@parcel/css-linux-arm64-gnu" "1.7.4" 185 | "@parcel/css-linux-arm64-musl" "1.7.4" 186 | "@parcel/css-linux-x64-gnu" "1.7.4" 187 | "@parcel/css-linux-x64-musl" "1.7.4" 188 | "@parcel/css-win32-x64-msvc" "1.7.4" 189 | 190 | "@parcel/diagnostic@2.4.1": 191 | version "2.4.1" 192 | resolved "https://registry.yarnpkg.com/@parcel/diagnostic/-/diagnostic-2.4.1.tgz#edb275699b543f71cf933bea141a3165ad919a0d" 193 | integrity sha512-wmJIfn0PG2ABuraS+kMjl6UKaLjTDTtG+XkjJLWHzU/dd5RozqAZDKp65GWjvHzHLx7KICTAdUJsXh2s3TnTOQ== 194 | dependencies: 195 | json-source-map "^0.6.1" 196 | nullthrows "^1.1.1" 197 | 198 | "@parcel/events@2.4.1": 199 | version "2.4.1" 200 | resolved "https://registry.yarnpkg.com/@parcel/events/-/events-2.4.1.tgz#6e1ba26d55f7a2d6a7491e0901d287de3e471e99" 201 | integrity sha512-er2jwyzYt3Zimkrp7TR865GIeIMYNd7YSSxW39y/egm4LIPBsruUpHSnKRD5b65Jd+gckkxDsnrpADG6MH1zNw== 202 | 203 | "@parcel/fs-search@2.4.1": 204 | version "2.4.1" 205 | resolved "https://registry.yarnpkg.com/@parcel/fs-search/-/fs-search-2.4.1.tgz#ae195107895f366183ed0a3fa34bd4eeeaf3dfef" 206 | integrity sha512-xfoLvHjHkZm4VZf3UWU5v6gzz+x7IBVY7siHGn0YyGwvlv73FmiR4mCSizqerXOyXknF2fpg6tNHNQyyNLS32Q== 207 | dependencies: 208 | detect-libc "^1.0.3" 209 | 210 | "@parcel/fs@2.4.1": 211 | version "2.4.1" 212 | resolved "https://registry.yarnpkg.com/@parcel/fs/-/fs-2.4.1.tgz#49e22a8f8018916a4922682e8e608256752c9692" 213 | integrity sha512-kE9HzW6XjO/ZA5bQnAzp1YVmGlXeDqUaius2cH2K0wU7KQX/GBjyfEWJm/UsKPB6QIrGXgkPH6ashNzOgwDqpw== 214 | dependencies: 215 | "@parcel/fs-search" "2.4.1" 216 | "@parcel/types" "2.4.1" 217 | "@parcel/utils" "2.4.1" 218 | "@parcel/watcher" "^2.0.0" 219 | "@parcel/workers" "2.4.1" 220 | 221 | "@parcel/graph@2.4.1": 222 | version "2.4.1" 223 | resolved "https://registry.yarnpkg.com/@parcel/graph/-/graph-2.4.1.tgz#33c8d370603e898d1ef6e99b4936b90c45d6d76c" 224 | integrity sha512-3JCnPI9BJdKpGIk6NtVN7ML3C/J9Ey+WfUfk8WisDxFP7vjYkXwZbNSR/HnxH+Y03wmB6cv4HI8A4kndF0H0pw== 225 | dependencies: 226 | "@parcel/utils" "2.4.1" 227 | nullthrows "^1.1.1" 228 | 229 | "@parcel/hash@2.4.1": 230 | version "2.4.1" 231 | resolved "https://registry.yarnpkg.com/@parcel/hash/-/hash-2.4.1.tgz#475ecec62b08dbd21dddb62d6dc5b9148a6e5fe5" 232 | integrity sha512-Ch1kkFPedef3geapU+XYmAdZY29u3eQXn/twMjowAKkWCmj6wZ+muUgBmOO2uCfK3xys7GycI8jYZcAbF5DVLg== 233 | dependencies: 234 | detect-libc "^1.0.3" 235 | xxhash-wasm "^0.4.2" 236 | 237 | "@parcel/logger@2.4.1": 238 | version "2.4.1" 239 | resolved "https://registry.yarnpkg.com/@parcel/logger/-/logger-2.4.1.tgz#8f87097009d6847409da69ecbc248a136b2f36c2" 240 | integrity sha512-wm7FoKY+1dyo+Dd7Z4b0d6hmpgRBWfZwCoZSSyhgbG96Ty68/oo3m7oEMXPfry8IVGIhShmWKDp4py44PH3l7w== 241 | dependencies: 242 | "@parcel/diagnostic" "2.4.1" 243 | "@parcel/events" "2.4.1" 244 | 245 | "@parcel/markdown-ansi@2.4.1": 246 | version "2.4.1" 247 | resolved "https://registry.yarnpkg.com/@parcel/markdown-ansi/-/markdown-ansi-2.4.1.tgz#65f798234e5767d92c5f411de5aae11e611cd9b6" 248 | integrity sha512-BkWhzbKQhTQ9lS96ZMMG0KyXSJBFdNeBVobWrdrrwcFlNER0nt2m6fdF7Hfpf1TqFhM4tT+GNFtON7ybL53RiQ== 249 | dependencies: 250 | chalk "^4.1.0" 251 | 252 | "@parcel/namer-default@2.4.1": 253 | version "2.4.1" 254 | resolved "https://registry.yarnpkg.com/@parcel/namer-default/-/namer-default-2.4.1.tgz#63442b2bf06ec555f825924435f450c9768bcc5a" 255 | integrity sha512-a/Xulfia7JJP6Cw/D6Wq5xX6IAKVKMRPEYtU2wB8vKuwC/et6kXi+0bFVeCLnTjDzVtsjDdyOEwfRC4yiEy3BA== 256 | dependencies: 257 | "@parcel/diagnostic" "2.4.1" 258 | "@parcel/plugin" "2.4.1" 259 | nullthrows "^1.1.1" 260 | 261 | "@parcel/node-resolver-core@2.4.1": 262 | version "2.4.1" 263 | resolved "https://registry.yarnpkg.com/@parcel/node-resolver-core/-/node-resolver-core-2.4.1.tgz#640fd087f610f030db7411bb2f61ae0e896d7cd1" 264 | integrity sha512-CvCADj3l4o5USqz/ZCaqbK8gdAQK63q94oSa0KnP6hrcDI/gDyf5Bk4+3cD4kSI+ByuN6aFLAYBS2nHBh5O/MQ== 265 | dependencies: 266 | "@parcel/diagnostic" "2.4.1" 267 | "@parcel/utils" "2.4.1" 268 | nullthrows "^1.1.1" 269 | 270 | "@parcel/optimizer-css@2.4.1": 271 | version "2.4.1" 272 | resolved "https://registry.yarnpkg.com/@parcel/optimizer-css/-/optimizer-css-2.4.1.tgz#67a6db736f3a2dce506cfefe40c12d25f23d530a" 273 | integrity sha512-+1CxZ43aoAUF8Hj2wLPK4d+TzdJlgYidXJ19Qwlh6XdQs8OeFGBAzIsUBFSr8+XCugXmnTkjYK94nX04Z2FhtQ== 274 | dependencies: 275 | "@parcel/css" "^1.7.4" 276 | "@parcel/diagnostic" "2.4.1" 277 | "@parcel/plugin" "2.4.1" 278 | "@parcel/source-map" "^2.0.0" 279 | "@parcel/utils" "2.4.1" 280 | browserslist "^4.6.6" 281 | nullthrows "^1.1.1" 282 | 283 | "@parcel/optimizer-htmlnano@2.4.1": 284 | version "2.4.1" 285 | resolved "https://registry.yarnpkg.com/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.4.1.tgz#18995b850fb1835a60c84378abff01b337f50cc7" 286 | integrity sha512-JkykHZcBS92iggT7GHuJJd+MDIc7BMAG0xxTJIY9KzzcxGNYsY8P3LedGVTL0/X8tkdlYQSGNLkTCntP0/62cw== 287 | dependencies: 288 | "@parcel/plugin" "2.4.1" 289 | htmlnano "^2.0.0" 290 | nullthrows "^1.1.1" 291 | posthtml "^0.16.5" 292 | svgo "^2.4.0" 293 | 294 | "@parcel/optimizer-image@2.4.1": 295 | version "2.4.1" 296 | resolved "https://registry.yarnpkg.com/@parcel/optimizer-image/-/optimizer-image-2.4.1.tgz#f3fd069290268c84e9a12bdda7dc5ded781c874e" 297 | integrity sha512-cv03Ta1FWuF75o9DJLuk1eYk1ULSdSbSkriQUAzc4InKW1bJH6gJasMZSTBsAg2Oz1TWqiDyiy5D/6i/UPoBJg== 298 | dependencies: 299 | "@parcel/diagnostic" "2.4.1" 300 | "@parcel/plugin" "2.4.1" 301 | "@parcel/utils" "2.4.1" 302 | "@parcel/workers" "2.4.1" 303 | detect-libc "^1.0.3" 304 | 305 | "@parcel/optimizer-svgo@2.4.1": 306 | version "2.4.1" 307 | resolved "https://registry.yarnpkg.com/@parcel/optimizer-svgo/-/optimizer-svgo-2.4.1.tgz#ff925aa40ca84a5dd816716662d22fb217b52288" 308 | integrity sha512-sOiofvHXjwJDu0NnTO8gGKDv0BztykVczfJdcedYmj207uU71JG1uODZvhyY4uiw1eRqmZnIXELZIftvYnZnDA== 309 | dependencies: 310 | "@parcel/diagnostic" "2.4.1" 311 | "@parcel/plugin" "2.4.1" 312 | "@parcel/utils" "2.4.1" 313 | svgo "^2.4.0" 314 | 315 | "@parcel/optimizer-terser@2.4.1": 316 | version "2.4.1" 317 | resolved "https://registry.yarnpkg.com/@parcel/optimizer-terser/-/optimizer-terser-2.4.1.tgz#999ae4551448540494f79861d4f68eb0cd0bfa48" 318 | integrity sha512-naRdp6gApWHUI1FCBZEJs9NzNngjZx8hRhIHeQtTxWpc2Mu8cVzxbVHNAwUj10nW3iOYmxyj4wleOArl8xpVCQ== 319 | dependencies: 320 | "@parcel/diagnostic" "2.4.1" 321 | "@parcel/plugin" "2.4.1" 322 | "@parcel/source-map" "^2.0.0" 323 | "@parcel/utils" "2.4.1" 324 | nullthrows "^1.1.1" 325 | terser "^5.2.0" 326 | 327 | "@parcel/package-manager@2.4.1": 328 | version "2.4.1" 329 | resolved "https://registry.yarnpkg.com/@parcel/package-manager/-/package-manager-2.4.1.tgz#fcd05b0d1999bef52496599043e0d5432abf57da" 330 | integrity sha512-JUUinm4U3hy4epHl9A389xb+BGiFR8n9+qw3Z4UDfS1te43sh8+0virBGcnai/G7mlr5/vHW+l9xulc7WQaY6w== 331 | dependencies: 332 | "@parcel/diagnostic" "2.4.1" 333 | "@parcel/fs" "2.4.1" 334 | "@parcel/logger" "2.4.1" 335 | "@parcel/types" "2.4.1" 336 | "@parcel/utils" "2.4.1" 337 | "@parcel/workers" "2.4.1" 338 | semver "^5.7.1" 339 | 340 | "@parcel/packager-css@2.4.1": 341 | version "2.4.1" 342 | resolved "https://registry.yarnpkg.com/@parcel/packager-css/-/packager-css-2.4.1.tgz#644d1b50426f08f08dd13beea6cd5b5a75d2d11b" 343 | integrity sha512-COx6RvHbpZ3DzuAgB/XvLLR/luxn9kYhqdFrnmIlYBh4B9atfXyr4rKDlWj1W/r2R72R6LHM35KhkwUATmrC/w== 344 | dependencies: 345 | "@parcel/plugin" "2.4.1" 346 | "@parcel/source-map" "^2.0.0" 347 | "@parcel/utils" "2.4.1" 348 | nullthrows "^1.1.1" 349 | 350 | "@parcel/packager-html@2.4.1": 351 | version "2.4.1" 352 | resolved "https://registry.yarnpkg.com/@parcel/packager-html/-/packager-html-2.4.1.tgz#6aa04c2650e4586fae0a5aa09913ee165d968cb9" 353 | integrity sha512-F5/PmWKoz8JhToufnp3u+NQ4LUoVkabzIJYHyQrM858XVmNbMInRfiTYxtgCBa2ARm2BTPhToh7N01OEyFCOhA== 354 | dependencies: 355 | "@parcel/plugin" "2.4.1" 356 | "@parcel/types" "2.4.1" 357 | "@parcel/utils" "2.4.1" 358 | nullthrows "^1.1.1" 359 | posthtml "^0.16.5" 360 | 361 | "@parcel/packager-js@2.4.1": 362 | version "2.4.1" 363 | resolved "https://registry.yarnpkg.com/@parcel/packager-js/-/packager-js-2.4.1.tgz#f544f9e48718a1187be7856a5e638dc231e1867e" 364 | integrity sha512-broWBUQisJLF5ThFtnl/asypuLMlMBwFPBTr8Ho9FYlL6W4wUzIymu7eOcuDljstmbD6luNVGMdCBYqt3IhHmw== 365 | dependencies: 366 | "@parcel/diagnostic" "2.4.1" 367 | "@parcel/hash" "2.4.1" 368 | "@parcel/plugin" "2.4.1" 369 | "@parcel/source-map" "^2.0.0" 370 | "@parcel/utils" "2.4.1" 371 | globals "^13.2.0" 372 | nullthrows "^1.1.1" 373 | 374 | "@parcel/packager-raw@2.4.1": 375 | version "2.4.1" 376 | resolved "https://registry.yarnpkg.com/@parcel/packager-raw/-/packager-raw-2.4.1.tgz#2566bd6187cf4e2393e5aad2b567d803248fdacb" 377 | integrity sha512-4lCY3TjiYaZyRIqshNF21i6XkQ5PJyr+ahhK4O2IymuYuD8/wGH2amTZqKPpGLuiF3j1HskRRUNv1ekpvExJ8w== 378 | dependencies: 379 | "@parcel/plugin" "2.4.1" 380 | 381 | "@parcel/packager-svg@2.4.1": 382 | version "2.4.1" 383 | resolved "https://registry.yarnpkg.com/@parcel/packager-svg/-/packager-svg-2.4.1.tgz#218c2b1e2efee648b4113ca72ed314a83ad38522" 384 | integrity sha512-V7GW/dgJPqXHReTzwpLcNEdyT5WWveYOW1MfxvKgOOK1ENk6oPgXL0FUdm5IHzqlK1bbwF5hzSQs2vaJMv7rPg== 385 | dependencies: 386 | "@parcel/plugin" "2.4.1" 387 | "@parcel/types" "2.4.1" 388 | "@parcel/utils" "2.4.1" 389 | posthtml "^0.16.4" 390 | 391 | "@parcel/plugin@2.4.1": 392 | version "2.4.1" 393 | resolved "https://registry.yarnpkg.com/@parcel/plugin/-/plugin-2.4.1.tgz#15294d796be2703b16fa4e617967cfaa8e5631d4" 394 | integrity sha512-EJzNhwNWYuSpIPRlG1U2hKcovq/RsVie4Os1z51/e2dcCto/uAoJOMoWYYsCxtjkJ7BjFYyQ7fcZRKM9DEr6gQ== 395 | dependencies: 396 | "@parcel/types" "2.4.1" 397 | 398 | "@parcel/reporter-cli@2.4.1": 399 | version "2.4.1" 400 | resolved "https://registry.yarnpkg.com/@parcel/reporter-cli/-/reporter-cli-2.4.1.tgz#011a84e4da9fdc5f65c7c44c31f7b24c8841ea8a" 401 | integrity sha512-99v/dSQ6wYmfpjmBxbsuBoxPWu9bm7PRxDDJxiVapbbym50bWYwVmMEHj6mYnK151YbMssV0garrSs1yYQEvqw== 402 | dependencies: 403 | "@parcel/plugin" "2.4.1" 404 | "@parcel/types" "2.4.1" 405 | "@parcel/utils" "2.4.1" 406 | chalk "^4.1.0" 407 | term-size "^2.2.1" 408 | 409 | "@parcel/reporter-dev-server@2.4.1": 410 | version "2.4.1" 411 | resolved "https://registry.yarnpkg.com/@parcel/reporter-dev-server/-/reporter-dev-server-2.4.1.tgz#dc29b399f0402ad6327fa1697ddc8bee74e7ff7d" 412 | integrity sha512-tRz1LHiudDhujBC3kJ3Qm0Wnbo3p3SpE6fjyCFRhdv2PJnEufNTTwzEUoa7lYZACwFVQUtrh6F7nMXFw6ynrsQ== 413 | dependencies: 414 | "@parcel/plugin" "2.4.1" 415 | "@parcel/utils" "2.4.1" 416 | 417 | "@parcel/resolver-default@2.4.1": 418 | version "2.4.1" 419 | resolved "https://registry.yarnpkg.com/@parcel/resolver-default/-/resolver-default-2.4.1.tgz#0ac851a42c9fb7521936339341f69730e6052495" 420 | integrity sha512-iJRt1+7lk0n7+wb+S/tVyiObbaiYP1YQGKRsTE8y4Kgp4/OPukdUHGFJwzbojWa0HnyoXm3zEgelVz7cHl47fQ== 421 | dependencies: 422 | "@parcel/node-resolver-core" "2.4.1" 423 | "@parcel/plugin" "2.4.1" 424 | 425 | "@parcel/runtime-browser-hmr@2.4.1": 426 | version "2.4.1" 427 | resolved "https://registry.yarnpkg.com/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.4.1.tgz#dcc0d5b41e5662aa694dc5ad937c00d088c80dca" 428 | integrity sha512-INsr78Kn0OuwMdXHCzw7v6l3Gf/UBTYtX7N7JNDOIBEFFkuZQiFWyAOI2P/DvMm8qeqcsrKliBO5Xty/a2Ivaw== 429 | dependencies: 430 | "@parcel/plugin" "2.4.1" 431 | "@parcel/utils" "2.4.1" 432 | 433 | "@parcel/runtime-js@2.4.1": 434 | version "2.4.1" 435 | resolved "https://registry.yarnpkg.com/@parcel/runtime-js/-/runtime-js-2.4.1.tgz#7322a434a49ce78a14dccfb945dfc24f009397df" 436 | integrity sha512-/EXwRpo+GPvWgN5yD0hjjt84Gm6QWp757dqOOzTG5R2rm1WU+g1a+zJJB1zXkxhu9lleQs44D1jEffzhh2Voyw== 437 | dependencies: 438 | "@parcel/plugin" "2.4.1" 439 | "@parcel/utils" "2.4.1" 440 | nullthrows "^1.1.1" 441 | 442 | "@parcel/runtime-react-refresh@2.4.1": 443 | version "2.4.1" 444 | resolved "https://registry.yarnpkg.com/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.4.1.tgz#86c9e2bbf4ce7a4bfed493da07716f8c3a24948d" 445 | integrity sha512-a4GBQ/fO7Mklh1M1G2JVpJBPbZD7YXUPAzh9Y4vpCf0ouTHBRMc8ew4CyKPJIrrTly5P42tFWnD3P4FVNKwHOQ== 446 | dependencies: 447 | "@parcel/plugin" "2.4.1" 448 | "@parcel/utils" "2.4.1" 449 | react-refresh "^0.9.0" 450 | 451 | "@parcel/runtime-service-worker@2.4.1": 452 | version "2.4.1" 453 | resolved "https://registry.yarnpkg.com/@parcel/runtime-service-worker/-/runtime-service-worker-2.4.1.tgz#928fb063273766ea52d8839758c212bbc657f1cb" 454 | integrity sha512-WtMKSiyQ0kF78rBw0XIx7n65mMb+6GBx+5m49r1aVZzeZEOSynpjJzJvqo7rxVmA7qTDkD2bko7BH41iScsEaw== 455 | dependencies: 456 | "@parcel/plugin" "2.4.1" 457 | "@parcel/utils" "2.4.1" 458 | nullthrows "^1.1.1" 459 | 460 | "@parcel/source-map@^2.0.0": 461 | version "2.0.2" 462 | resolved "https://registry.yarnpkg.com/@parcel/source-map/-/source-map-2.0.2.tgz#9aa0b00518cee31d5634de6e9c924a5539b142c1" 463 | integrity sha512-NnUrPYLpYB6qyx2v6bcRPn/gVigmGG6M6xL8wIg/i0dP1GLkuY1nf+Hqdf63FzPTqqT7K3k6eE5yHPQVMO5jcA== 464 | dependencies: 465 | detect-libc "^1.0.3" 466 | 467 | "@parcel/transformer-babel@2.4.1": 468 | version "2.4.1" 469 | resolved "https://registry.yarnpkg.com/@parcel/transformer-babel/-/transformer-babel-2.4.1.tgz#55e1a9587dd90adb4b3a16e600f625972a3a7a0f" 470 | integrity sha512-S+L14Fdr+S/+hqOi2nqnhuJvBbEJW24KyQeLmdaoMkt7DQLy5zENjGb9U2WYgB0Q96au0vX8NgB6jOnONecnpg== 471 | dependencies: 472 | "@parcel/diagnostic" "2.4.1" 473 | "@parcel/plugin" "2.4.1" 474 | "@parcel/source-map" "^2.0.0" 475 | "@parcel/utils" "2.4.1" 476 | browserslist "^4.6.6" 477 | json5 "^2.2.0" 478 | nullthrows "^1.1.1" 479 | semver "^5.7.0" 480 | 481 | "@parcel/transformer-css@2.4.1": 482 | version "2.4.1" 483 | resolved "https://registry.yarnpkg.com/@parcel/transformer-css/-/transformer-css-2.4.1.tgz#974cdf17ddf6a0a0a87c9f709d1c631b344e1820" 484 | integrity sha512-+6wCc0eEg4ez96Mucp/RjYKyRVN+7HPWPH7axalsQdp88t7wawWoqI2nd2mEw2PxpyuejIsk0ixLzYZ5opZivw== 485 | dependencies: 486 | "@parcel/css" "^1.7.4" 487 | "@parcel/diagnostic" "2.4.1" 488 | "@parcel/plugin" "2.4.1" 489 | "@parcel/source-map" "^2.0.0" 490 | "@parcel/utils" "2.4.1" 491 | browserslist "^4.6.6" 492 | nullthrows "^1.1.1" 493 | 494 | "@parcel/transformer-html@2.4.1": 495 | version "2.4.1" 496 | resolved "https://registry.yarnpkg.com/@parcel/transformer-html/-/transformer-html-2.4.1.tgz#f24ba5bc1d34c369e1d361e20e32fd194fc4aae0" 497 | integrity sha512-jyteTWuBA+f5wXn1RmAq3gOnB3yy41c748vARU9uNEXkLB4a7R106w4e5dlTG1DJfk+Tw1okSe1p2BeHoZntAw== 498 | dependencies: 499 | "@parcel/diagnostic" "2.4.1" 500 | "@parcel/hash" "2.4.1" 501 | "@parcel/plugin" "2.4.1" 502 | nullthrows "^1.1.1" 503 | posthtml "^0.16.5" 504 | posthtml-parser "^0.10.1" 505 | posthtml-render "^3.0.0" 506 | semver "^5.7.1" 507 | 508 | "@parcel/transformer-image@2.4.1": 509 | version "2.4.1" 510 | resolved "https://registry.yarnpkg.com/@parcel/transformer-image/-/transformer-image-2.4.1.tgz#5b3f97d8d41b08b29c47a0ca7cef6600520098ea" 511 | integrity sha512-pOfgPVe13lMTKdzydjXXNl4bojVMmuQmwm44OZ9cmpwOD3phkZzCtrxgySoV1eRBCOipdQg1O6GGI3za1KNdvw== 512 | dependencies: 513 | "@parcel/plugin" "2.4.1" 514 | "@parcel/workers" "2.4.1" 515 | nullthrows "^1.1.1" 516 | 517 | "@parcel/transformer-js@2.4.1": 518 | version "2.4.1" 519 | resolved "https://registry.yarnpkg.com/@parcel/transformer-js/-/transformer-js-2.4.1.tgz#824fc0cf86225a18eb3ac330a5096795ffb65374" 520 | integrity sha512-39Y9RUuDk5dc09Z3Pgj8snQd5E8926IqOowdTLKNJr7EcmkwHdinbpI4EqgKnisOwX4NSzxUti1I2DHsP1QZHw== 521 | dependencies: 522 | "@parcel/diagnostic" "2.4.1" 523 | "@parcel/plugin" "2.4.1" 524 | "@parcel/source-map" "^2.0.0" 525 | "@parcel/utils" "2.4.1" 526 | "@parcel/workers" "2.4.1" 527 | "@swc/helpers" "^0.3.6" 528 | browserslist "^4.6.6" 529 | detect-libc "^1.0.3" 530 | nullthrows "^1.1.1" 531 | regenerator-runtime "^0.13.7" 532 | semver "^5.7.1" 533 | 534 | "@parcel/transformer-json@2.4.1": 535 | version "2.4.1" 536 | resolved "https://registry.yarnpkg.com/@parcel/transformer-json/-/transformer-json-2.4.1.tgz#0585e539db5a81899a0409cfee63f509b81d6962" 537 | integrity sha512-bAwKyWb2/Wm6GS7OpQg1lWgcq+VDBXTKy5oFGX3edbpZFsrb59Ln1v+1jI888zRq4ehDBybhx8WTxPKTJnU+jA== 538 | dependencies: 539 | "@parcel/plugin" "2.4.1" 540 | json5 "^2.2.0" 541 | 542 | "@parcel/transformer-postcss@2.4.1": 543 | version "2.4.1" 544 | resolved "https://registry.yarnpkg.com/@parcel/transformer-postcss/-/transformer-postcss-2.4.1.tgz#5082c9733d4b8433c69466b1b532e23deaa36529" 545 | integrity sha512-I+jauarY5RlDUcd0zb9CC4GlpA7/+FqNSqCaGrM73aoszh6FNs4GiwD5tgy0pKOEASBZ0fBPmHEG1OBiVBXRGg== 546 | dependencies: 547 | "@parcel/diagnostic" "2.4.1" 548 | "@parcel/hash" "2.4.1" 549 | "@parcel/plugin" "2.4.1" 550 | "@parcel/utils" "2.4.1" 551 | clone "^2.1.1" 552 | nullthrows "^1.1.1" 553 | postcss-value-parser "^4.2.0" 554 | semver "^5.7.1" 555 | 556 | "@parcel/transformer-posthtml@2.4.1": 557 | version "2.4.1" 558 | resolved "https://registry.yarnpkg.com/@parcel/transformer-posthtml/-/transformer-posthtml-2.4.1.tgz#c5187fd92f38de1e8d05d17a6c849818eeaa2d7c" 559 | integrity sha512-DNtS41Sew940vnnqlFS0QK3ZbjQqCGT8JXkvwFojIrdH+3BW/n/9Hrtxj+X/bxrlwZlsRiqiRJ7crXp7TVhx2g== 560 | dependencies: 561 | "@parcel/plugin" "2.4.1" 562 | "@parcel/utils" "2.4.1" 563 | nullthrows "^1.1.1" 564 | posthtml "^0.16.5" 565 | posthtml-parser "^0.10.1" 566 | posthtml-render "^3.0.0" 567 | semver "^5.7.1" 568 | 569 | "@parcel/transformer-raw@2.4.1": 570 | version "2.4.1" 571 | resolved "https://registry.yarnpkg.com/@parcel/transformer-raw/-/transformer-raw-2.4.1.tgz#5e1842fbd661b6058294a7ba984a34b6896c3e65" 572 | integrity sha512-0PzdWJSGSTQ522aohymHEnq4GABy0mHSs+LkPZyMfNmX9ZAIyy6XuFJ9dz8nUmP4Nhn8qDvbRjoAYXR3XsGDGQ== 573 | dependencies: 574 | "@parcel/plugin" "2.4.1" 575 | 576 | "@parcel/transformer-react-refresh-wrap@2.4.1": 577 | version "2.4.1" 578 | resolved "https://registry.yarnpkg.com/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.4.1.tgz#14f9194f30e417b46fc325f78ee4035254670f64" 579 | integrity sha512-zF6pzj/BwSiD1jA/BHDCEJnKSIDekjblU+OWp1WpSjA1uYkJORuZ5knLcq6mXOQ8M2NCbOXosc1ru8071i8sYA== 580 | dependencies: 581 | "@parcel/plugin" "2.4.1" 582 | "@parcel/utils" "2.4.1" 583 | react-refresh "^0.9.0" 584 | 585 | "@parcel/transformer-svg@2.4.1": 586 | version "2.4.1" 587 | resolved "https://registry.yarnpkg.com/@parcel/transformer-svg/-/transformer-svg-2.4.1.tgz#30381670312f4a512e714b47abd4c501e1d2401f" 588 | integrity sha512-E0XdXsZOnP7g9zvJskfvXeIHx9pKjPHtLKo/txmpjW1eXOmsFcRMVy6l4pFh+kBciAgiZOI6o1pVHt+Uf7ia/g== 589 | dependencies: 590 | "@parcel/diagnostic" "2.4.1" 591 | "@parcel/hash" "2.4.1" 592 | "@parcel/plugin" "2.4.1" 593 | nullthrows "^1.1.1" 594 | posthtml "^0.16.5" 595 | posthtml-parser "^0.10.1" 596 | posthtml-render "^3.0.0" 597 | semver "^5.7.1" 598 | 599 | "@parcel/types@2.4.1": 600 | version "2.4.1" 601 | resolved "https://registry.yarnpkg.com/@parcel/types/-/types-2.4.1.tgz#4cd7b99db403ec36a1fe9f31a6320b2f6148f580" 602 | integrity sha512-YqkiyGS8oiD89Z2lJP7sbjn0F0wlSJMAuqgqf7obeKj0zmZJS7n2xK0uUEuIlUO+Cbqgl0kCGsUSjuT8xcEqjg== 603 | dependencies: 604 | "@parcel/cache" "2.4.1" 605 | "@parcel/diagnostic" "2.4.1" 606 | "@parcel/fs" "2.4.1" 607 | "@parcel/package-manager" "2.4.1" 608 | "@parcel/source-map" "^2.0.0" 609 | "@parcel/workers" "2.4.1" 610 | utility-types "^3.10.0" 611 | 612 | "@parcel/utils@2.4.1": 613 | version "2.4.1" 614 | resolved "https://registry.yarnpkg.com/@parcel/utils/-/utils-2.4.1.tgz#1d8e30fc0fb61a52c3445235f0ed2e0130a29797" 615 | integrity sha512-hmbrnPtFAfMT6s9FMMIVlIzCwEFX/+byB67GoJmSCAMRmj6RMu4a6xKlv2FdzkTKJV2ucg8vxAcua0MQ/q8rkQ== 616 | dependencies: 617 | "@parcel/codeframe" "2.4.1" 618 | "@parcel/diagnostic" "2.4.1" 619 | "@parcel/hash" "2.4.1" 620 | "@parcel/logger" "2.4.1" 621 | "@parcel/markdown-ansi" "2.4.1" 622 | "@parcel/source-map" "^2.0.0" 623 | chalk "^4.1.0" 624 | 625 | "@parcel/watcher@^2.0.0": 626 | version "2.0.5" 627 | resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.0.5.tgz#f913a54e1601b0aac972803829b0eece48de215b" 628 | integrity sha512-x0hUbjv891omnkcHD7ZOhiyyUqUUR6MNjq89JhEI3BxppeKWAm6NPQsqqRrAkCJBogdT/o/My21sXtTI9rJIsw== 629 | dependencies: 630 | node-addon-api "^3.2.1" 631 | node-gyp-build "^4.3.0" 632 | 633 | "@parcel/workers@2.4.1": 634 | version "2.4.1" 635 | resolved "https://registry.yarnpkg.com/@parcel/workers/-/workers-2.4.1.tgz#27bc3ac703625bc1694873fee07fdbeaf555d987" 636 | integrity sha512-EYujbJOblFqIt2NGQ+baIYTuavJqbhy84IfZ3j0jmACeKO5Ew1EHXZyl9LJgWHKaIPZsnvnbxw2mDOF05K65xQ== 637 | dependencies: 638 | "@parcel/diagnostic" "2.4.1" 639 | "@parcel/logger" "2.4.1" 640 | "@parcel/types" "2.4.1" 641 | "@parcel/utils" "2.4.1" 642 | chrome-trace-event "^1.0.2" 643 | nullthrows "^1.1.1" 644 | 645 | "@swc/helpers@^0.3.6": 646 | version "0.3.8" 647 | resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.3.8.tgz#5b9ecf4ee480ca00f1ffbc2d1a5d4eed0d1afe81" 648 | integrity sha512-aWItSZvJj4+GI6FWkjZR13xPNPctq2RRakzo+O6vN7bC2yjwdg5EFpgaSAUn95b7BGSgcflvzVDPoKmJv24IOg== 649 | 650 | "@trysound/sax@0.2.0": 651 | version "0.2.0" 652 | resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" 653 | integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== 654 | 655 | "@types/parse-json@^4.0.0": 656 | version "4.0.0" 657 | resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" 658 | integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== 659 | 660 | abortcontroller-polyfill@^1.1.9: 661 | version "1.7.3" 662 | resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.3.tgz#1b5b487bd6436b5b764fd52a612509702c3144b5" 663 | integrity sha512-zetDJxd89y3X99Kvo4qFx8GKlt6GsvN3UcRZHwU6iFA/0KiOmhkTVhe8oRoTBiTVPZu09x3vCra47+w8Yz1+2Q== 664 | 665 | acorn@^8.5.0: 666 | version "8.7.0" 667 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" 668 | integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== 669 | 670 | ansi-styles@^3.2.1: 671 | version "3.2.1" 672 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 673 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 674 | dependencies: 675 | color-convert "^1.9.0" 676 | 677 | ansi-styles@^4.1.0: 678 | version "4.3.0" 679 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" 680 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== 681 | dependencies: 682 | color-convert "^2.0.1" 683 | 684 | base-x@^3.0.8: 685 | version "3.0.9" 686 | resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" 687 | integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== 688 | dependencies: 689 | safe-buffer "^5.0.1" 690 | 691 | boolbase@^1.0.0: 692 | version "1.0.0" 693 | resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" 694 | integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= 695 | 696 | browserslist@^4.6.6: 697 | version "4.20.2" 698 | resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.2.tgz#567b41508757ecd904dab4d1c646c612cd3d4f88" 699 | integrity sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA== 700 | dependencies: 701 | caniuse-lite "^1.0.30001317" 702 | electron-to-chromium "^1.4.84" 703 | escalade "^3.1.1" 704 | node-releases "^2.0.2" 705 | picocolors "^1.0.0" 706 | 707 | bson-objectid@^2.0.3: 708 | version "2.0.3" 709 | resolved "https://registry.yarnpkg.com/bson-objectid/-/bson-objectid-2.0.3.tgz#d840185172846b2f10c42ce2bcdb4a50956a9db5" 710 | integrity sha512-WYwVtY9yqk179EPMNuF3vcxufdrGLEo2XwqdRVbfLVe9X6jLt7WKZQgP+ObOcprakBGbHxzl76tgTaieqsH29g== 711 | 712 | buffer-from@^1.0.0: 713 | version "1.1.2" 714 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" 715 | integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== 716 | 717 | callsites@^3.0.0: 718 | version "3.1.0" 719 | resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" 720 | integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== 721 | 722 | caniuse-lite@^1.0.30001317: 723 | version "1.0.30001325" 724 | resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001325.tgz#2b4ad19b77aa36f61f2eaf72e636d7481d55e606" 725 | integrity sha512-sB1bZHjseSjDtijV1Hb7PB2Zd58Kyx+n/9EotvZ4Qcz2K3d0lWB8dB4nb8wN/TsOGFq3UuAm0zQZNQ4SoR7TrQ== 726 | 727 | chalk@^2.0.0: 728 | version "2.4.2" 729 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 730 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 731 | dependencies: 732 | ansi-styles "^3.2.1" 733 | escape-string-regexp "^1.0.5" 734 | supports-color "^5.3.0" 735 | 736 | chalk@^4.1.0: 737 | version "4.1.2" 738 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" 739 | integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== 740 | dependencies: 741 | ansi-styles "^4.1.0" 742 | supports-color "^7.1.0" 743 | 744 | chrome-trace-event@^1.0.2: 745 | version "1.0.3" 746 | resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" 747 | integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== 748 | 749 | clone@^2.1.1: 750 | version "2.1.2" 751 | resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" 752 | integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= 753 | 754 | color-convert@^1.9.0: 755 | version "1.9.3" 756 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 757 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 758 | dependencies: 759 | color-name "1.1.3" 760 | 761 | color-convert@^2.0.1: 762 | version "2.0.1" 763 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 764 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 765 | dependencies: 766 | color-name "~1.1.4" 767 | 768 | color-name@1.1.3: 769 | version "1.1.3" 770 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 771 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= 772 | 773 | color-name@~1.1.4: 774 | version "1.1.4" 775 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" 776 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 777 | 778 | commander@^2.20.0: 779 | version "2.20.3" 780 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" 781 | integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== 782 | 783 | commander@^7.0.0, commander@^7.2.0: 784 | version "7.2.0" 785 | resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" 786 | integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== 787 | 788 | cosmiconfig@^7.0.1: 789 | version "7.0.1" 790 | resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" 791 | integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== 792 | dependencies: 793 | "@types/parse-json" "^4.0.0" 794 | import-fresh "^3.2.1" 795 | parse-json "^5.0.0" 796 | path-type "^4.0.0" 797 | yaml "^1.10.0" 798 | 799 | css-select@^4.1.3: 800 | version "4.3.0" 801 | resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b" 802 | integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ== 803 | dependencies: 804 | boolbase "^1.0.0" 805 | css-what "^6.0.1" 806 | domhandler "^4.3.1" 807 | domutils "^2.8.0" 808 | nth-check "^2.0.1" 809 | 810 | css-tree@^1.1.2, css-tree@^1.1.3: 811 | version "1.1.3" 812 | resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" 813 | integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== 814 | dependencies: 815 | mdn-data "2.0.14" 816 | source-map "^0.6.1" 817 | 818 | css-what@^6.0.1: 819 | version "6.1.0" 820 | resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" 821 | integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== 822 | 823 | csso@^4.2.0: 824 | version "4.2.0" 825 | resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" 826 | integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA== 827 | dependencies: 828 | css-tree "^1.1.2" 829 | 830 | detect-libc@^1.0.3: 831 | version "1.0.3" 832 | resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" 833 | integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= 834 | 835 | dom-serializer@^1.0.1: 836 | version "1.3.2" 837 | resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91" 838 | integrity sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig== 839 | dependencies: 840 | domelementtype "^2.0.1" 841 | domhandler "^4.2.0" 842 | entities "^2.0.0" 843 | 844 | domelementtype@^2.0.1, domelementtype@^2.2.0: 845 | version "2.2.0" 846 | resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" 847 | integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== 848 | 849 | domhandler@^4.2.0, domhandler@^4.2.2, domhandler@^4.3.1: 850 | version "4.3.1" 851 | resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c" 852 | integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ== 853 | dependencies: 854 | domelementtype "^2.2.0" 855 | 856 | domutils@^2.8.0: 857 | version "2.8.0" 858 | resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" 859 | integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== 860 | dependencies: 861 | dom-serializer "^1.0.1" 862 | domelementtype "^2.2.0" 863 | domhandler "^4.2.0" 864 | 865 | dotenv-expand@^5.1.0: 866 | version "5.1.0" 867 | resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0" 868 | integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA== 869 | 870 | dotenv@^7.0.0: 871 | version "7.0.0" 872 | resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-7.0.0.tgz#a2be3cd52736673206e8a85fb5210eea29628e7c" 873 | integrity sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g== 874 | 875 | electron-to-chromium@^1.4.84: 876 | version "1.4.103" 877 | resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.103.tgz#abfe376a4d70fa1e1b4b353b95df5d6dfd05da3a" 878 | integrity sha512-c/uKWR1Z/W30Wy/sx3dkZoj4BijbXX85QKWu9jJfjho3LBAXNEGAEW3oWiGb+dotA6C6BzCTxL2/aLes7jlUeg== 879 | 880 | entities@^2.0.0: 881 | version "2.2.0" 882 | resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" 883 | integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== 884 | 885 | entities@^3.0.1: 886 | version "3.0.1" 887 | resolved "https://registry.yarnpkg.com/entities/-/entities-3.0.1.tgz#2b887ca62585e96db3903482d336c1006c3001d4" 888 | integrity sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q== 889 | 890 | error-ex@^1.3.1: 891 | version "1.3.2" 892 | resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" 893 | integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== 894 | dependencies: 895 | is-arrayish "^0.2.1" 896 | 897 | escalade@^3.1.1: 898 | version "3.1.1" 899 | resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" 900 | integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== 901 | 902 | escape-string-regexp@^1.0.5: 903 | version "1.0.5" 904 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 905 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= 906 | 907 | get-port@^4.2.0: 908 | version "4.2.0" 909 | resolved "https://registry.yarnpkg.com/get-port/-/get-port-4.2.0.tgz#e37368b1e863b7629c43c5a323625f95cf24b119" 910 | integrity sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw== 911 | 912 | globals@^13.2.0: 913 | version "13.13.0" 914 | resolved "https://registry.yarnpkg.com/globals/-/globals-13.13.0.tgz#ac32261060d8070e2719dd6998406e27d2b5727b" 915 | integrity sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A== 916 | dependencies: 917 | type-fest "^0.20.2" 918 | 919 | has-flag@^3.0.0: 920 | version "3.0.0" 921 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 922 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= 923 | 924 | has-flag@^4.0.0: 925 | version "4.0.0" 926 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 927 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 928 | 929 | htmlnano@^2.0.0: 930 | version "2.0.0" 931 | resolved "https://registry.yarnpkg.com/htmlnano/-/htmlnano-2.0.0.tgz#07376faa064f7e1e832dfd91e1a9f606b0bc9b78" 932 | integrity sha512-thKQfhcp2xgtsWNE27A2bliEeqVL5xjAgGn0wajyttvFFsvFWWah1ntV9aEX61gz0T6MBQ5xK/1lXuEumhJTcg== 933 | dependencies: 934 | cosmiconfig "^7.0.1" 935 | posthtml "^0.16.5" 936 | timsort "^0.3.0" 937 | 938 | htmlparser2@^7.1.1: 939 | version "7.2.0" 940 | resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-7.2.0.tgz#8817cdea38bbc324392a90b1990908e81a65f5a5" 941 | integrity sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog== 942 | dependencies: 943 | domelementtype "^2.0.1" 944 | domhandler "^4.2.2" 945 | domutils "^2.8.0" 946 | entities "^3.0.1" 947 | 948 | immer@^9.0.12: 949 | version "9.0.12" 950 | resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.12.tgz#2d33ddf3ee1d247deab9d707ca472c8c942a0f20" 951 | integrity sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA== 952 | 953 | "immerhin@link:../..": 954 | version "0.0.0" 955 | uid "" 956 | 957 | import-fresh@^3.2.1: 958 | version "3.3.0" 959 | resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" 960 | integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== 961 | dependencies: 962 | parent-module "^1.0.0" 963 | resolve-from "^4.0.0" 964 | 965 | is-arrayish@^0.2.1: 966 | version "0.2.1" 967 | resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" 968 | integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= 969 | 970 | is-json@^2.0.1: 971 | version "2.0.1" 972 | resolved "https://registry.yarnpkg.com/is-json/-/is-json-2.0.1.tgz#6be166d144828a131d686891b983df62c39491ff" 973 | integrity sha1-a+Fm0USCihMdaGiRuYPfYsOUkf8= 974 | 975 | "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: 976 | version "4.0.0" 977 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 978 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== 979 | 980 | json-parse-even-better-errors@^2.3.0: 981 | version "2.3.1" 982 | resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" 983 | integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== 984 | 985 | json-source-map@^0.6.1: 986 | version "0.6.1" 987 | resolved "https://registry.yarnpkg.com/json-source-map/-/json-source-map-0.6.1.tgz#e0b1f6f4ce13a9ad57e2ae165a24d06e62c79a0f" 988 | integrity sha512-1QoztHPsMQqhDq0hlXY5ZqcEdUzxQEIxgFkKl4WUp2pgShObl+9ovi4kRh2TfvAfxAoHOJ9vIMEqk3k4iex7tg== 989 | 990 | json5@^2.2.0: 991 | version "2.2.1" 992 | resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" 993 | integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== 994 | 995 | lines-and-columns@^1.1.6: 996 | version "1.2.4" 997 | resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" 998 | integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== 999 | 1000 | lmdb@2.2.4: 1001 | version "2.2.4" 1002 | resolved "https://registry.yarnpkg.com/lmdb/-/lmdb-2.2.4.tgz#6494d5a1d1db152e0be759edcfa06893e4cbdb53" 1003 | integrity sha512-gto+BB2uEob8qRiTlOq+R3uX0YNHsX9mjxj9Sbdue/LIKqu6IlZjrsjKeGyOMquc/474GEqFyX2pdytpydp0rQ== 1004 | dependencies: 1005 | msgpackr "^1.5.4" 1006 | nan "^2.14.2" 1007 | node-gyp-build "^4.2.3" 1008 | ordered-binary "^1.2.4" 1009 | weak-lru-cache "^1.2.2" 1010 | 1011 | loose-envify@^1.1.0: 1012 | version "1.4.0" 1013 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" 1014 | integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== 1015 | dependencies: 1016 | js-tokens "^3.0.0 || ^4.0.0" 1017 | 1018 | mdn-data@2.0.14: 1019 | version "2.0.14" 1020 | resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" 1021 | integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== 1022 | 1023 | msgpackr-extract@^1.0.14: 1024 | version "1.0.16" 1025 | resolved "https://registry.yarnpkg.com/msgpackr-extract/-/msgpackr-extract-1.0.16.tgz#701c4f6e6f25c100ae84557092274e8fffeefe45" 1026 | integrity sha512-fxdRfQUxPrL/TizyfYfMn09dK58e+d65bRD/fcaVH4052vj30QOzzqxcQIS7B0NsqlypEQ/6Du3QmP2DhWFfCA== 1027 | dependencies: 1028 | nan "^2.14.2" 1029 | node-gyp-build "^4.2.3" 1030 | 1031 | msgpackr@^1.5.4: 1032 | version "1.5.5" 1033 | resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.5.5.tgz#c0562abc2951d7e29f75d77a8656b01f103a042c" 1034 | integrity sha512-JG0V47xRIQ9pyUnx6Hb4+3TrQoia2nA3UIdmyTldhxaxtKFkekkKpUW/N6fwHwod9o4BGuJGtouxOk+yCP5PEA== 1035 | optionalDependencies: 1036 | msgpackr-extract "^1.0.14" 1037 | 1038 | nan@^2.14.2: 1039 | version "2.15.0" 1040 | resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" 1041 | integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== 1042 | 1043 | nanostores@^0.7.1: 1044 | version "0.7.1" 1045 | resolved "https://registry.yarnpkg.com/nanostores/-/nanostores-0.7.1.tgz#ed27fa3f9b1c2ab9b28f14373811e28b9d3fc5eb" 1046 | integrity sha512-7HenoVpZOjRudHCmAVWKloBTk3+Ozw49KuRWq/pNlEIIVS3x9dID+I5z3Rhjxl1muhHwv4dFhpT+0FebT9jvaA== 1047 | 1048 | node-addon-api@^3.2.1: 1049 | version "3.2.1" 1050 | resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" 1051 | integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== 1052 | 1053 | node-gyp-build@^4.2.3, node-gyp-build@^4.3.0: 1054 | version "4.4.0" 1055 | resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.4.0.tgz#42e99687ce87ddeaf3a10b99dc06abc11021f3f4" 1056 | integrity sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ== 1057 | 1058 | node-releases@^2.0.2: 1059 | version "2.0.2" 1060 | resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.2.tgz#7139fe71e2f4f11b47d4d2986aaf8c48699e0c01" 1061 | integrity sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg== 1062 | 1063 | nth-check@^2.0.1: 1064 | version "2.0.1" 1065 | resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.1.tgz#2efe162f5c3da06a28959fbd3db75dbeea9f0fc2" 1066 | integrity sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w== 1067 | dependencies: 1068 | boolbase "^1.0.0" 1069 | 1070 | nullthrows@^1.1.1: 1071 | version "1.1.1" 1072 | resolved "https://registry.yarnpkg.com/nullthrows/-/nullthrows-1.1.1.tgz#7818258843856ae971eae4208ad7d7eb19a431b1" 1073 | integrity sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw== 1074 | 1075 | ordered-binary@^1.2.4: 1076 | version "1.2.4" 1077 | resolved "https://registry.yarnpkg.com/ordered-binary/-/ordered-binary-1.2.4.tgz#51d3a03af078a0bdba6c7bc8f4fedd1f5d45d83e" 1078 | integrity sha512-A/csN0d3n+igxBPfUrjbV5GC69LWj2pjZzAAeeHXLukQ4+fytfP4T1Lg0ju7MSPSwq7KtHkGaiwO8URZN5IpLg== 1079 | 1080 | parcel@^2.4.1: 1081 | version "2.4.1" 1082 | resolved "https://registry.yarnpkg.com/parcel/-/parcel-2.4.1.tgz#e369d0c1a3f383df244eb546d0613d1df51f6b35" 1083 | integrity sha512-H8n7cJ0rOt0AZZLuPuG6hvujUWiWz8kxx4pkqEDm31dijrbKb0pNgccXOllQ34em6r7elv6yH7lxox8jDCp0hw== 1084 | dependencies: 1085 | "@parcel/config-default" "2.4.1" 1086 | "@parcel/core" "2.4.1" 1087 | "@parcel/diagnostic" "2.4.1" 1088 | "@parcel/events" "2.4.1" 1089 | "@parcel/fs" "2.4.1" 1090 | "@parcel/logger" "2.4.1" 1091 | "@parcel/package-manager" "2.4.1" 1092 | "@parcel/reporter-cli" "2.4.1" 1093 | "@parcel/reporter-dev-server" "2.4.1" 1094 | "@parcel/utils" "2.4.1" 1095 | chalk "^4.1.0" 1096 | commander "^7.0.0" 1097 | get-port "^4.2.0" 1098 | v8-compile-cache "^2.0.0" 1099 | 1100 | parent-module@^1.0.0: 1101 | version "1.0.1" 1102 | resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" 1103 | integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== 1104 | dependencies: 1105 | callsites "^3.0.0" 1106 | 1107 | parse-json@^5.0.0: 1108 | version "5.2.0" 1109 | resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" 1110 | integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== 1111 | dependencies: 1112 | "@babel/code-frame" "^7.0.0" 1113 | error-ex "^1.3.1" 1114 | json-parse-even-better-errors "^2.3.0" 1115 | lines-and-columns "^1.1.6" 1116 | 1117 | path-type@^4.0.0: 1118 | version "4.0.0" 1119 | resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" 1120 | integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== 1121 | 1122 | picocolors@^1.0.0: 1123 | version "1.0.0" 1124 | resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" 1125 | integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== 1126 | 1127 | postcss-value-parser@^4.2.0: 1128 | version "4.2.0" 1129 | resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" 1130 | integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== 1131 | 1132 | posthtml-parser@^0.10.1: 1133 | version "0.10.2" 1134 | resolved "https://registry.yarnpkg.com/posthtml-parser/-/posthtml-parser-0.10.2.tgz#df364d7b179f2a6bf0466b56be7b98fd4e97c573" 1135 | integrity sha512-PId6zZ/2lyJi9LiKfe+i2xv57oEjJgWbsHGGANwos5AvdQp98i6AtamAl8gzSVFGfQ43Glb5D614cvZf012VKg== 1136 | dependencies: 1137 | htmlparser2 "^7.1.1" 1138 | 1139 | posthtml-parser@^0.11.0: 1140 | version "0.11.0" 1141 | resolved "https://registry.yarnpkg.com/posthtml-parser/-/posthtml-parser-0.11.0.tgz#25d1c7bf811ea83559bc4c21c189a29747a24b7a" 1142 | integrity sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw== 1143 | dependencies: 1144 | htmlparser2 "^7.1.1" 1145 | 1146 | posthtml-render@^3.0.0: 1147 | version "3.0.0" 1148 | resolved "https://registry.yarnpkg.com/posthtml-render/-/posthtml-render-3.0.0.tgz#97be44931496f495b4f07b99e903cc70ad6a3205" 1149 | integrity sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA== 1150 | dependencies: 1151 | is-json "^2.0.1" 1152 | 1153 | posthtml@^0.16.4, posthtml@^0.16.5: 1154 | version "0.16.6" 1155 | resolved "https://registry.yarnpkg.com/posthtml/-/posthtml-0.16.6.tgz#e2fc407f67a64d2fa3567afe770409ffdadafe59" 1156 | integrity sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ== 1157 | dependencies: 1158 | posthtml-parser "^0.11.0" 1159 | posthtml-render "^3.0.0" 1160 | 1161 | process@^0.11.10: 1162 | version "0.11.10" 1163 | resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" 1164 | integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= 1165 | 1166 | react-dom@>=16.8: 1167 | version "18.0.0" 1168 | resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.0.0.tgz#26b88534f8f1dbb80853e1eabe752f24100d8023" 1169 | integrity sha512-XqX7uzmFo0pUceWFCt7Gff6IyIMzFUn7QMZrbrQfGxtaxXZIcGQzoNpRLE3fQLnS4XzLLPMZX2T9TRcSrasicw== 1170 | dependencies: 1171 | loose-envify "^1.1.0" 1172 | scheduler "^0.21.0" 1173 | 1174 | react-refresh@^0.9.0: 1175 | version "0.9.0" 1176 | resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.9.0.tgz#71863337adc3e5c2f8a6bfddd12ae3bfe32aafbf" 1177 | integrity sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ== 1178 | 1179 | react@>=16.8: 1180 | version "18.0.0" 1181 | resolved "https://registry.yarnpkg.com/react/-/react-18.0.0.tgz#b468736d1f4a5891f38585ba8e8fb29f91c3cb96" 1182 | integrity sha512-x+VL6wbT4JRVPm7EGxXhZ8w8LTROaxPXOqhlGyVSrv0sB1jkyFGgXxJ8LVoPRLvPR6/CIZGFmfzqUa2NYeMr2A== 1183 | dependencies: 1184 | loose-envify "^1.1.0" 1185 | 1186 | regenerator-runtime@^0.13.7: 1187 | version "0.13.9" 1188 | resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" 1189 | integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== 1190 | 1191 | resolve-from@^4.0.0: 1192 | version "4.0.0" 1193 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" 1194 | integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== 1195 | 1196 | safe-buffer@^5.0.1: 1197 | version "5.2.1" 1198 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" 1199 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== 1200 | 1201 | scheduler@^0.21.0: 1202 | version "0.21.0" 1203 | resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.21.0.tgz#6fd2532ff5a6d877b6edb12f00d8ab7e8f308820" 1204 | integrity sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ== 1205 | dependencies: 1206 | loose-envify "^1.1.0" 1207 | 1208 | semver@^5.7.0, semver@^5.7.1: 1209 | version "5.7.1" 1210 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" 1211 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== 1212 | 1213 | source-map-support@~0.5.20: 1214 | version "0.5.21" 1215 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" 1216 | integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== 1217 | dependencies: 1218 | buffer-from "^1.0.0" 1219 | source-map "^0.6.0" 1220 | 1221 | source-map@^0.6.0, source-map@^0.6.1: 1222 | version "0.6.1" 1223 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" 1224 | integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== 1225 | 1226 | source-map@~0.7.2: 1227 | version "0.7.3" 1228 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" 1229 | integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== 1230 | 1231 | stable@^0.1.8: 1232 | version "0.1.8" 1233 | resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" 1234 | integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== 1235 | 1236 | supports-color@^5.3.0: 1237 | version "5.5.0" 1238 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 1239 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 1240 | dependencies: 1241 | has-flag "^3.0.0" 1242 | 1243 | supports-color@^7.1.0: 1244 | version "7.2.0" 1245 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" 1246 | integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== 1247 | dependencies: 1248 | has-flag "^4.0.0" 1249 | 1250 | svgo@^2.4.0: 1251 | version "2.8.0" 1252 | resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24" 1253 | integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg== 1254 | dependencies: 1255 | "@trysound/sax" "0.2.0" 1256 | commander "^7.2.0" 1257 | css-select "^4.1.3" 1258 | css-tree "^1.1.3" 1259 | csso "^4.2.0" 1260 | picocolors "^1.0.0" 1261 | stable "^0.1.8" 1262 | 1263 | term-size@^2.2.1: 1264 | version "2.2.1" 1265 | resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" 1266 | integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg== 1267 | 1268 | terser@^5.2.0: 1269 | version "5.12.1" 1270 | resolved "https://registry.yarnpkg.com/terser/-/terser-5.12.1.tgz#4cf2ebed1f5bceef5c83b9f60104ac4a78b49e9c" 1271 | integrity sha512-NXbs+7nisos5E+yXwAD+y7zrcTkMqb0dEJxIGtSKPdCBzopf7ni4odPul2aechpV7EXNvOudYOX2bb5tln1jbQ== 1272 | dependencies: 1273 | acorn "^8.5.0" 1274 | commander "^2.20.0" 1275 | source-map "~0.7.2" 1276 | source-map-support "~0.5.20" 1277 | 1278 | timsort@^0.3.0: 1279 | version "0.3.0" 1280 | resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" 1281 | integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= 1282 | 1283 | type-fest@^0.20.2: 1284 | version "0.20.2" 1285 | resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" 1286 | integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== 1287 | 1288 | use-sync-external-store@^1.2.0: 1289 | version "1.2.0" 1290 | resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" 1291 | integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== 1292 | 1293 | utility-types@^3.10.0: 1294 | version "3.10.0" 1295 | resolved "https://registry.yarnpkg.com/utility-types/-/utility-types-3.10.0.tgz#ea4148f9a741015f05ed74fd615e1d20e6bed82b" 1296 | integrity sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg== 1297 | 1298 | v8-compile-cache@^2.0.0: 1299 | version "2.3.0" 1300 | resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" 1301 | integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== 1302 | 1303 | weak-lru-cache@^1.2.2: 1304 | version "1.2.2" 1305 | resolved "https://registry.yarnpkg.com/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz#fdbb6741f36bae9540d12f480ce8254060dccd19" 1306 | integrity sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw== 1307 | 1308 | xxhash-wasm@^0.4.2: 1309 | version "0.4.2" 1310 | resolved "https://registry.yarnpkg.com/xxhash-wasm/-/xxhash-wasm-0.4.2.tgz#752398c131a4dd407b5132ba62ad372029be6f79" 1311 | integrity sha512-/eyHVRJQCirEkSZ1agRSCwriMhwlyUcFkXD5TPVSLP+IPzjsqMVzZwdoczLp1SoQU0R3dxz1RpIK+4YNQbCVOA== 1312 | 1313 | yaml@^1.10.0: 1314 | version "1.10.2" 1315 | resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" 1316 | integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== 1317 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "packageManager": "yarn@1.22.19", 3 | "name": "immerhin", 4 | "version": "0.10.0", 5 | "description": "Send patches around to keep the system in sync.", 6 | "type": "module", 7 | "exports": { 8 | "import": "./dist/immerhin.js", 9 | "types": "./dist/index.d.ts" 10 | }, 11 | "scripts": { 12 | "build:types": "tsc --declaration --emitDeclarationOnly --outDir dist", 13 | "build:js": "esbuild src/index.ts --bundle --format=esm --external:immer --external:nanoid --outfile=dist/immerhin.js", 14 | "build": "rm -rf dist && yarn build:js && yarn build:types", 15 | "typecheck": "tsc --noEmit", 16 | "prepublishOnly": "yarn build" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+ssh://git@github.com/webstudio-is/immerhin.git" 21 | }, 22 | "keywords": [ 23 | "Immer", 24 | "JSON", 25 | "Patch", 26 | "State", 27 | "management", 28 | "undo-redo" 29 | ], 30 | "author": "Oleg Isonen", 31 | "license": "MIT", 32 | "bugs": { 33 | "url": "https://github.com/webstudio-is/immerhin/issues" 34 | }, 35 | "homepage": "https://github.com/webstudio-is/immerhin#readme", 36 | "devDependencies": { 37 | "esbuild": "^0.18.15", 38 | "prettier": "^3.3.3", 39 | "typescript": "^5.1.6" 40 | }, 41 | "dependencies": { 42 | "immer": "^10.0.2", 43 | "nanoid": "^5.0.1" 44 | }, 45 | "files": [ 46 | "dist", 47 | "README.md" 48 | ] 49 | } 50 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { Store } from "./store"; 2 | export type { Change } from "./transaction"; 3 | export type { SyncItem } from "./sync-queue"; 4 | -------------------------------------------------------------------------------- /src/store.ts: -------------------------------------------------------------------------------- 1 | import { createDraft, finishDraft, enablePatches, type Patch } from "immer"; 2 | import { type ValueContainer } from "./types"; 3 | import { type Change, Transaction } from "./transaction"; 4 | import { 5 | type TransactionCallback, 6 | TransactionsManager, 7 | } from "./transactions-manager"; 8 | import { type Queue, enqueue, popAll } from "./sync-queue"; 9 | 10 | enablePatches(); 11 | 12 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 13 | type Any = any; 14 | 15 | type UnwrapContainers>> = { 16 | [Index in keyof Containers]: Containers[Index] extends ValueContainer< 17 | infer Value 18 | > 19 | ? Value 20 | : never; 21 | }; 22 | 23 | export class Store { 24 | namespaces = new Map, string>(); 25 | containers = new Map>(); 26 | 27 | transactionManager: TransactionsManager; 28 | 29 | private callbacks: TransactionCallback[] = []; 30 | 31 | private transactionQueue: Parameters[] = []; 32 | private syncQueue: Queue = []; 33 | 34 | constructor() { 35 | this.transactionManager = new TransactionsManager( 36 | (transactionId, changes, source) => { 37 | // store transactions until at least one subscription is added 38 | if (this.callbacks.length === 0) { 39 | this.transactionQueue.push([transactionId, changes, source]); 40 | } 41 | enqueue(this.syncQueue, transactionId, changes); 42 | for (const callback of this.callbacks) { 43 | callback(transactionId, changes, source); 44 | } 45 | }, 46 | ); 47 | } 48 | 49 | register(namespace: string, container: ValueContainer) { 50 | this.namespaces.set(container, namespace); 51 | this.containers.set(namespace, container); 52 | } 53 | 54 | createTransaction>>( 55 | containers: [...Containers], 56 | recipe: (...values: UnwrapContainers) => void, 57 | source?: string, 58 | ): UnwrapContainers { 59 | type Values = UnwrapContainers; 60 | const drafts = [] as unknown as Values; 61 | for (const container of containers) { 62 | drafts.push(createDraft(container.get())); 63 | } 64 | recipe(...drafts); 65 | const transaction = new Transaction(); 66 | const values = [] as unknown as Values; 67 | drafts.forEach((draft, index) => { 68 | const namespace = this.namespaces.get(containers[index]); 69 | if (namespace === undefined) { 70 | throw new Error( 71 | "Container used for transaction is not registered in sync engine", 72 | ); 73 | } 74 | const value = finishDraft( 75 | draft, 76 | (patches: Array, revisePatches: Array) => { 77 | // ignore empty changes 78 | if (patches.length === 0) { 79 | return; 80 | } 81 | transaction.add({ 82 | namespace, 83 | patches, 84 | revisePatches, 85 | container: containers[index], 86 | }); 87 | }, 88 | ); 89 | values.push(value); 90 | }); 91 | this.transactionManager.add(transaction, source); 92 | return values; 93 | } 94 | 95 | createTransactionFromChanges(changes: Array, source?: string) { 96 | const transaction = new Transaction(); 97 | for (const change of changes) { 98 | const container = this.containers.get(change.namespace); 99 | if (container) { 100 | transaction.add({ 101 | ...change, 102 | container, 103 | }); 104 | } 105 | } 106 | this.transactionManager.add(transaction, source); 107 | } 108 | 109 | addTransaction( 110 | transactionId: string, 111 | changes: Array, 112 | source?: string, 113 | ) { 114 | const transaction = new Transaction(transactionId); 115 | for (const change of changes) { 116 | const container = this.containers.get(change.namespace); 117 | if (container) { 118 | transaction.add({ 119 | ...change, 120 | container, 121 | }); 122 | } 123 | } 124 | this.transactionManager.add(transaction, source); 125 | } 126 | 127 | revertTransaction(transactionId: string) { 128 | this.transactionManager.revert(transactionId); 129 | } 130 | 131 | subscribe(callback: TransactionCallback) { 132 | // flush transactions from queue 133 | if (this.callbacks.length === 0) { 134 | for (const [transactionId, changes, source] of this.transactionQueue) { 135 | callback(transactionId, changes, source); 136 | } 137 | this.transactionQueue = []; 138 | } 139 | this.callbacks.push(callback); 140 | return () => { 141 | this.callbacks = this.callbacks.filter((item) => callback !== item); 142 | }; 143 | } 144 | 145 | undo() { 146 | this.transactionManager.undo(); 147 | } 148 | 149 | redo() { 150 | this.transactionManager.redo(); 151 | } 152 | 153 | popAll() { 154 | return popAll(this.syncQueue); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/sync-queue.ts: -------------------------------------------------------------------------------- 1 | import type { Change } from "./transaction"; 2 | 3 | export type SyncItem = { 4 | transactionId: string; 5 | changes: Array; 6 | }; 7 | 8 | export type Queue = SyncItem[] 9 | 10 | 11 | const dequeue = (queue: Queue, transactionId: string) => { 12 | const index = queue.findIndex( 13 | (entry) => entry.transactionId === transactionId 14 | ); 15 | if (index === -1) return false; 16 | queue.splice(index, 1); 17 | return true; 18 | }; 19 | 20 | export const enqueue = (queue: Queue, transactionId: string, changes: Array) => { 21 | // We are trying to delete that transaction from the queue, 22 | // if it was not found - we are adding the patches, because they are new 23 | // if it was found - we don't add it because it is technically an undo operation. 24 | // This can happen if user runs undo before sync happened, so we we are avoiding 25 | // sending it to the server unnecessarily. 26 | if (dequeue(queue, transactionId) === false) { 27 | queue.push({ transactionId, changes }); 28 | } 29 | }; 30 | 31 | export const popAll = (queue: Queue) => { 32 | if (queue.length === 0) return []; 33 | const queueCopy = [...queue]; 34 | queue.splice(0); 35 | return queueCopy; 36 | }; 37 | -------------------------------------------------------------------------------- /src/transaction.ts: -------------------------------------------------------------------------------- 1 | import { nanoid } from "nanoid"; 2 | import { applyPatches, type Patch } from "immer"; 3 | import { type ValueContainer } from "./types"; 4 | 5 | export type Change = { 6 | namespace: string; 7 | patches: Array; 8 | revisePatches: Array; 9 | }; 10 | 11 | type TransactionSpec = { 12 | namespace: string; 13 | patches: Array; 14 | revisePatches: Array; 15 | container: ValueContainer>; 16 | }; 17 | 18 | export class Transaction { 19 | id: string; 20 | specs: Array = []; 21 | constructor(id = nanoid()) { 22 | this.id = id; 23 | } 24 | applyPatches() { 25 | for (const change of this.specs) { 26 | const value = applyPatches(change.container.get(), change.patches); 27 | change.container.set(value); 28 | } 29 | } 30 | applyRevisePatches() { 31 | for (const change of this.specs) { 32 | const value = applyPatches(change.container.get(), change.revisePatches); 33 | change.container.set(value); 34 | } 35 | } 36 | add(change: TransactionSpec) { 37 | this.specs.push(change); 38 | } 39 | getChanges(): Array { 40 | return this.specs.map(({ namespace, patches, revisePatches }) => ({ 41 | namespace, 42 | patches, 43 | revisePatches, 44 | })); 45 | } 46 | getReviseChanges(): Array { 47 | return this.specs.map(({ namespace, patches, revisePatches }) => ({ 48 | namespace, 49 | patches: revisePatches, 50 | revisePatches: patches, 51 | })); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/transactions-manager.ts: -------------------------------------------------------------------------------- 1 | import type { Change, Transaction } from "./transaction"; 2 | 3 | export type TransactionCallback = ( 4 | transactionId: string, 5 | changes: Array, 6 | source?: string, 7 | ) => void; 8 | 9 | export class TransactionsManager { 10 | max = 100; 11 | currentStack: Array = []; 12 | undoneStack: Array = []; 13 | 14 | constructor(private callback: TransactionCallback) { } 15 | 16 | undo() { 17 | const transaction = this.currentStack.pop(); 18 | if (transaction === undefined) return; 19 | transaction.applyRevisePatches(); 20 | this.callback(transaction.id, transaction.getReviseChanges()); 21 | this.undoneStack.push(transaction); 22 | } 23 | 24 | redo() { 25 | const transaction = this.undoneStack.pop(); 26 | if (transaction === undefined) return; 27 | transaction.applyPatches(); 28 | this.currentStack.push(transaction); 29 | this.callback(transaction.id, transaction.getChanges()); 30 | } 31 | 32 | add(transaction: Transaction, source?: string) { 33 | // ignore empty transactions 34 | if (transaction.specs.length === 0) { 35 | return; 36 | } 37 | transaction.applyPatches(); 38 | this.currentStack.push(transaction); 39 | this.callback(transaction.id, transaction.getChanges(), source); 40 | if (this.currentStack.length > this.max) { 41 | this.currentStack.shift(); 42 | } 43 | // After we add a change, we can't redo something we have undone before. 44 | // It would make undo unpredictable, because there are new changes. 45 | this.undoneStack.splice(0); 46 | } 47 | 48 | revert(transactionId: string) { 49 | const transactionIndex = this.currentStack.findIndex( 50 | (transaction) => transaction.id === transactionId, 51 | ); 52 | const transaction = this.currentStack[transactionIndex]; 53 | transaction.applyRevisePatches(); 54 | this.currentStack.splice(transactionIndex, 1); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | export type ValueContainer = { 2 | get(): ValueType; 3 | set(value: ValueType): void; 4 | }; 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "moduleResolution": "bundler", 5 | "isolatedModules": true 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@esbuild/android-arm64@0.18.15": 6 | version "0.18.15" 7 | resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.15.tgz#abbe87b815d2f95ec749ffb4eba65d7d5343411f" 8 | integrity sha512-NI/gnWcMl2kXt1HJKOn2H69SYn4YNheKo6NZt1hyfKWdMbaGadxjZIkcj4Gjk/WPxnbFXs9/3HjGHaknCqjrww== 9 | 10 | "@esbuild/android-arm@0.18.15": 11 | version "0.18.15" 12 | resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.15.tgz#6afedd79c68d5d4d1e434e20a9ab620bb5849372" 13 | integrity sha512-wlkQBWb79/jeEEoRmrxt/yhn5T1lU236OCNpnfRzaCJHZ/5gf82uYx1qmADTBWE0AR/v7FiozE1auk2riyQd3w== 14 | 15 | "@esbuild/android-x64@0.18.15": 16 | version "0.18.15" 17 | resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.15.tgz#cdd886a58748b1584ad72d960c446fa958c11ab3" 18 | integrity sha512-FM9NQamSaEm/IZIhegF76aiLnng1kEsZl2eve/emxDeReVfRuRNmvT28l6hoFD9TsCxpK+i4v8LPpEj74T7yjA== 19 | 20 | "@esbuild/darwin-arm64@0.18.15": 21 | version "0.18.15" 22 | resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.15.tgz#648b124a6a63022adb5b0cf441e264e8f5ba4af2" 23 | integrity sha512-XmrFwEOYauKte9QjS6hz60FpOCnw4zaPAb7XV7O4lx1r39XjJhTN7ZpXqJh4sN6q60zbP6QwAVVA8N/wUyBH/w== 24 | 25 | "@esbuild/darwin-x64@0.18.15": 26 | version "0.18.15" 27 | resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.15.tgz#91cd2601c1604d123454d325e6b24fb6438350cf" 28 | integrity sha512-bMqBmpw1e//7Fh5GLetSZaeo9zSC4/CMtrVFdj+bqKPGJuKyfNJ5Nf2m3LknKZTS+Q4oyPiON+v3eaJ59sLB5A== 29 | 30 | "@esbuild/freebsd-arm64@0.18.15": 31 | version "0.18.15" 32 | resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.15.tgz#575940b0fc2f52833de4f6360445586742a8ff8b" 33 | integrity sha512-LoTK5N3bOmNI9zVLCeTgnk5Rk0WdUTrr9dyDAQGVMrNTh9EAPuNwSTCgaKOKiDpverOa0htPcO9NwslSE5xuLA== 34 | 35 | "@esbuild/freebsd-x64@0.18.15": 36 | version "0.18.15" 37 | resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.15.tgz#09694fc601dd8d3263a1075977ee7d3488514ef8" 38 | integrity sha512-62jX5n30VzgrjAjOk5orYeHFq6sqjvsIj1QesXvn5OZtdt5Gdj0vUNJy9NIpjfdNdqr76jjtzBJKf+h2uzYuTQ== 39 | 40 | "@esbuild/linux-arm64@0.18.15": 41 | version "0.18.15" 42 | resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.15.tgz#2f5d226b024964f2b5b6bce7c874a8ad31785fa2" 43 | integrity sha512-BWncQeuWDgYv0jTNzJjaNgleduV4tMbQjmk/zpPh/lUdMcNEAxy+jvneDJ6RJkrqloG7tB9S9rCrtfk/kuplsQ== 44 | 45 | "@esbuild/linux-arm@0.18.15": 46 | version "0.18.15" 47 | resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.15.tgz#172331fc66bbe89ba96e5e2ad583b2faa132d85c" 48 | integrity sha512-dT4URUv6ir45ZkBqhwZwyFV6cH61k8MttIwhThp2BGiVtagYvCToF+Bggyx2VI57RG4Fbt21f9TmXaYx0DeUJg== 49 | 50 | "@esbuild/linux-ia32@0.18.15": 51 | version "0.18.15" 52 | resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.15.tgz#fa797051131ee5f46d70c65a7edd14b6230cfc2f" 53 | integrity sha512-JPXORvgHRHITqfms1dWT/GbEY89u848dC08o0yK3fNskhp0t2TuNUnsrrSgOdH28ceb1hJuwyr8R/1RnyPwocw== 54 | 55 | "@esbuild/linux-loong64@0.18.15": 56 | version "0.18.15" 57 | resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.15.tgz#aeae1fa3d92b1486a91c0cb1cfd9c0ebe9168de4" 58 | integrity sha512-kArPI0DopjJCEplsVj/H+2Qgzz7vdFSacHNsgoAKpPS6W/Ndh8Oe24HRDQ5QCu4jHgN6XOtfFfLpRx3TXv/mEg== 59 | 60 | "@esbuild/linux-mips64el@0.18.15": 61 | version "0.18.15" 62 | resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.15.tgz#b63cfe356c33807c4d8ee5a75452922e98502073" 63 | integrity sha512-b/tmngUfO02E00c1XnNTw/0DmloKjb6XQeqxaYuzGwHe0fHVgx5/D6CWi+XH1DvkszjBUkK9BX7n1ARTOst59w== 64 | 65 | "@esbuild/linux-ppc64@0.18.15": 66 | version "0.18.15" 67 | resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.15.tgz#7dcb394e69cb47e4dc8a5960dd58b1a273d07f5d" 68 | integrity sha512-KXPY69MWw79QJkyvUYb2ex/OgnN/8N/Aw5UDPlgoRtoEfcBqfeLodPr42UojV3NdkoO4u10NXQdamWm1YEzSKw== 69 | 70 | "@esbuild/linux-riscv64@0.18.15": 71 | version "0.18.15" 72 | resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.15.tgz#fdfb9cf23b50d33112315e3194b9e16f7abf6c30" 73 | integrity sha512-komK3NEAeeGRnvFEjX1SfVg6EmkfIi5aKzevdvJqMydYr9N+pRQK0PGJXk+bhoPZwOUgLO4l99FZmLGk/L1jWg== 74 | 75 | "@esbuild/linux-s390x@0.18.15": 76 | version "0.18.15" 77 | resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.15.tgz#ce608d95989a502878d7cb1167df791e45268011" 78 | integrity sha512-632T5Ts6gQ2WiMLWRRyeflPAm44u2E/s/TJvn+BP6M5mnHSk93cieaypj3VSMYO2ePTCRqAFXtuYi1yv8uZJNA== 79 | 80 | "@esbuild/linux-x64@0.18.15": 81 | version "0.18.15" 82 | resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.18.15.tgz#49bbba5607702709f63b41906b4f1bcc44cf2f8e" 83 | integrity sha512-MsHtX0NgvRHsoOtYkuxyk4Vkmvk3PLRWfA4okK7c+6dT0Fu4SUqXAr9y4Q3d8vUf1VWWb6YutpL4XNe400iQ1g== 84 | 85 | "@esbuild/netbsd-x64@0.18.15": 86 | version "0.18.15" 87 | resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.15.tgz#08b5ccaf027c7e2174b9a19c29bebfe59dce1cfb" 88 | integrity sha512-djST6s+jQiwxMIVQ5rlt24JFIAr4uwUnzceuFL7BQT4CbrRtqBPueS4GjXSiIpmwVri1Icj/9pFRJ7/aScvT+A== 89 | 90 | "@esbuild/openbsd-x64@0.18.15": 91 | version "0.18.15" 92 | resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.15.tgz#38ec4223ebab562f0a89ffe20a40f05d500f89f0" 93 | integrity sha512-naeRhUIvhsgeounjkF5mvrNAVMGAm6EJWiabskeE5yOeBbLp7T89tAEw0j5Jm/CZAwyLe3c67zyCWH6fsBLCpw== 94 | 95 | "@esbuild/sunos-x64@0.18.15": 96 | version "0.18.15" 97 | resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.15.tgz#dbbebf641957a54b77f39ca9b10b0b38586799ba" 98 | integrity sha512-qkT2+WxyKbNIKV1AEhI8QiSIgTHMcRctzSaa/I3kVgMS5dl3fOeoqkb7pW76KwxHoriImhx7Mg3TwN/auMDsyQ== 99 | 100 | "@esbuild/win32-arm64@0.18.15": 101 | version "0.18.15" 102 | resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.15.tgz#7f15fe5d14b9b24eb18ca211ad92e0f5df92a18b" 103 | integrity sha512-HC4/feP+pB2Vb+cMPUjAnFyERs+HJN7E6KaeBlFdBv799MhD+aPJlfi/yk36SED58J9TPwI8MAcVpJgej4ud0A== 104 | 105 | "@esbuild/win32-ia32@0.18.15": 106 | version "0.18.15" 107 | resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.15.tgz#a6609735a4a5e8fbdeb045720bc8be46825566fa" 108 | integrity sha512-ovjwoRXI+gf52EVF60u9sSDj7myPixPxqzD5CmkEUmvs+W9Xd0iqISVBQn8xcx4ciIaIVlWCuTbYDOXOnOL44Q== 109 | 110 | "@esbuild/win32-x64@0.18.15": 111 | version "0.18.15" 112 | resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.15.tgz#41ee66253566124cc44bce1b4c760a87d9f5bf1d" 113 | integrity sha512-imUxH9a3WJARyAvrG7srLyiK73XdX83NXQkjKvQ+7vPh3ZxoLrzvPkQKKw2DwZ+RV2ZB6vBfNHP8XScAmQC3aA== 114 | 115 | esbuild@^0.18.15: 116 | version "0.18.15" 117 | resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.18.15.tgz#5b5c1a22e608afd5675f82ad466c4d2cfd723f85" 118 | integrity sha512-3WOOLhrvuTGPRzQPU6waSDWrDTnQriia72McWcn6UCi43GhCHrXH4S59hKMeez+IITmdUuUyvbU9JIp+t3xlPQ== 119 | optionalDependencies: 120 | "@esbuild/android-arm" "0.18.15" 121 | "@esbuild/android-arm64" "0.18.15" 122 | "@esbuild/android-x64" "0.18.15" 123 | "@esbuild/darwin-arm64" "0.18.15" 124 | "@esbuild/darwin-x64" "0.18.15" 125 | "@esbuild/freebsd-arm64" "0.18.15" 126 | "@esbuild/freebsd-x64" "0.18.15" 127 | "@esbuild/linux-arm" "0.18.15" 128 | "@esbuild/linux-arm64" "0.18.15" 129 | "@esbuild/linux-ia32" "0.18.15" 130 | "@esbuild/linux-loong64" "0.18.15" 131 | "@esbuild/linux-mips64el" "0.18.15" 132 | "@esbuild/linux-ppc64" "0.18.15" 133 | "@esbuild/linux-riscv64" "0.18.15" 134 | "@esbuild/linux-s390x" "0.18.15" 135 | "@esbuild/linux-x64" "0.18.15" 136 | "@esbuild/netbsd-x64" "0.18.15" 137 | "@esbuild/openbsd-x64" "0.18.15" 138 | "@esbuild/sunos-x64" "0.18.15" 139 | "@esbuild/win32-arm64" "0.18.15" 140 | "@esbuild/win32-ia32" "0.18.15" 141 | "@esbuild/win32-x64" "0.18.15" 142 | 143 | immer@^10.0.2: 144 | version "10.0.2" 145 | resolved "https://registry.yarnpkg.com/immer/-/immer-10.0.2.tgz#11636c5b77acf529e059582d76faf338beb56141" 146 | integrity sha512-Rx3CqeqQ19sxUtYV9CU911Vhy8/721wRFnJv3REVGWUmoAcIwzifTsdmJte/MV+0/XpM35LZdQMBGkRIoLPwQA== 147 | 148 | nanoid@^5.0.1: 149 | version "5.0.1" 150 | resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-5.0.1.tgz#3e95d775a8bc8a98afbf0a237e2bbc6a71b0662e" 151 | integrity sha512-vWeVtV5Cw68aML/QaZvqN/3QQXc6fBfIieAlu05m7FZW2Dgb+3f0xc0TTxuJW+7u30t7iSDTV/j3kVI0oJqIfQ== 152 | 153 | prettier@^3.3.3: 154 | version "3.3.3" 155 | resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105" 156 | integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== 157 | 158 | typescript@^5.1.6: 159 | version "5.1.6" 160 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274" 161 | integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA== 162 | --------------------------------------------------------------------------------