first commit

This commit is contained in:
2026-02-06 20:21:10 +08:00
commit f9d7f980bb
3994 changed files with 1146030 additions and 0 deletions
+21
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 }
);
});
}
@@ -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
View File
@@ -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);
}
});
@@ -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
View File
@@ -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
};
@@ -0,0 +1,2 @@
export declare function deepPick(obj: object, paths: Array<string>): {};
export declare function deepOmit(obj: object, paths: Array<string>): object;
+65
View File
@@ -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
View File
@@ -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
View File
@@ -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"
}
}