feat : add signin ,signout, forgot password features

This commit is contained in:
ghazall-ag
2025-10-29 22:43:48 +03:30
parent 46a1fae510
commit 5079a5bc56
63 changed files with 2920 additions and 125 deletions

32
node_modules/.package-lock.json generated vendored
View File

@@ -597,13 +597,13 @@
"version": "15.7.15",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
"integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
"dev": true
"devOptional": true
},
"node_modules/@types/react": {
"version": "18.3.26",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.26.tgz",
"integrity": "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==",
"dev": true,
"devOptional": true,
"dependencies": {
"@types/prop-types": "*",
"csstype": "^3.0.2"
@@ -5208,6 +5208,34 @@
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/zustand": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.8.tgz",
"integrity": "sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==",
"engines": {
"node": ">=12.20.0"
},
"peerDependencies": {
"@types/react": ">=18.0.0",
"immer": ">=9.0.6",
"react": ">=18.0.0",
"use-sync-external-store": ">=1.2.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"immer": {
"optional": true
},
"react": {
"optional": true
},
"use-sync-external-store": {
"optional": true
}
}
}
}
}

View File

@@ -1,53 +1,59 @@
{
"hash": "6cbb90ff",
"browserHash": "c7ceac79",
"hash": "ff6fda40",
"browserHash": "b50068b3",
"optimized": {
"react/jsx-runtime": {
"src": "../../react/jsx-runtime.js",
"file": "react_jsx-runtime.js",
"fileHash": "dd501a3d",
"fileHash": "ddd613d5",
"needsInterop": true
},
"react/jsx-dev-runtime": {
"src": "../../react/jsx-dev-runtime.js",
"file": "react_jsx-dev-runtime.js",
"fileHash": "734127f4",
"fileHash": "db7123d4",
"needsInterop": true
},
"react": {
"src": "../../react/index.js",
"file": "react.js",
"fileHash": "04b54be7",
"fileHash": "f0784960",
"needsInterop": true
},
"axios": {
"src": "../../axios/index.js",
"file": "axios.js",
"fileHash": "0645ca65",
"fileHash": "b9f81ab8",
"needsInterop": false
},
"lucide-react": {
"src": "../../lucide-react/dist/esm/lucide-react.mjs",
"file": "lucide-react.js",
"fileHash": "f1ba9b47",
"fileHash": "a5656c81",
"needsInterop": false
},
"react-dom/client": {
"src": "../../react-dom/client.js",
"file": "react-dom_client.js",
"fileHash": "eb1306a5",
"fileHash": "ae58904b",
"needsInterop": true
},
"react-router-dom": {
"src": "../../react-router-dom/dist/index.js",
"file": "react-router-dom.js",
"fileHash": "1d841c06",
"fileHash": "420348ee",
"needsInterop": false
},
"recharts": {
"src": "../../recharts/es6/index.js",
"file": "recharts.js",
"fileHash": "7cd4b4b9",
"fileHash": "dafddd35",
"needsInterop": false
},
"zustand": {
"src": "../../zustand/esm/index.mjs",
"file": "zustand.js",
"fileHash": "f2ee525b",
"needsInterop": false
}
},

56
node_modules/.vite/deps/zustand.js generated vendored Normal file
View File

@@ -0,0 +1,56 @@
import {
require_react
} from "./chunk-WQMOH32Y.js";
import {
__toESM
} from "./chunk-5WWUZCGV.js";
// node_modules/zustand/esm/vanilla.mjs
var createStoreImpl = (createState) => {
let state;
const listeners = /* @__PURE__ */ new Set();
const setState = (partial, replace) => {
const nextState = typeof partial === "function" ? partial(state) : partial;
if (!Object.is(nextState, state)) {
const previousState = state;
state = (replace != null ? replace : typeof nextState !== "object" || nextState === null) ? nextState : Object.assign({}, state, nextState);
listeners.forEach((listener) => listener(state, previousState));
}
};
const getState = () => state;
const getInitialState = () => initialState;
const subscribe = (listener) => {
listeners.add(listener);
return () => listeners.delete(listener);
};
const api = { setState, getState, getInitialState, subscribe };
const initialState = state = createState(setState, getState, api);
return api;
};
var createStore = (createState) => createState ? createStoreImpl(createState) : createStoreImpl;
// node_modules/zustand/esm/react.mjs
var import_react = __toESM(require_react(), 1);
var identity = (arg) => arg;
function useStore(api, selector = identity) {
const slice = import_react.default.useSyncExternalStore(
api.subscribe,
import_react.default.useCallback(() => selector(api.getState()), [api, selector]),
import_react.default.useCallback(() => selector(api.getInitialState()), [api, selector])
);
import_react.default.useDebugValue(slice);
return slice;
}
var createImpl = (createState) => {
const api = createStore(createState);
const useBoundStore = (selector) => useStore(api, selector);
Object.assign(useBoundStore, api);
return useBoundStore;
};
var create = (createState) => createState ? createImpl(createState) : createImpl;
export {
create,
createStore,
useStore
};
//# sourceMappingURL=zustand.js.map

7
node_modules/.vite/deps/zustand.js.map generated vendored Normal file
View File

@@ -0,0 +1,7 @@
{
"version": 3,
"sources": ["../../zustand/esm/vanilla.mjs", "../../zustand/esm/react.mjs"],
"sourcesContent": ["const createStoreImpl = (createState) => {\n let state;\n const listeners = /* @__PURE__ */ new Set();\n const setState = (partial, replace) => {\n const nextState = typeof partial === \"function\" ? partial(state) : partial;\n if (!Object.is(nextState, state)) {\n const previousState = state;\n state = (replace != null ? replace : typeof nextState !== \"object\" || nextState === null) ? nextState : Object.assign({}, state, nextState);\n listeners.forEach((listener) => listener(state, previousState));\n }\n };\n const getState = () => state;\n const getInitialState = () => initialState;\n const subscribe = (listener) => {\n listeners.add(listener);\n return () => listeners.delete(listener);\n };\n const api = { setState, getState, getInitialState, subscribe };\n const initialState = state = createState(setState, getState, api);\n return api;\n};\nconst createStore = ((createState) => createState ? createStoreImpl(createState) : createStoreImpl);\n\nexport { createStore };\n", "import React from 'react';\nimport { createStore } from 'zustand/vanilla';\n\nconst identity = (arg) => arg;\nfunction useStore(api, selector = identity) {\n const slice = React.useSyncExternalStore(\n api.subscribe,\n React.useCallback(() => selector(api.getState()), [api, selector]),\n React.useCallback(() => selector(api.getInitialState()), [api, selector])\n );\n React.useDebugValue(slice);\n return slice;\n}\nconst createImpl = (createState) => {\n const api = createStore(createState);\n const useBoundStore = (selector) => useStore(api, selector);\n Object.assign(useBoundStore, api);\n return useBoundStore;\n};\nconst create = ((createState) => createState ? createImpl(createState) : createImpl);\n\nexport { create, useStore };\n"],
"mappings": ";;;;;;;;AAAA,IAAM,kBAAkB,CAAC,gBAAgB;AACvC,MAAI;AACJ,QAAM,YAA4B,oBAAI,IAAI;AAC1C,QAAM,WAAW,CAAC,SAAS,YAAY;AACrC,UAAM,YAAY,OAAO,YAAY,aAAa,QAAQ,KAAK,IAAI;AACnE,QAAI,CAAC,OAAO,GAAG,WAAW,KAAK,GAAG;AAChC,YAAM,gBAAgB;AACtB,eAAS,WAAW,OAAO,UAAU,OAAO,cAAc,YAAY,cAAc,QAAQ,YAAY,OAAO,OAAO,CAAC,GAAG,OAAO,SAAS;AAC1I,gBAAU,QAAQ,CAAC,aAAa,SAAS,OAAO,aAAa,CAAC;AAAA,IAChE;AAAA,EACF;AACA,QAAM,WAAW,MAAM;AACvB,QAAM,kBAAkB,MAAM;AAC9B,QAAM,YAAY,CAAC,aAAa;AAC9B,cAAU,IAAI,QAAQ;AACtB,WAAO,MAAM,UAAU,OAAO,QAAQ;AAAA,EACxC;AACA,QAAM,MAAM,EAAE,UAAU,UAAU,iBAAiB,UAAU;AAC7D,QAAM,eAAe,QAAQ,YAAY,UAAU,UAAU,GAAG;AAChE,SAAO;AACT;AACA,IAAM,cAAe,CAAC,gBAAgB,cAAc,gBAAgB,WAAW,IAAI;;;ACrBnF,mBAAkB;AAGlB,IAAM,WAAW,CAAC,QAAQ;AAC1B,SAAS,SAAS,KAAK,WAAW,UAAU;AAC1C,QAAM,QAAQ,aAAAA,QAAM;AAAA,IAClB,IAAI;AAAA,IACJ,aAAAA,QAAM,YAAY,MAAM,SAAS,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC;AAAA,IACjE,aAAAA,QAAM,YAAY,MAAM,SAAS,IAAI,gBAAgB,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC;AAAA,EAC1E;AACA,eAAAA,QAAM,cAAc,KAAK;AACzB,SAAO;AACT;AACA,IAAM,aAAa,CAAC,gBAAgB;AAClC,QAAM,MAAM,YAAY,WAAW;AACnC,QAAM,gBAAgB,CAAC,aAAa,SAAS,KAAK,QAAQ;AAC1D,SAAO,OAAO,eAAe,GAAG;AAChC,SAAO;AACT;AACA,IAAM,SAAU,CAAC,gBAAgB,cAAc,WAAW,WAAW,IAAI;",
"names": ["React"]
}

21
node_modules/zustand/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Paul Henschel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

506
node_modules/zustand/README.md generated vendored Normal file
View File

@@ -0,0 +1,506 @@
<p align="center">
<img src="docs/bear.jpg" />
</p>
[![Build Status](https://img.shields.io/github/actions/workflow/status/pmndrs/zustand/test.yml?branch=main&style=flat&colorA=000000&colorB=000000)](https://github.com/pmndrs/zustand/actions?query=workflow%3ALint)
[![Build Size](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fdeno.bundlejs.com%2F%3Fq%3Dzustand&query=%24.size.uncompressedSize&style=flat&label=bundle%20size&colorA=000000&colorB=000000)](https://bundlejs.com/?q=zustand)
[![Version](https://img.shields.io/npm/v/zustand?style=flat&colorA=000000&colorB=000000)](https://www.npmjs.com/package/zustand)
[![Downloads](https://img.shields.io/npm/dt/zustand.svg?style=flat&colorA=000000&colorB=000000)](https://www.npmjs.com/package/zustand)
[![Discord Shield](https://img.shields.io/discord/740090768164651008?style=flat&colorA=000000&colorB=000000&label=discord&logo=discord&logoColor=ffffff)](https://discord.gg/poimandres)
A small, fast and scalable bearbones state-management solution using simplified flux principles. Has a comfy API based on hooks, isn't boilerplatey or opinionated.
Don't disregard it because it's cute. It has quite the claws, lots of time was spent dealing with common pitfalls, like the dreaded [zombie child problem](https://react-redux.js.org/api/hooks#stale-props-and-zombie-children), [react concurrency](https://github.com/bvaughn/rfcs/blob/useMutableSource/text/0000-use-mutable-source.md), and [context loss](https://github.com/facebook/react/issues/13332) between mixed renderers. It may be the one state-manager in the React space that gets all of these right.
You can try a live [demo](https://zustand-demo.pmnd.rs/) and read the [docs](https://zustand.docs.pmnd.rs/).
```bash
npm install zustand
```
:warning: This readme is written for JavaScript users. If you are a TypeScript user, be sure to check out our [TypeScript Usage section](#typescript-usage).
## First create a store
Your store is a hook! You can put anything in it: primitives, objects, functions. State has to be updated immutably and the `set` function [merges state](./docs/guides/immutable-state-and-merging.md) to help it.
```jsx
import { create } from 'zustand'
const useBearStore = create((set) => ({
bears: 0,
increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
removeAllBears: () => set({ bears: 0 }),
}))
```
## Then bind your components, and that's it!
Use the hook anywhere, no providers are needed. Select your state and the component will re-render on changes.
```jsx
function BearCounter() {
const bears = useBearStore((state) => state.bears)
return <h1>{bears} around here ...</h1>
}
function Controls() {
const increasePopulation = useBearStore((state) => state.increasePopulation)
return <button onClick={increasePopulation}>one up</button>
}
```
### Why zustand over redux?
- Simple and un-opinionated
- Makes hooks the primary means of consuming state
- Doesn't wrap your app in context providers
- [Can inform components transiently (without causing render)](#transient-updates-for-often-occurring-state-changes)
### Why zustand over context?
- Less boilerplate
- Renders components only on changes
- Centralized, action-based state management
---
# Recipes
## Fetching everything
You can, but bear in mind that it will cause the component to update on every state change!
```jsx
const state = useBearStore()
```
## Selecting multiple state slices
It detects changes with strict-equality (old === new) by default, this is efficient for atomic state picks.
```jsx
const nuts = useBearStore((state) => state.nuts)
const honey = useBearStore((state) => state.honey)
```
If you want to construct a single object with multiple state-picks inside, similar to redux's mapStateToProps, you can use [useShallow](./docs/guides/prevent-rerenders-with-use-shallow.md) to prevent unnecessary rerenders when the selector output does not change according to shallow equal.
```jsx
import { create } from 'zustand'
import { useShallow } from 'zustand/react/shallow'
const useBearStore = create((set) => ({
nuts: 0,
honey: 0,
treats: {},
// ...
}))
// Object pick, re-renders the component when either state.nuts or state.honey change
const { nuts, honey } = useBearStore(
useShallow((state) => ({ nuts: state.nuts, honey: state.honey })),
)
// Array pick, re-renders the component when either state.nuts or state.honey change
const [nuts, honey] = useBearStore(
useShallow((state) => [state.nuts, state.honey]),
)
// Mapped picks, re-renders the component when state.treats changes in order, count or keys
const treats = useBearStore(useShallow((state) => Object.keys(state.treats)))
```
For more control over re-rendering, you may provide any custom equality function (this example requires the use of [`createWithEqualityFn`](./docs/migrations/migrating-to-v5.md#using-custom-equality-functions-such-as-shallow)).
```jsx
const treats = useBearStore(
(state) => state.treats,
(oldTreats, newTreats) => compare(oldTreats, newTreats),
)
```
## Overwriting state
The `set` function has a second argument, `false` by default. Instead of merging, it will replace the state model. Be careful not to wipe out parts you rely on, like actions.
```jsx
const useFishStore = create((set) => ({
salmon: 1,
tuna: 2,
deleteEverything: () => set({}, true), // clears the entire store, actions included
deleteTuna: () => set(({ tuna, ...rest }) => rest, true),
}))
```
## Async actions
Just call `set` when you're ready, zustand doesn't care if your actions are async or not.
```jsx
const useFishStore = create((set) => ({
fishies: {},
fetch: async (pond) => {
const response = await fetch(pond)
set({ fishies: await response.json() })
},
}))
```
## Read from state in actions
`set` allows fn-updates `set(state => result)`, but you still have access to state outside of it through `get`.
```jsx
const useSoundStore = create((set, get) => ({
sound: 'grunt',
action: () => {
const sound = get().sound
...
```
## Reading/writing state and reacting to changes outside of components
Sometimes you need to access state in a non-reactive way or act upon the store. For these cases, the resulting hook has utility functions attached to its prototype.
:warning: This technique is not recommended for adding state in [React Server Components](https://github.com/reactjs/rfcs/blob/main/text/0188-server-components.md) (typically in Next.js 13 and above). It can lead to unexpected bugs and privacy issues for your users. For more details, see [#2200](https://github.com/pmndrs/zustand/discussions/2200).
```jsx
const useDogStore = create(() => ({ paw: true, snout: true, fur: true }))
// Getting non-reactive fresh state
const paw = useDogStore.getState().paw
// Listening to all changes, fires synchronously on every change
const unsub1 = useDogStore.subscribe(console.log)
// Updating state, will trigger listeners
useDogStore.setState({ paw: false })
// Unsubscribe listeners
unsub1()
// You can of course use the hook as you always would
function Component() {
const paw = useDogStore((state) => state.paw)
...
```
### Using subscribe with selector
If you need to subscribe with a selector,
`subscribeWithSelector` middleware will help.
With this middleware `subscribe` accepts an additional signature:
```ts
subscribe(selector, callback, options?: { equalityFn, fireImmediately }): Unsubscribe
```
```js
import { subscribeWithSelector } from 'zustand/middleware'
const useDogStore = create(
subscribeWithSelector(() => ({ paw: true, snout: true, fur: true })),
)
// Listening to selected changes, in this case when "paw" changes
const unsub2 = useDogStore.subscribe((state) => state.paw, console.log)
// Subscribe also exposes the previous value
const unsub3 = useDogStore.subscribe(
(state) => state.paw,
(paw, previousPaw) => console.log(paw, previousPaw),
)
// Subscribe also supports an optional equality function
const unsub4 = useDogStore.subscribe(
(state) => [state.paw, state.fur],
console.log,
{ equalityFn: shallow },
)
// Subscribe and fire immediately
const unsub5 = useDogStore.subscribe((state) => state.paw, console.log, {
fireImmediately: true,
})
```
## Using zustand without React
Zustand core can be imported and used without the React dependency. The only difference is that the create function does not return a hook, but the API utilities.
```jsx
import { createStore } from 'zustand/vanilla'
const store = createStore((set) => ...)
const { getState, setState, subscribe, getInitialState } = store
export default store
```
You can use a vanilla store with `useStore` hook available since v4.
```jsx
import { useStore } from 'zustand'
import { vanillaStore } from './vanillaStore'
const useBoundStore = (selector) => useStore(vanillaStore, selector)
```
:warning: Note that middlewares that modify `set` or `get` are not applied to `getState` and `setState`.
## Transient updates (for often occurring state-changes)
The subscribe function allows components to bind to a state-portion without forcing re-render on changes. Best combine it with useEffect for automatic unsubscribe on unmount. This can make a [drastic](https://codesandbox.io/s/peaceful-johnson-txtws) performance impact when you are allowed to mutate the view directly.
```jsx
const useScratchStore = create((set) => ({ scratches: 0, ... }))
const Component = () => {
// Fetch initial state
const scratchRef = useRef(useScratchStore.getState().scratches)
// Connect to the store on mount, disconnect on unmount, catch state-changes in a reference
useEffect(() => useScratchStore.subscribe(
state => (scratchRef.current = state.scratches)
), [])
...
```
## Sick of reducers and changing nested states? Use Immer!
Reducing nested structures is tiresome. Have you tried [immer](https://github.com/mweststrate/immer)?
```jsx
import { produce } from 'immer'
const useLushStore = create((set) => ({
lush: { forest: { contains: { a: 'bear' } } },
clearForest: () =>
set(
produce((state) => {
state.lush.forest.contains = null
}),
),
}))
const clearForest = useLushStore((state) => state.clearForest)
clearForest()
```
[Alternatively, there are some other solutions.](./docs/guides/updating-state.md#with-immer)
## Persist middleware
You can persist your store's data using any kind of storage.
```jsx
import { create } from 'zustand'
import { persist, createJSONStorage } from 'zustand/middleware'
const useFishStore = create(
persist(
(set, get) => ({
fishes: 0,
addAFish: () => set({ fishes: get().fishes + 1 }),
}),
{
name: 'food-storage', // name of the item in the storage (must be unique)
storage: createJSONStorage(() => sessionStorage), // (optional) by default, 'localStorage' is used
},
),
)
```
[See the full documentation for this middleware.](./docs/integrations/persisting-store-data.md)
## Immer middleware
Immer is available as middleware too.
```jsx
import { create } from 'zustand'
import { immer } from 'zustand/middleware/immer'
const useBeeStore = create(
immer((set) => ({
bees: 0,
addBees: (by) =>
set((state) => {
state.bees += by
}),
})),
)
```
## Can't live without redux-like reducers and action types?
```jsx
const types = { increase: 'INCREASE', decrease: 'DECREASE' }
const reducer = (state, { type, by = 1 }) => {
switch (type) {
case types.increase:
return { grumpiness: state.grumpiness + by }
case types.decrease:
return { grumpiness: state.grumpiness - by }
}
}
const useGrumpyStore = create((set) => ({
grumpiness: 0,
dispatch: (args) => set((state) => reducer(state, args)),
}))
const dispatch = useGrumpyStore((state) => state.dispatch)
dispatch({ type: types.increase, by: 2 })
```
Or, just use our redux-middleware. It wires up your main-reducer, sets the initial state, and adds a dispatch function to the state itself and the vanilla API.
```jsx
import { redux } from 'zustand/middleware'
const useGrumpyStore = create(redux(reducer, initialState))
```
## Redux devtools
Install the [Redux DevTools Chrome extension](https://chromewebstore.google.com/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd) to use the devtools middleware.
```jsx
import { devtools } from 'zustand/middleware'
// Usage with a plain action store, it will log actions as "setState"
const usePlainStore = create(devtools((set) => ...))
// Usage with a redux store, it will log full action types
const useReduxStore = create(devtools(redux(reducer, initialState)))
```
One redux devtools connection for multiple stores
```jsx
import { devtools } from 'zustand/middleware'
// Usage with a plain action store, it will log actions as "setState"
const usePlainStore1 = create(devtools((set) => ..., { name, store: storeName1 }))
const usePlainStore2 = create(devtools((set) => ..., { name, store: storeName2 }))
// Usage with a redux store, it will log full action types
const useReduxStore1 = create(devtools(redux(reducer, initialState)), { name, store: storeName3 })
const useReduxStore2 = create(devtools(redux(reducer, initialState)), { name, store: storeName4 })
```
Assigning different connection names will separate stores in redux devtools. This also helps group different stores into separate redux devtools connections.
devtools takes the store function as its first argument, optionally you can name the store or configure [serialize](https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/API/Arguments.md#serialize) options with a second argument.
Name store: `devtools(..., {name: "MyStore"})`, which will create a separate instance named "MyStore" in the devtools.
Serialize options: `devtools(..., { serialize: { options: true } })`.
#### Logging Actions
devtools will only log actions from each separated store unlike in a typical _combined reducers_ redux store. See an approach to combining stores https://github.com/pmndrs/zustand/issues/163
You can log a specific action type for each `set` function by passing a third parameter:
```jsx
const useBearStore = create(devtools((set) => ({
...
eatFish: () => set(
(prev) => ({ fishes: prev.fishes > 1 ? prev.fishes - 1 : 0 }),
undefined,
'bear/eatFish'
),
...
```
You can also log the action's type along with its payload:
```jsx
...
addFishes: (count) => set(
(prev) => ({ fishes: prev.fishes + count }),
undefined,
{ type: 'bear/addFishes', count, }
),
...
```
If an action type is not provided, it is defaulted to "anonymous". You can customize this default value by providing an `anonymousActionType` parameter:
```jsx
devtools(..., { anonymousActionType: 'unknown', ... })
```
If you wish to disable devtools (on production for instance). You can customize this setting by providing the `enabled` parameter:
```jsx
devtools(..., { enabled: false, ... })
```
## React context
The store created with `create` doesn't require context providers. In some cases, you may want to use contexts for dependency injection or if you want to initialize your store with props from a component. Because the normal store is a hook, passing it as a normal context value may violate the rules of hooks.
The recommended method available since v4 is to use the vanilla store.
```jsx
import { createContext, useContext } from 'react'
import { createStore, useStore } from 'zustand'
const store = createStore(...) // vanilla store without hooks
const StoreContext = createContext()
const App = () => (
<StoreContext.Provider value={store}>
...
</StoreContext.Provider>
)
const Component = () => {
const store = useContext(StoreContext)
const slice = useStore(store, selector)
...
```
## TypeScript Usage
Basic typescript usage doesn't require anything special except for writing `create<State>()(...)` instead of `create(...)`...
```ts
import { create } from 'zustand'
import { devtools, persist } from 'zustand/middleware'
import type {} from '@redux-devtools/extension' // required for devtools typing
interface BearState {
bears: number
increase: (by: number) => void
}
const useBearStore = create<BearState>()(
devtools(
persist(
(set) => ({
bears: 0,
increase: (by) => set((state) => ({ bears: state.bears + by })),
}),
{
name: 'bear-storage',
},
),
),
)
```
A more complete TypeScript guide is [here](docs/guides/typescript.md).
## Best practices
- You may wonder how to organize your code for better maintenance: [Splitting the store into separate slices](./docs/guides/slices-pattern.md).
- Recommended usage for this unopinionated library: [Flux inspired practice](./docs/guides/flux-inspired-practice.md).
- [Calling actions outside a React event handler in pre-React 18](./docs/guides/event-handler-in-pre-react-18.md).
- [Testing](./docs/guides/testing.md)
- For more, have a look [in the docs folder](./docs/)
## Third-Party Libraries
Some users may want to extend Zustand's feature set which can be done using third-party libraries made by the community. For information regarding third-party libraries with Zustand, visit [the doc](./docs/integrations/third-party-libraries.md).
## Comparison with other libraries
- [Difference between zustand and other state management libraries for React](https://zustand.docs.pmnd.rs/getting-started/comparison)

2
node_modules/zustand/esm/index.d.mts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
export * from 'zustand/vanilla';
export * from 'zustand/react';

2
node_modules/zustand/esm/index.mjs generated vendored Normal file
View File

@@ -0,0 +1,2 @@
export * from 'zustand/vanilla';
export * from 'zustand/react';

5
node_modules/zustand/esm/middleware.d.mts generated vendored Normal file
View File

@@ -0,0 +1,5 @@
export { redux } from './middleware/redux.mjs';
export { devtools, type DevtoolsOptions, type NamedSet, } from './middleware/devtools.mjs';
export { subscribeWithSelector } from './middleware/subscribeWithSelector.mjs';
export { combine } from './middleware/combine.mjs';
export { persist, createJSONStorage, type StateStorage, type StorageValue, type PersistStorage, type PersistOptions, } from './middleware/persist.mjs';

462
node_modules/zustand/esm/middleware.mjs generated vendored Normal file
View File

@@ -0,0 +1,462 @@
const reduxImpl = (reducer, initial) => (set, _get, api) => {
api.dispatch = (action) => {
set((state) => reducer(state, action), false, action);
return action;
};
api.dispatchFromDevtools = true;
return { dispatch: (...args) => api.dispatch(...args), ...initial };
};
const redux = reduxImpl;
const trackedConnections = /* @__PURE__ */ new Map();
const getTrackedConnectionState = (name) => {
const api = trackedConnections.get(name);
if (!api) return {};
return Object.fromEntries(
Object.entries(api.stores).map(([key, api2]) => [key, api2.getState()])
);
};
const extractConnectionInformation = (store, extensionConnector, options) => {
if (store === void 0) {
return {
type: "untracked",
connection: extensionConnector.connect(options)
};
}
const existingConnection = trackedConnections.get(options.name);
if (existingConnection) {
return { type: "tracked", store, ...existingConnection };
}
const newConnection = {
connection: extensionConnector.connect(options),
stores: {}
};
trackedConnections.set(options.name, newConnection);
return { type: "tracked", store, ...newConnection };
};
const removeStoreFromTrackedConnections = (name, store) => {
if (store === void 0) return;
const connectionInfo = trackedConnections.get(name);
if (!connectionInfo) return;
delete connectionInfo.stores[store];
if (Object.keys(connectionInfo.stores).length === 0) {
trackedConnections.delete(name);
}
};
const findCallerName = (stack) => {
var _a, _b;
if (!stack) return void 0;
const traceLines = stack.split("\n");
const apiSetStateLineIndex = traceLines.findIndex(
(traceLine) => traceLine.includes("api.setState")
);
if (apiSetStateLineIndex < 0) return void 0;
const callerLine = ((_a = traceLines[apiSetStateLineIndex + 1]) == null ? void 0 : _a.trim()) || "";
return (_b = /.+ (.+) .+/.exec(callerLine)) == null ? void 0 : _b[1];
};
const devtoolsImpl = (fn, devtoolsOptions = {}) => (set, get, api) => {
const { enabled, anonymousActionType, store, ...options } = devtoolsOptions;
let extensionConnector;
try {
extensionConnector = (enabled != null ? enabled : (import.meta.env ? import.meta.env.MODE : void 0) !== "production") && window.__REDUX_DEVTOOLS_EXTENSION__;
} catch (e) {
}
if (!extensionConnector) {
return fn(set, get, api);
}
const { connection, ...connectionInformation } = extractConnectionInformation(store, extensionConnector, options);
let isRecording = true;
api.setState = ((state, replace, nameOrAction) => {
const r = set(state, replace);
if (!isRecording) return r;
const action = nameOrAction === void 0 ? {
type: anonymousActionType || findCallerName(new Error().stack) || "anonymous"
} : typeof nameOrAction === "string" ? { type: nameOrAction } : nameOrAction;
if (store === void 0) {
connection == null ? void 0 : connection.send(action, get());
return r;
}
connection == null ? void 0 : connection.send(
{
...action,
type: `${store}/${action.type}`
},
{
...getTrackedConnectionState(options.name),
[store]: api.getState()
}
);
return r;
});
api.devtools = {
cleanup: () => {
if (connection && typeof connection.unsubscribe === "function") {
connection.unsubscribe();
}
removeStoreFromTrackedConnections(options.name, store);
}
};
const setStateFromDevtools = (...a) => {
const originalIsRecording = isRecording;
isRecording = false;
set(...a);
isRecording = originalIsRecording;
};
const initialState = fn(api.setState, get, api);
if (connectionInformation.type === "untracked") {
connection == null ? void 0 : connection.init(initialState);
} else {
connectionInformation.stores[connectionInformation.store] = api;
connection == null ? void 0 : connection.init(
Object.fromEntries(
Object.entries(connectionInformation.stores).map(([key, store2]) => [
key,
key === connectionInformation.store ? initialState : store2.getState()
])
)
);
}
if (api.dispatchFromDevtools && typeof api.dispatch === "function") {
let didWarnAboutReservedActionType = false;
const originalDispatch = api.dispatch;
api.dispatch = (...args) => {
if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && args[0].type === "__setState" && !didWarnAboutReservedActionType) {
console.warn(
'[zustand devtools middleware] "__setState" action type is reserved to set state from the devtools. Avoid using it.'
);
didWarnAboutReservedActionType = true;
}
originalDispatch(...args);
};
}
connection.subscribe((message) => {
var _a;
switch (message.type) {
case "ACTION":
if (typeof message.payload !== "string") {
console.error(
"[zustand devtools middleware] Unsupported action format"
);
return;
}
return parseJsonThen(
message.payload,
(action) => {
if (action.type === "__setState") {
if (store === void 0) {
setStateFromDevtools(action.state);
return;
}
if (Object.keys(action.state).length !== 1) {
console.error(
`
[zustand devtools middleware] Unsupported __setState action format.
When using 'store' option in devtools(), the 'state' should have only one key, which is a value of 'store' that was passed in devtools(),
and value of this only key should be a state object. Example: { "type": "__setState", "state": { "abc123Store": { "foo": "bar" } } }
`
);
}
const stateFromDevtools = action.state[store];
if (stateFromDevtools === void 0 || stateFromDevtools === null) {
return;
}
if (JSON.stringify(api.getState()) !== JSON.stringify(stateFromDevtools)) {
setStateFromDevtools(stateFromDevtools);
}
return;
}
if (!api.dispatchFromDevtools) return;
if (typeof api.dispatch !== "function") return;
api.dispatch(action);
}
);
case "DISPATCH":
switch (message.payload.type) {
case "RESET":
setStateFromDevtools(initialState);
if (store === void 0) {
return connection == null ? void 0 : connection.init(api.getState());
}
return connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));
case "COMMIT":
if (store === void 0) {
connection == null ? void 0 : connection.init(api.getState());
return;
}
return connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));
case "ROLLBACK":
return parseJsonThen(message.state, (state) => {
if (store === void 0) {
setStateFromDevtools(state);
connection == null ? void 0 : connection.init(api.getState());
return;
}
setStateFromDevtools(state[store]);
connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));
});
case "JUMP_TO_STATE":
case "JUMP_TO_ACTION":
return parseJsonThen(message.state, (state) => {
if (store === void 0) {
setStateFromDevtools(state);
return;
}
if (JSON.stringify(api.getState()) !== JSON.stringify(state[store])) {
setStateFromDevtools(state[store]);
}
});
case "IMPORT_STATE": {
const { nextLiftedState } = message.payload;
const lastComputedState = (_a = nextLiftedState.computedStates.slice(-1)[0]) == null ? void 0 : _a.state;
if (!lastComputedState) return;
if (store === void 0) {
setStateFromDevtools(lastComputedState);
} else {
setStateFromDevtools(lastComputedState[store]);
}
connection == null ? void 0 : connection.send(
null,
// FIXME no-any
nextLiftedState
);
return;
}
case "PAUSE_RECORDING":
return isRecording = !isRecording;
}
return;
}
});
return initialState;
};
const devtools = devtoolsImpl;
const parseJsonThen = (stringified, fn) => {
let parsed;
try {
parsed = JSON.parse(stringified);
} catch (e) {
console.error(
"[zustand devtools middleware] Could not parse the received json",
e
);
}
if (parsed !== void 0) fn(parsed);
};
const subscribeWithSelectorImpl = (fn) => (set, get, api) => {
const origSubscribe = api.subscribe;
api.subscribe = ((selector, optListener, options) => {
let listener = selector;
if (optListener) {
const equalityFn = (options == null ? void 0 : options.equalityFn) || Object.is;
let currentSlice = selector(api.getState());
listener = (state) => {
const nextSlice = selector(state);
if (!equalityFn(currentSlice, nextSlice)) {
const previousSlice = currentSlice;
optListener(currentSlice = nextSlice, previousSlice);
}
};
if (options == null ? void 0 : options.fireImmediately) {
optListener(currentSlice, currentSlice);
}
}
return origSubscribe(listener);
});
const initialState = fn(set, get, api);
return initialState;
};
const subscribeWithSelector = subscribeWithSelectorImpl;
function combine(initialState, create) {
return (...args) => Object.assign({}, initialState, create(...args));
}
function createJSONStorage(getStorage, options) {
let storage;
try {
storage = getStorage();
} catch (e) {
return;
}
const persistStorage = {
getItem: (name) => {
var _a;
const parse = (str2) => {
if (str2 === null) {
return null;
}
return JSON.parse(str2, options == null ? void 0 : options.reviver);
};
const str = (_a = storage.getItem(name)) != null ? _a : null;
if (str instanceof Promise) {
return str.then(parse);
}
return parse(str);
},
setItem: (name, newValue) => storage.setItem(name, JSON.stringify(newValue, options == null ? void 0 : options.replacer)),
removeItem: (name) => storage.removeItem(name)
};
return persistStorage;
}
const toThenable = (fn) => (input) => {
try {
const result = fn(input);
if (result instanceof Promise) {
return result;
}
return {
then(onFulfilled) {
return toThenable(onFulfilled)(result);
},
catch(_onRejected) {
return this;
}
};
} catch (e) {
return {
then(_onFulfilled) {
return this;
},
catch(onRejected) {
return toThenable(onRejected)(e);
}
};
}
};
const persistImpl = (config, baseOptions) => (set, get, api) => {
let options = {
storage: createJSONStorage(() => localStorage),
partialize: (state) => state,
version: 0,
merge: (persistedState, currentState) => ({
...currentState,
...persistedState
}),
...baseOptions
};
let hasHydrated = false;
const hydrationListeners = /* @__PURE__ */ new Set();
const finishHydrationListeners = /* @__PURE__ */ new Set();
let storage = options.storage;
if (!storage) {
return config(
(...args) => {
console.warn(
`[zustand persist middleware] Unable to update item '${options.name}', the given storage is currently unavailable.`
);
set(...args);
},
get,
api
);
}
const setItem = () => {
const state = options.partialize({ ...get() });
return storage.setItem(options.name, {
state,
version: options.version
});
};
const savedSetState = api.setState;
api.setState = (state, replace) => {
savedSetState(state, replace);
return setItem();
};
const configResult = config(
(...args) => {
set(...args);
return setItem();
},
get,
api
);
api.getInitialState = () => configResult;
let stateFromStorage;
const hydrate = () => {
var _a, _b;
if (!storage) return;
hasHydrated = false;
hydrationListeners.forEach((cb) => {
var _a2;
return cb((_a2 = get()) != null ? _a2 : configResult);
});
const postRehydrationCallback = ((_b = options.onRehydrateStorage) == null ? void 0 : _b.call(options, (_a = get()) != null ? _a : configResult)) || void 0;
return toThenable(storage.getItem.bind(storage))(options.name).then((deserializedStorageValue) => {
if (deserializedStorageValue) {
if (typeof deserializedStorageValue.version === "number" && deserializedStorageValue.version !== options.version) {
if (options.migrate) {
const migration = options.migrate(
deserializedStorageValue.state,
deserializedStorageValue.version
);
if (migration instanceof Promise) {
return migration.then((result) => [true, result]);
}
return [true, migration];
}
console.error(
`State loaded from storage couldn't be migrated since no migrate function was provided`
);
} else {
return [false, deserializedStorageValue.state];
}
}
return [false, void 0];
}).then((migrationResult) => {
var _a2;
const [migrated, migratedState] = migrationResult;
stateFromStorage = options.merge(
migratedState,
(_a2 = get()) != null ? _a2 : configResult
);
set(stateFromStorage, true);
if (migrated) {
return setItem();
}
}).then(() => {
postRehydrationCallback == null ? void 0 : postRehydrationCallback(stateFromStorage, void 0);
stateFromStorage = get();
hasHydrated = true;
finishHydrationListeners.forEach((cb) => cb(stateFromStorage));
}).catch((e) => {
postRehydrationCallback == null ? void 0 : postRehydrationCallback(void 0, e);
});
};
api.persist = {
setOptions: (newOptions) => {
options = {
...options,
...newOptions
};
if (newOptions.storage) {
storage = newOptions.storage;
}
},
clearStorage: () => {
storage == null ? void 0 : storage.removeItem(options.name);
},
getOptions: () => options,
rehydrate: () => hydrate(),
hasHydrated: () => hasHydrated,
onHydrate: (cb) => {
hydrationListeners.add(cb);
return () => {
hydrationListeners.delete(cb);
};
},
onFinishHydration: (cb) => {
finishHydrationListeners.add(cb);
return () => {
finishHydrationListeners.delete(cb);
};
}
};
if (!options.skipHydration) {
hydrate();
}
return stateFromStorage || configResult;
};
const persist = persistImpl;
export { combine, createJSONStorage, devtools, persist, redux, subscribeWithSelector };

4
node_modules/zustand/esm/middleware/combine.d.mts generated vendored Normal file
View File

@@ -0,0 +1,4 @@
import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla';
type Write<T, U> = Omit<T, keyof U> & U;
export declare function combine<T extends object, U extends object, Mps extends [StoreMutatorIdentifier, unknown][] = [], Mcs extends [StoreMutatorIdentifier, unknown][] = []>(initialState: T, create: StateCreator<T, Mps, Mcs, U>): StateCreator<Write<T, U>, Mps, Mcs>;
export {};

58
node_modules/zustand/esm/middleware/devtools.d.mts generated vendored Normal file
View File

@@ -0,0 +1,58 @@
import type { StateCreator, StoreApi, StoreMutatorIdentifier } from 'zustand/vanilla';
type Config = Parameters<(Window extends {
__REDUX_DEVTOOLS_EXTENSION__?: infer T;
} ? T : {
connect: (param: any) => any;
})['connect']>[0];
declare module '../vanilla.mjs' {
interface StoreMutators<S, A> {
'zustand/devtools': WithDevtools<S>;
}
}
type Cast<T, U> = T extends U ? T : U;
type Write<T, U> = Omit<T, keyof U> & U;
type TakeTwo<T> = T extends {
length: 0;
} ? [undefined, undefined] : T extends {
length: 1;
} ? [...args0: Cast<T, unknown[]>, arg1: undefined] : T extends {
length: 0 | 1;
} ? [...args0: Cast<T, unknown[]>, arg1: undefined] : T extends {
length: 2;
} ? T : T extends {
length: 1 | 2;
} ? T : T extends {
length: 0 | 1 | 2;
} ? T : T extends [infer A0, infer A1, ...unknown[]] ? [A0, A1] : T extends [infer A0, (infer A1)?, ...unknown[]] ? [A0, A1?] : T extends [(infer A0)?, (infer A1)?, ...unknown[]] ? [A0?, A1?] : never;
type WithDevtools<S> = Write<S, StoreDevtools<S>>;
type Action = string | {
type: string;
[x: string | number | symbol]: unknown;
};
type StoreDevtools<S> = S extends {
setState: {
(...args: infer Sa1): infer Sr1;
(...args: infer Sa2): infer Sr2;
};
} ? {
setState(...args: [...args: TakeTwo<Sa1>, action?: Action]): Sr1;
setState(...args: [...args: TakeTwo<Sa2>, action?: Action]): Sr2;
devtools: {
cleanup: () => void;
};
} : never;
export interface DevtoolsOptions extends Config {
name?: string;
enabled?: boolean;
anonymousActionType?: string;
store?: string;
}
type Devtools = <T, Mps extends [StoreMutatorIdentifier, unknown][] = [], Mcs extends [StoreMutatorIdentifier, unknown][] = [], U = T>(initializer: StateCreator<T, [...Mps, ['zustand/devtools', never]], Mcs, U>, devtoolsOptions?: DevtoolsOptions) => StateCreator<T, Mps, [['zustand/devtools', never], ...Mcs]>;
declare module '../vanilla.mjs' {
interface StoreMutators<S, A> {
'zustand/devtools': WithDevtools<S>;
}
}
export type NamedSet<T> = WithDevtools<StoreApi<T>>['setState'];
export declare const devtools: Devtools;
export {};

29
node_modules/zustand/esm/middleware/immer.d.mts generated vendored Normal file
View File

@@ -0,0 +1,29 @@
import type { Draft } from 'immer';
import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla';
type Immer = <T, Mps extends [StoreMutatorIdentifier, unknown][] = [], Mcs extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [...Mps, ['zustand/immer', never]], Mcs>) => StateCreator<T, Mps, [['zustand/immer', never], ...Mcs]>;
declare module '../vanilla.mjs' {
interface StoreMutators<S, A> {
['zustand/immer']: WithImmer<S>;
}
}
type Write<T, U> = Omit<T, keyof U> & U;
type SkipTwo<T> = T extends {
length: 0;
} ? [] : T extends {
length: 1;
} ? [] : T extends {
length: 0 | 1;
} ? [] : T extends [unknown, unknown, ...infer A] ? A : T extends [unknown, unknown?, ...infer A] ? A : T extends [unknown?, unknown?, ...infer A] ? A : never;
type SetStateType<T extends unknown[]> = Exclude<T[0], (...args: any[]) => any>;
type WithImmer<S> = Write<S, StoreImmer<S>>;
type StoreImmer<S> = S extends {
setState: infer SetState;
} ? SetState extends {
(...args: infer A1): infer Sr1;
(...args: infer A2): infer Sr2;
} ? {
setState(nextStateOrUpdater: SetStateType<A2> | Partial<SetStateType<A2>> | ((state: Draft<SetStateType<A2>>) => void), shouldReplace?: false, ...args: SkipTwo<A1>): Sr1;
setState(nextStateOrUpdater: SetStateType<A2> | ((state: Draft<SetStateType<A2>>) => void), shouldReplace: true, ...args: SkipTwo<A2>): Sr2;
} : never : never;
export declare const immer: Immer;
export {};

12
node_modules/zustand/esm/middleware/immer.mjs generated vendored Normal file
View File

@@ -0,0 +1,12 @@
import { produce } from 'immer';
const immerImpl = (initializer) => (set, get, store) => {
store.setState = (updater, replace, ...args) => {
const nextState = typeof updater === "function" ? produce(updater) : updater;
return set(nextState, replace, ...args);
};
return initializer(store.setState, get, store);
};
const immer = immerImpl;
export { immer };

99
node_modules/zustand/esm/middleware/persist.d.mts generated vendored Normal file
View File

@@ -0,0 +1,99 @@
import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla';
export interface StateStorage<R = unknown> {
getItem: (name: string) => string | null | Promise<string | null>;
setItem: (name: string, value: string) => R;
removeItem: (name: string) => R;
}
export type StorageValue<S> = {
state: S;
version?: number;
};
export interface PersistStorage<S, R = unknown> {
getItem: (name: string) => StorageValue<S> | null | Promise<StorageValue<S> | null>;
setItem: (name: string, value: StorageValue<S>) => R;
removeItem: (name: string) => R;
}
type JsonStorageOptions = {
reviver?: (key: string, value: unknown) => unknown;
replacer?: (key: string, value: unknown) => unknown;
};
export declare function createJSONStorage<S, R = unknown>(getStorage: () => StateStorage<R>, options?: JsonStorageOptions): PersistStorage<S, unknown> | undefined;
export interface PersistOptions<S, PersistedState = S, PersistReturn = unknown> {
/** Name of the storage (must be unique) */
name: string;
/**
* Use a custom persist storage.
*
* Combining `createJSONStorage` helps creating a persist storage
* with JSON.parse and JSON.stringify.
*
* @default createJSONStorage(() => localStorage)
*/
storage?: PersistStorage<PersistedState, PersistReturn> | undefined;
/**
* Filter the persisted value.
*
* @params state The state's value
*/
partialize?: (state: S) => PersistedState;
/**
* A function returning another (optional) function.
* The main function will be called before the state rehydration.
* The returned function will be called after the state rehydration or when an error occurred.
*/
onRehydrateStorage?: (state: S) => ((state?: S, error?: unknown) => void) | void;
/**
* If the stored state's version mismatch the one specified here, the storage will not be used.
* This is useful when adding a breaking change to your store.
*/
version?: number;
/**
* A function to perform persisted state migration.
* This function will be called when persisted state versions mismatch with the one specified here.
*/
migrate?: (persistedState: unknown, version: number) => PersistedState | Promise<PersistedState>;
/**
* A function to perform custom hydration merges when combining the stored state with the current one.
* By default, this function does a shallow merge.
*/
merge?: (persistedState: unknown, currentState: S) => S;
/**
* An optional boolean that will prevent the persist middleware from triggering hydration on initialization,
* This allows you to call `rehydrate()` at a specific point in your apps rendering life-cycle.
*
* This is useful in SSR application.
*
* @default false
*/
skipHydration?: boolean;
}
type PersistListener<S> = (state: S) => void;
type StorePersist<S, Ps, Pr> = S extends {
getState: () => infer T;
setState: {
(...args: infer Sa1): infer Sr1;
(...args: infer Sa2): infer Sr2;
};
} ? {
setState(...args: Sa1): Sr1 | Pr;
setState(...args: Sa2): Sr2 | Pr;
persist: {
setOptions: (options: Partial<PersistOptions<T, Ps, Pr>>) => void;
clearStorage: () => void;
rehydrate: () => Promise<void> | void;
hasHydrated: () => boolean;
onHydrate: (fn: PersistListener<T>) => () => void;
onFinishHydration: (fn: PersistListener<T>) => () => void;
getOptions: () => Partial<PersistOptions<T, Ps, Pr>>;
};
} : never;
type Persist = <T, Mps extends [StoreMutatorIdentifier, unknown][] = [], Mcs extends [StoreMutatorIdentifier, unknown][] = [], U = T>(initializer: StateCreator<T, [...Mps, ['zustand/persist', unknown]], Mcs>, options: PersistOptions<T, U>) => StateCreator<T, Mps, [['zustand/persist', U], ...Mcs]>;
declare module '../vanilla.mjs' {
interface StoreMutators<S, A> {
'zustand/persist': WithPersist<S, A>;
}
}
type Write<T, U> = Omit<T, keyof U> & U;
type WithPersist<S, A> = Write<S, StorePersist<S, A, unknown>>;
export declare const persist: Persist;
export {};

21
node_modules/zustand/esm/middleware/redux.d.mts generated vendored Normal file
View File

@@ -0,0 +1,21 @@
import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla';
type Write<T, U> = Omit<T, keyof U> & U;
type Action = {
type: string;
};
type StoreRedux<A> = {
dispatch: (a: A) => A;
dispatchFromDevtools: true;
};
type ReduxState<A> = {
dispatch: StoreRedux<A>['dispatch'];
};
type WithRedux<S, A> = Write<S, StoreRedux<A>>;
type Redux = <T, A extends Action, Cms extends [StoreMutatorIdentifier, unknown][] = []>(reducer: (state: T, action: A) => T, initialState: T) => StateCreator<Write<T, ReduxState<A>>, Cms, [['zustand/redux', A]]>;
declare module '../vanilla.mjs' {
interface StoreMutators<S, A> {
'zustand/redux': WithRedux<S, A>;
}
}
export declare const redux: Redux;
export {};

View File

@@ -0,0 +1,25 @@
import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla';
type SubscribeWithSelector = <T, Mps extends [StoreMutatorIdentifier, unknown][] = [], Mcs extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [
...Mps,
['zustand/subscribeWithSelector', never]
], Mcs>) => StateCreator<T, Mps, [['zustand/subscribeWithSelector', never], ...Mcs]>;
type Write<T, U> = Omit<T, keyof U> & U;
type WithSelectorSubscribe<S> = S extends {
getState: () => infer T;
} ? Write<S, StoreSubscribeWithSelector<T>> : never;
declare module '../vanilla.mjs' {
interface StoreMutators<S, A> {
['zustand/subscribeWithSelector']: WithSelectorSubscribe<S>;
}
}
type StoreSubscribeWithSelector<T> = {
subscribe: {
(listener: (selectedState: T, previousSelectedState: T) => void): () => void;
<U>(selector: (state: T) => U, listener: (selectedState: U, previousSelectedState: U) => void, options?: {
equalityFn?: (a: U, b: U) => boolean;
fireImmediately?: boolean;
}): () => void;
};
};
export declare const subscribeWithSelector: SubscribeWithSelector;
export {};

14
node_modules/zustand/esm/react.d.mts generated vendored Normal file
View File

@@ -0,0 +1,14 @@
import type { ExtractState, Mutate, StateCreator, StoreApi, StoreMutatorIdentifier } from 'zustand/vanilla';
type ReadonlyStoreApi<T> = Pick<StoreApi<T>, 'getState' | 'getInitialState' | 'subscribe'>;
export declare function useStore<S extends ReadonlyStoreApi<unknown>>(api: S): ExtractState<S>;
export declare function useStore<S extends ReadonlyStoreApi<unknown>, U>(api: S, selector: (state: ExtractState<S>) => U): U;
export type UseBoundStore<S extends ReadonlyStoreApi<unknown>> = {
(): ExtractState<S>;
<U>(selector: (state: ExtractState<S>) => U): U;
} & S;
type Create = {
<T, Mos extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [], Mos>): UseBoundStore<Mutate<StoreApi<T>, Mos>>;
<T>(): <Mos extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [], Mos>) => UseBoundStore<Mutate<StoreApi<T>, Mos>>;
};
export declare const create: Create;
export {};

22
node_modules/zustand/esm/react.mjs generated vendored Normal file
View File

@@ -0,0 +1,22 @@
import React from 'react';
import { createStore } from 'zustand/vanilla';
const identity = (arg) => arg;
function useStore(api, selector = identity) {
const slice = React.useSyncExternalStore(
api.subscribe,
React.useCallback(() => selector(api.getState()), [api, selector]),
React.useCallback(() => selector(api.getInitialState()), [api, selector])
);
React.useDebugValue(slice);
return slice;
}
const createImpl = (createState) => {
const api = createStore(createState);
const useBoundStore = (selector) => useStore(api, selector);
Object.assign(useBoundStore, api);
return useBoundStore;
};
const create = ((createState) => createState ? createImpl(createState) : createImpl);
export { create, useStore };

1
node_modules/zustand/esm/react/shallow.d.mts generated vendored Normal file
View File

@@ -0,0 +1 @@
export declare function useShallow<S, U>(selector: (state: S) => U): (state: S) => U;

12
node_modules/zustand/esm/react/shallow.mjs generated vendored Normal file
View File

@@ -0,0 +1,12 @@
import React from 'react';
import { shallow } from 'zustand/vanilla/shallow';
function useShallow(selector) {
const prev = React.useRef(void 0);
return (state) => {
const next = selector(state);
return shallow(prev.current, next) ? prev.current : prev.current = next;
};
}
export { useShallow };

2
node_modules/zustand/esm/shallow.d.mts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
export { shallow } from 'zustand/vanilla/shallow';
export { useShallow } from 'zustand/react/shallow';

2
node_modules/zustand/esm/shallow.mjs generated vendored Normal file
View File

@@ -0,0 +1,2 @@
export { shallow } from 'zustand/vanilla/shallow';
export { useShallow } from 'zustand/react/shallow';

14
node_modules/zustand/esm/traditional.d.mts generated vendored Normal file
View File

@@ -0,0 +1,14 @@
import type { ExtractState, Mutate, StateCreator, StoreApi, StoreMutatorIdentifier } from 'zustand/vanilla';
type ReadonlyStoreApi<T> = Pick<StoreApi<T>, 'getState' | 'getInitialState' | 'subscribe'>;
export declare function useStoreWithEqualityFn<S extends ReadonlyStoreApi<unknown>>(api: S): ExtractState<S>;
export declare function useStoreWithEqualityFn<S extends ReadonlyStoreApi<unknown>, U>(api: S, selector: (state: ExtractState<S>) => U, equalityFn?: (a: U, b: U) => boolean): U;
export type UseBoundStoreWithEqualityFn<S extends ReadonlyStoreApi<unknown>> = {
(): ExtractState<S>;
<U>(selector: (state: ExtractState<S>) => U, equalityFn?: (a: U, b: U) => boolean): U;
} & S;
type CreateWithEqualityFn = {
<T, Mos extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [], Mos>, defaultEqualityFn?: <U>(a: U, b: U) => boolean): UseBoundStoreWithEqualityFn<Mutate<StoreApi<T>, Mos>>;
<T>(): <Mos extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [], Mos>, defaultEqualityFn?: <U>(a: U, b: U) => boolean) => UseBoundStoreWithEqualityFn<Mutate<StoreApi<T>, Mos>>;
};
export declare const createWithEqualityFn: CreateWithEqualityFn;
export {};

26
node_modules/zustand/esm/traditional.mjs generated vendored Normal file
View File

@@ -0,0 +1,26 @@
import React from 'react';
import useSyncExternalStoreExports from 'use-sync-external-store/shim/with-selector.js';
import { createStore } from 'zustand/vanilla';
const { useSyncExternalStoreWithSelector } = useSyncExternalStoreExports;
const identity = (arg) => arg;
function useStoreWithEqualityFn(api, selector = identity, equalityFn) {
const slice = useSyncExternalStoreWithSelector(
api.subscribe,
api.getState,
api.getInitialState,
selector,
equalityFn
);
React.useDebugValue(slice);
return slice;
}
const createWithEqualityFnImpl = (createState, defaultEqualityFn) => {
const api = createStore(createState);
const useBoundStoreWithEqualityFn = (selector, equalityFn = defaultEqualityFn) => useStoreWithEqualityFn(api, selector, equalityFn);
Object.assign(useBoundStoreWithEqualityFn, api);
return useBoundStoreWithEqualityFn;
};
const createWithEqualityFn = ((createState, defaultEqualityFn) => createState ? createWithEqualityFnImpl(createState, defaultEqualityFn) : createWithEqualityFnImpl);
export { createWithEqualityFn, useStoreWithEqualityFn };

31
node_modules/zustand/esm/vanilla.d.mts generated vendored Normal file
View File

@@ -0,0 +1,31 @@
type SetStateInternal<T> = {
_(partial: T | Partial<T> | {
_(state: T): T | Partial<T>;
}['_'], replace?: false): void;
_(state: T | {
_(state: T): T;
}['_'], replace: true): void;
}['_'];
export interface StoreApi<T> {
setState: SetStateInternal<T>;
getState: () => T;
getInitialState: () => T;
subscribe: (listener: (state: T, prevState: T) => void) => () => void;
}
export type ExtractState<S> = S extends {
getState: () => infer T;
} ? T : never;
type Get<T, K, F> = K extends keyof T ? T[K] : F;
export type Mutate<S, Ms> = number extends Ms['length' & keyof Ms] ? S : Ms extends [] ? S : Ms extends [[infer Mi, infer Ma], ...infer Mrs] ? Mutate<StoreMutators<S, Ma>[Mi & StoreMutatorIdentifier], Mrs> : never;
export type StateCreator<T, Mis extends [StoreMutatorIdentifier, unknown][] = [], Mos extends [StoreMutatorIdentifier, unknown][] = [], U = T> = ((setState: Get<Mutate<StoreApi<T>, Mis>, 'setState', never>, getState: Get<Mutate<StoreApi<T>, Mis>, 'getState', never>, store: Mutate<StoreApi<T>, Mis>) => U) & {
$$storeMutators?: Mos;
};
export interface StoreMutators<S, A> {
}
export type StoreMutatorIdentifier = keyof StoreMutators<unknown, unknown>;
type CreateStore = {
<T, Mos extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [], Mos>): Mutate<StoreApi<T>, Mos>;
<T>(): <Mos extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [], Mos>) => Mutate<StoreApi<T>, Mos>;
};
export declare const createStore: CreateStore;
export {};

24
node_modules/zustand/esm/vanilla.mjs generated vendored Normal file
View File

@@ -0,0 +1,24 @@
const createStoreImpl = (createState) => {
let state;
const listeners = /* @__PURE__ */ new Set();
const setState = (partial, replace) => {
const nextState = typeof partial === "function" ? partial(state) : partial;
if (!Object.is(nextState, state)) {
const previousState = state;
state = (replace != null ? replace : typeof nextState !== "object" || nextState === null) ? nextState : Object.assign({}, state, nextState);
listeners.forEach((listener) => listener(state, previousState));
}
};
const getState = () => state;
const getInitialState = () => initialState;
const subscribe = (listener) => {
listeners.add(listener);
return () => listeners.delete(listener);
};
const api = { setState, getState, getInitialState, subscribe };
const initialState = state = createState(setState, getState, api);
return api;
};
const createStore = ((createState) => createState ? createStoreImpl(createState) : createStoreImpl);
export { createStore };

1
node_modules/zustand/esm/vanilla/shallow.d.mts generated vendored Normal file
View File

@@ -0,0 +1 @@
export declare function shallow<T>(valueA: T, valueB: T): boolean;

55
node_modules/zustand/esm/vanilla/shallow.mjs generated vendored Normal file
View File

@@ -0,0 +1,55 @@
const isIterable = (obj) => Symbol.iterator in obj;
const hasIterableEntries = (value) => (
// HACK: avoid checking entries type
"entries" in value
);
const compareEntries = (valueA, valueB) => {
const mapA = valueA instanceof Map ? valueA : new Map(valueA.entries());
const mapB = valueB instanceof Map ? valueB : new Map(valueB.entries());
if (mapA.size !== mapB.size) {
return false;
}
for (const [key, value] of mapA) {
if (!mapB.has(key) || !Object.is(value, mapB.get(key))) {
return false;
}
}
return true;
};
const compareIterables = (valueA, valueB) => {
const iteratorA = valueA[Symbol.iterator]();
const iteratorB = valueB[Symbol.iterator]();
let nextA = iteratorA.next();
let nextB = iteratorB.next();
while (!nextA.done && !nextB.done) {
if (!Object.is(nextA.value, nextB.value)) {
return false;
}
nextA = iteratorA.next();
nextB = iteratorB.next();
}
return !!nextA.done && !!nextB.done;
};
function shallow(valueA, valueB) {
if (Object.is(valueA, valueB)) {
return true;
}
if (typeof valueA !== "object" || valueA === null || typeof valueB !== "object" || valueB === null) {
return false;
}
if (Object.getPrototypeOf(valueA) !== Object.getPrototypeOf(valueB)) {
return false;
}
if (isIterable(valueA) && isIterable(valueB)) {
if (hasIterableEntries(valueA) && hasIterableEntries(valueB)) {
return compareEntries(valueA, valueB);
}
return compareIterables(valueA, valueB);
}
return compareEntries(
{ entries: () => Object.entries(valueA) },
{ entries: () => Object.entries(valueB) }
);
}
export { shallow };

2
node_modules/zustand/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
export * from 'zustand/vanilla';
export * from 'zustand/react';

19
node_modules/zustand/index.js generated vendored Normal file
View File

@@ -0,0 +1,19 @@
'use strict';
var vanilla = require('zustand/vanilla');
var react = require('zustand/react');
Object.keys(vanilla).forEach(function (k) {
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
enumerable: true,
get: function () { return vanilla[k]; }
});
});
Object.keys(react).forEach(function (k) {
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
enumerable: true,
get: function () { return react[k]; }
});
});

5
node_modules/zustand/middleware.d.ts generated vendored Normal file
View File

@@ -0,0 +1,5 @@
export { redux } from './middleware/redux';
export { devtools, type DevtoolsOptions, type NamedSet, } from './middleware/devtools';
export { subscribeWithSelector } from './middleware/subscribeWithSelector';
export { combine } from './middleware/combine';
export { persist, createJSONStorage, type StateStorage, type StorageValue, type PersistStorage, type PersistOptions, } from './middleware/persist';

469
node_modules/zustand/middleware.js generated vendored Normal file
View File

@@ -0,0 +1,469 @@
'use strict';
const reduxImpl = (reducer, initial) => (set, _get, api) => {
api.dispatch = (action) => {
set((state) => reducer(state, action), false, action);
return action;
};
api.dispatchFromDevtools = true;
return { dispatch: (...args) => api.dispatch(...args), ...initial };
};
const redux = reduxImpl;
const trackedConnections = /* @__PURE__ */ new Map();
const getTrackedConnectionState = (name) => {
const api = trackedConnections.get(name);
if (!api) return {};
return Object.fromEntries(
Object.entries(api.stores).map(([key, api2]) => [key, api2.getState()])
);
};
const extractConnectionInformation = (store, extensionConnector, options) => {
if (store === void 0) {
return {
type: "untracked",
connection: extensionConnector.connect(options)
};
}
const existingConnection = trackedConnections.get(options.name);
if (existingConnection) {
return { type: "tracked", store, ...existingConnection };
}
const newConnection = {
connection: extensionConnector.connect(options),
stores: {}
};
trackedConnections.set(options.name, newConnection);
return { type: "tracked", store, ...newConnection };
};
const removeStoreFromTrackedConnections = (name, store) => {
if (store === void 0) return;
const connectionInfo = trackedConnections.get(name);
if (!connectionInfo) return;
delete connectionInfo.stores[store];
if (Object.keys(connectionInfo.stores).length === 0) {
trackedConnections.delete(name);
}
};
const findCallerName = (stack) => {
var _a, _b;
if (!stack) return void 0;
const traceLines = stack.split("\n");
const apiSetStateLineIndex = traceLines.findIndex(
(traceLine) => traceLine.includes("api.setState")
);
if (apiSetStateLineIndex < 0) return void 0;
const callerLine = ((_a = traceLines[apiSetStateLineIndex + 1]) == null ? void 0 : _a.trim()) || "";
return (_b = /.+ (.+) .+/.exec(callerLine)) == null ? void 0 : _b[1];
};
const devtoolsImpl = (fn, devtoolsOptions = {}) => (set, get, api) => {
const { enabled, anonymousActionType, store, ...options } = devtoolsOptions;
let extensionConnector;
try {
extensionConnector = (enabled != null ? enabled : process.env.NODE_ENV !== "production") && window.__REDUX_DEVTOOLS_EXTENSION__;
} catch (e) {
}
if (!extensionConnector) {
return fn(set, get, api);
}
const { connection, ...connectionInformation } = extractConnectionInformation(store, extensionConnector, options);
let isRecording = true;
api.setState = ((state, replace, nameOrAction) => {
const r = set(state, replace);
if (!isRecording) return r;
const action = nameOrAction === void 0 ? {
type: anonymousActionType || findCallerName(new Error().stack) || "anonymous"
} : typeof nameOrAction === "string" ? { type: nameOrAction } : nameOrAction;
if (store === void 0) {
connection == null ? void 0 : connection.send(action, get());
return r;
}
connection == null ? void 0 : connection.send(
{
...action,
type: `${store}/${action.type}`
},
{
...getTrackedConnectionState(options.name),
[store]: api.getState()
}
);
return r;
});
api.devtools = {
cleanup: () => {
if (connection && typeof connection.unsubscribe === "function") {
connection.unsubscribe();
}
removeStoreFromTrackedConnections(options.name, store);
}
};
const setStateFromDevtools = (...a) => {
const originalIsRecording = isRecording;
isRecording = false;
set(...a);
isRecording = originalIsRecording;
};
const initialState = fn(api.setState, get, api);
if (connectionInformation.type === "untracked") {
connection == null ? void 0 : connection.init(initialState);
} else {
connectionInformation.stores[connectionInformation.store] = api;
connection == null ? void 0 : connection.init(
Object.fromEntries(
Object.entries(connectionInformation.stores).map(([key, store2]) => [
key,
key === connectionInformation.store ? initialState : store2.getState()
])
)
);
}
if (api.dispatchFromDevtools && typeof api.dispatch === "function") {
let didWarnAboutReservedActionType = false;
const originalDispatch = api.dispatch;
api.dispatch = (...args) => {
if (process.env.NODE_ENV !== "production" && args[0].type === "__setState" && !didWarnAboutReservedActionType) {
console.warn(
'[zustand devtools middleware] "__setState" action type is reserved to set state from the devtools. Avoid using it.'
);
didWarnAboutReservedActionType = true;
}
originalDispatch(...args);
};
}
connection.subscribe((message) => {
var _a;
switch (message.type) {
case "ACTION":
if (typeof message.payload !== "string") {
console.error(
"[zustand devtools middleware] Unsupported action format"
);
return;
}
return parseJsonThen(
message.payload,
(action) => {
if (action.type === "__setState") {
if (store === void 0) {
setStateFromDevtools(action.state);
return;
}
if (Object.keys(action.state).length !== 1) {
console.error(
`
[zustand devtools middleware] Unsupported __setState action format.
When using 'store' option in devtools(), the 'state' should have only one key, which is a value of 'store' that was passed in devtools(),
and value of this only key should be a state object. Example: { "type": "__setState", "state": { "abc123Store": { "foo": "bar" } } }
`
);
}
const stateFromDevtools = action.state[store];
if (stateFromDevtools === void 0 || stateFromDevtools === null) {
return;
}
if (JSON.stringify(api.getState()) !== JSON.stringify(stateFromDevtools)) {
setStateFromDevtools(stateFromDevtools);
}
return;
}
if (!api.dispatchFromDevtools) return;
if (typeof api.dispatch !== "function") return;
api.dispatch(action);
}
);
case "DISPATCH":
switch (message.payload.type) {
case "RESET":
setStateFromDevtools(initialState);
if (store === void 0) {
return connection == null ? void 0 : connection.init(api.getState());
}
return connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));
case "COMMIT":
if (store === void 0) {
connection == null ? void 0 : connection.init(api.getState());
return;
}
return connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));
case "ROLLBACK":
return parseJsonThen(message.state, (state) => {
if (store === void 0) {
setStateFromDevtools(state);
connection == null ? void 0 : connection.init(api.getState());
return;
}
setStateFromDevtools(state[store]);
connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));
});
case "JUMP_TO_STATE":
case "JUMP_TO_ACTION":
return parseJsonThen(message.state, (state) => {
if (store === void 0) {
setStateFromDevtools(state);
return;
}
if (JSON.stringify(api.getState()) !== JSON.stringify(state[store])) {
setStateFromDevtools(state[store]);
}
});
case "IMPORT_STATE": {
const { nextLiftedState } = message.payload;
const lastComputedState = (_a = nextLiftedState.computedStates.slice(-1)[0]) == null ? void 0 : _a.state;
if (!lastComputedState) return;
if (store === void 0) {
setStateFromDevtools(lastComputedState);
} else {
setStateFromDevtools(lastComputedState[store]);
}
connection == null ? void 0 : connection.send(
null,
// FIXME no-any
nextLiftedState
);
return;
}
case "PAUSE_RECORDING":
return isRecording = !isRecording;
}
return;
}
});
return initialState;
};
const devtools = devtoolsImpl;
const parseJsonThen = (stringified, fn) => {
let parsed;
try {
parsed = JSON.parse(stringified);
} catch (e) {
console.error(
"[zustand devtools middleware] Could not parse the received json",
e
);
}
if (parsed !== void 0) fn(parsed);
};
const subscribeWithSelectorImpl = (fn) => (set, get, api) => {
const origSubscribe = api.subscribe;
api.subscribe = ((selector, optListener, options) => {
let listener = selector;
if (optListener) {
const equalityFn = (options == null ? void 0 : options.equalityFn) || Object.is;
let currentSlice = selector(api.getState());
listener = (state) => {
const nextSlice = selector(state);
if (!equalityFn(currentSlice, nextSlice)) {
const previousSlice = currentSlice;
optListener(currentSlice = nextSlice, previousSlice);
}
};
if (options == null ? void 0 : options.fireImmediately) {
optListener(currentSlice, currentSlice);
}
}
return origSubscribe(listener);
});
const initialState = fn(set, get, api);
return initialState;
};
const subscribeWithSelector = subscribeWithSelectorImpl;
function combine(initialState, create) {
return (...args) => Object.assign({}, initialState, create(...args));
}
function createJSONStorage(getStorage, options) {
let storage;
try {
storage = getStorage();
} catch (e) {
return;
}
const persistStorage = {
getItem: (name) => {
var _a;
const parse = (str2) => {
if (str2 === null) {
return null;
}
return JSON.parse(str2, options == null ? void 0 : options.reviver);
};
const str = (_a = storage.getItem(name)) != null ? _a : null;
if (str instanceof Promise) {
return str.then(parse);
}
return parse(str);
},
setItem: (name, newValue) => storage.setItem(name, JSON.stringify(newValue, options == null ? void 0 : options.replacer)),
removeItem: (name) => storage.removeItem(name)
};
return persistStorage;
}
const toThenable = (fn) => (input) => {
try {
const result = fn(input);
if (result instanceof Promise) {
return result;
}
return {
then(onFulfilled) {
return toThenable(onFulfilled)(result);
},
catch(_onRejected) {
return this;
}
};
} catch (e) {
return {
then(_onFulfilled) {
return this;
},
catch(onRejected) {
return toThenable(onRejected)(e);
}
};
}
};
const persistImpl = (config, baseOptions) => (set, get, api) => {
let options = {
storage: createJSONStorage(() => localStorage),
partialize: (state) => state,
version: 0,
merge: (persistedState, currentState) => ({
...currentState,
...persistedState
}),
...baseOptions
};
let hasHydrated = false;
const hydrationListeners = /* @__PURE__ */ new Set();
const finishHydrationListeners = /* @__PURE__ */ new Set();
let storage = options.storage;
if (!storage) {
return config(
(...args) => {
console.warn(
`[zustand persist middleware] Unable to update item '${options.name}', the given storage is currently unavailable.`
);
set(...args);
},
get,
api
);
}
const setItem = () => {
const state = options.partialize({ ...get() });
return storage.setItem(options.name, {
state,
version: options.version
});
};
const savedSetState = api.setState;
api.setState = (state, replace) => {
savedSetState(state, replace);
return setItem();
};
const configResult = config(
(...args) => {
set(...args);
return setItem();
},
get,
api
);
api.getInitialState = () => configResult;
let stateFromStorage;
const hydrate = () => {
var _a, _b;
if (!storage) return;
hasHydrated = false;
hydrationListeners.forEach((cb) => {
var _a2;
return cb((_a2 = get()) != null ? _a2 : configResult);
});
const postRehydrationCallback = ((_b = options.onRehydrateStorage) == null ? void 0 : _b.call(options, (_a = get()) != null ? _a : configResult)) || void 0;
return toThenable(storage.getItem.bind(storage))(options.name).then((deserializedStorageValue) => {
if (deserializedStorageValue) {
if (typeof deserializedStorageValue.version === "number" && deserializedStorageValue.version !== options.version) {
if (options.migrate) {
const migration = options.migrate(
deserializedStorageValue.state,
deserializedStorageValue.version
);
if (migration instanceof Promise) {
return migration.then((result) => [true, result]);
}
return [true, migration];
}
console.error(
`State loaded from storage couldn't be migrated since no migrate function was provided`
);
} else {
return [false, deserializedStorageValue.state];
}
}
return [false, void 0];
}).then((migrationResult) => {
var _a2;
const [migrated, migratedState] = migrationResult;
stateFromStorage = options.merge(
migratedState,
(_a2 = get()) != null ? _a2 : configResult
);
set(stateFromStorage, true);
if (migrated) {
return setItem();
}
}).then(() => {
postRehydrationCallback == null ? void 0 : postRehydrationCallback(stateFromStorage, void 0);
stateFromStorage = get();
hasHydrated = true;
finishHydrationListeners.forEach((cb) => cb(stateFromStorage));
}).catch((e) => {
postRehydrationCallback == null ? void 0 : postRehydrationCallback(void 0, e);
});
};
api.persist = {
setOptions: (newOptions) => {
options = {
...options,
...newOptions
};
if (newOptions.storage) {
storage = newOptions.storage;
}
},
clearStorage: () => {
storage == null ? void 0 : storage.removeItem(options.name);
},
getOptions: () => options,
rehydrate: () => hydrate(),
hasHydrated: () => hasHydrated,
onHydrate: (cb) => {
hydrationListeners.add(cb);
return () => {
hydrationListeners.delete(cb);
};
},
onFinishHydration: (cb) => {
finishHydrationListeners.add(cb);
return () => {
finishHydrationListeners.delete(cb);
};
}
};
if (!options.skipHydration) {
hydrate();
}
return stateFromStorage || configResult;
};
const persist = persistImpl;
exports.combine = combine;
exports.createJSONStorage = createJSONStorage;
exports.devtools = devtools;
exports.persist = persist;
exports.redux = redux;
exports.subscribeWithSelector = subscribeWithSelector;

