From 5079a5bc561d30e7c9b0c624665b85b278a75a18 Mon Sep 17 00:00:00 2001 From: ghazall-ag Date: Wed, 29 Oct 2025 22:43:48 +0330 Subject: [PATCH] feat : add signin ,signout, forgot password features --- node_modules/.package-lock.json | 32 +- node_modules/.vite/deps/_metadata.json | 26 +- node_modules/.vite/deps/zustand.js | 56 ++ node_modules/.vite/deps/zustand.js.map | 7 + node_modules/zustand/LICENSE | 21 + node_modules/zustand/README.md | 506 ++++++++++++++++++ node_modules/zustand/esm/index.d.mts | 2 + node_modules/zustand/esm/index.mjs | 2 + node_modules/zustand/esm/middleware.d.mts | 5 + node_modules/zustand/esm/middleware.mjs | 462 ++++++++++++++++ .../zustand/esm/middleware/combine.d.mts | 4 + .../zustand/esm/middleware/devtools.d.mts | 58 ++ .../zustand/esm/middleware/immer.d.mts | 29 + node_modules/zustand/esm/middleware/immer.mjs | 12 + .../zustand/esm/middleware/persist.d.mts | 99 ++++ .../zustand/esm/middleware/redux.d.mts | 21 + .../middleware/subscribeWithSelector.d.mts | 25 + node_modules/zustand/esm/react.d.mts | 14 + node_modules/zustand/esm/react.mjs | 22 + node_modules/zustand/esm/react/shallow.d.mts | 1 + node_modules/zustand/esm/react/shallow.mjs | 12 + node_modules/zustand/esm/shallow.d.mts | 2 + node_modules/zustand/esm/shallow.mjs | 2 + node_modules/zustand/esm/traditional.d.mts | 14 + node_modules/zustand/esm/traditional.mjs | 26 + node_modules/zustand/esm/vanilla.d.mts | 31 ++ node_modules/zustand/esm/vanilla.mjs | 24 + .../zustand/esm/vanilla/shallow.d.mts | 1 + node_modules/zustand/esm/vanilla/shallow.mjs | 55 ++ node_modules/zustand/index.d.ts | 2 + node_modules/zustand/index.js | 19 + node_modules/zustand/middleware.d.ts | 5 + node_modules/zustand/middleware.js | 469 ++++++++++++++++ node_modules/zustand/middleware/combine.d.ts | 4 + node_modules/zustand/middleware/devtools.d.ts | 58 ++ node_modules/zustand/middleware/immer.d.ts | 29 + node_modules/zustand/middleware/immer.js | 14 + node_modules/zustand/middleware/persist.d.ts | 99 ++++ node_modules/zustand/middleware/redux.d.ts | 21 + .../middleware/subscribeWithSelector.d.ts | 25 + node_modules/zustand/package.json | 108 ++++ node_modules/zustand/react.d.ts | 14 + node_modules/zustand/react.js | 25 + node_modules/zustand/react/shallow.d.ts | 1 + node_modules/zustand/react/shallow.js | 14 + node_modules/zustand/shallow.d.ts | 2 + node_modules/zustand/shallow.js | 15 + node_modules/zustand/traditional.d.ts | 14 + node_modules/zustand/traditional.js | 29 + .../ts_version_4.5_and_above_is_required.d.ts | 0 node_modules/zustand/vanilla.d.ts | 31 ++ node_modules/zustand/vanilla.js | 26 + node_modules/zustand/vanilla/shallow.d.ts | 1 + node_modules/zustand/vanilla/shallow.js | 57 ++ package-lock.json | 35 +- package.json | 5 +- src/App.jsx | 21 +- src/components/Navbar.jsx | 22 +- src/pages/ForgotPassword.jsx | 100 ++++ src/pages/Login.jsx | 17 +- src/services/api.js | 168 +++--- src/store/authStore.js | 8 + vite.config.js | 16 + 63 files changed, 2920 insertions(+), 125 deletions(-) create mode 100644 node_modules/.vite/deps/zustand.js create mode 100644 node_modules/.vite/deps/zustand.js.map create mode 100644 node_modules/zustand/LICENSE create mode 100644 node_modules/zustand/README.md create mode 100644 node_modules/zustand/esm/index.d.mts create mode 100644 node_modules/zustand/esm/index.mjs create mode 100644 node_modules/zustand/esm/middleware.d.mts create mode 100644 node_modules/zustand/esm/middleware.mjs create mode 100644 node_modules/zustand/esm/middleware/combine.d.mts create mode 100644 node_modules/zustand/esm/middleware/devtools.d.mts create mode 100644 node_modules/zustand/esm/middleware/immer.d.mts create mode 100644 node_modules/zustand/esm/middleware/immer.mjs create mode 100644 node_modules/zustand/esm/middleware/persist.d.mts create mode 100644 node_modules/zustand/esm/middleware/redux.d.mts create mode 100644 node_modules/zustand/esm/middleware/subscribeWithSelector.d.mts create mode 100644 node_modules/zustand/esm/react.d.mts create mode 100644 node_modules/zustand/esm/react.mjs create mode 100644 node_modules/zustand/esm/react/shallow.d.mts create mode 100644 node_modules/zustand/esm/react/shallow.mjs create mode 100644 node_modules/zustand/esm/shallow.d.mts create mode 100644 node_modules/zustand/esm/shallow.mjs create mode 100644 node_modules/zustand/esm/traditional.d.mts create mode 100644 node_modules/zustand/esm/traditional.mjs create mode 100644 node_modules/zustand/esm/vanilla.d.mts create mode 100644 node_modules/zustand/esm/vanilla.mjs create mode 100644 node_modules/zustand/esm/vanilla/shallow.d.mts create mode 100644 node_modules/zustand/esm/vanilla/shallow.mjs create mode 100644 node_modules/zustand/index.d.ts create mode 100644 node_modules/zustand/index.js create mode 100644 node_modules/zustand/middleware.d.ts create mode 100644 node_modules/zustand/middleware.js create mode 100644 node_modules/zustand/middleware/combine.d.ts create mode 100644 node_modules/zustand/middleware/devtools.d.ts create mode 100644 node_modules/zustand/middleware/immer.d.ts create mode 100644 node_modules/zustand/middleware/immer.js create mode 100644 node_modules/zustand/middleware/persist.d.ts create mode 100644 node_modules/zustand/middleware/redux.d.ts create mode 100644 node_modules/zustand/middleware/subscribeWithSelector.d.ts create mode 100644 node_modules/zustand/package.json create mode 100644 node_modules/zustand/react.d.ts create mode 100644 node_modules/zustand/react.js create mode 100644 node_modules/zustand/react/shallow.d.ts create mode 100644 node_modules/zustand/react/shallow.js create mode 100644 node_modules/zustand/shallow.d.ts create mode 100644 node_modules/zustand/shallow.js create mode 100644 node_modules/zustand/traditional.d.ts create mode 100644 node_modules/zustand/traditional.js create mode 100644 node_modules/zustand/ts_version_4.5_and_above_is_required.d.ts create mode 100644 node_modules/zustand/vanilla.d.ts create mode 100644 node_modules/zustand/vanilla.js create mode 100644 node_modules/zustand/vanilla/shallow.d.ts create mode 100644 node_modules/zustand/vanilla/shallow.js create mode 100644 src/pages/ForgotPassword.jsx create mode 100644 src/store/authStore.js diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json index c60ad2c..e2965ba 100644 --- a/node_modules/.package-lock.json +++ b/node_modules/.package-lock.json @@ -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 + } + } } } } diff --git a/node_modules/.vite/deps/_metadata.json b/node_modules/.vite/deps/_metadata.json index d919f56..c3cb136 100644 --- a/node_modules/.vite/deps/_metadata.json +++ b/node_modules/.vite/deps/_metadata.json @@ -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 } }, diff --git a/node_modules/.vite/deps/zustand.js b/node_modules/.vite/deps/zustand.js new file mode 100644 index 0000000..2a5126f --- /dev/null +++ b/node_modules/.vite/deps/zustand.js @@ -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 diff --git a/node_modules/.vite/deps/zustand.js.map b/node_modules/.vite/deps/zustand.js.map new file mode 100644 index 0000000..d557d6b --- /dev/null +++ b/node_modules/.vite/deps/zustand.js.map @@ -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"] +} diff --git a/node_modules/zustand/LICENSE b/node_modules/zustand/LICENSE new file mode 100644 index 0000000..a2c2649 --- /dev/null +++ b/node_modules/zustand/LICENSE @@ -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. diff --git a/node_modules/zustand/README.md b/node_modules/zustand/README.md new file mode 100644 index 0000000..a8f6375 --- /dev/null +++ b/node_modules/zustand/README.md @@ -0,0 +1,506 @@ +

