├── .editorconfig ├── .github └── workflows │ ├── release.yml │ └── test.yml ├── .gitignore ├── .npmignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── create-logux-creator ├── index.d.ts ├── index.js └── index.test.ts ├── create-store-creator ├── errors.ts ├── index.d.ts ├── index.js ├── index.test.ts └── types.ts ├── index.d.ts ├── index.js ├── package.json ├── pnpm-lock.yaml ├── subscribe ├── index.d.ts ├── index.js └── index.test.ts ├── tsconfig.json ├── use-dispatch ├── errors.ts ├── index.d.ts ├── index.js └── types.tsx └── use-subscription ├── index.d.ts ├── index.js ├── index.test.ts └── types.tsx /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | push: 4 | tags: 5 | - '*' 6 | permissions: 7 | contents: write 8 | jobs: 9 | release: 10 | name: Release On Tag 11 | if: startsWith(github.ref, 'refs/tags/') 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout the repository 15 | uses: actions/checkout@v4 16 | - name: Extract the changelog 17 | id: changelog 18 | run: | 19 | TAG_NAME=${GITHUB_REF/refs\/tags\//} 20 | READ_SECTION=false 21 | CHANGELOG="" 22 | while IFS= read -r line; do 23 | if [[ "$line" =~ ^#+\ +(.*) ]]; then 24 | if [[ "${BASH_REMATCH[1]}" == "$TAG_NAME" ]]; then 25 | READ_SECTION=true 26 | elif [[ "$READ_SECTION" == true ]]; then 27 | break 28 | fi 29 | elif [[ "$READ_SECTION" == true ]]; then 30 | CHANGELOG+="$line"$'\n' 31 | fi 32 | done < "CHANGELOG.md" 33 | CHANGELOG=$(echo "$CHANGELOG" | awk '/./ {$1=$1;print}') 34 | echo "changelog_content<> $GITHUB_OUTPUT 35 | echo "$CHANGELOG" >> $GITHUB_OUTPUT 36 | echo "EOF" >> $GITHUB_OUTPUT 37 | - name: Create the release 38 | if: steps.changelog.outputs.changelog_content != '' 39 | uses: softprops/action-gh-release@v1 40 | with: 41 | name: ${{ github.ref_name }} 42 | body: '${{ steps.changelog.outputs.changelog_content }}' 43 | draft: false 44 | prerelease: false 45 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | on: 3 | push: 4 | branches: 5 | - main 6 | - next 7 | pull_request: 8 | permissions: 9 | contents: read 10 | jobs: 11 | full: 12 | name: Node.js Latest Full 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout the repository 16 | uses: actions/checkout@v4 17 | - name: Install pnpm 18 | uses: pnpm/action-setup@v4 19 | with: 20 | version: 9 21 | - name: Install Node.js 22 | uses: actions/setup-node@v4 23 | with: 24 | node-version: 22 25 | cache: pnpm 26 | - name: Install dependencies 27 | run: pnpm install --ignore-scripts 28 | - name: Run tests 29 | run: pnpm test 30 | short: 31 | runs-on: ubuntu-latest 32 | strategy: 33 | matrix: 34 | node-version: 35 | - 20 36 | - 18 37 | name: Node.js ${{ matrix.node-version }} Quick 38 | steps: 39 | - name: Checkout the repository 40 | uses: actions/checkout@v3 41 | - name: Install pnpm 42 | uses: pnpm/action-setup@v2 43 | with: 44 | version: 9 45 | - name: Install Node.js ${{ matrix.node-version }} 46 | uses: actions/setup-node@v3 47 | with: 48 | node-version: ${{ matrix.node-version }} 49 | cache: pnpm 50 | - name: Install dependencies 51 | run: pnpm install --ignore-scripts 52 | - name: Run unit tests 53 | run: pnpm unit 54 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | 3 | coverage/ 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | **/*.test.ts 2 | **/types.ts 3 | **/errors.ts 4 | tsconfig.json 5 | coverage/ 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | This project adheres to [Semantic Versioning](http://semver.org/). 3 | 4 | ## 0.8.4 5 | * Fixed docs. 6 | 7 | ## 0.8.3 8 | * Fixed double reduce in some replays (by Ben Teichman). 9 | 10 | ## 0.8.2 11 | * Fixed replay with existing snapshot (by @betalb). 12 | * Updated `@logux/client`. 13 | 14 | ## 0.8.1 15 | * Fixed peer dependency to the latest Logux Client. 16 | 17 | ## 0.8 18 | * Moved project to ESM-only type. Applications must use ESM too. 19 | * Dropped Node.js 10 support. 20 | * Fixed types performance by replacing `type` to `interface`. 21 | 22 | ## 0.7.1 23 | * Fix `isLoading` on channel changes (by Eduard Aksamitov). 24 | 25 | ## 0.7 26 | * Use Logux Core 0.6 and WebSocket Protocol 4. 27 | * Use Logux Client 0.9. 28 | * Fix types. 29 | 30 | ## 0.6.2 31 | * Add Redux methods to `LoguxReduxStore` type. 32 | 33 | ## 0.6.1 34 | * Export `LoguxReduxStore` type. 35 | 36 | ## 0.6 37 | * Use Logux Core 0.5 and WebSocket Protocol 3. 38 | * Use Logux Client 0.8 with `store.client.changeUser`. 39 | * Add support for dynamic tokens. 40 | * User ID must be always a string without `:`. 41 | * Rename credentials option to token. 42 | * Move Redux to `peerDependencies`. 43 | 44 | ## 0.5.2 45 | * Fix type compatibility issues with Redux <4.0.5. 46 | 47 | ## 0.5.1 48 | * Remove development dependencies from `dependencies`. 49 | 50 | ## 0.5 51 | * Rename `checkEvery` to `cleanEvery`. 52 | * Add ES modules support. 53 | * Add TypeScript definitions. 54 | * Move API docs from JSDoc to TypeDoc. 55 | * Mark package as side effect free. 56 | 57 | ## 0.4.2 58 | * Fix `store.client.tabId` support. 59 | 60 | ## 0.4.1 61 | * Set `noAutoReason` on explicit `meta.keepLast`. 62 | 63 | ## 0.4 64 | * Use Logux Client 0.5 with `store.client.tabId` instead of `store.client.id`. 65 | 66 | ## 0.3.2 67 | * Fix the way to keep latest 1000 action without explicit `reasons`. 68 | 69 | ## 0.3.1 70 | * Fix JSDoc. 71 | 72 | ## 0.3 73 | * Keep 1000 latest actions with missed `reasons`. 74 | 75 | ## 0.2.9 76 | * Improve error message on `logux/undo`. 77 | 78 | ## 0.2.8 79 | * Do not call reducers on `logux/*` actions during history replay. 80 | 81 | ## 0.2.7 82 | * Do not call reducers on `logux/subscribe` and `logux/unsubscribe`. 83 | 84 | ## 0.2.6 85 | * Fix history replays on `logux/processed`. 86 | 87 | ## 0.2.5 88 | * Fix compatibility with Logux Client 0.3.2. 89 | 90 | ## 0.2.4 91 | * Fix double subscription. 92 | 93 | ## 0.2.3 94 | * Fix React Redux warning. 95 | 96 | ## 0.2.2 97 | * Fix peer dependencies. 98 | 99 | ## 0.2.1 100 | * Reduce size. 101 | 102 | ## 0.2 103 | * Rename project from `logux-redux` to `@logux/redux`. 104 | * Merge with `react-logux`. 105 | * Use Logux Core 0.3. 106 | * Use React Redux 7 and new React Context. 107 | * Add `useSubscription` hook. 108 | * Add `isSubscribing` property to `connect()`. 109 | * Return `Promise` from `dispatch.sync()`. 110 | * Pass `enhancer` to `createStore` (by Dan Onoshko). 111 | 112 | ## 0.1.7 113 | * Use Redux 4. 114 | 115 | ## 0.1.6 116 | * Fix time traveling to the same position with 2 actions. 117 | 118 | ## 0.1.5 119 | * Fix time traveling algorithm. 120 | 121 | ## 0.1.4 122 | * Allow to miss `meta` in `dispatch.local()`. 123 | 124 | ## 0.1.3 125 | * Fix middleware support for legacy actions. 126 | 127 | ## 0.1.2 128 | * Don’t apply action if it was deleted during waiting for replay end. 129 | 130 | ## 0.1.1 131 | * Fix inserting reasons-less action in the middle of history. 132 | 133 | ## 0.1 134 | * Initial release. 135 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright 2017 Andrey Sitnik 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Logux Redux 2 | 3 | 5 | 6 | Logux is a new way to connect client and server. Instead of sending 7 | HTTP requests (e.g., AJAX and GraphQL) it synchronizes log of operations 8 | between client, server, and other clients. 9 | 10 | * **[Guide, recipes, and API](https://logux.org/)** 11 | * **[Issues](https://github.com/logux/logux/issues)** 12 | and **[roadmap](https://github.com/orgs/logux/projects/1)** 13 | * **[Projects](https://logux.org/guide/architecture/parts/)** 14 | inside Logux ecosystem 15 | 16 | This repository contains Redux compatible API on top of [Logux Client]. 17 | 18 | 19 | Sponsored by Evil Martians 21 | 22 | 23 | [Logux Client]: https://github.com/logux/client 24 | 25 | ## Install 26 | 27 | ```sh 28 | npm install @logux/core @logux/client @logux/redux redux 29 | ``` 30 | 31 | ## Usage 32 | 33 | See [documentation] for Logux API. 34 | 35 | ```js 36 | import { CrossTabClient, log } from '@logux/client' 37 | import { createStoreCreator } from '@logux/redux' 38 | 39 | let userId = document.querySelector('meta[name=user]').content 40 | let token = document.querySelector('meta[name=token]').content 41 | 42 | const client = new CrossTabClient({ 43 | subprotocol: '1.0.0', 44 | server: 'wss://example.com:1337', 45 | userId, 46 | token 47 | }) 48 | 49 | const createStore = createStoreCreator(client) 50 | 51 | const store = createStore(reducers, preloadedState) 52 | log(store.client) 53 | 54 | export default store 55 | ``` 56 | 57 | ```js 58 | import { Provider } from 'react-redux' 59 | import ReactDOM from 'react-dom' 60 | 61 | import store from './store' 62 | import App from './App' 63 | 64 | ReactDOM.render( 65 | , 66 | document.getElementById('root') 67 | ) 68 | ``` 69 | 70 | ```js 71 | import { useSubscription } from '@logux/redux' 72 | 73 | export const User = ({ id, name }) => { 74 | const isSubscribing = useSubscription([`user/${ id }`]) 75 | if (isSubscribing) { 76 | return 77 | } else { 78 | return

{ name }

79 | } 80 | } 81 | ``` 82 | 83 | [documentation]: https://logux.org 84 | -------------------------------------------------------------------------------- /create-logux-creator/index.d.ts: -------------------------------------------------------------------------------- 1 | import { ClientMeta, ClientOptions, CrossTabClient } from '@logux/client' 2 | import { Log } from '@logux/core' 3 | 4 | import { 5 | LoguxStoreCreator, 6 | LoguxReduxOptions 7 | } from '../create-store-creator/index.js' 8 | 9 | /** 10 | * @deprecated Use createStoreCreator(client, opts) instead. 11 | */ 12 | export function createLoguxCreator< 13 | H extends object = {}, 14 | L extends Log = Log 15 | >( 16 | config: ClientOptions & LoguxReduxOptions 17 | ): LoguxStoreCreator> 18 | -------------------------------------------------------------------------------- /create-logux-creator/index.js: -------------------------------------------------------------------------------- 1 | import { CrossTabClient } from '@logux/client' 2 | 3 | import { createStoreCreator } from '../create-store-creator/index.js' 4 | 5 | export function createLoguxCreator(config = {}) { 6 | console.warn( 7 | 'createLoguxCreator() will be removed in v0.9. ' + 8 | 'Use createStoreCreator(client, opts) instead.' 9 | ) 10 | 11 | let cleanEvery = config.cleanEvery || 25 12 | delete config.cleanEvery 13 | let saveStateEvery = config.saveStateEvery || 50 14 | delete config.saveStateEvery 15 | let onMissedHistory = config.onMissedHistory 16 | delete config.onMissedHistory 17 | let reasonlessHistory = config.reasonlessHistory || 1000 18 | delete config.reasonlessHistory 19 | 20 | let client = new CrossTabClient(config) 21 | 22 | return createStoreCreator(client, { 23 | cleanEvery, 24 | saveStateEvery, 25 | onMissedHistory, 26 | reasonlessHistory 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /create-logux-creator/index.test.ts: -------------------------------------------------------------------------------- 1 | import { Action, TestTime, TestLog } from '@logux/core' 2 | import { restoreAll, spyOn } from 'nanospy' 3 | import { ClientMeta } from '@logux/client' 4 | import { Reducer } from 'redux' 5 | import { equal } from 'uvu/assert' 6 | import { test } from 'uvu' 7 | 8 | import { createLoguxCreator } from '../index.js' 9 | 10 | type AddAction = { 11 | type: 'ADD' 12 | value: string 13 | } 14 | 15 | function isAdd(action: Action): action is AddAction { 16 | return action.type === 'ADD' 17 | } 18 | 19 | const ADD_A: AddAction = { type: 'ADD', value: 'a' } 20 | 21 | type State = { 22 | value: string 23 | } 24 | 25 | function history(state: State, action: Action): State { 26 | if (isAdd(action)) { 27 | return { value: `${state.value}${action.value}` } 28 | } else { 29 | return state 30 | } 31 | } 32 | 33 | // @ts-ignore 34 | global.WebSocket = () => {} 35 | 36 | test.after.each(() => { 37 | restoreAll() 38 | }) 39 | 40 | test('creates store', () => { 41 | let spy = spyOn(console, 'warn', () => {}) 42 | 43 | let creator = createLoguxCreator<{}, TestLog>({ 44 | server: 'wss://localhost:1337', 45 | subprotocol: '1.0.0', 46 | userId: '10', 47 | time: new TestTime() 48 | }) 49 | let historyReducer: Reducer = history 50 | let store = creator(historyReducer, { value: '0' }) 51 | store.dispatch(ADD_A) 52 | equal(store.getState(), { value: '0a' }) 53 | equal(spy.callCount, 1) 54 | }) 55 | 56 | test.run() 57 | -------------------------------------------------------------------------------- /create-store-creator/errors.ts: -------------------------------------------------------------------------------- 1 | import { CrossTabClient } from '@logux/client' 2 | import { Action } from '@logux/core' 3 | 4 | import { createStoreCreator } from '../index.js' 5 | 6 | let client = new CrossTabClient({ 7 | subprotocol: '1.0.0', 8 | server: 'ws://localhost', 9 | userId: '10' 10 | }) 11 | 12 | let createStore = createStoreCreator(client) 13 | 14 | type CounterState = number 15 | 16 | interface IncAction { 17 | type: 'INC' 18 | } 19 | 20 | function isInc(action: Action): action is IncAction { 21 | return action.type === 'INC' 22 | } 23 | 24 | function reducer(state: CounterState = 0, action: IncAction): CounterState { 25 | if (isInc(action)) { 26 | return state + 1 27 | } else { 28 | return state 29 | } 30 | } 31 | 32 | let store = createStore(reducer) 33 | 34 | // THROWS Type '"RENAME"' is not assignable to type '"INC"' 35 | store.dispatch({ type: 'RENAME' }) 36 | // THROWS Type 'number' is not assignable to type 'string[]' 37 | store.dispatch.crossTab({ type: 'INC' }, { reasons: 1 }) 38 | -------------------------------------------------------------------------------- /create-store-creator/index.d.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AnyAction, 3 | Action, 4 | Reducer, 5 | Observable, 6 | StoreEnhancer, 7 | PreloadedState, 8 | Store as ReduxStore 9 | } from 'redux' 10 | import { Client, ClientMeta } from '@logux/client' 11 | import { Unsubscribe } from 'nanoevents' 12 | import { Log } from '@logux/core' 13 | 14 | export interface LoguxDispatch { 15 | (action: T): T 16 | 17 | /** 18 | * Add sync action to log and update store state. 19 | * This action will be visible only for server and all browser tabs. 20 | * 21 | * ```js 22 | * store.dispatch.sync( 23 | * { type: 'CHANGE_NAME', name }, 24 | * { reasons: ['lastName'] } 25 | * ).then(meta => { 26 | * store.log.removeReason('lastName', { maxAdded: meta.added - 1 }) 27 | * }) 28 | * ``` 29 | * 30 | * @param action The new action. 31 | * @param meta Action’s metadata. 32 | * @returns Promise when action will be processed by the server. 33 | */ 34 | sync(action: T, meta?: Partial): Promise 35 | 36 | /** 37 | * Add cross-tab action to log and update store state. 38 | * This action will be visible only for all tabs. 39 | * 40 | * ```js 41 | * store.dispatch.crossTab( 42 | * { type: 'CHANGE_FAVICON', favicon }, 43 | * { reasons: ['lastFavicon'] } 44 | * ).then(meta => { 45 | * store.log.removeReason('lastFavicon', { maxAdded: meta.added - 1 }) 46 | * }) 47 | * ``` 48 | * 49 | * @param action The new action. 50 | * @param meta Action’s metadata. 51 | * @returns Promise when action will be saved to the log. 52 | */ 53 | crossTab( 54 | action: T, 55 | meta?: Partial 56 | ): Promise 57 | 58 | /** 59 | * Add local action to log and update store state. 60 | * This action will be visible only for current tab. 61 | * 62 | * ```js 63 | * 64 | * store.dispatch.local( 65 | * { type: 'OPEN_MENU' }, 66 | * { reasons: ['lastMenu'] } 67 | * ).then(meta => { 68 | * store.log.removeReason('lastMenu', { maxAdded: meta.added - 1 }) 69 | * }) 70 | * ``` 71 | * 72 | * @param action The new action. 73 | * @param meta Action’s metadata. 74 | * @returns Promise when action will be saved to the log. 75 | */ 76 | local(action: T, meta?: Partial): Promise 77 | } 78 | 79 | export interface ReduxStateListener { 80 | (state: S, prevState: S, action: A, meta: ClientMeta): void 81 | } 82 | 83 | export class LoguxReduxStore< 84 | S = any, 85 | A extends Action = AnyAction, 86 | L extends Log = Log, 87 | C extends Client = Client<{}, L> 88 | > implements ReduxStore { 89 | /** 90 | * Logux synchronization client. 91 | */ 92 | client: C 93 | 94 | /** 95 | * The Logux log. 96 | */ 97 | log: L 98 | 99 | /** 100 | * Promise until loading the state from IndexedDB. 101 | */ 102 | initialize: Promise 103 | 104 | /** 105 | * Add action to log with Redux compatible API. 106 | */ 107 | dispatch: LoguxDispatch 108 | 109 | /** 110 | * Subscribe for store events. Supported events: 111 | * 112 | * * `change`: when store was changed by action. 113 | * 114 | * ```js 115 | * store.on('change', (state, prevState, action, meta) => { 116 | * console.log(state, prevState, action, meta) 117 | * }) 118 | * ``` 119 | * 120 | * @param event The event name. 121 | * @param listener The listener function. 122 | * @returns Unbind listener from event. 123 | */ 124 | on(event: 'change', listener: ReduxStateListener): Unsubscribe 125 | 126 | /** 127 | * Reads the state tree managed by the store. 128 | * 129 | * @returns The current state tree of your application. 130 | */ 131 | getState(): S 132 | 133 | /** 134 | * Adds a change listener. 135 | * 136 | * @param listener A callback to be invoked on every dispatch. 137 | * @returns A function to remove this change listener. 138 | */ 139 | subscribe(listener: () => void): Unsubscribe 140 | 141 | /** 142 | * Replaces the reducer currently used by the store to calculate the state. 143 | * 144 | * @param nextReducer The reducer for the store to use instead. 145 | */ 146 | replaceReducer(nextReducer: Reducer): void 147 | 148 | [Symbol.observable](): Observable 149 | } 150 | 151 | export interface LoguxStoreCreator< 152 | L extends Log = Log, 153 | C extends Client = Client<{}, L> 154 | > { 155 | ( 156 | reducer: Reducer, 157 | enhancer?: StoreEnhancer 158 | ): LoguxReduxStore & Ext 159 | ( 160 | reducer: Reducer, 161 | preloadedState?: PreloadedState, 162 | enhancer?: StoreEnhancer 163 | ): LoguxReduxStore & Ext 164 | } 165 | 166 | export type LoguxReduxOptions = { 167 | /** 168 | * How many actions without `meta.reasons` will be kept for time travel. 169 | * Default is `1000`. 170 | */ 171 | reasonlessHistory?: number 172 | 173 | /** 174 | * How often save state to history. Default is `50`. 175 | */ 176 | saveStateEvery?: number 177 | 178 | /** 179 | * Callback when there is no history to replay actions accurate. 180 | */ 181 | onMissedHistory?: (action: Action) => void 182 | 183 | /** 184 | * How often we need to clean log from old actions. Default is every `25` 185 | * actions. 186 | */ 187 | cleanEvery?: number 188 | } 189 | 190 | /** 191 | * Connects Logux Client to Redux createStore function. 192 | * 193 | * ```js 194 | * import { CrossTabClient, createStoreCreator } from '@logux/redux' 195 | * 196 | * const client = new CrossTabClient({ 197 | * subprotocol: '1.0.0', 198 | * server: process.env.NODE_ENV === 'development' 199 | * ? 'ws://localhost:31337' 200 | * : 'wss://logux.example.com', 201 | * userId: userId.content 202 | * token: token.content 203 | * }) 204 | * 205 | * const createStore = createStoreCreator(client) 206 | * 207 | * const store = createStore(reducer) 208 | * store.client.start() 209 | * ``` 210 | * 211 | * @param client Logux Client. 212 | * @param options Logux Redux options. 213 | * @returns Redux’s `createStore` compatible function. 214 | */ 215 | export function createStoreCreator< 216 | L extends Log = Log, 217 | C extends Client = Client<{}, L> 218 | >(client: C, options?: LoguxReduxOptions): LoguxStoreCreator 219 | -------------------------------------------------------------------------------- /create-store-creator/index.js: -------------------------------------------------------------------------------- 1 | import { createStore as createReduxStore } from 'redux' 2 | import { createNanoEvents } from 'nanoevents' 3 | import { isFirstOlder } from '@logux/core' 4 | 5 | function hackReducer(reducer) { 6 | return (state, action) => { 7 | if (action.type === 'logux/state') { 8 | return action.state 9 | } else { 10 | return reducer(state, action) 11 | } 12 | } 13 | } 14 | 15 | export function createStoreCreator(client, options = {}) { 16 | let cleanEvery = options.cleanEvery || 25 17 | let saveStateEvery = options.saveStateEvery || 50 18 | let onMissedHistory = options.onMissedHistory 19 | let reasonlessHistory = options.reasonlessHistory || 1000 20 | 21 | let log = client.log 22 | 23 | return function createStore(reducer, preloadedState, enhancer) { 24 | let store = createReduxStore(hackReducer(reducer), preloadedState, enhancer) 25 | 26 | let emitter = createNanoEvents() 27 | 28 | store.client = client 29 | store.log = log 30 | let historyCleaned = false 31 | let stateHistory = {} 32 | let wait = {} 33 | 34 | let actionCount = 0 35 | function saveHistory(meta) { 36 | actionCount += 1 37 | if (saveStateEvery === 1 || actionCount % saveStateEvery === 1) { 38 | stateHistory[meta.id] = store.getState() 39 | } 40 | } 41 | 42 | let originReplace = store.replaceReducer 43 | store.replaceReducer = newReducer => { 44 | reducer = newReducer 45 | return originReplace(hackReducer(newReducer)) 46 | } 47 | 48 | store.on = emitter.on.bind(emitter) 49 | 50 | let init 51 | store.initialize = new Promise(resolve => { 52 | init = resolve 53 | }) 54 | 55 | let prevMeta 56 | let originDispatch = store.dispatch 57 | store.dispatch = action => { 58 | let meta = { 59 | id: log.generateId(), 60 | tab: store.client.tabId, 61 | reasons: ['timeTravelTab' + store.client.tabId], 62 | dispatch: true 63 | } 64 | log.add(action, meta) 65 | 66 | prevMeta = meta 67 | let prevState = store.getState() 68 | originDispatch(action) 69 | emitter.emit('change', store.getState(), prevState, action, meta) 70 | saveHistory(meta) 71 | } 72 | 73 | store.dispatch.local = (action, meta = {}) => { 74 | meta.tab = client.tabId 75 | if (meta.reasons || meta.keepLast) meta.noAutoReason = true 76 | return log.add(action, meta) 77 | } 78 | 79 | store.dispatch.crossTab = (action, meta = {}) => { 80 | if (meta.reasons || meta.keepLast) meta.noAutoReason = true 81 | return log.add(action, meta) 82 | } 83 | 84 | store.dispatch.sync = (action, meta = {}) => { 85 | if (meta.reasons || meta.keepLast) meta.noAutoReason = true 86 | return client.sync(action, meta) 87 | } 88 | 89 | function replaceState(state, actions, pushHistory) { 90 | let last = actions.length === 0 ? null : actions[actions.length - 1][1] 91 | let newState = actions.reduceRight((prev, [action, id]) => { 92 | delete wait[id] 93 | 94 | let changed = reducer(prev, action) 95 | if (pushHistory && id === last) { 96 | stateHistory[pushHistory] = changed 97 | } else if (stateHistory[id]) { 98 | stateHistory[id] = changed 99 | } 100 | return changed 101 | }, state) 102 | originDispatch({ type: 'logux/state', state: newState }) 103 | return newState 104 | } 105 | 106 | let replaying 107 | function replay(actionId) { 108 | let ignore = {} 109 | let actions = [] 110 | let replayed = false 111 | let newAction 112 | let collecting = true 113 | 114 | replaying = new Promise(resolve => { 115 | log 116 | .each((action, meta) => { 117 | if (meta.tab && meta.tab !== client.tabId) return true 118 | 119 | if (collecting || !stateHistory[meta.id]) { 120 | if (action.type === 'logux/undo') { 121 | ignore[action.id] = true 122 | return true 123 | } else if (action.type.startsWith('logux/')) { 124 | return true 125 | } 126 | 127 | if (!ignore[meta.id]) actions.push([action, meta.id]) 128 | if (meta.id === actionId) { 129 | newAction = action 130 | collecting = false 131 | } 132 | 133 | return true 134 | } else { 135 | replayed = true 136 | replaceState(stateHistory[meta.id], actions) 137 | return false 138 | } 139 | }) 140 | .then(() => { 141 | if (!replayed) { 142 | if (historyCleaned) { 143 | if (onMissedHistory) { 144 | onMissedHistory(newAction) 145 | } 146 | for (let i = actions.length - 1; i >= 0; i--) { 147 | let id = actions[i][1] 148 | if (stateHistory[id]) { 149 | replayed = true 150 | replaceState( 151 | stateHistory[id], 152 | actions.slice(0, i).concat([[newAction, actionId]]), 153 | id 154 | ) 155 | break 156 | } 157 | } 158 | } 159 | 160 | if (!replayed) { 161 | replaceState( 162 | preloadedState, 163 | actions.concat([[{ type: '@@redux/INIT' }]]) 164 | ) 165 | } 166 | } 167 | 168 | replaying = false 169 | resolve() 170 | }) 171 | }) 172 | 173 | return replaying 174 | } 175 | 176 | log.on('preadd', (action, meta) => { 177 | let type = action.type 178 | let isLogux = type.startsWith('logux/') 179 | if (type === 'logux/undo') { 180 | meta.reasons.push('reasonsLoading') 181 | } 182 | if (!isLogux && !isFirstOlder(prevMeta, meta)) { 183 | meta.reasons.push('replay') 184 | } 185 | if (!isLogux && !meta.noAutoReason && !meta.dispatch) { 186 | meta.reasons.push('timeTravel') 187 | } 188 | }) 189 | 190 | async function process(action, meta) { 191 | if (replaying) { 192 | wait[meta.id] = true 193 | await replaying 194 | if (wait[meta.id]) { 195 | delete wait[meta.id] 196 | await process(action, meta) 197 | } 198 | 199 | return 200 | } 201 | 202 | if (action.type === 'logux/undo') { 203 | let [undoAction, undoMeta] = await log.byId(action.id) 204 | if (undoAction) { 205 | log.changeMeta(meta.id, { 206 | reasons: undoMeta.reasons.filter(i => i !== 'syncing') 207 | }) 208 | delete stateHistory[action.id] 209 | await replay(action.id) 210 | } else { 211 | await log.changeMeta(meta.id, { reasons: [] }) 212 | } 213 | } else if (!action.type.startsWith('logux/')) { 214 | if (isFirstOlder(prevMeta, meta)) { 215 | prevMeta = meta 216 | originDispatch(action) 217 | if (meta.added) saveHistory(meta) 218 | } else { 219 | await replay(meta.id) 220 | if (meta.reasons.includes('replay')) { 221 | log.changeMeta(meta.id, { 222 | reasons: meta.reasons.filter(i => i !== 'replay') 223 | }) 224 | } 225 | } 226 | } 227 | } 228 | 229 | let lastAdded = 0 230 | let addCalls = 0 231 | client.on('add', (action, meta) => { 232 | if (meta.added > lastAdded) lastAdded = meta.added 233 | 234 | if (action.type !== 'logux/processed' && !meta.noAutoReason) { 235 | addCalls += 1 236 | if (addCalls % cleanEvery === 0 && lastAdded > reasonlessHistory) { 237 | historyCleaned = true 238 | log.removeReason('timeTravel', { 239 | maxAdded: lastAdded - reasonlessHistory 240 | }) 241 | log.removeReason('timeTravelTab' + store.client.tabId, { 242 | maxAdded: lastAdded - reasonlessHistory 243 | }) 244 | } 245 | } 246 | 247 | if (!meta.dispatch) { 248 | let prevState = store.getState() 249 | process(action, meta).then(() => { 250 | emitter.emit('change', store.getState(), prevState, action, meta) 251 | }) 252 | } 253 | }) 254 | 255 | client.on('clean', (action, meta) => { 256 | delete wait[meta.id] 257 | delete stateHistory[meta.id] 258 | }) 259 | 260 | let previous = [] 261 | let ignores = {} 262 | log 263 | .each((action, meta) => { 264 | if (!meta.tab) { 265 | if (action.type === 'logux/undo') { 266 | ignores[action.id] = true 267 | } else if (!ignores[meta.id]) { 268 | previous.push([action, meta]) 269 | } 270 | } 271 | }) 272 | .then(() => { 273 | if (previous.length > 0) { 274 | Promise.all(previous.map(i => process(...i))).then(() => init()) 275 | } else { 276 | init() 277 | } 278 | }) 279 | 280 | return store 281 | } 282 | } 283 | -------------------------------------------------------------------------------- /create-store-creator/index.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CrossTabClient, 3 | LoguxUndoError, 4 | ClientOptions, 5 | ClientMeta 6 | } from '@logux/client' 7 | import { applyMiddleware, Reducer, StoreEnhancer } from 'redux' 8 | import { TestPair, TestTime, Action, TestLog } from '@logux/core' 9 | import { spyOn, restoreAll, spy } from 'nanospy' 10 | import { equal, is, ok, type } from 'uvu/assert' 11 | import { LoguxUndoAction } from '@logux/actions' 12 | import { delay } from 'nanodelay' 13 | import { test } from 'uvu' 14 | 15 | import { 16 | createStoreCreator, 17 | LoguxReduxOptions, 18 | LoguxReduxStore 19 | } from '../index.js' 20 | 21 | type State = { 22 | value: string 23 | } 24 | 25 | type AddAction = { 26 | type: 'ADD' 27 | value: string 28 | } 29 | 30 | function createStore( 31 | reducer: Reducer = history, 32 | opts: Partial = {}, 33 | enhancer: StoreEnhancer | undefined = undefined 34 | ): LoguxReduxStore> { 35 | let creatorOptions = { 36 | cleanEvery: opts.cleanEvery, 37 | saveStateEvery: opts.saveStateEvery, 38 | onMissedHistory: opts.onMissedHistory, 39 | reasonlessHistory: opts.reasonlessHistory 40 | } 41 | 42 | delete opts.cleanEvery 43 | delete opts.onMissedHistory 44 | delete opts.saveStateEvery 45 | delete opts.reasonlessHistory 46 | 47 | let client = new CrossTabClient<{}, TestLog>({ 48 | server: 'wss://localhost:1337', 49 | subprotocol: '1.0.0', 50 | userId: '10', 51 | time: new TestTime(), 52 | ...opts 53 | }) 54 | let creator = createStoreCreator>(client, creatorOptions) 55 | let store = creator( 56 | reducer, 57 | { value: '0' }, 58 | enhancer 59 | ) 60 | 61 | return store 62 | } 63 | 64 | function isAdd(action: Action): action is AddAction { 65 | return action.type === 'ADD' 66 | } 67 | 68 | function history(state: State, action: Action): State { 69 | if (isAdd(action)) { 70 | return { value: `${state.value}${action.value}` } 71 | } else { 72 | return state 73 | } 74 | } 75 | 76 | function emit(obj: any, event: string, ...args: any[]): void { 77 | obj.emitter.emit(event, ...args) 78 | } 79 | 80 | const ADD_A: AddAction = { type: 'ADD', value: 'a' } 81 | 82 | // @ts-ignore 83 | global.WebSocket = () => {} 84 | 85 | test.after.each(() => { 86 | restoreAll() 87 | }) 88 | 89 | test('creates Redux store', () => { 90 | let store = createStore() 91 | store.dispatch(ADD_A) 92 | equal(store.getState(), { value: '0a' }) 93 | }) 94 | 95 | test('creates Logux client', () => { 96 | let store = createStore() 97 | equal(store.client.options.subprotocol, '1.0.0') 98 | }) 99 | 100 | test('sets tab ID', async () => { 101 | let store = createStore() 102 | await new Promise(resolve => { 103 | store.log.on('add', (action, meta) => { 104 | equal(meta.tab, store.client.tabId) 105 | equal(meta.reasons, [`timeTravelTab${store.client.tabId}`]) 106 | resolve() 107 | }) 108 | store.dispatch(ADD_A) 109 | }) 110 | }) 111 | 112 | test('has shortcut for add', async () => { 113 | let store = createStore() 114 | await store.dispatch.crossTab(ADD_A, { reasons: ['test'] }) 115 | equal(store.getState(), { value: '0a' }) 116 | equal(store.log.entries()[0][1].reasons, ['test']) 117 | }) 118 | 119 | test('listen for action from other tabs', () => { 120 | let store = createStore() 121 | emit(store.client, 'add', ADD_A, { id: '1 t 0' }) 122 | equal(store.getState(), { value: '0a' }) 123 | }) 124 | 125 | test('undoes last when snapshot exists', async () => { 126 | let store = createStore(undefined, { saveStateEvery: 1 }) 127 | 128 | await store.dispatch.crossTab(ADD_A, { 129 | id: '57 106:test1 1', 130 | reasons: ['test'] 131 | }) 132 | await store.dispatch.crossTab(ADD_A, { 133 | id: '58 106:test1 1', 134 | reasons: ['test'] 135 | }) 136 | await store.dispatch.crossTab( 137 | { 138 | type: 'logux/undo', 139 | id: '58 106:test1 1', 140 | reason: 'test undo', 141 | action: { type: '???' } 142 | }, 143 | { 144 | id: '59 106:test1 1', 145 | reasons: ['as requested'] 146 | } 147 | ) 148 | await delay(10) 149 | equal(store.getState(), { value: '0a' }) 150 | }) 151 | 152 | test('saves previous states', async () => { 153 | let calls = 0 154 | let store = createStore((state: State, action: Action) => { 155 | if (action.type === 'ADD') calls += 1 156 | return state 157 | }) 158 | 159 | let promise: Promise = Promise.resolve() 160 | for (let i = 0; i < 60; i++) { 161 | if (i % 2 === 0) { 162 | promise = promise.then(() => { 163 | return store.dispatch.crossTab(ADD_A, { reasons: ['test'] }) 164 | }) 165 | } else { 166 | store.dispatch(ADD_A) 167 | } 168 | } 169 | await promise 170 | equal(calls, 60) 171 | calls = 0 172 | await store.dispatch.crossTab(ADD_A, { 173 | id: '57 10:test1 1', 174 | reasons: ['test'] 175 | }) 176 | await delay(10) 177 | equal(calls, 10) 178 | }) 179 | 180 | test('changes history recording frequency', async () => { 181 | let calls = 0 182 | let store = createStore( 183 | (state: State, action: Action) => { 184 | if (action.type === 'ADD') calls += 1 185 | return state 186 | }, 187 | { 188 | saveStateEvery: 1 189 | } 190 | ) 191 | 192 | await Promise.all([ 193 | store.dispatch.crossTab(ADD_A, { reasons: ['test'] }), 194 | store.dispatch.crossTab(ADD_A, { reasons: ['test'] }), 195 | store.dispatch.crossTab(ADD_A, { reasons: ['test'] }), 196 | store.dispatch.crossTab(ADD_A, { reasons: ['test'] }) 197 | ]) 198 | calls = 0 199 | await store.dispatch.crossTab(ADD_A, { 200 | id: '3 10:test1 1', 201 | reasons: ['test'] 202 | }) 203 | await delay(10) 204 | equal(calls, 2) 205 | }) 206 | 207 | test('cleans its history on removing action', async () => { 208 | let calls = 0 209 | let store = createStore( 210 | (state: State, action: Action) => { 211 | if (action.type === 'ADD') calls += 1 212 | return state 213 | }, 214 | { 215 | saveStateEvery: 2 216 | } 217 | ) 218 | let nodeId = store.client.nodeId 219 | 220 | await Promise.all([ 221 | store.dispatch.crossTab(ADD_A, { reasons: ['test'] }), 222 | store.dispatch.crossTab(ADD_A, { reasons: ['test'] }), 223 | store.dispatch.crossTab(ADD_A, { reasons: ['test'] }), 224 | store.dispatch.crossTab(ADD_A, { reasons: ['test'] }), 225 | store.dispatch.crossTab(ADD_A, { reasons: ['test'] }), 226 | store.dispatch.crossTab(ADD_A, { reasons: ['test'] }) 227 | ]) 228 | await store.log.changeMeta(`5 ${nodeId} 0`, { reasons: [] }) 229 | calls = 0 230 | await store.dispatch.crossTab(ADD_A, { 231 | id: `5 ${nodeId} 1`, 232 | reasons: ['test'] 233 | }) 234 | await delay(10) 235 | equal(calls, 3) 236 | }) 237 | 238 | test('changes history', async () => { 239 | let store = createStore() 240 | 241 | await Promise.all([ 242 | store.dispatch.crossTab({ type: 'ADD', value: 'a' }, { reasons: ['test'] }), 243 | store.dispatch.crossTab({ type: 'ADD', value: 'b' }, { reasons: ['test'] }) 244 | ]) 245 | store.dispatch({ type: 'ADD', value: 'c' }) 246 | store.dispatch({ type: 'ADD', value: 'd' }) 247 | await store.dispatch.crossTab( 248 | { type: 'ADD', value: '|' }, 249 | { id: '2 10:test1 1', reasons: ['test'] } 250 | ) 251 | await delay(10) 252 | equal(store.getState().value, '0ab|cd') 253 | }) 254 | 255 | test('undoes actions', async () => { 256 | let store = createStore() 257 | let nodeId = store.client.nodeId 258 | 259 | await Promise.all([ 260 | store.dispatch.crossTab({ type: 'ADD', value: 'a' }, { reasons: ['test'] }), 261 | store.dispatch.crossTab({ type: 'ADD', value: 'b' }, { reasons: ['test'] }), 262 | store.dispatch.crossTab({ type: 'ADD', value: 'c' }, { reasons: ['test'] }) 263 | ]) 264 | equal(store.getState().value, '0abc') 265 | store.dispatch.crossTab( 266 | { 267 | type: 'logux/undo', 268 | id: `2 ${nodeId} 0`, 269 | action: { type: 'ADD', value: 'b' }, 270 | reason: 'error' 271 | }, 272 | { reasons: ['test'] } 273 | ) 274 | await delay(1) 275 | equal(store.getState().value, '0ac') 276 | }) 277 | 278 | test('replaces reducer', async () => { 279 | let store = createStore() 280 | store.dispatch({ type: 'ADD', value: 'a' }) 281 | store.dispatch({ type: 'ADD', value: 'b' }) 282 | equal(store.getState().value, '0ab') 283 | 284 | store.replaceReducer( 285 | (state: State | undefined, action: AddAction | LoguxUndoAction): State => { 286 | if (isAdd(action) && typeof state !== 'undefined') { 287 | return { value: state.value + action.value.toUpperCase() } 288 | } else { 289 | return { value: '0' } 290 | } 291 | } 292 | ) 293 | await store.dispatch.crossTab( 294 | { type: 'ADD', value: 'z' }, 295 | { id: '1 10:test1 1', reasons: ['test'] } 296 | ) 297 | await delay(10) 298 | equal(store.getState().value, '0aZB') 299 | }) 300 | 301 | test('ignores cleaned history from non-legacy actions', async () => { 302 | let onMissedHistory = spy() 303 | let store = createStore(history, { 304 | onMissedHistory, 305 | saveStateEvery: 2 306 | }) 307 | await Promise.all([ 308 | store.dispatch.crossTab({ type: 'ADD', value: 'a' }, { reasons: ['one'] }), 309 | store.dispatch.crossTab({ type: 'ADD', value: 'b' }, { reasons: ['test'] }), 310 | store.dispatch.crossTab({ type: 'ADD', value: 'c' }, { reasons: ['test'] }), 311 | store.dispatch.crossTab({ type: 'ADD', value: 'd' }, { reasons: ['test'] }) 312 | ]) 313 | await store.log.removeReason('one') 314 | store.dispatch.crossTab( 315 | { type: 'ADD', value: '|' }, 316 | { id: '1 10:test1 0', reasons: ['test'] } 317 | ) 318 | await delay(1) 319 | equal(store.getState().value, '0|bcd') 320 | is(onMissedHistory.called, false) 321 | }) 322 | 323 | test('does not replays actions on logux/ actions', async () => { 324 | let reduced: string[] = [] 325 | let store = createStore((state, action) => { 326 | if (action.type.slice(0, 2) !== '@@') reduced.push(action.type) 327 | return state 328 | }) 329 | store.log.add({ type: 'A' }, { reasons: ['t'] }) 330 | store.log.add({ type: 'logux/processed' }, { time: 0 }) 331 | store.log.add({ type: 'logux/subscribe' }, { sync: true, time: 0 }) 332 | store.log.add({ type: 'logux/unsubscribe' }, { sync: true, time: 0 }) 333 | store.log.add({ type: 'B' }, { reasons: ['t'], time: 0 }) 334 | await delay(1) 335 | equal(reduced, ['A', 'B', 'A']) 336 | equal(store.log.actions(), [ 337 | { type: 'logux/subscribe' }, 338 | { type: 'B' }, 339 | { type: 'A' } 340 | ]) 341 | }) 342 | 343 | test('replays history for reason-less action', async () => { 344 | let store = createStore() 345 | await Promise.all([ 346 | store.dispatch.crossTab({ type: 'ADD', value: 'a' }, { reasons: ['test'] }), 347 | store.dispatch.crossTab({ type: 'ADD', value: 'b' }, { reasons: ['test'] }), 348 | store.dispatch.crossTab({ type: 'ADD', value: 'c' }, { reasons: ['test'] }) 349 | ]) 350 | store.dispatch.crossTab( 351 | { type: 'ADD', value: '|' }, 352 | { id: '1 10:test1 1', noAutoReason: true } 353 | ) 354 | await delay(1) 355 | equal(store.getState().value, '0a|bc') 356 | equal(store.log.entries().length, 3) 357 | }) 358 | 359 | test('does not re-process actions that occurred in replay', async () => { 360 | let store = createStore() 361 | 362 | store.dispatch({ type: 'ADD', value: 'a' }) 363 | store.dispatch.sync({ type: 'ADD', value: 'b' }, { reasons: ['test'] }) 364 | store.dispatch({ type: 'ADD', value: 'c' }) 365 | store.dispatch.sync({ type: 'ADD', value: 'd' }, { reasons: ['test'] }) 366 | await delay(1) 367 | equal(store.getState().value, '0abcd') 368 | equal(store.log.entries().length, 4) 369 | }) 370 | 371 | test('replays actions before staring since initial state', async () => { 372 | let onMissedHistory = spy() 373 | let store = createStore(history, { 374 | onMissedHistory, 375 | saveStateEvery: 2 376 | }) 377 | await Promise.all([ 378 | store.dispatch.crossTab({ type: 'ADD', value: 'b' }, { reasons: ['test'] }), 379 | store.dispatch.crossTab({ type: 'ADD', value: 'c' }, { reasons: ['test'] }), 380 | store.dispatch.crossTab({ type: 'ADD', value: 'd' }, { reasons: ['test'] }) 381 | ]) 382 | store.dispatch.crossTab( 383 | { type: 'ADD', value: '|' }, 384 | { id: '0 10:test1 0', reasons: ['test'] } 385 | ) 386 | await delay(1) 387 | is(onMissedHistory.called, false) 388 | equal(store.getState().value, '0|bcd') 389 | }) 390 | 391 | test('replays actions on missed history', async () => { 392 | let onMissedHistory = spy() 393 | let store = createStore(history, { 394 | reasonlessHistory: 2, 395 | onMissedHistory, 396 | saveStateEvery: 2, 397 | cleanEvery: 1 398 | }) 399 | store.dispatch({ type: 'ADD', value: 'a' }) 400 | store.dispatch({ type: 'ADD', value: 'b' }) 401 | store.dispatch({ type: 'ADD', value: 'c' }) 402 | store.dispatch({ type: 'ADD', value: 'd' }) 403 | await delay(1) 404 | store.dispatch.crossTab( 405 | { type: 'ADD', value: '[' }, 406 | { id: '0 10:test1 0', reasons: ['test'] } 407 | ) 408 | await delay(1) 409 | equal(store.getState().value, '0abc[d') 410 | equal(onMissedHistory.calls, [[{ type: 'ADD', value: '[' }]]) 411 | store.dispatch.crossTab( 412 | { type: 'ADD', value: ']' }, 413 | { id: '0 10:test1 1', reasons: ['test'] } 414 | ) 415 | await delay(1) 416 | equal(store.getState().value, '0abc[]d') 417 | }) 418 | 419 | test('works without onMissedHistory', async () => { 420 | let store = createStore(history, { 421 | reasonlessHistory: 2, 422 | saveStateEvery: 2, 423 | cleanEvery: 1 424 | }) 425 | store.dispatch({ type: 'ADD', value: 'a' }) 426 | store.dispatch({ type: 'ADD', value: 'b' }) 427 | store.dispatch({ type: 'ADD', value: 'c' }) 428 | store.dispatch({ type: 'ADD', value: 'd' }) 429 | await delay(1) 430 | await store.dispatch.crossTab( 431 | { type: 'ADD', value: '|' }, 432 | { id: '0 10:test1 0', reasons: ['test'] } 433 | ) 434 | }) 435 | 436 | test('does not fall on missed onMissedHistory', async () => { 437 | let store = createStore(history) 438 | await store.dispatch.crossTab( 439 | { type: 'ADD', value: 'a' }, 440 | { reasons: ['first'] } 441 | ) 442 | await store.log.removeReason('first') 443 | store.dispatch.crossTab( 444 | { type: 'ADD', value: '|' }, 445 | { id: '0 10:test1 0', reasons: ['test'] } 446 | ) 447 | await delay(1) 448 | equal(store.getState().value, '0|') 449 | }) 450 | 451 | test('cleans action added without reason', async () => { 452 | let store = createStore(history, { reasonlessHistory: 3 }) 453 | 454 | store.dispatch.local({ type: 'ADD', value: '0' }, { reasons: ['test'] }) 455 | equal(store.log.entries()[0][1].reasons, ['test']) 456 | 457 | function add(index: number) { 458 | return () => { 459 | store.dispatch({ type: 'ADD', value: `${4 * index - 3}` }) 460 | store.dispatch.local({ type: 'ADD', value: `${4 * index - 2}` }) 461 | store.dispatch.crossTab({ type: 'ADD', value: `${4 * index - 1}` }) 462 | store.dispatch.sync({ type: 'ADD', value: `${4 * index}` }) 463 | } 464 | } 465 | 466 | let promise = Promise.resolve() 467 | for (let i = 1; i <= 6; i++) { 468 | promise = promise.then(add(i)) 469 | } 470 | 471 | await promise 472 | await delay(1) 473 | 474 | let entries = store.log.entries() 475 | let last = entries[entries.length - 1] 476 | equal(last[1].reasons, ['syncing', 'timeTravel']) 477 | store.dispatch({ type: 'ADD', value: '25' }) 478 | await store.log.removeReason('syncing') 479 | await delay(1) 480 | equal(store.log.actions(), [ 481 | { type: 'ADD', value: '0' }, 482 | { type: 'ADD', value: '23' }, 483 | { type: 'ADD', value: '24' }, 484 | { type: 'ADD', value: '25' } 485 | ]) 486 | }) 487 | 488 | test('cleans last 1000 by default', async () => { 489 | let store = createStore() 490 | 491 | let promise = Promise.resolve() 492 | for (let i = 0; i < 1050; i++) { 493 | promise = promise.then(() => { 494 | store.dispatch(ADD_A) 495 | }) 496 | } 497 | 498 | await promise 499 | await delay(1) 500 | equal(store.log.actions().length, 1000) 501 | }) 502 | 503 | test('copies reasons to undo action', async () => { 504 | let store = createStore() 505 | let nodeId = store.client.nodeId 506 | await store.dispatch.crossTab(ADD_A, { reasons: ['a', 'b'] }) 507 | await store.dispatch.crossTab( 508 | { type: 'logux/undo', id: `1 ${nodeId} 0`, action: ADD_A, reason: 'error' }, 509 | { reasons: [] } 510 | ) 511 | let result = await store.log.byId(`2 ${nodeId} 0`) 512 | if (result[0] === null) throw new Error('Action was not found') 513 | equal(result[0].type, 'logux/undo') 514 | equal(result[1].reasons, ['a', 'b']) 515 | }) 516 | 517 | test('dispatches local actions', async () => { 518 | let store = createStore() 519 | await store.dispatch.local(ADD_A, { reasons: ['test'] }) 520 | equal(store.log.entries()[0][0], ADD_A) 521 | equal(store.log.entries()[0][1].tab, store.client.tabId) 522 | equal(store.log.entries()[0][1].reasons, ['test']) 523 | }) 524 | 525 | test('allows to miss meta for local actions', async () => { 526 | let store = createStore() 527 | store.log.on('preadd', (action, meta) => { 528 | meta.reasons.push('preadd') 529 | }) 530 | await store.dispatch.local(ADD_A) 531 | equal(store.log.entries()[0][0], ADD_A) 532 | }) 533 | 534 | test('dispatches sync actions', async () => { 535 | let store = createStore() 536 | store.dispatch.sync(ADD_A, { reasons: ['test'] }) 537 | await delay(1) 538 | let log = store.log.entries() 539 | equal(log[0][0], ADD_A) 540 | is(log[0][1].sync, true) 541 | equal(log[0][1].reasons, ['test', 'syncing']) 542 | }) 543 | 544 | test('cleans sync action after processing', async () => { 545 | let warn = spyOn(console, 'warn', () => {}) 546 | let pair = new TestPair() 547 | let store = createStore(history, { server: pair.left }) 548 | let resultA, resultB 549 | 550 | store.dispatch 551 | .sync({ type: 'ADD', value: 'a' }) 552 | .then(() => { 553 | resultA = 'processed' 554 | }) 555 | .catch((e: LoguxUndoError) => { 556 | ok(e.message.includes('undid')) 557 | ok(e.message.includes('because of error')) 558 | resultA = e.action.reason 559 | }) 560 | store.dispatch 561 | .sync({ type: 'ADD', value: 'b' }, { id: '3 10:1:1 0' }) 562 | .then(() => { 563 | resultB = 'processed' 564 | }) 565 | .catch(e => { 566 | ok(e.message.includes('undid')) 567 | ok(e.message.includes('because of error')) 568 | resultB = e.action.reason 569 | }) 570 | 571 | store.log.removeReason('timeTravel') 572 | await store.log.add({ type: 'logux/processed', id: '0 10:1:1 0' }) 573 | is(resultA, undefined) 574 | is(resultB, undefined) 575 | equal(store.log.actions(), [ 576 | { type: 'ADD', value: 'a' }, 577 | { type: 'ADD', value: 'b' } 578 | ]) 579 | await store.log.add({ type: 'logux/processed', id: '1 10:1:1 0' }) 580 | equal(resultA, 'processed') 581 | is(resultB, undefined) 582 | equal(store.log.actions(), [{ type: 'ADD', value: 'b' }]) 583 | store.log.add({ type: 'logux/undo', reason: 'error', id: '3 10:1:1 0' }) 584 | await delay(1) 585 | equal(resultB, 'error') 586 | equal(store.log.actions(), []) 587 | is(warn.called, false) 588 | }) 589 | 590 | test('applies old actions from store', async () => { 591 | let store1 = createStore(history, { reasonlessHistory: 2 }) 592 | let store2 593 | await Promise.all([ 594 | store1.dispatch.crossTab( 595 | { type: 'ADD', value: '1' }, 596 | { id: '0 10:x 1', reasons: ['test'] } 597 | ), 598 | store1.dispatch.crossTab( 599 | { type: 'ADD', value: '2' }, 600 | { id: '0 10:x 2', reasons: ['test'] } 601 | ), 602 | store1.dispatch.crossTab( 603 | { type: 'ADD', value: '3' }, 604 | { id: '0 10:x 3', reasons: ['test'] } 605 | ), 606 | store1.dispatch.crossTab( 607 | { type: 'ADD', value: '4' }, 608 | { id: '0 10:x 4', reasons: ['test'] } 609 | ), 610 | store1.log.add( 611 | { type: 'ADD', value: '5' }, 612 | { id: '0 10:x 5', reasons: ['test'], tab: 'test2' } 613 | ), 614 | store1.dispatch.crossTab( 615 | { 616 | type: 'logux/undo', 617 | id: '0 10:x 2', 618 | action: { type: 'ADD', value: '2' }, 619 | reason: 'error' 620 | }, 621 | { id: '0 10:x 6', reasons: ['test'] } 622 | ) 623 | ]) 624 | store2 = createStore(history, { store: store1.log.store }) 625 | 626 | store2.dispatch({ type: 'ADD', value: 'a' }) 627 | store2.dispatch({ type: 'ADD', value: 'b' }) 628 | store2.dispatch.crossTab({ type: 'ADD', value: 'c' }, { reasons: ['test'] }) 629 | store2.dispatch({ type: 'ADD', value: 'd' }) 630 | store2.dispatch({ type: 'ADD', value: 'e' }) 631 | equal(store2.getState().value, '0abde') 632 | 633 | await store2.initialize 634 | equal(store2.getState().value, '0134abcde') 635 | }) 636 | 637 | test('supports middlewares', () => { 638 | let store = createStore( 639 | history, 640 | {}, 641 | applyMiddleware(() => { 642 | return dispatch => { 643 | return action => { 644 | if (action.value !== 'a') { 645 | dispatch(action) 646 | } 647 | } 648 | } 649 | }) 650 | ) 651 | 652 | store.dispatch({ type: 'ADD', value: 'a' }) 653 | store.dispatch({ type: 'ADD', value: 'b' }) 654 | equal(store.getState().value, '0b') 655 | }) 656 | 657 | test('waits for replaying', async () => { 658 | let store = createStore(history) 659 | let run: undefined | (() => void) 660 | let waiting = new Promise(resolve => { 661 | run = resolve 662 | }) 663 | 664 | let first = true 665 | let originEach = store.log.each 666 | store.log.each = async function (...args: any) { 667 | let result = originEach.apply(this, args) 668 | if (first) { 669 | first = false 670 | await waiting 671 | } 672 | return result 673 | } 674 | 675 | await store.dispatch.crossTab({ type: 'ADD', value: 'b' }, { reasons: ['t'] }) 676 | await store.dispatch.crossTab( 677 | { type: 'ADD', value: 'a' }, 678 | { id: '0 test 0', reasons: ['t'] } 679 | ) 680 | await Promise.all([ 681 | store.dispatch.crossTab({ type: 'ADD', value: 'c' }, { reasons: ['o'] }), 682 | store.dispatch.crossTab({ type: 'ADD', value: 'd' }, { reasons: ['t'] }) 683 | ]) 684 | delay(1) 685 | equal(store.getState().value, '0b') 686 | store.log.removeReason('o') 687 | if (typeof run === 'undefined') throw new Error('run was not set') 688 | run() 689 | await delay(10) 690 | equal(store.getState().value, '0abd') 691 | }) 692 | 693 | test('emits change event', async () => { 694 | let store = createStore(history) 695 | 696 | store.log.on('preadd', (action, meta) => { 697 | meta.reasons.push('test') 698 | }) 699 | 700 | let calls: [State, State, Action][] = [] 701 | store.on('change', (state, prevState, action, meta) => { 702 | type(meta.id, 'string') 703 | calls.push([state, prevState, action]) 704 | }) 705 | 706 | store.dispatch({ type: 'ADD', value: 'a' }) 707 | store.dispatch.local({ type: 'ADD', value: 'c' }) 708 | store.dispatch.local({ type: 'ADD', value: 'b' }, { id: '1 10:test1 1' }) 709 | await delay(10) 710 | equal(calls, [ 711 | [{ value: '0a' }, { value: '0' }, { type: 'ADD', value: 'a' }], 712 | [{ value: '0ac' }, { value: '0a' }, { type: 'ADD', value: 'c' }], 713 | [{ value: '0abc' }, { value: '0ac' }, { type: 'ADD', value: 'b' }] 714 | ]) 715 | }) 716 | 717 | test('warns about undoes cleaned action', async () => { 718 | let store = createStore(history) 719 | await store.dispatch.crossTab({ 720 | type: 'logux/undo', 721 | id: '1 t 0', 722 | action: { type: 'ADD' }, 723 | reason: 'error' 724 | }) 725 | await delay(10) 726 | equal(store.log.actions().length, 0) 727 | }) 728 | 729 | test('does not put reason on request', async () => { 730 | let store = createStore(history) 731 | await store.dispatch.crossTab( 732 | { type: 'ADD', value: 'A' }, 733 | { noAutoReason: true } 734 | ) 735 | await store.dispatch.crossTab({ type: 'ADD', value: 'B' }) 736 | equal(store.log.actions(), [{ type: 'ADD', value: 'B' }]) 737 | 738 | await store.dispatch.crossTab({ type: 'ADD', value: 'a' }, { reasons: ['a'] }) 739 | await store.dispatch.crossTab({ type: 'ADD', value: 'b' }, { keepLast: 'b' }) 740 | equal(store.log.actions(), [ 741 | { type: 'ADD', value: 'B' }, 742 | { type: 'ADD', value: 'a' }, 743 | { type: 'ADD', value: 'b' } 744 | ]) 745 | is(store.log.entries()[1][1].noAutoReason, true) 746 | is(store.log.entries()[2][1].noAutoReason, true) 747 | }) 748 | 749 | test.run() 750 | -------------------------------------------------------------------------------- /create-store-creator/types.ts: -------------------------------------------------------------------------------- 1 | import { CrossTabClient } from '@logux/client' 2 | import { Action } from '@logux/core' 3 | 4 | import { createStoreCreator } from '../index.js' 5 | 6 | let client = new CrossTabClient({ 7 | subprotocol: '1.0.0', 8 | server: 'ws://localhost', 9 | userId: '10' 10 | }) 11 | 12 | let createStore = createStoreCreator(client) 13 | 14 | type CounterState = number 15 | 16 | interface IncAction { 17 | type: 'INC' 18 | } 19 | 20 | function isInc(action: Action): action is IncAction { 21 | return action.type === 'INC' 22 | } 23 | 24 | function reducer( 25 | state: CounterState | undefined, 26 | action: IncAction 27 | ): CounterState { 28 | if (isInc(action)) { 29 | return (state ?? 0) + 1 30 | } else { 31 | return state ?? 0 32 | } 33 | } 34 | 35 | let store = createStore(reducer) 36 | 37 | console.log(store.client.role) 38 | 39 | store.dispatch({ type: 'INC' }) 40 | store.dispatch.crossTab({ type: 'INC' }, { reasons: ['reason'] }) 41 | store.dispatch.sync({ type: 'INC' }).then(meta => { 42 | console.log(meta.id) 43 | }) 44 | 45 | console.log(store.getState().toFixed()) 46 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | export { 2 | createStoreCreator, 3 | LoguxReduxStore, 4 | LoguxReduxOptions 5 | } from './create-store-creator/index.js' 6 | export { createLoguxCreator } from './create-logux-creator/index.js' 7 | export { useSubscription, Channel } from './use-subscription/index.js' 8 | export { useDispatch } from './use-dispatch/index.js' 9 | export { subscribe } from './subscribe/index.js' 10 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | export { createStoreCreator } from './create-store-creator/index.js' 2 | export { createLoguxCreator } from './create-logux-creator/index.js' 3 | export { useSubscription } from './use-subscription/index.js' 4 | export { useDispatch } from './use-dispatch/index.js' 5 | export { subscribe } from './subscribe/index.js' 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@logux/redux", 3 | "version": "0.8.4", 4 | "description": "Redux compatible API for Logux", 5 | "keywords": [ 6 | "logux", 7 | "client", 8 | "redux", 9 | "websocket" 10 | ], 11 | "scripts": { 12 | "unit": "tsm node_modules/uvu/bin.js . '\\.test\\.(ts|js)$'", 13 | "test:coverage": "c8 pnpm unit", 14 | "test:lint": "eslint .", 15 | "test:types": "check-dts", 16 | "test:size": "size-limit", 17 | "test": "pnpm run /^test:/" 18 | }, 19 | "author": "Andrey Sitnik ", 20 | "license": "MIT", 21 | "homepage": "https://logux.org/", 22 | "repository": "logux/redux", 23 | "sideEffects": false, 24 | "type": "module", 25 | "types": "./index.d.ts", 26 | "exports": { 27 | ".": "./index.js", 28 | "./package.json": "./package.json" 29 | }, 30 | "engines": { 31 | "node": "^18.0.0 || ^20.0.0 || >=22.0.0" 32 | }, 33 | "peerDependencies": { 34 | "@logux/client": ">=0.10.0", 35 | "@logux/core": ">=0.7.0", 36 | "react": ">=16.8.4", 37 | "react-redux": ">=6.0.0", 38 | "redux": ">=4.0.0" 39 | }, 40 | "dependencies": { 41 | "nanoevents": "^7.0.1" 42 | }, 43 | "devDependencies": { 44 | "@logux/actions": "^0.3.1", 45 | "@logux/client": "^0.18.4", 46 | "@logux/core": "^0.8.4", 47 | "@logux/eslint-config": "^49.0.0", 48 | "@size-limit/preset-small-lib": "^8.2.6", 49 | "@types/node": "^18.17.2", 50 | "@types/react": "^18.2.18", 51 | "@types/react-redux": "^7.1.25", 52 | "@types/react-test-renderer": "^18.0.0", 53 | "@types/ws": "^8.5.5", 54 | "@typescript-eslint/eslint-plugin": "^5.62.0", 55 | "@typescript-eslint/parser": "^5.62.0", 56 | "c8": "^7.14.0", 57 | "check-dts": "^0.7.2", 58 | "clean-publish": "^4.2.0", 59 | "eslint": "^8.46.0", 60 | "eslint-config-standard": "^17.1.0", 61 | "eslint-plugin-import": "^2.28.0", 62 | "eslint-plugin-n": "^15.7.0", 63 | "eslint-plugin-prefer-let": "^3.0.1", 64 | "eslint-plugin-promise": "^6.1.1", 65 | "nanodelay": "^2.0.2", 66 | "nanospy": "^0.5.0", 67 | "nanostores": "^0.6.0", 68 | "prettier": "^2.8.8", 69 | "react": "^18.2.0", 70 | "react-dom": "^18.2.0", 71 | "react-redux": "^8.1.2", 72 | "react-test-renderer": "^18.2.0", 73 | "redux": "^4.2.1", 74 | "size-limit": "^8.2.6", 75 | "tsm": "^2.3.0", 76 | "typescript": "^5.1.6", 77 | "uvu": "^0.5.6" 78 | }, 79 | "prettier": { 80 | "arrowParens": "avoid", 81 | "jsxSingleQuote": false, 82 | "quoteProps": "consistent", 83 | "semi": false, 84 | "singleQuote": true, 85 | "trailingComma": "none" 86 | }, 87 | "c8": { 88 | "exclude": [ 89 | "**/*.test.*" 90 | ], 91 | "lines": 100, 92 | "check-coverage": true 93 | }, 94 | "eslintConfig": { 95 | "extends": "@logux/eslint-config/esm", 96 | "rules": { 97 | "@typescript-eslint/no-var-requires": "off", 98 | "@typescript-eslint/no-explicit-any": "off", 99 | "no-console": "off" 100 | } 101 | }, 102 | "eslintIgnore": [ 103 | "**/errors.ts" 104 | ], 105 | "size-limit": [ 106 | { 107 | "import": { 108 | "@logux/client": "{ CrossTabClient }", 109 | "./index.js": "{ createStoreCreator, useSubscription, useDispatch }" 110 | }, 111 | "limit": "6 KB" 112 | } 113 | ] 114 | } 115 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | dependencies: 11 | nanoevents: 12 | specifier: ^7.0.1 13 | version: 7.0.1 14 | devDependencies: 15 | '@logux/actions': 16 | specifier: ^0.3.1 17 | version: 0.3.1(@logux/core@0.8.4) 18 | '@logux/client': 19 | specifier: ^0.18.4 20 | version: 0.18.4(@logux/core@0.8.4)(nanostores@0.6.0)(react-dom@18.2.0)(react@18.2.0) 21 | '@logux/core': 22 | specifier: ^0.8.4 23 | version: 0.8.4 24 | '@logux/eslint-config': 25 | specifier: ^49.0.0 26 | version: 49.0.0(eslint-config-standard@17.1.0)(eslint-plugin-import@2.28.0)(eslint-plugin-n@15.7.0)(eslint-plugin-prefer-let@3.0.1)(eslint-plugin-promise@6.1.1)(eslint@8.46.0) 27 | '@size-limit/preset-small-lib': 28 | specifier: ^8.2.6 29 | version: 8.2.6(size-limit@8.2.6) 30 | '@types/node': 31 | specifier: ^18.17.2 32 | version: 18.17.2 33 | '@types/react': 34 | specifier: ^18.2.18 35 | version: 18.2.18 36 | '@types/react-redux': 37 | specifier: ^7.1.25 38 | version: 7.1.25 39 | '@types/react-test-renderer': 40 | specifier: ^18.0.0 41 | version: 18.0.0 42 | '@types/ws': 43 | specifier: ^8.5.5 44 | version: 8.5.5 45 | '@typescript-eslint/eslint-plugin': 46 | specifier: ^5.62.0 47 | version: 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.46.0)(typescript@5.1.6) 48 | '@typescript-eslint/parser': 49 | specifier: ^5.62.0 50 | version: 5.62.0(eslint@8.46.0)(typescript@5.1.6) 51 | c8: 52 | specifier: ^7.14.0 53 | version: 7.14.0 54 | check-dts: 55 | specifier: ^0.7.2 56 | version: 0.7.2(typescript@5.1.6) 57 | clean-publish: 58 | specifier: ^4.2.0 59 | version: 4.2.0 60 | eslint: 61 | specifier: ^8.46.0 62 | version: 8.46.0 63 | eslint-config-standard: 64 | specifier: ^17.1.0 65 | version: 17.1.0(eslint-plugin-import@2.28.0)(eslint-plugin-n@15.7.0)(eslint-plugin-promise@6.1.1)(eslint@8.46.0) 66 | eslint-plugin-import: 67 | specifier: ^2.28.0 68 | version: 2.28.0(@typescript-eslint/parser@5.62.0)(eslint@8.46.0) 69 | eslint-plugin-n: 70 | specifier: ^15.7.0 71 | version: 15.7.0(eslint@8.46.0) 72 | eslint-plugin-prefer-let: 73 | specifier: ^3.0.1 74 | version: 3.0.1 75 | eslint-plugin-promise: 76 | specifier: ^6.1.1 77 | version: 6.1.1(eslint@8.46.0) 78 | nanodelay: 79 | specifier: ^2.0.2 80 | version: 2.0.2 81 | nanospy: 82 | specifier: ^0.5.0 83 | version: 0.5.0 84 | nanostores: 85 | specifier: ^0.6.0 86 | version: 0.6.0 87 | prettier: 88 | specifier: ^2.8.8 89 | version: 2.8.8 90 | react: 91 | specifier: ^18.2.0 92 | version: 18.2.0 93 | react-dom: 94 | specifier: ^18.2.0 95 | version: 18.2.0(react@18.2.0) 96 | react-redux: 97 | specifier: ^8.1.2 98 | version: 8.1.2(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0)(redux@4.2.1) 99 | react-test-renderer: 100 | specifier: ^18.2.0 101 | version: 18.2.0(react@18.2.0) 102 | redux: 103 | specifier: ^4.2.1 104 | version: 4.2.1 105 | size-limit: 106 | specifier: ^8.2.6 107 | version: 8.2.6 108 | tsm: 109 | specifier: ^2.3.0 110 | version: 2.3.0 111 | typescript: 112 | specifier: ^5.1.6 113 | version: 5.1.6 114 | uvu: 115 | specifier: ^0.5.6 116 | version: 0.5.6 117 | 118 | packages: 119 | 120 | '@aashutoshrathi/word-wrap@1.2.6': 121 | resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} 122 | engines: {node: '>=0.10.0'} 123 | 124 | '@babel/runtime@7.22.6': 125 | resolution: {integrity: sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==} 126 | engines: {node: '>=6.9.0'} 127 | 128 | '@bcoe/v8-coverage@0.2.3': 129 | resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} 130 | 131 | '@esbuild/android-arm64@0.18.17': 132 | resolution: {integrity: sha512-9np+YYdNDed5+Jgr1TdWBsozZ85U1Oa3xW0c7TWqH0y2aGghXtZsuT8nYRbzOMcl0bXZXjOGbksoTtVOlWrRZg==} 133 | engines: {node: '>=12'} 134 | cpu: [arm64] 135 | os: [android] 136 | 137 | '@esbuild/android-arm@0.15.18': 138 | resolution: {integrity: sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==} 139 | engines: {node: '>=12'} 140 | cpu: [arm] 141 | os: [android] 142 | 143 | '@esbuild/android-arm@0.18.17': 144 | resolution: {integrity: sha512-wHsmJG/dnL3OkpAcwbgoBTTMHVi4Uyou3F5mf58ZtmUyIKfcdA7TROav/6tCzET4A3QW2Q2FC+eFneMU+iyOxg==} 145 | engines: {node: '>=12'} 146 | cpu: [arm] 147 | os: [android] 148 | 149 | '@esbuild/android-x64@0.18.17': 150 | resolution: {integrity: sha512-O+FeWB/+xya0aLg23hHEM2E3hbfwZzjqumKMSIqcHbNvDa+dza2D0yLuymRBQQnC34CWrsJUXyH2MG5VnLd6uw==} 151 | engines: {node: '>=12'} 152 | cpu: [x64] 153 | os: [android] 154 | 155 | '@esbuild/darwin-arm64@0.18.17': 156 | resolution: {integrity: sha512-M9uJ9VSB1oli2BE/dJs3zVr9kcCBBsE883prage1NWz6pBS++1oNn/7soPNS3+1DGj0FrkSvnED4Bmlu1VAE9g==} 157 | engines: {node: '>=12'} 158 | cpu: [arm64] 159 | os: [darwin] 160 | 161 | '@esbuild/darwin-x64@0.18.17': 162 | resolution: {integrity: sha512-XDre+J5YeIJDMfp3n0279DFNrGCXlxOuGsWIkRb1NThMZ0BsrWXoTg23Jer7fEXQ9Ye5QjrvXpxnhzl3bHtk0g==} 163 | engines: {node: '>=12'} 164 | cpu: [x64] 165 | os: [darwin] 166 | 167 | '@esbuild/freebsd-arm64@0.18.17': 168 | resolution: {integrity: sha512-cjTzGa3QlNfERa0+ptykyxs5A6FEUQQF0MuilYXYBGdBxD3vxJcKnzDlhDCa1VAJCmAxed6mYhA2KaJIbtiNuQ==} 169 | engines: {node: '>=12'} 170 | cpu: [arm64] 171 | os: [freebsd] 172 | 173 | '@esbuild/freebsd-x64@0.18.17': 174 | resolution: {integrity: sha512-sOxEvR8d7V7Kw8QqzxWc7bFfnWnGdaFBut1dRUYtu+EIRXefBc/eIsiUiShnW0hM3FmQ5Zf27suDuHsKgZ5QrA==} 175 | engines: {node: '>=12'} 176 | cpu: [x64] 177 | os: [freebsd] 178 | 179 | '@esbuild/linux-arm64@0.18.17': 180 | resolution: {integrity: sha512-c9w3tE7qA3CYWjT+M3BMbwMt+0JYOp3vCMKgVBrCl1nwjAlOMYzEo+gG7QaZ9AtqZFj5MbUc885wuBBmu6aADQ==} 181 | engines: {node: '>=12'} 182 | cpu: [arm64] 183 | os: [linux] 184 | 185 | '@esbuild/linux-arm@0.18.17': 186 | resolution: {integrity: sha512-2d3Lw6wkwgSLC2fIvXKoMNGVaeY8qdN0IC3rfuVxJp89CRfA3e3VqWifGDfuakPmp90+ZirmTfye1n4ncjv2lg==} 187 | engines: {node: '>=12'} 188 | cpu: [arm] 189 | os: [linux] 190 | 191 | '@esbuild/linux-ia32@0.18.17': 192 | resolution: {integrity: sha512-1DS9F966pn5pPnqXYz16dQqWIB0dmDfAQZd6jSSpiT9eX1NzKh07J6VKR3AoXXXEk6CqZMojiVDSZi1SlmKVdg==} 193 | engines: {node: '>=12'} 194 | cpu: [ia32] 195 | os: [linux] 196 | 197 | '@esbuild/linux-loong64@0.15.18': 198 | resolution: {integrity: sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==} 199 | engines: {node: '>=12'} 200 | cpu: [loong64] 201 | os: [linux] 202 | 203 | '@esbuild/linux-loong64@0.18.17': 204 | resolution: {integrity: sha512-EvLsxCk6ZF0fpCB6w6eOI2Fc8KW5N6sHlIovNe8uOFObL2O+Mr0bflPHyHwLT6rwMg9r77WOAWb2FqCQrVnwFg==} 205 | engines: {node: '>=12'} 206 | cpu: [loong64] 207 | os: [linux] 208 | 209 | '@esbuild/linux-mips64el@0.18.17': 210 | resolution: {integrity: sha512-e0bIdHA5p6l+lwqTE36NAW5hHtw2tNRmHlGBygZC14QObsA3bD4C6sXLJjvnDIjSKhW1/0S3eDy+QmX/uZWEYQ==} 211 | engines: {node: '>=12'} 212 | cpu: [mips64el] 213 | os: [linux] 214 | 215 | '@esbuild/linux-ppc64@0.18.17': 216 | resolution: {integrity: sha512-BAAilJ0M5O2uMxHYGjFKn4nJKF6fNCdP1E0o5t5fvMYYzeIqy2JdAP88Az5LHt9qBoUa4tDaRpfWt21ep5/WqQ==} 217 | engines: {node: '>=12'} 218 | cpu: [ppc64] 219 | os: [linux] 220 | 221 | '@esbuild/linux-riscv64@0.18.17': 222 | resolution: {integrity: sha512-Wh/HW2MPnC3b8BqRSIme/9Zhab36PPH+3zam5pqGRH4pE+4xTrVLx2+XdGp6fVS3L2x+DrsIcsbMleex8fbE6g==} 223 | engines: {node: '>=12'} 224 | cpu: [riscv64] 225 | os: [linux] 226 | 227 | '@esbuild/linux-s390x@0.18.17': 228 | resolution: {integrity: sha512-j/34jAl3ul3PNcK3pfI0NSlBANduT2UO5kZ7FCaK33XFv3chDhICLY8wJJWIhiQ+YNdQ9dxqQctRg2bvrMlYgg==} 229 | engines: {node: '>=12'} 230 | cpu: [s390x] 231 | os: [linux] 232 | 233 | '@esbuild/linux-x64@0.18.17': 234 | resolution: {integrity: sha512-QM50vJ/y+8I60qEmFxMoxIx4de03pGo2HwxdBeFd4nMh364X6TIBZ6VQ5UQmPbQWUVWHWws5MmJXlHAXvJEmpQ==} 235 | engines: {node: '>=12'} 236 | cpu: [x64] 237 | os: [linux] 238 | 239 | '@esbuild/netbsd-x64@0.18.17': 240 | resolution: {integrity: sha512-/jGlhWR7Sj9JPZHzXyyMZ1RFMkNPjC6QIAan0sDOtIo2TYk3tZn5UDrkE0XgsTQCxWTTOcMPf9p6Rh2hXtl5TQ==} 241 | engines: {node: '>=12'} 242 | cpu: [x64] 243 | os: [netbsd] 244 | 245 | '@esbuild/openbsd-x64@0.18.17': 246 | resolution: {integrity: sha512-rSEeYaGgyGGf4qZM2NonMhMOP/5EHp4u9ehFiBrg7stH6BYEEjlkVREuDEcQ0LfIl53OXLxNbfuIj7mr5m29TA==} 247 | engines: {node: '>=12'} 248 | cpu: [x64] 249 | os: [openbsd] 250 | 251 | '@esbuild/sunos-x64@0.18.17': 252 | resolution: {integrity: sha512-Y7ZBbkLqlSgn4+zot4KUNYst0bFoO68tRgI6mY2FIM+b7ZbyNVtNbDP5y8qlu4/knZZ73fgJDlXID+ohY5zt5g==} 253 | engines: {node: '>=12'} 254 | cpu: [x64] 255 | os: [sunos] 256 | 257 | '@esbuild/win32-arm64@0.18.17': 258 | resolution: {integrity: sha512-bwPmTJsEQcbZk26oYpc4c/8PvTY3J5/QK8jM19DVlEsAB41M39aWovWoHtNm78sd6ip6prilxeHosPADXtEJFw==} 259 | engines: {node: '>=12'} 260 | cpu: [arm64] 261 | os: [win32] 262 | 263 | '@esbuild/win32-ia32@0.18.17': 264 | resolution: {integrity: sha512-H/XaPtPKli2MhW+3CQueo6Ni3Avggi6hP/YvgkEe1aSaxw+AeO8MFjq8DlgfTd9Iz4Yih3QCZI6YLMoyccnPRg==} 265 | engines: {node: '>=12'} 266 | cpu: [ia32] 267 | os: [win32] 268 | 269 | '@esbuild/win32-x64@0.18.17': 270 | resolution: {integrity: sha512-fGEb8f2BSA3CW7riJVurug65ACLuQAzKq0SSqkY2b2yHHH0MzDfbLyKIGzHwOI/gkHcxM/leuSW6D5w/LMNitA==} 271 | engines: {node: '>=12'} 272 | cpu: [x64] 273 | os: [win32] 274 | 275 | '@eslint-community/eslint-utils@4.4.0': 276 | resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} 277 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 278 | peerDependencies: 279 | eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 280 | 281 | '@eslint-community/regexpp@4.6.2': 282 | resolution: {integrity: sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==} 283 | engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} 284 | 285 | '@eslint/eslintrc@2.1.1': 286 | resolution: {integrity: sha512-9t7ZA7NGGK8ckelF0PQCfcxIUzs1Md5rrO6U/c+FIQNanea5UZC0wqKXH4vHBccmu4ZJgZ2idtPeW7+Q2npOEA==} 287 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 288 | 289 | '@eslint/js@8.46.0': 290 | resolution: {integrity: sha512-a8TLtmPi8xzPkCbp/OGFUo5yhRkHM2Ko9kOWP4znJr0WAhWyThaw3PnwX4vOTWOAMsV2uRt32PPDcEz63esSaA==} 291 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 292 | 293 | '@humanwhocodes/config-array@0.11.10': 294 | resolution: {integrity: sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==} 295 | engines: {node: '>=10.10.0'} 296 | 297 | '@humanwhocodes/module-importer@1.0.1': 298 | resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} 299 | engines: {node: '>=12.22'} 300 | 301 | '@humanwhocodes/object-schema@1.2.1': 302 | resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} 303 | 304 | '@istanbuljs/schema@0.1.3': 305 | resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} 306 | engines: {node: '>=8'} 307 | 308 | '@jridgewell/resolve-uri@3.1.0': 309 | resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} 310 | engines: {node: '>=6.0.0'} 311 | 312 | '@jridgewell/sourcemap-codec@1.4.14': 313 | resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} 314 | 315 | '@jridgewell/trace-mapping@0.3.18': 316 | resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==} 317 | 318 | '@logux/actions@0.3.1': 319 | resolution: {integrity: sha512-9NU+3he2DaOYXlQjaZWornrnMsbw+8mvgUHtTyKcBotvpS5me5VVxVo9y02G7k2byz4FXtvafq9KPVStyag3oA==} 320 | engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0} 321 | peerDependencies: 322 | '@logux/core': ^0.8.0 323 | 324 | '@logux/client@0.18.4': 325 | resolution: {integrity: sha512-gFOU22dxxxR1psxmQH1EO82nSgqkfSgVtKsMpwdLQCvgidjoYLAQYmiv8w5wfo5Kk53V/QvK9irMvr/0N7IW7Q==} 326 | engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0} 327 | peerDependencies: 328 | '@logux/core': ^0.8.0 329 | '@nanostores/preact': '>=0.0.0' 330 | '@nanostores/react': '>=0.0.0' 331 | '@nanostores/vue': '>=0.0.0' 332 | nanostores: ^0.6.0 || ^0.7.0 333 | preact: '>=10.0.0' 334 | react: '>=18.0.0' 335 | react-dom: '>=16.8.0' 336 | vue: '>=3.2.30' 337 | peerDependenciesMeta: 338 | '@nanostores/preact': 339 | optional: true 340 | '@nanostores/react': 341 | optional: true 342 | '@nanostores/vue': 343 | optional: true 344 | preact: 345 | optional: true 346 | react: 347 | optional: true 348 | react-dom: 349 | optional: true 350 | vue: 351 | optional: true 352 | 353 | '@logux/core@0.8.4': 354 | resolution: {integrity: sha512-dw/Wq+6iBLN1lalKf98WOsiksO1WtN0kH3SN8LcpWGF+wGP6x+N8jpqP8ZPKFOyduvb3r1T50gvk3xyr2mDLuQ==} 355 | engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0} 356 | 357 | '@logux/eslint-config@49.0.0': 358 | resolution: {integrity: sha512-5Aj1wytb+1oej3wLH8G7D35Glx88Iuj07JcVL3YruRhl4v7WZnF3w3RR3IVSQAvllQch4eemvHnLenrZ3PimFg==} 359 | engines: {node: '>=10.0.0'} 360 | peerDependencies: 361 | eslint: ^8.35.0 362 | eslint-config-standard: ^17.0.0 363 | eslint-plugin-import: ^2.27.5 364 | eslint-plugin-n: ^15.6.1 365 | eslint-plugin-prefer-let: ^3.0.1 366 | eslint-plugin-promise: ^6.1.1 367 | 368 | '@nodelib/fs.scandir@2.1.5': 369 | resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} 370 | engines: {node: '>= 8'} 371 | 372 | '@nodelib/fs.stat@2.0.5': 373 | resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} 374 | engines: {node: '>= 8'} 375 | 376 | '@nodelib/fs.walk@1.2.8': 377 | resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} 378 | engines: {node: '>= 8'} 379 | 380 | '@size-limit/esbuild@8.2.6': 381 | resolution: {integrity: sha512-a4c8xVDuDMYw5jF655ADjQDluw3jGPPYer6UJock5rSnUlWnIbmT/Ohud7gJGq5gqyLUQOCrBD7NB3g+mlhj4g==} 382 | engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0} 383 | peerDependencies: 384 | size-limit: 8.2.6 385 | 386 | '@size-limit/file@8.2.6': 387 | resolution: {integrity: sha512-B7ayjxiJsbtXdIIWazJkB5gezi5WBMecdHTFPMDhI3NwEML1RVvUjAkrb1mPAAkIpt2LVHPnhdCUHjqDdjugwg==} 388 | engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0} 389 | peerDependencies: 390 | size-limit: 8.2.6 391 | 392 | '@size-limit/preset-small-lib@8.2.6': 393 | resolution: {integrity: sha512-roanEuscDaaXDsT5Cg9agMbmsQVlMr66eRg3AwT2o4vE7WFLR8Z42p0AHZiwucW1nGpCxAh8E08Qa/yyVuj5nA==} 394 | peerDependencies: 395 | size-limit: 8.2.6 396 | 397 | '@types/hoist-non-react-statics@3.3.1': 398 | resolution: {integrity: sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==} 399 | 400 | '@types/istanbul-lib-coverage@2.0.4': 401 | resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} 402 | 403 | '@types/json-schema@7.0.12': 404 | resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==} 405 | 406 | '@types/json5@0.0.29': 407 | resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} 408 | 409 | '@types/node@18.17.2': 410 | resolution: {integrity: sha512-wBo3KqP/PBqje5TI9UTiuL3yWfP6sdPtjtygSOqcYZWT232dfDeDOnkDps5wqZBP9NgGgYrNejinl0faAuE+HQ==} 411 | 412 | '@types/prop-types@15.7.5': 413 | resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} 414 | 415 | '@types/react-redux@7.1.25': 416 | resolution: {integrity: sha512-bAGh4e+w5D8dajd6InASVIyCo4pZLJ66oLb80F9OBLO1gKESbZcRCJpTT6uLXX+HAB57zw1WTdwJdAsewuTweg==} 417 | 418 | '@types/react-test-renderer@18.0.0': 419 | resolution: {integrity: sha512-C7/5FBJ3g3sqUahguGi03O79b8afNeSD6T8/GU50oQrJCU0bVCCGQHaGKUbg2Ce8VQEEqTw8/HiS6lXHHdgkdQ==} 420 | 421 | '@types/react@18.2.18': 422 | resolution: {integrity: sha512-da4NTSeBv/P34xoZPhtcLkmZuJ+oYaCxHmyHzwaDQo9RQPBeXV+06gEk2FpqEcsX9XrnNLvRpVh6bdavDSjtiQ==} 423 | 424 | '@types/scheduler@0.16.3': 425 | resolution: {integrity: sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==} 426 | 427 | '@types/semver@7.5.0': 428 | resolution: {integrity: sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==} 429 | 430 | '@types/unist@2.0.7': 431 | resolution: {integrity: sha512-cputDpIbFgLUaGQn6Vqg3/YsJwxUwHLO13v3i5ouxT4lat0khip9AEWxtERujXV9wxIB1EyF97BSJFt6vpdI8g==} 432 | 433 | '@types/use-sync-external-store@0.0.3': 434 | resolution: {integrity: sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==} 435 | 436 | '@types/ws@8.5.5': 437 | resolution: {integrity: sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==} 438 | 439 | '@typescript-eslint/eslint-plugin@5.62.0': 440 | resolution: {integrity: sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==} 441 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 442 | peerDependencies: 443 | '@typescript-eslint/parser': ^5.0.0 444 | eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 445 | typescript: '*' 446 | peerDependenciesMeta: 447 | typescript: 448 | optional: true 449 | 450 | '@typescript-eslint/parser@5.62.0': 451 | resolution: {integrity: sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==} 452 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 453 | peerDependencies: 454 | eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 455 | typescript: '*' 456 | peerDependenciesMeta: 457 | typescript: 458 | optional: true 459 | 460 | '@typescript-eslint/scope-manager@5.62.0': 461 | resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} 462 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 463 | 464 | '@typescript-eslint/type-utils@5.62.0': 465 | resolution: {integrity: sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==} 466 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 467 | peerDependencies: 468 | eslint: '*' 469 | typescript: '*' 470 | peerDependenciesMeta: 471 | typescript: 472 | optional: true 473 | 474 | '@typescript-eslint/types@5.62.0': 475 | resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} 476 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 477 | 478 | '@typescript-eslint/typescript-estree@5.62.0': 479 | resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} 480 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 481 | peerDependencies: 482 | typescript: '*' 483 | peerDependenciesMeta: 484 | typescript: 485 | optional: true 486 | 487 | '@typescript-eslint/utils@5.62.0': 488 | resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} 489 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 490 | peerDependencies: 491 | eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 492 | 493 | '@typescript-eslint/visitor-keys@5.62.0': 494 | resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} 495 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 496 | 497 | acorn-jsx@5.3.2: 498 | resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} 499 | peerDependencies: 500 | acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 501 | 502 | acorn@8.10.0: 503 | resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} 504 | engines: {node: '>=0.4.0'} 505 | hasBin: true 506 | 507 | ajv@6.12.6: 508 | resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} 509 | 510 | ansi-regex@5.0.1: 511 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 512 | engines: {node: '>=8'} 513 | 514 | ansi-styles@4.3.0: 515 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 516 | engines: {node: '>=8'} 517 | 518 | anymatch@3.1.3: 519 | resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} 520 | engines: {node: '>= 8'} 521 | 522 | argparse@2.0.1: 523 | resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} 524 | 525 | array-buffer-byte-length@1.0.0: 526 | resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} 527 | 528 | array-includes@3.1.6: 529 | resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==} 530 | engines: {node: '>= 0.4'} 531 | 532 | array-union@2.1.0: 533 | resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} 534 | engines: {node: '>=8'} 535 | 536 | array.prototype.findlastindex@1.2.2: 537 | resolution: {integrity: sha512-tb5thFFlUcp7NdNF6/MpDk/1r/4awWG1FIz3YqDf+/zJSTezBb+/5WViH41obXULHVpDzoiCLpJ/ZO9YbJMsdw==} 538 | engines: {node: '>= 0.4'} 539 | 540 | array.prototype.flat@1.3.1: 541 | resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==} 542 | engines: {node: '>= 0.4'} 543 | 544 | array.prototype.flatmap@1.3.1: 545 | resolution: {integrity: sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==} 546 | engines: {node: '>= 0.4'} 547 | 548 | arraybuffer.prototype.slice@1.0.1: 549 | resolution: {integrity: sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==} 550 | engines: {node: '>= 0.4'} 551 | 552 | available-typed-arrays@1.0.5: 553 | resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} 554 | engines: {node: '>= 0.4'} 555 | 556 | balanced-match@1.0.2: 557 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 558 | 559 | binary-extensions@2.2.0: 560 | resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} 561 | engines: {node: '>=8'} 562 | 563 | brace-expansion@1.1.11: 564 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} 565 | 566 | braces@3.0.2: 567 | resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} 568 | engines: {node: '>=8'} 569 | 570 | builtins@5.0.1: 571 | resolution: {integrity: sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==} 572 | 573 | bytes-iec@3.1.1: 574 | resolution: {integrity: sha512-fey6+4jDK7TFtFg/klGSvNKJctyU7n2aQdnM+CO0ruLPbqqMOM8Tio0Pc+deqUeVKX1tL5DQep1zQ7+37aTAsA==} 575 | engines: {node: '>= 0.8'} 576 | 577 | c8@7.14.0: 578 | resolution: {integrity: sha512-i04rtkkcNcCf7zsQcSv/T9EbUn4RXQ6mropeMcjFOsQXQ0iGLAr/xT6TImQg4+U9hmNpN9XdvPkjUL1IzbgxJw==} 579 | engines: {node: '>=10.12.0'} 580 | hasBin: true 581 | 582 | call-bind@1.0.2: 583 | resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} 584 | 585 | callsites@3.1.0: 586 | resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} 587 | engines: {node: '>=6'} 588 | 589 | chalk@4.1.2: 590 | resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} 591 | engines: {node: '>=10'} 592 | 593 | check-dts@0.7.2: 594 | resolution: {integrity: sha512-ZflsEhv7SXlgNECrNIw1WmMJZ1787KtS62anWknLPI+k9g9OY2eA/UfT+Tsb0i0eWLUZHtFfznrNtGlQJrGaKw==} 595 | engines: {node: '>=14.0.0'} 596 | hasBin: true 597 | peerDependencies: 598 | typescript: '>=4.0.0' 599 | 600 | chokidar@3.5.3: 601 | resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} 602 | engines: {node: '>= 8.10.0'} 603 | 604 | clean-publish@4.2.0: 605 | resolution: {integrity: sha512-dqZF5y6KtlkYhbnJoXiOCP4L1TPdI7HtuDysslUrbI8vLPu65ZjVO3pu5xp4qH0X2cWdDN/La04woe6fg4LNSw==} 606 | engines: {node: '>= 16.0.0'} 607 | hasBin: true 608 | 609 | cliui@7.0.4: 610 | resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} 611 | 612 | color-convert@2.0.1: 613 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 614 | engines: {node: '>=7.0.0'} 615 | 616 | color-name@1.1.4: 617 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 618 | 619 | concat-map@0.0.1: 620 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} 621 | 622 | convert-source-map@1.9.0: 623 | resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} 624 | 625 | cross-spawn@7.0.3: 626 | resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} 627 | engines: {node: '>= 8'} 628 | 629 | csstype@3.1.2: 630 | resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} 631 | 632 | debug@3.2.7: 633 | resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} 634 | peerDependencies: 635 | supports-color: '*' 636 | peerDependenciesMeta: 637 | supports-color: 638 | optional: true 639 | 640 | debug@4.3.4: 641 | resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} 642 | engines: {node: '>=6.0'} 643 | peerDependencies: 644 | supports-color: '*' 645 | peerDependenciesMeta: 646 | supports-color: 647 | optional: true 648 | 649 | deep-is@0.1.4: 650 | resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} 651 | 652 | define-properties@1.2.0: 653 | resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==} 654 | engines: {node: '>= 0.4'} 655 | 656 | dequal@2.0.3: 657 | resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} 658 | engines: {node: '>=6'} 659 | 660 | diff@5.1.0: 661 | resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==} 662 | engines: {node: '>=0.3.1'} 663 | 664 | dir-glob@3.0.1: 665 | resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} 666 | engines: {node: '>=8'} 667 | 668 | doctrine@2.1.0: 669 | resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} 670 | engines: {node: '>=0.10.0'} 671 | 672 | doctrine@3.0.0: 673 | resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} 674 | engines: {node: '>=6.0.0'} 675 | 676 | emoji-regex@8.0.0: 677 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 678 | 679 | es-abstract@1.22.1: 680 | resolution: {integrity: sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==} 681 | engines: {node: '>= 0.4'} 682 | 683 | es-set-tostringtag@2.0.1: 684 | resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==} 685 | engines: {node: '>= 0.4'} 686 | 687 | es-shim-unscopables@1.0.0: 688 | resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} 689 | 690 | es-to-primitive@1.2.1: 691 | resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} 692 | engines: {node: '>= 0.4'} 693 | 694 | esbuild-android-64@0.15.18: 695 | resolution: {integrity: sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==} 696 | engines: {node: '>=12'} 697 | cpu: [x64] 698 | os: [android] 699 | 700 | esbuild-android-arm64@0.15.18: 701 | resolution: {integrity: sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==} 702 | engines: {node: '>=12'} 703 | cpu: [arm64] 704 | os: [android] 705 | 706 | esbuild-darwin-64@0.15.18: 707 | resolution: {integrity: sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==} 708 | engines: {node: '>=12'} 709 | cpu: [x64] 710 | os: [darwin] 711 | 712 | esbuild-darwin-arm64@0.15.18: 713 | resolution: {integrity: sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==} 714 | engines: {node: '>=12'} 715 | cpu: [arm64] 716 | os: [darwin] 717 | 718 | esbuild-freebsd-64@0.15.18: 719 | resolution: {integrity: sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==} 720 | engines: {node: '>=12'} 721 | cpu: [x64] 722 | os: [freebsd] 723 | 724 | esbuild-freebsd-arm64@0.15.18: 725 | resolution: {integrity: sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==} 726 | engines: {node: '>=12'} 727 | cpu: [arm64] 728 | os: [freebsd] 729 | 730 | esbuild-linux-32@0.15.18: 731 | resolution: {integrity: sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==} 732 | engines: {node: '>=12'} 733 | cpu: [ia32] 734 | os: [linux] 735 | 736 | esbuild-linux-64@0.15.18: 737 | resolution: {integrity: sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==} 738 | engines: {node: '>=12'} 739 | cpu: [x64] 740 | os: [linux] 741 | 742 | esbuild-linux-arm64@0.15.18: 743 | resolution: {integrity: sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==} 744 | engines: {node: '>=12'} 745 | cpu: [arm64] 746 | os: [linux] 747 | 748 | esbuild-linux-arm@0.15.18: 749 | resolution: {integrity: sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==} 750 | engines: {node: '>=12'} 751 | cpu: [arm] 752 | os: [linux] 753 | 754 | esbuild-linux-mips64le@0.15.18: 755 | resolution: {integrity: sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==} 756 | engines: {node: '>=12'} 757 | cpu: [mips64el] 758 | os: [linux] 759 | 760 | esbuild-linux-ppc64le@0.15.18: 761 | resolution: {integrity: sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==} 762 | engines: {node: '>=12'} 763 | cpu: [ppc64] 764 | os: [linux] 765 | 766 | esbuild-linux-riscv64@0.15.18: 767 | resolution: {integrity: sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==} 768 | engines: {node: '>=12'} 769 | cpu: [riscv64] 770 | os: [linux] 771 | 772 | esbuild-linux-s390x@0.15.18: 773 | resolution: {integrity: sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==} 774 | engines: {node: '>=12'} 775 | cpu: [s390x] 776 | os: [linux] 777 | 778 | esbuild-netbsd-64@0.15.18: 779 | resolution: {integrity: sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==} 780 | engines: {node: '>=12'} 781 | cpu: [x64] 782 | os: [netbsd] 783 | 784 | esbuild-openbsd-64@0.15.18: 785 | resolution: {integrity: sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==} 786 | engines: {node: '>=12'} 787 | cpu: [x64] 788 | os: [openbsd] 789 | 790 | esbuild-sunos-64@0.15.18: 791 | resolution: {integrity: sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==} 792 | engines: {node: '>=12'} 793 | cpu: [x64] 794 | os: [sunos] 795 | 796 | esbuild-windows-32@0.15.18: 797 | resolution: {integrity: sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==} 798 | engines: {node: '>=12'} 799 | cpu: [ia32] 800 | os: [win32] 801 | 802 | esbuild-windows-64@0.15.18: 803 | resolution: {integrity: sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==} 804 | engines: {node: '>=12'} 805 | cpu: [x64] 806 | os: [win32] 807 | 808 | esbuild-windows-arm64@0.15.18: 809 | resolution: {integrity: sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==} 810 | engines: {node: '>=12'} 811 | cpu: [arm64] 812 | os: [win32] 813 | 814 | esbuild@0.15.18: 815 | resolution: {integrity: sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==} 816 | engines: {node: '>=12'} 817 | hasBin: true 818 | 819 | esbuild@0.18.17: 820 | resolution: {integrity: sha512-1GJtYnUxsJreHYA0Y+iQz2UEykonY66HNWOb0yXYZi9/kNrORUEHVg87eQsCtqh59PEJ5YVZJO98JHznMJSWjg==} 821 | engines: {node: '>=12'} 822 | hasBin: true 823 | 824 | escalade@3.1.1: 825 | resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} 826 | engines: {node: '>=6'} 827 | 828 | escape-string-regexp@4.0.0: 829 | resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} 830 | engines: {node: '>=10'} 831 | 832 | eslint-config-standard@17.1.0: 833 | resolution: {integrity: sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==} 834 | engines: {node: '>=12.0.0'} 835 | peerDependencies: 836 | eslint: ^8.0.1 837 | eslint-plugin-import: ^2.25.2 838 | eslint-plugin-n: '^15.0.0 || ^16.0.0 ' 839 | eslint-plugin-promise: ^6.0.0 840 | 841 | eslint-import-resolver-node@0.3.7: 842 | resolution: {integrity: sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==} 843 | 844 | eslint-module-utils@2.8.0: 845 | resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} 846 | engines: {node: '>=4'} 847 | peerDependencies: 848 | '@typescript-eslint/parser': '*' 849 | eslint: '*' 850 | eslint-import-resolver-node: '*' 851 | eslint-import-resolver-typescript: '*' 852 | eslint-import-resolver-webpack: '*' 853 | peerDependenciesMeta: 854 | '@typescript-eslint/parser': 855 | optional: true 856 | eslint: 857 | optional: true 858 | eslint-import-resolver-node: 859 | optional: true 860 | eslint-import-resolver-typescript: 861 | optional: true 862 | eslint-import-resolver-webpack: 863 | optional: true 864 | 865 | eslint-plugin-es@4.1.0: 866 | resolution: {integrity: sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==} 867 | engines: {node: '>=8.10.0'} 868 | peerDependencies: 869 | eslint: '>=4.19.1' 870 | 871 | eslint-plugin-import@2.28.0: 872 | resolution: {integrity: sha512-B8s/n+ZluN7sxj9eUf7/pRFERX0r5bnFA2dCaLHy2ZeaQEAz0k+ZZkFWRFHJAqxfxQDx6KLv9LeIki7cFdwW+Q==} 873 | engines: {node: '>=4'} 874 | peerDependencies: 875 | '@typescript-eslint/parser': '*' 876 | eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 877 | peerDependenciesMeta: 878 | '@typescript-eslint/parser': 879 | optional: true 880 | 881 | eslint-plugin-n@15.7.0: 882 | resolution: {integrity: sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q==} 883 | engines: {node: '>=12.22.0'} 884 | peerDependencies: 885 | eslint: '>=7.0.0' 886 | 887 | eslint-plugin-prefer-let@3.0.1: 888 | resolution: {integrity: sha512-vbznkkBSXB63d4o1o0NIm5C2ey3V5wKr/25dAvPdydQXdowAcnr69cbLgxd2YAG81IV5eddCO55Lp6gL7wSE4w==} 889 | engines: {node: '>=0.10.0'} 890 | 891 | eslint-plugin-promise@6.1.1: 892 | resolution: {integrity: sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==} 893 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 894 | peerDependencies: 895 | eslint: ^7.0.0 || ^8.0.0 896 | 897 | eslint-scope@5.1.1: 898 | resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} 899 | engines: {node: '>=8.0.0'} 900 | 901 | eslint-scope@7.2.2: 902 | resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} 903 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 904 | 905 | eslint-utils@2.1.0: 906 | resolution: {integrity: sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==} 907 | engines: {node: '>=6'} 908 | 909 | eslint-utils@3.0.0: 910 | resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} 911 | engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} 912 | peerDependencies: 913 | eslint: '>=5' 914 | 915 | eslint-visitor-keys@1.3.0: 916 | resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==} 917 | engines: {node: '>=4'} 918 | 919 | eslint-visitor-keys@2.1.0: 920 | resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} 921 | engines: {node: '>=10'} 922 | 923 | eslint-visitor-keys@3.4.2: 924 | resolution: {integrity: sha512-8drBzUEyZ2llkpCA67iYrgEssKDUu68V8ChqqOfFupIaG/LCVPUT+CoGJpT77zJprs4T/W7p07LP7zAIMuweVw==} 925 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 926 | 927 | eslint@8.46.0: 928 | resolution: {integrity: sha512-cIO74PvbW0qU8e0mIvk5IV3ToWdCq5FYG6gWPHHkx6gNdjlbAYvtfHmlCMXxjcoVaIdwy/IAt3+mDkZkfvb2Dg==} 929 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 930 | hasBin: true 931 | 932 | espree@9.6.1: 933 | resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} 934 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 935 | 936 | esquery@1.5.0: 937 | resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} 938 | engines: {node: '>=0.10'} 939 | 940 | esrecurse@4.3.0: 941 | resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} 942 | engines: {node: '>=4.0'} 943 | 944 | estraverse@4.3.0: 945 | resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} 946 | engines: {node: '>=4.0'} 947 | 948 | estraverse@5.3.0: 949 | resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} 950 | engines: {node: '>=4.0'} 951 | 952 | esutils@2.0.3: 953 | resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} 954 | engines: {node: '>=0.10.0'} 955 | 956 | fast-deep-equal@3.1.3: 957 | resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} 958 | 959 | fast-glob@3.3.1: 960 | resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} 961 | engines: {node: '>=8.6.0'} 962 | 963 | fast-json-stable-stringify@2.1.0: 964 | resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} 965 | 966 | fast-levenshtein@2.0.6: 967 | resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} 968 | 969 | fastq@1.15.0: 970 | resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} 971 | 972 | file-entry-cache@6.0.1: 973 | resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} 974 | engines: {node: ^10.12.0 || >=12.0.0} 975 | 976 | fill-range@7.0.1: 977 | resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} 978 | engines: {node: '>=8'} 979 | 980 | find-up@5.0.0: 981 | resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} 982 | engines: {node: '>=10'} 983 | 984 | flat-cache@3.0.4: 985 | resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} 986 | engines: {node: ^10.12.0 || >=12.0.0} 987 | 988 | flatted@3.2.7: 989 | resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} 990 | 991 | for-each@0.3.3: 992 | resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} 993 | 994 | foreground-child@2.0.0: 995 | resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==} 996 | engines: {node: '>=8.0.0'} 997 | 998 | fs.realpath@1.0.0: 999 | resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} 1000 | 1001 | fsevents@2.3.2: 1002 | resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} 1003 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 1004 | os: [darwin] 1005 | 1006 | function-bind@1.1.1: 1007 | resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} 1008 | 1009 | function.prototype.name@1.1.5: 1010 | resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} 1011 | engines: {node: '>= 0.4'} 1012 | 1013 | functions-have-names@1.2.3: 1014 | resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} 1015 | 1016 | get-caller-file@2.0.5: 1017 | resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} 1018 | engines: {node: 6.* || 8.* || >= 10.*} 1019 | 1020 | get-intrinsic@1.2.1: 1021 | resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==} 1022 | 1023 | get-symbol-description@1.0.0: 1024 | resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} 1025 | engines: {node: '>= 0.4'} 1026 | 1027 | glob-parent@5.1.2: 1028 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 1029 | engines: {node: '>= 6'} 1030 | 1031 | glob-parent@6.0.2: 1032 | resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} 1033 | engines: {node: '>=10.13.0'} 1034 | 1035 | glob@7.2.3: 1036 | resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} 1037 | 1038 | globals@13.20.0: 1039 | resolution: {integrity: sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==} 1040 | engines: {node: '>=8'} 1041 | 1042 | globalthis@1.0.3: 1043 | resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} 1044 | engines: {node: '>= 0.4'} 1045 | 1046 | globby@11.1.0: 1047 | resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} 1048 | engines: {node: '>=10'} 1049 | 1050 | gopd@1.0.1: 1051 | resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} 1052 | 1053 | graphemer@1.4.0: 1054 | resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} 1055 | 1056 | has-bigints@1.0.2: 1057 | resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} 1058 | 1059 | has-flag@4.0.0: 1060 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 1061 | engines: {node: '>=8'} 1062 | 1063 | has-property-descriptors@1.0.0: 1064 | resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} 1065 | 1066 | has-proto@1.0.1: 1067 | resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} 1068 | engines: {node: '>= 0.4'} 1069 | 1070 | has-symbols@1.0.3: 1071 | resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} 1072 | engines: {node: '>= 0.4'} 1073 | 1074 | has-tostringtag@1.0.0: 1075 | resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} 1076 | engines: {node: '>= 0.4'} 1077 | 1078 | has@1.0.3: 1079 | resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} 1080 | engines: {node: '>= 0.4.0'} 1081 | 1082 | hoist-non-react-statics@3.3.2: 1083 | resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} 1084 | 1085 | html-escaper@2.0.2: 1086 | resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} 1087 | 1088 | ignore@5.2.4: 1089 | resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} 1090 | engines: {node: '>= 4'} 1091 | 1092 | import-fresh@3.3.0: 1093 | resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} 1094 | engines: {node: '>=6'} 1095 | 1096 | imurmurhash@0.1.4: 1097 | resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} 1098 | engines: {node: '>=0.8.19'} 1099 | 1100 | inflight@1.0.6: 1101 | resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} 1102 | 1103 | inherits@2.0.4: 1104 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 1105 | 1106 | internal-slot@1.0.5: 1107 | resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==} 1108 | engines: {node: '>= 0.4'} 1109 | 1110 | is-array-buffer@3.0.2: 1111 | resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} 1112 | 1113 | is-bigint@1.0.4: 1114 | resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} 1115 | 1116 | is-binary-path@2.1.0: 1117 | resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} 1118 | engines: {node: '>=8'} 1119 | 1120 | is-boolean-object@1.1.2: 1121 | resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} 1122 | engines: {node: '>= 0.4'} 1123 | 1124 | is-buffer@2.0.5: 1125 | resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==} 1126 | engines: {node: '>=4'} 1127 | 1128 | is-callable@1.2.7: 1129 | resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} 1130 | engines: {node: '>= 0.4'} 1131 | 1132 | is-core-module@2.12.1: 1133 | resolution: {integrity: sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==} 1134 | 1135 | is-date-object@1.0.5: 1136 | resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} 1137 | engines: {node: '>= 0.4'} 1138 | 1139 | is-extglob@2.1.1: 1140 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 1141 | engines: {node: '>=0.10.0'} 1142 | 1143 | is-fullwidth-code-point@3.0.0: 1144 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 1145 | engines: {node: '>=8'} 1146 | 1147 | is-glob@4.0.3: 1148 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 1149 | engines: {node: '>=0.10.0'} 1150 | 1151 | is-negative-zero@2.0.2: 1152 | resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} 1153 | engines: {node: '>= 0.4'} 1154 | 1155 | is-number-object@1.0.7: 1156 | resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} 1157 | engines: {node: '>= 0.4'} 1158 | 1159 | is-number@7.0.0: 1160 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 1161 | engines: {node: '>=0.12.0'} 1162 | 1163 | is-path-inside@3.0.3: 1164 | resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} 1165 | engines: {node: '>=8'} 1166 | 1167 | is-regex@1.1.4: 1168 | resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} 1169 | engines: {node: '>= 0.4'} 1170 | 1171 | is-shared-array-buffer@1.0.2: 1172 | resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} 1173 | 1174 | is-string@1.0.7: 1175 | resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} 1176 | engines: {node: '>= 0.4'} 1177 | 1178 | is-symbol@1.0.4: 1179 | resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} 1180 | engines: {node: '>= 0.4'} 1181 | 1182 | is-typed-array@1.1.12: 1183 | resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==} 1184 | engines: {node: '>= 0.4'} 1185 | 1186 | is-weakref@1.0.2: 1187 | resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} 1188 | 1189 | isarray@2.0.5: 1190 | resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} 1191 | 1192 | isexe@2.0.0: 1193 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 1194 | 1195 | istanbul-lib-coverage@3.2.0: 1196 | resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} 1197 | engines: {node: '>=8'} 1198 | 1199 | istanbul-lib-report@3.0.1: 1200 | resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} 1201 | engines: {node: '>=10'} 1202 | 1203 | istanbul-reports@3.1.6: 1204 | resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==} 1205 | engines: {node: '>=8'} 1206 | 1207 | js-tokens@4.0.0: 1208 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} 1209 | 1210 | js-yaml@4.1.0: 1211 | resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} 1212 | hasBin: true 1213 | 1214 | json-schema-traverse@0.4.1: 1215 | resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} 1216 | 1217 | json-stable-stringify-without-jsonify@1.0.1: 1218 | resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} 1219 | 1220 | json5@1.0.2: 1221 | resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} 1222 | hasBin: true 1223 | 1224 | kleur@4.1.5: 1225 | resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} 1226 | engines: {node: '>=6'} 1227 | 1228 | levn@0.4.1: 1229 | resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} 1230 | engines: {node: '>= 0.8.0'} 1231 | 1232 | lilconfig@2.1.0: 1233 | resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} 1234 | engines: {node: '>=10'} 1235 | 1236 | locate-path@6.0.0: 1237 | resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} 1238 | engines: {node: '>=10'} 1239 | 1240 | lodash.merge@4.6.2: 1241 | resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} 1242 | 1243 | loose-envify@1.4.0: 1244 | resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} 1245 | hasBin: true 1246 | 1247 | lru-cache@6.0.0: 1248 | resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} 1249 | engines: {node: '>=10'} 1250 | 1251 | make-dir@4.0.0: 1252 | resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} 1253 | engines: {node: '>=10'} 1254 | 1255 | merge2@1.4.1: 1256 | resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} 1257 | engines: {node: '>= 8'} 1258 | 1259 | micromatch@4.0.5: 1260 | resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} 1261 | engines: {node: '>=8.6'} 1262 | 1263 | minimatch@3.1.2: 1264 | resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} 1265 | 1266 | minimist@1.2.8: 1267 | resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} 1268 | 1269 | mri@1.2.0: 1270 | resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} 1271 | engines: {node: '>=4'} 1272 | 1273 | ms@2.1.2: 1274 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} 1275 | 1276 | ms@2.1.3: 1277 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 1278 | 1279 | nanodelay@2.0.2: 1280 | resolution: {integrity: sha512-6AS5aCSXsjoxq2Jr9CdaAeT60yoYDOTp6po9ziqeOeY6vf6uTEHYSqWql6EFILrM3fEfXgkZ4KqE9L0rTm/wlA==} 1281 | engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} 1282 | 1283 | nanoevents@7.0.1: 1284 | resolution: {integrity: sha512-o6lpKiCxLeijK4hgsqfR6CNToPyRU3keKyyI6uwuHRvpRTbZ0wXw51WRgyldVugZqoJfkGFrjrIenYH3bfEO3Q==} 1285 | engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0} 1286 | 1287 | nanoid@3.3.6: 1288 | resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} 1289 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 1290 | hasBin: true 1291 | 1292 | nanoid@4.0.2: 1293 | resolution: {integrity: sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw==} 1294 | engines: {node: ^14 || ^16 || >=18} 1295 | hasBin: true 1296 | 1297 | nanospinner@1.1.0: 1298 | resolution: {integrity: sha512-yFvNYMig4AthKYfHFl1sLj7B2nkHL4lzdig4osvl9/LdGbXwrdFRoqBS98gsEsOakr0yH+r5NZ/1Y9gdVB8trA==} 1299 | 1300 | nanospy@0.5.0: 1301 | resolution: {integrity: sha512-QxH93ntkjRiSP+gJrBLcgOO3neU6pGhUKjPAJ7rAFag/+tJ+/0lw6dXic+iXUQ/3Cxk4Dp/FwLnf57xnQsjecQ==} 1302 | engines: {node: ^8.0.0 || ^10.0.0 || ^12.0.0 || ^14.0.0 || >=16.0.0} 1303 | 1304 | nanostores@0.6.0: 1305 | resolution: {integrity: sha512-CQpKE8wtaJAr66hbg32t0MOAeybzLywU6UsLAX18kyQL/bME+xwhjWpmrvJRBp5kueFy6hs2oHlt3HFpNP+JaA==} 1306 | engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0} 1307 | 1308 | natural-compare-lite@1.4.0: 1309 | resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} 1310 | 1311 | natural-compare@1.4.0: 1312 | resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} 1313 | 1314 | normalize-path@3.0.0: 1315 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} 1316 | engines: {node: '>=0.10.0'} 1317 | 1318 | object-assign@4.1.1: 1319 | resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} 1320 | engines: {node: '>=0.10.0'} 1321 | 1322 | object-inspect@1.12.3: 1323 | resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} 1324 | 1325 | object-keys@1.1.1: 1326 | resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} 1327 | engines: {node: '>= 0.4'} 1328 | 1329 | object.assign@4.1.4: 1330 | resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} 1331 | engines: {node: '>= 0.4'} 1332 | 1333 | object.fromentries@2.0.6: 1334 | resolution: {integrity: sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==} 1335 | engines: {node: '>= 0.4'} 1336 | 1337 | object.groupby@1.0.0: 1338 | resolution: {integrity: sha512-70MWG6NfRH9GnbZOikuhPPYzpUpof9iW2J9E4dW7FXTqPNb6rllE6u39SKwwiNh8lCwX3DDb5OgcKGiEBrTTyw==} 1339 | 1340 | object.values@1.1.6: 1341 | resolution: {integrity: sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==} 1342 | engines: {node: '>= 0.4'} 1343 | 1344 | once@1.4.0: 1345 | resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} 1346 | 1347 | optionator@0.9.3: 1348 | resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} 1349 | engines: {node: '>= 0.8.0'} 1350 | 1351 | p-limit@3.1.0: 1352 | resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} 1353 | engines: {node: '>=10'} 1354 | 1355 | p-locate@5.0.0: 1356 | resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} 1357 | engines: {node: '>=10'} 1358 | 1359 | parent-module@1.0.1: 1360 | resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} 1361 | engines: {node: '>=6'} 1362 | 1363 | path-exists@4.0.0: 1364 | resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} 1365 | engines: {node: '>=8'} 1366 | 1367 | path-is-absolute@1.0.1: 1368 | resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} 1369 | engines: {node: '>=0.10.0'} 1370 | 1371 | path-key@3.1.1: 1372 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 1373 | engines: {node: '>=8'} 1374 | 1375 | path-parse@1.0.7: 1376 | resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} 1377 | 1378 | path-type@4.0.0: 1379 | resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} 1380 | engines: {node: '>=8'} 1381 | 1382 | picocolors@1.0.0: 1383 | resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} 1384 | 1385 | picomatch@2.3.1: 1386 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 1387 | engines: {node: '>=8.6'} 1388 | 1389 | prelude-ls@1.2.1: 1390 | resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} 1391 | engines: {node: '>= 0.8.0'} 1392 | 1393 | prettier@2.8.8: 1394 | resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} 1395 | engines: {node: '>=10.13.0'} 1396 | hasBin: true 1397 | 1398 | punycode@2.3.0: 1399 | resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} 1400 | engines: {node: '>=6'} 1401 | 1402 | queue-microtask@1.2.3: 1403 | resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} 1404 | 1405 | react-dom@18.2.0: 1406 | resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} 1407 | peerDependencies: 1408 | react: ^18.2.0 1409 | 1410 | react-is@16.13.1: 1411 | resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} 1412 | 1413 | react-is@18.2.0: 1414 | resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} 1415 | 1416 | react-redux@8.1.2: 1417 | resolution: {integrity: sha512-xJKYI189VwfsFc4CJvHqHlDrzyFTY/3vZACbE+rr/zQ34Xx1wQfB4OTOSeOSNrF6BDVe8OOdxIrAnMGXA3ggfw==} 1418 | peerDependencies: 1419 | '@types/react': ^16.8 || ^17.0 || ^18.0 1420 | '@types/react-dom': ^16.8 || ^17.0 || ^18.0 1421 | react: ^16.8 || ^17.0 || ^18.0 1422 | react-dom: ^16.8 || ^17.0 || ^18.0 1423 | react-native: '>=0.59' 1424 | redux: ^4 || ^5.0.0-beta.0 1425 | peerDependenciesMeta: 1426 | '@types/react': 1427 | optional: true 1428 | '@types/react-dom': 1429 | optional: true 1430 | react-dom: 1431 | optional: true 1432 | react-native: 1433 | optional: true 1434 | redux: 1435 | optional: true 1436 | 1437 | react-shallow-renderer@16.15.0: 1438 | resolution: {integrity: sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==} 1439 | peerDependencies: 1440 | react: ^16.0.0 || ^17.0.0 || ^18.0.0 1441 | 1442 | react-test-renderer@18.2.0: 1443 | resolution: {integrity: sha512-JWD+aQ0lh2gvh4NM3bBM42Kx+XybOxCpgYK7F8ugAlpaTSnWsX+39Z4XkOykGZAHrjwwTZT3x3KxswVWxHPUqA==} 1444 | peerDependencies: 1445 | react: ^18.2.0 1446 | 1447 | react@18.2.0: 1448 | resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} 1449 | engines: {node: '>=0.10.0'} 1450 | 1451 | readdirp@3.6.0: 1452 | resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} 1453 | engines: {node: '>=8.10.0'} 1454 | 1455 | redux@4.2.1: 1456 | resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==} 1457 | 1458 | regenerator-runtime@0.13.11: 1459 | resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} 1460 | 1461 | regexp.prototype.flags@1.5.0: 1462 | resolution: {integrity: sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==} 1463 | engines: {node: '>= 0.4'} 1464 | 1465 | regexpp@3.2.0: 1466 | resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} 1467 | engines: {node: '>=8'} 1468 | 1469 | require-directory@2.1.1: 1470 | resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} 1471 | engines: {node: '>=0.10.0'} 1472 | 1473 | requireindex@1.2.0: 1474 | resolution: {integrity: sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==} 1475 | engines: {node: '>=0.10.5'} 1476 | 1477 | resolve-from@4.0.0: 1478 | resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} 1479 | engines: {node: '>=4'} 1480 | 1481 | resolve@1.22.2: 1482 | resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==} 1483 | hasBin: true 1484 | 1485 | resolve@1.22.3: 1486 | resolution: {integrity: sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==} 1487 | hasBin: true 1488 | 1489 | reusify@1.0.4: 1490 | resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} 1491 | engines: {iojs: '>=1.0.0', node: '>=0.10.0'} 1492 | 1493 | rimraf@3.0.2: 1494 | resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} 1495 | hasBin: true 1496 | 1497 | run-parallel@1.2.0: 1498 | resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} 1499 | 1500 | sade@1.8.1: 1501 | resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} 1502 | engines: {node: '>=6'} 1503 | 1504 | safe-array-concat@1.0.0: 1505 | resolution: {integrity: sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==} 1506 | engines: {node: '>=0.4'} 1507 | 1508 | safe-regex-test@1.0.0: 1509 | resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} 1510 | 1511 | scheduler@0.23.0: 1512 | resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} 1513 | 1514 | semver@6.3.1: 1515 | resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} 1516 | hasBin: true 1517 | 1518 | semver@7.5.3: 1519 | resolution: {integrity: sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==} 1520 | engines: {node: '>=10'} 1521 | hasBin: true 1522 | 1523 | semver@7.5.4: 1524 | resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} 1525 | engines: {node: '>=10'} 1526 | hasBin: true 1527 | 1528 | shebang-command@2.0.0: 1529 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 1530 | engines: {node: '>=8'} 1531 | 1532 | shebang-regex@3.0.0: 1533 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 1534 | engines: {node: '>=8'} 1535 | 1536 | side-channel@1.0.4: 1537 | resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} 1538 | 1539 | signal-exit@3.0.7: 1540 | resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} 1541 | 1542 | size-limit@8.2.6: 1543 | resolution: {integrity: sha512-zpznim/tX/NegjoQuRKgWTF4XiB0cn2qt90uJzxYNTFAqexk4b94DOAkBD3TwhC6c3kw2r0KcnA5upziVMZqDg==} 1544 | engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0} 1545 | hasBin: true 1546 | 1547 | slash@3.0.0: 1548 | resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} 1549 | engines: {node: '>=8'} 1550 | 1551 | string-width@4.2.3: 1552 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 1553 | engines: {node: '>=8'} 1554 | 1555 | string.prototype.trim@1.2.7: 1556 | resolution: {integrity: sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==} 1557 | engines: {node: '>= 0.4'} 1558 | 1559 | string.prototype.trimend@1.0.6: 1560 | resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==} 1561 | 1562 | string.prototype.trimstart@1.0.6: 1563 | resolution: {integrity: sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==} 1564 | 1565 | strip-ansi@6.0.1: 1566 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 1567 | engines: {node: '>=8'} 1568 | 1569 | strip-bom@3.0.0: 1570 | resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} 1571 | engines: {node: '>=4'} 1572 | 1573 | strip-json-comments@3.1.1: 1574 | resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} 1575 | engines: {node: '>=8'} 1576 | 1577 | supports-color@7.2.0: 1578 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 1579 | engines: {node: '>=8'} 1580 | 1581 | supports-preserve-symlinks-flag@1.0.0: 1582 | resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} 1583 | engines: {node: '>= 0.4'} 1584 | 1585 | test-exclude@6.0.0: 1586 | resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} 1587 | engines: {node: '>=8'} 1588 | 1589 | text-table@0.2.0: 1590 | resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} 1591 | 1592 | to-regex-range@5.0.1: 1593 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 1594 | engines: {node: '>=8.0'} 1595 | 1596 | tsconfig-paths@3.14.2: 1597 | resolution: {integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==} 1598 | 1599 | tslib@1.14.1: 1600 | resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} 1601 | 1602 | tsm@2.3.0: 1603 | resolution: {integrity: sha512-++0HFnmmR+gMpDtKTnW3XJ4yv9kVGi20n+NfyQWB9qwJvTaIWY9kBmzek2YUQK5APTQ/1DTrXmm4QtFPmW9Rzw==} 1604 | engines: {node: '>=12'} 1605 | hasBin: true 1606 | 1607 | tsutils@3.21.0: 1608 | resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} 1609 | engines: {node: '>= 6'} 1610 | peerDependencies: 1611 | typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' 1612 | 1613 | type-check@0.4.0: 1614 | resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} 1615 | engines: {node: '>= 0.8.0'} 1616 | 1617 | type-fest@0.20.2: 1618 | resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} 1619 | engines: {node: '>=10'} 1620 | 1621 | typed-array-buffer@1.0.0: 1622 | resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} 1623 | engines: {node: '>= 0.4'} 1624 | 1625 | typed-array-byte-length@1.0.0: 1626 | resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} 1627 | engines: {node: '>= 0.4'} 1628 | 1629 | typed-array-byte-offset@1.0.0: 1630 | resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} 1631 | engines: {node: '>= 0.4'} 1632 | 1633 | typed-array-length@1.0.4: 1634 | resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} 1635 | 1636 | typescript@5.1.6: 1637 | resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==} 1638 | engines: {node: '>=14.17'} 1639 | hasBin: true 1640 | 1641 | unbox-primitive@1.0.2: 1642 | resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} 1643 | 1644 | unist-util-stringify-position@3.0.3: 1645 | resolution: {integrity: sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==} 1646 | 1647 | uri-js@4.4.1: 1648 | resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} 1649 | 1650 | use-sync-external-store@1.2.0: 1651 | resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} 1652 | peerDependencies: 1653 | react: ^16.8.0 || ^17.0.0 || ^18.0.0 1654 | 1655 | uvu@0.5.6: 1656 | resolution: {integrity: sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==} 1657 | engines: {node: '>=8'} 1658 | hasBin: true 1659 | 1660 | v8-to-istanbul@9.1.0: 1661 | resolution: {integrity: sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==} 1662 | engines: {node: '>=10.12.0'} 1663 | 1664 | vfile-location@4.1.0: 1665 | resolution: {integrity: sha512-YF23YMyASIIJXpktBa4vIGLJ5Gs88UB/XePgqPmTa7cDA+JeO3yclbpheQYCHjVHBn/yePzrXuygIL+xbvRYHw==} 1666 | 1667 | vfile-message@3.1.4: 1668 | resolution: {integrity: sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==} 1669 | 1670 | vfile@5.3.7: 1671 | resolution: {integrity: sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==} 1672 | 1673 | which-boxed-primitive@1.0.2: 1674 | resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} 1675 | 1676 | which-typed-array@1.1.11: 1677 | resolution: {integrity: sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==} 1678 | engines: {node: '>= 0.4'} 1679 | 1680 | which@2.0.2: 1681 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 1682 | engines: {node: '>= 8'} 1683 | hasBin: true 1684 | 1685 | wrap-ansi@7.0.0: 1686 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} 1687 | engines: {node: '>=10'} 1688 | 1689 | wrappy@1.0.2: 1690 | resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} 1691 | 1692 | y18n@5.0.8: 1693 | resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} 1694 | engines: {node: '>=10'} 1695 | 1696 | yallist@4.0.0: 1697 | resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} 1698 | 1699 | yargs-parser@20.2.9: 1700 | resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} 1701 | engines: {node: '>=10'} 1702 | 1703 | yargs@16.2.0: 1704 | resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} 1705 | engines: {node: '>=10'} 1706 | 1707 | yocto-queue@0.1.0: 1708 | resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} 1709 | engines: {node: '>=10'} 1710 | 1711 | snapshots: 1712 | 1713 | '@aashutoshrathi/word-wrap@1.2.6': {} 1714 | 1715 | '@babel/runtime@7.22.6': 1716 | dependencies: 1717 | regenerator-runtime: 0.13.11 1718 | 1719 | '@bcoe/v8-coverage@0.2.3': {} 1720 | 1721 | '@esbuild/android-arm64@0.18.17': 1722 | optional: true 1723 | 1724 | '@esbuild/android-arm@0.15.18': 1725 | optional: true 1726 | 1727 | '@esbuild/android-arm@0.18.17': 1728 | optional: true 1729 | 1730 | '@esbuild/android-x64@0.18.17': 1731 | optional: true 1732 | 1733 | '@esbuild/darwin-arm64@0.18.17': 1734 | optional: true 1735 | 1736 | '@esbuild/darwin-x64@0.18.17': 1737 | optional: true 1738 | 1739 | '@esbuild/freebsd-arm64@0.18.17': 1740 | optional: true 1741 | 1742 | '@esbuild/freebsd-x64@0.18.17': 1743 | optional: true 1744 | 1745 | '@esbuild/linux-arm64@0.18.17': 1746 | optional: true 1747 | 1748 | '@esbuild/linux-arm@0.18.17': 1749 | optional: true 1750 | 1751 | '@esbuild/linux-ia32@0.18.17': 1752 | optional: true 1753 | 1754 | '@esbuild/linux-loong64@0.15.18': 1755 | optional: true 1756 | 1757 | '@esbuild/linux-loong64@0.18.17': 1758 | optional: true 1759 | 1760 | '@esbuild/linux-mips64el@0.18.17': 1761 | optional: true 1762 | 1763 | '@esbuild/linux-ppc64@0.18.17': 1764 | optional: true 1765 | 1766 | '@esbuild/linux-riscv64@0.18.17': 1767 | optional: true 1768 | 1769 | '@esbuild/linux-s390x@0.18.17': 1770 | optional: true 1771 | 1772 | '@esbuild/linux-x64@0.18.17': 1773 | optional: true 1774 | 1775 | '@esbuild/netbsd-x64@0.18.17': 1776 | optional: true 1777 | 1778 | '@esbuild/openbsd-x64@0.18.17': 1779 | optional: true 1780 | 1781 | '@esbuild/sunos-x64@0.18.17': 1782 | optional: true 1783 | 1784 | '@esbuild/win32-arm64@0.18.17': 1785 | optional: true 1786 | 1787 | '@esbuild/win32-ia32@0.18.17': 1788 | optional: true 1789 | 1790 | '@esbuild/win32-x64@0.18.17': 1791 | optional: true 1792 | 1793 | '@eslint-community/eslint-utils@4.4.0(eslint@8.46.0)': 1794 | dependencies: 1795 | eslint: 8.46.0 1796 | eslint-visitor-keys: 3.4.2 1797 | 1798 | '@eslint-community/regexpp@4.6.2': {} 1799 | 1800 | '@eslint/eslintrc@2.1.1': 1801 | dependencies: 1802 | ajv: 6.12.6 1803 | debug: 4.3.4 1804 | espree: 9.6.1 1805 | globals: 13.20.0 1806 | ignore: 5.2.4 1807 | import-fresh: 3.3.0 1808 | js-yaml: 4.1.0 1809 | minimatch: 3.1.2 1810 | strip-json-comments: 3.1.1 1811 | transitivePeerDependencies: 1812 | - supports-color 1813 | 1814 | '@eslint/js@8.46.0': {} 1815 | 1816 | '@humanwhocodes/config-array@0.11.10': 1817 | dependencies: 1818 | '@humanwhocodes/object-schema': 1.2.1 1819 | debug: 4.3.4 1820 | minimatch: 3.1.2 1821 | transitivePeerDependencies: 1822 | - supports-color 1823 | 1824 | '@humanwhocodes/module-importer@1.0.1': {} 1825 | 1826 | '@humanwhocodes/object-schema@1.2.1': {} 1827 | 1828 | '@istanbuljs/schema@0.1.3': {} 1829 | 1830 | '@jridgewell/resolve-uri@3.1.0': {} 1831 | 1832 | '@jridgewell/sourcemap-codec@1.4.14': {} 1833 | 1834 | '@jridgewell/trace-mapping@0.3.18': 1835 | dependencies: 1836 | '@jridgewell/resolve-uri': 3.1.0 1837 | '@jridgewell/sourcemap-codec': 1.4.14 1838 | 1839 | '@logux/actions@0.3.1(@logux/core@0.8.4)': 1840 | dependencies: 1841 | '@logux/core': 0.8.4 1842 | 1843 | '@logux/client@0.18.4(@logux/core@0.8.4)(nanostores@0.6.0)(react-dom@18.2.0)(react@18.2.0)': 1844 | dependencies: 1845 | '@logux/actions': 0.3.1(@logux/core@0.8.4) 1846 | '@logux/core': 0.8.4 1847 | fast-json-stable-stringify: 2.1.0 1848 | nanodelay: 2.0.2 1849 | nanoevents: 7.0.1 1850 | nanoid: 4.0.2 1851 | nanostores: 0.6.0 1852 | react: 18.2.0 1853 | react-dom: 18.2.0(react@18.2.0) 1854 | 1855 | '@logux/core@0.8.4': 1856 | dependencies: 1857 | nanoevents: 7.0.1 1858 | 1859 | '@logux/eslint-config@49.0.0(eslint-config-standard@17.1.0)(eslint-plugin-import@2.28.0)(eslint-plugin-n@15.7.0)(eslint-plugin-prefer-let@3.0.1)(eslint-plugin-promise@6.1.1)(eslint@8.46.0)': 1860 | dependencies: 1861 | eslint: 8.46.0 1862 | eslint-config-standard: 17.1.0(eslint-plugin-import@2.28.0)(eslint-plugin-n@15.7.0)(eslint-plugin-promise@6.1.1)(eslint@8.46.0) 1863 | eslint-plugin-import: 2.28.0(@typescript-eslint/parser@5.62.0)(eslint@8.46.0) 1864 | eslint-plugin-n: 15.7.0(eslint@8.46.0) 1865 | eslint-plugin-prefer-let: 3.0.1 1866 | eslint-plugin-promise: 6.1.1(eslint@8.46.0) 1867 | 1868 | '@nodelib/fs.scandir@2.1.5': 1869 | dependencies: 1870 | '@nodelib/fs.stat': 2.0.5 1871 | run-parallel: 1.2.0 1872 | 1873 | '@nodelib/fs.stat@2.0.5': {} 1874 | 1875 | '@nodelib/fs.walk@1.2.8': 1876 | dependencies: 1877 | '@nodelib/fs.scandir': 2.1.5 1878 | fastq: 1.15.0 1879 | 1880 | '@size-limit/esbuild@8.2.6(size-limit@8.2.6)': 1881 | dependencies: 1882 | esbuild: 0.18.17 1883 | nanoid: 3.3.6 1884 | size-limit: 8.2.6 1885 | 1886 | '@size-limit/file@8.2.6(size-limit@8.2.6)': 1887 | dependencies: 1888 | semver: 7.5.3 1889 | size-limit: 8.2.6 1890 | 1891 | '@size-limit/preset-small-lib@8.2.6(size-limit@8.2.6)': 1892 | dependencies: 1893 | '@size-limit/esbuild': 8.2.6(size-limit@8.2.6) 1894 | '@size-limit/file': 8.2.6(size-limit@8.2.6) 1895 | size-limit: 8.2.6 1896 | 1897 | '@types/hoist-non-react-statics@3.3.1': 1898 | dependencies: 1899 | '@types/react': 18.2.18 1900 | hoist-non-react-statics: 3.3.2 1901 | 1902 | '@types/istanbul-lib-coverage@2.0.4': {} 1903 | 1904 | '@types/json-schema@7.0.12': {} 1905 | 1906 | '@types/json5@0.0.29': {} 1907 | 1908 | '@types/node@18.17.2': {} 1909 | 1910 | '@types/prop-types@15.7.5': {} 1911 | 1912 | '@types/react-redux@7.1.25': 1913 | dependencies: 1914 | '@types/hoist-non-react-statics': 3.3.1 1915 | '@types/react': 18.2.18 1916 | hoist-non-react-statics: 3.3.2 1917 | redux: 4.2.1 1918 | 1919 | '@types/react-test-renderer@18.0.0': 1920 | dependencies: 1921 | '@types/react': 18.2.18 1922 | 1923 | '@types/react@18.2.18': 1924 | dependencies: 1925 | '@types/prop-types': 15.7.5 1926 | '@types/scheduler': 0.16.3 1927 | csstype: 3.1.2 1928 | 1929 | '@types/scheduler@0.16.3': {} 1930 | 1931 | '@types/semver@7.5.0': {} 1932 | 1933 | '@types/unist@2.0.7': {} 1934 | 1935 | '@types/use-sync-external-store@0.0.3': {} 1936 | 1937 | '@types/ws@8.5.5': 1938 | dependencies: 1939 | '@types/node': 18.17.2 1940 | 1941 | '@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.46.0)(typescript@5.1.6)': 1942 | dependencies: 1943 | '@eslint-community/regexpp': 4.6.2 1944 | '@typescript-eslint/parser': 5.62.0(eslint@8.46.0)(typescript@5.1.6) 1945 | '@typescript-eslint/scope-manager': 5.62.0 1946 | '@typescript-eslint/type-utils': 5.62.0(eslint@8.46.0)(typescript@5.1.6) 1947 | '@typescript-eslint/utils': 5.62.0(eslint@8.46.0)(typescript@5.1.6) 1948 | debug: 4.3.4 1949 | eslint: 8.46.0 1950 | graphemer: 1.4.0 1951 | ignore: 5.2.4 1952 | natural-compare-lite: 1.4.0 1953 | semver: 7.5.4 1954 | tsutils: 3.21.0(typescript@5.1.6) 1955 | typescript: 5.1.6 1956 | transitivePeerDependencies: 1957 | - supports-color 1958 | 1959 | '@typescript-eslint/parser@5.62.0(eslint@8.46.0)(typescript@5.1.6)': 1960 | dependencies: 1961 | '@typescript-eslint/scope-manager': 5.62.0 1962 | '@typescript-eslint/types': 5.62.0 1963 | '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.1.6) 1964 | debug: 4.3.4 1965 | eslint: 8.46.0 1966 | typescript: 5.1.6 1967 | transitivePeerDependencies: 1968 | - supports-color 1969 | 1970 | '@typescript-eslint/scope-manager@5.62.0': 1971 | dependencies: 1972 | '@typescript-eslint/types': 5.62.0 1973 | '@typescript-eslint/visitor-keys': 5.62.0 1974 | 1975 | '@typescript-eslint/type-utils@5.62.0(eslint@8.46.0)(typescript@5.1.6)': 1976 | dependencies: 1977 | '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.1.6) 1978 | '@typescript-eslint/utils': 5.62.0(eslint@8.46.0)(typescript@5.1.6) 1979 | debug: 4.3.4 1980 | eslint: 8.46.0 1981 | tsutils: 3.21.0(typescript@5.1.6) 1982 | typescript: 5.1.6 1983 | transitivePeerDependencies: 1984 | - supports-color 1985 | 1986 | '@typescript-eslint/types@5.62.0': {} 1987 | 1988 | '@typescript-eslint/typescript-estree@5.62.0(typescript@5.1.6)': 1989 | dependencies: 1990 | '@typescript-eslint/types': 5.62.0 1991 | '@typescript-eslint/visitor-keys': 5.62.0 1992 | debug: 4.3.4 1993 | globby: 11.1.0 1994 | is-glob: 4.0.3 1995 | semver: 7.5.4 1996 | tsutils: 3.21.0(typescript@5.1.6) 1997 | typescript: 5.1.6 1998 | transitivePeerDependencies: 1999 | - supports-color 2000 | 2001 | '@typescript-eslint/utils@5.62.0(eslint@8.46.0)(typescript@5.1.6)': 2002 | dependencies: 2003 | '@eslint-community/eslint-utils': 4.4.0(eslint@8.46.0) 2004 | '@types/json-schema': 7.0.12 2005 | '@types/semver': 7.5.0 2006 | '@typescript-eslint/scope-manager': 5.62.0 2007 | '@typescript-eslint/types': 5.62.0 2008 | '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.1.6) 2009 | eslint: 8.46.0 2010 | eslint-scope: 5.1.1 2011 | semver: 7.5.4 2012 | transitivePeerDependencies: 2013 | - supports-color 2014 | - typescript 2015 | 2016 | '@typescript-eslint/visitor-keys@5.62.0': 2017 | dependencies: 2018 | '@typescript-eslint/types': 5.62.0 2019 | eslint-visitor-keys: 3.4.2 2020 | 2021 | acorn-jsx@5.3.2(acorn@8.10.0): 2022 | dependencies: 2023 | acorn: 8.10.0 2024 | 2025 | acorn@8.10.0: {} 2026 | 2027 | ajv@6.12.6: 2028 | dependencies: 2029 | fast-deep-equal: 3.1.3 2030 | fast-json-stable-stringify: 2.1.0 2031 | json-schema-traverse: 0.4.1 2032 | uri-js: 4.4.1 2033 | 2034 | ansi-regex@5.0.1: {} 2035 | 2036 | ansi-styles@4.3.0: 2037 | dependencies: 2038 | color-convert: 2.0.1 2039 | 2040 | anymatch@3.1.3: 2041 | dependencies: 2042 | normalize-path: 3.0.0 2043 | picomatch: 2.3.1 2044 | 2045 | argparse@2.0.1: {} 2046 | 2047 | array-buffer-byte-length@1.0.0: 2048 | dependencies: 2049 | call-bind: 1.0.2 2050 | is-array-buffer: 3.0.2 2051 | 2052 | array-includes@3.1.6: 2053 | dependencies: 2054 | call-bind: 1.0.2 2055 | define-properties: 1.2.0 2056 | es-abstract: 1.22.1 2057 | get-intrinsic: 1.2.1 2058 | is-string: 1.0.7 2059 | 2060 | array-union@2.1.0: {} 2061 | 2062 | array.prototype.findlastindex@1.2.2: 2063 | dependencies: 2064 | call-bind: 1.0.2 2065 | define-properties: 1.2.0 2066 | es-abstract: 1.22.1 2067 | es-shim-unscopables: 1.0.0 2068 | get-intrinsic: 1.2.1 2069 | 2070 | array.prototype.flat@1.3.1: 2071 | dependencies: 2072 | call-bind: 1.0.2 2073 | define-properties: 1.2.0 2074 | es-abstract: 1.22.1 2075 | es-shim-unscopables: 1.0.0 2076 | 2077 | array.prototype.flatmap@1.3.1: 2078 | dependencies: 2079 | call-bind: 1.0.2 2080 | define-properties: 1.2.0 2081 | es-abstract: 1.22.1 2082 | es-shim-unscopables: 1.0.0 2083 | 2084 | arraybuffer.prototype.slice@1.0.1: 2085 | dependencies: 2086 | array-buffer-byte-length: 1.0.0 2087 | call-bind: 1.0.2 2088 | define-properties: 1.2.0 2089 | get-intrinsic: 1.2.1 2090 | is-array-buffer: 3.0.2 2091 | is-shared-array-buffer: 1.0.2 2092 | 2093 | available-typed-arrays@1.0.5: {} 2094 | 2095 | balanced-match@1.0.2: {} 2096 | 2097 | binary-extensions@2.2.0: {} 2098 | 2099 | brace-expansion@1.1.11: 2100 | dependencies: 2101 | balanced-match: 1.0.2 2102 | concat-map: 0.0.1 2103 | 2104 | braces@3.0.2: 2105 | dependencies: 2106 | fill-range: 7.0.1 2107 | 2108 | builtins@5.0.1: 2109 | dependencies: 2110 | semver: 7.5.4 2111 | 2112 | bytes-iec@3.1.1: {} 2113 | 2114 | c8@7.14.0: 2115 | dependencies: 2116 | '@bcoe/v8-coverage': 0.2.3 2117 | '@istanbuljs/schema': 0.1.3 2118 | find-up: 5.0.0 2119 | foreground-child: 2.0.0 2120 | istanbul-lib-coverage: 3.2.0 2121 | istanbul-lib-report: 3.0.1 2122 | istanbul-reports: 3.1.6 2123 | rimraf: 3.0.2 2124 | test-exclude: 6.0.0 2125 | v8-to-istanbul: 9.1.0 2126 | yargs: 16.2.0 2127 | yargs-parser: 20.2.9 2128 | 2129 | call-bind@1.0.2: 2130 | dependencies: 2131 | function-bind: 1.1.1 2132 | get-intrinsic: 1.2.1 2133 | 2134 | callsites@3.1.0: {} 2135 | 2136 | chalk@4.1.2: 2137 | dependencies: 2138 | ansi-styles: 4.3.0 2139 | supports-color: 7.2.0 2140 | 2141 | check-dts@0.7.2(typescript@5.1.6): 2142 | dependencies: 2143 | fast-glob: 3.3.1 2144 | nanospinner: 1.1.0 2145 | picocolors: 1.0.0 2146 | typescript: 5.1.6 2147 | vfile-location: 4.1.0 2148 | 2149 | chokidar@3.5.3: 2150 | dependencies: 2151 | anymatch: 3.1.3 2152 | braces: 3.0.2 2153 | glob-parent: 5.1.2 2154 | is-binary-path: 2.1.0 2155 | is-glob: 4.0.3 2156 | normalize-path: 3.0.0 2157 | readdirp: 3.6.0 2158 | optionalDependencies: 2159 | fsevents: 2.3.2 2160 | 2161 | clean-publish@4.2.0: 2162 | dependencies: 2163 | cross-spawn: 7.0.3 2164 | fast-glob: 3.3.1 2165 | lilconfig: 2.1.0 2166 | micromatch: 4.0.5 2167 | 2168 | cliui@7.0.4: 2169 | dependencies: 2170 | string-width: 4.2.3 2171 | strip-ansi: 6.0.1 2172 | wrap-ansi: 7.0.0 2173 | 2174 | color-convert@2.0.1: 2175 | dependencies: 2176 | color-name: 1.1.4 2177 | 2178 | color-name@1.1.4: {} 2179 | 2180 | concat-map@0.0.1: {} 2181 | 2182 | convert-source-map@1.9.0: {} 2183 | 2184 | cross-spawn@7.0.3: 2185 | dependencies: 2186 | path-key: 3.1.1 2187 | shebang-command: 2.0.0 2188 | which: 2.0.2 2189 | 2190 | csstype@3.1.2: {} 2191 | 2192 | debug@3.2.7: 2193 | dependencies: 2194 | ms: 2.1.3 2195 | 2196 | debug@4.3.4: 2197 | dependencies: 2198 | ms: 2.1.2 2199 | 2200 | deep-is@0.1.4: {} 2201 | 2202 | define-properties@1.2.0: 2203 | dependencies: 2204 | has-property-descriptors: 1.0.0 2205 | object-keys: 1.1.1 2206 | 2207 | dequal@2.0.3: {} 2208 | 2209 | diff@5.1.0: {} 2210 | 2211 | dir-glob@3.0.1: 2212 | dependencies: 2213 | path-type: 4.0.0 2214 | 2215 | doctrine@2.1.0: 2216 | dependencies: 2217 | esutils: 2.0.3 2218 | 2219 | doctrine@3.0.0: 2220 | dependencies: 2221 | esutils: 2.0.3 2222 | 2223 | emoji-regex@8.0.0: {} 2224 | 2225 | es-abstract@1.22.1: 2226 | dependencies: 2227 | array-buffer-byte-length: 1.0.0 2228 | arraybuffer.prototype.slice: 1.0.1 2229 | available-typed-arrays: 1.0.5 2230 | call-bind: 1.0.2 2231 | es-set-tostringtag: 2.0.1 2232 | es-to-primitive: 1.2.1 2233 | function.prototype.name: 1.1.5 2234 | get-intrinsic: 1.2.1 2235 | get-symbol-description: 1.0.0 2236 | globalthis: 1.0.3 2237 | gopd: 1.0.1 2238 | has: 1.0.3 2239 | has-property-descriptors: 1.0.0 2240 | has-proto: 1.0.1 2241 | has-symbols: 1.0.3 2242 | internal-slot: 1.0.5 2243 | is-array-buffer: 3.0.2 2244 | is-callable: 1.2.7 2245 | is-negative-zero: 2.0.2 2246 | is-regex: 1.1.4 2247 | is-shared-array-buffer: 1.0.2 2248 | is-string: 1.0.7 2249 | is-typed-array: 1.1.12 2250 | is-weakref: 1.0.2 2251 | object-inspect: 1.12.3 2252 | object-keys: 1.1.1 2253 | object.assign: 4.1.4 2254 | regexp.prototype.flags: 1.5.0 2255 | safe-array-concat: 1.0.0 2256 | safe-regex-test: 1.0.0 2257 | string.prototype.trim: 1.2.7 2258 | string.prototype.trimend: 1.0.6 2259 | string.prototype.trimstart: 1.0.6 2260 | typed-array-buffer: 1.0.0 2261 | typed-array-byte-length: 1.0.0 2262 | typed-array-byte-offset: 1.0.0 2263 | typed-array-length: 1.0.4 2264 | unbox-primitive: 1.0.2 2265 | which-typed-array: 1.1.11 2266 | 2267 | es-set-tostringtag@2.0.1: 2268 | dependencies: 2269 | get-intrinsic: 1.2.1 2270 | has: 1.0.3 2271 | has-tostringtag: 1.0.0 2272 | 2273 | es-shim-unscopables@1.0.0: 2274 | dependencies: 2275 | has: 1.0.3 2276 | 2277 | es-to-primitive@1.2.1: 2278 | dependencies: 2279 | is-callable: 1.2.7 2280 | is-date-object: 1.0.5 2281 | is-symbol: 1.0.4 2282 | 2283 | esbuild-android-64@0.15.18: 2284 | optional: true 2285 | 2286 | esbuild-android-arm64@0.15.18: 2287 | optional: true 2288 | 2289 | esbuild-darwin-64@0.15.18: 2290 | optional: true 2291 | 2292 | esbuild-darwin-arm64@0.15.18: 2293 | optional: true 2294 | 2295 | esbuild-freebsd-64@0.15.18: 2296 | optional: true 2297 | 2298 | esbuild-freebsd-arm64@0.15.18: 2299 | optional: true 2300 | 2301 | esbuild-linux-32@0.15.18: 2302 | optional: true 2303 | 2304 | esbuild-linux-64@0.15.18: 2305 | optional: true 2306 | 2307 | esbuild-linux-arm64@0.15.18: 2308 | optional: true 2309 | 2310 | esbuild-linux-arm@0.15.18: 2311 | optional: true 2312 | 2313 | esbuild-linux-mips64le@0.15.18: 2314 | optional: true 2315 | 2316 | esbuild-linux-ppc64le@0.15.18: 2317 | optional: true 2318 | 2319 | esbuild-linux-riscv64@0.15.18: 2320 | optional: true 2321 | 2322 | esbuild-linux-s390x@0.15.18: 2323 | optional: true 2324 | 2325 | esbuild-netbsd-64@0.15.18: 2326 | optional: true 2327 | 2328 | esbuild-openbsd-64@0.15.18: 2329 | optional: true 2330 | 2331 | esbuild-sunos-64@0.15.18: 2332 | optional: true 2333 | 2334 | esbuild-windows-32@0.15.18: 2335 | optional: true 2336 | 2337 | esbuild-windows-64@0.15.18: 2338 | optional: true 2339 | 2340 | esbuild-windows-arm64@0.15.18: 2341 | optional: true 2342 | 2343 | esbuild@0.15.18: 2344 | optionalDependencies: 2345 | '@esbuild/android-arm': 0.15.18 2346 | '@esbuild/linux-loong64': 0.15.18 2347 | esbuild-android-64: 0.15.18 2348 | esbuild-android-arm64: 0.15.18 2349 | esbuild-darwin-64: 0.15.18 2350 | esbuild-darwin-arm64: 0.15.18 2351 | esbuild-freebsd-64: 0.15.18 2352 | esbuild-freebsd-arm64: 0.15.18 2353 | esbuild-linux-32: 0.15.18 2354 | esbuild-linux-64: 0.15.18 2355 | esbuild-linux-arm: 0.15.18 2356 | esbuild-linux-arm64: 0.15.18 2357 | esbuild-linux-mips64le: 0.15.18 2358 | esbuild-linux-ppc64le: 0.15.18 2359 | esbuild-linux-riscv64: 0.15.18 2360 | esbuild-linux-s390x: 0.15.18 2361 | esbuild-netbsd-64: 0.15.18 2362 | esbuild-openbsd-64: 0.15.18 2363 | esbuild-sunos-64: 0.15.18 2364 | esbuild-windows-32: 0.15.18 2365 | esbuild-windows-64: 0.15.18 2366 | esbuild-windows-arm64: 0.15.18 2367 | 2368 | esbuild@0.18.17: 2369 | optionalDependencies: 2370 | '@esbuild/android-arm': 0.18.17 2371 | '@esbuild/android-arm64': 0.18.17 2372 | '@esbuild/android-x64': 0.18.17 2373 | '@esbuild/darwin-arm64': 0.18.17 2374 | '@esbuild/darwin-x64': 0.18.17 2375 | '@esbuild/freebsd-arm64': 0.18.17 2376 | '@esbuild/freebsd-x64': 0.18.17 2377 | '@esbuild/linux-arm': 0.18.17 2378 | '@esbuild/linux-arm64': 0.18.17 2379 | '@esbuild/linux-ia32': 0.18.17 2380 | '@esbuild/linux-loong64': 0.18.17 2381 | '@esbuild/linux-mips64el': 0.18.17 2382 | '@esbuild/linux-ppc64': 0.18.17 2383 | '@esbuild/linux-riscv64': 0.18.17 2384 | '@esbuild/linux-s390x': 0.18.17 2385 | '@esbuild/linux-x64': 0.18.17 2386 | '@esbuild/netbsd-x64': 0.18.17 2387 | '@esbuild/openbsd-x64': 0.18.17 2388 | '@esbuild/sunos-x64': 0.18.17 2389 | '@esbuild/win32-arm64': 0.18.17 2390 | '@esbuild/win32-ia32': 0.18.17 2391 | '@esbuild/win32-x64': 0.18.17 2392 | 2393 | escalade@3.1.1: {} 2394 | 2395 | escape-string-regexp@4.0.0: {} 2396 | 2397 | eslint-config-standard@17.1.0(eslint-plugin-import@2.28.0)(eslint-plugin-n@15.7.0)(eslint-plugin-promise@6.1.1)(eslint@8.46.0): 2398 | dependencies: 2399 | eslint: 8.46.0 2400 | eslint-plugin-import: 2.28.0(@typescript-eslint/parser@5.62.0)(eslint@8.46.0) 2401 | eslint-plugin-n: 15.7.0(eslint@8.46.0) 2402 | eslint-plugin-promise: 6.1.1(eslint@8.46.0) 2403 | 2404 | eslint-import-resolver-node@0.3.7: 2405 | dependencies: 2406 | debug: 3.2.7 2407 | is-core-module: 2.12.1 2408 | resolve: 1.22.3 2409 | transitivePeerDependencies: 2410 | - supports-color 2411 | 2412 | eslint-module-utils@2.8.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.7)(eslint@8.46.0): 2413 | dependencies: 2414 | '@typescript-eslint/parser': 5.62.0(eslint@8.46.0)(typescript@5.1.6) 2415 | debug: 3.2.7 2416 | eslint: 8.46.0 2417 | eslint-import-resolver-node: 0.3.7 2418 | transitivePeerDependencies: 2419 | - supports-color 2420 | 2421 | eslint-plugin-es@4.1.0(eslint@8.46.0): 2422 | dependencies: 2423 | eslint: 8.46.0 2424 | eslint-utils: 2.1.0 2425 | regexpp: 3.2.0 2426 | 2427 | eslint-plugin-import@2.28.0(@typescript-eslint/parser@5.62.0)(eslint@8.46.0): 2428 | dependencies: 2429 | '@typescript-eslint/parser': 5.62.0(eslint@8.46.0)(typescript@5.1.6) 2430 | array-includes: 3.1.6 2431 | array.prototype.findlastindex: 1.2.2 2432 | array.prototype.flat: 1.3.1 2433 | array.prototype.flatmap: 1.3.1 2434 | debug: 3.2.7 2435 | doctrine: 2.1.0 2436 | eslint: 8.46.0 2437 | eslint-import-resolver-node: 0.3.7 2438 | eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.7)(eslint@8.46.0) 2439 | has: 1.0.3 2440 | is-core-module: 2.12.1 2441 | is-glob: 4.0.3 2442 | minimatch: 3.1.2 2443 | object.fromentries: 2.0.6 2444 | object.groupby: 1.0.0 2445 | object.values: 1.1.6 2446 | resolve: 1.22.3 2447 | semver: 6.3.1 2448 | tsconfig-paths: 3.14.2 2449 | transitivePeerDependencies: 2450 | - eslint-import-resolver-typescript 2451 | - eslint-import-resolver-webpack 2452 | - supports-color 2453 | 2454 | eslint-plugin-n@15.7.0(eslint@8.46.0): 2455 | dependencies: 2456 | builtins: 5.0.1 2457 | eslint: 8.46.0 2458 | eslint-plugin-es: 4.1.0(eslint@8.46.0) 2459 | eslint-utils: 3.0.0(eslint@8.46.0) 2460 | ignore: 5.2.4 2461 | is-core-module: 2.12.1 2462 | minimatch: 3.1.2 2463 | resolve: 1.22.2 2464 | semver: 7.5.4 2465 | 2466 | eslint-plugin-prefer-let@3.0.1: 2467 | dependencies: 2468 | requireindex: 1.2.0 2469 | 2470 | eslint-plugin-promise@6.1.1(eslint@8.46.0): 2471 | dependencies: 2472 | eslint: 8.46.0 2473 | 2474 | eslint-scope@5.1.1: 2475 | dependencies: 2476 | esrecurse: 4.3.0 2477 | estraverse: 4.3.0 2478 | 2479 | eslint-scope@7.2.2: 2480 | dependencies: 2481 | esrecurse: 4.3.0 2482 | estraverse: 5.3.0 2483 | 2484 | eslint-utils@2.1.0: 2485 | dependencies: 2486 | eslint-visitor-keys: 1.3.0 2487 | 2488 | eslint-utils@3.0.0(eslint@8.46.0): 2489 | dependencies: 2490 | eslint: 8.46.0 2491 | eslint-visitor-keys: 2.1.0 2492 | 2493 | eslint-visitor-keys@1.3.0: {} 2494 | 2495 | eslint-visitor-keys@2.1.0: {} 2496 | 2497 | eslint-visitor-keys@3.4.2: {} 2498 | 2499 | eslint@8.46.0: 2500 | dependencies: 2501 | '@eslint-community/eslint-utils': 4.4.0(eslint@8.46.0) 2502 | '@eslint-community/regexpp': 4.6.2 2503 | '@eslint/eslintrc': 2.1.1 2504 | '@eslint/js': 8.46.0 2505 | '@humanwhocodes/config-array': 0.11.10 2506 | '@humanwhocodes/module-importer': 1.0.1 2507 | '@nodelib/fs.walk': 1.2.8 2508 | ajv: 6.12.6 2509 | chalk: 4.1.2 2510 | cross-spawn: 7.0.3 2511 | debug: 4.3.4 2512 | doctrine: 3.0.0 2513 | escape-string-regexp: 4.0.0 2514 | eslint-scope: 7.2.2 2515 | eslint-visitor-keys: 3.4.2 2516 | espree: 9.6.1 2517 | esquery: 1.5.0 2518 | esutils: 2.0.3 2519 | fast-deep-equal: 3.1.3 2520 | file-entry-cache: 6.0.1 2521 | find-up: 5.0.0 2522 | glob-parent: 6.0.2 2523 | globals: 13.20.0 2524 | graphemer: 1.4.0 2525 | ignore: 5.2.4 2526 | imurmurhash: 0.1.4 2527 | is-glob: 4.0.3 2528 | is-path-inside: 3.0.3 2529 | js-yaml: 4.1.0 2530 | json-stable-stringify-without-jsonify: 1.0.1 2531 | levn: 0.4.1 2532 | lodash.merge: 4.6.2 2533 | minimatch: 3.1.2 2534 | natural-compare: 1.4.0 2535 | optionator: 0.9.3 2536 | strip-ansi: 6.0.1 2537 | text-table: 0.2.0 2538 | transitivePeerDependencies: 2539 | - supports-color 2540 | 2541 | espree@9.6.1: 2542 | dependencies: 2543 | acorn: 8.10.0 2544 | acorn-jsx: 5.3.2(acorn@8.10.0) 2545 | eslint-visitor-keys: 3.4.2 2546 | 2547 | esquery@1.5.0: 2548 | dependencies: 2549 | estraverse: 5.3.0 2550 | 2551 | esrecurse@4.3.0: 2552 | dependencies: 2553 | estraverse: 5.3.0 2554 | 2555 | estraverse@4.3.0: {} 2556 | 2557 | estraverse@5.3.0: {} 2558 | 2559 | esutils@2.0.3: {} 2560 | 2561 | fast-deep-equal@3.1.3: {} 2562 | 2563 | fast-glob@3.3.1: 2564 | dependencies: 2565 | '@nodelib/fs.stat': 2.0.5 2566 | '@nodelib/fs.walk': 1.2.8 2567 | glob-parent: 5.1.2 2568 | merge2: 1.4.1 2569 | micromatch: 4.0.5 2570 | 2571 | fast-json-stable-stringify@2.1.0: {} 2572 | 2573 | fast-levenshtein@2.0.6: {} 2574 | 2575 | fastq@1.15.0: 2576 | dependencies: 2577 | reusify: 1.0.4 2578 | 2579 | file-entry-cache@6.0.1: 2580 | dependencies: 2581 | flat-cache: 3.0.4 2582 | 2583 | fill-range@7.0.1: 2584 | dependencies: 2585 | to-regex-range: 5.0.1 2586 | 2587 | find-up@5.0.0: 2588 | dependencies: 2589 | locate-path: 6.0.0 2590 | path-exists: 4.0.0 2591 | 2592 | flat-cache@3.0.4: 2593 | dependencies: 2594 | flatted: 3.2.7 2595 | rimraf: 3.0.2 2596 | 2597 | flatted@3.2.7: {} 2598 | 2599 | for-each@0.3.3: 2600 | dependencies: 2601 | is-callable: 1.2.7 2602 | 2603 | foreground-child@2.0.0: 2604 | dependencies: 2605 | cross-spawn: 7.0.3 2606 | signal-exit: 3.0.7 2607 | 2608 | fs.realpath@1.0.0: {} 2609 | 2610 | fsevents@2.3.2: 2611 | optional: true 2612 | 2613 | function-bind@1.1.1: {} 2614 | 2615 | function.prototype.name@1.1.5: 2616 | dependencies: 2617 | call-bind: 1.0.2 2618 | define-properties: 1.2.0 2619 | es-abstract: 1.22.1 2620 | functions-have-names: 1.2.3 2621 | 2622 | functions-have-names@1.2.3: {} 2623 | 2624 | get-caller-file@2.0.5: {} 2625 | 2626 | get-intrinsic@1.2.1: 2627 | dependencies: 2628 | function-bind: 1.1.1 2629 | has: 1.0.3 2630 | has-proto: 1.0.1 2631 | has-symbols: 1.0.3 2632 | 2633 | get-symbol-description@1.0.0: 2634 | dependencies: 2635 | call-bind: 1.0.2 2636 | get-intrinsic: 1.2.1 2637 | 2638 | glob-parent@5.1.2: 2639 | dependencies: 2640 | is-glob: 4.0.3 2641 | 2642 | glob-parent@6.0.2: 2643 | dependencies: 2644 | is-glob: 4.0.3 2645 | 2646 | glob@7.2.3: 2647 | dependencies: 2648 | fs.realpath: 1.0.0 2649 | inflight: 1.0.6 2650 | inherits: 2.0.4 2651 | minimatch: 3.1.2 2652 | once: 1.4.0 2653 | path-is-absolute: 1.0.1 2654 | 2655 | globals@13.20.0: 2656 | dependencies: 2657 | type-fest: 0.20.2 2658 | 2659 | globalthis@1.0.3: 2660 | dependencies: 2661 | define-properties: 1.2.0 2662 | 2663 | globby@11.1.0: 2664 | dependencies: 2665 | array-union: 2.1.0 2666 | dir-glob: 3.0.1 2667 | fast-glob: 3.3.1 2668 | ignore: 5.2.4 2669 | merge2: 1.4.1 2670 | slash: 3.0.0 2671 | 2672 | gopd@1.0.1: 2673 | dependencies: 2674 | get-intrinsic: 1.2.1 2675 | 2676 | graphemer@1.4.0: {} 2677 | 2678 | has-bigints@1.0.2: {} 2679 | 2680 | has-flag@4.0.0: {} 2681 | 2682 | has-property-descriptors@1.0.0: 2683 | dependencies: 2684 | get-intrinsic: 1.2.1 2685 | 2686 | has-proto@1.0.1: {} 2687 | 2688 | has-symbols@1.0.3: {} 2689 | 2690 | has-tostringtag@1.0.0: 2691 | dependencies: 2692 | has-symbols: 1.0.3 2693 | 2694 | has@1.0.3: 2695 | dependencies: 2696 | function-bind: 1.1.1 2697 | 2698 | hoist-non-react-statics@3.3.2: 2699 | dependencies: 2700 | react-is: 16.13.1 2701 | 2702 | html-escaper@2.0.2: {} 2703 | 2704 | ignore@5.2.4: {} 2705 | 2706 | import-fresh@3.3.0: 2707 | dependencies: 2708 | parent-module: 1.0.1 2709 | resolve-from: 4.0.0 2710 | 2711 | imurmurhash@0.1.4: {} 2712 | 2713 | inflight@1.0.6: 2714 | dependencies: 2715 | once: 1.4.0 2716 | wrappy: 1.0.2 2717 | 2718 | inherits@2.0.4: {} 2719 | 2720 | internal-slot@1.0.5: 2721 | dependencies: 2722 | get-intrinsic: 1.2.1 2723 | has: 1.0.3 2724 | side-channel: 1.0.4 2725 | 2726 | is-array-buffer@3.0.2: 2727 | dependencies: 2728 | call-bind: 1.0.2 2729 | get-intrinsic: 1.2.1 2730 | is-typed-array: 1.1.12 2731 | 2732 | is-bigint@1.0.4: 2733 | dependencies: 2734 | has-bigints: 1.0.2 2735 | 2736 | is-binary-path@2.1.0: 2737 | dependencies: 2738 | binary-extensions: 2.2.0 2739 | 2740 | is-boolean-object@1.1.2: 2741 | dependencies: 2742 | call-bind: 1.0.2 2743 | has-tostringtag: 1.0.0 2744 | 2745 | is-buffer@2.0.5: {} 2746 | 2747 | is-callable@1.2.7: {} 2748 | 2749 | is-core-module@2.12.1: 2750 | dependencies: 2751 | has: 1.0.3 2752 | 2753 | is-date-object@1.0.5: 2754 | dependencies: 2755 | has-tostringtag: 1.0.0 2756 | 2757 | is-extglob@2.1.1: {} 2758 | 2759 | is-fullwidth-code-point@3.0.0: {} 2760 | 2761 | is-glob@4.0.3: 2762 | dependencies: 2763 | is-extglob: 2.1.1 2764 | 2765 | is-negative-zero@2.0.2: {} 2766 | 2767 | is-number-object@1.0.7: 2768 | dependencies: 2769 | has-tostringtag: 1.0.0 2770 | 2771 | is-number@7.0.0: {} 2772 | 2773 | is-path-inside@3.0.3: {} 2774 | 2775 | is-regex@1.1.4: 2776 | dependencies: 2777 | call-bind: 1.0.2 2778 | has-tostringtag: 1.0.0 2779 | 2780 | is-shared-array-buffer@1.0.2: 2781 | dependencies: 2782 | call-bind: 1.0.2 2783 | 2784 | is-string@1.0.7: 2785 | dependencies: 2786 | has-tostringtag: 1.0.0 2787 | 2788 | is-symbol@1.0.4: 2789 | dependencies: 2790 | has-symbols: 1.0.3 2791 | 2792 | is-typed-array@1.1.12: 2793 | dependencies: 2794 | which-typed-array: 1.1.11 2795 | 2796 | is-weakref@1.0.2: 2797 | dependencies: 2798 | call-bind: 1.0.2 2799 | 2800 | isarray@2.0.5: {} 2801 | 2802 | isexe@2.0.0: {} 2803 | 2804 | istanbul-lib-coverage@3.2.0: {} 2805 | 2806 | istanbul-lib-report@3.0.1: 2807 | dependencies: 2808 | istanbul-lib-coverage: 3.2.0 2809 | make-dir: 4.0.0 2810 | supports-color: 7.2.0 2811 | 2812 | istanbul-reports@3.1.6: 2813 | dependencies: 2814 | html-escaper: 2.0.2 2815 | istanbul-lib-report: 3.0.1 2816 | 2817 | js-tokens@4.0.0: {} 2818 | 2819 | js-yaml@4.1.0: 2820 | dependencies: 2821 | argparse: 2.0.1 2822 | 2823 | json-schema-traverse@0.4.1: {} 2824 | 2825 | json-stable-stringify-without-jsonify@1.0.1: {} 2826 | 2827 | json5@1.0.2: 2828 | dependencies: 2829 | minimist: 1.2.8 2830 | 2831 | kleur@4.1.5: {} 2832 | 2833 | levn@0.4.1: 2834 | dependencies: 2835 | prelude-ls: 1.2.1 2836 | type-check: 0.4.0 2837 | 2838 | lilconfig@2.1.0: {} 2839 | 2840 | locate-path@6.0.0: 2841 | dependencies: 2842 | p-locate: 5.0.0 2843 | 2844 | lodash.merge@4.6.2: {} 2845 | 2846 | loose-envify@1.4.0: 2847 | dependencies: 2848 | js-tokens: 4.0.0 2849 | 2850 | lru-cache@6.0.0: 2851 | dependencies: 2852 | yallist: 4.0.0 2853 | 2854 | make-dir@4.0.0: 2855 | dependencies: 2856 | semver: 7.5.4 2857 | 2858 | merge2@1.4.1: {} 2859 | 2860 | micromatch@4.0.5: 2861 | dependencies: 2862 | braces: 3.0.2 2863 | picomatch: 2.3.1 2864 | 2865 | minimatch@3.1.2: 2866 | dependencies: 2867 | brace-expansion: 1.1.11 2868 | 2869 | minimist@1.2.8: {} 2870 | 2871 | mri@1.2.0: {} 2872 | 2873 | ms@2.1.2: {} 2874 | 2875 | ms@2.1.3: {} 2876 | 2877 | nanodelay@2.0.2: {} 2878 | 2879 | nanoevents@7.0.1: {} 2880 | 2881 | nanoid@3.3.6: {} 2882 | 2883 | nanoid@4.0.2: {} 2884 | 2885 | nanospinner@1.1.0: 2886 | dependencies: 2887 | picocolors: 1.0.0 2888 | 2889 | nanospy@0.5.0: {} 2890 | 2891 | nanostores@0.6.0: {} 2892 | 2893 | natural-compare-lite@1.4.0: {} 2894 | 2895 | natural-compare@1.4.0: {} 2896 | 2897 | normalize-path@3.0.0: {} 2898 | 2899 | object-assign@4.1.1: {} 2900 | 2901 | object-inspect@1.12.3: {} 2902 | 2903 | object-keys@1.1.1: {} 2904 | 2905 | object.assign@4.1.4: 2906 | dependencies: 2907 | call-bind: 1.0.2 2908 | define-properties: 1.2.0 2909 | has-symbols: 1.0.3 2910 | object-keys: 1.1.1 2911 | 2912 | object.fromentries@2.0.6: 2913 | dependencies: 2914 | call-bind: 1.0.2 2915 | define-properties: 1.2.0 2916 | es-abstract: 1.22.1 2917 | 2918 | object.groupby@1.0.0: 2919 | dependencies: 2920 | call-bind: 1.0.2 2921 | define-properties: 1.2.0 2922 | es-abstract: 1.22.1 2923 | get-intrinsic: 1.2.1 2924 | 2925 | object.values@1.1.6: 2926 | dependencies: 2927 | call-bind: 1.0.2 2928 | define-properties: 1.2.0 2929 | es-abstract: 1.22.1 2930 | 2931 | once@1.4.0: 2932 | dependencies: 2933 | wrappy: 1.0.2 2934 | 2935 | optionator@0.9.3: 2936 | dependencies: 2937 | '@aashutoshrathi/word-wrap': 1.2.6 2938 | deep-is: 0.1.4 2939 | fast-levenshtein: 2.0.6 2940 | levn: 0.4.1 2941 | prelude-ls: 1.2.1 2942 | type-check: 0.4.0 2943 | 2944 | p-limit@3.1.0: 2945 | dependencies: 2946 | yocto-queue: 0.1.0 2947 | 2948 | p-locate@5.0.0: 2949 | dependencies: 2950 | p-limit: 3.1.0 2951 | 2952 | parent-module@1.0.1: 2953 | dependencies: 2954 | callsites: 3.1.0 2955 | 2956 | path-exists@4.0.0: {} 2957 | 2958 | path-is-absolute@1.0.1: {} 2959 | 2960 | path-key@3.1.1: {} 2961 | 2962 | path-parse@1.0.7: {} 2963 | 2964 | path-type@4.0.0: {} 2965 | 2966 | picocolors@1.0.0: {} 2967 | 2968 | picomatch@2.3.1: {} 2969 | 2970 | prelude-ls@1.2.1: {} 2971 | 2972 | prettier@2.8.8: {} 2973 | 2974 | punycode@2.3.0: {} 2975 | 2976 | queue-microtask@1.2.3: {} 2977 | 2978 | react-dom@18.2.0(react@18.2.0): 2979 | dependencies: 2980 | loose-envify: 1.4.0 2981 | react: 18.2.0 2982 | scheduler: 0.23.0 2983 | 2984 | react-is@16.13.1: {} 2985 | 2986 | react-is@18.2.0: {} 2987 | 2988 | react-redux@8.1.2(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0)(redux@4.2.1): 2989 | dependencies: 2990 | '@babel/runtime': 7.22.6 2991 | '@types/hoist-non-react-statics': 3.3.1 2992 | '@types/react': 18.2.18 2993 | '@types/use-sync-external-store': 0.0.3 2994 | hoist-non-react-statics: 3.3.2 2995 | react: 18.2.0 2996 | react-dom: 18.2.0(react@18.2.0) 2997 | react-is: 18.2.0 2998 | redux: 4.2.1 2999 | use-sync-external-store: 1.2.0(react@18.2.0) 3000 | 3001 | react-shallow-renderer@16.15.0(react@18.2.0): 3002 | dependencies: 3003 | object-assign: 4.1.1 3004 | react: 18.2.0 3005 | react-is: 18.2.0 3006 | 3007 | react-test-renderer@18.2.0(react@18.2.0): 3008 | dependencies: 3009 | react: 18.2.0 3010 | react-is: 18.2.0 3011 | react-shallow-renderer: 16.15.0(react@18.2.0) 3012 | scheduler: 0.23.0 3013 | 3014 | react@18.2.0: 3015 | dependencies: 3016 | loose-envify: 1.4.0 3017 | 3018 | readdirp@3.6.0: 3019 | dependencies: 3020 | picomatch: 2.3.1 3021 | 3022 | redux@4.2.1: 3023 | dependencies: 3024 | '@babel/runtime': 7.22.6 3025 | 3026 | regenerator-runtime@0.13.11: {} 3027 | 3028 | regexp.prototype.flags@1.5.0: 3029 | dependencies: 3030 | call-bind: 1.0.2 3031 | define-properties: 1.2.0 3032 | functions-have-names: 1.2.3 3033 | 3034 | regexpp@3.2.0: {} 3035 | 3036 | require-directory@2.1.1: {} 3037 | 3038 | requireindex@1.2.0: {} 3039 | 3040 | resolve-from@4.0.0: {} 3041 | 3042 | resolve@1.22.2: 3043 | dependencies: 3044 | is-core-module: 2.12.1 3045 | path-parse: 1.0.7 3046 | supports-preserve-symlinks-flag: 1.0.0 3047 | 3048 | resolve@1.22.3: 3049 | dependencies: 3050 | is-core-module: 2.12.1 3051 | path-parse: 1.0.7 3052 | supports-preserve-symlinks-flag: 1.0.0 3053 | 3054 | reusify@1.0.4: {} 3055 | 3056 | rimraf@3.0.2: 3057 | dependencies: 3058 | glob: 7.2.3 3059 | 3060 | run-parallel@1.2.0: 3061 | dependencies: 3062 | queue-microtask: 1.2.3 3063 | 3064 | sade@1.8.1: 3065 | dependencies: 3066 | mri: 1.2.0 3067 | 3068 | safe-array-concat@1.0.0: 3069 | dependencies: 3070 | call-bind: 1.0.2 3071 | get-intrinsic: 1.2.1 3072 | has-symbols: 1.0.3 3073 | isarray: 2.0.5 3074 | 3075 | safe-regex-test@1.0.0: 3076 | dependencies: 3077 | call-bind: 1.0.2 3078 | get-intrinsic: 1.2.1 3079 | is-regex: 1.1.4 3080 | 3081 | scheduler@0.23.0: 3082 | dependencies: 3083 | loose-envify: 1.4.0 3084 | 3085 | semver@6.3.1: {} 3086 | 3087 | semver@7.5.3: 3088 | dependencies: 3089 | lru-cache: 6.0.0 3090 | 3091 | semver@7.5.4: 3092 | dependencies: 3093 | lru-cache: 6.0.0 3094 | 3095 | shebang-command@2.0.0: 3096 | dependencies: 3097 | shebang-regex: 3.0.0 3098 | 3099 | shebang-regex@3.0.0: {} 3100 | 3101 | side-channel@1.0.4: 3102 | dependencies: 3103 | call-bind: 1.0.2 3104 | get-intrinsic: 1.2.1 3105 | object-inspect: 1.12.3 3106 | 3107 | signal-exit@3.0.7: {} 3108 | 3109 | size-limit@8.2.6: 3110 | dependencies: 3111 | bytes-iec: 3.1.1 3112 | chokidar: 3.5.3 3113 | globby: 11.1.0 3114 | lilconfig: 2.1.0 3115 | nanospinner: 1.1.0 3116 | picocolors: 1.0.0 3117 | 3118 | slash@3.0.0: {} 3119 | 3120 | string-width@4.2.3: 3121 | dependencies: 3122 | emoji-regex: 8.0.0 3123 | is-fullwidth-code-point: 3.0.0 3124 | strip-ansi: 6.0.1 3125 | 3126 | string.prototype.trim@1.2.7: 3127 | dependencies: 3128 | call-bind: 1.0.2 3129 | define-properties: 1.2.0 3130 | es-abstract: 1.22.1 3131 | 3132 | string.prototype.trimend@1.0.6: 3133 | dependencies: 3134 | call-bind: 1.0.2 3135 | define-properties: 1.2.0 3136 | es-abstract: 1.22.1 3137 | 3138 | string.prototype.trimstart@1.0.6: 3139 | dependencies: 3140 | call-bind: 1.0.2 3141 | define-properties: 1.2.0 3142 | es-abstract: 1.22.1 3143 | 3144 | strip-ansi@6.0.1: 3145 | dependencies: 3146 | ansi-regex: 5.0.1 3147 | 3148 | strip-bom@3.0.0: {} 3149 | 3150 | strip-json-comments@3.1.1: {} 3151 | 3152 | supports-color@7.2.0: 3153 | dependencies: 3154 | has-flag: 4.0.0 3155 | 3156 | supports-preserve-symlinks-flag@1.0.0: {} 3157 | 3158 | test-exclude@6.0.0: 3159 | dependencies: 3160 | '@istanbuljs/schema': 0.1.3 3161 | glob: 7.2.3 3162 | minimatch: 3.1.2 3163 | 3164 | text-table@0.2.0: {} 3165 | 3166 | to-regex-range@5.0.1: 3167 | dependencies: 3168 | is-number: 7.0.0 3169 | 3170 | tsconfig-paths@3.14.2: 3171 | dependencies: 3172 | '@types/json5': 0.0.29 3173 | json5: 1.0.2 3174 | minimist: 1.2.8 3175 | strip-bom: 3.0.0 3176 | 3177 | tslib@1.14.1: {} 3178 | 3179 | tsm@2.3.0: 3180 | dependencies: 3181 | esbuild: 0.15.18 3182 | 3183 | tsutils@3.21.0(typescript@5.1.6): 3184 | dependencies: 3185 | tslib: 1.14.1 3186 | typescript: 5.1.6 3187 | 3188 | type-check@0.4.0: 3189 | dependencies: 3190 | prelude-ls: 1.2.1 3191 | 3192 | type-fest@0.20.2: {} 3193 | 3194 | typed-array-buffer@1.0.0: 3195 | dependencies: 3196 | call-bind: 1.0.2 3197 | get-intrinsic: 1.2.1 3198 | is-typed-array: 1.1.12 3199 | 3200 | typed-array-byte-length@1.0.0: 3201 | dependencies: 3202 | call-bind: 1.0.2 3203 | for-each: 0.3.3 3204 | has-proto: 1.0.1 3205 | is-typed-array: 1.1.12 3206 | 3207 | typed-array-byte-offset@1.0.0: 3208 | dependencies: 3209 | available-typed-arrays: 1.0.5 3210 | call-bind: 1.0.2 3211 | for-each: 0.3.3 3212 | has-proto: 1.0.1 3213 | is-typed-array: 1.1.12 3214 | 3215 | typed-array-length@1.0.4: 3216 | dependencies: 3217 | call-bind: 1.0.2 3218 | for-each: 0.3.3 3219 | is-typed-array: 1.1.12 3220 | 3221 | typescript@5.1.6: {} 3222 | 3223 | unbox-primitive@1.0.2: 3224 | dependencies: 3225 | call-bind: 1.0.2 3226 | has-bigints: 1.0.2 3227 | has-symbols: 1.0.3 3228 | which-boxed-primitive: 1.0.2 3229 | 3230 | unist-util-stringify-position@3.0.3: 3231 | dependencies: 3232 | '@types/unist': 2.0.7 3233 | 3234 | uri-js@4.4.1: 3235 | dependencies: 3236 | punycode: 2.3.0 3237 | 3238 | use-sync-external-store@1.2.0(react@18.2.0): 3239 | dependencies: 3240 | react: 18.2.0 3241 | 3242 | uvu@0.5.6: 3243 | dependencies: 3244 | dequal: 2.0.3 3245 | diff: 5.1.0 3246 | kleur: 4.1.5 3247 | sade: 1.8.1 3248 | 3249 | v8-to-istanbul@9.1.0: 3250 | dependencies: 3251 | '@jridgewell/trace-mapping': 0.3.18 3252 | '@types/istanbul-lib-coverage': 2.0.4 3253 | convert-source-map: 1.9.0 3254 | 3255 | vfile-location@4.1.0: 3256 | dependencies: 3257 | '@types/unist': 2.0.7 3258 | vfile: 5.3.7 3259 | 3260 | vfile-message@3.1.4: 3261 | dependencies: 3262 | '@types/unist': 2.0.7 3263 | unist-util-stringify-position: 3.0.3 3264 | 3265 | vfile@5.3.7: 3266 | dependencies: 3267 | '@types/unist': 2.0.7 3268 | is-buffer: 2.0.5 3269 | unist-util-stringify-position: 3.0.3 3270 | vfile-message: 3.1.4 3271 | 3272 | which-boxed-primitive@1.0.2: 3273 | dependencies: 3274 | is-bigint: 1.0.4 3275 | is-boolean-object: 1.1.2 3276 | is-number-object: 1.0.7 3277 | is-string: 1.0.7 3278 | is-symbol: 1.0.4 3279 | 3280 | which-typed-array@1.1.11: 3281 | dependencies: 3282 | available-typed-arrays: 1.0.5 3283 | call-bind: 1.0.2 3284 | for-each: 0.3.3 3285 | gopd: 1.0.1 3286 | has-tostringtag: 1.0.0 3287 | 3288 | which@2.0.2: 3289 | dependencies: 3290 | isexe: 2.0.0 3291 | 3292 | wrap-ansi@7.0.0: 3293 | dependencies: 3294 | ansi-styles: 4.3.0 3295 | string-width: 4.2.3 3296 | strip-ansi: 6.0.1 3297 | 3298 | wrappy@1.0.2: {} 3299 | 3300 | y18n@5.0.8: {} 3301 | 3302 | yallist@4.0.0: {} 3303 | 3304 | yargs-parser@20.2.9: {} 3305 | 3306 | yargs@16.2.0: 3307 | dependencies: 3308 | cliui: 7.0.4 3309 | escalade: 3.1.1 3310 | get-caller-file: 2.0.5 3311 | require-directory: 2.1.1 3312 | string-width: 4.2.3 3313 | y18n: 5.0.8 3314 | yargs-parser: 20.2.9 3315 | 3316 | yocto-queue@0.1.0: {} 3317 | -------------------------------------------------------------------------------- /subscribe/index.d.ts: -------------------------------------------------------------------------------- 1 | import { ComponentType, Context as ReduxContext } from 'react' 2 | 3 | import { LoguxReduxStore } from '../create-store-creator/index.js' 4 | import { Channel } from '../use-subscription/index.js' 5 | 6 | interface Subscriber

{ 7 | (props: P): Channel[] | Channel 8 | } 9 | 10 | type WrappedComponent

= ComponentType

& { 11 | WrappedComponent: ComponentType 12 | } 13 | 14 | interface Wrapper

{ 15 | ( 16 | component: ComponentType<{ isSubscribing: boolean } & P> 17 | ): WrappedComponent

18 | } 19 | 20 | type SubscribeOptions = { 21 | /** 22 | * Context with the store. 23 | */ 24 | context?: ReduxContext<{ store: LoguxReduxStore }> 25 | 26 | /** 27 | * Change default `isSubscribing` property. 28 | */ 29 | subscribingProp?: string 30 | } 31 | 32 | /** 33 | * Decorator to add subscribe action on component mount and unsubscribe 34 | * on unmount. 35 | * 36 | * ```js 37 | * import subscribe from '@logux/redux' 38 | * class User extends React.Component { … } 39 | * export default subscribe(({ id }) => `user/${ id }`)(User) 40 | * ``` 41 | * 42 | * ```js 43 | * import subscribe from '@logux/redux' 44 | * class User extends React.Component { … } 45 | * const SubscribeUser = subscribe(props => { 46 | * return { channel: `user/${ props.id }`, fields: ['name'] } 47 | * })(User) 48 | * ``` 49 | * 50 | * @param subscriber Callback to return subscribe action properties according 51 | * to component props. 52 | * @param opts Options. 53 | * 54 | * @return Class wrapper. 55 | */ 56 | export function subscribe

( 57 | subscriber: Subscriber

| Channel[] | Channel, 58 | opts?: SubscribeOptions 59 | ): Wrapper

60 | -------------------------------------------------------------------------------- /subscribe/index.js: -------------------------------------------------------------------------------- 1 | import { createElement } from 'react' 2 | 3 | import { useSubscription } from '../use-subscription/index.js' 4 | 5 | export function subscribe(subscriber, opts = {}) { 6 | let subscribingProp = 'isSubscribing' 7 | if (opts.subscribingProp) subscribingProp = opts.subscribingProp 8 | 9 | return function (Wrapped) { 10 | function SubscribeComponent(ownProps) { 11 | let channels = subscriber 12 | if (typeof subscriber === 'function') channels = subscriber(ownProps) 13 | if (!Array.isArray(channels)) channels = [channels] 14 | let isSubscribing = useSubscription(channels, opts) 15 | let props = { ...ownProps } 16 | props[subscribingProp] = isSubscribing 17 | return createElement(Wrapped, props) 18 | } 19 | SubscribeComponent.WrappedComponent = Wrapped 20 | return SubscribeComponent 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /subscribe/index.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createElement as h, 3 | createContext, 4 | Component, 5 | ReactNode, 6 | FC 7 | } from 'react' 8 | import { 9 | ReactTestRendererJSON, 10 | ReactTestRenderer, 11 | create, 12 | act 13 | } from 'react-test-renderer' 14 | import { ClientMeta, CrossTabClient } from '@logux/client' 15 | import { TestTime, TestLog } from '@logux/core' 16 | import { equal, is } from 'uvu/assert' 17 | import { Provider } from 'react-redux' 18 | import { delay } from 'nanodelay' 19 | import { test } from 'uvu' 20 | 21 | import { createStoreCreator, LoguxReduxStore, subscribe } from '../index.js' 22 | 23 | interface TestComponent extends ReactTestRenderer { 24 | client: CrossTabClient<{}, TestLog> 25 | } 26 | 27 | function createComponent(content: ReactNode): TestComponent { 28 | let client = new CrossTabClient<{}, TestLog>({ 29 | subprotocol: '0.0.0', 30 | server: 'wss://localhost:1337', 31 | userId: '10', 32 | time: new TestTime() 33 | }) 34 | let createStore = createStoreCreator(client) 35 | let store = createStore(() => ({})) 36 | let component = create(h(Provider, { store, children: content })) 37 | return { ...component, client: store.client } 38 | } 39 | 40 | type Users = { 41 | [key: string]: number 42 | } 43 | 44 | type UserPhotoProps = { 45 | id: number 46 | isSubscribing: boolean 47 | } 48 | 49 | type SubsribedUserPhotoProps = { 50 | id: number 51 | nonId?: number 52 | } 53 | 54 | let UserPhoto: FC = ({ id, isSubscribing }) => { 55 | return h('img', { isSubscribing, src: `${id}.jpg` }) 56 | } 57 | 58 | let SubscribeUserPhoto = subscribe(({ id }) => { 59 | return { channel: `users/${id}`, fields: ['photo'] } 60 | })(UserPhoto) 61 | 62 | function getJSON(component: TestComponent): ReactTestRendererJSON { 63 | let value = component.toJSON() 64 | if (value === null || 'length' in value) { 65 | throw new Error('Wrong JSON result') 66 | } 67 | return value 68 | } 69 | 70 | function click(component: TestComponent, event: any): void { 71 | getJSON(component).props.onClick(event) 72 | } 73 | 74 | function getProps( 75 | component: TestComponent, 76 | i?: number 77 | ): ReactTestRendererJSON['props'] { 78 | let node = getJSON(component) 79 | if (typeof i !== 'undefined') { 80 | if (node.children === null) throw new Error('Component has no childern') 81 | let child = node.children[i] 82 | if (typeof child !== 'object') throw new Error('Child has no a object') 83 | return child.props 84 | } else { 85 | return node.props 86 | } 87 | } 88 | 89 | // @ts-ignore 90 | global.WebSocket = () => {} 91 | 92 | test('passes properties', () => { 93 | let Post: FC<{ title: string; children: ReactNode }> = ({ 94 | title, 95 | children 96 | }) => { 97 | return h('article', {}, h('h1', {}, title), children) 98 | } 99 | let SubscribePost = subscribe<{ title: string; children: ReactNode }>( 100 | () => 'posts/10' 101 | )(Post) 102 | 103 | let component = createComponent( 104 | h(SubscribePost, { title: 'A', children: h('p', {}, 'Text') }) 105 | ) 106 | equal(component.toJSON(), { 107 | type: 'article', 108 | props: {}, 109 | children: [ 110 | { type: 'h1', props: {}, children: ['A'] }, 111 | { type: 'p', props: {}, children: ['Text'] } 112 | ] 113 | }) 114 | }) 115 | 116 | test('returns wrapped component', () => { 117 | is(SubscribeUserPhoto.WrappedComponent, UserPhoto) 118 | }) 119 | 120 | test('subscribes', async () => { 121 | let User: FC = () => null 122 | let SubscribeUser = subscribe<{ id: number }>(({ id }) => `users/${id}`)(User) 123 | 124 | let component = createComponent( 125 | h('div', {}, [ 126 | h(SubscribeUser, { id: 1, key: 1 }), 127 | h(SubscribeUser, { id: 1, key: 2 }), 128 | h(SubscribeUser, { id: 2, key: 3 }) 129 | ]) 130 | ) 131 | await delay(1) 132 | equal(component.client.log.actions(), [ 133 | { type: 'logux/subscribe', channel: 'users/1' }, 134 | { type: 'logux/subscribe', channel: 'users/2' } 135 | ]) 136 | }) 137 | 138 | test('subscribes by channel name', async () => { 139 | let UserList: FC = () => null 140 | let SubscribeUsers = subscribe(['users'])(UserList) 141 | 142 | let component = createComponent( 143 | h('div', {}, [h(SubscribeUsers, { key: 1 }), h(SubscribeUsers, { key: 2 })]) 144 | ) 145 | await delay(1) 146 | equal(component.client.log.actions(), [ 147 | { type: 'logux/subscribe', channel: 'users' } 148 | ]) 149 | }) 150 | 151 | test('unsubscribes', async () => { 152 | class UserList extends Component<{}, { users: Users }> { 153 | constructor(props: {}) { 154 | super(props) 155 | this.state = { users: { a: 1, b: 1, c: 2 } } 156 | } 157 | 158 | change(users: Users): void { 159 | this.setState({ users }) 160 | } 161 | 162 | render(): ReactNode { 163 | let users = this.state.users 164 | return h( 165 | 'div', 166 | { 167 | onClick: this.change.bind(this) 168 | }, 169 | Object.keys(this.state.users).map(key => { 170 | return h(SubscribeUserPhoto, { id: users[key], key }) 171 | }) 172 | ) 173 | } 174 | } 175 | 176 | let component = createComponent(h(UserList, {})) 177 | await delay(1) 178 | equal(component.client.log.actions(), [ 179 | { type: 'logux/subscribe', channel: 'users/1', fields: ['photo'] }, 180 | { type: 'logux/subscribe', channel: 'users/2', fields: ['photo'] } 181 | ]) 182 | click(component, { a: 1, c: 2 }) 183 | await delay(1) 184 | equal(component.client.log.actions(), [ 185 | { type: 'logux/subscribe', channel: 'users/1', fields: ['photo'] }, 186 | { type: 'logux/subscribe', channel: 'users/2', fields: ['photo'] } 187 | ]) 188 | click(component, { a: 1 }) 189 | await delay(1) 190 | equal(component.client.log.actions(), [ 191 | { type: 'logux/subscribe', channel: 'users/1', fields: ['photo'] } 192 | ]) 193 | }) 194 | 195 | test('changes subscription', async () => { 196 | class Profile extends Component<{}, { id: number }> { 197 | constructor(props: {}) { 198 | super(props) 199 | this.state = { id: 1 } 200 | } 201 | 202 | change(id: number): void { 203 | this.setState({ id }) 204 | } 205 | 206 | render(): ReactNode { 207 | return h( 208 | 'div', 209 | { onClick: this.change.bind(this) }, 210 | h(SubscribeUserPhoto, { id: this.state.id }) 211 | ) 212 | } 213 | } 214 | 215 | let component = createComponent(h(Profile, {})) 216 | await delay(1) 217 | equal(component.client.log.actions(), [ 218 | { type: 'logux/subscribe', channel: 'users/1', fields: ['photo'] } 219 | ]) 220 | click(component, 2) 221 | await delay(1) 222 | equal(component.client.log.actions(), [ 223 | { type: 'logux/subscribe', channel: 'users/2', fields: ['photo'] } 224 | ]) 225 | }) 226 | 227 | test('does not resubscribe on non-relevant props changes', () => { 228 | class Profile extends Component<{}, { id: number }> { 229 | constructor(props: {}) { 230 | super(props) 231 | this.state = { id: 1 } 232 | } 233 | 234 | change(id: number): void { 235 | this.setState({ id }) 236 | } 237 | 238 | render(): ReactNode { 239 | return h( 240 | 'div', 241 | { onClick: this.change.bind(this) }, 242 | h(SubscribeUserPhoto, { id: 1, nonId: this.state.id }) 243 | ) 244 | } 245 | } 246 | 247 | let component = createComponent(h(Profile, {})) 248 | 249 | let resubscriptions = 0 250 | component.client.log.on('add', () => { 251 | resubscriptions += 1 252 | }) 253 | 254 | click(component, 2) 255 | equal(resubscriptions, 0) 256 | }) 257 | 258 | test('supports multiple channels', async () => { 259 | let User: FC = () => null 260 | 261 | let SubscribeUser = subscribe<{ id: number }>(({ id }) => { 262 | return [`users/${id}`, `pictures/${id}`] 263 | })(User) 264 | 265 | let component = createComponent( 266 | h('div', {}, [ 267 | h(SubscribeUser, { id: 1, key: 1 }), 268 | h(SubscribeUser, { id: 1, key: 2 }), 269 | h(SubscribeUser, { id: 2, key: 3 }) 270 | ]) 271 | ) 272 | await delay(1) 273 | equal(component.client.log.actions(), [ 274 | { type: 'logux/subscribe', channel: 'users/1' }, 275 | { type: 'logux/subscribe', channel: 'pictures/1' }, 276 | { type: 'logux/subscribe', channel: 'users/2' }, 277 | { type: 'logux/subscribe', channel: 'pictures/2' } 278 | ]) 279 | }) 280 | 281 | test('supports different store sources', async () => { 282 | let client = new CrossTabClient<{}, TestLog>({ 283 | subprotocol: '0.0.0', 284 | server: 'wss://localhost:1337', 285 | userId: '10', 286 | time: new TestTime() 287 | }) 288 | let createStore = createStoreCreator(client) 289 | let store = createStore(() => ({})) 290 | 291 | let MyContext = createContext<{ store: LoguxReduxStore }>({ store }) 292 | 293 | let LoguxUserPhoto = subscribe<{ id: number }>(({ id }) => `users/${id}`, { 294 | context: MyContext 295 | })(UserPhoto) 296 | 297 | let Profile: FC = () => { 298 | return h( 299 | MyContext.Provider, 300 | { value: { store } }, 301 | h('div', null, h(LoguxUserPhoto, { id: 1 })) 302 | ) 303 | } 304 | 305 | createComponent(h(Profile, {})) 306 | await delay(1) 307 | equal(store.client.log.actions(), [ 308 | { type: 'logux/subscribe', channel: 'users/1' } 309 | ]) 310 | }) 311 | 312 | test('reports about subscription end', async () => { 313 | class Profile extends Component<{}, { id: number }> { 314 | constructor(props: {}) { 315 | super(props) 316 | this.state = { id: 1 } 317 | } 318 | 319 | change(id: number): void { 320 | this.setState({ id }) 321 | } 322 | 323 | render(): ReactNode { 324 | return h( 325 | 'div', 326 | { onClick: this.change.bind(this) }, 327 | h(SubscribeUserPhoto, { id: this.state.id }) 328 | ) 329 | } 330 | } 331 | 332 | let component = createComponent(h(Profile, {})) 333 | let nodeId = component.client.nodeId 334 | let log = component.client.log 335 | await delay(1) 336 | is(getProps(component, 0).isSubscribing, true) 337 | await act(async () => { 338 | click(component, 1) 339 | await delay(1) 340 | }) 341 | is(getProps(component, 0).isSubscribing, true) 342 | await act(async () => { 343 | click(component, 2) 344 | await delay(1) 345 | }) 346 | is(getProps(component, 0).isSubscribing, true) 347 | await act(async () => { 348 | log.add({ type: 'logux/processed', id: '1 ' + nodeId + ' 0' }) 349 | await delay(1) 350 | }) 351 | is(getProps(component, 0).isSubscribing, true) 352 | await act(async () => { 353 | log.add({ type: 'logux/processed', id: '3 ' + nodeId + ' 0' }) 354 | await delay(1) 355 | }) 356 | is(getProps(component, 0).isSubscribing, false) 357 | }) 358 | 359 | test('allows to change subscribing prop', async () => { 360 | type UserPhoto2Props = { 361 | one: number 362 | isSubscribing: boolean 363 | } 364 | let UserPhoto2: FC = props => { 365 | return h('img', props) 366 | } 367 | type Props = { 368 | one: number 369 | } 370 | let SubscribeUserPhoto2 = subscribe(() => 'user/2', { 371 | subscribingProp: 'isLoading' 372 | })(UserPhoto2) 373 | 374 | let component = createComponent(h(SubscribeUserPhoto2, { one: 1 })) 375 | let nodeId = component.client.nodeId 376 | let log = component.client.log 377 | await delay(1) 378 | equal(getProps(component), { isLoading: true, one: 1 }) 379 | await act(async () => { 380 | log.add({ type: 'logux/processed', id: '1 ' + nodeId + ' 0' }) 381 | await delay(1) 382 | }) 383 | equal(getProps(component), { isLoading: false, one: 1 }) 384 | }) 385 | 386 | test.run() 387 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", 4 | "module": "esnext", 5 | "moduleResolution": "node", 6 | "esModuleInterop": true, 7 | "skipLibCheck": true, 8 | "allowJs": true, 9 | "strict": true, 10 | "noEmit": true, 11 | "jsx": "react" 12 | }, 13 | "exclude": [ 14 | "**/errors.ts" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /use-dispatch/errors.ts: -------------------------------------------------------------------------------- 1 | import { useDispatch } from '../index.js' 2 | 3 | interface IncAction { 4 | type: 'INC' 5 | } 6 | 7 | let dispatch = useDispatch() 8 | 9 | // THROWS Type '"RENAME"' is not assignable to type '"INC"'. 10 | dispatch.sync({ type: 'RENAME' }) 11 | -------------------------------------------------------------------------------- /use-dispatch/index.d.ts: -------------------------------------------------------------------------------- 1 | import { Action, AnyAction } from 'redux' 2 | 3 | import { LoguxDispatch } from '../create-store-creator/index.js' 4 | 5 | /** 6 | * A hook to access the Logux Redux `dispatch` function. 7 | * 8 | * ```js 9 | * export const Counter = ({ value }) => { 10 | * let dispatch = useDispatch() 11 | * return ( 12 | *

13 | * {value} 14 | * 17 | *
18 | * ) 19 | * } 20 | * 21 | * @return Logux Redux store’s `dispatch` function. 22 | */ 23 | export function useDispatch
(): LoguxDispatch 24 | -------------------------------------------------------------------------------- /use-dispatch/index.js: -------------------------------------------------------------------------------- 1 | export { useDispatch } from 'react-redux' 2 | -------------------------------------------------------------------------------- /use-dispatch/types.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from 'react' 2 | 3 | import { useDispatch } from '../index.js' 4 | 5 | interface IncAction { 6 | type: 'INC' 7 | } 8 | 9 | export const Counter: FC<{ value: number }> = ({ value }) => { 10 | let dispatch = useDispatch() 11 | return ( 12 |
13 | {value} 14 | 17 |
18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /use-subscription/index.d.ts: -------------------------------------------------------------------------------- 1 | import { Context as ReduxContext } from 'react' 2 | 3 | import { LoguxReduxStore } from '../create-store-creator/index.js' 4 | 5 | type SubscribingOptions = { 6 | /** 7 | * Context with the store. 8 | */ 9 | context?: ReduxContext<{ store: LoguxReduxStore }> 10 | /** 11 | * Delay in milliseconds to avoid returning `true` when switching between `channels`. 12 | */ 13 | debounce?: number 14 | } 15 | 16 | export type Channel = 17 | | string 18 | | { 19 | channel: string 20 | [extra: string]: any 21 | } 22 | 23 | /** 24 | * Hook to subscribe for channel during component render and unsubscribe 25 | * on component unmount. 26 | * 27 | * ```js 28 | * import useSubscription from '@logux/redux' 29 | * import { useSelector } from 'react-redux' 30 | * 31 | * const UserPage = ({ userId }) => { 32 | * const isSubscribing = useSubscription([`user/${ userId }`]) 33 | * const user = useSelector(state => state.users.find(i => i.id === userId)) 34 | * if (isSubscribing) { 35 | * return 36 | * } else { 37 | * return

{ user.name }

38 | * } 39 | * } 40 | * ``` 41 | * 42 | * @param channels Channels to subscribe. 43 | * @param opts Options 44 | * @return `true` during data loading. 45 | */ 46 | export function useSubscription( 47 | channels: Channel[], 48 | opts?: SubscribingOptions 49 | ): boolean 50 | -------------------------------------------------------------------------------- /use-subscription/index.js: -------------------------------------------------------------------------------- 1 | import { useContext, useEffect, useState } from 'react' 2 | import { ReactReduxContext } from 'react-redux' 3 | 4 | function add(store, subscriptions) { 5 | if (!store.subscriptions) store.subscriptions = {} 6 | if (!store.subscribers) store.subscribers = {} 7 | 8 | return Promise.all( 9 | subscriptions.map(i => { 10 | let subscription = i[0] 11 | let json = i[1] 12 | if (!store.subscribers[json]) store.subscribers[json] = 0 13 | store.subscribers[json] += 1 14 | if (store.subscribers[json] === 1) { 15 | let action = { ...subscription, type: 'logux/subscribe' } 16 | store.subscriptions[json] = store.dispatch.sync(action) 17 | } 18 | return store.subscriptions[json] 19 | }) 20 | ) 21 | } 22 | 23 | function remove(store, subscriptions) { 24 | subscriptions.forEach(i => { 25 | let subscription = i[0] 26 | let json = i[1] 27 | store.subscribers[json] -= 1 28 | if (store.subscribers[json] === 0) { 29 | let action = { ...subscription, type: 'logux/unsubscribe' } 30 | store.log.add(action, { sync: true }) 31 | delete store.subscriptions[json] 32 | } 33 | }) 34 | } 35 | 36 | export function useSubscription(channels, opts = {}) { 37 | let debounce = opts.debounce || 0 38 | let [isSubscribing, changeSubscribing] = useState(true) 39 | let { store } = useContext(opts.context || ReactReduxContext) 40 | 41 | let subscriptions = channels.map(i => { 42 | let subscription = typeof i === 'string' ? { channel: i } : i 43 | return [subscription, JSON.stringify(subscription)] 44 | }) 45 | 46 | let id = subscriptions 47 | .map(i => i[1]) 48 | .sort() 49 | .join(' ') 50 | 51 | useEffect(() => { 52 | let timeout 53 | let ignoreResponce = false 54 | 55 | function resetTimeout() { 56 | clearTimeout(timeout) 57 | timeout = null 58 | } 59 | 60 | if (debounce > 0) { 61 | timeout = setTimeout(() => { 62 | changeSubscribing(true) 63 | }, debounce) 64 | } else { 65 | changeSubscribing(true) 66 | } 67 | 68 | add(store, subscriptions).then(() => { 69 | if (timeout) resetTimeout() 70 | if (!ignoreResponce) changeSubscribing(false) 71 | }) 72 | return () => { 73 | ignoreResponce = true 74 | remove(store, subscriptions) 75 | if (timeout) resetTimeout() 76 | } 77 | }, [id]) 78 | 79 | return isSubscribing 80 | } 81 | -------------------------------------------------------------------------------- /use-subscription/index.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createElement as h, 3 | createContext, 4 | Component, 5 | ReactNode, 6 | FC 7 | } from 'react' 8 | import { 9 | ReactTestRendererJSON, 10 | ReactTestRenderer, 11 | create, 12 | act 13 | } from 'react-test-renderer' 14 | import { ClientMeta, CrossTabClient } from '@logux/client' 15 | import { TestTime, TestLog } from '@logux/core' 16 | import { spyOn, restoreAll } from 'nanospy' 17 | import { equal, is } from 'uvu/assert' 18 | import { Provider } from 'react-redux' 19 | import { delay } from 'nanodelay' 20 | import { test } from 'uvu' 21 | 22 | import { 23 | createStoreCreator, 24 | useSubscription, 25 | LoguxReduxStore 26 | } from '../index.js' 27 | 28 | interface TestComponent extends ReactTestRenderer { 29 | client: CrossTabClient<{}, TestLog> 30 | } 31 | 32 | function createComponent(content: ReactNode): TestComponent { 33 | let client = new CrossTabClient<{}, TestLog>({ 34 | subprotocol: '0.0.0', 35 | server: 'wss://localhost:1337', 36 | userId: '10', 37 | time: new TestTime() 38 | }) 39 | let createStore = createStoreCreator(client) 40 | let store = createStore(() => ({})) 41 | let component = create(h(Provider, { store, children: content })) 42 | return { ...component, client: store.client } 43 | } 44 | 45 | interface Users { 46 | [key: string]: number 47 | } 48 | 49 | interface UserPhotoProps { 50 | id: number 51 | nonId?: number 52 | debounce?: number 53 | } 54 | 55 | let UserPhoto: FC = ({ id, debounce = 0 }) => { 56 | let isSubscribing = useSubscription( 57 | [{ channel: `users/${id}`, fields: ['photo'] }], 58 | { debounce } 59 | ) 60 | return h('img', { isSubscribing, src: `${id}.jpg` }) 61 | } 62 | 63 | function getJSON(component: TestComponent): ReactTestRendererJSON { 64 | let value = component.toJSON() 65 | if (value === null || 'length' in value) { 66 | throw new Error('Wrong JSON result') 67 | } 68 | return value 69 | } 70 | 71 | function click(component: TestComponent, event: any): void { 72 | getJSON(component).props.onClick(event) 73 | } 74 | 75 | function childProps( 76 | component: TestComponent, 77 | i: number 78 | ): ReactTestRendererJSON['props'] { 79 | let node = getJSON(component) 80 | if (node.children === null) throw new Error('Component has no childern') 81 | let child = node.children[i] 82 | if (typeof child !== 'object') throw new Error('Child has no a object') 83 | return child.props 84 | } 85 | 86 | // @ts-ignore 87 | global.WebSocket = () => {} 88 | 89 | test.after.each(() => { 90 | restoreAll() 91 | }) 92 | 93 | test('subscribes', async () => { 94 | let component = createComponent( 95 | h('div', {}, [ 96 | h(UserPhoto, { id: 1, key: 1 }), 97 | h(UserPhoto, { id: 1, key: 2 }), 98 | h(UserPhoto, { id: 2, key: 3 }) 99 | ]) 100 | ) 101 | await delay(1) 102 | equal(component.client.log.actions(), [ 103 | { type: 'logux/subscribe', channel: 'users/1', fields: ['photo'] }, 104 | { type: 'logux/subscribe', channel: 'users/2', fields: ['photo'] } 105 | ]) 106 | }) 107 | 108 | test('accepts channel names', async () => { 109 | let User: FC<{ id: string }> = ({ id }) => { 110 | useSubscription([`users/${id}`, `users/${id}/comments`]) 111 | return h('div') 112 | } 113 | let component = createComponent(h('div', {}, [h(User, { id: '1', key: 1 })])) 114 | await delay(1) 115 | equal(component.client.log.actions(), [ 116 | { type: 'logux/subscribe', channel: 'users/1' }, 117 | { type: 'logux/subscribe', channel: 'users/1/comments' } 118 | ]) 119 | }) 120 | 121 | test('unsubscribes', async () => { 122 | class UserList extends Component<{}, { users: Users }> { 123 | constructor(props: {}) { 124 | super(props) 125 | this.state = { users: { a: 1, b: 1, c: 2 } } 126 | } 127 | 128 | change(users: Users): void { 129 | this.setState({ users }) 130 | } 131 | 132 | render(): ReactNode { 133 | return h( 134 | 'div', 135 | { 136 | onClick: this.change.bind(this) 137 | }, 138 | Object.entries(this.state.users).map(([key, id]) => { 139 | return h(UserPhoto, { id, key }) 140 | }) 141 | ) 142 | } 143 | } 144 | 145 | let component = createComponent(h(UserList, {})) 146 | await delay(1) 147 | equal(component.client.log.actions(), [ 148 | { type: 'logux/subscribe', channel: 'users/1', fields: ['photo'] }, 149 | { type: 'logux/subscribe', channel: 'users/2', fields: ['photo'] } 150 | ]) 151 | click(component, { a: 1, c: 2 }) 152 | await delay(1) 153 | equal(component.client.log.actions(), [ 154 | { type: 'logux/subscribe', channel: 'users/1', fields: ['photo'] }, 155 | { type: 'logux/subscribe', channel: 'users/2', fields: ['photo'] } 156 | ]) 157 | click(component, { a: 1 }) 158 | await delay(1) 159 | equal(component.client.log.actions(), [ 160 | { type: 'logux/subscribe', channel: 'users/1', fields: ['photo'] } 161 | ]) 162 | }) 163 | 164 | test('changes subscription', async () => { 165 | class Profile extends Component<{}, { id: number }> { 166 | constructor(props: {}) { 167 | super(props) 168 | this.state = { id: 1 } 169 | } 170 | 171 | change(id: number): void { 172 | this.setState({ id }) 173 | } 174 | 175 | render(): ReactNode { 176 | return h( 177 | 'div', 178 | { onClick: this.change.bind(this) }, 179 | h(UserPhoto, { id: this.state.id }) 180 | ) 181 | } 182 | } 183 | 184 | let component = createComponent(h(Profile, {})) 185 | await delay(1) 186 | equal(component.client.log.actions(), [ 187 | { type: 'logux/subscribe', channel: 'users/1', fields: ['photo'] } 188 | ]) 189 | click(component, 2) 190 | await delay(1) 191 | equal(component.client.log.actions(), [ 192 | { type: 'logux/subscribe', channel: 'users/2', fields: ['photo'] } 193 | ]) 194 | }) 195 | 196 | test('does not resubscribe on non-relevant props changes', () => { 197 | class Profile extends Component<{}, { id: number }> { 198 | constructor(props: {}) { 199 | super(props) 200 | this.state = { id: 1 } 201 | } 202 | 203 | change(id: number): void { 204 | this.setState({ id }) 205 | } 206 | 207 | render(): ReactNode { 208 | return h( 209 | 'div', 210 | { onClick: this.change.bind(this) }, 211 | h(UserPhoto, { id: 1, nonId: this.state.id }) 212 | ) 213 | } 214 | } 215 | 216 | let component = createComponent(h(Profile, {})) 217 | 218 | let resubscriptions = 0 219 | component.client.log.on('add', () => { 220 | resubscriptions += 1 221 | }) 222 | 223 | click(component, 2) 224 | equal(resubscriptions, 0) 225 | }) 226 | 227 | test('supports different store sources', async () => { 228 | let client = new CrossTabClient<{}, TestLog>({ 229 | subprotocol: '0.0.0', 230 | server: 'wss://localhost:1337', 231 | userId: '10', 232 | time: new TestTime() 233 | }) 234 | let createStore = createStoreCreator(client) 235 | let store = createStore(() => ({})) 236 | let MyContext = createContext<{ store: LoguxReduxStore }>({ store }) 237 | 238 | let LoguxUserPhoto: FC = () => { 239 | useSubscription(['users/1'], { context: MyContext }) 240 | return h('div') 241 | } 242 | 243 | let Profile: FC = () => { 244 | return h( 245 | MyContext.Provider, 246 | { value: { store } }, 247 | h('div', null, h(LoguxUserPhoto)) 248 | ) 249 | } 250 | 251 | createComponent(h(Profile, {})) 252 | await delay(1) 253 | equal(store.client.log.actions(), [ 254 | { type: 'logux/subscribe', channel: 'users/1' } 255 | ]) 256 | }) 257 | 258 | test('reports about subscription end', async () => { 259 | class Profile extends Component<{}, { id: number }> { 260 | constructor(props: {}) { 261 | super(props) 262 | this.state = { id: 1 } 263 | } 264 | 265 | change(id: number): void { 266 | this.setState({ id }) 267 | } 268 | 269 | render(): ReactNode { 270 | return h( 271 | 'div', 272 | { onClick: this.change.bind(this) }, 273 | h(UserPhoto, { id: this.state.id, debounce: 250 }) 274 | ) 275 | } 276 | } 277 | 278 | let component = createComponent(h(Profile, {})) 279 | let nodeId = component.client.nodeId 280 | let log = component.client.log 281 | await delay(1) 282 | is(childProps(component, 0).isSubscribing, true) 283 | act(() => { 284 | click(component, 1) 285 | }) 286 | is(childProps(component, 0).isSubscribing, true) 287 | act(() => { 288 | click(component, 2) 289 | }) 290 | is(childProps(component, 0).isSubscribing, true) 291 | await act(async () => { 292 | log.add({ type: 'logux/processed', id: `1 ${nodeId} 0` }) 293 | await delay(1) 294 | }) 295 | is(childProps(component, 0).isSubscribing, true) 296 | await act(async () => { 297 | log.add({ type: 'logux/processed', id: `3 ${nodeId} 0` }) 298 | await delay(1) 299 | }) 300 | is(childProps(component, 0).isSubscribing, false) 301 | act(() => { 302 | click(component, 3) 303 | }) 304 | is(childProps(component, 0).isSubscribing, false) 305 | await act(async () => { 306 | log.add({ type: 'logux/processed', id: `7 ${nodeId} 0` }) 307 | await delay(1) 308 | }) 309 | is(childProps(component, 0).isSubscribing, false) 310 | act(() => { 311 | click(component, 4) 312 | }) 313 | is(childProps(component, 0).isSubscribing, false) 314 | act(() => { 315 | click(component, 5) 316 | }) 317 | is(childProps(component, 0).isSubscribing, false) 318 | await act(async () => { 319 | await delay(250) 320 | }) 321 | is(childProps(component, 0).isSubscribing, true) 322 | await act(async () => { 323 | log.add({ type: 'logux/processed', id: `10 ${nodeId} 0` }) 324 | await delay(1) 325 | }) 326 | is(childProps(component, 0).isSubscribing, true) 327 | await act(async () => { 328 | log.add({ type: 'logux/processed', id: `12 ${nodeId} 0` }) 329 | await delay(1) 330 | }) 331 | is(childProps(component, 0).isSubscribing, false) 332 | }) 333 | 334 | test('works on channels size changes', () => { 335 | let error = spyOn(console, 'error') 336 | let UserList: FC<{ ids: number[] }> = ({ ids }) => { 337 | useSubscription(ids.map(id => `users/${id}`)) 338 | return h('div') 339 | } 340 | 341 | class UsersPage extends Component<{}, { ids: number[] }> { 342 | constructor(props: {}) { 343 | super(props) 344 | this.state = { ids: [1] } 345 | } 346 | 347 | change(ids: number[]): void { 348 | this.setState({ ids }) 349 | } 350 | 351 | render(): ReactNode { 352 | return h( 353 | 'div', 354 | { onClick: this.change.bind(this) }, 355 | h(UserList, { ids: this.state.ids }) 356 | ) 357 | } 358 | } 359 | 360 | let component = createComponent(h(UsersPage, {})) 361 | act(() => { 362 | click(component, [1, 2]) 363 | }) 364 | is(error.called, false) 365 | }) 366 | 367 | test.run() 368 | -------------------------------------------------------------------------------- /use-subscription/types.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from 'react' 2 | 3 | import { useSubscription } from '../index.js' 4 | 5 | export const UserList: FC<{ id: number }> = ({ id }) => { 6 | let isLoading = useSubscription([ 7 | 'users', 8 | { channel: `user/${id}`, fields: ['name'] } 9 | ]) 10 | if (isLoading) { 11 | return
Loading
12 | } else { 13 | return

Users:

14 | } 15 | } 16 | --------------------------------------------------------------------------------