4
node_modules/zustand/middleware/combine.d.ts generated vendored Normal file
View File

@@ -0,0 +1,4 @@
import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla';
type Write<T, U> = Omit<T, keyof U> & U;
export declare function combine<T extends object, U extends object, Mps extends [StoreMutatorIdentifier, unknown][] = [], Mcs extends [StoreMutatorIdentifier, unknown][] = []>(initialState: T, create: StateCreator<T, Mps, Mcs, U>): StateCreator<Write<T, U>, Mps, Mcs>;
export {};

58
node_modules/zustand/middleware/devtools.d.ts generated vendored Normal file
View File

@@ -0,0 +1,58 @@
import type { StateCreator, StoreApi, StoreMutatorIdentifier } from 'zustand/vanilla';
type Config = Parameters<(Window extends {
__REDUX_DEVTOOLS_EXTENSION__?: infer T;
} ? T : {
connect: (param: any) => any;
})['connect']>[0];
declare module '../vanilla' {
interface StoreMutators<S, A> {
'zustand/devtools': WithDevtools<S>;
}
}
type Cast<T, U> = T extends U ? T : U;
type Write<T, U> = Omit<T, keyof U> & U;
type TakeTwo<T> = T extends {
length: 0;
} ? [undefined, undefined] : T extends {
length: 1;
} ? [...args0: Cast<T, unknown[]>, arg1: undefined] : T extends {
length: 0 | 1;
} ? [...args0: Cast<T, unknown[]>, arg1: undefined] : T extends {
length: 2;
} ? T : T extends {
length: 1 | 2;
} ? T : T extends {
length: 0 | 1 | 2;
} ? T : T extends [infer A0, infer A1, ...unknown[]] ? [A0, A1] : T extends [infer A0, (infer A1)?, ...unknown[]] ? [A0, A1?] : T extends [(infer A0)?, (infer A1)?, ...unknown[]] ? [A0?, A1?] : never;
type WithDevtools<S> = Write<S, StoreDevtools<S>>;
type Action = string | {
type: string;
[x: string | number | symbol]: unknown;
};
type StoreDevtools<S> = S extends {
setState: {
(...args: infer Sa1): infer Sr1;
(...args: infer Sa2): infer Sr2;
};
} ? {
setState(...args: [...args: TakeTwo<Sa1>, action?: Action]): Sr1;
setState(...args: [...args: TakeTwo<Sa2>, action?: Action]): Sr2;
devtools: {
cleanup: () => void;
};
} : never;
export interface DevtoolsOptions extends Config {
name?: string;
enabled?: boolean;
anonymousActionType?: string;
store?: string;
}
type Devtools = <T, Mps extends [StoreMutatorIdentifier, unknown][] = [], Mcs extends [StoreMutatorIdentifier, unknown][] = [], U = T>(initializer: StateCreator<T, [...Mps, ['zustand/devtools', never]], Mcs, U>, devtoolsOptions?: DevtoolsOptions) => StateCreator<T, Mps, [['zustand/devtools', never], ...Mcs]>;
declare module '../vanilla' {
interface StoreMutators<S, A> {
'zustand/devtools': WithDevtools<S>;
}
}
export type NamedSet<T> = WithDevtools<StoreApi<T>>['setState'];
export declare const devtools: Devtools;
export {};