+ +

+ +[![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

{bears} around here ...

+} + +function Controls() { + const increasePopulation = useBearStore((state) => state.increasePopulation) + return +} +``` + +### 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 = () => ( + + ... + +) + +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()(...)` 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()( + 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) diff --git a/node_modules/zustand/esm/index.d.mts b/node_modules/zustand/esm/index.d.mts new file mode 100644 index 0000000..a1afbf8 --- /dev/null +++ b/node_modules/zustand/esm/index.d.mts @@ -0,0 +1,2 @@ +export * from 'zustand/vanilla'; +export * from 'zustand/react'; diff --git a/node_modules/zustand/esm/index.mjs b/node_modules/zustand/esm/index.mjs new file mode 100644 index 0000000..a1afbf8 --- /dev/null +++ b/node_modules/zustand/esm/index.mjs @@ -0,0 +1,2 @@ +export * from 'zustand/vanilla'; +export * from 'zustand/react'; diff --git a/node_modules/zustand/esm/middleware.d.mts b/node_modules/zustand/esm/middleware.d.mts new file mode 100644 index 0000000..415816f --- /dev/null +++ b/node_modules/zustand/esm/middleware.d.mts @@ -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'; diff --git a/node_modules/zustand/esm/middleware.mjs b/node_modules/zustand/esm/middleware.mjs new file mode 100644 index 0000000..875cce3 --- /dev/null +++ b/node_modules/zustand/esm/middleware.mjs @@ -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 }; diff --git a/node_modules/zustand/esm/middleware/combine.d.mts b/node_modules/zustand/esm/middleware/combine.d.mts new file mode 100644 index 0000000..c6bd310 --- /dev/null +++ b/node_modules/zustand/esm/middleware/combine.d.mts @@ -0,0 +1,4 @@ +import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla'; +type Write = Omit & U; +export declare function combine(initialState: T, create: StateCreator): StateCreator, Mps, Mcs>; +export {}; diff --git a/node_modules/zustand/esm/middleware/devtools.d.mts b/node_modules/zustand/esm/middleware/devtools.d.mts new file mode 100644 index 0000000..64a95e9 --- /dev/null +++ b/node_modules/zustand/esm/middleware/devtools.d.mts @@ -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 { + 'zustand/devtools': WithDevtools; + } +} +type Cast = T extends U ? T : U; +type Write = Omit & U; +type TakeTwo = T extends { + length: 0; +} ? [undefined, undefined] : T extends { + length: 1; +} ? [...args0: Cast, arg1: undefined] : T extends { + length: 0 | 1; +} ? [...args0: Cast, 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 = Write>; +type Action = string | { + type: string; + [x: string | number | symbol]: unknown; +}; +type StoreDevtools = S extends { + setState: { + (...args: infer Sa1): infer Sr1; + (...args: infer Sa2): infer Sr2; + }; +} ? { + setState(...args: [...args: TakeTwo, action?: Action]): Sr1; + setState(...args: [...args: TakeTwo, action?: Action]): Sr2; + devtools: { + cleanup: () => void; + }; +} : never; +export interface DevtoolsOptions extends Config { + name?: string; + enabled?: boolean; + anonymousActionType?: string; + store?: string; +} +type Devtools = (initializer: StateCreator, devtoolsOptions?: DevtoolsOptions) => StateCreator; +declare module '../vanilla.mjs' { + interface StoreMutators { + 'zustand/devtools': WithDevtools; + } +} +export type NamedSet = WithDevtools>['setState']; +export declare const devtools: Devtools; +export {}; diff --git a/node_modules/zustand/esm/middleware/immer.d.mts b/node_modules/zustand/esm/middleware/immer.d.mts new file mode 100644 index 0000000..dd10e1f --- /dev/null +++ b/node_modules/zustand/esm/middleware/immer.d.mts @@ -0,0 +1,29 @@ +import type { Draft } from 'immer'; +import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla'; +type Immer = (initializer: StateCreator) => StateCreator; +declare module '../vanilla.mjs' { + interface StoreMutators { + ['zustand/immer']: WithImmer; + } +} +type Write = Omit & U; +type SkipTwo = 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 = Exclude any>; +type WithImmer = Write>; +type StoreImmer = S extends { + setState: infer SetState; +} ? SetState extends { + (...args: infer A1): infer Sr1; + (...args: infer A2): infer Sr2; +} ? { + setState(nextStateOrUpdater: SetStateType | Partial> | ((state: Draft>) => void), shouldReplace?: false, ...args: SkipTwo): Sr1; + setState(nextStateOrUpdater: SetStateType | ((state: Draft>) => void), shouldReplace: true, ...args: SkipTwo): Sr2; +} : never : never; +export declare const immer: Immer; +export {}; diff --git a/node_modules/zustand/esm/middleware/immer.mjs b/node_modules/zustand/esm/middleware/immer.mjs new file mode 100644 index 0000000..a526e82 --- /dev/null +++ b/node_modules/zustand/esm/middleware/immer.mjs @@ -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 }; diff --git a/node_modules/zustand/esm/middleware/persist.d.mts b/node_modules/zustand/esm/middleware/persist.d.mts new file mode 100644 index 0000000..69da8d6 --- /dev/null +++ b/node_modules/zustand/esm/middleware/persist.d.mts @@ -0,0 +1,99 @@ +import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla'; +export interface StateStorage { + getItem: (name: string) => string | null | Promise; + setItem: (name: string, value: string) => R; + removeItem: (name: string) => R; +} +export type StorageValue = { + state: S; + version?: number; +}; +export interface PersistStorage { + getItem: (name: string) => StorageValue | null | Promise | null>; + setItem: (name: string, value: StorageValue) => R; + removeItem: (name: string) => R; +} +type JsonStorageOptions = { + reviver?: (key: string, value: unknown) => unknown; + replacer?: (key: string, value: unknown) => unknown; +}; +export declare function createJSONStorage(getStorage: () => StateStorage, options?: JsonStorageOptions): PersistStorage | undefined; +export interface PersistOptions { + /** 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 | 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; + /** + * 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 = (state: S) => void; +type StorePersist = 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>) => void; + clearStorage: () => void; + rehydrate: () => Promise | void; + hasHydrated: () => boolean; + onHydrate: (fn: PersistListener) => () => void; + onFinishHydration: (fn: PersistListener) => () => void; + getOptions: () => Partial>; + }; +} : never; +type Persist = (initializer: StateCreator, options: PersistOptions) => StateCreator; +declare module '../vanilla.mjs' { + interface StoreMutators { + 'zustand/persist': WithPersist; + } +} +type Write = Omit & U; +type WithPersist = Write>; +export declare const persist: Persist; +export {}; diff --git a/node_modules/zustand/esm/middleware/redux.d.mts b/node_modules/zustand/esm/middleware/redux.d.mts new file mode 100644 index 0000000..bb297fd --- /dev/null +++ b/node_modules/zustand/esm/middleware/redux.d.mts @@ -0,0 +1,21 @@ +import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla'; +type Write = Omit & U; +type Action = { + type: string; +}; +type StoreRedux = { + dispatch: (a: A) => A; + dispatchFromDevtools: true; +}; +type ReduxState = { + dispatch: StoreRedux['dispatch']; +}; +type WithRedux = Write>; +type Redux = (reducer: (state: T, action: A) => T, initialState: T) => StateCreator>, Cms, [['zustand/redux', A]]>; +declare module '../vanilla.mjs' { + interface StoreMutators { + 'zustand/redux': WithRedux; + } +} +export declare const redux: Redux; +export {}; diff --git a/node_modules/zustand/esm/middleware/subscribeWithSelector.d.mts b/node_modules/zustand/esm/middleware/subscribeWithSelector.d.mts new file mode 100644 index 0000000..afe0f1e --- /dev/null +++ b/node_modules/zustand/esm/middleware/subscribeWithSelector.d.mts @@ -0,0 +1,25 @@ +import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla'; +type SubscribeWithSelector = (initializer: StateCreator) => StateCreator; +type Write = Omit & U; +type WithSelectorSubscribe = S extends { + getState: () => infer T; +} ? Write> : never; +declare module '../vanilla.mjs' { + interface StoreMutators { + ['zustand/subscribeWithSelector']: WithSelectorSubscribe; + } +} +type StoreSubscribeWithSelector = { + subscribe: { + (listener: (selectedState: T, previousSelectedState: T) => void): () => void; + (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 {}; diff --git a/node_modules/zustand/esm/react.d.mts b/node_modules/zustand/esm/react.d.mts new file mode 100644 index 0000000..e190f29 --- /dev/null +++ b/node_modules/zustand/esm/react.d.mts @@ -0,0 +1,14 @@ +import type { ExtractState, Mutate, StateCreator, StoreApi, StoreMutatorIdentifier } from 'zustand/vanilla'; +type ReadonlyStoreApi = Pick, 'getState' | 'getInitialState' | 'subscribe'>; +export declare function useStore>(api: S): ExtractState; +export declare function useStore, U>(api: S, selector: (state: ExtractState) => U): U; +export type UseBoundStore> = { + (): ExtractState; + (selector: (state: ExtractState) => U): U; +} & S; +type Create = { + (initializer: StateCreator): UseBoundStore, Mos>>; + (): (initializer: StateCreator) => UseBoundStore, Mos>>; +}; +export declare const create: Create; +export {}; diff --git a/node_modules/zustand/esm/react.mjs b/node_modules/zustand/esm/react.mjs new file mode 100644 index 0000000..8577f16 --- /dev/null +++ b/node_modules/zustand/esm/react.mjs @@ -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 }; diff --git a/node_modules/zustand/esm/react/shallow.d.mts b/node_modules/zustand/esm/react/shallow.d.mts new file mode 100644 index 0000000..9068d46 --- /dev/null +++ b/node_modules/zustand/esm/react/shallow.d.mts @@ -0,0 +1 @@ +export declare function useShallow(selector: (state: S) => U): (state: S) => U; diff --git a/node_modules/zustand/esm/react/shallow.mjs b/node_modules/zustand/esm/react/shallow.mjs new file mode 100644 index 0000000..570729c --- /dev/null +++ b/node_modules/zustand/esm/react/shallow.mjs @@ -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 }; diff --git a/node_modules/zustand/esm/shallow.d.mts b/node_modules/zustand/esm/shallow.d.mts new file mode 100644 index 0000000..806efca --- /dev/null +++ b/node_modules/zustand/esm/shallow.d.mts @@ -0,0 +1,2 @@ +export { shallow } from 'zustand/vanilla/shallow'; +export { useShallow } from 'zustand/react/shallow'; diff --git a/node_modules/zustand/esm/shallow.mjs b/node_modules/zustand/esm/shallow.mjs new file mode 100644 index 0000000..806efca --- /dev/null +++ b/node_modules/zustand/esm/shallow.mjs @@ -0,0 +1,2 @@ +export { shallow } from 'zustand/vanilla/shallow'; +export { useShallow } from 'zustand/react/shallow'; diff --git a/node_modules/zustand/esm/traditional.d.mts b/node_modules/zustand/esm/traditional.d.mts new file mode 100644 index 0000000..a039720 --- /dev/null +++ b/node_modules/zustand/esm/traditional.d.mts @@ -0,0 +1,14 @@ +import type { ExtractState, Mutate, StateCreator, StoreApi, StoreMutatorIdentifier } from 'zustand/vanilla'; +type ReadonlyStoreApi = Pick, 'getState' | 'getInitialState' | 'subscribe'>; +export declare function useStoreWithEqualityFn>(api: S): ExtractState; +export declare function useStoreWithEqualityFn, U>(api: S, selector: (state: ExtractState) => U, equalityFn?: (a: U, b: U) => boolean): U; +export type UseBoundStoreWithEqualityFn> = { + (): ExtractState; + (selector: (state: ExtractState) => U, equalityFn?: (a: U, b: U) => boolean): U; +} & S; +type CreateWithEqualityFn = { + (initializer: StateCreator, defaultEqualityFn?: (a: U, b: U) => boolean): UseBoundStoreWithEqualityFn, Mos>>; + (): (initializer: StateCreator, defaultEqualityFn?: (a: U, b: U) => boolean) => UseBoundStoreWithEqualityFn, Mos>>; +}; +export declare const createWithEqualityFn: CreateWithEqualityFn; +export {}; diff --git a/node_modules/zustand/esm/traditional.mjs b/node_modules/zustand/esm/traditional.mjs new file mode 100644 index 0000000..48fd788 --- /dev/null +++ b/node_modules/zustand/esm/traditional.mjs @@ -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 }; diff --git a/node_modules/zustand/esm/vanilla.d.mts b/node_modules/zustand/esm/vanilla.d.mts new file mode 100644 index 0000000..8f427f8 --- /dev/null +++ b/node_modules/zustand/esm/vanilla.d.mts @@ -0,0 +1,31 @@ +type SetStateInternal = { + _(partial: T | Partial | { + _(state: T): T | Partial; + }['_'], replace?: false): void; + _(state: T | { + _(state: T): T; + }['_'], replace: true): void; +}['_']; +export interface StoreApi { + setState: SetStateInternal; + getState: () => T; + getInitialState: () => T; + subscribe: (listener: (state: T, prevState: T) => void) => () => void; +} +export type ExtractState = S extends { + getState: () => infer T; +} ? T : never; +type Get = K extends keyof T ? T[K] : F; +export type Mutate = number extends Ms['length' & keyof Ms] ? S : Ms extends [] ? S : Ms extends [[infer Mi, infer Ma], ...infer Mrs] ? Mutate[Mi & StoreMutatorIdentifier], Mrs> : never; +export type StateCreator = ((setState: Get, Mis>, 'setState', never>, getState: Get, Mis>, 'getState', never>, store: Mutate, Mis>) => U) & { + $$storeMutators?: Mos; +}; +export interface StoreMutators { +} +export type StoreMutatorIdentifier = keyof StoreMutators; +type CreateStore = { + (initializer: StateCreator): Mutate, Mos>; + (): (initializer: StateCreator) => Mutate, Mos>; +}; +export declare const createStore: CreateStore; +export {}; diff --git a/node_modules/zustand/esm/vanilla.mjs b/node_modules/zustand/esm/vanilla.mjs new file mode 100644 index 0000000..3436c05 --- /dev/null +++ b/node_modules/zustand/esm/vanilla.mjs @@ -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 }; diff --git a/node_modules/zustand/esm/vanilla/shallow.d.mts b/node_modules/zustand/esm/vanilla/shallow.d.mts new file mode 100644 index 0000000..0e077a9 --- /dev/null +++ b/node_modules/zustand/esm/vanilla/shallow.d.mts @@ -0,0 +1 @@ +export declare function shallow(valueA: T, valueB: T): boolean; diff --git a/node_modules/zustand/esm/vanilla/shallow.mjs b/node_modules/zustand/esm/vanilla/shallow.mjs new file mode 100644 index 0000000..0cd203f --- /dev/null +++ b/node_modules/zustand/esm/vanilla/shallow.mjs @@ -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 }; diff --git a/node_modules/zustand/index.d.ts b/node_modules/zustand/index.d.ts new file mode 100644 index 0000000..a1afbf8 --- /dev/null +++ b/node_modules/zustand/index.d.ts @@ -0,0 +1,2 @@ +export * from 'zustand/vanilla'; +export * from 'zustand/react'; diff --git a/node_modules/zustand/index.js b/node_modules/zustand/index.js new file mode 100644 index 0000000..564d277 --- /dev/null +++ b/node_modules/zustand/index.js @@ -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]; } + }); +}); diff --git a/node_modules/zustand/middleware.d.ts b/node_modules/zustand/middleware.d.ts new file mode 100644 index 0000000..dc35768 --- /dev/null +++ b/node_modules/zustand/middleware.d.ts @@ -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'; diff --git a/node_modules/zustand/middleware.js b/node_modules/zustand/middleware.js new file mode 100644 index 0000000..8c89320 --- /dev/null +++ b/node_modules/zustand/middleware.js @@ -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; diff --git a/node_modules/zustand/middleware/combine.d.ts b/node_modules/zustand/middleware/combine.d.ts new file mode 100644 index 0000000..c6bd310 --- /dev/null +++ b/node_modules/zustand/middleware/combine.d.ts @@ -0,0 +1,4 @@ +import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla'; +type Write = Omit & U; +export declare function combine(initialState: T, create: StateCreator): StateCreator, Mps, Mcs>; +export {}; diff --git a/node_modules/zustand/middleware/devtools.d.ts b/node_modules/zustand/middleware/devtools.d.ts new file mode 100644 index 0000000..85233d7 --- /dev/null +++ b/node_modules/zustand/middleware/devtools.d.ts @@ -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 { + 'zustand/devtools': WithDevtools; + } +} +type Cast = T extends U ? T : U; +type Write = Omit & U; +type TakeTwo = T extends { + length: 0; +} ? [undefined, undefined] : T extends { + length: 1; +} ? [...args0: Cast, arg1: undefined] : T extends { + length: 0 | 1; +} ? [...args0: Cast, 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 = Write>; +type Action = string | { + type: string; + [x: string | number | symbol]: unknown; +}; +type StoreDevtools = S extends { + setState: { + (...args: infer Sa1): infer Sr1; + (...args: infer Sa2): infer Sr2; + }; +} ? { + setState(...args: [...args: TakeTwo, action?: Action]): Sr1; + setState(...args: [...args: TakeTwo, action?: Action]): Sr2; + devtools: { + cleanup: () => void; + }; +} : never; +export interface DevtoolsOptions extends Config { + name?: string; + enabled?: boolean; + anonymousActionType?: string; + store?: string; +} +type Devtools = (initializer: StateCreator, devtoolsOptions?: DevtoolsOptions) => StateCreator; +declare module '../vanilla' { + interface StoreMutators { + 'zustand/devtools': WithDevtools; + } +} +export type NamedSet = WithDevtools>['setState']; +export declare const devtools: Devtools; +export {}; diff --git a/node_modules/zustand/middleware/immer.d.ts b/node_modules/zustand/middleware/immer.d.ts new file mode 100644 index 0000000..bd7934d --- /dev/null +++ b/node_modules/zustand/middleware/immer.d.ts @@ -0,0 +1,29 @@ +import type { Draft } from 'immer'; +import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla'; +type Immer = (initializer: StateCreator) => StateCreator; +declare module '../vanilla' { + interface StoreMutators { + ['zustand/immer']: WithImmer; + } +} +type Write = Omit & U; +type SkipTwo = 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 = Exclude any>; +type WithImmer = Write>; +type StoreImmer = S extends { + setState: infer SetState; +} ? SetState extends { + (...args: infer A1): infer Sr1; + (...args: infer A2): infer Sr2; +} ? { + setState(nextStateOrUpdater: SetStateType | Partial> | ((state: Draft>) => void), shouldReplace?: false, ...args: SkipTwo): Sr1; + setState(nextStateOrUpdater: SetStateType | ((state: Draft>) => void), shouldReplace: true, ...args: SkipTwo): Sr2; +} : never : never; +export declare const immer: Immer; +export {}; diff --git a/node_modules/zustand/middleware/immer.js b/node_modules/zustand/middleware/immer.js new file mode 100644 index 0000000..c6db7ad --- /dev/null +++ b/node_modules/zustand/middleware/immer.js @@ -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; diff --git a/node_modules/zustand/middleware/persist.d.ts b/node_modules/zustand/middleware/persist.d.ts new file mode 100644 index 0000000..9bebf1a --- /dev/null +++ b/node_modules/zustand/middleware/persist.d.ts @@ -0,0 +1,99 @@ +import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla'; +export interface StateStorage { + getItem: (name: string) => string | null | Promise; + setItem: (name: string, value: string) => R; + removeItem: (name: string) => R; +} +export type StorageValue = { + state: S; + version?: number; +}; +export interface PersistStorage { + getItem: (name: string) => StorageValue | null | Promise | null>; + setItem: (name: string, value: StorageValue) => R; + removeItem: (name: string) => R; +} +type JsonStorageOptions = { + reviver?: (key: string, value: unknown) => unknown; + replacer?: (key: string, value: unknown) => unknown; +}; +export declare function createJSONStorage(getStorage: () => StateStorage, options?: JsonStorageOptions): PersistStorage | undefined; +export interface PersistOptions { + /** 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 | 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; + /** + * 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 = (state: S) => void; +type StorePersist = 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>) => void; + clearStorage: () => void; + rehydrate: () => Promise | void; + hasHydrated: () => boolean; + onHydrate: (fn: PersistListener) => () => void; + onFinishHydration: (fn: PersistListener) => () => void; + getOptions: () => Partial>; + }; +} : never; +type Persist = (initializer: StateCreator, options: PersistOptions) => StateCreator; +declare module '../vanilla' { + interface StoreMutators { + 'zustand/persist': WithPersist; + } +} +type Write = Omit & U; +type WithPersist = Write>; +export declare const persist: Persist; +export {}; diff --git a/node_modules/zustand/middleware/redux.d.ts b/node_modules/zustand/middleware/redux.d.ts new file mode 100644 index 0000000..509527c --- /dev/null +++ b/node_modules/zustand/middleware/redux.d.ts @@ -0,0 +1,21 @@ +import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla'; +type Write = Omit & U; +type Action = { + type: string; +}; +type StoreRedux = { + dispatch: (a: A) => A; + dispatchFromDevtools: true; +}; +type ReduxState = { + dispatch: StoreRedux['dispatch']; +}; +type WithRedux = Write>; +type Redux = (reducer: (state: T, action: A) => T, initialState: T) => StateCreator>, Cms, [['zustand/redux', A]]>; +declare module '../vanilla' { + interface StoreMutators { + 'zustand/redux': WithRedux; + } +} +export declare const redux: Redux; +export {}; diff --git a/node_modules/zustand/middleware/subscribeWithSelector.d.ts b/node_modules/zustand/middleware/subscribeWithSelector.d.ts new file mode 100644 index 0000000..ca35387 --- /dev/null +++ b/node_modules/zustand/middleware/subscribeWithSelector.d.ts @@ -0,0 +1,25 @@ +import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla'; +type SubscribeWithSelector = (initializer: StateCreator) => StateCreator; +type Write = Omit & U; +type WithSelectorSubscribe = S extends { + getState: () => infer T; +} ? Write> : never; +declare module '../vanilla' { + interface StoreMutators { + ['zustand/subscribeWithSelector']: WithSelectorSubscribe; + } +} +type StoreSubscribeWithSelector = { + subscribe: { + (listener: (selectedState: T, previousSelectedState: T) => void): () => void; + (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 {}; diff --git a/node_modules/zustand/package.json b/node_modules/zustand/package.json new file mode 100644 index 0000000..0cb517e --- /dev/null +++ b/node_modules/zustand/package.json @@ -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 + } + } +} diff --git a/node_modules/zustand/react.d.ts b/node_modules/zustand/react.d.ts new file mode 100644 index 0000000..e190f29 --- /dev/null +++ b/node_modules/zustand/react.d.ts @@ -0,0 +1,14 @@ +import type { ExtractState, Mutate, StateCreator, StoreApi, StoreMutatorIdentifier } from 'zustand/vanilla'; +type ReadonlyStoreApi = Pick, 'getState' | 'getInitialState' | 'subscribe'>; +export declare function useStore>(api: S): ExtractState; +export declare function useStore, U>(api: S, selector: (state: ExtractState) => U): U; +export type UseBoundStore> = { + (): ExtractState; + (selector: (state: ExtractState) => U): U; +} & S; +type Create = { + (initializer: StateCreator): UseBoundStore, Mos>>; + (): (initializer: StateCreator) => UseBoundStore, Mos>>; +}; +export declare const create: Create; +export {}; diff --git a/node_modules/zustand/react.js b/node_modules/zustand/react.js new file mode 100644 index 0000000..f0a3aed --- /dev/null +++ b/node_modules/zustand/react.js @@ -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; diff --git a/node_modules/zustand/react/shallow.d.ts b/node_modules/zustand/react/shallow.d.ts new file mode 100644 index 0000000..9068d46 --- /dev/null +++ b/node_modules/zustand/react/shallow.d.ts @@ -0,0 +1 @@ +export declare function useShallow(selector: (state: S) => U): (state: S) => U; diff --git a/node_modules/zustand/react/shallow.js b/node_modules/zustand/react/shallow.js new file mode 100644 index 0000000..d0cc55c --- /dev/null +++ b/node_modules/zustand/react/shallow.js @@ -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; diff --git a/node_modules/zustand/shallow.d.ts b/node_modules/zustand/shallow.d.ts new file mode 100644 index 0000000..806efca --- /dev/null +++ b/node_modules/zustand/shallow.d.ts @@ -0,0 +1,2 @@ +export { shallow } from 'zustand/vanilla/shallow'; +export { useShallow } from 'zustand/react/shallow'; diff --git a/node_modules/zustand/shallow.js b/node_modules/zustand/shallow.js new file mode 100644 index 0000000..e7ab019 --- /dev/null +++ b/node_modules/zustand/shallow.js @@ -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; } +}); diff --git a/node_modules/zustand/traditional.d.ts b/node_modules/zustand/traditional.d.ts new file mode 100644 index 0000000..a039720 --- /dev/null +++ b/node_modules/zustand/traditional.d.ts @@ -0,0 +1,14 @@ +import type { ExtractState, Mutate, StateCreator, StoreApi, StoreMutatorIdentifier } from 'zustand/vanilla'; +type ReadonlyStoreApi = Pick, 'getState' | 'getInitialState' | 'subscribe'>; +export declare function useStoreWithEqualityFn>(api: S): ExtractState; +export declare function useStoreWithEqualityFn, U>(api: S, selector: (state: ExtractState) => U, equalityFn?: (a: U, b: U) => boolean): U; +export type UseBoundStoreWithEqualityFn> = { + (): ExtractState; + (selector: (state: ExtractState) => U, equalityFn?: (a: U, b: U) => boolean): U; +} & S; +type CreateWithEqualityFn = { + (initializer: StateCreator, defaultEqualityFn?: (a: U, b: U) => boolean): UseBoundStoreWithEqualityFn, Mos>>; + (): (initializer: StateCreator, defaultEqualityFn?: (a: U, b: U) => boolean) => UseBoundStoreWithEqualityFn, Mos>>; +}; +export declare const createWithEqualityFn: CreateWithEqualityFn; +export {}; diff --git a/node_modules/zustand/traditional.js b/node_modules/zustand/traditional.js new file mode 100644 index 0000000..cbc391b --- /dev/null +++ b/node_modules/zustand/traditional.js @@ -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; diff --git a/node_modules/zustand/ts_version_4.5_and_above_is_required.d.ts b/node_modules/zustand/ts_version_4.5_and_above_is_required.d.ts new file mode 100644 index 0000000..e69de29 diff --git a/node_modules/zustand/vanilla.d.ts b/node_modules/zustand/vanilla.d.ts new file mode 100644 index 0000000..8f427f8 --- /dev/null +++ b/node_modules/zustand/vanilla.d.ts @@ -0,0 +1,31 @@ +type SetStateInternal = { + _(partial: T | Partial | { + _(state: T): T | Partial; + }['_'], replace?: false): void; + _(state: T | { + _(state: T): T; + }['_'], replace: true): void; +}['_']; +export interface StoreApi { + setState: SetStateInternal; + getState: () => T; + getInitialState: () => T; + subscribe: (listener: (state: T, prevState: T) => void) => () => void; +} +export type ExtractState = S extends { + getState: () => infer T; +} ? T : never; +type Get = K extends keyof T ? T[K] : F; +export type Mutate = number extends Ms['length' & keyof Ms] ? S : Ms extends [] ? S : Ms extends [[infer Mi, infer Ma], ...infer Mrs] ? Mutate[Mi & StoreMutatorIdentifier], Mrs> : never; +export type StateCreator = ((setState: Get, Mis>, 'setState', never>, getState: Get, Mis>, 'getState', never>, store: Mutate, Mis>) => U) & { + $$storeMutators?: Mos; +}; +export interface StoreMutators { +} +export type StoreMutatorIdentifier = keyof StoreMutators; +type CreateStore = { + (initializer: StateCreator): Mutate, Mos>; + (): (initializer: StateCreator) => Mutate, Mos>; +}; +export declare const createStore: CreateStore; +export {}; diff --git a/node_modules/zustand/vanilla.js b/node_modules/zustand/vanilla.js new file mode 100644 index 0000000..6f8dd6a --- /dev/null +++ b/node_modules/zustand/vanilla.js @@ -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; diff --git a/node_modules/zustand/vanilla/shallow.d.ts b/node_modules/zustand/vanilla/shallow.d.ts new file mode 100644 index 0000000..0e077a9 --- /dev/null +++ b/node_modules/zustand/vanilla/shallow.d.ts @@ -0,0 +1 @@ +export declare function shallow(valueA: T, valueB: T): boolean; diff --git a/node_modules/zustand/vanilla/shallow.js b/node_modules/zustand/vanilla/shallow.js new file mode 100644 index 0000000..1665ab5 --- /dev/null +++ b/node_modules/zustand/vanilla/shallow.js @@ -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; diff --git a/package-lock.json b/package-lock.json index 72889c3..6552b55 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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 + } + } } } } diff --git a/package.json b/package.json index b933b15..5f7a64e 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/App.jsx b/src/App.jsx index 28ff33c..5ac7495 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -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 : ; + return isLoggedIn ? children : ; }; // Main Layout Component @@ -58,6 +60,7 @@ const AppRoutes = () => { return ( } /> + } /> { // Main App Component const App = () => { return ( - - -
- -
-
-
+ +
+ +
+
); }; diff --git a/src/components/Navbar.jsx b/src/components/Navbar.jsx index 9208710..175dab2 100644 --- a/src/components/Navbar.jsx +++ b/src/components/Navbar.jsx @@ -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?.name || 'Admin'} + {isLoggedIn ? 'Admin' : 'Guest'} @@ -81,10 +87,10 @@ const Navbar = ({ onSidebarToggle }) => {

- {user?.name || 'Admin User'} + {isLoggedIn ? 'Admin User' : 'Guest'}

- {user?.email || 'admin@example.com'} + {isLoggedIn ? 'admin@example.com' : ''}

+
+ + +
+ Back to Login +
+ + + + ); +}; + +export default ForgotPassword; + + diff --git a/src/pages/Login.jsx b/src/pages/Login.jsx index abfd691..fa42bd3 100644 --- a/src/pages/Login.jsx +++ b/src/pages/Login.jsx @@ -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 = () => {
diff --git a/src/services/api.js b/src/services/api.js index af9444f..a06fe15 100644 --- a/src/services/api.js +++ b/src/services/api.js @@ -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; diff --git a/src/store/authStore.js b/src/store/authStore.js new file mode 100644 index 0000000..fe96042 --- /dev/null +++ b/src/store/authStore.js @@ -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 }), +})); diff --git a/vite.config.js b/vite.config.js index 5a33944..69b68f0 100644 --- a/vite.config.js +++ b/vite.config.js @@ -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); + }); + }, + }, + }, + }, })