first commit
This commit is contained in:
+21
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 praz <https://codeberg.org/praz>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
# pinia-plugin-persistedstate
|
||||
|
||||
[![npm version][version-src]][version-href]
|
||||
[![bundle size][bundle-src]][bundle-href]
|
||||
[![license][license-src]][license-href]
|
||||
|
||||
> Configurable persistence and rehydration of Pinia stores.
|
||||
|
||||
[**_Read the full documentation_**](https://praz.codeberg.page/pinia-plugin-persistedstate)
|
||||
|
||||
## Features
|
||||
|
||||
- Persist Pinia stores with a friendly API inspired by [`vuex-persistedstate`](https://github.com/robinvdvleuten/vuex-persistedstate).
|
||||
- Highly customizable (storage, serializer, paths picking/omitting).
|
||||
- Out of the box SSR-friendly support for [`Nuxt`](#usage-with-nuxt).
|
||||
- Very smol (<2kB minzipped).
|
||||
|
||||
## Quickstart
|
||||
|
||||
1. Install with your favorite package manager:
|
||||
- **pnpm** : `pnpm add pinia-plugin-persistedstate`
|
||||
- npm : `npm i pinia-plugin-persistedstate`
|
||||
- yarn : `yarn add pinia-plugin-persistedstate`
|
||||
|
||||
2. Add the plugin to pinia:
|
||||
|
||||
```ts
|
||||
import { createPinia } from 'pinia'
|
||||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
|
||||
|
||||
const pinia = createPinia()
|
||||
pinia.use(piniaPluginPersistedstate)
|
||||
```
|
||||
|
||||
3. Add the `persist` option to the store you want to be persisted:
|
||||
|
||||
```ts
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export const useStore = defineStore('store', {
|
||||
state: () => ({
|
||||
someState: 'hello pinia',
|
||||
}),
|
||||
persist: true,
|
||||
})
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
You can configure how a store is persisted by specifying options to the `persist` property:
|
||||
|
||||
```ts
|
||||
export const useStore = defineStore('store', () => {
|
||||
const someState = ref('hello pinia')
|
||||
return { someState }
|
||||
}, {
|
||||
persist: {
|
||||
storage: sessionStorage,
|
||||
pick: ['someState'],
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
All the available configuration options are explained [here](https://praz.codeberg.page/pinia-plugin-persistedstate/guide/config).
|
||||
|
||||
## Usage with Nuxt
|
||||
|
||||
Nuxt support comes out of the box thanks to the included module. You just need to install the package and add the module to your `nuxt.config.ts` as follows:
|
||||
|
||||
```ts
|
||||
export default defineNuxtConfig({
|
||||
modules: [
|
||||
'@pinia/nuxt', // required
|
||||
'pinia-plugin-persistedstate/nuxt',
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
More information on storages and configuration in Nuxt [here](https://praz.codeberg.page/pinia-plugin-persistedstate/frameworks/nuxt).
|
||||
|
||||
## Limitations
|
||||
|
||||
There are several limitations that should be considered, more on those [here](https://praz.codeberg.page/pinia-plugin-persistedstate/guide/limitations).
|
||||
|
||||
## Contributing
|
||||
|
||||
See the [contribution guide](https://codeberg.org/praz/pinia-plugin-persistedstate/src/branch/main/CONTRIBUTING.md).
|
||||
|
||||
## License
|
||||
|
||||
[MIT](https://codeberg.org/praz/pinia-plugin-persistedstate/src/branch/main/LICENSE) © 2021-present [praz](https://codeberg.org/praz)
|
||||
|
||||
[version-src]: https://img.shields.io/npm/v/pinia-plugin-persistedstate?style=flat-square&labelColor=313244&color=cba6f7
|
||||
[version-href]: https://npmjs.com/package/pinia-plugin-persistedstate
|
||||
[bundle-src]: https://img.shields.io/bundlejs/size/pinia-plugin-persistedstate?style=flat-square&labelColor=313244&color=cba6f7
|
||||
[bundle-href]: https://bundlejs.com/?q=pinia-plugin-persistedstate
|
||||
[license-src]: https://img.shields.io/npm/l/pinia-plugin-persistedstate?style=flat-square&labelColor=313244&color=cba6f7
|
||||
[license-href]: https://codeberg.org/praz/pinia-plugin-persistedstate/src/branch/main/LICENSE
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
//#region src/runtime/utils.ts
|
||||
function get(obj, path) {
|
||||
if (obj == null) return void 0;
|
||||
let value = obj;
|
||||
for (let i = 0; i < path.length; i++) {
|
||||
if (value === void 0 || value[path[i]] === void 0) return void 0;
|
||||
if (value === null || value[path[i]] === null) return null;
|
||||
value = value[path[i]];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
function set(obj, value, path) {
|
||||
if (path.length === 0) return value;
|
||||
const idx = path[0];
|
||||
if (path.length > 1) value = set(typeof obj !== "object" || obj === null || !Object.prototype.hasOwnProperty.call(obj, idx) ? Number.isInteger(Number(path[1])) ? [] : {} : obj[idx], value, Array.prototype.slice.call(path, 1));
|
||||
if (Number.isInteger(Number(idx)) && Array.isArray(obj)) return obj.slice()[idx];
|
||||
return Object.assign({}, obj, { [idx]: value });
|
||||
}
|
||||
function unset(obj, path) {
|
||||
if (obj == null || path.length === 0) return obj;
|
||||
if (path.length === 1) {
|
||||
if (obj == null) return obj;
|
||||
if (Number.isInteger(path[0]) && Array.isArray(obj)) return Array.prototype.slice.call(obj, 0).splice(path[0], 1);
|
||||
const result = {};
|
||||
for (const p in obj) result[p] = obj[p];
|
||||
delete result[path[0]];
|
||||
return result;
|
||||
}
|
||||
if (obj[path[0]] == null) {
|
||||
if (Number.isInteger(path[0]) && Array.isArray(obj)) return Array.prototype.concat.call([], obj);
|
||||
const result = {};
|
||||
for (const p in obj) result[p] = obj[p];
|
||||
return result;
|
||||
}
|
||||
return set(obj, unset(obj[path[0]], Array.prototype.slice.call(path, 1)), [path[0]]);
|
||||
}
|
||||
function deepPick(obj, paths) {
|
||||
return paths.map((p) => p.split(".")).map((p) => [p, get(obj, p)]).filter((t) => t[1] !== void 0).reduce((acc, cur) => set(acc, cur[1], cur[0]), {});
|
||||
}
|
||||
function deepOmit(obj, paths) {
|
||||
return paths.map((p) => p.split(".")).reduce((acc, cur) => unset(acc, cur), obj);
|
||||
}
|
||||
|
||||
//#endregion
|
||||
//#region src/runtime/core.ts
|
||||
function hydrateStore(store, { storage, serializer, key, debug, pick, omit, beforeHydrate, afterHydrate }, context, runHooks = true) {
|
||||
try {
|
||||
if (runHooks) beforeHydrate?.(context);
|
||||
const fromStorage = storage.getItem(key);
|
||||
if (fromStorage) {
|
||||
const deserialized = serializer.deserialize(fromStorage);
|
||||
const picked = pick ? deepPick(deserialized, pick) : deserialized;
|
||||
const omitted = omit ? deepOmit(picked, omit) : picked;
|
||||
store.$patch(omitted);
|
||||
}
|
||||
if (runHooks) afterHydrate?.(context);
|
||||
} catch (error) {
|
||||
if (debug) console.error("[pinia-plugin-persistedstate]", error);
|
||||
}
|
||||
}
|
||||
function persistState(state, { storage, serializer, key, debug, pick, omit }) {
|
||||
try {
|
||||
const picked = pick ? deepPick(state, pick) : state;
|
||||
const omitted = omit ? deepOmit(picked, omit) : picked;
|
||||
const toStorage = serializer.serialize(omitted);
|
||||
storage.setItem(key, toStorage);
|
||||
} catch (error) {
|
||||
if (debug) console.error("[pinia-plugin-persistedstate]", error);
|
||||
}
|
||||
}
|
||||
function parsePersistKey(key, storeId) {
|
||||
return typeof key === "function" ? key(storeId) : typeof key === "string" ? key : storeId;
|
||||
}
|
||||
function createPersistence(context, optionsParser, auto) {
|
||||
const { pinia, store, options: { persist = auto } } = context;
|
||||
if (!persist) return;
|
||||
// v8 ignore if -- @preserve
|
||||
if (!(store.$id in pinia.state.value)) {
|
||||
const originalStore = pinia._s.get(store.$id.replace("__hot:", ""));
|
||||
if (originalStore) Promise.resolve().then(() => originalStore.$persist());
|
||||
return;
|
||||
}
|
||||
const persistences = (Array.isArray(persist) ? persist : persist === true ? [{}] : [persist]).map(optionsParser);
|
||||
store.$hydrate = ({ runHooks = true } = {}) => {
|
||||
persistences.forEach((p) => {
|
||||
hydrateStore(store, p, context, runHooks);
|
||||
});
|
||||
};
|
||||
store.$persist = () => {
|
||||
persistences.forEach((p) => {
|
||||
persistState(store.$state, p);
|
||||
});
|
||||
};
|
||||
persistences.forEach((p) => {
|
||||
hydrateStore(store, p, context);
|
||||
store.$subscribe((_mutation, state) => persistState(state, p), { detached: true });
|
||||
});
|
||||
}
|
||||
|
||||
//#endregion
|
||||
//#region src/index.ts
|
||||
/**
|
||||
* Create a Pinia persistence plugin.
|
||||
* @see https://codeberg.org/praz/pinia-plugin-persistedstate
|
||||
*/
|
||||
function createPersistedState(options = {}) {
|
||||
return function(context) {
|
||||
createPersistence(context, (p) => {
|
||||
const persistKey = parsePersistKey(p.key, context.store.$id);
|
||||
return {
|
||||
key: (options.key ? options.key : (x) => x)(persistKey),
|
||||
debug: p.debug ?? options.debug ?? false,
|
||||
serializer: p.serializer ?? options.serializer ?? {
|
||||
serialize: (data) => JSON.stringify(data),
|
||||
deserialize: (data) => JSON.parse(data)
|
||||
},
|
||||
storage: p.storage ?? options.storage ?? window.localStorage,
|
||||
beforeHydrate: p.beforeHydrate ?? options.beforeHydrate,
|
||||
afterHydrate: p.afterHydrate ?? options.afterHydrate,
|
||||
pick: p.pick,
|
||||
omit: p.omit
|
||||
};
|
||||
}, options.auto ?? false);
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Pinia plugin to persist stores.
|
||||
* @see https://codeberg.org/praz/pinia-plugin-persistedstate
|
||||
*/
|
||||
var src_default = createPersistedState();
|
||||
|
||||
//#endregion
|
||||
exports.createPersistedState = createPersistedState;
|
||||
exports.default = src_default;
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
import { PiniaPluginContext, StateTree } from "pinia";
|
||||
|
||||
//#region src/types.d.ts
|
||||
type IsAny<T> = unknown extends T ? ([keyof T] extends [never] ? false : true) : false;
|
||||
type ExcludeArrayKeys<T> = T extends ArrayLike<any> ? Exclude<keyof T, keyof any[]> : keyof T;
|
||||
type PathImpl<T, Key extends keyof T> = Key extends string ? IsAny<T[Key]> extends true ? never : T[Key] extends Record<string, any> ? `${Key}.${PathImpl<T[Key], ExcludeArrayKeys<T[Key]>> & string}` | `${Key}.${ExcludeArrayKeys<T[Key]> & string}` : never : never;
|
||||
type Path<T> = keyof T extends string ? (PathImpl<T, keyof T> | keyof T) extends infer P ? P extends string | keyof T ? P : keyof T : keyof T : never;
|
||||
/**
|
||||
* Synchronous storage based on Web Storage API.
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/Storage
|
||||
*/
|
||||
interface StorageLike {
|
||||
/**
|
||||
* Get a key's value if it exists.
|
||||
*/
|
||||
getItem: (key: string) => string | null;
|
||||
/**
|
||||
* Set a key with a value, or update it if it exists.
|
||||
*/
|
||||
setItem: (key: string, value: string) => void;
|
||||
}
|
||||
/**
|
||||
* Serializer implementation to stringify/parse state.
|
||||
*/
|
||||
interface Serializer {
|
||||
/**
|
||||
* Serialize state into string before storing.
|
||||
* @default JSON.stringify
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
|
||||
*/
|
||||
serialize: (data: StateTree) => string;
|
||||
/**
|
||||
* Deserializes string into state before hydrating.
|
||||
* @default JSON.parse
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse
|
||||
*/
|
||||
deserialize: (data: string) => StateTree;
|
||||
}
|
||||
interface Persistence<State extends StateTree = StateTree> {
|
||||
key: string;
|
||||
/**
|
||||
* Log errors in console.
|
||||
* @default false
|
||||
*/
|
||||
debug: boolean;
|
||||
/**
|
||||
* Synchronous storage to persist the state.
|
||||
*/
|
||||
storage: StorageLike;
|
||||
/**
|
||||
* Serializer to serialize/deserialize state into storage.
|
||||
*/
|
||||
serializer: Serializer;
|
||||
/**
|
||||
* Hook called before hydrating store.
|
||||
*/
|
||||
beforeHydrate?: (context: PiniaPluginContext) => void;
|
||||
/**
|
||||
* Hook called after hydrating store.
|
||||
*/
|
||||
afterHydrate?: (context: PiniaPluginContext) => void;
|
||||
/**
|
||||
* Dot-notation paths to pick from state before persisting.
|
||||
*/
|
||||
pick?: Path<State>[] | string[];
|
||||
/**
|
||||
* Dot-notation paths to omit from state before persisting.
|
||||
*/
|
||||
omit?: Path<State>[] | string[];
|
||||
}
|
||||
type PersistenceOptions<State extends StateTree = StateTree> = Partial<Omit<Persistence<State>, 'key'>> & {
|
||||
/**
|
||||
* Storage key to use.
|
||||
* @default $store.id
|
||||
*/
|
||||
key?: ((s: string) => string) | string;
|
||||
};
|
||||
type Persist<State extends StateTree = StateTree> = boolean | PersistenceOptions<State> | PersistenceOptions<State>[];
|
||||
declare module 'pinia' {
|
||||
interface DefineStoreOptionsBase<S extends StateTree, Store> {
|
||||
/**
|
||||
* Persist store in storage
|
||||
* @see https://codeberg.org/praz/pinia-plugin-persistedstate
|
||||
*/
|
||||
persist?: Persist<S>;
|
||||
}
|
||||
interface PiniaCustomProperties {
|
||||
/**
|
||||
* Hydrate store from configured storage
|
||||
* Warning: this is for advances usecases, make sure you know what you're doing
|
||||
*/
|
||||
$hydrate: (opts?: {
|
||||
runHooks?: boolean;
|
||||
}) => void;
|
||||
/**
|
||||
* Persist store into configured storage
|
||||
* Warning: this is for advances usecases, make sure you know what you're doing
|
||||
*/
|
||||
$persist: () => void;
|
||||
}
|
||||
}
|
||||
//#endregion
|
||||
//#region src/index.d.ts
|
||||
/**
|
||||
* Options passed to `createPersistedState` to apply globally.
|
||||
*/
|
||||
type PluginOptions = Pick<PersistenceOptions, 'storage' | 'debug' | 'serializer' | 'afterHydrate' | 'beforeHydrate'> & {
|
||||
/**
|
||||
* Global key generator, allow pre/postfixing store keys.
|
||||
*/
|
||||
key?: (storeKey: string) => string;
|
||||
/**
|
||||
* Automatically persist all stores with global defaults, opt-out individually.
|
||||
*/
|
||||
auto?: boolean;
|
||||
};
|
||||
/**
|
||||
* Create a Pinia persistence plugin.
|
||||
* @see https://codeberg.org/praz/pinia-plugin-persistedstate
|
||||
*/
|
||||
declare function createPersistedState(options?: PluginOptions): (context: PiniaPluginContext) => void;
|
||||
/**
|
||||
* Pinia plugin to persist stores.
|
||||
* @see https://codeberg.org/praz/pinia-plugin-persistedstate
|
||||
*/
|
||||
declare const _default: (context: PiniaPluginContext) => void;
|
||||
//#endregion
|
||||
export { type PersistenceOptions, PluginOptions, type Serializer, type StorageLike, createPersistedState, _default as default };
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
import { PiniaPluginContext, StateTree } from "pinia";
|
||||
|
||||
//#region src/types.d.ts
|
||||
type IsAny<T> = unknown extends T ? ([keyof T] extends [never] ? false : true) : false;
|
||||
type ExcludeArrayKeys<T> = T extends ArrayLike<any> ? Exclude<keyof T, keyof any[]> : keyof T;
|
||||
type PathImpl<T, Key extends keyof T> = Key extends string ? IsAny<T[Key]> extends true ? never : T[Key] extends Record<string, any> ? `${Key}.${PathImpl<T[Key], ExcludeArrayKeys<T[Key]>> & string}` | `${Key}.${ExcludeArrayKeys<T[Key]> & string}` : never : never;
|
||||
type Path<T> = keyof T extends string ? (PathImpl<T, keyof T> | keyof T) extends infer P ? P extends string | keyof T ? P : keyof T : keyof T : never;
|
||||
/**
|
||||
* Synchronous storage based on Web Storage API.
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/Storage
|
||||
*/
|
||||
interface StorageLike {
|
||||
/**
|
||||
* Get a key's value if it exists.
|
||||
*/
|
||||
getItem: (key: string) => string | null;
|
||||
/**
|
||||
* Set a key with a value, or update it if it exists.
|
||||
*/
|
||||
setItem: (key: string, value: string) => void;
|
||||
}
|
||||
/**
|
||||
* Serializer implementation to stringify/parse state.
|
||||
*/
|
||||
interface Serializer {
|
||||
/**
|
||||
* Serialize state into string before storing.
|
||||
* @default JSON.stringify
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
|
||||
*/
|
||||
serialize: (data: StateTree) => string;
|
||||
/**
|
||||
* Deserializes string into state before hydrating.
|
||||
* @default JSON.parse
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse
|
||||
*/
|
||||
deserialize: (data: string) => StateTree;
|
||||
}
|
||||
interface Persistence<State extends StateTree = StateTree> {
|
||||
key: string;
|
||||
/**
|
||||
* Log errors in console.
|
||||
* @default false
|
||||
*/
|
||||
debug: boolean;
|
||||
/**
|
||||
* Synchronous storage to persist the state.
|
||||
*/
|
||||
storage: StorageLike;
|
||||
/**
|
||||
* Serializer to serialize/deserialize state into storage.
|
||||
*/
|
||||
serializer: Serializer;
|
||||
/**
|
||||
* Hook called before hydrating store.
|
||||
*/
|
||||
beforeHydrate?: (context: PiniaPluginContext) => void;
|
||||
/**
|
||||
* Hook called after hydrating store.
|
||||
*/
|
||||
afterHydrate?: (context: PiniaPluginContext) => void;
|
||||
/**
|
||||
* Dot-notation paths to pick from state before persisting.
|
||||
*/
|
||||
pick?: Path<State>[] | string[];
|
||||
/**
|
||||
* Dot-notation paths to omit from state before persisting.
|
||||
*/
|
||||
omit?: Path<State>[] | string[];
|
||||
}
|
||||
type PersistenceOptions<State extends StateTree = StateTree> = Partial<Omit<Persistence<State>, 'key'>> & {
|
||||
/**
|
||||
* Storage key to use.
|
||||
* @default $store.id
|
||||
*/
|
||||
key?: ((s: string) => string) | string;
|
||||
};
|
||||
type Persist<State extends StateTree = StateTree> = boolean | PersistenceOptions<State> | PersistenceOptions<State>[];
|
||||
declare module 'pinia' {
|
||||
interface DefineStoreOptionsBase<S extends StateTree, Store> {
|
||||
/**
|
||||
* Persist store in storage
|
||||
* @see https://codeberg.org/praz/pinia-plugin-persistedstate
|
||||
*/
|
||||
persist?: Persist<S>;
|
||||
}
|
||||
interface PiniaCustomProperties {
|
||||
/**
|
||||
* Hydrate store from configured storage
|
||||
* Warning: this is for advances usecases, make sure you know what you're doing
|
||||
*/
|
||||
$hydrate: (opts?: {
|
||||
runHooks?: boolean;
|
||||
}) => void;
|
||||
/**
|
||||
* Persist store into configured storage
|
||||
* Warning: this is for advances usecases, make sure you know what you're doing
|
||||
*/
|
||||
$persist: () => void;
|
||||
}
|
||||
}
|
||||
//#endregion
|
||||
//#region src/index.d.ts
|
||||
/**
|
||||
* Options passed to `createPersistedState` to apply globally.
|
||||
*/
|
||||
type PluginOptions = Pick<PersistenceOptions, 'storage' | 'debug' | 'serializer' | 'afterHydrate' | 'beforeHydrate'> & {
|
||||
/**
|
||||
* Global key generator, allow pre/postfixing store keys.
|
||||
*/
|
||||
key?: (storeKey: string) => string;
|
||||
/**
|
||||
* Automatically persist all stores with global defaults, opt-out individually.
|
||||
*/
|
||||
auto?: boolean;
|
||||
};
|
||||
/**
|
||||
* Create a Pinia persistence plugin.
|
||||
* @see https://codeberg.org/praz/pinia-plugin-persistedstate
|
||||
*/
|
||||
declare function createPersistedState(options?: PluginOptions): (context: PiniaPluginContext) => void;
|
||||
/**
|
||||
* Pinia plugin to persist stores.
|
||||
* @see https://codeberg.org/praz/pinia-plugin-persistedstate
|
||||
*/
|
||||
declare const _default: (context: PiniaPluginContext) => void;
|
||||
//#endregion
|
||||
export { type PersistenceOptions, PluginOptions, type Serializer, type StorageLike, createPersistedState, _default as default };
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
var piniaPluginPersistedstate = (function(exports) {
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
//#region src/runtime/utils.ts
|
||||
function get(obj, path) {
|
||||
if (obj == null) return void 0;
|
||||
let value = obj;
|
||||
for (let i = 0; i < path.length; i++) {
|
||||
if (value === void 0 || value[path[i]] === void 0) return void 0;
|
||||
if (value === null || value[path[i]] === null) return null;
|
||||
value = value[path[i]];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
function set(obj, value, path) {
|
||||
if (path.length === 0) return value;
|
||||
const idx = path[0];
|
||||
if (path.length > 1) value = set(typeof obj !== "object" || obj === null || !Object.prototype.hasOwnProperty.call(obj, idx) ? Number.isInteger(Number(path[1])) ? [] : {} : obj[idx], value, Array.prototype.slice.call(path, 1));
|
||||
if (Number.isInteger(Number(idx)) && Array.isArray(obj)) return obj.slice()[idx];
|
||||
return Object.assign({}, obj, { [idx]: value });
|
||||
}
|
||||
function unset(obj, path) {
|
||||
if (obj == null || path.length === 0) return obj;
|
||||
if (path.length === 1) {
|
||||
if (obj == null) return obj;
|
||||
if (Number.isInteger(path[0]) && Array.isArray(obj)) return Array.prototype.slice.call(obj, 0).splice(path[0], 1);
|
||||
const result = {};
|
||||
for (const p in obj) result[p] = obj[p];
|
||||
delete result[path[0]];
|
||||
return result;
|
||||
}
|
||||
if (obj[path[0]] == null) {
|
||||
if (Number.isInteger(path[0]) && Array.isArray(obj)) return Array.prototype.concat.call([], obj);
|
||||
const result = {};
|
||||
for (const p in obj) result[p] = obj[p];
|
||||
return result;
|
||||
}
|
||||
return set(obj, unset(obj[path[0]], Array.prototype.slice.call(path, 1)), [path[0]]);
|
||||
}
|
||||
function deepPick(obj, paths) {
|
||||
return paths.map((p) => p.split(".")).map((p) => [p, get(obj, p)]).filter((t) => t[1] !== void 0).reduce((acc, cur) => set(acc, cur[1], cur[0]), {});
|
||||
}
|
||||
function deepOmit(obj, paths) {
|
||||
return paths.map((p) => p.split(".")).reduce((acc, cur) => unset(acc, cur), obj);
|
||||
}
|
||||
|
||||
//#endregion
|
||||
//#region src/runtime/core.ts
|
||||
function hydrateStore(store, { storage, serializer, key, debug, pick, omit, beforeHydrate, afterHydrate }, context, runHooks = true) {
|
||||
try {
|
||||
if (runHooks) beforeHydrate?.(context);
|
||||
const fromStorage = storage.getItem(key);
|
||||
if (fromStorage) {
|
||||
const deserialized = serializer.deserialize(fromStorage);
|
||||
const picked = pick ? deepPick(deserialized, pick) : deserialized;
|
||||
const omitted = omit ? deepOmit(picked, omit) : picked;
|
||||
store.$patch(omitted);
|
||||
}
|
||||
if (runHooks) afterHydrate?.(context);
|
||||
} catch (error) {
|
||||
if (debug) console.error("[pinia-plugin-persistedstate]", error);
|
||||
}
|
||||
}
|
||||
function persistState(state, { storage, serializer, key, debug, pick, omit }) {
|
||||
try {
|
||||
const picked = pick ? deepPick(state, pick) : state;
|
||||
const omitted = omit ? deepOmit(picked, omit) : picked;
|
||||
const toStorage = serializer.serialize(omitted);
|
||||
storage.setItem(key, toStorage);
|
||||
} catch (error) {
|
||||
if (debug) console.error("[pinia-plugin-persistedstate]", error);
|
||||
}
|
||||
}
|
||||
function parsePersistKey(key, storeId) {
|
||||
return typeof key === "function" ? key(storeId) : typeof key === "string" ? key : storeId;
|
||||
}
|
||||
function createPersistence(context, optionsParser, auto) {
|
||||
const { pinia, store, options: { persist = auto } } = context;
|
||||
if (!persist) return;
|
||||
// v8 ignore if -- @preserve
|
||||
if (!(store.$id in pinia.state.value)) {
|
||||
const originalStore = pinia._s.get(store.$id.replace("__hot:", ""));
|
||||
if (originalStore) Promise.resolve().then(() => originalStore.$persist());
|
||||
return;
|
||||
}
|
||||
const persistences = (Array.isArray(persist) ? persist : persist === true ? [{}] : [persist]).map(optionsParser);
|
||||
store.$hydrate = ({ runHooks = true } = {}) => {
|
||||
persistences.forEach((p) => {
|
||||
hydrateStore(store, p, context, runHooks);
|
||||
});
|
||||
};
|
||||
store.$persist = () => {
|
||||
persistences.forEach((p) => {
|
||||
persistState(store.$state, p);
|
||||
});
|
||||
};
|
||||
persistences.forEach((p) => {
|
||||
hydrateStore(store, p, context);
|
||||
store.$subscribe((_mutation, state) => persistState(state, p), { detached: true });
|
||||
});
|
||||
}
|
||||
|
||||
//#endregion
|
||||
//#region src/index.ts
|
||||
/**
|
||||
* Create a Pinia persistence plugin.
|
||||
* @see https://codeberg.org/praz/pinia-plugin-persistedstate
|
||||
*/
|
||||
function createPersistedState(options = {}) {
|
||||
return function(context) {
|
||||
createPersistence(context, (p) => {
|
||||
const persistKey = parsePersistKey(p.key, context.store.$id);
|
||||
return {
|
||||
key: (options.key ? options.key : (x) => x)(persistKey),
|
||||
debug: p.debug ?? options.debug ?? false,
|
||||
serializer: p.serializer ?? options.serializer ?? {
|
||||
serialize: (data) => JSON.stringify(data),
|
||||
deserialize: (data) => JSON.parse(data)
|
||||
},
|
||||
storage: p.storage ?? options.storage ?? window.localStorage,
|
||||
beforeHydrate: p.beforeHydrate ?? options.beforeHydrate,
|
||||
afterHydrate: p.afterHydrate ?? options.afterHydrate,
|
||||
pick: p.pick,
|
||||
omit: p.omit
|
||||
};
|
||||
}, options.auto ?? false);
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Pinia plugin to persist stores.
|
||||
* @see https://codeberg.org/praz/pinia-plugin-persistedstate
|
||||
*/
|
||||
var src_default = createPersistedState();
|
||||
|
||||
//#endregion
|
||||
exports.createPersistedState = createPersistedState;
|
||||
exports.default = src_default;
|
||||
return exports;
|
||||
})({});
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
//#region src/runtime/utils.ts
|
||||
function get(obj, path) {
|
||||
if (obj == null) return void 0;
|
||||
let value = obj;
|
||||
for (let i = 0; i < path.length; i++) {
|
||||
if (value === void 0 || value[path[i]] === void 0) return void 0;
|
||||
if (value === null || value[path[i]] === null) return null;
|
||||
value = value[path[i]];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
function set(obj, value, path) {
|
||||
if (path.length === 0) return value;
|
||||
const idx = path[0];
|
||||
if (path.length > 1) value = set(typeof obj !== "object" || obj === null || !Object.prototype.hasOwnProperty.call(obj, idx) ? Number.isInteger(Number(path[1])) ? [] : {} : obj[idx], value, Array.prototype.slice.call(path, 1));
|
||||
if (Number.isInteger(Number(idx)) && Array.isArray(obj)) return obj.slice()[idx];
|
||||
return Object.assign({}, obj, { [idx]: value });
|
||||
}
|
||||
function unset(obj, path) {
|
||||
if (obj == null || path.length === 0) return obj;
|
||||
if (path.length === 1) {
|
||||
if (obj == null) return obj;
|
||||
if (Number.isInteger(path[0]) && Array.isArray(obj)) return Array.prototype.slice.call(obj, 0).splice(path[0], 1);
|
||||
const result = {};
|
||||
for (const p in obj) result[p] = obj[p];
|
||||
delete result[path[0]];
|
||||
return result;
|
||||
}
|
||||
if (obj[path[0]] == null) {
|
||||
if (Number.isInteger(path[0]) && Array.isArray(obj)) return Array.prototype.concat.call([], obj);
|
||||
const result = {};
|
||||
for (const p in obj) result[p] = obj[p];
|
||||
return result;
|
||||
}
|
||||
return set(obj, unset(obj[path[0]], Array.prototype.slice.call(path, 1)), [path[0]]);
|
||||
}
|
||||
function deepPick(obj, paths) {
|
||||
return paths.map((p) => p.split(".")).map((p) => [p, get(obj, p)]).filter((t) => t[1] !== void 0).reduce((acc, cur) => set(acc, cur[1], cur[0]), {});
|
||||
}
|
||||
function deepOmit(obj, paths) {
|
||||
return paths.map((p) => p.split(".")).reduce((acc, cur) => unset(acc, cur), obj);
|
||||
}
|
||||
|
||||
//#endregion
|
||||
//#region src/runtime/core.ts
|
||||
function hydrateStore(store, { storage, serializer, key, debug, pick, omit, beforeHydrate, afterHydrate }, context, runHooks = true) {
|
||||
try {
|
||||
if (runHooks) beforeHydrate?.(context);
|
||||
const fromStorage = storage.getItem(key);
|
||||
if (fromStorage) {
|
||||
const deserialized = serializer.deserialize(fromStorage);
|
||||
const picked = pick ? deepPick(deserialized, pick) : deserialized;
|
||||
const omitted = omit ? deepOmit(picked, omit) : picked;
|
||||
store.$patch(omitted);
|
||||
}
|
||||
if (runHooks) afterHydrate?.(context);
|
||||
} catch (error) {
|
||||
if (debug) console.error("[pinia-plugin-persistedstate]", error);
|
||||
}
|
||||
}
|
||||
function persistState(state, { storage, serializer, key, debug, pick, omit }) {
|
||||
try {
|
||||
const picked = pick ? deepPick(state, pick) : state;
|
||||
const omitted = omit ? deepOmit(picked, omit) : picked;
|
||||
const toStorage = serializer.serialize(omitted);
|
||||
storage.setItem(key, toStorage);
|
||||
} catch (error) {
|
||||
if (debug) console.error("[pinia-plugin-persistedstate]", error);
|
||||
}
|
||||
}
|
||||
function parsePersistKey(key, storeId) {
|
||||
return typeof key === "function" ? key(storeId) : typeof key === "string" ? key : storeId;
|
||||
}
|
||||
function createPersistence(context, optionsParser, auto) {
|
||||
const { pinia, store, options: { persist = auto } } = context;
|
||||
if (!persist) return;
|
||||
// v8 ignore if -- @preserve
|
||||
if (!(store.$id in pinia.state.value)) {
|
||||
const originalStore = pinia._s.get(store.$id.replace("__hot:", ""));
|
||||
if (originalStore) Promise.resolve().then(() => originalStore.$persist());
|
||||
return;
|
||||
}
|
||||
const persistences = (Array.isArray(persist) ? persist : persist === true ? [{}] : [persist]).map(optionsParser);
|
||||
store.$hydrate = ({ runHooks = true } = {}) => {
|
||||
persistences.forEach((p) => {
|
||||
hydrateStore(store, p, context, runHooks);
|
||||
});
|
||||
};
|
||||
store.$persist = () => {
|
||||
persistences.forEach((p) => {
|
||||
persistState(store.$state, p);
|
||||
});
|
||||
};
|
||||
persistences.forEach((p) => {
|
||||
hydrateStore(store, p, context);
|
||||
store.$subscribe((_mutation, state) => persistState(state, p), { detached: true });
|
||||
});
|
||||
}
|
||||
|
||||
//#endregion
|
||||
//#region src/index.ts
|
||||
/**
|
||||
* Create a Pinia persistence plugin.
|
||||
* @see https://codeberg.org/praz/pinia-plugin-persistedstate
|
||||
*/
|
||||
function createPersistedState(options = {}) {
|
||||
return function(context) {
|
||||
createPersistence(context, (p) => {
|
||||
const persistKey = parsePersistKey(p.key, context.store.$id);
|
||||
return {
|
||||
key: (options.key ? options.key : (x) => x)(persistKey),
|
||||
debug: p.debug ?? options.debug ?? false,
|
||||
serializer: p.serializer ?? options.serializer ?? {
|
||||
serialize: (data) => JSON.stringify(data),
|
||||
deserialize: (data) => JSON.parse(data)
|
||||
},
|
||||
storage: p.storage ?? options.storage ?? window.localStorage,
|
||||
beforeHydrate: p.beforeHydrate ?? options.beforeHydrate,
|
||||
afterHydrate: p.afterHydrate ?? options.afterHydrate,
|
||||
pick: p.pick,
|
||||
omit: p.omit
|
||||
};
|
||||
}, options.auto ?? false);
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Pinia plugin to persist stores.
|
||||
* @see https://codeberg.org/praz/pinia-plugin-persistedstate
|
||||
*/
|
||||
var src_default = createPersistedState();
|
||||
|
||||
//#endregion
|
||||
export { createPersistedState, src_default as default };
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
(function(global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
||||
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
||||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.piniaPluginPersistedstate = {})));
|
||||
})(this, function(exports) {
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
//#region src/runtime/utils.ts
|
||||
function get(obj, path) {
|
||||
if (obj == null) return void 0;
|
||||
let value = obj;
|
||||
for (let i = 0; i < path.length; i++) {
|
||||
if (value === void 0 || value[path[i]] === void 0) return void 0;
|
||||
if (value === null || value[path[i]] === null) return null;
|
||||
value = value[path[i]];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
function set(obj, value, path) {
|
||||
if (path.length === 0) return value;
|
||||
const idx = path[0];
|
||||
if (path.length > 1) value = set(typeof obj !== "object" || obj === null || !Object.prototype.hasOwnProperty.call(obj, idx) ? Number.isInteger(Number(path[1])) ? [] : {} : obj[idx], value, Array.prototype.slice.call(path, 1));
|
||||
if (Number.isInteger(Number(idx)) && Array.isArray(obj)) return obj.slice()[idx];
|
||||
return Object.assign({}, obj, { [idx]: value });
|
||||
}
|
||||
function unset(obj, path) {
|
||||
if (obj == null || path.length === 0) return obj;
|
||||
if (path.length === 1) {
|
||||
if (obj == null) return obj;
|
||||
if (Number.isInteger(path[0]) && Array.isArray(obj)) return Array.prototype.slice.call(obj, 0).splice(path[0], 1);
|
||||
const result = {};
|
||||
for (const p in obj) result[p] = obj[p];
|
||||
delete result[path[0]];
|
||||
return result;
|
||||
}
|
||||
if (obj[path[0]] == null) {
|
||||
if (Number.isInteger(path[0]) && Array.isArray(obj)) return Array.prototype.concat.call([], obj);
|
||||
const result = {};
|
||||
for (const p in obj) result[p] = obj[p];
|
||||
return result;
|
||||
}
|
||||
return set(obj, unset(obj[path[0]], Array.prototype.slice.call(path, 1)), [path[0]]);
|
||||
}
|
||||
function deepPick(obj, paths) {
|
||||
return paths.map((p) => p.split(".")).map((p) => [p, get(obj, p)]).filter((t) => t[1] !== void 0).reduce((acc, cur) => set(acc, cur[1], cur[0]), {});
|
||||
}
|
||||
function deepOmit(obj, paths) {
|
||||
return paths.map((p) => p.split(".")).reduce((acc, cur) => unset(acc, cur), obj);
|
||||
}
|
||||
|
||||
//#endregion
|
||||
//#region src/runtime/core.ts
|
||||
function hydrateStore(store, { storage, serializer, key, debug, pick, omit, beforeHydrate, afterHydrate }, context, runHooks = true) {
|
||||
try {
|
||||
if (runHooks) beforeHydrate?.(context);
|
||||
const fromStorage = storage.getItem(key);
|
||||
if (fromStorage) {
|
||||
const deserialized = serializer.deserialize(fromStorage);
|
||||
const picked = pick ? deepPick(deserialized, pick) : deserialized;
|
||||
const omitted = omit ? deepOmit(picked, omit) : picked;
|
||||
store.$patch(omitted);
|
||||
}
|
||||
if (runHooks) afterHydrate?.(context);
|
||||
} catch (error) {
|
||||
if (debug) console.error("[pinia-plugin-persistedstate]", error);
|
||||
}
|
||||
}
|
||||
function persistState(state, { storage, serializer, key, debug, pick, omit }) {
|
||||
try {
|
||||
const picked = pick ? deepPick(state, pick) : state;
|
||||
const omitted = omit ? deepOmit(picked, omit) : picked;
|
||||
const toStorage = serializer.serialize(omitted);
|
||||
storage.setItem(key, toStorage);
|
||||
} catch (error) {
|
||||
if (debug) console.error("[pinia-plugin-persistedstate]", error);
|
||||
}
|
||||
}
|
||||
function parsePersistKey(key, storeId) {
|
||||
return typeof key === "function" ? key(storeId) : typeof key === "string" ? key : storeId;
|
||||
}
|
||||
function createPersistence(context, optionsParser, auto) {
|
||||
const { pinia, store, options: { persist = auto } } = context;
|
||||
if (!persist) return;
|
||||
// v8 ignore if -- @preserve
|
||||
if (!(store.$id in pinia.state.value)) {
|
||||
const originalStore = pinia._s.get(store.$id.replace("__hot:", ""));
|
||||
if (originalStore) Promise.resolve().then(() => originalStore.$persist());
|
||||
return;
|
||||
}
|
||||
const persistences = (Array.isArray(persist) ? persist : persist === true ? [{}] : [persist]).map(optionsParser);
|
||||
store.$hydrate = ({ runHooks = true } = {}) => {
|
||||
persistences.forEach((p) => {
|
||||
hydrateStore(store, p, context, runHooks);
|
||||
});
|
||||
};
|
||||
store.$persist = () => {
|
||||
persistences.forEach((p) => {
|
||||
persistState(store.$state, p);
|
||||
});
|
||||
};
|
||||
persistences.forEach((p) => {
|
||||
hydrateStore(store, p, context);
|
||||
store.$subscribe((_mutation, state) => persistState(state, p), { detached: true });
|
||||
});
|
||||
}
|
||||
|
||||
//#endregion
|
||||
//#region src/index.ts
|
||||
/**
|
||||
* Create a Pinia persistence plugin.
|
||||
* @see https://codeberg.org/praz/pinia-plugin-persistedstate
|
||||
*/
|
||||
function createPersistedState(options = {}) {
|
||||
return function(context) {
|
||||
createPersistence(context, (p) => {
|
||||
const persistKey = parsePersistKey(p.key, context.store.$id);
|
||||
return {
|
||||
key: (options.key ? options.key : (x) => x)(persistKey),
|
||||
debug: p.debug ?? options.debug ?? false,
|
||||
serializer: p.serializer ?? options.serializer ?? {
|
||||
serialize: (data) => JSON.stringify(data),
|
||||
deserialize: (data) => JSON.parse(data)
|
||||
},
|
||||
storage: p.storage ?? options.storage ?? window.localStorage,
|
||||
beforeHydrate: p.beforeHydrate ?? options.beforeHydrate,
|
||||
afterHydrate: p.afterHydrate ?? options.afterHydrate,
|
||||
pick: p.pick,
|
||||
omit: p.omit
|
||||
};
|
||||
}, options.auto ?? false);
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Pinia plugin to persist stores.
|
||||
* @see https://codeberg.org/praz/pinia-plugin-persistedstate
|
||||
*/
|
||||
var src_default = createPersistedState();
|
||||
|
||||
//#endregion
|
||||
exports.createPersistedState = createPersistedState;
|
||||
exports.default = src_default;
|
||||
});
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
import * as _nuxt_schema from '@nuxt/schema';
|
||||
import { CookiesStorageOptions } from '../dist/nuxt/runtime/storages.js';
|
||||
import { StateTree, PiniaPluginContext } from 'pinia';
|
||||
|
||||
type IsAny<T> = unknown extends T ? ([keyof T] extends [never] ? false : true) : false;
|
||||
type ExcludeArrayKeys<T> = T extends ArrayLike<any> ? Exclude<keyof T, keyof any[]> : keyof T;
|
||||
type PathImpl<T, Key extends keyof T> = Key extends string ? IsAny<T[Key]> extends true ? never : T[Key] extends Record<string, any> ? `${Key}.${PathImpl<T[Key], ExcludeArrayKeys<T[Key]>> & string}` | `${Key}.${ExcludeArrayKeys<T[Key]> & string}` : never : never;
|
||||
type Path<T> = keyof T extends string ? (PathImpl<T, keyof T> | keyof T) extends infer P ? P extends string | keyof T ? P : keyof T : keyof T : never;
|
||||
/**
|
||||
* Synchronous storage based on Web Storage API.
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/Storage
|
||||
*/
|
||||
interface StorageLike {
|
||||
/**
|
||||
* Get a key's value if it exists.
|
||||
*/
|
||||
getItem: (key: string) => string | null;
|
||||
/**
|
||||
* Set a key with a value, or update it if it exists.
|
||||
*/
|
||||
setItem: (key: string, value: string) => void;
|
||||
}
|
||||
/**
|
||||
* Serializer implementation to stringify/parse state.
|
||||
*/
|
||||
interface Serializer {
|
||||
/**
|
||||
* Serialize state into string before storing.
|
||||
* @default JSON.stringify
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
|
||||
*/
|
||||
serialize: (data: StateTree) => string;
|
||||
/**
|
||||
* Deserializes string into state before hydrating.
|
||||
* @default JSON.parse
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse
|
||||
*/
|
||||
deserialize: (data: string) => StateTree;
|
||||
}
|
||||
interface Persistence<State extends StateTree = StateTree> {
|
||||
key: string;
|
||||
/**
|
||||
* Log errors in console.
|
||||
* @default false
|
||||
*/
|
||||
debug: boolean;
|
||||
/**
|
||||
* Synchronous storage to persist the state.
|
||||
*/
|
||||
storage: StorageLike;
|
||||
/**
|
||||
* Serializer to serialize/deserialize state into storage.
|
||||
*/
|
||||
serializer: Serializer;
|
||||
/**
|
||||
* Hook called before hydrating store.
|
||||
*/
|
||||
beforeHydrate?: (context: PiniaPluginContext) => void;
|
||||
/**
|
||||
* Hook called after hydrating store.
|
||||
*/
|
||||
afterHydrate?: (context: PiniaPluginContext) => void;
|
||||
/**
|
||||
* Dot-notation paths to pick from state before persisting.
|
||||
*/
|
||||
pick?: Path<State>[] | string[];
|
||||
/**
|
||||
* Dot-notation paths to omit from state before persisting.
|
||||
*/
|
||||
omit?: Path<State>[] | string[];
|
||||
}
|
||||
type PersistenceOptions<State extends StateTree = StateTree> = Partial<Omit<Persistence<State>, 'key'>> & {
|
||||
/**
|
||||
* Storage key to use.
|
||||
* @default $store.id
|
||||
*/
|
||||
key?: ((s: string) => string) | string;
|
||||
};
|
||||
type Persist<State extends StateTree = StateTree> = boolean | PersistenceOptions<State> | PersistenceOptions<State>[];
|
||||
declare module 'pinia' {
|
||||
interface DefineStoreOptionsBase<S extends StateTree, Store> {
|
||||
/**
|
||||
* Persist store in storage
|
||||
* @see https://codeberg.org/praz/pinia-plugin-persistedstate
|
||||
*/
|
||||
persist?: Persist<S>;
|
||||
}
|
||||
interface PiniaCustomProperties {
|
||||
/**
|
||||
* Hydrate store from configured storage
|
||||
* Warning: this is for advances usecases, make sure you know what you're doing
|
||||
*/
|
||||
$hydrate: (opts?: {
|
||||
runHooks?: boolean;
|
||||
}) => void;
|
||||
/**
|
||||
* Persist store into configured storage
|
||||
* Warning: this is for advances usecases, make sure you know what you're doing
|
||||
*/
|
||||
$persist: () => void;
|
||||
}
|
||||
}
|
||||
|
||||
type ModuleOptions = Pick<PersistenceOptions, 'debug'> & {
|
||||
/**
|
||||
* Default storage for persistence. Only accepts presets.
|
||||
*/
|
||||
storage?: 'cookies' | 'localStorage' | 'sessionStorage';
|
||||
/**
|
||||
* Global key template, allow pre/postfixing store keys.
|
||||
* @example 'my-%id-persistence' will yield 'my-<store-id>-persistence'
|
||||
*/
|
||||
key?: `${string}%id${string}`;
|
||||
/**
|
||||
* Options used globally by default cookie storage.
|
||||
* Ignored for other storages.
|
||||
*/
|
||||
cookieOptions?: Omit<CookiesStorageOptions, 'encode' | 'decode'>;
|
||||
/**
|
||||
* Automatically persist all stores with global defaults, opt-out individually.
|
||||
*/
|
||||
auto?: boolean;
|
||||
};
|
||||
declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
|
||||
|
||||
declare module '@nuxt/schema' {
|
||||
interface PublicRuntimeConfig {
|
||||
piniaPluginPersistedstate: ModuleOptions;
|
||||
}
|
||||
}
|
||||
|
||||
export { _default as default };
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "pinia-plugin-persistedstate",
|
||||
"configKey": "piniaPluginPersistedstate",
|
||||
"compatibility": {
|
||||
"nuxt": ">=3.0.0"
|
||||
},
|
||||
"version": "4.7.1",
|
||||
"builder": {
|
||||
"@nuxt/module-builder": "1.0.2",
|
||||
"unbuild": "3.6.0"
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
import { defineNuxtModule, createResolver, useLogger, hasNuxtModule, addImports, addPlugin } from '@nuxt/kit';
|
||||
import { defu } from 'defu';
|
||||
|
||||
const module = defineNuxtModule({
|
||||
meta: {
|
||||
name: "pinia-plugin-persistedstate",
|
||||
configKey: "piniaPluginPersistedstate",
|
||||
compatibility: {
|
||||
nuxt: ">=3.0.0"
|
||||
}
|
||||
},
|
||||
defaults: {},
|
||||
setup(options, nuxt) {
|
||||
const resolver = createResolver(import.meta.url);
|
||||
const logger = useLogger();
|
||||
if (!hasNuxtModule("pinia", nuxt)) {
|
||||
logger.warn("The `@pinia/nuxt` module was not found, `pinia-plugin-persistedstate/nuxt` will not work.");
|
||||
return;
|
||||
}
|
||||
nuxt.options.build.transpile.push(resolver.resolve("./runtime"));
|
||||
nuxt.options.runtimeConfig.public.piniaPluginPersistedstate = defu(nuxt.options.runtimeConfig.public.piniaPluginPersistedstate, options);
|
||||
addImports({
|
||||
name: "storages",
|
||||
from: resolver.resolve("./runtime/storages"),
|
||||
as: "piniaPluginPersistedstate"
|
||||
});
|
||||
addPlugin(resolver.resolve("./runtime/plugin"));
|
||||
}
|
||||
});
|
||||
|
||||
export { module as default };
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { PiniaPluginContext } from 'pinia';
|
||||
import type { Persistence, PersistenceOptions } from '../types.js';
|
||||
export declare function parsePersistKey(key: PersistenceOptions['key'], storeId: string): string;
|
||||
export declare function createPersistence(context: PiniaPluginContext, optionsParser: (p: PersistenceOptions) => Persistence, auto: boolean): void;
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
import { deepOmit, deepPick } from "./utils.js";
|
||||
function hydrateStore(store, {
|
||||
storage,
|
||||
serializer,
|
||||
key,
|
||||
debug,
|
||||
pick,
|
||||
omit,
|
||||
beforeHydrate,
|
||||
afterHydrate
|
||||
}, context, runHooks = true) {
|
||||
try {
|
||||
if (runHooks)
|
||||
beforeHydrate?.(context);
|
||||
const fromStorage = storage.getItem(key);
|
||||
if (fromStorage) {
|
||||
const deserialized = serializer.deserialize(fromStorage);
|
||||
const picked = pick ? deepPick(deserialized, pick) : deserialized;
|
||||
const omitted = omit ? deepOmit(picked, omit) : picked;
|
||||
store.$patch(omitted);
|
||||
}
|
||||
if (runHooks)
|
||||
afterHydrate?.(context);
|
||||
} catch (error) {
|
||||
if (debug)
|
||||
console.error("[pinia-plugin-persistedstate]", error);
|
||||
}
|
||||
}
|
||||
function persistState(state, {
|
||||
storage,
|
||||
serializer,
|
||||
key,
|
||||
debug,
|
||||
pick,
|
||||
omit
|
||||
}) {
|
||||
try {
|
||||
const picked = pick ? deepPick(state, pick) : state;
|
||||
const omitted = omit ? deepOmit(picked, omit) : picked;
|
||||
const toStorage = serializer.serialize(omitted);
|
||||
storage.setItem(key, toStorage);
|
||||
} catch (error) {
|
||||
if (debug)
|
||||
console.error("[pinia-plugin-persistedstate]", error);
|
||||
}
|
||||
}
|
||||
export function parsePersistKey(key, storeId) {
|
||||
return typeof key === "function" ? key(storeId) : typeof key === "string" ? key : storeId;
|
||||
}
|
||||
export function createPersistence(context, optionsParser, auto) {
|
||||
const { pinia, store, options: { persist = auto } } = context;
|
||||
if (!persist)
|
||||
return;
|
||||
// v8 ignore if -- @preserve
|
||||
if (!(store.$id in pinia.state.value)) {
|
||||
const originalStore = pinia._s.get(store.$id.replace("__hot:", ""));
|
||||
if (originalStore)
|
||||
void Promise.resolve().then(() => originalStore.$persist());
|
||||
return;
|
||||
}
|
||||
const persistenceOptions = Array.isArray(persist) ? persist : persist === true ? [{}] : [persist];
|
||||
const persistences = persistenceOptions.map(optionsParser);
|
||||
store.$hydrate = ({ runHooks = true } = {}) => {
|
||||
persistences.forEach((p) => {
|
||||
hydrateStore(store, p, context, runHooks);
|
||||
});
|
||||
};
|
||||
store.$persist = () => {
|
||||
persistences.forEach((p) => {
|
||||
persistState(store.$state, p);
|
||||
});
|
||||
};
|
||||
persistences.forEach((p) => {
|
||||
hydrateStore(store, p, context);
|
||||
store.$subscribe(
|
||||
(_mutation, state) => persistState(state, p),
|
||||
{ detached: true }
|
||||
);
|
||||
});
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
declare const _default: import("nuxt/app").Plugin<Record<string, unknown>> & import("nuxt/app").ObjectPlugin<Record<string, unknown>>;
|
||||
export default _default;
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
import { defineNuxtPlugin, useRuntimeConfig } from "#app";
|
||||
import { createPersistence, parsePersistKey } from "./core.js";
|
||||
import { storages } from "./storages.js";
|
||||
function piniaPlugin(context) {
|
||||
const config = useRuntimeConfig();
|
||||
const options = config.public.piniaPluginPersistedstate;
|
||||
createPersistence(
|
||||
context,
|
||||
(p) => {
|
||||
const persistKey = parsePersistKey(p.key, context.store.$id);
|
||||
return {
|
||||
key: options.key ? options.key.replace(/%id/g, persistKey) : persistKey,
|
||||
debug: p.debug ?? options.debug ?? false,
|
||||
serializer: p.serializer ?? {
|
||||
serialize: (data) => JSON.stringify(data),
|
||||
deserialize: (data) => JSON.parse(data)
|
||||
},
|
||||
storage: p.storage ?? (options.storage ? options.storage === "cookies" ? storages.cookies(options.cookieOptions) : storages[options.storage]() : storages.cookies()),
|
||||
beforeHydrate: p.beforeHydrate,
|
||||
afterHydrate: p.afterHydrate,
|
||||
pick: p.pick,
|
||||
omit: p.omit
|
||||
};
|
||||
},
|
||||
options.auto ?? false
|
||||
);
|
||||
}
|
||||
export default defineNuxtPlugin({
|
||||
name: "pinia-plugin-persistedstate",
|
||||
setup({ $pinia }) {
|
||||
$pinia.use(piniaPlugin);
|
||||
}
|
||||
});
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
import type { CookieOptions } from '#app';
|
||||
import type { StorageLike } from '../types.js';
|
||||
export type CookiesStorageOptions = Omit<CookieOptions, 'default' | 'watch' | 'readonly' | 'filter'>;
|
||||
/**
|
||||
* Cookie-based storage. Cookie options can be passed as parameter.
|
||||
* Uses Nuxt's `useCookie` under the hood.
|
||||
*/
|
||||
declare function cookies(options?: CookiesStorageOptions): StorageLike;
|
||||
/**
|
||||
* LocalStorage-based storage.
|
||||
* Warning: only works client-side.
|
||||
*/
|
||||
declare function localStorage(): StorageLike;
|
||||
/**
|
||||
* SessionStorage-based storage.
|
||||
* Warning: only works client-side.
|
||||
*/
|
||||
declare function sessionStorage(): StorageLike;
|
||||
export declare const storages: {
|
||||
cookies: typeof cookies;
|
||||
localStorage: typeof localStorage;
|
||||
sessionStorage: typeof sessionStorage;
|
||||
};
|
||||
export {};
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
import { useCookie, useRuntimeConfig } from "#app";
|
||||
function cookies(options) {
|
||||
return {
|
||||
getItem: (key) => useCookie(
|
||||
key,
|
||||
{
|
||||
...options ?? useRuntimeConfig().public.piniaPluginPersistedstate.cookieOptions ?? {},
|
||||
decode: options?.decode ?? decodeURIComponent,
|
||||
readonly: true
|
||||
}
|
||||
).value,
|
||||
setItem: (key, value) => useCookie(
|
||||
key,
|
||||
{
|
||||
...options ?? useRuntimeConfig().public.piniaPluginPersistedstate.cookieOptions ?? {},
|
||||
encode: options?.encode ?? encodeURIComponent
|
||||
}
|
||||
).value = value
|
||||
};
|
||||
}
|
||||
function localStorage() {
|
||||
return {
|
||||
getItem: (key) => import.meta.client ? window.localStorage.getItem(key) : null,
|
||||
setItem: (key, value) => import.meta.client ? window.localStorage.setItem(key, value) : null
|
||||
};
|
||||
}
|
||||
function sessionStorage() {
|
||||
return {
|
||||
getItem: (key) => import.meta.client ? window.sessionStorage.getItem(key) : null,
|
||||
setItem: (key, value) => import.meta.client ? window.sessionStorage.setItem(key, value) : null
|
||||
};
|
||||
}
|
||||
export const storages = {
|
||||
cookies,
|
||||
localStorage,
|
||||
sessionStorage
|
||||
};
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
export declare function deepPick(obj: object, paths: Array<string>): {};
|
||||
export declare function deepOmit(obj: object, paths: Array<string>): object;
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
function get(obj, path) {
|
||||
if (obj == null)
|
||||
return void 0;
|
||||
let value = obj;
|
||||
for (let i = 0; i < path.length; i++) {
|
||||
if (value === void 0 || value[path[i]] === void 0)
|
||||
return void 0;
|
||||
if (value === null || value[path[i]] === null)
|
||||
return null;
|
||||
value = value[path[i]];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
function set(obj, value, path) {
|
||||
if (path.length === 0)
|
||||
return value;
|
||||
const idx = path[0];
|
||||
if (path.length > 1) {
|
||||
value = set(
|
||||
typeof obj !== "object" || obj === null || !Object.prototype.hasOwnProperty.call(obj, idx) ? Number.isInteger(Number(path[1])) ? [] : {} : obj[idx],
|
||||
value,
|
||||
Array.prototype.slice.call(path, 1)
|
||||
);
|
||||
}
|
||||
if (Number.isInteger(Number(idx)) && Array.isArray(obj))
|
||||
return obj.slice()[idx];
|
||||
return Object.assign({}, obj, { [idx]: value });
|
||||
}
|
||||
function unset(obj, path) {
|
||||
if (obj == null || path.length === 0)
|
||||
return obj;
|
||||
if (path.length === 1) {
|
||||
if (obj == null)
|
||||
return obj;
|
||||
if (Number.isInteger(path[0]) && Array.isArray(obj))
|
||||
return Array.prototype.slice.call(obj, 0).splice(path[0], 1);
|
||||
const result = {};
|
||||
for (const p in obj)
|
||||
result[p] = obj[p];
|
||||
delete result[path[0]];
|
||||
return result;
|
||||
}
|
||||
if (obj[path[0]] == null) {
|
||||
if (Number.isInteger(path[0]) && Array.isArray(obj))
|
||||
return Array.prototype.concat.call([], obj);
|
||||
const result = {};
|
||||
for (const p in obj)
|
||||
result[p] = obj[p];
|
||||
return result;
|
||||
}
|
||||
return set(
|
||||
obj,
|
||||
unset(
|
||||
obj[path[0]],
|
||||
Array.prototype.slice.call(path, 1)
|
||||
),
|
||||
[path[0]]
|
||||
);
|
||||
}
|
||||
export function deepPick(obj, paths) {
|
||||
return paths.map((p) => p.split(".")).map((p) => [p, get(obj, p)]).filter((t) => t[1] !== void 0).reduce((acc, cur) => set(acc, cur[1], cur[0]), {});
|
||||
}
|
||||
export function deepOmit(obj, paths) {
|
||||
return paths.map((p) => p.split(".")).reduce((acc, cur) => unset(acc, cur), obj);
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import type { NuxtModule } from '@nuxt/schema'
|
||||
|
||||
import type { default as Module } from './module.mjs'
|
||||
|
||||
export type ModuleOptions = typeof Module extends NuxtModule<infer O> ? Partial<O> : Record<string, any>
|
||||
|
||||
export { default } from './module.mjs'
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
{
|
||||
"name": "pinia-plugin-persistedstate",
|
||||
"type": "module",
|
||||
"version": "4.7.1",
|
||||
"packageManager": "pnpm@10.20.0",
|
||||
"description": "Configurable persistence and rehydration of Pinia stores.",
|
||||
"author": "praz <dev@praz.me> (https://praz.me)",
|
||||
"license": "MIT",
|
||||
"homepage": "https://praz.codeberg.page/pinia-plugin-persistedstate",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://codeberg.org/praz/pinia-plugin-persistedstate.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://codeberg.org/praz/pinia-plugin-persistedstate/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"vue",
|
||||
"store",
|
||||
"pinia",
|
||||
"persistence",
|
||||
"pinia-plugin",
|
||||
"nuxt",
|
||||
"nuxt-module"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"import": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/index.d.cts",
|
||||
"default": "./dist/index.cjs"
|
||||
}
|
||||
},
|
||||
"./nuxt": {
|
||||
"import": {
|
||||
"types": "./dist/nuxt/types.d.mts",
|
||||
"default": "./dist/nuxt/module.mjs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "pnpm build:plugin && pnpm build:module",
|
||||
"build:plugin": "tsdown",
|
||||
"build:module": "nuxt-module-build build --outDir dist/nuxt",
|
||||
"dev": "nuxi dev playground",
|
||||
"dev:build": "nuxi build playground",
|
||||
"dev:prepare": "nuxt-module-build prepare && nuxi prepare playground",
|
||||
"release": "changelogen --release --push",
|
||||
"docs": "vitepress dev docs",
|
||||
"docs:build": "vitepress build docs",
|
||||
"docs:preview": "vitepress preview docs",
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "eslint . --fix",
|
||||
"publint": "publint",
|
||||
"test": "vitest",
|
||||
"test:coverage": "vitest --coverage",
|
||||
"test:ui": "vitest --ui",
|
||||
"typecheck": "nuxi typecheck"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@nuxt/kit": ">=3.0.0",
|
||||
"@pinia/nuxt": ">=0.10.0",
|
||||
"pinia": ">=3.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@nuxt/kit": {
|
||||
"optional": true
|
||||
},
|
||||
"@pinia/nuxt": {
|
||||
"optional": true
|
||||
},
|
||||
"pinia": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"defu": "^6.1.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config": "^6.2.0",
|
||||
"@iconify-json/catppuccin": "^1.2.17",
|
||||
"@nuxt/devtools": "^3.0.1",
|
||||
"@nuxt/kit": "^4.2.0",
|
||||
"@nuxt/module-builder": "^1.0.2",
|
||||
"@nuxt/schema": "^4.2.0",
|
||||
"@pinia/nuxt": "^0.11.2",
|
||||
"@rollup/plugin-node-resolve": "^16.0.3",
|
||||
"@shikijs/vitepress-twoslash": "^3.14.0",
|
||||
"@types/node": "^24.9.2",
|
||||
"@vitest/coverage-v8": "^4.0.6",
|
||||
"@vitest/ui": "^4.0.6",
|
||||
"changelogen": "^0.6.2",
|
||||
"esbuild": "^0.25.11",
|
||||
"eslint": "^9.39.0",
|
||||
"eslint-plugin-format": "^1.0.2",
|
||||
"happy-dom": "^20.0.10",
|
||||
"lint-staged": "^16.2.6",
|
||||
"nuxt": "^4.2.0",
|
||||
"pinia": "^3.0.3",
|
||||
"pinia-plugin-persistedstate": "link:",
|
||||
"publint": "^0.3.15",
|
||||
"rollup": "^4.52.5",
|
||||
"rollup-plugin-esbuild": "^6.2.1",
|
||||
"simple-git-hooks": "^2.13.1",
|
||||
"tsdown": "^0.15.12",
|
||||
"tsup": "^8.5.0",
|
||||
"typescript": "~5.9.3",
|
||||
"vitepress": "^1.6.4",
|
||||
"vitepress-plugin-group-icons": "^1.6.5",
|
||||
"vitest": "^4.0.6",
|
||||
"vue": "^3.5.22",
|
||||
"vue-tsc": "^3.1.2"
|
||||
},
|
||||
"pnpm": {
|
||||
"onlyBuiltDependencies": [
|
||||
"@parcel/watcher",
|
||||
"esbuild",
|
||||
"simple-git-hooks"
|
||||
]
|
||||
},
|
||||
"simple-git-hooks": {
|
||||
"pre-commit": "pnpm lint-staged"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*": "eslint --fix"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user