29
node_modules/zustand/middleware/immer.d.ts generated vendored Normal file
View File

@@ -0,0 +1,29 @@
import type { Draft } from 'immer';
import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla';
type Immer = <T, Mps extends [StoreMutatorIdentifier, unknown][] = [], Mcs extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [...Mps, ['zustand/immer', never]], Mcs>) => StateCreator<T, Mps, [['zustand/immer', never], ...Mcs]>;
declare module '../vanilla' {
interface StoreMutators<S, A> {
['zustand/immer']: WithImmer<S>;
}
}
type Write<T, U> = Omit<T, keyof U> & U;
type SkipTwo<T> = T extends {
length: 0;
} ? [] : T extends {
length: 1;
} ? [] : T extends {
length: 0 | 1;
} ? [] : T extends [unknown, unknown, ...infer A] ? A : T extends [unknown, unknown?, ...infer A] ? A : T extends [unknown?, unknown?, ...infer A] ? A : never;
type SetStateType<T extends unknown[]> = Exclude<T[0], (...args: any[]) => any>;
type WithImmer<S> = Write<S, StoreImmer<S>>;
type StoreImmer<S> = S extends {
setState: infer SetState;
} ? SetState extends {
(...args: infer A1): infer Sr1;
(...args: infer A2): infer Sr2;
} ? {
setState(nextStateOrUpdater: SetStateType<A2> | Partial<SetStateType<A2>> | ((state: Draft<SetStateType<A2>>) => void), shouldReplace?: false, ...args: SkipTwo<A1>): Sr1;
setState(nextStateOrUpdater: SetStateType<A2> | ((state: Draft<SetStateType<A2>>) => void), shouldReplace: true, ...args: SkipTwo<A2>): Sr2;
} : never : never;
export declare const immer: Immer;
export {};

