Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

pinia

Package Overview
Dependencies
Maintainers
1
Versions
119
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

pinia - npm Package Compare versions

Comparing version 2.0.0-beta.5 to 2.0.0-rc.0

41

CHANGELOG.md

@@ -0,1 +1,42 @@

# [2.0.0-rc.0](https://github.com/posva/pinia/compare/v2.0.0-beta.5...v2.0.0-rc.0) (2021-07-28)
## Required Vue version ‼️
This release requires Vue 3.2.0, which is currently only available under the `beta` dist tag (`npm i vue@beta` or `yarn add vue@beta` + the corresponding packages like `@vue/compiler-sfc@beta`).
It contains major improvements:
- Performance: Pinia now uses `effectScope()`, effectively reducing memory consumption and removing the drawbacks mentioned in the Plugin section about `useStore()` creating multiple store instances (still sharing the state).
- Devtools: Many improvements over the information displayed in devtools as well as a few bugfixes
- HMR (Hot Module Replacement): You can now modify your stores without reloading the page and losing the state, making development much easier. Until 3.2.0 (stable) is released, you can find an example [in the playground](https://github.com/posva/pinia/blob/2b98eafe441ea7e9a3ff3cef122c24eb5fa03f1d/playground/src/stores/counter.ts#L66-L68). After that, you can read up to date instructions [in the documentation](https://pinia.esm.dev/cookbook/hot-module-replacement.html).
- Setup syntax: You can now define stores with a function instead of options. This enables more complex patterns. See an example [in the playground](https://github.com/posva/pinia/blob/75f1fe6aa4ef2629ae1c9840a2d4542ac6e62686/playground/src/stores/jokes-swrv.ts). Setup Stores are unable to group actions like Option Stores due to their very permissive syntax.
- Option syntax: we can now pass the `id` as the first parameter. This syntax is preferred over the object syntax to be consistent with the Setup syntax.
### Bug Fixes
- avoid modifying options argument ([59ac9b9](https://github.com/posva/pinia/commit/59ac9b962778f730ade9c2a8b1a575922957d907))
- **devtools:** avoid grouping patches and mutations with finished actions ([18a87fe](https://github.com/posva/pinia/commit/18a87fe260317c679732d0ec271c036b9806448f))
- **errors:** allow async errors to propagate ([17ee4e8](https://github.com/posva/pinia/commit/17ee4e85fb2c084ba27730dae4f21683686156c6)), closes [#576](https://github.com/posva/pinia/issues/576)
- **ssr:** delay getters read ([2f3bd53](https://github.com/posva/pinia/commit/2f3bd5330e853b8ef11b6364a3a86e780c5f309f))
- **types:** actual generic store ([e4c541f](https://github.com/posva/pinia/commit/e4c541fdd17ea97e25dfd45bd3378732ff6a344d))
- **types:** stricter types for mapState ([f702356](https://github.com/posva/pinia/commit/f702356a5549dfe184c4d3805757c494a7088b19))
### Features
- allow actions to be destructured ([859d094](https://github.com/posva/pinia/commit/859d094bd993f4714093af17182ed73dd98659c5))
- **devtools:** display pinia without stores ([ca59257](https://github.com/posva/pinia/commit/ca59257a4ca3a37f54d6b9690a2ceedbc545dedd))
- **devtools:** show hot update in timeline ([3b9ed17](https://github.com/posva/pinia/commit/3b9ed1777621b1c8c0f781f5c974357da042c6e7))
- **types:** add StorState, StoreGetters, and StoreActions helpers ([47c0610](https://github.com/posva/pinia/commit/47c06101555328b6ca24e2f574f8f402b3bf1675))
### BREAKING CHANGES
- **types:** The existing `Store<Id, S, G, A>` types was trying to be generic when no types were specified but failing at it. Now, `Store` without any type will default to an empty Store. This enables a stricter version of `defineStore` when any of state, getters, and actions are missing. If you were using `Store` as a type, you should now use `StoreGeneric` instead, which also replaces `GenericStore` (marked as deprecated).
```diff
-function takeAnyStore(store: Store) {}
+function takeAnyStore(store: StoreGeneric) {}
```
- **types** The existing `DefineStoreOptions` is no longer the one that should be extended to add custom options unless you only want them to be applied to Option Stores. Use `DefineStoreOptionsBase` instead.
# [2.0.0-beta.5](https://github.com/posva/pinia/compare/v2.0.0-beta.3...v2.0.0-beta.5) (2021-07-10)

@@ -2,0 +43,0 @@

1123

dist/pinia.cjs.js
/*!
* pinia v2.0.0-beta.5
* pinia v2.0.0-rc.0
* (c) 2021 Eduardo San Martin Morote

@@ -37,7 +37,2 @@ * @license MIT

};
/**
* Map of stores based on a Pinia instance. Allows setting and retrieving stores
* for the current running application (with its pinia).
*/
const storesMap = new WeakMap();
const piniaSymbol = ((process.env.NODE_ENV !== 'production') ? Symbol('pinia') : /* istanbul ignore next */ Symbol());

@@ -426,3 +421,2 @@

key,
// @ts-expect-error
value: store.$state[key],

@@ -436,3 +430,2 @@ })),

key: getterName,
// @ts-expect-error
value: store[getterName],

@@ -445,3 +438,2 @@ }));

key,
// @ts-expect-error
value: store[key],

@@ -492,7 +484,2 @@ }));

/**
* Registered stores used for devtools.
*/
const registeredStores = /*#__PURE__*/ new Map();
let isAlreadyInstalled;
// timeline can be paused when directly changing the state

@@ -503,14 +490,17 @@ let isTimelineActive = true;

const INSPECTOR_ID = 'pinia';
function addDevtools(app, store) {
// TODO: we probably need to ensure the latest version of the store is kept:
// without effectScope, multiple stores will be created and will have a
// limited lifespan for getters.
// add a dev only variable that is removed in unmounted and replace the store
let hasSubscribed = true;
const storeType = '🍍 ' + store.$id;
if (!registeredStores.has(store.$id)) {
registeredStores.set(store.$id, store);
componentStateTypes.push(storeType);
hasSubscribed = false;
}
/**
* Gets the displayed name of a store in devtools
*
* @param id - id of the store
* @returns a formatted string
*/
const getStoreType = (id) => '🍍 ' + id;
/**
* Add the pinia plugin without any store. Allows displaying a Pinia plugin tab
* as soon as it is added to the application.
*
* @param app - Vue application
* @param pinia - pinia instance
*/
function registerPiniaDevtools(app, pinia) {
devtoolsApi.setupDevtoolsPlugin({

@@ -525,157 +515,161 @@ id: 'dev.esm.pinia',

}, (api) => {
if (!isAlreadyInstalled) {
api.addTimelineLayer({
id: MUTATIONS_LAYER_ID,
label: `Pinia 🍍`,
color: 0xe5df88,
});
api.addInspector({
id: INSPECTOR_ID,
label: 'Pinia 🍍',
icon: 'storage',
treeFilterPlaceholder: 'Search stores',
actions: [
{
icon: 'content_copy',
action: () => {
actionGlobalCopyState(store._p);
},
tooltip: 'Serialize and copy the state',
api.addTimelineLayer({
id: MUTATIONS_LAYER_ID,
label: `Pinia 🍍`,
color: 0xe5df88,
});
api.addInspector({
id: INSPECTOR_ID,
label: 'Pinia 🍍',
icon: 'storage',
treeFilterPlaceholder: 'Search stores',
actions: [
{
icon: 'content_copy',
action: () => {
actionGlobalCopyState(pinia);
},
{
icon: 'content_paste',
action: async () => {
await actionGlobalPasteState(store._p);
api.sendInspectorTree(INSPECTOR_ID);
api.sendInspectorState(INSPECTOR_ID);
},
tooltip: 'Replace the state with the content of your clipboard',
tooltip: 'Serialize and copy the state',
},
{
icon: 'content_paste',
action: async () => {
await actionGlobalPasteState(pinia);
api.sendInspectorTree(INSPECTOR_ID);
api.sendInspectorState(INSPECTOR_ID);
},
{
icon: 'save',
action: () => {
actionGlobalSaveState(store._p);
},
tooltip: 'Save the state as a JSON file',
tooltip: 'Replace the state with the content of your clipboard',
},
{
icon: 'save',
action: () => {
actionGlobalSaveState(pinia);
},
{
icon: 'folder_open',
action: async () => {
await actionGlobalOpenStateFile(store._p);
api.sendInspectorTree(INSPECTOR_ID);
api.sendInspectorState(INSPECTOR_ID);
},
tooltip: 'Import the state from a JSON file',
tooltip: 'Save the state as a JSON file',
},
{
icon: 'folder_open',
action: async () => {
await actionGlobalOpenStateFile(pinia);
api.sendInspectorTree(INSPECTOR_ID);
api.sendInspectorState(INSPECTOR_ID);
},
],
});
api.on.inspectComponent((payload, ctx) => {
const proxy = (payload.componentInstance &&
payload.componentInstance.proxy);
if (proxy && proxy._pStores) {
const piniaStores = payload.componentInstance.proxy._pStores;
Object.values(piniaStores).forEach((store) => {
tooltip: 'Import the state from a JSON file',
},
],
});
api.on.inspectComponent((payload, ctx) => {
const proxy = (payload.componentInstance &&
payload.componentInstance.proxy);
if (proxy && proxy._pStores) {
const piniaStores = payload.componentInstance.proxy._pStores;
Object.values(piniaStores).forEach((store) => {
payload.instanceData.state.push({
type: getStoreType(store.$id),
key: 'state',
editable: true,
value: store.$state,
});
if (store._getters && store._getters.length) {
payload.instanceData.state.push({
type: storeType,
key: 'state',
editable: true,
value: store.$state,
type: getStoreType(store.$id),
key: 'getters',
editable: false,
value: store._getters.reduce((getters, key) => {
getters[key] = store[key];
return getters;
}, {}),
});
if (store._getters && store._getters.length) {
payload.instanceData.state.push({
type: storeType,
key: 'getters',
editable: false,
value: store._getters.reduce((getters, key) => {
// @ts-expect-error
getters[key] = store[key];
return getters;
}, {}),
});
}
});
}
});
}
});
api.on.getInspectorTree((payload) => {
if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {
let stores = [pinia];
stores = stores.concat(Array.from(pinia._s.values()));
payload.rootNodes = (payload.filter
? stores.filter((store) => '$id' in store
? store.$id
.toLowerCase()
.includes(payload.filter.toLowerCase())
: PINIA_ROOT_LABEL.toLowerCase().includes(payload.filter.toLowerCase()))
: stores).map(formatStoreForInspectorTree);
}
});
api.on.getInspectorState((payload) => {
if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {
const inspectedStore = payload.nodeId === PINIA_ROOT_ID
? pinia
: pinia._s.get(payload.nodeId);
if (!inspectedStore) {
// this could be the selected store restored for a different project
// so it's better not to say anything here
return;
}
});
api.on.getInspectorTree((payload) => {
if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {
let stores = [store._p];
stores = stores.concat(Array.from(registeredStores.values()));
payload.rootNodes = (payload.filter
? stores.filter((store) => '$id' in store
? store.$id
.toLowerCase()
.includes(payload.filter.toLowerCase())
: PINIA_ROOT_LABEL.toLowerCase().includes(payload.filter.toLowerCase()))
: stores).map(formatStoreForInspectorTree);
if (inspectedStore) {
payload.state = formatStoreForInspectorState(inspectedStore);
}
});
api.on.getInspectorState((payload) => {
if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {
const inspectedStore = payload.nodeId === PINIA_ROOT_ID
? store._p
: registeredStores.get(payload.nodeId);
if (!inspectedStore) {
// this could be the selected store restored for a different project
// so it's better not to say anything here
return;
}
if (inspectedStore) {
payload.state = formatStoreForInspectorState(inspectedStore);
}
}
});
api.on.editInspectorState((payload, ctx) => {
if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {
const inspectedStore = payload.nodeId === PINIA_ROOT_ID
? pinia
: pinia._s.get(payload.nodeId);
if (!inspectedStore) {
return toastMessage(`store "${payload.nodeId}" not found`, 'error');
}
});
api.on.editInspectorState((payload, ctx) => {
if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {
const inspectedStore = payload.nodeId === PINIA_ROOT_ID
? store._p
: registeredStores.get(payload.nodeId);
if (!inspectedStore) {
return toastMessage(`store "${payload.nodeId}" not found`, 'error');
const { path } = payload;
if (!isPinia(inspectedStore)) {
// access only the state
if (path.length !== 1 ||
!inspectedStore._customProperties.has(path[0]) ||
path[0] in inspectedStore.$state) {
path.unshift('$state');
}
const { path } = payload;
if (!isPinia(store)) {
// access only the state
if (path.length !== 1 ||
!store._customProperties.has(path[0]) ||
path[0] in store.$state) {
path.unshift('$state');
}
}
else {
path.unshift('state', 'value');
}
isTimelineActive = false;
payload.set(inspectedStore, path, payload.state.value);
isTimelineActive = true;
}
});
api.on.editComponentState((payload) => {
if (payload.type.startsWith('🍍')) {
const storeId = payload.type.replace(/^🍍\s*/, '');
const store = registeredStores.get(storeId);
if (!store) {
return toastMessage(`store "${storeId}" not found`, 'error');
}
const { path } = payload;
if (path[0] !== 'state') {
return toastMessage(`Invalid path for store "${storeId}":\n${path}\nOnly state can be modified.`);
}
// rewrite the first entry to be able to directly set the state as
// well as any other path
path[0] = '$state';
isTimelineActive = false;
payload.set(store, path, payload.state.value);
isTimelineActive = true;
else {
path.unshift('state', 'value');
}
});
isAlreadyInstalled = true;
}
else {
api.sendInspectorTree(INSPECTOR_ID);
api.sendInspectorState(INSPECTOR_ID);
}
// avoid subscribing to mutations and actions twice
if (hasSubscribed)
return;
store.$onAction(({ after, onError, name, args, store }) => {
isTimelineActive = false;
payload.set(inspectedStore, path, payload.state.value);
isTimelineActive = true;
}
});
api.on.editComponentState((payload) => {
if (payload.type.startsWith('🍍')) {
const storeId = payload.type.replace(/^🍍\s*/, '');
const store = pinia._s.get(storeId);
if (!store) {
return toastMessage(`store "${storeId}" not found`, 'error');
}
const { path } = payload;
if (path[0] !== 'state') {
return toastMessage(`Invalid path for store "${storeId}":\n${path}\nOnly state can be modified.`);
}
// rewrite the first entry to be able to directly set the state as
// well as any other path
path[0] = '$state';
isTimelineActive = false;
payload.set(store, path, payload.state.value);
isTimelineActive = true;
}
});
});
}
function addStoreToDevtools(app, store) {
if (!componentStateTypes.includes(getStoreType(store.$id))) {
componentStateTypes.push(getStoreType(store.$id));
}
devtoolsApi.setupDevtoolsPlugin({
id: 'dev.esm.pinia',
label: 'Pinia 🍍',
logo: 'https://pinia.esm.dev/logo.svg',
packageName: 'pinia',
homepage: 'https://pinia.esm.dev',
componentStateTypes,
app,
}, (api) => {
store.$onAction(({ after, onError, name, args }) => {
const groupId = runningActionId++;

@@ -689,2 +683,3 @@ api.addTimelineEvent({

data: {
store: formatDisplay(store.$id),
action: formatDisplay(name),

@@ -697,2 +692,3 @@ args,

after((result) => {
activeAction = undefined;
api.addTimelineEvent({

@@ -705,2 +701,3 @@ layerId: MUTATIONS_LAYER_ID,

data: {
store: formatDisplay(store.$id),
action: formatDisplay(name),

@@ -715,2 +712,3 @@ args,

onError((error) => {
activeAction = undefined;
api.addTimelineEvent({

@@ -724,2 +722,3 @@ layerId: MUTATIONS_LAYER_ID,

data: {
store: formatDisplay(store.$id),
action: formatDisplay(name),

@@ -733,3 +732,3 @@ args,

});
});
}, true);
store.$subscribe(({ events, type }, state) => {

@@ -744,3 +743,6 @@ if (!isTimelineActive)

title: formatMutationType(type),
data: formatEventData(events),
data: {
store: formatDisplay(store.$id),
...formatEventData(events),
},
groupId: activeAction,

@@ -773,6 +775,23 @@ };

});
}, true);
const hotUpdate = store._hotUpdate;
store._hotUpdate = vue.markRaw((newStore) => {
hotUpdate(newStore);
api.addTimelineEvent({
layerId: MUTATIONS_LAYER_ID,
event: {
time: Date.now(),
title: '🔥 ' + store.$id,
subtitle: 'HMR update',
data: {
store: formatDisplay(store.$id),
info: formatDisplay(`HMR update`),
},
},
});
});
// trigger an update so it can display new registered stores
// @ts-ignore
api.notifyComponentUpdate();
api.sendInspectorTree(INSPECTOR_ID);
api.sendInspectorState(INSPECTOR_ID);
toastMessage(`"${store.$id}" store installed`);

@@ -784,8 +803,10 @@ });

/**
* pinia.use(devtoolsPlugin)
* Patches a store to enable action grouping in devtools by wrapping the store with a Proxy that is passed as the context of all actions, allowing us to set `runningAction` on each access and effectively associating any state mutation to the action.
*
* @param store - store to patch
* @param actionNames - list of actionst to patch
*/
function devtoolsPlugin({ app, store, options, pinia }) {
function patchActionForGrouping(store, actionNames) {
// original actions of the store as they are given by pinia. We are going to override them
const actions = Object.keys(options.actions || {}).reduce((storeActions, actionName) => {
// @ts-expect-error
const actions = actionNames.reduce((storeActions, actionName) => {
// use toRaw to avoid tracking #541

@@ -796,5 +817,4 @@ storeActions[actionName] = vue.toRaw(store)[actionName];

for (const actionName in actions) {
// @ts-expect-error
store[actionName] = function () {
setActivePinia(pinia);
// setActivePinia(store._p)
// the running action id is incremented in a before action hook

@@ -815,4 +835,26 @@ const _actionId = runningActionId;

}
addDevtools(app,
// @ts-expect-error: FIXME: if possible...
}
/**
* pinia.use(devtoolsPlugin)
*/
function devtoolsPlugin({ app, store, options }) {
// HMR module
if (store.$id.startsWith('__hot:')) {
return;
}
// only wrap actions in option-defined stores as this technique relies on
// wrapping the context of the action with a proxy
if ('id' in options) {
patchActionForGrouping(
// @ts-expect-error: can cast the store...
store, Object.keys(options.actions));
const originalHotUpdate = store._hotUpdate;
// Upgrade the HMR to also update the new actions
vue.toRaw(store)._hotUpdate = function (newStore) {
originalHotUpdate.apply(this, arguments);
patchActionForGrouping(store, Object.keys(newStore._hmrPayload.actions));
};
}
addStoreToDevtools(app,
// FIXME: is there a way to allow the assignment from Store<Id, S, G, A> to StoreGeneric?
store);

@@ -825,6 +867,6 @@ }

function createPinia() {
const scope = vue.effectScope(true);
// NOTE: here we could check the window object for a state and directly set it
// if there is anything like it with Vue 3 SSR
const state = vue.ref({});
let localApp;
const state = scope.run(() => vue.ref({}));
let _p = [];

@@ -835,3 +877,3 @@ // plugins added before calling app.use(pinia)

install(app) {
pinia._a = localApp = app;
pinia._a = app;
app.provide(piniaSymbol, pinia);

@@ -843,2 +885,5 @@ app.config.globalProperties.$pinia = pinia;

setActivePinia(pinia);
if ((process.env.NODE_ENV !== 'production')) {
registerPiniaDevtools(app, pinia);
}
}

@@ -848,3 +893,3 @@ toBeInstalled.forEach((plugin) => _p.push(plugin));

use(plugin) {
if (!localApp) {
if (!this._a) {
toBeInstalled.push(plugin);

@@ -859,3 +904,6 @@ }

// it's actually undefined here
_a: localApp,
// @ts-expect-error
_a: null,
_e: scope,
_s: new Map(),
state,

@@ -871,4 +919,110 @@ });

/**
* Checks if a function is a `StoreDefinition`
*
* @param fn - object to test
* @returns true if `fn` is a StoreDefinition
*/
const isUseStore = (fn) => {
return typeof fn === 'function' && typeof fn.$id === 'string';
};
/**
* Mutates in place `newState` with `oldState` to _hot update_ it. It will
* remove any key not existing in `newState` and recursively merge plain
* objects.
*
* @param newState - new state object to be patched
* @param oldState - old state that should be used to patch newState
* @returns - newState
*/
function patchObject(newState, oldState) {
// no need to go through symbols because they cannot be serialized anyway
for (const key in oldState) {
const subPatch = oldState[key];
// skip the whole sub tree
if (!(key in newState)) {
continue;
}
const targetValue = newState[key];
if (isPlainObject(targetValue) &&
isPlainObject(subPatch) &&
!vue.isRef(subPatch) &&
!vue.isReactive(subPatch)) {
newState[key] = patchObject(targetValue, subPatch);
}
else {
// objects are either a bit more complex (e.g. refs) or primitives, so we
// just set the whole thing
newState[key] = subPatch;
}
}
return newState;
}
/**
* Creates an _accept_ function to pass to `import.meta.hot` in Vite applications.
*
* @example
* ```js
* const useUser = defineStore(...)
* if (import.meta.hot) {
* import.meta.hot.accept(acceptHMRUpdate(useUser, import.meta.hot))
* }
* ```
*
* @param initialUseStore - return of the defineStore to hot update
* @param hot - `import.meta.hot`
*/
function acceptHMRUpdate(initialUseStore, hot) {
return (newModule) => {
const pinia = hot.data.pinia || initialUseStore._pinia;
if (!pinia) {
// this store is still not used
return;
}
// preserve the pinia instance across loads
hot.data.pinia = pinia;
// console.log('got data', newStore)
for (const exportName in newModule) {
const useStore = newModule[exportName];
// console.log('checking for', exportName)
if (isUseStore(useStore) && pinia._s.has(useStore.$id)) {
// console.log('Accepting update for', useStore.$id)
const id = useStore.$id;
if (id !== initialUseStore.$id) {
console.warn(`The id of the store changed from "${initialUseStore.$id}" to "${id}". Reloading.`);
// return import.meta.hot.invalidate()
return hot.invalidate();
}
const existingStore = pinia._s.get(id);
if (!existingStore) {
console.log(`skipping hmr because store doesn't exist yet`);
return;
}
useStore(pinia, existingStore);
}
}
};
}
function addSubscription(subscriptions, callback, detached) {
subscriptions.push(callback);
const removeSubscription = () => {
const idx = subscriptions.indexOf(callback);
if (idx > -1) {
subscriptions.splice(idx, 1);
}
};
if (!detached && vue.getCurrentInstance()) {
vue.onUnmounted(removeSubscription);
}
return removeSubscription;
}
function triggerSubscriptions(subscriptions, ...args) {
subscriptions.forEach((callback) => {
callback(...args);
});
}
function innerPatch(target, patchToApply) {
// TODO: get all keys like symbols as well
// no need to go through symbols because they cannot be serialized anyway
for (const key in patchToApply) {

@@ -891,36 +1045,98 @@ const subPatch = patchToApply[key];

const { assign } = Object;
/**
* Create an object of computed properties referring to
*
* @param rootStateRef - pinia.state
* @param id - unique name
*/
function computedFromState(rootStateRef, id) {
// let asComputed = computed<T>()
const reactiveObject = {};
const state = rootStateRef.value[id];
for (const key in state) {
// @ts-expect-error: the key matches
reactiveObject[key] = vue.computed({
get: () => rootStateRef.value[id][key],
set: (value) => (rootStateRef.value[id][key] = value),
});
function isComputed(o) {
return o && o.effect;
}
function createOptionsStore(id, options, pinia, hot) {
const { state, actions, getters } = options;
function $reset() {
pinia.state.value[id] = state ? state() : {};
}
return reactiveObject;
const initialState = pinia.state.value[id];
let store;
function setup() {
if (!initialState && (!(process.env.NODE_ENV !== 'production') || !hot)) {
$reset();
}
// pinia.state.value[id] = state ? state() : {}
// avoid creating a state in pinia.state.value
const localState = (process.env.NODE_ENV !== 'production') && hot
? vue.toRefs(vue.ref(state ? state() : {}).value)
: initialState || vue.toRefs(pinia.state.value[id]);
return assign(localState, actions, Object.keys(getters || {}).reduce((computedGetters, name) => {
computedGetters[name] = vue.markRaw(vue.computed(() => {
setActivePinia(pinia);
// const context = store || ref(localState).value
// @ts-expect-error
// return getters![name].call(context, context)
return store && getters[name].call(store, store);
}));
return computedGetters;
}, {}));
}
store = createSetupStore(id, setup, options, pinia, hot);
store.$reset = $reset;
return store;
}
/**
* Creates a store with its state object. This is meant to be augmented with getters and actions
*
* @param id - unique identifier of the store, like a name. eg: main, cart, user
* @param buildState - function to build the initial state
* @param initialState - initial state applied to the store, Must be correctly typed to infer typings
*/
function initStore($id, buildState = () => ({}), initialState) {
const pinia = getActivePinia();
pinia.state.value[$id] = initialState || buildState();
// const state: Ref<S> = toRef(_p.state.value, $id)
let isListening = true;
const noop = () => { };
function createSetupStore($id, setup, options = {}, pinia, hot) {
let scope;
const buildState = options.state;
const optionsForPlugin = {
actions: {},
...options,
};
// watcher options for $subscribe
const $subscribeOptions = { deep: true, flush: 'sync' };
/* istanbul ignore else */
if ((process.env.NODE_ENV !== 'production')) {
$subscribeOptions.onTrigger = (event) => {
if (isListening) {
debuggerEvents = event;
// avoid triggering this while the store is being built and the state is being set in pinia
}
else if (isListening == false && !store._hotUpdating) {
// let patch send all the events together later
/* istanbul ignore else */
if (Array.isArray(debuggerEvents)) {
debuggerEvents.push(event);
}
else {
console.error('🍍 debuggerEvents should be an array. This is most likely an internal Pinia bug.');
}
}
};
}
// internal state
let isListening; // set to true at the end
let subscriptions = vue.markRaw([]);
let actionSubscriptions = vue.markRaw([]);
let debuggerEvents;
const initialState = pinia.state.value[$id];
if (!initialState && (process.env.NODE_ENV !== 'production') && !hot) {
// should be set in Vue 2
pinia.state.value[$id] = {};
}
const hotState = vue.ref({});
if ((process.env.NODE_ENV !== 'production') && !pinia._e.active) {
throw new Error('Pinia destroyed');
}
// TODO: idea create skipSerialize that marks properties as non serializable and they are skipped
const setupStore = pinia._e.run(() => {
scope = vue.effectScope();
return scope.run(() => {
// skip setting up the watcher on HMR
if (!(process.env.NODE_ENV !== 'production') || !hot) {
vue.watch(() => pinia.state.value[$id], (state, oldState) => {
if (isListening) {
triggerSubscriptions(subscriptions, {
storeId: $id,
type: exports.MutationType.direct,
events: debuggerEvents,
}, state);
}
}, $subscribeOptions);
}
return setup();
});
});
function $patch(partialStateOrMutator) {

@@ -953,124 +1169,20 @@ let subscriptionMutation;

// because we paused the watcher, we need to manually call the subscriptions
subscriptions.forEach((callback) => {
callback(subscriptionMutation, pinia.state.value[$id]);
});
triggerSubscriptions(subscriptions, subscriptionMutation, pinia.state.value[$id]);
}
function $subscribe(callback) {
subscriptions.push(callback);
// watch here to link the subscription to the current active instance
// e.g. inside the setup of a component
const options = { deep: true, flush: 'sync' };
/* istanbul ignore else */
if ((process.env.NODE_ENV !== 'production')) {
options.onTrigger = (event) => {
if (isListening) {
debuggerEvents = event;
}
else {
// let patch send all the events together later
/* istanbul ignore else */
if (Array.isArray(debuggerEvents)) {
debuggerEvents.push(event);
}
else {
console.error('🍍 debuggerEvents should be an array. This is most likely an internal Pinia bug.');
}
}
};
const $reset = (process.env.NODE_ENV !== 'production')
? () => {
throw new Error(`🍍: Store "${$id}" is build using the setup syntax and does not implement $reset().`);
}
const stopWatcher = vue.watch(() => pinia.state.value[$id], (state, oldState) => {
if (isListening) {
callback({
storeId: $id,
type: exports.MutationType.direct,
events: debuggerEvents,
}, state);
}
}, options);
const removeSubscription = () => {
const idx = subscriptions.indexOf(callback);
if (idx > -1) {
subscriptions.splice(idx, 1);
stopWatcher();
}
};
if (vue.getCurrentInstance()) {
vue.onUnmounted(removeSubscription);
}
return removeSubscription;
}
function $onAction(callback) {
actionSubscriptions.push(callback);
const removeSubscription = () => {
const idx = actionSubscriptions.indexOf(callback);
if (idx > -1) {
actionSubscriptions.splice(idx, 1);
}
};
if (vue.getCurrentInstance()) {
vue.onUnmounted(removeSubscription);
}
return removeSubscription;
}
function $reset() {
pinia.state.value[$id] = buildState();
}
const storeWithState = {
$id,
_p: pinia,
_as: actionSubscriptions,
// $state is added underneath
$patch,
$subscribe,
$onAction,
$reset,
};
const injectionSymbol = (process.env.NODE_ENV !== 'production')
? Symbol(`PiniaStore(${$id})`)
: /* istanbul ignore next */
Symbol();
return [
storeWithState,
{
get: () => pinia.state.value[$id],
set: (newState) => {
isListening = false;
pinia.state.value[$id] = newState;
isListening = true;
},
},
injectionSymbol,
];
}
const noop = () => { };
/**
* Creates a store bound to the lifespan of where the function is called. This
* means creating the store inside of a component's setup will bound it to the
* lifespan of that component while creating it outside of a component will
* create an ever living store
*
* @param partialStore - store with state returned by initStore
* @param descriptor - descriptor to setup $state property
* @param $id - unique name of the store
* @param getters - getters of the store
* @param actions - actions of the store
*/
function buildStoreToUse(partialStore, descriptor, $id, getters = {}, actions = {}, options) {
const pinia = getActivePinia();
const computedGetters = {};
for (const getterName in getters) {
// @ts-ignore: it's only readonly for the users
computedGetters[getterName] = vue.computed(() => {
: noop;
/**
* Wraps an action to handle subscriptions.
*
* @param name - name of the action
* @param action - action to wrap
* @returns a wrapped action to handle subscriptions
*/
function wrapAction(name, action) {
return function () {
setActivePinia(pinia);
// eslint-disable-next-line @typescript-eslint/no-use-before-define
// @ts-expect-error: the argument count is correct
return getters[getterName].call(store, store);
});
}
const wrappedActions = {};
for (const actionName in actions) {
wrappedActions[actionName] = function () {
setActivePinia(pinia);
const args = Array.from(arguments);
const localStore = this || store;
let afterCallback = noop;

@@ -1084,18 +1196,99 @@ let onErrorCallback = noop;

}
partialStore._as.forEach((callback) => {
// @ts-expect-error
callback({ args, name: actionName, store: localStore, after, onError });
// @ts-expect-error
triggerSubscriptions(actionSubscriptions, {
args,
name,
store,
after,
onError,
});
let ret;
try {
ret = actions[actionName].apply(localStore, args);
Promise.resolve(ret).then(afterCallback).catch(onErrorCallback);
ret = action.apply(this && this.$id === $id ? this : store, args);
// handle sync errors
}
catch (error) {
onErrorCallback(error);
throw error;
if (onErrorCallback(error) !== false) {
throw error;
}
}
return ret;
if (ret instanceof Promise) {
return ret
.then((value) => {
const newRet = afterCallback(value);
// allow the afterCallback to override the return value
return newRet === undefined ? value : newRet;
})
.catch((error) => {
if (onErrorCallback(error) !== false) {
return Promise.reject(error);
}
});
}
// allow the afterCallback to override the return value
const newRet = afterCallback(ret);
return newRet === undefined ? ret : newRet;
};
}
const _hmrPayload = /*#__PURE__*/ vue.markRaw({
actions: {},
getters: {},
state: [],
hotState,
});
// overwrite existing actions to support $onAction
for (const key in setupStore) {
const prop = setupStore[key];
if ((vue.isRef(prop) && !isComputed(prop)) || vue.isReactive(prop)) {
// mark it as a piece of state to be serialized
if ((process.env.NODE_ENV !== 'production') && hot) {
hotState.value[key] = vue.toRef(setupStore, key);
// createOptionStore already did this
}
else if (!buildState) {
pinia.state.value[$id][key] = prop;
// TODO: avoid if state exists for SSR
}
if ((process.env.NODE_ENV !== 'production')) {
_hmrPayload.state.push(key);
}
// action
}
else if (typeof prop === 'function') {
// @ts-expect-error: we are overriding the function we avoid wrapping if
// this a hot module replacement store because the hotUpdate method needs
// to do it with the right context
setupStore[key] = (process.env.NODE_ENV !== 'production') && hot ? prop : wrapAction(key, prop);
if ((process.env.NODE_ENV !== 'production')) {
_hmrPayload.actions[key] = prop;
}
// list actions so they can be used in plugins
// @ts-expect-error
optionsForPlugin.actions[key] = prop;
}
else if ((process.env.NODE_ENV !== 'production')) {
// add getters for devtools
if (isComputed(prop)) {
_hmrPayload.getters[key] = buildState
? // @ts-expect-error
options.getters[key]
: prop;
if (IS_CLIENT) {
const getters =
// @ts-expect-error: it should be on the store
setupStore._getters || (setupStore._getters = vue.markRaw([]));
getters.push(key);
}
}
}
}
const partialStore = {
_p: pinia,
// _s: scope,
$id,
$onAction: addSubscription.bind(null, actionSubscriptions),
$patch,
$reset,
$subscribe: addSubscription.bind(null, subscriptions),
};
const store = vue.reactive(assign((process.env.NODE_ENV !== 'production') && IS_CLIENT

@@ -1105,13 +1298,102 @@ ? // devtools custom properties

_customProperties: vue.markRaw(new Set()),
_hmrPayload,
}
: {}, partialStore,
// using this means no new properties can be added as state
computedFromState(pinia.state, $id), computedGetters, wrappedActions));
: {}, partialStore, setupStore));
// use this instead of a computed with setter to be able to create it anywhere
// without linking the computed lifespan to wherever the store is first
// created.
Object.defineProperty(store, '$state', descriptor);
// add getters for devtools
if ((process.env.NODE_ENV !== 'production') && IS_CLIENT) {
store._getters = vue.markRaw(Object.keys(getters));
Object.defineProperty(store, '$state', {
get: () => ((process.env.NODE_ENV !== 'production') && hot ? hotState.value : pinia.state.value[$id]),
set: (state) => {
if ((process.env.NODE_ENV !== 'production') && hot) {
throw new Error('cannot set hotState');
}
pinia.state.value[$id] = state;
},
});
// add the hotUpdate before plugins to allow them to override it
if ((process.env.NODE_ENV !== 'production')) {
store._hotUpdate = vue.markRaw((newStore) => {
store._hotUpdating = true;
newStore._hmrPayload.state.forEach((stateKey) => {
if (stateKey in store.$state) {
const newStateTarget = newStore.$state[stateKey];
const oldStateSource = store.$state[stateKey];
if (typeof newStateTarget === 'object' &&
isPlainObject(newStateTarget) &&
isPlainObject(oldStateSource)) {
patchObject(newStateTarget, oldStateSource);
}
else {
// transfer the ref
newStore.$state[stateKey] = oldStateSource;
}
}
// patch direct access properties to allow store.stateProperty to work as
// store.$state.stateProperty
// @ts-expect-error
store[stateKey] = vue.toRef(newStore.$state, stateKey);
});
// remove deleted state properties
Object.keys(store.$state).forEach((stateKey) => {
if (!(stateKey in newStore.$state)) {
delete store[stateKey];
}
});
// avoid devtools logging this as a mutation
isListening = false;
pinia.state.value[$id] = vue.toRef(newStore._hmrPayload, 'hotState');
isListening = true;
for (const actionName in newStore._hmrPayload.actions) {
const action = newStore[actionName];
// @ts-expect-error: new key
store[actionName] =
// new line forced for TS
wrapAction(actionName, action);
}
// TODO: does this work in both setup and option store?
for (const getterName in newStore._hmrPayload.getters) {
const getter = newStore._hmrPayload.getters[getterName];
// @ts-expect-error
store[getterName] =
// ---
buildState
? // special handling of options api
vue.computed(() => {
setActivePinia(pinia);
return getter.call(store, store);
})
: getter;
}
// remove deleted getters
Object.keys(store._hmrPayload.getters).forEach((key) => {
if (!(key in newStore._hmrPayload.getters)) {
delete store[key];
}
});
// remove old actions
Object.keys(store._hmrPayload.actions).forEach((key) => {
if (!(key in newStore._hmrPayload.actions)) {
delete store[key];
}
});
// update the values used in devtools and to allow deleting new properties later on
store._hmrPayload = newStore._hmrPayload;
store._getters = newStore._getters;
store._hotUpdating = false;
});
const nonEnumerable = {
writable: true,
configurable: true,
// avoid warning on devtools trying to display this property
enumerable: false,
};
if (IS_CLIENT) {
['_p', '_hmrPayload', '_getters', '_customProperties'].forEach((p) => {
Object.defineProperty(store, p, {
value: store[p],
...nonEnumerable,
});
});
}
}

@@ -1121,4 +1403,9 @@ // apply all plugins

if ((process.env.NODE_ENV !== 'production') && IS_CLIENT) {
// @ts-expect-error: conflict between A and ActionsTree
const extensions = extender({ store, app: pinia._a, pinia, options });
const extensions = extender({
store,
app: pinia._a,
pinia,
// @ts-expect-error
options: optionsForPlugin,
});
Object.keys(extensions || {}).forEach((key) => store._customProperties.add(key));

@@ -1128,19 +1415,34 @@ assign(store, extensions);

else {
// @ts-expect-error: conflict between A and ActionsTree
assign(store, extender({ store, app: pinia._a, pinia, options }));
assign(store, extender({
store,
app: pinia._a,
pinia,
// @ts-expect-error
options: optionsForPlugin,
}));
}
});
if (initialState) {
(options.hydrate || innerPatch)(store, initialState);
}
isListening = true;
return store;
}
/**
* Creates a `useStore` function that retrieves the store instance
* @param options - options to define the store
*/
function defineStore(options) {
const { id, state, getters, actions } = options;
function useStore(pinia) {
function defineStore(
// TODO: add proper types from above
idOrOptions, setup, setupOptions) {
let id;
let options;
const isSetupStore = typeof setup === 'function';
if (typeof idOrOptions === 'string') {
id = idOrOptions;
// the option store setup will contain the actual options in this case
options = isSetupStore ? setupOptions : setup;
}
else {
options = idOrOptions;
id = idOrOptions.id;
}
function useStore(pinia, hot) {
const currentInstance = vue.getCurrentInstance();
// only run provide when pinia hasn't been manually passed
const shouldProvide = currentInstance && !pinia;
// avoid injecting if `useStore` when not possible
pinia =

@@ -1155,33 +1457,36 @@ // in test mode, ignore the argument provided as we can always retrieve a

pinia = getActivePinia();
let storeCache = storesMap.get(pinia);
if (!storeCache)
storesMap.set(pinia, (storeCache = new Map()));
let storeAndDescriptor = storeCache.get(id);
let store;
if (!storeAndDescriptor) {
storeAndDescriptor = initStore(id, state, pinia.state.value[id]);
// @ts-expect-error: annoying to type
storeCache.set(id, storeAndDescriptor);
store = buildStoreToUse(storeAndDescriptor[0], storeAndDescriptor[1], id, getters, actions, options);
// allow children to reuse this store instance to avoid creating a new
// store for each child
if (shouldProvide) {
vue.provide(storeAndDescriptor[2], store);
if (!pinia._s.has(id)) {
pinia._s.set(id, isSetupStore
? createSetupStore(id, setup, options, pinia)
: createOptionsStore(id, options, pinia));
if ((process.env.NODE_ENV !== 'production')) {
// @ts-expect-error: not the right inferred type
useStore._pinia = pinia;
}
}
else {
store =
(currentInstance && vue.inject(storeAndDescriptor[2], null)) ||
buildStoreToUse(storeAndDescriptor[0], storeAndDescriptor[1], id, getters, actions, options);
const store = pinia._s.get(id);
if ((process.env.NODE_ENV !== 'production') && hot) {
const hotId = '__hot:' + id;
const newStore = isSetupStore
? createSetupStore(hotId, setup, options, pinia, true)
: createOptionsStore(hotId, assign({}, options), pinia, true);
hot._hotUpdate(newStore);
// cleanup the state properties and the store from the cache
delete pinia.state.value[hotId];
pinia._s.delete(hotId);
}
// save stores in instances to access them devtools
if ((process.env.NODE_ENV !== 'production') && IS_CLIENT && currentInstance && currentInstance.proxy) {
if ((process.env.NODE_ENV !== 'production') &&
IS_CLIENT &&
currentInstance &&
currentInstance.proxy &&
// avoid adding stores that are just built for hot module replacement
!hot) {
const vm = currentInstance.proxy;
const cache = '_pStores' in vm ? vm._pStores : (vm._pStores = {});
// @ts-expect-error: still can't cast Store with generics to Store
cache[store.$id] = store;
cache[id] = store;
}
// StoreGeneric cannot be casted towards Store
return store;
}
// needed by map helpers
useStore.$id = id;

@@ -1191,8 +1496,2 @@ return useStore;

function getCachedStore(vm, useStore) {
const cache = '_pStores' in vm ? vm._pStores : (vm._pStores = {});
const id = useStore.$id;
return (cache[id] ||
(cache[id] = useStore(vm.$pinia)));
}
let mapStoreSuffix = 'Store';

@@ -1245,3 +1544,3 @@ /**

reduced[useStore.$id + mapStoreSuffix] = function () {
return getCachedStore(this, useStore);
return useStore(this.$pinia);
};

@@ -1263,4 +1562,3 @@ return reduced;

reduced[key] = function () {
// @ts-expect-error
return getCachedStore(this, useStore)[key];
return useStore(this.$pinia)[key];
};

@@ -1270,4 +1568,5 @@ return reduced;

: Object.keys(keysOrMapper).reduce((reduced, key) => {
// @ts-expect-error
reduced[key] = function () {
const store = getCachedStore(this, useStore);
const store = useStore(this.$pinia);
const storeKey = keysOrMapper[key];

@@ -1301,4 +1600,3 @@ // for some reason TS is unable to infer the type of storeKey to be a

reduced[key] = function (...args) {
// @ts-expect-error
return getCachedStore(this, useStore)[key](...args);
return useStore(this.$pinia)[key](...args);
};

@@ -1310,4 +1608,3 @@ return reduced;

reduced[key] = function (...args) {
// @ts-expect-error
return getCachedStore(this, useStore)[keysOrMapper[key]](...args);
return useStore(this.$pinia)[keysOrMapper[key]](...args);
};

@@ -1331,9 +1628,7 @@ return reduced;

get() {
// @ts-expect-error
return getCachedStore(this, useStore)[key];
return useStore(this.$pinia)[key];
},
set(value) {
// it's easier to type it here as any
// @ts-expect-error
return (getCachedStore(this, useStore)[key] = value);
return (useStore(this.$pinia)[key] = value);
},

@@ -1347,10 +1642,7 @@ };

get() {
// @ts-expect-error
return getCachedStore(this, useStore)[keysOrMapper[key]];
return useStore(this.$pinia)[keysOrMapper[key]];
},
set(value) {
// it's easier to type it here as any
// @ts-expect-error
return (getCachedStore(this, useStore)[keysOrMapper[key]] =
value);
return (useStore(this.$pinia)[keysOrMapper[key]] = value);
},

@@ -1370,3 +1662,3 @@ };

*
* @internal - STILL NOT RELEASED, DO NOT USE. It will be likely moved to its
* @alpha - STILL NOT RELEASED, DO NOT USE. It will be likely moved to its
* own package.

@@ -1380,3 +1672,3 @@ *

plugins.forEach((plugin) => pinia.use(plugin));
// @ts-ignore
// @ts-ignore: this can fail in TS depending of the existence of jest
createSpy = createSpy || (typeof jest !== undefined && jest.fn);

@@ -1389,14 +1681,10 @@ if (!createSpy) {

pinia.use(({ store, options }) => {
if (!spiedActions.has(options.id)) {
spiedActions.set(options.id, {});
if (!spiedActions.has(store.$id)) {
spiedActions.set(store.$id, {});
}
const actionsCache = spiedActions.get(options.id);
const actionsCache = spiedActions.get(store.$id);
Object.keys(options.actions || {}).forEach((action) => {
actionsCache[action] =
actionsCache[action] ||
(stubActions
? createSpy()
: // @ts-expect-error:
createSpy(store[action]));
// @ts-expect-error:
(stubActions ? createSpy() : createSpy(store[action]));
store[action] = actionsCache[action];

@@ -1422,2 +1710,3 @@ });

exports.acceptHMRUpdate = acceptHMRUpdate;
exports.createPinia = createPinia;

@@ -1424,0 +1713,0 @@ exports.createTestingPinia = createTestingPinia;

/*!
* pinia v2.0.0-beta.5
* pinia v2.0.0-rc.0
* (c) 2021 Eduardo San Martin Morote

@@ -31,7 +31,2 @@ * @license MIT

};
/**
* Map of stores based on a Pinia instance. Allows setting and retrieving stores
* for the current running application (with its pinia).
*/
const storesMap = new WeakMap();
const piniaSymbol = (/* istanbul ignore next */ Symbol());

@@ -83,6 +78,6 @@

function createPinia() {
const scope = vue.effectScope(true);
// NOTE: here we could check the window object for a state and directly set it
// if there is anything like it with Vue 3 SSR
const state = vue.ref({});
let localApp;
const state = scope.run(() => vue.ref({}));
let _p = [];

@@ -93,3 +88,3 @@ // plugins added before calling app.use(pinia)

install(app) {
pinia._a = localApp = app;
pinia._a = app;
app.provide(piniaSymbol, pinia);

@@ -105,3 +100,3 @@ app.config.globalProperties.$pinia = pinia;

use(plugin) {
if (!localApp) {
if (!this._a) {
toBeInstalled.push(plugin);

@@ -116,3 +111,6 @@ }

// it's actually undefined here
_a: localApp,
// @ts-expect-error
_a: null,
_e: scope,
_s: new Map(),
state,

@@ -123,4 +121,78 @@ });

/**
* Checks if a function is a `StoreDefinition`
*
* @param fn - object to test
* @returns true if `fn` is a StoreDefinition
*/
const isUseStore = (fn) => {
return typeof fn === 'function' && typeof fn.$id === 'string';
};
/**
* Creates an _accept_ function to pass to `import.meta.hot` in Vite applications.
*
* @example
* ```js
* const useUser = defineStore(...)
* if (import.meta.hot) {
* import.meta.hot.accept(acceptHMRUpdate(useUser, import.meta.hot))
* }
* ```
*
* @param initialUseStore - return of the defineStore to hot update
* @param hot - `import.meta.hot`
*/
function acceptHMRUpdate(initialUseStore, hot) {
return (newModule) => {
const pinia = hot.data.pinia || initialUseStore._pinia;
if (!pinia) {
// this store is still not used
return;
}
// preserve the pinia instance across loads
hot.data.pinia = pinia;
// console.log('got data', newStore)
for (const exportName in newModule) {
const useStore = newModule[exportName];
// console.log('checking for', exportName)
if (isUseStore(useStore) && pinia._s.has(useStore.$id)) {
// console.log('Accepting update for', useStore.$id)
const id = useStore.$id;
if (id !== initialUseStore.$id) {
console.warn(`The id of the store changed from "${initialUseStore.$id}" to "${id}". Reloading.`);
// return import.meta.hot.invalidate()
return hot.invalidate();
}
const existingStore = pinia._s.get(id);
if (!existingStore) {
console.log(`skipping hmr because store doesn't exist yet`);
return;
}
useStore(pinia, existingStore);
}
}
};
}
function addSubscription(subscriptions, callback, detached) {
subscriptions.push(callback);
const removeSubscription = () => {
const idx = subscriptions.indexOf(callback);
if (idx > -1) {
subscriptions.splice(idx, 1);
}
};
if (!detached && vue.getCurrentInstance()) {
vue.onUnmounted(removeSubscription);
}
return removeSubscription;
}
function triggerSubscriptions(subscriptions, ...args) {
subscriptions.forEach((callback) => {
callback(...args);
});
}
function innerPatch(target, patchToApply) {
// TODO: get all keys like symbols as well
// no need to go through symbols because they cannot be serialized anyway
for (const key in patchToApply) {

@@ -143,36 +215,74 @@ const subPatch = patchToApply[key];

const { assign } = Object;
/**
* Create an object of computed properties referring to
*
* @param rootStateRef - pinia.state
* @param id - unique name
*/
function computedFromState(rootStateRef, id) {
// let asComputed = computed<T>()
const reactiveObject = {};
const state = rootStateRef.value[id];
for (const key in state) {
// @ts-expect-error: the key matches
reactiveObject[key] = vue.computed({
get: () => rootStateRef.value[id][key],
set: (value) => (rootStateRef.value[id][key] = value),
});
function isComputed(o) {
return o && o.effect;
}
function createOptionsStore(id, options, pinia, hot) {
const { state, actions, getters } = options;
function $reset() {
pinia.state.value[id] = state ? state() : {};
}
return reactiveObject;
const initialState = pinia.state.value[id];
let store;
function setup() {
if (!initialState && (!false )) {
$reset();
}
// pinia.state.value[id] = state ? state() : {}
// avoid creating a state in pinia.state.value
const localState = initialState || vue.toRefs(pinia.state.value[id]);
return assign(localState, actions, Object.keys(getters || {}).reduce((computedGetters, name) => {
computedGetters[name] = vue.markRaw(vue.computed(() => {
setActivePinia(pinia);
// const context = store || ref(localState).value
// @ts-expect-error
// return getters![name].call(context, context)
return store && getters[name].call(store, store);
}));
return computedGetters;
}, {}));
}
store = createSetupStore(id, setup, options, pinia, hot);
store.$reset = $reset;
return store;
}
/**
* Creates a store with its state object. This is meant to be augmented with getters and actions
*
* @param id - unique identifier of the store, like a name. eg: main, cart, user
* @param buildState - function to build the initial state
* @param initialState - initial state applied to the store, Must be correctly typed to infer typings
*/
function initStore($id, buildState = () => ({}), initialState) {
const pinia = getActivePinia();
pinia.state.value[$id] = initialState || buildState();
// const state: Ref<S> = toRef(_p.state.value, $id)
let isListening = true;
const noop = () => { };
function createSetupStore($id, setup, options = {}, pinia, hot) {
let scope;
const buildState = options.state;
const optionsForPlugin = {
actions: {},
...options,
};
// watcher options for $subscribe
const $subscribeOptions = { deep: true, flush: 'sync' };
// internal state
let isListening; // set to true at the end
let subscriptions = vue.markRaw([]);
let actionSubscriptions = vue.markRaw([]);
let debuggerEvents;
const initialState = pinia.state.value[$id];
if (!initialState && false && !hot) {
// should be set in Vue 2
pinia.state.value[$id] = {};
}
vue.ref({});
// TODO: idea create skipSerialize that marks properties as non serializable and they are skipped
const setupStore = pinia._e.run(() => {
scope = vue.effectScope();
return scope.run(() => {
// skip setting up the watcher on HMR
{
vue.watch(() => pinia.state.value[$id], (state, oldState) => {
if (isListening) {
triggerSubscriptions(subscriptions, {
storeId: $id,
type: exports.MutationType.direct,
events: debuggerEvents,
}, state);
}
}, $subscribeOptions);
}
return setup();
});
});
function $patch(partialStateOrMutator) {

@@ -200,104 +310,16 @@ let subscriptionMutation;

// because we paused the watcher, we need to manually call the subscriptions
subscriptions.forEach((callback) => {
callback(subscriptionMutation, pinia.state.value[$id]);
});
triggerSubscriptions(subscriptions, subscriptionMutation, pinia.state.value[$id]);
}
function $subscribe(callback) {
subscriptions.push(callback);
// watch here to link the subscription to the current active instance
// e.g. inside the setup of a component
const options = { deep: true, flush: 'sync' };
const stopWatcher = vue.watch(() => pinia.state.value[$id], (state, oldState) => {
if (isListening) {
callback({
storeId: $id,
type: exports.MutationType.direct,
events: debuggerEvents,
}, state);
}
}, options);
const removeSubscription = () => {
const idx = subscriptions.indexOf(callback);
if (idx > -1) {
subscriptions.splice(idx, 1);
stopWatcher();
}
};
if (vue.getCurrentInstance()) {
vue.onUnmounted(removeSubscription);
}
return removeSubscription;
}
function $onAction(callback) {
actionSubscriptions.push(callback);
const removeSubscription = () => {
const idx = actionSubscriptions.indexOf(callback);
if (idx > -1) {
actionSubscriptions.splice(idx, 1);
}
};
if (vue.getCurrentInstance()) {
vue.onUnmounted(removeSubscription);
}
return removeSubscription;
}
function $reset() {
pinia.state.value[$id] = buildState();
}
const storeWithState = {
$id,
_p: pinia,
_as: actionSubscriptions,
// $state is added underneath
$patch,
$subscribe,
$onAction,
$reset,
};
const injectionSymbol = /* istanbul ignore next */
Symbol();
return [
storeWithState,
{
get: () => pinia.state.value[$id],
set: (newState) => {
isListening = false;
pinia.state.value[$id] = newState;
isListening = true;
},
},
injectionSymbol,
];
}
const noop = () => { };
/**
* Creates a store bound to the lifespan of where the function is called. This
* means creating the store inside of a component's setup will bound it to the
* lifespan of that component while creating it outside of a component will
* create an ever living store
*
* @param partialStore - store with state returned by initStore
* @param descriptor - descriptor to setup $state property
* @param $id - unique name of the store
* @param getters - getters of the store
* @param actions - actions of the store
*/
function buildStoreToUse(partialStore, descriptor, $id, getters = {}, actions = {}, options) {
const pinia = getActivePinia();
const computedGetters = {};
for (const getterName in getters) {
// @ts-ignore: it's only readonly for the users
computedGetters[getterName] = vue.computed(() => {
const $reset = noop;
/**
* Wraps an action to handle subscriptions.
*
* @param name - name of the action
* @param action - action to wrap
* @returns a wrapped action to handle subscriptions
*/
function wrapAction(name, action) {
return function () {
setActivePinia(pinia);
// eslint-disable-next-line @typescript-eslint/no-use-before-define
// @ts-expect-error: the argument count is correct
return getters[getterName].call(store, store);
});
}
const wrappedActions = {};
for (const actionName in actions) {
wrappedActions[actionName] = function () {
setActivePinia(pinia);
const args = Array.from(arguments);
const localStore = this || store;
let afterCallback = noop;

@@ -311,45 +333,114 @@ let onErrorCallback = noop;

}
partialStore._as.forEach((callback) => {
// @ts-expect-error
callback({ args, name: actionName, store: localStore, after, onError });
// @ts-expect-error
triggerSubscriptions(actionSubscriptions, {
args,
name,
store,
after,
onError,
});
let ret;
try {
ret = actions[actionName].apply(localStore, args);
Promise.resolve(ret).then(afterCallback).catch(onErrorCallback);
ret = action.apply(this && this.$id === $id ? this : store, args);
// handle sync errors
}
catch (error) {
onErrorCallback(error);
throw error;
if (onErrorCallback(error) !== false) {
throw error;
}
}
return ret;
if (ret instanceof Promise) {
return ret
.then((value) => {
const newRet = afterCallback(value);
// allow the afterCallback to override the return value
return newRet === undefined ? value : newRet;
})
.catch((error) => {
if (onErrorCallback(error) !== false) {
return Promise.reject(error);
}
});
}
// allow the afterCallback to override the return value
const newRet = afterCallback(ret);
return newRet === undefined ? ret : newRet;
};
}
const store = vue.reactive(assign({}, partialStore,
// using this means no new properties can be added as state
computedFromState(pinia.state, $id), computedGetters, wrappedActions));
// overwrite existing actions to support $onAction
for (const key in setupStore) {
const prop = setupStore[key];
if ((vue.isRef(prop) && !isComputed(prop)) || vue.isReactive(prop)) {
// mark it as a piece of state to be serialized
if (!buildState) {
pinia.state.value[$id][key] = prop;
// TODO: avoid if state exists for SSR
}
// action
}
else if (typeof prop === 'function') {
// @ts-expect-error: we are overriding the function we avoid wrapping if
// this a hot module replacement store because the hotUpdate method needs
// to do it with the right context
setupStore[key] = wrapAction(key, prop);
// list actions so they can be used in plugins
// @ts-expect-error
optionsForPlugin.actions[key] = prop;
}
else ;
}
const partialStore = {
_p: pinia,
// _s: scope,
$id,
$onAction: addSubscription.bind(null, actionSubscriptions),
$patch,
$reset,
$subscribe: addSubscription.bind(null, subscriptions),
};
const store = vue.reactive(assign({}, partialStore, setupStore));
// use this instead of a computed with setter to be able to create it anywhere
// without linking the computed lifespan to wherever the store is first
// created.
Object.defineProperty(store, '$state', descriptor);
Object.defineProperty(store, '$state', {
get: () => (pinia.state.value[$id]),
set: (state) => {
pinia.state.value[$id] = state;
},
});
// apply all plugins
pinia._p.forEach((extender) => {
{
// @ts-expect-error: conflict between A and ActionsTree
assign(store, extender({ store, app: pinia._a, pinia, options }));
assign(store, extender({
store,
app: pinia._a,
pinia,
// @ts-expect-error
options: optionsForPlugin,
}));
}
});
if (initialState) {
(options.hydrate || innerPatch)(store, initialState);
}
isListening = true;
return store;
}
/**
* Creates a `useStore` function that retrieves the store instance
* @param options - options to define the store
*/
function defineStore(options) {
const { id, state, getters, actions } = options;
function useStore(pinia) {
function defineStore(
// TODO: add proper types from above
idOrOptions, setup, setupOptions) {
let id;
let options;
const isSetupStore = typeof setup === 'function';
if (typeof idOrOptions === 'string') {
id = idOrOptions;
// the option store setup will contain the actual options in this case
options = isSetupStore ? setupOptions : setup;
}
else {
options = idOrOptions;
id = idOrOptions.id;
}
function useStore(pinia, hot) {
const currentInstance = vue.getCurrentInstance();
// only run provide when pinia hasn't been manually passed
const shouldProvide = currentInstance && !pinia;
// avoid injecting if `useStore` when not possible
pinia =

@@ -364,26 +455,11 @@ // in test mode, ignore the argument provided as we can always retrieve a

pinia = getActivePinia();
let storeCache = storesMap.get(pinia);
if (!storeCache)
storesMap.set(pinia, (storeCache = new Map()));
let storeAndDescriptor = storeCache.get(id);
let store;
if (!storeAndDescriptor) {
storeAndDescriptor = initStore(id, state, pinia.state.value[id]);
// @ts-expect-error: annoying to type
storeCache.set(id, storeAndDescriptor);
store = buildStoreToUse(storeAndDescriptor[0], storeAndDescriptor[1], id, getters, actions, options);
// allow children to reuse this store instance to avoid creating a new
// store for each child
if (shouldProvide) {
vue.provide(storeAndDescriptor[2], store);
}
if (!pinia._s.has(id)) {
pinia._s.set(id, isSetupStore
? createSetupStore(id, setup, options, pinia)
: createOptionsStore(id, options, pinia));
}
else {
store =
(currentInstance && vue.inject(storeAndDescriptor[2], null)) ||
buildStoreToUse(storeAndDescriptor[0], storeAndDescriptor[1], id, getters, actions, options);
}
const store = pinia._s.get(id);
// StoreGeneric cannot be casted towards Store
return store;
}
// needed by map helpers
useStore.$id = id;

@@ -393,8 +469,2 @@ return useStore;

function getCachedStore(vm, useStore) {
const cache = '_pStores' in vm ? vm._pStores : (vm._pStores = {});
const id = useStore.$id;
return (cache[id] ||
(cache[id] = useStore(vm.$pinia)));
}
let mapStoreSuffix = 'Store';

@@ -438,3 +508,3 @@ /**

reduced[useStore.$id + mapStoreSuffix] = function () {
return getCachedStore(this, useStore);
return useStore(this.$pinia);
};

@@ -456,4 +526,3 @@ return reduced;

reduced[key] = function () {
// @ts-expect-error
return getCachedStore(this, useStore)[key];
return useStore(this.$pinia)[key];
};

@@ -463,4 +532,5 @@ return reduced;

: Object.keys(keysOrMapper).reduce((reduced, key) => {
// @ts-expect-error
reduced[key] = function () {
const store = getCachedStore(this, useStore);
const store = useStore(this.$pinia);
const storeKey = keysOrMapper[key];

@@ -494,4 +564,3 @@ // for some reason TS is unable to infer the type of storeKey to be a

reduced[key] = function (...args) {
// @ts-expect-error
return getCachedStore(this, useStore)[key](...args);
return useStore(this.$pinia)[key](...args);
};

@@ -503,4 +572,3 @@ return reduced;

reduced[key] = function (...args) {
// @ts-expect-error
return getCachedStore(this, useStore)[keysOrMapper[key]](...args);
return useStore(this.$pinia)[keysOrMapper[key]](...args);
};

@@ -524,9 +592,7 @@ return reduced;

get() {
// @ts-expect-error
return getCachedStore(this, useStore)[key];
return useStore(this.$pinia)[key];
},
set(value) {
// it's easier to type it here as any
// @ts-expect-error
return (getCachedStore(this, useStore)[key] = value);
return (useStore(this.$pinia)[key] = value);
},

@@ -540,10 +606,7 @@ };

get() {
// @ts-expect-error
return getCachedStore(this, useStore)[keysOrMapper[key]];
return useStore(this.$pinia)[keysOrMapper[key]];
},
set(value) {
// it's easier to type it here as any
// @ts-expect-error
return (getCachedStore(this, useStore)[keysOrMapper[key]] =
value);
return (useStore(this.$pinia)[keysOrMapper[key]] = value);
},

@@ -563,3 +626,3 @@ };

*
* @internal - STILL NOT RELEASED, DO NOT USE. It will be likely moved to its
* @alpha - STILL NOT RELEASED, DO NOT USE. It will be likely moved to its
* own package.

@@ -573,3 +636,3 @@ *

plugins.forEach((plugin) => pinia.use(plugin));
// @ts-ignore
// @ts-ignore: this can fail in TS depending of the existence of jest
createSpy = createSpy || (typeof jest !== undefined && jest.fn);

@@ -582,14 +645,10 @@ if (!createSpy) {

pinia.use(({ store, options }) => {
if (!spiedActions.has(options.id)) {
spiedActions.set(options.id, {});
if (!spiedActions.has(store.$id)) {
spiedActions.set(store.$id, {});
}
const actionsCache = spiedActions.get(options.id);
const actionsCache = spiedActions.get(store.$id);
Object.keys(options.actions || {}).forEach((action) => {
actionsCache[action] =
actionsCache[action] ||
(stubActions
? createSpy()
: // @ts-expect-error:
createSpy(store[action]));
// @ts-expect-error:
(stubActions ? createSpy() : createSpy(store[action]));
store[action] = actionsCache[action];

@@ -615,2 +674,3 @@ });

exports.acceptHMRUpdate = acceptHMRUpdate;
exports.createPinia = createPinia;

@@ -617,0 +677,0 @@ exports.createTestingPinia = createTestingPinia;

import { App } from 'vue';
import { ComputedRef } from 'vue';
import { DebuggerEvent } from 'vue';
import { EffectScope } from 'vue';
import { Plugin as Plugin_2 } from 'vue';

@@ -8,4 +10,20 @@ import { Ref } from 'vue';

/**
* Type of an object of Actions
* Creates an _accept_ function to pass to `import.meta.hot` in Vite applications.
*
* @example
* ```js
* const useUser = defineStore(...)
* if (import.meta.hot) {
* import.meta.hot.accept(acceptHMRUpdate(useUser, import.meta.hot))
* }
* ```
*
* @param initialUseStore - return of the defineStore to hot update
* @param hot - `import.meta.hot`
*/
export declare function acceptHMRUpdate(initialUseStore: StoreDefinition, hot: any): (newModule: any) => any;
/**
* Type of an object of Actions.
*
* @internal

@@ -28,3 +46,3 @@ */

*
* @internal - STILL NOT RELEASED, DO NOT USE. It will be likely moved to its
* @alpha - STILL NOT RELEASED, DO NOT USE. It will be likely moved to its
* own package.

@@ -37,2 +55,7 @@ *

/**
* Recursive `Partial<T>`. Used by {@link Store.$patch}.
*
* @internal
*/
declare type DeepPartial<T> = {

@@ -43,12 +66,43 @@ [K in keyof T]?: DeepPartial<T[K]>;

/**
* Options parameter of `defineStore()` for setup stores. Can be extended to
* augment stores with the plugin API. @see {@link DefineStoreOptionsBase}.
*/
export declare interface DefineSetupStoreOptions<Id extends string, S extends StateTree, G, A> extends DefineStoreOptionsBase<S, Store<Id, S, G, A>> {
/**
* Extracted actions. Added by useStore(). SHOULD NOT be added by the user when
* creating the store. Can be used in plugins to get the list of actions in a
* store defined with a setup function. Note this is always defined
*/
actions?: A;
}
/**
* Creates a `useStore` function that retrieves the store instance
*
* @param id - id of the store (must be unique)
* @param options - options to define the store
*/
export declare function defineStore<Id extends string, S extends StateTree, G extends GettersTree<S>, A>(options: DefineStoreOptions<Id, S, G, A>): StoreDefinition<Id, S, G, A>;
export declare function defineStore<Id extends string, S extends StateTree = {}, G extends GettersTree<S> = {}, A = {}>(id: Id, options: Omit<DefineStoreOptions<Id, S, G, A>, 'id'>): StoreDefinition<Id, S, G, A>;
/**
* Options parameter of `defineStore()`. Can be extended to augment stores with
* the plugin API.
* Creates a `useStore` function that retrieves the store instance
*
* @param options - options to define the store
*/
export declare interface DefineStoreOptions<Id extends string, S extends StateTree, G extends GettersTree<S>, A> {
export declare function defineStore<Id extends string, S extends StateTree = {}, G extends GettersTree<S> = {}, A = {}>(options: DefineStoreOptions<Id, S, G, A>): StoreDefinition<Id, S, G, A>;
/**
* Creates a `useStore` function that retrieves the store instance
*
* @param id - id of the store (must be unique)
* @param storeSetup - function that defines the store
* @param options - extra options
*/
export declare function defineStore<Id extends string, SS>(id: Id, storeSetup: () => SS, options?: DefineSetupStoreOptions<Id, _ExtractStateFromSetupStore<SS>, _ExtractGettersFromSetupStore<SS>, _ExtractActionsFromSetupStore<SS>>): StoreDefinition<Id, _ExtractStateFromSetupStore<SS>, _ExtractGettersFromSetupStore<SS>, _ExtractActionsFromSetupStore<SS>>;
/**
* Options parameter of `defineStore()` for option stores. Can be extended to
* augment stores with the plugin API. @see {@link DefineStoreOptionsBase}.
*/
export declare interface DefineStoreOptions<Id extends string, S extends StateTree, G, A> extends DefineStoreOptionsBase<S, Store<Id, S, G, A>> {
/**

@@ -65,22 +119,72 @@ * Unique string key to identify the store across the application.

*/
getters?: G & ThisType<UnwrapRef<StateTree extends S ? {} : S> & StoreWithGetters<G> & PiniaCustomProperties>;
getters?: G & ThisType<UnwrapRef<S> & StoreWithGetters<G> & PiniaCustomProperties> & GettersTree<S>;
/**
* Optional object of actions.
*/
actions?: A & ThisType<A & UnwrapRef<StateTree extends S ? {} : S> & StoreWithState<Id, S, G, A> & StoreWithGetters<GettersTree<S> extends G ? {} : G> & PiniaCustomProperties>;
actions?: A & ThisType<A & UnwrapRef<S> & StoreWithState<Id, S, G, A> & StoreWithGetters<G> & PiniaCustomProperties>;
}
/**
* Options passed to `defineStore()` that are common between option and setup
* stores. Extend this interface if you want to add custom options to both kinds
* of stores.
*/
export declare interface DefineStoreOptionsBase<S extends StateTree, Store> {
/**
* Allows hydrating the store during SSR when there is an available state in
* pinia.state.
*
* @param store - the store
* @param initialState - initialState
*/
hydrate?(store: Store, initialState: UnwrapRef<S>): void;
}
/**
* Available `options` when creating a pinia plugin.
*/
export declare interface DefineStoreOptionsInPlugin<Id extends string, S extends StateTree, G, A> extends Omit<DefineStoreOptions<Id, S, G, A>, 'id' | 'actions'> {
/**
* Extracted object of actions. Added by useStore() when the store is built
* using the setup API, otherwise uses the one passed to `defineStore()`.
* Defaults to an empty object if no actions are defined.
*/
actions: A;
/**
* Id of the store. Only available when the options API is used.
*
* @deprecated Use `store.$id` instead.
*/
id?: Id;
}
/**
* @internal
*/
declare type _ExtractActionsFromSetupStore<SS> = _SpreadPropertiesFromObject<SS, _UnionToTuple<keyof SS>, _Method>;
/**
* @internal
*/
declare type _ExtractGettersFromSetupStore<SS> = _SpreadPropertiesFromObject<SS, _UnionToTuple<keyof SS>, ComputedRef<any>>;
/**
* @internal
*/
declare type _ExtractStateFromSetupStore<SS> = _SpreadStateFromStore<SS, _UnionToTuple<keyof SS>>;
/**
* Generic and type-unsafe version of Store. Doesn't fail on access with
* strings, making it much easier to write generic functions that do not care
* about the kind of store that is passed.
* @deprecated Use `StoreGeneric` instead
*/
export declare type GenericStore<Id extends string = string, S extends StateTree = any, G extends GettersTree<S> = GettersTree<S>, A = ActionsTree> = StoreWithState<Id, S, G, A> & UnwrapRef<S> & StoreWithGetters<G> & StoreWithActions<A> & PiniaCustomProperties<Id, S, G, A> & PiniaCustomStateProperties<S>;
export declare type GenericStore<Id extends string = string, S extends StateTree = StateTree, G = GettersTree<S>, A = ActionsTree> = StoreWithState<Id, S, G, A> & UnwrapRef<S> & StoreWithGetters<G> & A & PiniaCustomProperties<Id, S, G, A> & PiniaCustomStateProperties<S>;
/**
* Type of an object of Getters that infers the argument
* Type of an object of Getters that infers the argument.
*
* @internal
*/
export declare type GettersTree<S extends StateTree> = Record<string, ((state: UnwrapRef<(StateTree extends S ? {} : S) & PiniaCustomStateProperties<S>>) => any) | (() => any)>;
export declare type GettersTree<S extends StateTree> = Record<string, ((state: UnwrapRef<S> & UnwrapRef<PiniaCustomStateProperties<S>>) => any) | (() => any)>;

@@ -220,3 +324,3 @@ /**

*/
export declare function mapState<Id extends string, S extends StateTree, G extends GettersTree<S>, A>(useStore: StoreDefinition<Id, S, G, A>, keys: Array<keyof S | keyof G>): _MapStateReturn<S, G>;
export declare function mapState<Id extends string, S extends StateTree, G extends GettersTree<S>, A, Keys extends keyof S | keyof G>(useStore: StoreDefinition<Id, S, G, A>, keys: readonly Keys[]): _MapStateReturn<S, G, Keys>;

@@ -226,4 +330,4 @@ /**

*/
export declare type _MapStateObjectReturn<Id extends string, S extends StateTree, G extends GettersTree<S>, A, T extends Record<string, keyof S | keyof G | ((store: Store<Id, S, G, A>) => any)>> = {
[key in keyof T]: () => T[key] extends (store: Store) => infer R ? R : T[key] extends keyof Store<Id, S, G, A> ? Store<Id, S, G, A>[T[key]] : never;
export declare type _MapStateObjectReturn<Id extends string, S extends StateTree, G extends GettersTree<S>, A, T extends Record<string, keyof S | keyof G | ((store: Store<Id, S, G, A>) => any)> = {}> = {
[key in keyof T]: () => T[key] extends (store: any) => infer R ? R : T[key] extends keyof Store<Id, S, G, A> ? Store<Id, S, G, A>[T[key]] : never;
};

@@ -234,4 +338,4 @@

*/
export declare type _MapStateReturn<S extends StateTree, G extends GettersTree<S>> = {
[key in keyof S | keyof G]: () => key extends keyof Store<string, S, G, {}> ? Store<string, S, G, {}>[key] : never;
export declare type _MapStateReturn<S extends StateTree, G extends GettersTree<S>, Keys extends keyof S | keyof G = keyof S | keyof G> = {
[key in Keys]: () => Store<string, S, G, {}>[key];
};

@@ -345,2 +449,6 @@

declare type _Overwrite<T, S extends any> = {
[P in keyof T]: P extends keyof S ? S[P] : never;
};
/**

@@ -374,2 +482,14 @@ * Every application must own its own pinia to be able to create stores

/**
* Effect scope the pinia is attached to
*
* @internal
*/
_e: EffectScope;
/**
* Registry of stores used by this pinia.
*
* @internal
*/
_s: Map<string, StoreGeneric>;
/**
* Added by `createTestingPinia()` to bypass `useStore(pinia)`.

@@ -383,9 +503,9 @@ *

/**
* Properties that are added to every store by `pinia.use()`
* Properties that are added to every store by `pinia.use()`.
*/
export declare interface PiniaCustomProperties<Id extends string = string, S extends StateTree = StateTree, G extends GettersTree<S> = GettersTree<S>, A = ActionsTree> {
export declare interface PiniaCustomProperties<Id extends string = string, S extends StateTree = StateTree, G = GettersTree<S>, A = ActionsTree> {
}
/**
* Properties that are added to every `store.$state` by `pinia.use()`
* Properties that are added to every `store.$state` by `pinia.use()`.
*/

@@ -398,3 +518,3 @@ export declare interface PiniaCustomStateProperties<S extends StateTree = StateTree> {

*/
export declare interface PiniaPluginContext<Id extends string = string, S extends StateTree = StateTree, G extends GettersTree<S> = GettersTree<S>, A = ActionsTree> {
export declare interface PiniaPluginContext<Id extends string = string, S extends StateTree = StateTree, G = GettersTree<S>, A = ActionsTree> {
/**

@@ -415,3 +535,3 @@ * pinia instance.

*/
options: DefineStoreOptions<Id, S, G, A>;
options: DefineStoreOptionsInPlugin<Id, S, G, A>;
}

@@ -432,2 +552,4 @@

declare type _PopUnion<U> = _UnionToOvlds<U> extends (a: infer A) => void ? A : never;
/**

@@ -456,2 +578,15 @@ * Sets or unsets the active pinia. Used in SSR and internally when calling

/**
* @internal
*/
declare type _SpreadPropertiesFromObject<SS, K extends readonly any[], T> = K extends readonly [infer A, ...infer Rest] ? A extends string | number | symbol ? SS extends Record<A, T> ? Record<A, UnwrapRef<SS[A]>> & _SpreadPropertiesFromObject<SS, Rest, T> : _SpreadPropertiesFromObject<SS, Rest, T> : {} : {};
/**
* @internal
*/
declare type _SpreadStateFromStore<SS, K extends readonly any[]> = K extends readonly [
infer A,
...infer Rest
] ? A extends string | number | symbol ? SS extends Record<A, _Method | ComputedRef<any>> ? _SpreadStateFromStore<SS, Rest> : SS extends Record<A, any> ? Record<A, UnwrapRef<SS[A]>> & _SpreadStateFromStore<SS, Rest> : never : {} : {};
/**
* Generic state of a Store

@@ -464,8 +599,14 @@ */

*/
export declare type Store<Id extends string = string, S extends StateTree = StateTree, G extends GettersTree<S> = GettersTree<S>, A = ActionsTree> = StoreWithState<Id, StateTree extends S ? {} : S, G, A> & (StateTree extends S ? {} : UnwrapRef<S>) & (GettersTree<S> extends G ? {} : StoreWithGetters<G>) & (ActionsTree extends A ? {} : StoreWithActions<A>) & PiniaCustomProperties<Id, S, G, A> & PiniaCustomStateProperties<S>;
export declare type Store<Id extends string = string, S extends StateTree = {}, G = {}, A = {}> = StoreWithState<Id, S, G, A> & UnwrapRef<S> & StoreWithGetters<G> & (ActionsTree extends A ? {} : A) & PiniaCustomProperties<Id, S, G, A> & PiniaCustomStateProperties<S>;
/**
* Extract the actions of a store type. Works with both a Setup Store or an
* Options Store.
*/
export declare type StoreActions<SS> = SS extends Store<string, StateTree, GettersTree<StateTree>, infer A> ? A : _ExtractActionsFromSetupStore<SS>;
/**
* Return type of `defineStore()`. Function that allows instantiating a store.
*/
export declare interface StoreDefinition<Id extends string = string, S extends StateTree = StateTree, G extends GettersTree<S> = GettersTree<S>, A = ActionsTree> {
export declare interface StoreDefinition<Id extends string = string, S extends StateTree = StateTree, G = GettersTree<S>, A = ActionsTree> {
/**

@@ -475,4 +616,5 @@ * Returns a store, creates it if necessary.

* @param pinia - Pinia instance to retrieve the store
* @param hot - dev only hot module replacement
*/
(pinia?: Pinia | null | undefined): Store<Id, S, G, A>;
(pinia?: Pinia | null | undefined, hot?: StoreGeneric): Store<Id, S, G, A>;
/**

@@ -482,5 +624,24 @@ * Id of the store. Used by map helpers.

$id: Id;
/**
* Dev only pinia for HMR.
*
* @internal
*/
_pinia?: Pinia;
}
/**
* Generic and type-unsafe version of Store. Doesn't fail on access with
* strings, making it much easier to write generic functions that do not care
* about the kind of store that is passed.
*/
export declare type StoreGeneric = Store<string, StateTree, GettersTree<StateTree>, ActionsTree>;
/**
* Extract the getters of a store type. Works with both a Setup Store or an
* Options Store.
*/
export declare type StoreGetters<SS> = SS extends Store<string, StateTree, infer G, ActionsTree> ? StoreWithGetters<G> : _ExtractGettersFromSetupStore<SS>;
/**
* @internal

@@ -495,34 +656,99 @@ */

*/
export declare type StoreOnActionListener<Id extends string = string, S extends StateTree = StateTree, G extends GettersTree<S> = GettersTree<S>, A = ActionsTree> = (context: StoreOnActionListenerContext<Id, S, G, A>) => void;
export declare type StoreOnActionListener<Id extends string, S extends StateTree, G, A> = (context: StoreOnActionListenerContext<Id, S, G, {} extends A ? ActionsTree : A>) => void;
/**
* Context object passed to callbacks of `store.$onAction(context => {})`
* TODO: should have only the Id, the Store and Actions to generate the proper object
*/
export declare type StoreOnActionListenerContext<Id extends string, S extends StateTree, G extends GettersTree<S>, A> = {
[Name in keyof A]: {
/**
* Name of the action
*/
name: Name;
/**
* Store that is invoking the action
*/
store: Store<Id, S, G, A>;
/**
* Parameters passed to the action
*/
args: A[Name] extends _Method ? Parameters<A[Name]> : unknown[];
/**
* Sets up a hook once the action is finished. It receives the return value of
* the action, if it's a Promise, it will be unwrapped.
*/
after: (callback: A[Name] extends _Method ? (resolvedReturn: UnwrapPromise<ReturnType<A[Name]>>) => void : () => void) => void;
/**
* Sets up a hook if the action fails.
*/
onError: (callback: (error: unknown) => void) => void;
};
export declare type StoreOnActionListenerContext<Id extends string, S extends StateTree, G, A> = ActionsTree extends A ? _StoreOnActionListenerContext<StoreGeneric, string, ActionsTree> : {
[Name in keyof A]: Name extends string ? _StoreOnActionListenerContext<Store<Id, S, G, A>, Name, A> : never;
}[keyof A];
declare type _StoreOnActionListenerContext<Store, ActionName extends string, A> = {
/**
* Name of the action
*/
name: ActionName;
/**
* Store that is invoking the action
*/
store: Store;
/**
* Parameters passed to the action
*/
args: A extends Record<ActionName, _Method> ? Parameters<A[ActionName]> : unknown[];
/**
* Sets up a hook once the action is finished. It receives the return value
* of the action, if it's a Promise, it will be unwrapped. Can return a
* value (other than `undefined`) to **override** the returned value.
*/
after: (callback: A extends Record<ActionName, _Method> ? (resolvedReturn: UnwrapPromise<ReturnType<A[ActionName]>>) => void | ReturnType<A[ActionName]> | UnwrapPromise<ReturnType<A[ActionName]>> : () => void) => void;
/**
* Sets up a hook if the action fails. Return `false` to catch the error and
* stop it fro propagating.
*/
onError: (callback: (error: unknown) => unknown | false) => void;
};
/**
* Properties of a store.
*/
export declare interface StoreProperties<Id extends string> {
/**
* Unique identifier of the store
*/
$id: Id;
/**
* Private property defining the pinia the store is attached to.
*
* @internal
*/
_p: Pinia;
/**
* Used by devtools plugin to retrieve getters. Removed in production.
*
* @internal
*/
_getters?: string[];
/**
* Used by devtools plugin to retrieve properties added with plugins. Removed
* in production. Can be used by the user to add property keys of the store
* that should be displayed in devtools.
*
* @internal
*/
_customProperties: Set<string>;
/**
* Handles a HMR replacement of this store. Dev Only.
*
* @internal
*/
_hotUpdate(useStore: StoreGeneric): void;
/**
* Allows pausing some of the watching mechanisms while the store is being
* patched with a newer version.
*
* @internal
*/
_hotUpdating: boolean;
/**
* Payload of the hmr update. Dev only.
*
* @internal
*/
_hmrPayload: {
state: string[];
hotState: Ref<StateTree>;
actions: ActionsTree;
getters: ActionsTree;
};
}
/**
* Extract the state of a store type. Works with both a Setup Store or an
* Options Store. Note this unwraps refs.
*/
export declare type StoreState<SS> = SS extends Store<string, infer S, GettersTree<StateTree>, ActionsTree> ? UnwrapRef<S> : _ExtractStateFromSetupStore<SS>;
/**
* Store augmented for actions

@@ -549,30 +775,8 @@ *

*/
export declare interface StoreWithState<Id extends string, S extends StateTree, G extends GettersTree<StateTree> = GettersTree<S>, A = ActionsTree> {
export declare interface StoreWithState<Id extends string, S extends StateTree, G, A> extends StoreProperties<Id> {
/**
* Unique identifier of the store
*/
$id: Id;
/**
* State of the Store. Setting it will replace the whole state.
*/
$state: UnwrapRef<StateTree extends S ? {} : S> & PiniaCustomStateProperties<S>;
$state: UnwrapRef<S> & PiniaCustomStateProperties<S>;
/**
* Private property defining the pinia the store is attached to.
*
* @internal
*/
_p: Pinia;
/**
* Used by devtools plugin to retrieve getters. Removed in production.
*
* @internal
*/
_getters?: string[];
/**
* Used by devtools plugin to retrieve properties added with plugins. Removed in production.
*
* @internal
*/
_customProperties: Set<string>;
/**
* Applies a state patch to current state. Allows passing nested values

@@ -593,2 +797,3 @@ *

* Resets the store to its initial state by building a new state object.
* TODO: make this options only
*/

@@ -600,16 +805,11 @@ $reset(): void;

* `store.$subscribe()` inside of a component, it will be automatically
* cleanup up when the component gets unmounted.
* cleanup up when the component gets unmounted unless `detached` is set to
* true.
*
* @param callback - callback passed to the watcher
* @param detached - detach the subscription from the context this is called from
* @returns function that removes the watcher
*/
$subscribe(callback: SubscriptionCallback<S>): () => void;
$subscribe(callback: SubscriptionCallback<S>, detached?: boolean): () => void;
/**
* Array of registered action subscriptions.Set without the generics to avoid
* errors between the generic version of Store and specific stores.
*
* @internal
*/
_as: StoreOnActionListener[];
/**
* @alpha Please send feedback at https://github.com/posva/pinia/issues/240

@@ -628,3 +828,3 @@ * Setups a callback to be called every time an action is about to get

* `store.$onAction()` inside of a component, it will be automatically cleanup
* up when the component gets unmounted.
* up when the component gets unmounted unless `detached` is set to true.
*

@@ -649,5 +849,6 @@ * @example

* @param callback - callback called before every action
* @param detached - detach the subscription from the context this is called from
* @returns function that removes the watcher
*/
$onAction(callback: StoreOnActionListener<Id, S, G, A>): () => void;
$onAction(callback: StoreOnActionListener<Id, S, G, A>, detached?: boolean): () => void;
}

@@ -766,3 +967,7 @@

declare interface TestingPinia extends Pinia {
/**
* Pinia instance specifically designed for testing. Extends a regular
* {@link Pinia} instance with test specific properties.
*/
export declare interface TestingPinia extends Pinia {
/**

@@ -776,4 +981,21 @@ * Clears the cache of spies used for actions.

declare type TuplePush<T extends any[], X> = T extends any ? _Overwrite<_TupleUnshift<T, any>, T & {
[x: string]: X;
}> : never;
declare type _TupleUnshift<T extends any[], X> = T extends any ? ((x: X, ...t: T) => void) extends (...t: infer R) => void ? R : never : never;
declare type _UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
declare type _UnionToOvlds<U> = _UnionToIntersection<U extends any ? (f: U) => void : never>;
declare type _UnionToTuple<U> = _UnionToTupleRecursively<[], U>;
declare type _UnionToTupleRecursively<T extends any[], U> = {
1: T;
0: _PopUnion<U> extends infer SELF ? _UnionToTupleRecursively<TuplePush<T, SELF>, Exclude<U, SELF>> : never;
}[[U] extends [never] ? 1 : 0];
declare type UnwrapPromise<T> = T extends Promise<infer V> ? V : T;
export { }
/*!
* pinia v2.0.0-beta.5
* pinia v2.0.0-rc.0
* (c) 2021 Eduardo San Martin Morote
* @license MIT
*/
import { warn, toRaw, ref, markRaw, getCurrentInstance, inject, provide, computed, reactive, watch, onUnmounted, isRef, isReactive, createApp } from 'vue';
import { warn, toRaw, markRaw, effectScope, ref, isRef, isReactive, getCurrentInstance, onUnmounted, inject, watch, toRef, reactive, computed, toRefs, createApp } from 'vue';
import { setupDevtoolsPlugin } from '@vue/devtools-api';

@@ -33,7 +33,2 @@

};
/**
* Map of stores based on a Pinia instance. Allows setting and retrieving stores
* for the current running application (with its pinia).
*/
const storesMap = new WeakMap();
const piniaSymbol = (Symbol('pinia') );

@@ -422,3 +417,2 @@

key,
// @ts-expect-error
value: store.$state[key],

@@ -432,3 +426,2 @@ })),

key: getterName,
// @ts-expect-error
value: store[getterName],

@@ -441,3 +434,2 @@ }));

key,
// @ts-expect-error
value: store[key],

@@ -488,7 +480,2 @@ }));

/**
* Registered stores used for devtools.
*/
const registeredStores = /*#__PURE__*/ new Map();
let isAlreadyInstalled;
// timeline can be paused when directly changing the state

@@ -499,14 +486,17 @@ let isTimelineActive = true;

const INSPECTOR_ID = 'pinia';
function addDevtools(app, store) {
// TODO: we probably need to ensure the latest version of the store is kept:
// without effectScope, multiple stores will be created and will have a
// limited lifespan for getters.
// add a dev only variable that is removed in unmounted and replace the store
let hasSubscribed = true;
const storeType = '🍍 ' + store.$id;
if (!registeredStores.has(store.$id)) {
registeredStores.set(store.$id, store);
componentStateTypes.push(storeType);
hasSubscribed = false;
}
/**
* Gets the displayed name of a store in devtools
*
* @param id - id of the store
* @returns a formatted string
*/
const getStoreType = (id) => '🍍 ' + id;
/**
* Add the pinia plugin without any store. Allows displaying a Pinia plugin tab
* as soon as it is added to the application.
*
* @param app - Vue application
* @param pinia - pinia instance
*/
function registerPiniaDevtools(app, pinia) {
setupDevtoolsPlugin({

@@ -521,157 +511,161 @@ id: 'dev.esm.pinia',

}, (api) => {
if (!isAlreadyInstalled) {
api.addTimelineLayer({
id: MUTATIONS_LAYER_ID,
label: `Pinia 🍍`,
color: 0xe5df88,
});
api.addInspector({
id: INSPECTOR_ID,
label: 'Pinia 🍍',
icon: 'storage',
treeFilterPlaceholder: 'Search stores',
actions: [
{
icon: 'content_copy',
action: () => {
actionGlobalCopyState(store._p);
},
tooltip: 'Serialize and copy the state',
api.addTimelineLayer({
id: MUTATIONS_LAYER_ID,
label: `Pinia 🍍`,
color: 0xe5df88,
});
api.addInspector({
id: INSPECTOR_ID,
label: 'Pinia 🍍',
icon: 'storage',
treeFilterPlaceholder: 'Search stores',
actions: [
{
icon: 'content_copy',
action: () => {
actionGlobalCopyState(pinia);
},
{
icon: 'content_paste',
action: async () => {
await actionGlobalPasteState(store._p);
api.sendInspectorTree(INSPECTOR_ID);
api.sendInspectorState(INSPECTOR_ID);
},
tooltip: 'Replace the state with the content of your clipboard',
tooltip: 'Serialize and copy the state',
},
{
icon: 'content_paste',
action: async () => {
await actionGlobalPasteState(pinia);
api.sendInspectorTree(INSPECTOR_ID);
api.sendInspectorState(INSPECTOR_ID);
},
{
icon: 'save',
action: () => {
actionGlobalSaveState(store._p);
},
tooltip: 'Save the state as a JSON file',
tooltip: 'Replace the state with the content of your clipboard',
},
{
icon: 'save',
action: () => {
actionGlobalSaveState(pinia);
},
{
icon: 'folder_open',
action: async () => {
await actionGlobalOpenStateFile(store._p);
api.sendInspectorTree(INSPECTOR_ID);
api.sendInspectorState(INSPECTOR_ID);
},
tooltip: 'Import the state from a JSON file',
tooltip: 'Save the state as a JSON file',
},
{
icon: 'folder_open',
action: async () => {
await actionGlobalOpenStateFile(pinia);
api.sendInspectorTree(INSPECTOR_ID);
api.sendInspectorState(INSPECTOR_ID);
},
],
});
api.on.inspectComponent((payload, ctx) => {
const proxy = (payload.componentInstance &&
payload.componentInstance.proxy);
if (proxy && proxy._pStores) {
const piniaStores = payload.componentInstance.proxy._pStores;
Object.values(piniaStores).forEach((store) => {
tooltip: 'Import the state from a JSON file',
},
],
});
api.on.inspectComponent((payload, ctx) => {
const proxy = (payload.componentInstance &&
payload.componentInstance.proxy);
if (proxy && proxy._pStores) {
const piniaStores = payload.componentInstance.proxy._pStores;
Object.values(piniaStores).forEach((store) => {
payload.instanceData.state.push({
type: getStoreType(store.$id),
key: 'state',
editable: true,
value: store.$state,
});
if (store._getters && store._getters.length) {
payload.instanceData.state.push({
type: storeType,
key: 'state',
editable: true,
value: store.$state,
type: getStoreType(store.$id),
key: 'getters',
editable: false,
value: store._getters.reduce((getters, key) => {
getters[key] = store[key];
return getters;
}, {}),
});
if (store._getters && store._getters.length) {
payload.instanceData.state.push({
type: storeType,
key: 'getters',
editable: false,
value: store._getters.reduce((getters, key) => {
// @ts-expect-error
getters[key] = store[key];
return getters;
}, {}),
});
}
});
}
});
}
});
api.on.getInspectorTree((payload) => {
if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {
let stores = [pinia];
stores = stores.concat(Array.from(pinia._s.values()));
payload.rootNodes = (payload.filter
? stores.filter((store) => '$id' in store
? store.$id
.toLowerCase()
.includes(payload.filter.toLowerCase())
: PINIA_ROOT_LABEL.toLowerCase().includes(payload.filter.toLowerCase()))
: stores).map(formatStoreForInspectorTree);
}
});
api.on.getInspectorState((payload) => {
if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {
const inspectedStore = payload.nodeId === PINIA_ROOT_ID
? pinia
: pinia._s.get(payload.nodeId);
if (!inspectedStore) {
// this could be the selected store restored for a different project
// so it's better not to say anything here
return;
}
});
api.on.getInspectorTree((payload) => {
if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {
let stores = [store._p];
stores = stores.concat(Array.from(registeredStores.values()));
payload.rootNodes = (payload.filter
? stores.filter((store) => '$id' in store
? store.$id
.toLowerCase()
.includes(payload.filter.toLowerCase())
: PINIA_ROOT_LABEL.toLowerCase().includes(payload.filter.toLowerCase()))
: stores).map(formatStoreForInspectorTree);
if (inspectedStore) {
payload.state = formatStoreForInspectorState(inspectedStore);
}
});
api.on.getInspectorState((payload) => {
if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {
const inspectedStore = payload.nodeId === PINIA_ROOT_ID
? store._p
: registeredStores.get(payload.nodeId);
if (!inspectedStore) {
// this could be the selected store restored for a different project
// so it's better not to say anything here
return;
}
if (inspectedStore) {
payload.state = formatStoreForInspectorState(inspectedStore);
}
}
});
api.on.editInspectorState((payload, ctx) => {
if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {
const inspectedStore = payload.nodeId === PINIA_ROOT_ID
? pinia
: pinia._s.get(payload.nodeId);
if (!inspectedStore) {
return toastMessage(`store "${payload.nodeId}" not found`, 'error');
}
});
api.on.editInspectorState((payload, ctx) => {
if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {
const inspectedStore = payload.nodeId === PINIA_ROOT_ID
? store._p
: registeredStores.get(payload.nodeId);
if (!inspectedStore) {
return toastMessage(`store "${payload.nodeId}" not found`, 'error');
const { path } = payload;
if (!isPinia(inspectedStore)) {
// access only the state
if (path.length !== 1 ||
!inspectedStore._customProperties.has(path[0]) ||
path[0] in inspectedStore.$state) {
path.unshift('$state');
}
const { path } = payload;
if (!isPinia(store)) {
// access only the state
if (path.length !== 1 ||
!store._customProperties.has(path[0]) ||
path[0] in store.$state) {
path.unshift('$state');
}
}
else {
path.unshift('state', 'value');
}
isTimelineActive = false;
payload.set(inspectedStore, path, payload.state.value);
isTimelineActive = true;
}
});
api.on.editComponentState((payload) => {
if (payload.type.startsWith('🍍')) {
const storeId = payload.type.replace(/^🍍\s*/, '');
const store = registeredStores.get(storeId);
if (!store) {
return toastMessage(`store "${storeId}" not found`, 'error');
}
const { path } = payload;
if (path[0] !== 'state') {
return toastMessage(`Invalid path for store "${storeId}":\n${path}\nOnly state can be modified.`);
}
// rewrite the first entry to be able to directly set the state as
// well as any other path
path[0] = '$state';
isTimelineActive = false;
payload.set(store, path, payload.state.value);
isTimelineActive = true;
else {
path.unshift('state', 'value');
}
});
isAlreadyInstalled = true;
}
else {
api.sendInspectorTree(INSPECTOR_ID);
api.sendInspectorState(INSPECTOR_ID);
}
// avoid subscribing to mutations and actions twice
if (hasSubscribed)
return;
store.$onAction(({ after, onError, name, args, store }) => {
isTimelineActive = false;
payload.set(inspectedStore, path, payload.state.value);
isTimelineActive = true;
}
});
api.on.editComponentState((payload) => {
if (payload.type.startsWith('🍍')) {
const storeId = payload.type.replace(/^🍍\s*/, '');
const store = pinia._s.get(storeId);
if (!store) {
return toastMessage(`store "${storeId}" not found`, 'error');
}
const { path } = payload;
if (path[0] !== 'state') {
return toastMessage(`Invalid path for store "${storeId}":\n${path}\nOnly state can be modified.`);
}
// rewrite the first entry to be able to directly set the state as
// well as any other path
path[0] = '$state';
isTimelineActive = false;
payload.set(store, path, payload.state.value);
isTimelineActive = true;
}
});
});
}
function addStoreToDevtools(app, store) {
if (!componentStateTypes.includes(getStoreType(store.$id))) {
componentStateTypes.push(getStoreType(store.$id));
}
setupDevtoolsPlugin({
id: 'dev.esm.pinia',
label: 'Pinia 🍍',
logo: 'https://pinia.esm.dev/logo.svg',
packageName: 'pinia',
homepage: 'https://pinia.esm.dev',
componentStateTypes,
app,
}, (api) => {
store.$onAction(({ after, onError, name, args }) => {
const groupId = runningActionId++;

@@ -685,2 +679,3 @@ api.addTimelineEvent({

data: {
store: formatDisplay(store.$id),
action: formatDisplay(name),

@@ -693,2 +688,3 @@ args,

after((result) => {
activeAction = undefined;
api.addTimelineEvent({

@@ -701,2 +697,3 @@ layerId: MUTATIONS_LAYER_ID,

data: {
store: formatDisplay(store.$id),
action: formatDisplay(name),

@@ -711,2 +708,3 @@ args,

onError((error) => {
activeAction = undefined;
api.addTimelineEvent({

@@ -720,2 +718,3 @@ layerId: MUTATIONS_LAYER_ID,

data: {
store: formatDisplay(store.$id),
action: formatDisplay(name),

@@ -729,3 +728,3 @@ args,

});
});
}, true);
store.$subscribe(({ events, type }, state) => {

@@ -740,3 +739,6 @@ if (!isTimelineActive)

title: formatMutationType(type),
data: formatEventData(events),
data: {
store: formatDisplay(store.$id),
...formatEventData(events),
},
groupId: activeAction,

@@ -769,6 +771,23 @@ };

});
}, true);
const hotUpdate = store._hotUpdate;
store._hotUpdate = markRaw((newStore) => {
hotUpdate(newStore);
api.addTimelineEvent({
layerId: MUTATIONS_LAYER_ID,
event: {
time: Date.now(),
title: '🔥 ' + store.$id,
subtitle: 'HMR update',
data: {
store: formatDisplay(store.$id),
info: formatDisplay(`HMR update`),
},
},
});
});
// trigger an update so it can display new registered stores
// @ts-ignore
api.notifyComponentUpdate();
api.sendInspectorTree(INSPECTOR_ID);
api.sendInspectorState(INSPECTOR_ID);
toastMessage(`"${store.$id}" store installed`);

@@ -780,8 +799,10 @@ });

/**
* pinia.use(devtoolsPlugin)
* Patches a store to enable action grouping in devtools by wrapping the store with a Proxy that is passed as the context of all actions, allowing us to set `runningAction` on each access and effectively associating any state mutation to the action.
*
* @param store - store to patch
* @param actionNames - list of actionst to patch
*/
function devtoolsPlugin({ app, store, options, pinia }) {
function patchActionForGrouping(store, actionNames) {
// original actions of the store as they are given by pinia. We are going to override them
const actions = Object.keys(options.actions || {}).reduce((storeActions, actionName) => {
// @ts-expect-error
const actions = actionNames.reduce((storeActions, actionName) => {
// use toRaw to avoid tracking #541

@@ -792,5 +813,4 @@ storeActions[actionName] = toRaw(store)[actionName];

for (const actionName in actions) {
// @ts-expect-error
store[actionName] = function () {
setActivePinia(pinia);
// setActivePinia(store._p)
// the running action id is incremented in a before action hook

@@ -811,4 +831,26 @@ const _actionId = runningActionId;

}
addDevtools(app,
// @ts-expect-error: FIXME: if possible...
}
/**
* pinia.use(devtoolsPlugin)
*/
function devtoolsPlugin({ app, store, options }) {
// HMR module
if (store.$id.startsWith('__hot:')) {
return;
}
// only wrap actions in option-defined stores as this technique relies on
// wrapping the context of the action with a proxy
if ('id' in options) {
patchActionForGrouping(
// @ts-expect-error: can cast the store...
store, Object.keys(options.actions));
const originalHotUpdate = store._hotUpdate;
// Upgrade the HMR to also update the new actions
toRaw(store)._hotUpdate = function (newStore) {
originalHotUpdate.apply(this, arguments);
patchActionForGrouping(store, Object.keys(newStore._hmrPayload.actions));
};
}
addStoreToDevtools(app,
// FIXME: is there a way to allow the assignment from Store<Id, S, G, A> to StoreGeneric?
store);

@@ -821,6 +863,6 @@ }

function createPinia() {
const scope = effectScope(true);
// NOTE: here we could check the window object for a state and directly set it
// if there is anything like it with Vue 3 SSR
const state = ref({});
let localApp;
const state = scope.run(() => ref({}));
let _p = [];

@@ -831,3 +873,3 @@ // plugins added before calling app.use(pinia)

install(app) {
pinia._a = localApp = app;
pinia._a = app;
app.provide(piniaSymbol, pinia);

@@ -839,2 +881,5 @@ app.config.globalProperties.$pinia = pinia;

setActivePinia(pinia);
{
registerPiniaDevtools(app, pinia);
}
}

@@ -844,3 +889,3 @@ toBeInstalled.forEach((plugin) => _p.push(plugin));

use(plugin) {
if (!localApp) {
if (!this._a) {
toBeInstalled.push(plugin);

@@ -855,3 +900,6 @@ }

// it's actually undefined here
_a: localApp,
// @ts-expect-error
_a: null,
_e: scope,
_s: new Map(),
state,

@@ -867,4 +915,110 @@ });

/**
* Checks if a function is a `StoreDefinition`
*
* @param fn - object to test
* @returns true if `fn` is a StoreDefinition
*/
const isUseStore = (fn) => {
return typeof fn === 'function' && typeof fn.$id === 'string';
};
/**
* Mutates in place `newState` with `oldState` to _hot update_ it. It will
* remove any key not existing in `newState` and recursively merge plain
* objects.
*
* @param newState - new state object to be patched
* @param oldState - old state that should be used to patch newState
* @returns - newState
*/
function patchObject(newState, oldState) {
// no need to go through symbols because they cannot be serialized anyway
for (const key in oldState) {
const subPatch = oldState[key];
// skip the whole sub tree
if (!(key in newState)) {
continue;
}
const targetValue = newState[key];
if (isPlainObject(targetValue) &&
isPlainObject(subPatch) &&
!isRef(subPatch) &&
!isReactive(subPatch)) {
newState[key] = patchObject(targetValue, subPatch);
}
else {
// objects are either a bit more complex (e.g. refs) or primitives, so we
// just set the whole thing
newState[key] = subPatch;
}
}
return newState;
}
/**
* Creates an _accept_ function to pass to `import.meta.hot` in Vite applications.
*
* @example
* ```js
* const useUser = defineStore(...)
* if (import.meta.hot) {
* import.meta.hot.accept(acceptHMRUpdate(useUser, import.meta.hot))
* }
* ```
*
* @param initialUseStore - return of the defineStore to hot update
* @param hot - `import.meta.hot`
*/
function acceptHMRUpdate(initialUseStore, hot) {
return (newModule) => {
const pinia = hot.data.pinia || initialUseStore._pinia;
if (!pinia) {
// this store is still not used
return;
}
// preserve the pinia instance across loads
hot.data.pinia = pinia;
// console.log('got data', newStore)
for (const exportName in newModule) {
const useStore = newModule[exportName];
// console.log('checking for', exportName)
if (isUseStore(useStore) && pinia._s.has(useStore.$id)) {
// console.log('Accepting update for', useStore.$id)
const id = useStore.$id;
if (id !== initialUseStore.$id) {
console.warn(`The id of the store changed from "${initialUseStore.$id}" to "${id}". Reloading.`);
// return import.meta.hot.invalidate()
return hot.invalidate();
}
const existingStore = pinia._s.get(id);
if (!existingStore) {
console.log(`skipping hmr because store doesn't exist yet`);
return;
}
useStore(pinia, existingStore);
}
}
};
}
function addSubscription(subscriptions, callback, detached) {
subscriptions.push(callback);
const removeSubscription = () => {
const idx = subscriptions.indexOf(callback);
if (idx > -1) {
subscriptions.splice(idx, 1);
}
};
if (!detached && getCurrentInstance()) {
onUnmounted(removeSubscription);
}
return removeSubscription;
}
function triggerSubscriptions(subscriptions, ...args) {
subscriptions.forEach((callback) => {
callback(...args);
});
}
function innerPatch(target, patchToApply) {
// TODO: get all keys like symbols as well
// no need to go through symbols because they cannot be serialized anyway
for (const key in patchToApply) {

@@ -887,36 +1041,98 @@ const subPatch = patchToApply[key];

const { assign } = Object;
/**
* Create an object of computed properties referring to
*
* @param rootStateRef - pinia.state
* @param id - unique name
*/
function computedFromState(rootStateRef, id) {
// let asComputed = computed<T>()
const reactiveObject = {};
const state = rootStateRef.value[id];
for (const key in state) {
// @ts-expect-error: the key matches
reactiveObject[key] = computed({
get: () => rootStateRef.value[id][key],
set: (value) => (rootStateRef.value[id][key] = value),
});
function isComputed(o) {
return o && o.effect;
}
function createOptionsStore(id, options, pinia, hot) {
const { state, actions, getters } = options;
function $reset() {
pinia.state.value[id] = state ? state() : {};
}
return reactiveObject;
const initialState = pinia.state.value[id];
let store;
function setup() {
if (!initialState && (!hot)) {
$reset();
}
// pinia.state.value[id] = state ? state() : {}
// avoid creating a state in pinia.state.value
const localState = hot
? toRefs(ref(state ? state() : {}).value)
: initialState || toRefs(pinia.state.value[id]);
return assign(localState, actions, Object.keys(getters || {}).reduce((computedGetters, name) => {
computedGetters[name] = markRaw(computed(() => {
setActivePinia(pinia);
// const context = store || ref(localState).value
// @ts-expect-error
// return getters![name].call(context, context)
return store && getters[name].call(store, store);
}));
return computedGetters;
}, {}));
}
store = createSetupStore(id, setup, options, pinia, hot);
store.$reset = $reset;
return store;
}
/**
* Creates a store with its state object. This is meant to be augmented with getters and actions
*
* @param id - unique identifier of the store, like a name. eg: main, cart, user
* @param buildState - function to build the initial state
* @param initialState - initial state applied to the store, Must be correctly typed to infer typings
*/
function initStore($id, buildState = () => ({}), initialState) {
const pinia = getActivePinia();
pinia.state.value[$id] = initialState || buildState();
// const state: Ref<S> = toRef(_p.state.value, $id)
let isListening = true;
const noop = () => { };
function createSetupStore($id, setup, options = {}, pinia, hot) {
let scope;
const buildState = options.state;
const optionsForPlugin = {
actions: {},
...options,
};
// watcher options for $subscribe
const $subscribeOptions = { deep: true, flush: 'sync' };
/* istanbul ignore else */
{
$subscribeOptions.onTrigger = (event) => {
if (isListening) {
debuggerEvents = event;
// avoid triggering this while the store is being built and the state is being set in pinia
}
else if (isListening == false && !store._hotUpdating) {
// let patch send all the events together later
/* istanbul ignore else */
if (Array.isArray(debuggerEvents)) {
debuggerEvents.push(event);
}
else {
console.error('🍍 debuggerEvents should be an array. This is most likely an internal Pinia bug.');
}
}
};
}
// internal state
let isListening; // set to true at the end
let subscriptions = markRaw([]);
let actionSubscriptions = markRaw([]);
let debuggerEvents;
const initialState = pinia.state.value[$id];
if (!initialState && true && !hot) {
// should be set in Vue 2
pinia.state.value[$id] = {};
}
const hotState = ref({});
if (!pinia._e.active) {
throw new Error('Pinia destroyed');
}
// TODO: idea create skipSerialize that marks properties as non serializable and they are skipped
const setupStore = pinia._e.run(() => {
scope = effectScope();
return scope.run(() => {
// skip setting up the watcher on HMR
if (!hot) {
watch(() => pinia.state.value[$id], (state, oldState) => {
if (isListening) {
triggerSubscriptions(subscriptions, {
storeId: $id,
type: MutationType.direct,
events: debuggerEvents,
}, state);
}
}, $subscribeOptions);
}
return setup();
});
});
function $patch(partialStateOrMutator) {

@@ -949,122 +1165,19 @@ let subscriptionMutation;

// because we paused the watcher, we need to manually call the subscriptions
subscriptions.forEach((callback) => {
callback(subscriptionMutation, pinia.state.value[$id]);
});
triggerSubscriptions(subscriptions, subscriptionMutation, pinia.state.value[$id]);
}
function $subscribe(callback) {
subscriptions.push(callback);
// watch here to link the subscription to the current active instance
// e.g. inside the setup of a component
const options = { deep: true, flush: 'sync' };
/* istanbul ignore else */
{
options.onTrigger = (event) => {
if (isListening) {
debuggerEvents = event;
}
else {
// let patch send all the events together later
/* istanbul ignore else */
if (Array.isArray(debuggerEvents)) {
debuggerEvents.push(event);
}
else {
console.error('🍍 debuggerEvents should be an array. This is most likely an internal Pinia bug.');
}
}
};
const $reset = () => {
throw new Error(`🍍: Store "${$id}" is build using the setup syntax and does not implement $reset().`);
}
const stopWatcher = watch(() => pinia.state.value[$id], (state, oldState) => {
if (isListening) {
callback({
storeId: $id,
type: MutationType.direct,
events: debuggerEvents,
}, state);
}
}, options);
const removeSubscription = () => {
const idx = subscriptions.indexOf(callback);
if (idx > -1) {
subscriptions.splice(idx, 1);
stopWatcher();
}
};
if (getCurrentInstance()) {
onUnmounted(removeSubscription);
}
return removeSubscription;
}
function $onAction(callback) {
actionSubscriptions.push(callback);
const removeSubscription = () => {
const idx = actionSubscriptions.indexOf(callback);
if (idx > -1) {
actionSubscriptions.splice(idx, 1);
}
};
if (getCurrentInstance()) {
onUnmounted(removeSubscription);
}
return removeSubscription;
}
function $reset() {
pinia.state.value[$id] = buildState();
}
const storeWithState = {
$id,
_p: pinia,
_as: actionSubscriptions,
// $state is added underneath
$patch,
$subscribe,
$onAction,
$reset,
};
const injectionSymbol = Symbol(`PiniaStore(${$id})`)
;
return [
storeWithState,
{
get: () => pinia.state.value[$id],
set: (newState) => {
isListening = false;
pinia.state.value[$id] = newState;
isListening = true;
},
},
injectionSymbol,
];
}
const noop = () => { };
/**
* Creates a store bound to the lifespan of where the function is called. This
* means creating the store inside of a component's setup will bound it to the
* lifespan of that component while creating it outside of a component will
* create an ever living store
*
* @param partialStore - store with state returned by initStore
* @param descriptor - descriptor to setup $state property
* @param $id - unique name of the store
* @param getters - getters of the store
* @param actions - actions of the store
*/
function buildStoreToUse(partialStore, descriptor, $id, getters = {}, actions = {}, options) {
const pinia = getActivePinia();
const computedGetters = {};
for (const getterName in getters) {
// @ts-ignore: it's only readonly for the users
computedGetters[getterName] = computed(() => {
/**
* Wraps an action to handle subscriptions.
*
* @param name - name of the action
* @param action - action to wrap
* @returns a wrapped action to handle subscriptions
*/
function wrapAction(name, action) {
return function () {
setActivePinia(pinia);
// eslint-disable-next-line @typescript-eslint/no-use-before-define
// @ts-expect-error: the argument count is correct
return getters[getterName].call(store, store);
});
}
const wrappedActions = {};
for (const actionName in actions) {
wrappedActions[actionName] = function () {
setActivePinia(pinia);
const args = Array.from(arguments);
const localStore = this || store;
let afterCallback = noop;

@@ -1078,18 +1191,99 @@ let onErrorCallback = noop;

}
partialStore._as.forEach((callback) => {
// @ts-expect-error
callback({ args, name: actionName, store: localStore, after, onError });
// @ts-expect-error
triggerSubscriptions(actionSubscriptions, {
args,
name,
store,
after,
onError,
});
let ret;
try {
ret = actions[actionName].apply(localStore, args);
Promise.resolve(ret).then(afterCallback).catch(onErrorCallback);
ret = action.apply(this && this.$id === $id ? this : store, args);
// handle sync errors
}
catch (error) {
onErrorCallback(error);
throw error;
if (onErrorCallback(error) !== false) {
throw error;
}
}
return ret;
if (ret instanceof Promise) {
return ret
.then((value) => {
const newRet = afterCallback(value);
// allow the afterCallback to override the return value
return newRet === undefined ? value : newRet;
})
.catch((error) => {
if (onErrorCallback(error) !== false) {
return Promise.reject(error);
}
});
}
// allow the afterCallback to override the return value
const newRet = afterCallback(ret);
return newRet === undefined ? ret : newRet;
};
}
const _hmrPayload = /*#__PURE__*/ markRaw({
actions: {},
getters: {},
state: [],
hotState,
});
// overwrite existing actions to support $onAction
for (const key in setupStore) {
const prop = setupStore[key];
if ((isRef(prop) && !isComputed(prop)) || isReactive(prop)) {
// mark it as a piece of state to be serialized
if (hot) {
hotState.value[key] = toRef(setupStore, key);
// createOptionStore already did this
}
else if (!buildState) {
pinia.state.value[$id][key] = prop;
// TODO: avoid if state exists for SSR
}
{
_hmrPayload.state.push(key);
}
// action
}
else if (typeof prop === 'function') {
// @ts-expect-error: we are overriding the function we avoid wrapping if
// this a hot module replacement store because the hotUpdate method needs
// to do it with the right context
setupStore[key] = hot ? prop : wrapAction(key, prop);
{
_hmrPayload.actions[key] = prop;
}
// list actions so they can be used in plugins
// @ts-expect-error
optionsForPlugin.actions[key] = prop;
}
else {
// add getters for devtools
if (isComputed(prop)) {
_hmrPayload.getters[key] = buildState
? // @ts-expect-error
options.getters[key]
: prop;
if (IS_CLIENT) {
const getters =
// @ts-expect-error: it should be on the store
setupStore._getters || (setupStore._getters = markRaw([]));
getters.push(key);
}
}
}
}
const partialStore = {
_p: pinia,
// _s: scope,
$id,
$onAction: addSubscription.bind(null, actionSubscriptions),
$patch,
$reset,
$subscribe: addSubscription.bind(null, subscriptions),
};
const store = reactive(assign(IS_CLIENT

@@ -1099,13 +1293,102 @@ ? // devtools custom properties

_customProperties: markRaw(new Set()),
_hmrPayload,
}
: {}, partialStore,
// using this means no new properties can be added as state
computedFromState(pinia.state, $id), computedGetters, wrappedActions));
: {}, partialStore, setupStore));
// use this instead of a computed with setter to be able to create it anywhere
// without linking the computed lifespan to wherever the store is first
// created.
Object.defineProperty(store, '$state', descriptor);
// add getters for devtools
if (IS_CLIENT) {
store._getters = markRaw(Object.keys(getters));
Object.defineProperty(store, '$state', {
get: () => (hot ? hotState.value : pinia.state.value[$id]),
set: (state) => {
if (hot) {
throw new Error('cannot set hotState');
}
pinia.state.value[$id] = state;
},
});
// add the hotUpdate before plugins to allow them to override it
{
store._hotUpdate = markRaw((newStore) => {
store._hotUpdating = true;
newStore._hmrPayload.state.forEach((stateKey) => {
if (stateKey in store.$state) {
const newStateTarget = newStore.$state[stateKey];
const oldStateSource = store.$state[stateKey];
if (typeof newStateTarget === 'object' &&
isPlainObject(newStateTarget) &&
isPlainObject(oldStateSource)) {
patchObject(newStateTarget, oldStateSource);
}
else {
// transfer the ref
newStore.$state[stateKey] = oldStateSource;
}
}
// patch direct access properties to allow store.stateProperty to work as
// store.$state.stateProperty
// @ts-expect-error
store[stateKey] = toRef(newStore.$state, stateKey);
});
// remove deleted state properties
Object.keys(store.$state).forEach((stateKey) => {
if (!(stateKey in newStore.$state)) {
delete store[stateKey];
}
});
// avoid devtools logging this as a mutation
isListening = false;
pinia.state.value[$id] = toRef(newStore._hmrPayload, 'hotState');
isListening = true;
for (const actionName in newStore._hmrPayload.actions) {
const action = newStore[actionName];
// @ts-expect-error: new key
store[actionName] =
// new line forced for TS
wrapAction(actionName, action);
}
// TODO: does this work in both setup and option store?
for (const getterName in newStore._hmrPayload.getters) {
const getter = newStore._hmrPayload.getters[getterName];
// @ts-expect-error
store[getterName] =
// ---
buildState
? // special handling of options api
computed(() => {
setActivePinia(pinia);
return getter.call(store, store);
})
: getter;
}
// remove deleted getters
Object.keys(store._hmrPayload.getters).forEach((key) => {
if (!(key in newStore._hmrPayload.getters)) {
delete store[key];
}
});
// remove old actions
Object.keys(store._hmrPayload.actions).forEach((key) => {
if (!(key in newStore._hmrPayload.actions)) {
delete store[key];
}
});
// update the values used in devtools and to allow deleting new properties later on
store._hmrPayload = newStore._hmrPayload;
store._getters = newStore._getters;
store._hotUpdating = false;
});
const nonEnumerable = {
writable: true,
configurable: true,
// avoid warning on devtools trying to display this property
enumerable: false,
};
if (IS_CLIENT) {
['_p', '_hmrPayload', '_getters', '_customProperties'].forEach((p) => {
Object.defineProperty(store, p, {
value: store[p],
...nonEnumerable,
});
});
}
}

@@ -1115,4 +1398,9 @@ // apply all plugins

if (IS_CLIENT) {
// @ts-expect-error: conflict between A and ActionsTree
const extensions = extender({ store, app: pinia._a, pinia, options });
const extensions = extender({
store,
app: pinia._a,
pinia,
// @ts-expect-error
options: optionsForPlugin,
});
Object.keys(extensions || {}).forEach((key) => store._customProperties.add(key));

@@ -1122,19 +1410,34 @@ assign(store, extensions);

else {
// @ts-expect-error: conflict between A and ActionsTree
assign(store, extender({ store, app: pinia._a, pinia, options }));
assign(store, extender({
store,
app: pinia._a,
pinia,
// @ts-expect-error
options: optionsForPlugin,
}));
}
});
if (initialState) {
(options.hydrate || innerPatch)(store, initialState);
}
isListening = true;
return store;
}
/**
* Creates a `useStore` function that retrieves the store instance
* @param options - options to define the store
*/
function defineStore(options) {
const { id, state, getters, actions } = options;
function useStore(pinia) {
function defineStore(
// TODO: add proper types from above
idOrOptions, setup, setupOptions) {
let id;
let options;
const isSetupStore = typeof setup === 'function';
if (typeof idOrOptions === 'string') {
id = idOrOptions;
// the option store setup will contain the actual options in this case
options = isSetupStore ? setupOptions : setup;
}
else {
options = idOrOptions;
id = idOrOptions.id;
}
function useStore(pinia, hot) {
const currentInstance = getCurrentInstance();
// only run provide when pinia hasn't been manually passed
const shouldProvide = currentInstance && !pinia;
// avoid injecting if `useStore` when not possible
pinia =

@@ -1149,33 +1452,35 @@ // in test mode, ignore the argument provided as we can always retrieve a

pinia = getActivePinia();
let storeCache = storesMap.get(pinia);
if (!storeCache)
storesMap.set(pinia, (storeCache = new Map()));
let storeAndDescriptor = storeCache.get(id);
let store;
if (!storeAndDescriptor) {
storeAndDescriptor = initStore(id, state, pinia.state.value[id]);
// @ts-expect-error: annoying to type
storeCache.set(id, storeAndDescriptor);
store = buildStoreToUse(storeAndDescriptor[0], storeAndDescriptor[1], id, getters, actions, options);
// allow children to reuse this store instance to avoid creating a new
// store for each child
if (shouldProvide) {
provide(storeAndDescriptor[2], store);
if (!pinia._s.has(id)) {
pinia._s.set(id, isSetupStore
? createSetupStore(id, setup, options, pinia)
: createOptionsStore(id, options, pinia));
{
// @ts-expect-error: not the right inferred type
useStore._pinia = pinia;
}
}
else {
store =
(currentInstance && inject(storeAndDescriptor[2], null)) ||
buildStoreToUse(storeAndDescriptor[0], storeAndDescriptor[1], id, getters, actions, options);
const store = pinia._s.get(id);
if (hot) {
const hotId = '__hot:' + id;
const newStore = isSetupStore
? createSetupStore(hotId, setup, options, pinia, true)
: createOptionsStore(hotId, assign({}, options), pinia, true);
hot._hotUpdate(newStore);
// cleanup the state properties and the store from the cache
delete pinia.state.value[hotId];
pinia._s.delete(hotId);
}
// save stores in instances to access them devtools
if (IS_CLIENT && currentInstance && currentInstance.proxy) {
if (IS_CLIENT &&
currentInstance &&
currentInstance.proxy &&
// avoid adding stores that are just built for hot module replacement
!hot) {
const vm = currentInstance.proxy;
const cache = '_pStores' in vm ? vm._pStores : (vm._pStores = {});
// @ts-expect-error: still can't cast Store with generics to Store
cache[store.$id] = store;
cache[id] = store;
}
// StoreGeneric cannot be casted towards Store
return store;
}
// needed by map helpers
useStore.$id = id;

@@ -1185,8 +1490,2 @@ return useStore;

function getCachedStore(vm, useStore) {
const cache = '_pStores' in vm ? vm._pStores : (vm._pStores = {});
const id = useStore.$id;
return (cache[id] ||
(cache[id] = useStore(vm.$pinia)));
}
let mapStoreSuffix = 'Store';

@@ -1239,3 +1538,3 @@ /**

reduced[useStore.$id + mapStoreSuffix] = function () {
return getCachedStore(this, useStore);
return useStore(this.$pinia);
};

@@ -1257,4 +1556,3 @@ return reduced;

reduced[key] = function () {
// @ts-expect-error
return getCachedStore(this, useStore)[key];
return useStore(this.$pinia)[key];
};

@@ -1264,4 +1562,5 @@ return reduced;

: Object.keys(keysOrMapper).reduce((reduced, key) => {
// @ts-expect-error
reduced[key] = function () {
const store = getCachedStore(this, useStore);
const store = useStore(this.$pinia);
const storeKey = keysOrMapper[key];

@@ -1295,4 +1594,3 @@ // for some reason TS is unable to infer the type of storeKey to be a

reduced[key] = function (...args) {
// @ts-expect-error
return getCachedStore(this, useStore)[key](...args);
return useStore(this.$pinia)[key](...args);
};

@@ -1304,4 +1602,3 @@ return reduced;

reduced[key] = function (...args) {
// @ts-expect-error
return getCachedStore(this, useStore)[keysOrMapper[key]](...args);
return useStore(this.$pinia)[keysOrMapper[key]](...args);
};

@@ -1325,9 +1622,7 @@ return reduced;

get() {
// @ts-expect-error
return getCachedStore(this, useStore)[key];
return useStore(this.$pinia)[key];
},
set(value) {
// it's easier to type it here as any
// @ts-expect-error
return (getCachedStore(this, useStore)[key] = value);
return (useStore(this.$pinia)[key] = value);
},

@@ -1341,10 +1636,7 @@ };

get() {
// @ts-expect-error
return getCachedStore(this, useStore)[keysOrMapper[key]];
return useStore(this.$pinia)[keysOrMapper[key]];
},
set(value) {
// it's easier to type it here as any
// @ts-expect-error
return (getCachedStore(this, useStore)[keysOrMapper[key]] =
value);
return (useStore(this.$pinia)[keysOrMapper[key]] = value);
},

@@ -1364,3 +1656,3 @@ };

*
* @internal - STILL NOT RELEASED, DO NOT USE. It will be likely moved to its
* @alpha - STILL NOT RELEASED, DO NOT USE. It will be likely moved to its
* own package.

@@ -1374,3 +1666,3 @@ *

plugins.forEach((plugin) => pinia.use(plugin));
// @ts-ignore
// @ts-ignore: this can fail in TS depending of the existence of jest
createSpy = createSpy || (typeof jest !== undefined && jest.fn);

@@ -1383,14 +1675,10 @@ if (!createSpy) {

pinia.use(({ store, options }) => {
if (!spiedActions.has(options.id)) {
spiedActions.set(options.id, {});
if (!spiedActions.has(store.$id)) {
spiedActions.set(store.$id, {});
}
const actionsCache = spiedActions.get(options.id);
const actionsCache = spiedActions.get(store.$id);
Object.keys(options.actions || {}).forEach((action) => {
actionsCache[action] =
actionsCache[action] ||
(stubActions
? createSpy()
: // @ts-expect-error:
createSpy(store[action]));
// @ts-expect-error:
(stubActions ? createSpy() : createSpy(store[action]));
store[action] = actionsCache[action];

@@ -1416,2 +1704,2 @@ });

export { MutationType, createPinia, createTestingPinia, defineStore, mapActions, mapGetters, mapState, mapStores, mapWritableState, setActivePinia, setMapStoreSuffix };
export { MutationType, acceptHMRUpdate, createPinia, createTestingPinia, defineStore, mapActions, mapGetters, mapState, mapStores, mapWritableState, setActivePinia, setMapStoreSuffix };
/*!
* pinia v2.0.0-beta.5
* pinia v2.0.0-rc.0
* (c) 2021 Eduardo San Martin Morote
* @license MIT
*/
import { warn, toRaw, ref, markRaw, getCurrentInstance, inject, provide, computed, reactive, watch, onUnmounted, isRef, isReactive, createApp } from 'vue';
import { warn, toRaw, markRaw, effectScope, ref, isRef, isReactive, getCurrentInstance, onUnmounted, inject, watch, toRef, reactive, computed, toRefs, createApp } from 'vue';
import { setupDevtoolsPlugin } from '@vue/devtools-api';

@@ -33,7 +33,2 @@

};
/**
* Map of stores based on a Pinia instance. Allows setting and retrieving stores
* for the current running application (with its pinia).
*/
const storesMap = new WeakMap();
const piniaSymbol = ((process.env.NODE_ENV !== 'production') ? Symbol('pinia') : /* istanbul ignore next */ Symbol());

@@ -422,3 +417,2 @@

key,
// @ts-expect-error
value: store.$state[key],

@@ -432,3 +426,2 @@ })),

key: getterName,
// @ts-expect-error
value: store[getterName],

@@ -441,3 +434,2 @@ }));

key,
// @ts-expect-error
value: store[key],

@@ -488,7 +480,2 @@ }));

/**
* Registered stores used for devtools.
*/
const registeredStores = /*#__PURE__*/ new Map();
let isAlreadyInstalled;
// timeline can be paused when directly changing the state

@@ -499,14 +486,17 @@ let isTimelineActive = true;

const INSPECTOR_ID = 'pinia';
function addDevtools(app, store) {
// TODO: we probably need to ensure the latest version of the store is kept:
// without effectScope, multiple stores will be created and will have a
// limited lifespan for getters.
// add a dev only variable that is removed in unmounted and replace the store
let hasSubscribed = true;
const storeType = '🍍 ' + store.$id;
if (!registeredStores.has(store.$id)) {
registeredStores.set(store.$id, store);
componentStateTypes.push(storeType);
hasSubscribed = false;
}
/**
* Gets the displayed name of a store in devtools
*
* @param id - id of the store
* @returns a formatted string
*/
const getStoreType = (id) => '🍍 ' + id;
/**
* Add the pinia plugin without any store. Allows displaying a Pinia plugin tab
* as soon as it is added to the application.
*
* @param app - Vue application
* @param pinia - pinia instance
*/
function registerPiniaDevtools(app, pinia) {
setupDevtoolsPlugin({

@@ -521,157 +511,161 @@ id: 'dev.esm.pinia',

}, (api) => {
if (!isAlreadyInstalled) {
api.addTimelineLayer({
id: MUTATIONS_LAYER_ID,
label: `Pinia 🍍`,
color: 0xe5df88,
});
api.addInspector({
id: INSPECTOR_ID,
label: 'Pinia 🍍',
icon: 'storage',
treeFilterPlaceholder: 'Search stores',
actions: [
{
icon: 'content_copy',
action: () => {
actionGlobalCopyState(store._p);
},
tooltip: 'Serialize and copy the state',
api.addTimelineLayer({
id: MUTATIONS_LAYER_ID,
label: `Pinia 🍍`,
color: 0xe5df88,
});
api.addInspector({
id: INSPECTOR_ID,
label: 'Pinia 🍍',
icon: 'storage',
treeFilterPlaceholder: 'Search stores',
actions: [
{
icon: 'content_copy',
action: () => {
actionGlobalCopyState(pinia);
},
{
icon: 'content_paste',
action: async () => {
await actionGlobalPasteState(store._p);
api.sendInspectorTree(INSPECTOR_ID);
api.sendInspectorState(INSPECTOR_ID);
},
tooltip: 'Replace the state with the content of your clipboard',
tooltip: 'Serialize and copy the state',
},
{
icon: 'content_paste',
action: async () => {
await actionGlobalPasteState(pinia);
api.sendInspectorTree(INSPECTOR_ID);
api.sendInspectorState(INSPECTOR_ID);
},
{
icon: 'save',
action: () => {
actionGlobalSaveState(store._p);
},
tooltip: 'Save the state as a JSON file',
tooltip: 'Replace the state with the content of your clipboard',
},
{
icon: 'save',
action: () => {
actionGlobalSaveState(pinia);
},
{
icon: 'folder_open',
action: async () => {
await actionGlobalOpenStateFile(store._p);
api.sendInspectorTree(INSPECTOR_ID);
api.sendInspectorState(INSPECTOR_ID);
},
tooltip: 'Import the state from a JSON file',
tooltip: 'Save the state as a JSON file',
},
{
icon: 'folder_open',
action: async () => {
await actionGlobalOpenStateFile(pinia);
api.sendInspectorTree(INSPECTOR_ID);
api.sendInspectorState(INSPECTOR_ID);
},
],
});
api.on.inspectComponent((payload, ctx) => {
const proxy = (payload.componentInstance &&
payload.componentInstance.proxy);
if (proxy && proxy._pStores) {
const piniaStores = payload.componentInstance.proxy._pStores;
Object.values(piniaStores).forEach((store) => {
tooltip: 'Import the state from a JSON file',
},
],
});
api.on.inspectComponent((payload, ctx) => {
const proxy = (payload.componentInstance &&
payload.componentInstance.proxy);
if (proxy && proxy._pStores) {
const piniaStores = payload.componentInstance.proxy._pStores;
Object.values(piniaStores).forEach((store) => {
payload.instanceData.state.push({
type: getStoreType(store.$id),
key: 'state',
editable: true,
value: store.$state,
});
if (store._getters && store._getters.length) {
payload.instanceData.state.push({
type: storeType,
key: 'state',
editable: true,
value: store.$state,
type: getStoreType(store.$id),
key: 'getters',
editable: false,
value: store._getters.reduce((getters, key) => {
getters[key] = store[key];
return getters;
}, {}),
});
if (store._getters && store._getters.length) {
payload.instanceData.state.push({
type: storeType,
key: 'getters',
editable: false,
value: store._getters.reduce((getters, key) => {
// @ts-expect-error
getters[key] = store[key];
return getters;
}, {}),
});
}
});
}
});
}
});
api.on.getInspectorTree((payload) => {
if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {
let stores = [pinia];
stores = stores.concat(Array.from(pinia._s.values()));
payload.rootNodes = (payload.filter
? stores.filter((store) => '$id' in store
? store.$id
.toLowerCase()
.includes(payload.filter.toLowerCase())
: PINIA_ROOT_LABEL.toLowerCase().includes(payload.filter.toLowerCase()))
: stores).map(formatStoreForInspectorTree);
}
});
api.on.getInspectorState((payload) => {
if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {
const inspectedStore = payload.nodeId === PINIA_ROOT_ID
? pinia
: pinia._s.get(payload.nodeId);
if (!inspectedStore) {
// this could be the selected store restored for a different project
// so it's better not to say anything here
return;
}
});
api.on.getInspectorTree((payload) => {
if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {
let stores = [store._p];
stores = stores.concat(Array.from(registeredStores.values()));
payload.rootNodes = (payload.filter
? stores.filter((store) => '$id' in store
? store.$id
.toLowerCase()
.includes(payload.filter.toLowerCase())
: PINIA_ROOT_LABEL.toLowerCase().includes(payload.filter.toLowerCase()))
: stores).map(formatStoreForInspectorTree);
if (inspectedStore) {
payload.state = formatStoreForInspectorState(inspectedStore);
}
});
api.on.getInspectorState((payload) => {
if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {
const inspectedStore = payload.nodeId === PINIA_ROOT_ID
? store._p
: registeredStores.get(payload.nodeId);
if (!inspectedStore) {
// this could be the selected store restored for a different project
// so it's better not to say anything here
return;
}
if (inspectedStore) {
payload.state = formatStoreForInspectorState(inspectedStore);
}
}
});
api.on.editInspectorState((payload, ctx) => {
if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {
const inspectedStore = payload.nodeId === PINIA_ROOT_ID
? pinia
: pinia._s.get(payload.nodeId);
if (!inspectedStore) {
return toastMessage(`store "${payload.nodeId}" not found`, 'error');
}
});
api.on.editInspectorState((payload, ctx) => {
if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {
const inspectedStore = payload.nodeId === PINIA_ROOT_ID
? store._p
: registeredStores.get(payload.nodeId);
if (!inspectedStore) {
return toastMessage(`store "${payload.nodeId}" not found`, 'error');
const { path } = payload;
if (!isPinia(inspectedStore)) {
// access only the state
if (path.length !== 1 ||
!inspectedStore._customProperties.has(path[0]) ||
path[0] in inspectedStore.$state) {
path.unshift('$state');
}
const { path } = payload;
if (!isPinia(store)) {
// access only the state
if (path.length !== 1 ||
!store._customProperties.has(path[0]) ||
path[0] in store.$state) {
path.unshift('$state');
}
}
else {
path.unshift('state', 'value');
}
isTimelineActive = false;
payload.set(inspectedStore, path, payload.state.value);
isTimelineActive = true;
}
});
api.on.editComponentState((payload) => {
if (payload.type.startsWith('🍍')) {
const storeId = payload.type.replace(/^🍍\s*/, '');
const store = registeredStores.get(storeId);
if (!store) {
return toastMessage(`store "${storeId}" not found`, 'error');
}
const { path } = payload;
if (path[0] !== 'state') {
return toastMessage(`Invalid path for store "${storeId}":\n${path}\nOnly state can be modified.`);
}
// rewrite the first entry to be able to directly set the state as
// well as any other path
path[0] = '$state';
isTimelineActive = false;
payload.set(store, path, payload.state.value);
isTimelineActive = true;
else {
path.unshift('state', 'value');
}
});
isAlreadyInstalled = true;
}
else {
api.sendInspectorTree(INSPECTOR_ID);
api.sendInspectorState(INSPECTOR_ID);
}
// avoid subscribing to mutations and actions twice
if (hasSubscribed)
return;
store.$onAction(({ after, onError, name, args, store }) => {
isTimelineActive = false;
payload.set(inspectedStore, path, payload.state.value);
isTimelineActive = true;
}
});
api.on.editComponentState((payload) => {
if (payload.type.startsWith('🍍')) {
const storeId = payload.type.replace(/^🍍\s*/, '');
const store = pinia._s.get(storeId);
if (!store) {
return toastMessage(`store "${storeId}" not found`, 'error');
}
const { path } = payload;
if (path[0] !== 'state') {
return toastMessage(`Invalid path for store "${storeId}":\n${path}\nOnly state can be modified.`);
}
// rewrite the first entry to be able to directly set the state as
// well as any other path
path[0] = '$state';
isTimelineActive = false;
payload.set(store, path, payload.state.value);
isTimelineActive = true;
}
});
});
}
function addStoreToDevtools(app, store) {
if (!componentStateTypes.includes(getStoreType(store.$id))) {
componentStateTypes.push(getStoreType(store.$id));
}
setupDevtoolsPlugin({
id: 'dev.esm.pinia',
label: 'Pinia 🍍',
logo: 'https://pinia.esm.dev/logo.svg',
packageName: 'pinia',
homepage: 'https://pinia.esm.dev',
componentStateTypes,
app,
}, (api) => {
store.$onAction(({ after, onError, name, args }) => {
const groupId = runningActionId++;

@@ -685,2 +679,3 @@ api.addTimelineEvent({

data: {
store: formatDisplay(store.$id),
action: formatDisplay(name),

@@ -693,2 +688,3 @@ args,

after((result) => {
activeAction = undefined;
api.addTimelineEvent({

@@ -701,2 +697,3 @@ layerId: MUTATIONS_LAYER_ID,

data: {
store: formatDisplay(store.$id),
action: formatDisplay(name),

@@ -711,2 +708,3 @@ args,

onError((error) => {
activeAction = undefined;
api.addTimelineEvent({

@@ -720,2 +718,3 @@ layerId: MUTATIONS_LAYER_ID,

data: {
store: formatDisplay(store.$id),
action: formatDisplay(name),

@@ -729,3 +728,3 @@ args,

});
});
}, true);
store.$subscribe(({ events, type }, state) => {

@@ -740,3 +739,6 @@ if (!isTimelineActive)

title: formatMutationType(type),
data: formatEventData(events),
data: {
store: formatDisplay(store.$id),
...formatEventData(events),
},
groupId: activeAction,

@@ -769,6 +771,23 @@ };

});
}, true);
const hotUpdate = store._hotUpdate;
store._hotUpdate = markRaw((newStore) => {
hotUpdate(newStore);
api.addTimelineEvent({
layerId: MUTATIONS_LAYER_ID,
event: {
time: Date.now(),
title: '🔥 ' + store.$id,
subtitle: 'HMR update',
data: {
store: formatDisplay(store.$id),
info: formatDisplay(`HMR update`),
},
},
});
});
// trigger an update so it can display new registered stores
// @ts-ignore
api.notifyComponentUpdate();
api.sendInspectorTree(INSPECTOR_ID);
api.sendInspectorState(INSPECTOR_ID);
toastMessage(`"${store.$id}" store installed`);

@@ -780,8 +799,10 @@ });

/**
* pinia.use(devtoolsPlugin)
* Patches a store to enable action grouping in devtools by wrapping the store with a Proxy that is passed as the context of all actions, allowing us to set `runningAction` on each access and effectively associating any state mutation to the action.
*
* @param store - store to patch
* @param actionNames - list of actionst to patch
*/
function devtoolsPlugin({ app, store, options, pinia }) {
function patchActionForGrouping(store, actionNames) {
// original actions of the store as they are given by pinia. We are going to override them
const actions = Object.keys(options.actions || {}).reduce((storeActions, actionName) => {
// @ts-expect-error
const actions = actionNames.reduce((storeActions, actionName) => {
// use toRaw to avoid tracking #541

@@ -792,5 +813,4 @@ storeActions[actionName] = toRaw(store)[actionName];

for (const actionName in actions) {
// @ts-expect-error
store[actionName] = function () {
setActivePinia(pinia);
// setActivePinia(store._p)
// the running action id is incremented in a before action hook

@@ -811,4 +831,26 @@ const _actionId = runningActionId;

}
addDevtools(app,
// @ts-expect-error: FIXME: if possible...
}
/**
* pinia.use(devtoolsPlugin)
*/
function devtoolsPlugin({ app, store, options }) {
// HMR module
if (store.$id.startsWith('__hot:')) {
return;
}
// only wrap actions in option-defined stores as this technique relies on
// wrapping the context of the action with a proxy
if ('id' in options) {
patchActionForGrouping(
// @ts-expect-error: can cast the store...
store, Object.keys(options.actions));
const originalHotUpdate = store._hotUpdate;
// Upgrade the HMR to also update the new actions
toRaw(store)._hotUpdate = function (newStore) {
originalHotUpdate.apply(this, arguments);
patchActionForGrouping(store, Object.keys(newStore._hmrPayload.actions));
};
}
addStoreToDevtools(app,
// FIXME: is there a way to allow the assignment from Store<Id, S, G, A> to StoreGeneric?
store);

@@ -821,6 +863,6 @@ }

function createPinia() {
const scope = effectScope(true);
// NOTE: here we could check the window object for a state and directly set it
// if there is anything like it with Vue 3 SSR
const state = ref({});
let localApp;
const state = scope.run(() => ref({}));
let _p = [];

@@ -831,3 +873,3 @@ // plugins added before calling app.use(pinia)

install(app) {
pinia._a = localApp = app;
pinia._a = app;
app.provide(piniaSymbol, pinia);

@@ -839,2 +881,5 @@ app.config.globalProperties.$pinia = pinia;

setActivePinia(pinia);
if ((process.env.NODE_ENV !== 'production')) {
registerPiniaDevtools(app, pinia);
}
}

@@ -844,3 +889,3 @@ toBeInstalled.forEach((plugin) => _p.push(plugin));

use(plugin) {
if (!localApp) {
if (!this._a) {
toBeInstalled.push(plugin);

@@ -855,3 +900,6 @@ }

// it's actually undefined here
_a: localApp,
// @ts-expect-error
_a: null,
_e: scope,
_s: new Map(),
state,

@@ -867,4 +915,110 @@ });

/**
* Checks if a function is a `StoreDefinition`
*
* @param fn - object to test
* @returns true if `fn` is a StoreDefinition
*/
const isUseStore = (fn) => {
return typeof fn === 'function' && typeof fn.$id === 'string';
};
/**
* Mutates in place `newState` with `oldState` to _hot update_ it. It will
* remove any key not existing in `newState` and recursively merge plain
* objects.
*
* @param newState - new state object to be patched
* @param oldState - old state that should be used to patch newState
* @returns - newState
*/
function patchObject(newState, oldState) {
// no need to go through symbols because they cannot be serialized anyway
for (const key in oldState) {
const subPatch = oldState[key];
// skip the whole sub tree
if (!(key in newState)) {
continue;
}
const targetValue = newState[key];
if (isPlainObject(targetValue) &&
isPlainObject(subPatch) &&
!isRef(subPatch) &&
!isReactive(subPatch)) {
newState[key] = patchObject(targetValue, subPatch);
}
else {
// objects are either a bit more complex (e.g. refs) or primitives, so we
// just set the whole thing
newState[key] = subPatch;
}
}
return newState;
}
/**
* Creates an _accept_ function to pass to `import.meta.hot` in Vite applications.
*
* @example
* ```js
* const useUser = defineStore(...)
* if (import.meta.hot) {
* import.meta.hot.accept(acceptHMRUpdate(useUser, import.meta.hot))
* }
* ```
*
* @param initialUseStore - return of the defineStore to hot update
* @param hot - `import.meta.hot`
*/
function acceptHMRUpdate(initialUseStore, hot) {
return (newModule) => {
const pinia = hot.data.pinia || initialUseStore._pinia;
if (!pinia) {
// this store is still not used
return;
}
// preserve the pinia instance across loads
hot.data.pinia = pinia;
// console.log('got data', newStore)
for (const exportName in newModule) {
const useStore = newModule[exportName];
// console.log('checking for', exportName)
if (isUseStore(useStore) && pinia._s.has(useStore.$id)) {
// console.log('Accepting update for', useStore.$id)
const id = useStore.$id;
if (id !== initialUseStore.$id) {
console.warn(`The id of the store changed from "${initialUseStore.$id}" to "${id}". Reloading.`);
// return import.meta.hot.invalidate()
return hot.invalidate();
}
const existingStore = pinia._s.get(id);
if (!existingStore) {
console.log(`skipping hmr because store doesn't exist yet`);
return;
}
useStore(pinia, existingStore);
}
}
};
}
function addSubscription(subscriptions, callback, detached) {
subscriptions.push(callback);
const removeSubscription = () => {
const idx = subscriptions.indexOf(callback);
if (idx > -1) {
subscriptions.splice(idx, 1);
}
};
if (!detached && getCurrentInstance()) {
onUnmounted(removeSubscription);
}
return removeSubscription;
}
function triggerSubscriptions(subscriptions, ...args) {
subscriptions.forEach((callback) => {
callback(...args);
});
}
function innerPatch(target, patchToApply) {
// TODO: get all keys like symbols as well
// no need to go through symbols because they cannot be serialized anyway
for (const key in patchToApply) {

@@ -887,36 +1041,98 @@ const subPatch = patchToApply[key];

const { assign } = Object;
/**
* Create an object of computed properties referring to
*
* @param rootStateRef - pinia.state
* @param id - unique name
*/
function computedFromState(rootStateRef, id) {
// let asComputed = computed<T>()
const reactiveObject = {};
const state = rootStateRef.value[id];
for (const key in state) {
// @ts-expect-error: the key matches
reactiveObject[key] = computed({
get: () => rootStateRef.value[id][key],
set: (value) => (rootStateRef.value[id][key] = value),
});
function isComputed(o) {
return o && o.effect;
}
function createOptionsStore(id, options, pinia, hot) {
const { state, actions, getters } = options;
function $reset() {
pinia.state.value[id] = state ? state() : {};
}
return reactiveObject;
const initialState = pinia.state.value[id];
let store;
function setup() {
if (!initialState && (!(process.env.NODE_ENV !== 'production') || !hot)) {
$reset();
}
// pinia.state.value[id] = state ? state() : {}
// avoid creating a state in pinia.state.value
const localState = (process.env.NODE_ENV !== 'production') && hot
? toRefs(ref(state ? state() : {}).value)
: initialState || toRefs(pinia.state.value[id]);
return assign(localState, actions, Object.keys(getters || {}).reduce((computedGetters, name) => {
computedGetters[name] = markRaw(computed(() => {
setActivePinia(pinia);
// const context = store || ref(localState).value
// @ts-expect-error
// return getters![name].call(context, context)
return store && getters[name].call(store, store);
}));
return computedGetters;
}, {}));
}
store = createSetupStore(id, setup, options, pinia, hot);
store.$reset = $reset;
return store;
}
/**
* Creates a store with its state object. This is meant to be augmented with getters and actions
*
* @param id - unique identifier of the store, like a name. eg: main, cart, user
* @param buildState - function to build the initial state
* @param initialState - initial state applied to the store, Must be correctly typed to infer typings
*/
function initStore($id, buildState = () => ({}), initialState) {
const pinia = getActivePinia();
pinia.state.value[$id] = initialState || buildState();
// const state: Ref<S> = toRef(_p.state.value, $id)
let isListening = true;
const noop = () => { };
function createSetupStore($id, setup, options = {}, pinia, hot) {
let scope;
const buildState = options.state;
const optionsForPlugin = {
actions: {},
...options,
};
// watcher options for $subscribe
const $subscribeOptions = { deep: true, flush: 'sync' };
/* istanbul ignore else */
if ((process.env.NODE_ENV !== 'production')) {
$subscribeOptions.onTrigger = (event) => {
if (isListening) {
debuggerEvents = event;
// avoid triggering this while the store is being built and the state is being set in pinia
}
else if (isListening == false && !store._hotUpdating) {
// let patch send all the events together later
/* istanbul ignore else */
if (Array.isArray(debuggerEvents)) {
debuggerEvents.push(event);
}
else {
console.error('🍍 debuggerEvents should be an array. This is most likely an internal Pinia bug.');
}
}
};
}
// internal state
let isListening; // set to true at the end
let subscriptions = markRaw([]);
let actionSubscriptions = markRaw([]);
let debuggerEvents;
const initialState = pinia.state.value[$id];
if (!initialState && (process.env.NODE_ENV !== 'production') && !hot) {
// should be set in Vue 2
pinia.state.value[$id] = {};
}
const hotState = ref({});
if ((process.env.NODE_ENV !== 'production') && !pinia._e.active) {
throw new Error('Pinia destroyed');
}
// TODO: idea create skipSerialize that marks properties as non serializable and they are skipped
const setupStore = pinia._e.run(() => {
scope = effectScope();
return scope.run(() => {
// skip setting up the watcher on HMR
if (!(process.env.NODE_ENV !== 'production') || !hot) {
watch(() => pinia.state.value[$id], (state, oldState) => {
if (isListening) {
triggerSubscriptions(subscriptions, {
storeId: $id,
type: MutationType.direct,
events: debuggerEvents,
}, state);
}
}, $subscribeOptions);
}
return setup();
});
});
function $patch(partialStateOrMutator) {

@@ -949,124 +1165,20 @@ let subscriptionMutation;

// because we paused the watcher, we need to manually call the subscriptions
subscriptions.forEach((callback) => {
callback(subscriptionMutation, pinia.state.value[$id]);
});
triggerSubscriptions(subscriptions, subscriptionMutation, pinia.state.value[$id]);
}
function $subscribe(callback) {
subscriptions.push(callback);
// watch here to link the subscription to the current active instance
// e.g. inside the setup of a component
const options = { deep: true, flush: 'sync' };
/* istanbul ignore else */
if ((process.env.NODE_ENV !== 'production')) {
options.onTrigger = (event) => {
if (isListening) {
debuggerEvents = event;
}
else {
// let patch send all the events together later
/* istanbul ignore else */
if (Array.isArray(debuggerEvents)) {
debuggerEvents.push(event);
}
else {
console.error('🍍 debuggerEvents should be an array. This is most likely an internal Pinia bug.');
}
}
};
const $reset = (process.env.NODE_ENV !== 'production')
? () => {
throw new Error(`🍍: Store "${$id}" is build using the setup syntax and does not implement $reset().`);
}
const stopWatcher = watch(() => pinia.state.value[$id], (state, oldState) => {
if (isListening) {
callback({
storeId: $id,
type: MutationType.direct,
events: debuggerEvents,
}, state);
}
}, options);
const removeSubscription = () => {
const idx = subscriptions.indexOf(callback);
if (idx > -1) {
subscriptions.splice(idx, 1);
stopWatcher();
}
};
if (getCurrentInstance()) {
onUnmounted(removeSubscription);
}
return removeSubscription;
}
function $onAction(callback) {
actionSubscriptions.push(callback);
const removeSubscription = () => {
const idx = actionSubscriptions.indexOf(callback);
if (idx > -1) {
actionSubscriptions.splice(idx, 1);
}
};
if (getCurrentInstance()) {
onUnmounted(removeSubscription);
}
return removeSubscription;
}
function $reset() {
pinia.state.value[$id] = buildState();
}
const storeWithState = {
$id,
_p: pinia,
_as: actionSubscriptions,
// $state is added underneath
$patch,
$subscribe,
$onAction,
$reset,
};
const injectionSymbol = (process.env.NODE_ENV !== 'production')
? Symbol(`PiniaStore(${$id})`)
: /* istanbul ignore next */
Symbol();
return [
storeWithState,
{
get: () => pinia.state.value[$id],
set: (newState) => {
isListening = false;
pinia.state.value[$id] = newState;
isListening = true;
},
},
injectionSymbol,
];
}
const noop = () => { };
/**
* Creates a store bound to the lifespan of where the function is called. This
* means creating the store inside of a component's setup will bound it to the
* lifespan of that component while creating it outside of a component will
* create an ever living store
*
* @param partialStore - store with state returned by initStore
* @param descriptor - descriptor to setup $state property
* @param $id - unique name of the store
* @param getters - getters of the store
* @param actions - actions of the store
*/
function buildStoreToUse(partialStore, descriptor, $id, getters = {}, actions = {}, options) {
const pinia = getActivePinia();
const computedGetters = {};
for (const getterName in getters) {
// @ts-ignore: it's only readonly for the users
computedGetters[getterName] = computed(() => {
: noop;
/**
* Wraps an action to handle subscriptions.
*
* @param name - name of the action
* @param action - action to wrap
* @returns a wrapped action to handle subscriptions
*/
function wrapAction(name, action) {
return function () {
setActivePinia(pinia);
// eslint-disable-next-line @typescript-eslint/no-use-before-define
// @ts-expect-error: the argument count is correct
return getters[getterName].call(store, store);
});
}
const wrappedActions = {};
for (const actionName in actions) {
wrappedActions[actionName] = function () {
setActivePinia(pinia);
const args = Array.from(arguments);
const localStore = this || store;
let afterCallback = noop;

@@ -1080,18 +1192,99 @@ let onErrorCallback = noop;

}
partialStore._as.forEach((callback) => {
// @ts-expect-error
callback({ args, name: actionName, store: localStore, after, onError });
// @ts-expect-error
triggerSubscriptions(actionSubscriptions, {
args,
name,
store,
after,
onError,
});
let ret;
try {
ret = actions[actionName].apply(localStore, args);
Promise.resolve(ret).then(afterCallback).catch(onErrorCallback);
ret = action.apply(this && this.$id === $id ? this : store, args);
// handle sync errors
}
catch (error) {
onErrorCallback(error);
throw error;
if (onErrorCallback(error) !== false) {
throw error;
}
}
return ret;
if (ret instanceof Promise) {
return ret
.then((value) => {
const newRet = afterCallback(value);
// allow the afterCallback to override the return value
return newRet === undefined ? value : newRet;
})
.catch((error) => {
if (onErrorCallback(error) !== false) {
return Promise.reject(error);
}
});
}
// allow the afterCallback to override the return value
const newRet = afterCallback(ret);
return newRet === undefined ? ret : newRet;
};
}
const _hmrPayload = /*#__PURE__*/ markRaw({
actions: {},
getters: {},
state: [],
hotState,
});
// overwrite existing actions to support $onAction
for (const key in setupStore) {
const prop = setupStore[key];
if ((isRef(prop) && !isComputed(prop)) || isReactive(prop)) {
// mark it as a piece of state to be serialized
if ((process.env.NODE_ENV !== 'production') && hot) {
hotState.value[key] = toRef(setupStore, key);
// createOptionStore already did this
}
else if (!buildState) {
pinia.state.value[$id][key] = prop;
// TODO: avoid if state exists for SSR
}
if ((process.env.NODE_ENV !== 'production')) {
_hmrPayload.state.push(key);
}
// action
}
else if (typeof prop === 'function') {
// @ts-expect-error: we are overriding the function we avoid wrapping if
// this a hot module replacement store because the hotUpdate method needs
// to do it with the right context
setupStore[key] = (process.env.NODE_ENV !== 'production') && hot ? prop : wrapAction(key, prop);
if ((process.env.NODE_ENV !== 'production')) {
_hmrPayload.actions[key] = prop;
}
// list actions so they can be used in plugins
// @ts-expect-error
optionsForPlugin.actions[key] = prop;
}
else if ((process.env.NODE_ENV !== 'production')) {
// add getters for devtools
if (isComputed(prop)) {
_hmrPayload.getters[key] = buildState
? // @ts-expect-error
options.getters[key]
: prop;
if (IS_CLIENT) {
const getters =
// @ts-expect-error: it should be on the store
setupStore._getters || (setupStore._getters = markRaw([]));
getters.push(key);
}
}
}
}
const partialStore = {
_p: pinia,
// _s: scope,
$id,
$onAction: addSubscription.bind(null, actionSubscriptions),
$patch,
$reset,
$subscribe: addSubscription.bind(null, subscriptions),
};
const store = reactive(assign((process.env.NODE_ENV !== 'production') && IS_CLIENT

@@ -1101,13 +1294,102 @@ ? // devtools custom properties

_customProperties: markRaw(new Set()),
_hmrPayload,
}
: {}, partialStore,
// using this means no new properties can be added as state
computedFromState(pinia.state, $id), computedGetters, wrappedActions));
: {}, partialStore, setupStore));
// use this instead of a computed with setter to be able to create it anywhere
// without linking the computed lifespan to wherever the store is first
// created.
Object.defineProperty(store, '$state', descriptor);
// add getters for devtools
if ((process.env.NODE_ENV !== 'production') && IS_CLIENT) {
store._getters = markRaw(Object.keys(getters));
Object.defineProperty(store, '$state', {
get: () => ((process.env.NODE_ENV !== 'production') && hot ? hotState.value : pinia.state.value[$id]),
set: (state) => {
if ((process.env.NODE_ENV !== 'production') && hot) {
throw new Error('cannot set hotState');
}
pinia.state.value[$id] = state;
},
});
// add the hotUpdate before plugins to allow them to override it
if ((process.env.NODE_ENV !== 'production')) {
store._hotUpdate = markRaw((newStore) => {
store._hotUpdating = true;
newStore._hmrPayload.state.forEach((stateKey) => {
if (stateKey in store.$state) {
const newStateTarget = newStore.$state[stateKey];
const oldStateSource = store.$state[stateKey];
if (typeof newStateTarget === 'object' &&
isPlainObject(newStateTarget) &&
isPlainObject(oldStateSource)) {
patchObject(newStateTarget, oldStateSource);
}
else {
// transfer the ref
newStore.$state[stateKey] = oldStateSource;
}
}
// patch direct access properties to allow store.stateProperty to work as
// store.$state.stateProperty
// @ts-expect-error
store[stateKey] = toRef(newStore.$state, stateKey);
});
// remove deleted state properties
Object.keys(store.$state).forEach((stateKey) => {
if (!(stateKey in newStore.$state)) {
delete store[stateKey];
}
});
// avoid devtools logging this as a mutation
isListening = false;
pinia.state.value[$id] = toRef(newStore._hmrPayload, 'hotState');
isListening = true;
for (const actionName in newStore._hmrPayload.actions) {
const action = newStore[actionName];
// @ts-expect-error: new key
store[actionName] =
// new line forced for TS
wrapAction(actionName, action);
}
// TODO: does this work in both setup and option store?
for (const getterName in newStore._hmrPayload.getters) {
const getter = newStore._hmrPayload.getters[getterName];
// @ts-expect-error
store[getterName] =
// ---
buildState
? // special handling of options api
computed(() => {
setActivePinia(pinia);
return getter.call(store, store);
})
: getter;
}
// remove deleted getters
Object.keys(store._hmrPayload.getters).forEach((key) => {
if (!(key in newStore._hmrPayload.getters)) {
delete store[key];
}
});
// remove old actions
Object.keys(store._hmrPayload.actions).forEach((key) => {
if (!(key in newStore._hmrPayload.actions)) {
delete store[key];
}
});
// update the values used in devtools and to allow deleting new properties later on
store._hmrPayload = newStore._hmrPayload;
store._getters = newStore._getters;
store._hotUpdating = false;
});
const nonEnumerable = {
writable: true,
configurable: true,
// avoid warning on devtools trying to display this property
enumerable: false,
};
if (IS_CLIENT) {
['_p', '_hmrPayload', '_getters', '_customProperties'].forEach((p) => {
Object.defineProperty(store, p, {
value: store[p],
...nonEnumerable,
});
});
}
}

@@ -1117,4 +1399,9 @@ // apply all plugins

if ((process.env.NODE_ENV !== 'production') && IS_CLIENT) {
// @ts-expect-error: conflict between A and ActionsTree
const extensions = extender({ store, app: pinia._a, pinia, options });
const extensions = extender({
store,
app: pinia._a,
pinia,
// @ts-expect-error
options: optionsForPlugin,
});
Object.keys(extensions || {}).forEach((key) => store._customProperties.add(key));

@@ -1124,19 +1411,34 @@ assign(store, extensions);

else {
// @ts-expect-error: conflict between A and ActionsTree
assign(store, extender({ store, app: pinia._a, pinia, options }));
assign(store, extender({
store,
app: pinia._a,
pinia,
// @ts-expect-error
options: optionsForPlugin,
}));
}
});
if (initialState) {
(options.hydrate || innerPatch)(store, initialState);
}
isListening = true;
return store;
}
/**
* Creates a `useStore` function that retrieves the store instance
* @param options - options to define the store
*/
function defineStore(options) {
const { id, state, getters, actions } = options;
function useStore(pinia) {
function defineStore(
// TODO: add proper types from above
idOrOptions, setup, setupOptions) {
let id;
let options;
const isSetupStore = typeof setup === 'function';
if (typeof idOrOptions === 'string') {
id = idOrOptions;
// the option store setup will contain the actual options in this case
options = isSetupStore ? setupOptions : setup;
}
else {
options = idOrOptions;
id = idOrOptions.id;
}
function useStore(pinia, hot) {
const currentInstance = getCurrentInstance();
// only run provide when pinia hasn't been manually passed
const shouldProvide = currentInstance && !pinia;
// avoid injecting if `useStore` when not possible
pinia =

@@ -1151,33 +1453,36 @@ // in test mode, ignore the argument provided as we can always retrieve a

pinia = getActivePinia();
let storeCache = storesMap.get(pinia);
if (!storeCache)
storesMap.set(pinia, (storeCache = new Map()));
let storeAndDescriptor = storeCache.get(id);
let store;
if (!storeAndDescriptor) {
storeAndDescriptor = initStore(id, state, pinia.state.value[id]);
// @ts-expect-error: annoying to type
storeCache.set(id, storeAndDescriptor);
store = buildStoreToUse(storeAndDescriptor[0], storeAndDescriptor[1], id, getters, actions, options);
// allow children to reuse this store instance to avoid creating a new
// store for each child
if (shouldProvide) {
provide(storeAndDescriptor[2], store);
if (!pinia._s.has(id)) {
pinia._s.set(id, isSetupStore
? createSetupStore(id, setup, options, pinia)
: createOptionsStore(id, options, pinia));
if ((process.env.NODE_ENV !== 'production')) {
// @ts-expect-error: not the right inferred type
useStore._pinia = pinia;
}
}
else {
store =
(currentInstance && inject(storeAndDescriptor[2], null)) ||
buildStoreToUse(storeAndDescriptor[0], storeAndDescriptor[1], id, getters, actions, options);
const store = pinia._s.get(id);
if ((process.env.NODE_ENV !== 'production') && hot) {
const hotId = '__hot:' + id;
const newStore = isSetupStore
? createSetupStore(hotId, setup, options, pinia, true)
: createOptionsStore(hotId, assign({}, options), pinia, true);
hot._hotUpdate(newStore);
// cleanup the state properties and the store from the cache
delete pinia.state.value[hotId];
pinia._s.delete(hotId);
}
// save stores in instances to access them devtools
if ((process.env.NODE_ENV !== 'production') && IS_CLIENT && currentInstance && currentInstance.proxy) {
if ((process.env.NODE_ENV !== 'production') &&
IS_CLIENT &&
currentInstance &&
currentInstance.proxy &&
// avoid adding stores that are just built for hot module replacement
!hot) {
const vm = currentInstance.proxy;
const cache = '_pStores' in vm ? vm._pStores : (vm._pStores = {});
// @ts-expect-error: still can't cast Store with generics to Store
cache[store.$id] = store;
cache[id] = store;
}
// StoreGeneric cannot be casted towards Store
return store;
}
// needed by map helpers
useStore.$id = id;

@@ -1187,8 +1492,2 @@ return useStore;

function getCachedStore(vm, useStore) {
const cache = '_pStores' in vm ? vm._pStores : (vm._pStores = {});
const id = useStore.$id;
return (cache[id] ||
(cache[id] = useStore(vm.$pinia)));
}
let mapStoreSuffix = 'Store';

@@ -1241,3 +1540,3 @@ /**

reduced[useStore.$id + mapStoreSuffix] = function () {
return getCachedStore(this, useStore);
return useStore(this.$pinia);
};

@@ -1259,4 +1558,3 @@ return reduced;

reduced[key] = function () {
// @ts-expect-error
return getCachedStore(this, useStore)[key];
return useStore(this.$pinia)[key];
};

@@ -1266,4 +1564,5 @@ return reduced;

: Object.keys(keysOrMapper).reduce((reduced, key) => {
// @ts-expect-error
reduced[key] = function () {
const store = getCachedStore(this, useStore);
const store = useStore(this.$pinia);
const storeKey = keysOrMapper[key];

@@ -1297,4 +1596,3 @@ // for some reason TS is unable to infer the type of storeKey to be a

reduced[key] = function (...args) {
// @ts-expect-error
return getCachedStore(this, useStore)[key](...args);
return useStore(this.$pinia)[key](...args);
};

@@ -1306,4 +1604,3 @@ return reduced;

reduced[key] = function (...args) {
// @ts-expect-error
return getCachedStore(this, useStore)[keysOrMapper[key]](...args);
return useStore(this.$pinia)[keysOrMapper[key]](...args);
};

@@ -1327,9 +1624,7 @@ return reduced;

get() {
// @ts-expect-error
return getCachedStore(this, useStore)[key];
return useStore(this.$pinia)[key];
},
set(value) {
// it's easier to type it here as any
// @ts-expect-error
return (getCachedStore(this, useStore)[key] = value);
return (useStore(this.$pinia)[key] = value);
},

@@ -1343,10 +1638,7 @@ };

get() {
// @ts-expect-error
return getCachedStore(this, useStore)[keysOrMapper[key]];
return useStore(this.$pinia)[keysOrMapper[key]];
},
set(value) {
// it's easier to type it here as any
// @ts-expect-error
return (getCachedStore(this, useStore)[keysOrMapper[key]] =
value);
return (useStore(this.$pinia)[keysOrMapper[key]] = value);
},

@@ -1366,3 +1658,3 @@ };

*
* @internal - STILL NOT RELEASED, DO NOT USE. It will be likely moved to its
* @alpha - STILL NOT RELEASED, DO NOT USE. It will be likely moved to its
* own package.

@@ -1376,3 +1668,3 @@ *

plugins.forEach((plugin) => pinia.use(plugin));
// @ts-ignore
// @ts-ignore: this can fail in TS depending of the existence of jest
createSpy = createSpy || (typeof jest !== undefined && jest.fn);

@@ -1385,14 +1677,10 @@ if (!createSpy) {

pinia.use(({ store, options }) => {
if (!spiedActions.has(options.id)) {
spiedActions.set(options.id, {});
if (!spiedActions.has(store.$id)) {
spiedActions.set(store.$id, {});
}
const actionsCache = spiedActions.get(options.id);
const actionsCache = spiedActions.get(store.$id);
Object.keys(options.actions || {}).forEach((action) => {
actionsCache[action] =
actionsCache[action] ||
(stubActions
? createSpy()
: // @ts-expect-error:
createSpy(store[action]));
// @ts-expect-error:
(stubActions ? createSpy() : createSpy(store[action]));
store[action] = actionsCache[action];

@@ -1418,2 +1706,2 @@ });

export { MutationType, createPinia, createTestingPinia, defineStore, mapActions, mapGetters, mapState, mapStores, mapWritableState, setActivePinia, setMapStoreSuffix };
export { MutationType, acceptHMRUpdate, createPinia, createTestingPinia, defineStore, mapActions, mapGetters, mapState, mapStores, mapWritableState, setActivePinia, setMapStoreSuffix };
/*!
* pinia v2.0.0-beta.5
* pinia v2.0.0-rc.0
* (c) 2021 Eduardo San Martin Morote
* @license MIT
*/
var Pinia=function(t,e){"use strict";let n;const r=t=>n=t,o=()=>n,c=new WeakMap,s=Symbol();function i(t){return t&&"object"==typeof t&&"[object Object]"===Object.prototype.toString.call(t)&&"function"!=typeof t.toJSON}var a;t.MutationType=void 0,(a=t.MutationType||(t.MutationType={})).direct="direct",a.patchObject="patch object",a.patchFunction="patch function";const u="undefined"!=typeof window;function p(){const t=e.ref({});let n,o=[];const c=[],i=e.markRaw({install(t){i._a=n=t,t.provide(s,i),t.config.globalProperties.$pinia=i,u&&r(i),c.forEach((t=>o.push(t)))},use(t){return n?o.push(t):c.push(t),this},_p:o,_a:n,state:t});return i}function f(t,n){for(const r in n){const o=n[r],c=t[r];t[r]=i(c)&&i(o)&&!e.isRef(o)&&!e.isReactive(o)?f(c,o):o}return t}const{assign:l}=Object;function h(n,r=(()=>({})),c){const s=o();s.state.value[n]=c||r();let i,a=!0,u=e.markRaw([]),p=e.markRaw([]);return[{$id:n,_p:s,_as:p,$patch:function(e){let r;a=!1,"function"==typeof e?(e(s.state.value[n]),r={type:t.MutationType.patchFunction,storeId:n,events:i}):(f(s.state.value[n],e),r={type:t.MutationType.patchObject,payload:e,storeId:n,events:i}),a=!0,u.forEach((t=>{t(r,s.state.value[n])}))},$subscribe:function(r){u.push(r);const o=e.watch((()=>s.state.value[n]),((e,o)=>{a&&r({storeId:n,type:t.MutationType.direct,events:i},e)}),{deep:!0,flush:"sync"}),c=()=>{const t=u.indexOf(r);t>-1&&(u.splice(t,1),o())};return e.getCurrentInstance()&&e.onUnmounted(c),c},$onAction:function(t){p.push(t);const n=()=>{const e=p.indexOf(t);e>-1&&p.splice(e,1)};return e.getCurrentInstance()&&e.onUnmounted(n),n},$reset:function(){s.state.value[n]=r()}},{get:()=>s.state.value[n],set:t=>{a=!1,s.state.value[n]=t,a=!0}},Symbol()]}const d=()=>{};function y(t,n,c,s={},i={},a){const u=o(),p={};for(const t in s)p[t]=e.computed((()=>(r(u),s[t].call(h,h))));const f={};for(const e in i)f[e]=function(){r(u);const n=Array.from(arguments),o=this||h;let c,s=d,a=d;function p(t){s=t}function f(t){a=t}t._as.forEach((t=>{t({args:n,name:e,store:o,after:p,onError:f})}));try{c=i[e].apply(o,n),Promise.resolve(c).then(s).catch(a)}catch(t){throw a(t),t}return c};const h=e.reactive(l({},t,function(t,n){const r={},o=t.value[n];for(const c in o)r[c]=e.computed({get:()=>t.value[n][c],set:e=>t.value[n][c]=e});return r}(u.state,c),p,f));return Object.defineProperty(h,"$state",n),u._p.forEach((t=>{l(h,t({store:h,app:u._a,pinia:u,options:a}))})),h}function v(t,e){const n="_pStores"in t?t._pStores:t._pStores={},r=e.$id;return n[r]||(n[r]=e(t.$pinia))}let b="Store";function g(t,e){return Array.isArray(e)?e.reduce(((e,n)=>(e[n]=function(){return v(this,t)[n]},e)),{}):Object.keys(e).reduce(((n,r)=>(n[r]=function(){const n=v(this,t),o=e[r];return"function"==typeof o?o.call(this,n):n[o]},n)),{})}const j=g;return t.createPinia=p,t.createTestingPinia=function({plugins:t=[],stubActions:n=!0,stubPatch:o=!1,fakeApp:c=!1,createSpy:s}={}){const i=p();if(t.forEach((t=>i.use(t))),!(s=s||void 0!==typeof jest&&jest.fn))throw new Error("You must configure the `createSpy` option.");const a=new Map;if(i.use((({store:t,options:e})=>{a.has(e.id)||a.set(e.id,{});const r=a.get(e.id);Object.keys(e.actions||{}).forEach((e=>{r[e]=r[e]||(n?s():s(t[e])),t[e]=r[e]})),t.$patch=o?s():s(t.$patch)})),c){e.createApp({}).use(i)}return i._testing=!0,r(i),Object.assign({resetSpyCache(){a.clear()},get app(){return this._a}},i)},t.defineStore=function(t){const{id:n,state:i,getters:a,actions:u}=t;function p(p){const f=e.getCurrentInstance(),l=f&&!p;(p=p||f&&e.inject(s))&&r(p),p=o();let d=c.get(p);d||c.set(p,d=new Map);let v,b=d.get(n);return b?v=f&&e.inject(b[2],null)||y(b[0],b[1],n,a,u,t):(b=h(n,i,p.state.value[n]),d.set(n,b),v=y(b[0],b[1],n,a,u,t),l&&e.provide(b[2],v)),v}return p.$id=n,p},t.mapActions=function(t,e){return Array.isArray(e)?e.reduce(((e,n)=>(e[n]=function(...e){return v(this,t)[n](...e)},e)),{}):Object.keys(e).reduce(((n,r)=>(n[r]=function(...n){return v(this,t)[e[r]](...n)},n)),{})},t.mapGetters=j,t.mapState=g,t.mapStores=function(...t){return t.reduce(((t,e)=>(t[e.$id+b]=function(){return v(this,e)},t)),{})},t.mapWritableState=function(t,e){return Array.isArray(e)?e.reduce(((e,n)=>(e[n]={get(){return v(this,t)[n]},set(e){return v(this,t)[n]=e}},e)),{}):Object.keys(e).reduce(((n,r)=>(n[r]={get(){return v(this,t)[e[r]]},set(n){return v(this,t)[e[r]]=n}},n)),{})},t.setActivePinia=r,t.setMapStoreSuffix=function(t){b=t},Object.defineProperty(t,"__esModule",{value:!0}),t}({},Vue);
var Pinia=function(t,e){"use strict";let n;const i=t=>n=t,r=Symbol();function o(t){return t&&"object"==typeof t&&"[object Object]"===Object.prototype.toString.call(t)&&"function"!=typeof t.toJSON}var c;t.MutationType=void 0,(c=t.MutationType||(t.MutationType={})).direct="direct",c.patchObject="patch object",c.patchFunction="patch function";const s="undefined"!=typeof window;function a(){const t=e.effectScope(!0),n=t.run((()=>e.ref({})));let o=[];const c=[],a=e.markRaw({install(t){a._a=t,t.provide(r,a),t.config.globalProperties.$pinia=a,s&&i(a),c.forEach((t=>o.push(t)))},use(t){return this._a?o.push(t):c.push(t),this},_p:o,_a:null,_e:t,_s:new Map,state:n});return a}function u(t,n,i){t.push(n);const r=()=>{const e=t.indexOf(n);e>-1&&t.splice(e,1)};return!i&&e.getCurrentInstance()&&e.onUnmounted(r),r}function f(t,...e){t.forEach((t=>{t(...e)}))}function p(t,n){for(const i in n){const r=n[i],c=t[i];t[i]=o(c)&&o(r)&&!e.isRef(r)&&!e.isReactive(r)?p(c,r):r}return t}const{assign:d}=Object;const h=()=>{};function l(n,r,o={},c,s){let a;const l=o.state,y={actions:{},...o},$={deep:!0,flush:"sync"};let v,b,g=e.markRaw([]),j=e.markRaw([]);const _=c.state.value[n];e.ref({});const m=c._e.run((()=>(a=e.effectScope(),a.run((()=>(e.watch((()=>c.state.value[n]),((e,i)=>{v&&f(g,{storeId:n,type:t.MutationType.direct,events:b},e)}),$),r()))))));const O=h;function S(t,e){return function(){i(c);const r=Array.from(arguments);let o,s=h,a=h;function u(t){s=t}function p(t){a=t}f(j,{args:r,name:t,store:k,after:u,onError:p});try{o=e.apply(this&&this.$id===n?this:k,r)}catch(t){if(!1!==a(t))throw t}if(o instanceof Promise)return o.then((t=>{const e=s(t);return void 0===e?t:e})).catch((t=>{if(!1!==a(t))return Promise.reject(t)}));const d=s(o);return void 0===d?o:d}}for(const t in m){const i=m[t];e.isRef(i)&&(!(w=i)||!w.effect)||e.isReactive(i)?l||(c.state.value[n][t]=i):"function"==typeof i&&(m[t]=S(t,i),y.actions[t]=i)}var w;const A={_p:c,$id:n,$onAction:u.bind(null,j),$patch:function(e){let i;v=!1,"function"==typeof e?(e(c.state.value[n]),i={type:t.MutationType.patchFunction,storeId:n,events:b}):(p(c.state.value[n],e),i={type:t.MutationType.patchObject,payload:e,storeId:n,events:b}),v=!0,f(g,i,c.state.value[n])},$reset:O,$subscribe:u.bind(null,g)},k=e.reactive(d({},A,m));return Object.defineProperty(k,"$state",{get:()=>c.state.value[n],set:t=>{c.state.value[n]=t}}),c._p.forEach((t=>{d(k,t({store:k,app:c._a,pinia:c,options:y}))})),_&&(o.hydrate||p)(k,_),v=!0,k}let y="Store";function $(t,e){return Array.isArray(e)?e.reduce(((e,n)=>(e[n]=function(){return t(this.$pinia)[n]},e)),{}):Object.keys(e).reduce(((n,i)=>(n[i]=function(){const n=t(this.$pinia),r=e[i];return"function"==typeof r?r.call(this,n):n[r]},n)),{})}const v=$;return t.acceptHMRUpdate=function(t,e){return n=>{const i=e.data.pinia||t._pinia;if(i){e.data.pinia=i;for(const o in n){const c=n[o];if("function"==typeof(r=c)&&"string"==typeof r.$id&&i._s.has(c.$id)){const n=c.$id;if(n!==t.$id)return console.warn(`The id of the store changed from "${t.$id}" to "${n}". Reloading.`),e.invalidate();const r=i._s.get(n);if(!r)return void console.log("skipping hmr because store doesn't exist yet");c(i,r)}}var r}}},t.createPinia=a,t.createTestingPinia=function({plugins:t=[],stubActions:n=!0,stubPatch:r=!1,fakeApp:o=!1,createSpy:c}={}){const s=a();if(t.forEach((t=>s.use(t))),!(c=c||void 0!==typeof jest&&jest.fn))throw new Error("You must configure the `createSpy` option.");const u=new Map;if(s.use((({store:t,options:e})=>{u.has(t.$id)||u.set(t.$id,{});const i=u.get(t.$id);Object.keys(e.actions||{}).forEach((e=>{i[e]=i[e]||(n?c():c(t[e])),t[e]=i[e]})),t.$patch=r?c():c(t.$patch)})),o){e.createApp({}).use(s)}return s._testing=!0,i(s),Object.assign({resetSpyCache(){u.clear()},get app(){return this._a}},s)},t.defineStore=function(t,o,c){let s,a;const u="function"==typeof o;function f(t,c){const f=e.getCurrentInstance();(t=t||f&&e.inject(r))&&i(t),(t=n)._s.has(s)||t._s.set(s,u?l(s,o,a,t):function(t,n,r,o){const{state:c,actions:s,getters:a}=n;function u(){r.state.value[t]=c?c():{}}const f=r.state.value[t];let p;return p=l(t,(function(){f||u();const n=f||e.toRefs(r.state.value[t]);return d(n,s,Object.keys(a||{}).reduce(((t,n)=>(t[n]=e.markRaw(e.computed((()=>(i(r),p&&a[n].call(p,p))))),t)),{}))}),n,r),p.$reset=u,p}(s,a,t));return t._s.get(s)}return"string"==typeof t?(s=t,a=u?c:o):(a=t,s=t.id),f.$id=s,f},t.mapActions=function(t,e){return Array.isArray(e)?e.reduce(((e,n)=>(e[n]=function(...e){return t(this.$pinia)[n](...e)},e)),{}):Object.keys(e).reduce(((n,i)=>(n[i]=function(...n){return t(this.$pinia)[e[i]](...n)},n)),{})},t.mapGetters=v,t.mapState=$,t.mapStores=function(...t){return t.reduce(((t,e)=>(t[e.$id+y]=function(){return e(this.$pinia)},t)),{})},t.mapWritableState=function(t,e){return Array.isArray(e)?e.reduce(((e,n)=>(e[n]={get(){return t(this.$pinia)[n]},set(e){return t(this.$pinia)[n]=e}},e)),{}):Object.keys(e).reduce(((n,i)=>(n[i]={get(){return t(this.$pinia)[e[i]]},set(n){return t(this.$pinia)[e[i]]=n}},n)),{})},t.setActivePinia=i,t.setMapStoreSuffix=function(t){y=t},Object.defineProperty(t,"__esModule",{value:!0}),t}({},Vue);
{
"name": "pinia",
"version": "2.0.0-beta.5",
"version": "2.0.0-rc.0",
"description": "Intuitive, type safe and flexible Store for Vue",

@@ -29,3 +29,3 @@ "main": "dist/pinia.cjs.js",

"build:dts": "api-extractor run --local --verbose",
"size": "rollup -c size-checks/rollup.config.js && node scripts/check-size.js",
"size": "rollup -c size-checks/rollup.config.js && node scripts/check-size.mjs",
"release": "bash scripts/release.sh",

@@ -39,2 +39,3 @@ "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 1",

"dev": "yarn run test:unit --watchAll",
"playground": "yarn vite",
"pretest": "yarn run lint",

@@ -67,28 +68,38 @@ "test": "yarn run test:types && yarn run test:unit && yarn run build && yarn run build:dts && yarn test:dts"

"devDependencies": {
"@microsoft/api-extractor": "7.18.0",
"@rollup/plugin-alias": "^3.1.2",
"@rollup/plugin-commonjs": "^19.0.0",
"@rollup/plugin-node-resolve": "^13.0.0",
"@rollup/plugin-replace": "^2.4.2",
"@microsoft/api-extractor": "7.18.4",
"@rollup/plugin-alias": "^3.1.4",
"@rollup/plugin-commonjs": "^19.0.1",
"@rollup/plugin-node-resolve": "^13.0.4",
"@rollup/plugin-replace": "^3.0.0",
"@sucrase/jest-plugin": "^2.1.0",
"@types/jest": "^26.0.24",
"@types/node": "^16.0.1",
"@vue/server-renderer": "^3.1.4",
"@vue/test-utils": "^2.0.0-rc.9",
"@vueuse/core": "^5.1.3",
"brotli": "^1.3.2",
"@types/lodash.kebabcase": "^4.1.6",
"@types/node": "^16.4.3",
"@vitejs/plugin-vue": "^1.2.4",
"@vue/compiler-sfc": "^3.2.0-beta.1",
"@vue/server-renderer": "^3.2.0-beta.1",
"@vue/test-utils": "^2.0.0-rc.10",
"@vueuse/core": "^5.2.0",
"brotli-wasm": "^1.1.0",
"codecov": "^3.8.2",
"conventional-changelog-cli": "^2.1.1",
"globby": "^12.0.0",
"jest": "^26.6.3",
"jest-mock-warn": "^1.1.0",
"lint-staged": "^11.0.0",
"lint-staged": "^11.1.1",
"lodash.kebabcase": "^4.1.1",
"mande": "^1.0.0",
"pascalcase": "^1.0.0",
"prettier": "^2.3.2",
"rimraf": "^3.0.2",
"rollup": "^2.52.8",
"rollup": "^2.54.0",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-typescript2": "^0.30.0",
"swrv": "^1.0.0-beta.8",
"typescript": "~4.3.5",
"vite": "^2.4.1",
"vitepress": "^0.15.6",
"vue": "^3.1.4",
"vue": "^3.2.0-beta.1",
"vue-promised": "^2.1.0",
"vue-router": "^4.0.10",
"yorkie": "^2.0.0"

@@ -100,3 +111,4 @@ },

"peerDependencies": {
"typescript": "^4.3.5"
"typescript": "^4.3.5",
"vue": "^3.2.0 || ^3.2.0-beta.4"
},

@@ -103,0 +115,0 @@ "peerDependenciesMeta": {

@@ -133,6 +133,5 @@ <p align="center">

export const useMainStore = defineStore({
// name of the store
// it is used in devtools and allows restoring state
id: 'main',
// main is the name of the store. It is unique across your application
// and will appear in devtools
export const useMainStore = defineStore('main', {
// a function that returns a fresh state

@@ -139,0 +138,0 @@ state: () => ({

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc