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
+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);
}