14
node_modules/zustand/middleware/immer.js generated vendored Normal file
View File

@@ -0,0 +1,14 @@
'use strict';
var immer$1 = require('immer');
const immerImpl = (initializer) => (set, get, store) => {
store.setState = (updater, replace, ...args) => {
const nextState = typeof updater === "function" ? immer$1.produce(updater) : updater;
return set(nextState, replace, ...args);
};
return initializer(store.setState, get, store);
};
const immer = immerImpl;
exports.immer = immer;

99
node_modules/zustand/middleware/persist.d.ts generated vendored Normal file
View File

@@ -0,0 +1,99 @@
import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla';
export interface StateStorage<R = unknown> {
getItem: (name: string) => string | null | Promise<string | null>;
setItem: (name: string, value: string) => R;
removeItem: (name: string) => R;
}
export type StorageValue<S> = {
state: S;
version?: number;
};
export interface PersistStorage<S, R = unknown> {
getItem: (name: string) => StorageValue<S> | null | Promise<StorageValue<S> | null>;
setItem: (name: string, value: StorageValue<S>) => R;
removeItem: (name: string) => R;
}
type JsonStorageOptions = {
reviver?: (key: string, value: unknown) => unknown;
replacer?: (key: string, value: unknown) => unknown;
};
export declare function createJSONStorage<S, R = unknown>(getStorage: () => StateStorage<R>, options?: JsonStorageOptions): PersistStorage<S, unknown> | undefined;
export interface PersistOptions<S, PersistedState = S, PersistReturn = unknown> {
/** Name of the storage (must be unique) */
name: string;
/**
* Use a custom persist storage.
*
* Combining `createJSONStorage` helps creating a persist storage
* with JSON.parse and JSON.stringify.
*
* @default createJSONStorage(() => localStorage)
*/
storage?: PersistStorage<PersistedState, PersistReturn> | undefined;
/**
* Filter the persisted value.
*
* @params state The state's value
*/
partialize?: (state: S) => PersistedState;
/**
* A function returning another (optional) function.
* The main function will be called before the state rehydration.
* The returned function will be called after the state rehydration or when an error occurred.
*/
onRehydrateStorage?: (state: S) => ((state?: S, error?: unknown) => void) | void;
/**
* If the stored state's version mismatch the one specified here, the storage will not be used.
* This is useful when adding a breaking change to your store.
*/
version?: number;
/**
* A function to perform persisted state migration.
* This function will be called when persisted state versions mismatch with the one specified here.
*/
migrate?: (persistedState: unknown, version: number) => PersistedState | Promise<PersistedState>;
/**
* A function to perform custom hydration merges when combining the stored state with the current one.
* By default, this function does a shallow merge.
*/
merge?: (persistedState: unknown, currentState: S) => S;
/**
* An optional boolean that will prevent the persist middleware from triggering hydration on initialization,
* This allows you to call `rehydrate()` at a specific point in your apps rendering life-cycle.
*
* This is useful in SSR application.
*
* @default false
*/
skipHydration?: boolean;
}
type PersistListener<S> = (state: S) => void;
type StorePersist<S, Ps, Pr> = S extends {
getState: () => infer T;
setState: {
(...args: infer Sa1): infer Sr1;
(...args: infer Sa2): infer Sr2;
};
} ? {
setState(...args: Sa1): Sr1 | Pr;
setState(...args: Sa2): Sr2 | Pr;
persist: {
setOptions: (options: Partial<PersistOptions<T, Ps, Pr>>) => void;
clearStorage: () => void;
rehydrate: () => Promise<void> | void;
hasHydrated: () => boolean;
onHydrate: (fn: PersistListener<T>) => () => void;
onFinishHydration: (fn: PersistListener<T>) => () => void;
getOptions: () => Partial<PersistOptions<T, Ps, Pr>>;
};
} : never;
type Persist = <T, Mps extends [StoreMutatorIdentifier, unknown][] = [], Mcs extends [StoreMutatorIdentifier, unknown][] = [], U = T>(initializer: StateCreator<T, [...Mps, ['zustand/persist', unknown]], Mcs>, options: PersistOptions<T, U>) => StateCreator<T, Mps, [['zustand/persist', U], ...Mcs]>;
declare module '../vanilla' {
interface StoreMutators<S, A> {
'zustand/persist': WithPersist<S, A>;
}
}
type Write<T, U> = Omit<T, keyof U> & U;
type WithPersist<S, A> = Write<S, StorePersist<S, A, unknown>>;
export declare const persist: Persist;
export {};

