pinia.prod.cjs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
  1. /*!
  2. * pinia v3.0.4
  3. * (c) 2025 Eduardo San Martin Morote
  4. * @license MIT
  5. */
  6. 'use strict';
  7. var vue = require('vue');
  8. require('@vue/devtools-api');
  9. /**
  10. * setActivePinia must be called to handle SSR at the top of functions like
  11. * `fetch`, `setup`, `serverPrefetch` and others
  12. */
  13. let activePinia;
  14. /**
  15. * Sets or unsets the active pinia. Used in SSR and internally when calling
  16. * actions and getters
  17. *
  18. * @param pinia - Pinia instance
  19. */
  20. // @ts-expect-error: cannot constrain the type of the return
  21. const setActivePinia = (pinia) => (activePinia = pinia);
  22. /**
  23. * Get the currently active pinia if there is any.
  24. */
  25. const getActivePinia = () => (vue.hasInjectionContext() && vue.inject(piniaSymbol)) || activePinia;
  26. const piniaSymbol = (/* istanbul ignore next */ Symbol());
  27. function isPlainObject(
  28. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  29. o) {
  30. return (o &&
  31. typeof o === 'object' &&
  32. Object.prototype.toString.call(o) === '[object Object]' &&
  33. typeof o.toJSON !== 'function');
  34. }
  35. // type DeepReadonly<T> = { readonly [P in keyof T]: DeepReadonly<T[P]> }
  36. // TODO: can we change these to numbers?
  37. /**
  38. * Possible types for SubscriptionCallback
  39. */
  40. exports.MutationType = void 0;
  41. (function (MutationType) {
  42. /**
  43. * Direct mutation of the state:
  44. *
  45. * - `store.name = 'new name'`
  46. * - `store.$state.name = 'new name'`
  47. * - `store.list.push('new item')`
  48. */
  49. MutationType["direct"] = "direct";
  50. /**
  51. * Mutated the state with `$patch` and an object
  52. *
  53. * - `store.$patch({ name: 'newName' })`
  54. */
  55. MutationType["patchObject"] = "patch object";
  56. /**
  57. * Mutated the state with `$patch` and a function
  58. *
  59. * - `store.$patch(state => state.name = 'newName')`
  60. */
  61. MutationType["patchFunction"] = "patch function";
  62. // maybe reset? for $state = {} and $reset
  63. })(exports.MutationType || (exports.MutationType = {}));
  64. /**
  65. * Creates a Pinia instance to be used by the application
  66. */
  67. function createPinia() {
  68. const scope = vue.effectScope(true);
  69. // NOTE: here we could check the window object for a state and directly set it
  70. // if there is anything like it with Vue 3 SSR
  71. const state = scope.run(() => vue.ref({}));
  72. let _p = [];
  73. // plugins added before calling app.use(pinia)
  74. let toBeInstalled = [];
  75. const pinia = vue.markRaw({
  76. install(app) {
  77. // this allows calling useStore() outside of a component setup after
  78. // installing pinia's plugin
  79. setActivePinia(pinia);
  80. pinia._a = app;
  81. app.provide(piniaSymbol, pinia);
  82. app.config.globalProperties.$pinia = pinia;
  83. toBeInstalled.forEach((plugin) => _p.push(plugin));
  84. toBeInstalled = [];
  85. },
  86. use(plugin) {
  87. if (!this._a) {
  88. toBeInstalled.push(plugin);
  89. }
  90. else {
  91. _p.push(plugin);
  92. }
  93. return this;
  94. },
  95. _p,
  96. // it's actually undefined here
  97. // @ts-expect-error
  98. _a: null,
  99. _e: scope,
  100. _s: new Map(),
  101. state,
  102. });
  103. return pinia;
  104. }
  105. /**
  106. * Dispose a Pinia instance by stopping its effectScope and removing the state, plugins and stores. This is mostly
  107. * useful in tests, with both a testing pinia or a regular pinia and in applications that use multiple pinia instances.
  108. * Once disposed, the pinia instance cannot be used anymore.
  109. *
  110. * @param pinia - pinia instance
  111. */
  112. function disposePinia(pinia) {
  113. pinia._e.stop();
  114. pinia._s.clear();
  115. pinia._p.splice(0);
  116. pinia.state.value = {};
  117. // @ts-expect-error: non valid
  118. pinia._a = null;
  119. }
  120. /**
  121. * Creates an _accept_ function to pass to `import.meta.hot` in Vite applications.
  122. *
  123. * @example
  124. * ```js
  125. * const useUser = defineStore(...)
  126. * if (import.meta.hot) {
  127. * import.meta.hot.accept(acceptHMRUpdate(useUser, import.meta.hot))
  128. * }
  129. * ```
  130. *
  131. * @param initialUseStore - return of the defineStore to hot update
  132. * @param hot - `import.meta.hot`
  133. */
  134. function acceptHMRUpdate(initialUseStore, hot) {
  135. // strip as much as possible from iife.prod
  136. {
  137. return () => { };
  138. }
  139. }
  140. const noop = () => { };
  141. function addSubscription(subscriptions, callback, detached, onCleanup = noop) {
  142. subscriptions.add(callback);
  143. const removeSubscription = () => {
  144. const isDel = subscriptions.delete(callback);
  145. isDel && onCleanup();
  146. };
  147. if (!detached && vue.getCurrentScope()) {
  148. vue.onScopeDispose(removeSubscription);
  149. }
  150. return removeSubscription;
  151. }
  152. function triggerSubscriptions(subscriptions, ...args) {
  153. subscriptions.forEach((callback) => {
  154. callback(...args);
  155. });
  156. }
  157. const fallbackRunWithContext = (fn) => fn();
  158. /**
  159. * Marks a function as an action for `$onAction`
  160. * @internal
  161. */
  162. const ACTION_MARKER = Symbol();
  163. /**
  164. * Action name symbol. Allows to add a name to an action after defining it
  165. * @internal
  166. */
  167. const ACTION_NAME = Symbol();
  168. function mergeReactiveObjects(target, patchToApply) {
  169. // Handle Map instances
  170. if (target instanceof Map && patchToApply instanceof Map) {
  171. patchToApply.forEach((value, key) => target.set(key, value));
  172. }
  173. else if (target instanceof Set && patchToApply instanceof Set) {
  174. // Handle Set instances
  175. patchToApply.forEach(target.add, target);
  176. }
  177. // no need to go through symbols because they cannot be serialized anyway
  178. for (const key in patchToApply) {
  179. if (!patchToApply.hasOwnProperty(key))
  180. continue;
  181. const subPatch = patchToApply[key];
  182. const targetValue = target[key];
  183. if (isPlainObject(targetValue) &&
  184. isPlainObject(subPatch) &&
  185. target.hasOwnProperty(key) &&
  186. !vue.isRef(subPatch) &&
  187. !vue.isReactive(subPatch)) {
  188. // NOTE: here I wanted to warn about inconsistent types but it's not possible because in setup stores one might
  189. // start the value of a property as a certain type e.g. a Map, and then for some reason, during SSR, change that
  190. // to `undefined`. When trying to hydrate, we want to override the Map with `undefined`.
  191. target[key] = mergeReactiveObjects(targetValue, subPatch);
  192. }
  193. else {
  194. // @ts-expect-error: subPatch is a valid value
  195. target[key] = subPatch;
  196. }
  197. }
  198. return target;
  199. }
  200. const skipHydrateSymbol = /* istanbul ignore next */ Symbol();
  201. /**
  202. * Tells Pinia to skip the hydration process of a given object. This is useful in setup stores (only) when you return a
  203. * stateful object in the store but it isn't really state. e.g. returning a router instance in a setup store.
  204. *
  205. * @param obj - target object
  206. * @returns obj
  207. */
  208. function skipHydrate(obj) {
  209. return Object.defineProperty(obj, skipHydrateSymbol, {});
  210. }
  211. /**
  212. * Returns whether a value should be hydrated
  213. *
  214. * @param obj - target variable
  215. * @returns true if `obj` should be hydrated
  216. */
  217. function shouldHydrate(obj) {
  218. return (!isPlainObject(obj) ||
  219. !Object.prototype.hasOwnProperty.call(obj, skipHydrateSymbol));
  220. }
  221. const { assign } = Object;
  222. function isComputed(o) {
  223. return !!(vue.isRef(o) && o.effect);
  224. }
  225. function createOptionsStore(id, options, pinia, hot) {
  226. const { state, actions, getters } = options;
  227. const initialState = pinia.state.value[id];
  228. let store;
  229. function setup() {
  230. if (!initialState && (true)) {
  231. /* istanbul ignore if */
  232. pinia.state.value[id] = state ? state() : {};
  233. }
  234. // avoid creating a state in pinia.state.value
  235. const localState = vue.toRefs(pinia.state.value[id]);
  236. return assign(localState, actions, Object.keys(getters || {}).reduce((computedGetters, name) => {
  237. computedGetters[name] = vue.markRaw(vue.computed(() => {
  238. setActivePinia(pinia);
  239. // it was created just before
  240. const store = pinia._s.get(id);
  241. // allow cross using stores
  242. // @ts-expect-error
  243. // return getters![name].call(context, context)
  244. // TODO: avoid reading the getter while assigning with a global variable
  245. return getters[name].call(store, store);
  246. }));
  247. return computedGetters;
  248. }, {}));
  249. }
  250. store = createSetupStore(id, setup, options, pinia, hot, true);
  251. return store;
  252. }
  253. function createSetupStore($id, setup, options = {}, pinia, hot, isOptionsStore) {
  254. let scope;
  255. const optionsForPlugin = assign({ actions: {} }, options);
  256. // watcher options for $subscribe
  257. const $subscribeOptions = { deep: true };
  258. // internal state
  259. let isListening; // set to true at the end
  260. let isSyncListening; // set to true at the end
  261. let subscriptions = new Set();
  262. let actionSubscriptions = new Set();
  263. let debuggerEvents;
  264. const initialState = pinia.state.value[$id];
  265. // avoid setting the state for option stores if it is set
  266. // by the setup
  267. if (!isOptionsStore && !initialState && (true)) {
  268. /* istanbul ignore if */
  269. pinia.state.value[$id] = {};
  270. }
  271. vue.ref({});
  272. // avoid triggering too many listeners
  273. // https://github.com/vuejs/pinia/issues/1129
  274. let activeListener;
  275. function $patch(partialStateOrMutator) {
  276. let subscriptionMutation;
  277. isListening = isSyncListening = false;
  278. if (typeof partialStateOrMutator === 'function') {
  279. partialStateOrMutator(pinia.state.value[$id]);
  280. subscriptionMutation = {
  281. type: exports.MutationType.patchFunction,
  282. storeId: $id,
  283. events: debuggerEvents,
  284. };
  285. }
  286. else {
  287. mergeReactiveObjects(pinia.state.value[$id], partialStateOrMutator);
  288. subscriptionMutation = {
  289. type: exports.MutationType.patchObject,
  290. payload: partialStateOrMutator,
  291. storeId: $id,
  292. events: debuggerEvents,
  293. };
  294. }
  295. const myListenerId = (activeListener = Symbol());
  296. vue.nextTick().then(() => {
  297. if (activeListener === myListenerId) {
  298. isListening = true;
  299. }
  300. });
  301. isSyncListening = true;
  302. // because we paused the watcher, we need to manually call the subscriptions
  303. triggerSubscriptions(subscriptions, subscriptionMutation, pinia.state.value[$id]);
  304. }
  305. const $reset = isOptionsStore
  306. ? function $reset() {
  307. const { state } = options;
  308. const newState = state ? state() : {};
  309. // we use a patch to group all changes into one single subscription
  310. this.$patch(($state) => {
  311. // @ts-expect-error: FIXME: shouldn't error?
  312. assign($state, newState);
  313. });
  314. }
  315. : /* istanbul ignore next */
  316. noop;
  317. function $dispose() {
  318. scope.stop();
  319. subscriptions.clear();
  320. actionSubscriptions.clear();
  321. pinia._s.delete($id);
  322. }
  323. /**
  324. * Helper that wraps function so it can be tracked with $onAction
  325. * @param fn - action to wrap
  326. * @param name - name of the action
  327. */
  328. const action = (fn, name = '') => {
  329. if (ACTION_MARKER in fn) {
  330. fn[ACTION_NAME] = name;
  331. return fn;
  332. }
  333. const wrappedAction = function () {
  334. setActivePinia(pinia);
  335. const args = Array.from(arguments);
  336. const afterCallbackSet = new Set();
  337. const onErrorCallbackSet = new Set();
  338. function after(callback) {
  339. afterCallbackSet.add(callback);
  340. }
  341. function onError(callback) {
  342. onErrorCallbackSet.add(callback);
  343. }
  344. // @ts-expect-error
  345. triggerSubscriptions(actionSubscriptions, {
  346. args,
  347. name: wrappedAction[ACTION_NAME],
  348. store,
  349. after,
  350. onError,
  351. });
  352. let ret;
  353. try {
  354. ret = fn.apply(this && this.$id === $id ? this : store, args);
  355. // handle sync errors
  356. }
  357. catch (error) {
  358. triggerSubscriptions(onErrorCallbackSet, error);
  359. throw error;
  360. }
  361. if (ret instanceof Promise) {
  362. return ret
  363. .then((value) => {
  364. triggerSubscriptions(afterCallbackSet, value);
  365. return value;
  366. })
  367. .catch((error) => {
  368. triggerSubscriptions(onErrorCallbackSet, error);
  369. return Promise.reject(error);
  370. });
  371. }
  372. // trigger after callbacks
  373. triggerSubscriptions(afterCallbackSet, ret);
  374. return ret;
  375. };
  376. wrappedAction[ACTION_MARKER] = true;
  377. wrappedAction[ACTION_NAME] = name; // will be set later
  378. // @ts-expect-error: we are intentionally limiting the returned type to just Fn
  379. // because all the added properties are internals that are exposed through `$onAction()` only
  380. return wrappedAction;
  381. };
  382. const partialStore = {
  383. _p: pinia,
  384. // _s: scope,
  385. $id,
  386. $onAction: addSubscription.bind(null, actionSubscriptions),
  387. $patch,
  388. $reset,
  389. $subscribe(callback, options = {}) {
  390. const removeSubscription = addSubscription(subscriptions, callback, options.detached, () => stopWatcher());
  391. const stopWatcher = scope.run(() => vue.watch(() => pinia.state.value[$id], (state) => {
  392. if (options.flush === 'sync' ? isSyncListening : isListening) {
  393. callback({
  394. storeId: $id,
  395. type: exports.MutationType.direct,
  396. events: debuggerEvents,
  397. }, state);
  398. }
  399. }, assign({}, $subscribeOptions, options)));
  400. return removeSubscription;
  401. },
  402. $dispose,
  403. };
  404. const store = vue.reactive(partialStore);
  405. // store the partial store now so the setup of stores can instantiate each other before they are finished without
  406. // creating infinite loops.
  407. pinia._s.set($id, store);
  408. const runWithContext = (pinia._a && pinia._a.runWithContext) || fallbackRunWithContext;
  409. // TODO: idea create skipSerialize that marks properties as non serializable and they are skipped
  410. const setupStore = runWithContext(() => pinia._e.run(() => (scope = vue.effectScope()).run(() => setup({ action }))));
  411. // overwrite existing actions to support $onAction
  412. for (const key in setupStore) {
  413. const prop = setupStore[key];
  414. if ((vue.isRef(prop) && !isComputed(prop)) || vue.isReactive(prop)) {
  415. // mark it as a piece of state to be serialized
  416. if (!isOptionsStore) {
  417. // in setup stores we must hydrate the state and sync pinia state tree with the refs the user just created
  418. if (initialState && shouldHydrate(prop)) {
  419. if (vue.isRef(prop)) {
  420. prop.value = initialState[key];
  421. }
  422. else {
  423. // probably a reactive object, lets recursively assign
  424. // @ts-expect-error: prop is unknown
  425. mergeReactiveObjects(prop, initialState[key]);
  426. }
  427. }
  428. // transfer the ref to the pinia state to keep everything in sync
  429. pinia.state.value[$id][key] = prop;
  430. }
  431. // action
  432. }
  433. else if (typeof prop === 'function') {
  434. const actionValue = action(prop, key);
  435. // this a hot module replacement store because the hotUpdate method needs
  436. // to do it with the right context
  437. // @ts-expect-error
  438. setupStore[key] = actionValue;
  439. // list actions so they can be used in plugins
  440. // @ts-expect-error
  441. optionsForPlugin.actions[key] = prop;
  442. }
  443. else ;
  444. }
  445. // add the state, getters, and action properties
  446. /* istanbul ignore if */
  447. assign(store, setupStore);
  448. // allows retrieving reactive objects with `storeToRefs()`. Must be called after assigning to the reactive object.
  449. // Make `storeToRefs()` work with `reactive()` #799
  450. assign(vue.toRaw(store), setupStore);
  451. // use this instead of a computed with setter to be able to create it anywhere
  452. // without linking the computed lifespan to wherever the store is first
  453. // created.
  454. Object.defineProperty(store, '$state', {
  455. get: () => (pinia.state.value[$id]),
  456. set: (state) => {
  457. $patch(($state) => {
  458. // @ts-expect-error: FIXME: shouldn't error?
  459. assign($state, state);
  460. });
  461. },
  462. });
  463. // apply all plugins
  464. pinia._p.forEach((extender) => {
  465. /* istanbul ignore else */
  466. {
  467. assign(store, scope.run(() => extender({
  468. store: store,
  469. app: pinia._a,
  470. pinia,
  471. options: optionsForPlugin,
  472. })));
  473. }
  474. });
  475. // only apply hydrate to option stores with an initial state in pinia
  476. if (initialState &&
  477. isOptionsStore &&
  478. options.hydrate) {
  479. options.hydrate(store.$state, initialState);
  480. }
  481. isListening = true;
  482. isSyncListening = true;
  483. return store;
  484. }
  485. // allows unused stores to be tree shaken
  486. /*! #__NO_SIDE_EFFECTS__ */
  487. function defineStore(
  488. // TODO: add proper types from above
  489. id, setup, setupOptions) {
  490. let options;
  491. const isSetupStore = typeof setup === 'function';
  492. // the option store setup will contain the actual options in this case
  493. options = isSetupStore ? setupOptions : setup;
  494. function useStore(pinia, hot) {
  495. const hasContext = vue.hasInjectionContext();
  496. pinia =
  497. // in test mode, ignore the argument provided as we can always retrieve a
  498. // pinia instance with getActivePinia()
  499. ((process.env.NODE_ENV === 'test') && activePinia && activePinia._testing ? null : pinia) ||
  500. (hasContext ? vue.inject(piniaSymbol, null) : null);
  501. if (pinia)
  502. setActivePinia(pinia);
  503. pinia = activePinia;
  504. if (!pinia._s.has(id)) {
  505. // creating the store registers it in `pinia._s`
  506. if (isSetupStore) {
  507. createSetupStore(id, setup, options, pinia);
  508. }
  509. else {
  510. createOptionsStore(id, options, pinia);
  511. }
  512. }
  513. const store = pinia._s.get(id);
  514. // StoreGeneric cannot be casted towards Store
  515. return store;
  516. }
  517. useStore.$id = id;
  518. return useStore;
  519. }
  520. let mapStoreSuffix = 'Store';
  521. /**
  522. * Changes the suffix added by `mapStores()`. Can be set to an empty string.
  523. * Defaults to `"Store"`. Make sure to extend the MapStoresCustomization
  524. * interface if you are using TypeScript.
  525. *
  526. * @param suffix - new suffix
  527. */
  528. function setMapStoreSuffix(suffix // could be 'Store' but that would be annoying for JS
  529. ) {
  530. mapStoreSuffix = suffix;
  531. }
  532. /**
  533. * Allows using stores without the composition API (`setup()`) by generating an
  534. * object to be spread in the `computed` field of a component. It accepts a list
  535. * of store definitions.
  536. *
  537. * @example
  538. * ```js
  539. * export default {
  540. * computed: {
  541. * // other computed properties
  542. * ...mapStores(useUserStore, useCartStore)
  543. * },
  544. *
  545. * created() {
  546. * this.userStore // store with id "user"
  547. * this.cartStore // store with id "cart"
  548. * }
  549. * }
  550. * ```
  551. *
  552. * @param stores - list of stores to map to an object
  553. */
  554. function mapStores(...stores) {
  555. return stores.reduce((reduced, useStore) => {
  556. // @ts-expect-error: $id is added by defineStore
  557. reduced[useStore.$id + mapStoreSuffix] = function () {
  558. return useStore(this.$pinia);
  559. };
  560. return reduced;
  561. }, {});
  562. }
  563. /**
  564. * Allows using state and getters from one store without using the composition
  565. * API (`setup()`) by generating an object to be spread in the `computed` field
  566. * of a component.
  567. *
  568. * @param useStore - store to map from
  569. * @param keysOrMapper - array or object
  570. */
  571. function mapState(useStore, keysOrMapper) {
  572. return Array.isArray(keysOrMapper)
  573. ? keysOrMapper.reduce((reduced, key) => {
  574. reduced[key] = function () {
  575. // @ts-expect-error: FIXME: should work?
  576. return useStore(this.$pinia)[key];
  577. };
  578. return reduced;
  579. }, {})
  580. : Object.keys(keysOrMapper).reduce((reduced, key) => {
  581. // @ts-expect-error
  582. reduced[key] = function () {
  583. const store = useStore(this.$pinia);
  584. const storeKey = keysOrMapper[key];
  585. // for some reason TS is unable to infer the type of storeKey to be a
  586. // function
  587. return typeof storeKey === 'function'
  588. ? storeKey.call(this, store)
  589. : // @ts-expect-error: FIXME: should work?
  590. store[storeKey];
  591. };
  592. return reduced;
  593. }, {});
  594. }
  595. /**
  596. * Alias for `mapState()`. You should use `mapState()` instead.
  597. * @deprecated use `mapState()` instead.
  598. */
  599. const mapGetters = mapState;
  600. /**
  601. * Allows directly using actions from your store without using the composition
  602. * API (`setup()`) by generating an object to be spread in the `methods` field
  603. * of a component.
  604. *
  605. * @param useStore - store to map from
  606. * @param keysOrMapper - array or object
  607. */
  608. function mapActions(useStore, keysOrMapper) {
  609. return Array.isArray(keysOrMapper)
  610. ? keysOrMapper.reduce((reduced, key) => {
  611. // @ts-expect-error
  612. reduced[key] = function (...args) {
  613. // @ts-expect-error: FIXME: should work?
  614. return useStore(this.$pinia)[key](...args);
  615. };
  616. return reduced;
  617. }, {})
  618. : Object.keys(keysOrMapper).reduce((reduced, key) => {
  619. // @ts-expect-error
  620. reduced[key] = function (...args) {
  621. // @ts-expect-error: FIXME: should work?
  622. return useStore(this.$pinia)[keysOrMapper[key]](...args);
  623. };
  624. return reduced;
  625. }, {});
  626. }
  627. /**
  628. * Allows using state and getters from one store without using the composition
  629. * API (`setup()`) by generating an object to be spread in the `computed` field
  630. * of a component.
  631. *
  632. * @param useStore - store to map from
  633. * @param keysOrMapper - array or object
  634. */
  635. function mapWritableState(useStore, keysOrMapper) {
  636. return Array.isArray(keysOrMapper)
  637. ? keysOrMapper.reduce((reduced, key) => {
  638. reduced[key] = {
  639. get() {
  640. return useStore(this.$pinia)[key];
  641. },
  642. set(value) {
  643. return (useStore(this.$pinia)[key] = value);
  644. },
  645. };
  646. return reduced;
  647. }, {})
  648. : Object.keys(keysOrMapper).reduce((reduced, key) => {
  649. reduced[key] = {
  650. get() {
  651. return useStore(this.$pinia)[keysOrMapper[key]];
  652. },
  653. set(value) {
  654. return (useStore(this.$pinia)[keysOrMapper[key]] = value);
  655. },
  656. };
  657. return reduced;
  658. }, {});
  659. }
  660. /**
  661. * Creates an object of references with all the state, getters, and plugin-added
  662. * state properties of the store. Similar to `toRefs()` but specifically
  663. * designed for Pinia stores so methods and non reactive properties are
  664. * completely ignored.
  665. *
  666. * @param store - store to extract the refs from
  667. */
  668. function storeToRefs(store) {
  669. const rawStore = vue.toRaw(store);
  670. const refs = {};
  671. for (const key in rawStore) {
  672. const value = rawStore[key];
  673. // There is no native method to check for a computed
  674. // https://github.com/vuejs/core/pull/4165
  675. if (value.effect) {
  676. // @ts-expect-error: too hard to type correctly
  677. refs[key] =
  678. // ...
  679. vue.computed({
  680. get: () => store[key],
  681. set(value) {
  682. store[key] = value;
  683. },
  684. });
  685. }
  686. else if (vue.isRef(value) || vue.isReactive(value)) {
  687. // @ts-expect-error: the key is state or getter
  688. refs[key] =
  689. // ---
  690. vue.toRef(store, key);
  691. }
  692. }
  693. return refs;
  694. }
  695. exports.acceptHMRUpdate = acceptHMRUpdate;
  696. exports.createPinia = createPinia;
  697. exports.defineStore = defineStore;
  698. exports.disposePinia = disposePinia;
  699. exports.getActivePinia = getActivePinia;
  700. exports.mapActions = mapActions;
  701. exports.mapGetters = mapGetters;
  702. exports.mapState = mapState;
  703. exports.mapStores = mapStores;
  704. exports.mapWritableState = mapWritableState;
  705. exports.setActivePinia = setActivePinia;
  706. exports.setMapStoreSuffix = setMapStoreSuffix;
  707. exports.shouldHydrate = shouldHydrate;
  708. exports.skipHydrate = skipHydrate;
  709. exports.storeToRefs = storeToRefs;