first commit
This commit is contained in:
+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);
|
||||
}
|
||||
Reference in New Issue
Block a user