21
node_modules/zustand/middleware/redux.d.ts generated vendored Normal file
View File

@@ -0,0 +1,21 @@
import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla';
type Write<T, U> = Omit<T, keyof U> & U;
type Action = {
type: string;
};
type StoreRedux<A> = {
dispatch: (a: A) => A;
dispatchFromDevtools: true;
};
type ReduxState<A> = {
dispatch: StoreRedux<A>['dispatch'];
};
type WithRedux<S, A> = Write<S, StoreRedux<A>>;
type Redux = <T, A extends Action, Cms extends [StoreMutatorIdentifier, unknown][] = []>(reducer: (state: T, action: A) => T, initialState: T) => StateCreator<Write<T, ReduxState<A>>, Cms, [['zustand/redux', A]]>;
declare module '../vanilla' {
interface StoreMutators<S, A> {
'zustand/redux': WithRedux<S, A>;
}
}
export declare const redux: Redux;
export {};

View File

@@ -0,0 +1,25 @@
import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla';
type SubscribeWithSelector = <T, Mps extends [StoreMutatorIdentifier, unknown][] = [], Mcs extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [
...Mps,
['zustand/subscribeWithSelector', never]
], Mcs>) => StateCreator<T, Mps, [['zustand/subscribeWithSelector', never], ...Mcs]>;
type Write<T, U> = Omit<T, keyof U> & U;
type WithSelectorSubscribe<S> = S extends {
getState: () => infer T;
} ? Write<S, StoreSubscribeWithSelector<T>> : never;
declare module '../vanilla' {
interface StoreMutators<S, A> {
['zustand/subscribeWithSelector']: WithSelectorSubscribe<S>;
}
}
type StoreSubscribeWithSelector<T> = {
subscribe: {
(listener: (selectedState: T, previousSelectedState: T) => void): () => void;
<U>(selector: (state: T) => U, listener: (selectedState: U, previousSelectedState: U) => void, options?: {
equalityFn?: (a: U, b: U) => boolean;
fireImmediately?: boolean;
}): () => void;
};
};
export declare const subscribeWithSelector: SubscribeWithSelector;
export {};

108
node_modules/zustand/package.json generated vendored Normal file
View File

@@ -0,0 +1,108 @@
{
"name": "zustand",
"description": "🐻 Bear necessities for state management in React",
"private": false,
"type": "commonjs",
"version": "5.0.8",
"main": "./index.js",
"types": "./index.d.ts",
"typesVersions": {
">=4.5": {
"esm/*": [
"esm/*"
],
"*": [
"*"
]
},
"*": {
"esm/*": [
"ts_version_4.5_and_above_is_required.d.ts"
],
"*": [
"ts_version_4.5_and_above_is_required.d.ts"
]
}
},
"exports": {
"./package.json": "./package.json",
".": {
"react-native": {
"types": "./index.d.ts",
"default": "./index.js"
},
"import": {
"types": "./esm/index.d.mts",
"default": "./esm/index.mjs"
},
"default": {
"types": "./index.d.ts",
"default": "./index.js"
}
},
"./*": {
"react-native": {
"types": "./*.d.ts",
"default": "./*.js"
},
"import": {
"types": "./esm/*.d.mts",
"default": "./esm/*.mjs"
},
"default": {
"types": "./*.d.ts",
"default": "./*.js"
}
}
},
"files": [
"**"
],
"sideEffects": false,
"engines": {
"node": ">=12.20.0"
},
"repository": {
"type": "git",
"url": "git+https://github.com/pmndrs/zustand.git"
},
"keywords": [
"react",
"state",
"manager",
"management",
"redux",
"store"
],
"author": "Paul Henschel",
"contributors": [
"Jeremy Holcomb (https://github.com/JeremyRH)",
"Daishi Kato (https://github.com/dai-shi)"
],
"license": "MIT",
"bugs": {
"url": "https://github.com/pmndrs/zustand/issues"
},
"homepage": "https://github.com/pmndrs/zustand",
"packageManager": "pnpm@9.15.5",
"peerDependencies": {
"@types/react": ">=18.0.0",
"immer": ">=9.0.6",
"react": ">=18.0.0",
"use-sync-external-store": ">=1.2.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"immer": {
"optional": true
},
"react": {
"optional": true
},
"use-sync-external-store": {
"optional": true
}
}
}

14
node_modules/zustand/react.d.ts generated vendored Normal file
View File

@@ -0,0 +1,14 @@
import type { ExtractState, Mutate, StateCreator, StoreApi, StoreMutatorIdentifier } from 'zustand/vanilla';
type ReadonlyStoreApi<T> = Pick<StoreApi<T>, 'getState' | 'getInitialState' | 'subscribe'>;
export declare function useStore<S extends ReadonlyStoreApi<unknown>>(api: S): ExtractState<S>;
export declare function useStore<S extends ReadonlyStoreApi<unknown>, U>(api: S, selector: (state: ExtractState<S>) => U): U;
export type UseBoundStore<S extends ReadonlyStoreApi<unknown>> = {
(): ExtractState<S>;
<U>(selector: (state: ExtractState<S>) => U): U;
} & S;
type Create = {
<T, Mos extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [], Mos>): UseBoundStore<Mutate<StoreApi<T>, Mos>>;
<T>(): <Mos extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [], Mos>) => UseBoundStore<Mutate<StoreApi<T>, Mos>>;
};
export declare const create: Create;
export {};

25
node_modules/zustand/react.js generated vendored Normal file
View File

@@ -0,0 +1,25 @@
'use strict';
var React = require('react');
var vanilla = require('zustand/vanilla');
const identity = (arg) => arg;
function useStore(api, selector = identity) {
const slice = React.useSyncExternalStore(
api.subscribe,
React.useCallback(() => selector(api.getState()), [api, selector]),
React.useCallback(() => selector(api.getInitialState()), [api, selector])
);
React.useDebugValue(slice);
return slice;
}
const createImpl = (createState) => {
const api = vanilla.createStore(createState);
const useBoundStore = (selector) => useStore(api, selector);
Object.assign(useBoundStore, api);
return useBoundStore;
};
const create = ((createState) => createState ? createImpl(createState) : createImpl);
exports.create = create;
exports.useStore = useStore;

1
node_modules/zustand/react/shallow.d.ts generated vendored Normal file
View File

@@ -0,0 +1 @@
export declare function useShallow<S, U>(selector: (state: S) => U): (state: S) => U;

14
node_modules/zustand/react/shallow.js generated vendored Normal file
View File

@@ -0,0 +1,14 @@
'use strict';
var React = require('react');
var shallow = require('zustand/vanilla/shallow');
function useShallow(selector) {
const prev = React.useRef(void 0);
return (state) => {
const next = selector(state);
return shallow.shallow(prev.current, next) ? prev.current : prev.current = next;
};
}
exports.useShallow = useShallow;

2
node_modules/zustand/shallow.d.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
export { shallow } from 'zustand/vanilla/shallow';
export { useShallow } from 'zustand/react/shallow';

15
node_modules/zustand/shallow.js generated vendored Normal file
View File

@@ -0,0 +1,15 @@
'use strict';
var shallow = require('zustand/vanilla/shallow');
var shallow$1 = require('zustand/react/shallow');
Object.defineProperty(exports, "shallow", {
enumerable: true,
get: function () { return shallow.shallow; }
});
Object.defineProperty(exports, "useShallow", {
enumerable: true,
get: function () { return shallow$1.useShallow; }
});

14
node_modules/zustand/traditional.d.ts generated vendored Normal file
View File

@@ -0,0 +1,14 @@
import type { ExtractState, Mutate, StateCreator, StoreApi, StoreMutatorIdentifier } from 'zustand/vanilla';
type ReadonlyStoreApi<T> = Pick<StoreApi<T>, 'getState' | 'getInitialState' | 'subscribe'>;
export declare function useStoreWithEqualityFn<S extends ReadonlyStoreApi<unknown>>(api: S): ExtractState<S>;
export declare function useStoreWithEqualityFn<S extends ReadonlyStoreApi<unknown>, U>(api: S, selector: (state: ExtractState<S>) => U, equalityFn?: (a: U, b: U) => boolean): U;
export type UseBoundStoreWithEqualityFn<S extends ReadonlyStoreApi<unknown>> = {
(): ExtractState<S>;
<U>(selector: (state: ExtractState<S>) => U, equalityFn?: (a: U, b: U) => boolean): U;
} & S;
type CreateWithEqualityFn = {
<T, Mos extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [], Mos>, defaultEqualityFn?: <U>(a: U, b: U) => boolean): UseBoundStoreWithEqualityFn<Mutate<StoreApi<T>, Mos>>;
<T>(): <Mos extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [], Mos>, defaultEqualityFn?: <U>(a: U, b: U) => boolean) => UseBoundStoreWithEqualityFn<Mutate<StoreApi<T>, Mos>>;
};
export declare const createWithEqualityFn: CreateWithEqualityFn;
export {};

29
node_modules/zustand/traditional.js generated vendored Normal file
View File

@@ -0,0 +1,29 @@
'use strict';
var React = require('react');
var useSyncExternalStoreExports = require('use-sync-external-store/shim/with-selector');
var vanilla = require('zustand/vanilla');
const { useSyncExternalStoreWithSelector } = useSyncExternalStoreExports;
const identity = (arg) => arg;
function useStoreWithEqualityFn(api, selector = identity, equalityFn) {
const slice = useSyncExternalStoreWithSelector(
api.subscribe,
api.getState,
api.getInitialState,
selector,
equalityFn
);
React.useDebugValue(slice);
return slice;
}
const createWithEqualityFnImpl = (createState, defaultEqualityFn) => {
const api = vanilla.createStore(createState);
const useBoundStoreWithEqualityFn = (selector, equalityFn = defaultEqualityFn) => useStoreWithEqualityFn(api, selector, equalityFn);
Object.assign(useBoundStoreWithEqualityFn, api);
return useBoundStoreWithEqualityFn;
};
const createWithEqualityFn = ((createState, defaultEqualityFn) => createState ? createWithEqualityFnImpl(createState, defaultEqualityFn) : createWithEqualityFnImpl);
exports.createWithEqualityFn = createWithEqualityFn;
exports.useStoreWithEqualityFn = useStoreWithEqualityFn;

View File

31
node_modules/zustand/vanilla.d.ts generated vendored Normal file
View File

@@ -0,0 +1,31 @@
type SetStateInternal<T> = {
_(partial: T | Partial<T> | {
_(state: T): T | Partial<T>;
}['_'], replace?: false): void;
_(state: T | {
_(state: T): T;
}['_'], replace: true): void;
}['_'];
export interface StoreApi<T> {
setState: SetStateInternal<T>;
getState: () => T;
getInitialState: () => T;
subscribe: (listener: (state: T, prevState: T) => void) => () => void;
}
export type ExtractState<S> = S extends {
getState: () => infer T;
} ? T : never;
type Get<T, K, F> = K extends keyof T ? T[K] : F;
export type Mutate<S, Ms> = number extends Ms['length' & keyof Ms] ? S : Ms extends [] ? S : Ms extends [[infer Mi, infer Ma], ...infer Mrs] ? Mutate<StoreMutators<S, Ma>[Mi & StoreMutatorIdentifier], Mrs> : never;
export type StateCreator<T, Mis extends [StoreMutatorIdentifier, unknown][] = [], Mos extends [StoreMutatorIdentifier, unknown][] = [], U = T> = ((setState: Get<Mutate<StoreApi<T>, Mis>, 'setState', never>, getState: Get<Mutate<StoreApi<T>, Mis>, 'getState', never>, store: Mutate<StoreApi<T>, Mis>) => U) & {
$$storeMutators?: Mos;
};
export interface StoreMutators<S, A> {
}
export type StoreMutatorIdentifier = keyof StoreMutators<unknown, unknown>;
type CreateStore = {
<T, Mos extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [], Mos>): Mutate<StoreApi<T>, Mos>;
<T>(): <Mos extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [], Mos>) => Mutate<StoreApi<T>, Mos>;
};
export declare const createStore: CreateStore;
export {};

26
node_modules/zustand/vanilla.js generated vendored Normal file
View File

@@ -0,0 +1,26 @@
'use strict';
const createStoreImpl = (createState) => {
let state;
const listeners = /* @__PURE__ */ new Set();
const setState = (partial, replace) => {
const nextState = typeof partial === "function" ? partial(state) : partial;
if (!Object.is(nextState, state)) {
const previousState = state;
state = (replace != null ? replace : typeof nextState !== "object" || nextState === null) ? nextState : Object.assign({}, state, nextState);
listeners.forEach((listener) => listener(state, previousState));
}
};
const getState = () => state;
const getInitialState = () => initialState;
const subscribe = (listener) => {
listeners.add(listener);
return () => listeners.delete(listener);
};
const api = { setState, getState, getInitialState, subscribe };
const initialState = state = createState(setState, getState, api);
return api;
};
const createStore = ((createState) => createState ? createStoreImpl(createState) : createStoreImpl);
exports.createStore = createStore;

1
node_modules/zustand/vanilla/shallow.d.ts generated vendored Normal file
View File

@@ -0,0 +1 @@
export declare function shallow<T>(valueA: T, valueB: T): boolean;

57
node_modules/zustand/vanilla/shallow.js generated vendored Normal file
View File

@@ -0,0 +1,57 @@
'use strict';
const isIterable = (obj) => Symbol.iterator in obj;
const hasIterableEntries = (value) => (
// HACK: avoid checking entries type
"entries" in value
);
const compareEntries = (valueA, valueB) => {
const mapA = valueA instanceof Map ? valueA : new Map(valueA.entries());
const mapB = valueB instanceof Map ? valueB : new Map(valueB.entries());
if (mapA.size !== mapB.size) {
return false;
}
for (const [key, value] of mapA) {
if (!mapB.has(key) || !Object.is(value, mapB.get(key))) {
return false;
}
}
return true;
};
const compareIterables = (valueA, valueB) => {
const iteratorA = valueA[Symbol.iterator]();
const iteratorB = valueB[Symbol.iterator]();
let nextA = iteratorA.next();
let nextB = iteratorB.next();
while (!nextA.done && !nextB.done) {
if (!Object.is(nextA.value, nextB.value)) {
return false;
}
nextA = iteratorA.next();
nextB = iteratorB.next();
}
return !!nextA.done && !!nextB.done;
};
function shallow(valueA, valueB) {
if (Object.is(valueA, valueB)) {
return true;
}
if (typeof valueA !== "object" || valueA === null || typeof valueB !== "object" || valueB === null) {
return false;
}
if (Object.getPrototypeOf(valueA) !== Object.getPrototypeOf(valueB)) {
return false;
}
if (isIterable(valueA) && isIterable(valueB)) {
if (hasIterableEntries(valueA) && hasIterableEntries(valueB)) {
return compareEntries(valueA, valueB);
}
return compareIterables(valueA, valueB);
}
return compareEntries(
{ entries: () => Object.entries(valueA) },
{ entries: () => Object.entries(valueB) }
);
}
exports.shallow = shallow;

35
package-lock.json generated
View File

@@ -13,7 +13,8 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.8.1",
"recharts": "^2.5.0"
"recharts": "^2.5.0",
"zustand": "^5.0.8"
},
"devDependencies": {
"@types/react": "^18.0.28",
@@ -958,13 +959,13 @@
"version": "15.7.15",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
"integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
"dev": true
"devOptional": true
},
"node_modules/@types/react": {
"version": "18.3.26",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.26.tgz",
"integrity": "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==",
"dev": true,
"devOptional": true,
"dependencies": {
"@types/prop-types": "*",
"csstype": "^3.0.2"
@@ -5583,6 +5584,34 @@
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/zustand": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.8.tgz",
"integrity": "sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==",
"engines": {
"node": ">=12.20.0"
},
"peerDependencies": {
"@types/react": ">=18.0.0",
"immer": ">=9.0.6",
"react": ">=18.0.0",
"use-sync-external-store": ">=1.2.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"immer": {
"optional": true
},
"react": {
"optional": true
},
"use-sync-external-store": {
"optional": true
}
}
}
}
}

View File

@@ -10,12 +10,13 @@
"preview": "vite preview"
},
"dependencies": {
"axios": "^1.3.4",
"lucide-react": "^0.263.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.8.1",
"axios": "^1.3.4",
"recharts": "^2.5.0",
"lucide-react": "^0.263.1"
"zustand": "^5.0.8"
},
"devDependencies": {
"@types/react": "^18.0.28",

View File

@@ -1,16 +1,18 @@
import React from 'react';
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
import { AuthProvider, useAuth } from './context/AuthContext';
import { useAuthStore } from './store/authStore';
import Sidebar from './components/Sidebar';
import Navbar from './components/Navbar';
import Login from './pages/Login';
import Dashboard from './pages/Dashboard';
import Transactions from './pages/Transactions';
import Settings from './pages/Settings';
import ForgotPassword from './pages/ForgotPassword';
// Protected Route Component
const ProtectedRoute = ({ children }) => {
const { isAuthenticated, loading } = useAuth();
const isLoggedIn = useAuthStore((s) => s.isLoggedIn);
const loading = useAuthStore((s) => s.loading);
if (loading) {
return (
@@ -20,7 +22,7 @@ const ProtectedRoute = ({ children }) => {
);
}
return isAuthenticated ? children : <Navigate to="/login" />;
return isLoggedIn ? children : <Navigate to="/login" />;
};
// Main Layout Component
@@ -58,6 +60,7 @@ const AppRoutes = () => {
return (
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/forgot-password" element={<ForgotPassword />} />
<Route
path="/"
element={
@@ -96,13 +99,11 @@ const AppRoutes = () => {
// Main App Component
const App = () => {
return (
<AuthProvider>
<Router>
<div className="App">
<AppRoutes />
</div>
</Router>
</AuthProvider>
<Router>
<div className="App">
<AppRoutes />
</div>
</Router>
);
};

View File

@@ -1,9 +1,10 @@
import React, { useState } from 'react';
import { Menu, Sun, Moon, User, LogOut, ChevronDown } from 'lucide-react';
import { useAuth } from '../context/AuthContext';
import { signOut } from '../services/api';
import { useAuthStore } from '../store/authStore';
const Navbar = ({ onSidebarToggle }) => {
const { user, logout } = useAuth();
const isLoggedIn = useAuthStore((s) => s.isLoggedIn);
const [isDarkMode, setIsDarkMode] = useState(() => {
return localStorage.getItem('theme') === 'dark' ||
(!localStorage.getItem('theme') && window.matchMedia('(prefers-color-scheme: dark)').matches);
@@ -25,9 +26,14 @@ const Navbar = ({ onSidebarToggle }) => {
setIsDarkMode(!isDarkMode);
};
const handleLogout = () => {
logout();
setIsUserMenuOpen(false);
const handleLogout = async () => {
try {
await signOut();
} catch (e) {
// no-op; interceptor handles redirect and state
} finally {
setIsUserMenuOpen(false);
}
};
return (
@@ -71,7 +77,7 @@ const Navbar = ({ onSidebarToggle }) => {
<User className="h-4 w-4 text-blue-600 dark:text-blue-400" />
</div>
<span className="hidden sm:block text-sm font-medium">
{user?.name || 'Admin'}
{isLoggedIn ? 'Admin' : 'Guest'}
</span>
<ChevronDown className="h-4 w-4" />
</button>
@@ -81,10 +87,10 @@ const Navbar = ({ onSidebarToggle }) => {
<div className="absolute right-0 mt-2 w-48 bg-white dark:bg-gray-800 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 py-1 z-50">
<div className="px-4 py-2 border-b border-gray-200 dark:border-gray-700">
<p className="text-sm font-medium text-gray-900 dark:text-white">
{user?.name || 'Admin User'}
{isLoggedIn ? 'Admin User' : 'Guest'}
</p>
<p className="text-xs text-gray-500 dark:text-gray-400">
{user?.email || 'admin@example.com'}
{isLoggedIn ? 'admin@example.com' : ''}
</p>
</div>
<button

View File

@@ -0,0 +1,100 @@
import React, { useState } from 'react';
import { useNavigate, Link } from 'react-router-dom';
import { CreditCard } from 'lucide-react';
import { forgotPassword } from '../services/api';
const ForgotPassword = () => {
const [email, setEmail] = useState('');
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const [success, setSuccess] = useState('');
const navigate = useNavigate();
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
setError('');
setSuccess('');
try {
const res = await forgotPassword(email);
setSuccess(res?.message || 'If the email exists, a reset link was sent.');
} catch (err) {
setError(typeof err === 'string' ? err : 'Request failed. Please try again.');
} finally {
setLoading(false);
}
};
return (
<div className="min-h-screen bg-gray-50 dark:bg-gray-900 flex flex-col justify-center py-12 sm:px-6 lg:px-8">
<div className="sm:mx-auto sm:w-full sm:max-w-md">
<div className="flex justify-center">
<div className="bg-primary-600 p-3 rounded-full">
<CreditCard className="h-8 w-8 text-white" />
</div>
</div>
<h2 className="mt-6 text-center text-3xl font-bold text-gray-900 dark:text-white">
Forgot Password
</h2>
<p className="mt-2 text-center text-sm text-gray-600 dark:text-gray-400">
Enter your email to receive a new password
</p>
</div>
<div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
<div className="bg-white dark:bg-gray-800 py-8 px-4 shadow sm:rounded-lg sm:px-10 border border-gray-200 dark:border-gray-700">
<form className="space-y-6" onSubmit={handleSubmit}>
{error && (
<div className="bg-red-50 dark:bg-red-900 border border-red-200 dark:border-red-700 text-red-700 dark:text-red-300 px-4 py-3 rounded-md text-sm">
{error}
</div>
)}
{success && (
<div className="bg-green-50 dark:bg-green-900 border border-green-200 dark:border-green-700 text-green-700 dark:text-green-300 px-4 py-3 rounded-md text-sm">
{success}
</div>
)}
<div>
<label htmlFor="email" className="block text-sm font-medium text-gray-700 dark:text-gray-300">
Email address
</label>
<div className="mt-1">
<input
id="email"
name="email"
type="email"
autoComplete="email"
required
value={email}
onChange={(e) => setEmail(e.target.value)}
className="input-field"
placeholder="you@example.com"
/>
</div>
</div>
<div>
<button
type="submit"
disabled={loading}
className="w-full btn-primary disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center"
>
{loading ? 'Sending...' : 'Send new password'}
</button>
</div>
</form>
<div className="mt-6 text-center text-sm text-gray-600 dark:text-gray-400">
<Link to="/login" className="text-primary-600 hover:text-primary-700">Back to Login</Link>
</div>
</div>
</div>
</div>
);
};
export default ForgotPassword;

View File

@@ -1,7 +1,8 @@
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useAuth } from '../context/AuthContext';
import { CreditCard, Eye, EyeOff } from 'lucide-react';
import { login as apiLogin } from '../services/api';
import { useAuthStore } from '../store/authStore';
const Login = () => {
const [email, setEmail] = useState('');
@@ -10,7 +11,7 @@ const Login = () => {
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const { login } = useAuth();
const setLoggedIn = useAuthStore((s) => s.setLoggedIn);
const navigate = useNavigate();
const handleSubmit = async (e) => {
@@ -19,14 +20,16 @@ const Login = () => {
setError('');
try {
const result = await login(email, password);
if (result.success) {
const result = await apiLogin(email, password);
// If server responds successfully, consider logged in (session cookie via withCredentials)
if (result) {
setLoggedIn(true);
navigate('/');
} else {
setError('Invalid email or password');
}
} catch (err) {
setError('Login failed. Please try again.');
setError(typeof err === 'string' ? err : 'Login failed. Please try again.');
} finally {
setLoading(false);
}
@@ -140,8 +143,8 @@ const Login = () => {
</div>
<div className="mt-4 text-center text-sm text-gray-600 dark:text-gray-400">
<p>Email: admin@example.com</p>
<p>Password: password</p>
<p>Forget Password? <a href="/forgot-password" className="text-primary-600 hover:text-primary-700">Reset Password</a></p>
</div>
</div>
</div>

View File

@@ -1,43 +1,95 @@
import axios from 'axios';
// Create axios instance
import { useAuthStore } from "../store/authStore";
const BASE_URL = import.meta.env.DEV ? "/" : "https://khalijpay-core.qaserver.ir";
// ساخت instance از axios
const api = axios.create({
baseURL: import.meta.env.VITE_API_URL || 'http://localhost:3001/api',
timeout: 10000,
baseURL: BASE_URL,
withCredentials: true, // ارسال و دریافت cookie/session
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
});
// Request interceptor to add JWT token
api.interceptors.request.use(
(config) => {
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
// -----------------------------
// Interceptor پاسخ‌ها
// -----------------------------
api.interceptors.response.use(
(response) => response,
(error) => {
return Promise.reject(error);
if (error.response?.status === 401) {
// session منقضی شده → هدایت به login
const setLoggedIn = useAuthStore.getState().setLoggedIn;
setLoggedIn(false);
window.location.href = "/";
}
return Promise.reject(error.response?.data || error);
}
);
// Response interceptor to handle token expiration
api.interceptors.response.use(
(response) => {
return response;
},
(error) => {
if (error.response?.status === 401) {
// Token expired or invalid
localStorage.removeItem('token');
localStorage.removeItem('user');
window.location.href = '/login';
}
return Promise.reject(error);
// -----------------------------
// توابع API
// -----------------------------
// Login
export async function login(username, password) {
try {
const res = await api.post("/api/v1/Auth/SignIn", {
// include common variants to satisfy different backends
userName: username,
username: username,
email: username,
password: password,
});
return res.data;
} catch (error) {
throw error;
}
);
}
// خروج از سیستم
export async function signOut() {
try {
const res = await api.post("/api/v1/Auth/SignOut");
// پاک کردن وضعیت login در Zustand
const setLoggedIn = useAuthStore.getState().setLoggedIn;
setLoggedIn(false);
window.location.href = "/";
return res.data;
} catch (error) {
throw error;
}
}
// فراموشی رمز عبور
export async function forgotPassword(email) {
try {
const res = await api.post("/api/v1/Auth/ForgotPassword", { email });
return res.data;
} catch (error) {
throw error;
}
}
// گرفتن داده‌های محافظت‌شده
export async function fetchProtectedData(endpoint) {
try {
const res = await api.get(endpoint);
return res.data;
} catch (error) {
throw error;
}
}
// Mock data for development
const mockData = {
@@ -99,62 +151,12 @@ const mockData = {
]
};
// API functions
export const authAPI = {
login: async (email, password) => {
try {
const response = await api.post('/auth/login', { email, password });
return response.data;
} catch (error) {
// Return mock data for demo
return {
token: 'mock-jwt-token-' + Date.now(),
user: {
id: 1,
email: email,
name: 'Admin User',
role: 'admin'
}
};
}
}
};
// Expose mock payment API for dashboard until real endpoints are integrated
export const paymentsAPI = {
getStats: async () => {
try {
const response = await api.get('/payments/stats');
return response.data;
} catch (error) {
// Return mock data for demo
return mockData.stats;
}
async getStats() {
return mockData.stats;
},
getPayments: async (page = 1, limit = 10) => {
try {
const response = await api.get(`/payments?page=${page}&limit=${limit}`);
return response.data;
} catch (error) {
// Return mock data for demo
return {
data: mockData.payments,
total: mockData.payments.length,
page,
limit
};
}
async getChartData() {
return mockData.chartData;
},
getChartData: async () => {
try {
const response = await api.get('/payments/chart-data');
return response.data;
} catch (error) {
// Return mock data for demo
return mockData.chartData;
}
}
};
export default api;

8
src/store/authStore.js Normal file
View File

@@ -0,0 +1,8 @@
import { create } from "zustand";
export const useAuthStore = create((set) => ({
isLoggedIn: false,
loading: false,
setLoggedIn: (status) => set({ isLoggedIn: status }),
setLoading: (status) => set({ loading: status }),
}));

View File

@@ -4,4 +4,20 @@ import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
server: {
proxy: {
'/api': {
target: 'https://khalijpay-core.qaserver.ir',
changeOrigin: true,
secure: false,
configure: (proxy) => {
proxy.on('proxyReq', (proxyReq, req) => {
// Ensure cookies are forwarded for withCredentials
const origin = req.headers.origin;
if (origin) proxyReq.setHeader('origin', origin);
});
},
},
},
},
})