vue-context-storage 0.1.22 → 0.1.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,12 +1,12 @@
1
- import * as vue0 from "vue";
1
+ import * as vue9 from "vue";
2
2
  import { InjectionKey, MaybeRefOrGetter, Plugin, PropType, UnwrapNestedRefs, WatchHandle } from "vue";
3
3
  import { LocationQuery, LocationQueryValue } from "vue-router";
4
4
 
5
5
  //#region src/components/ContextStorageActivator.vue.d.ts
6
6
  declare const _default$1: typeof __VLS_export$3;
7
- declare const __VLS_export$3: vue0.DefineComponent<{}, () => vue0.VNode<vue0.RendererNode, vue0.RendererElement, {
7
+ declare const __VLS_export$3: vue9.DefineComponent<{}, () => vue9.VNode<vue9.RendererNode, vue9.RendererElement, {
8
8
  [key: string]: any;
9
- }>, {}, {}, {}, vue0.ComponentOptionsMixin, vue0.ComponentOptionsMixin, {}, string, vue0.PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, vue0.ComponentProvideOptions, true, {}, any>;
9
+ }>, {}, {}, {}, vue9.ComponentOptionsMixin, vue9.ComponentOptionsMixin, {}, string, vue9.PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, vue9.ComponentProvideOptions, true, {}, any>;
10
10
  //#endregion
11
11
  //#region src/handlers.d.ts
12
12
  interface ContextStorageHandlerConstructor {
@@ -26,55 +26,55 @@ interface ContextStorageHandler {
26
26
  //#endregion
27
27
  //#region src/components/ContextStorageCollection.vue.d.ts
28
28
  declare const _default$2: typeof __VLS_export$2;
29
- declare const __VLS_export$2: vue0.DefineComponent<vue0.ExtractPropTypes<{
29
+ declare const __VLS_export$2: vue9.DefineComponent<vue9.ExtractPropTypes<{
30
30
  handlers: {
31
31
  type: PropType<ContextStorageHandlerConstructor[]>;
32
32
  default: () => ContextStorageHandlerConstructor[];
33
33
  };
34
- }>, () => vue0.VNode<vue0.RendererNode, vue0.RendererElement, {
34
+ }>, () => vue9.VNode<vue9.RendererNode, vue9.RendererElement, {
35
35
  [key: string]: any;
36
- }>[] | undefined, {}, {}, {}, vue0.ComponentOptionsMixin, vue0.ComponentOptionsMixin, {}, string, vue0.PublicProps, Readonly<vue0.ExtractPropTypes<{
36
+ }>[] | undefined, {}, {}, {}, vue9.ComponentOptionsMixin, vue9.ComponentOptionsMixin, {}, string, vue9.PublicProps, Readonly<vue9.ExtractPropTypes<{
37
37
  handlers: {
38
38
  type: PropType<ContextStorageHandlerConstructor[]>;
39
39
  default: () => ContextStorageHandlerConstructor[];
40
40
  };
41
41
  }>> & Readonly<{}>, {
42
42
  handlers: ContextStorageHandlerConstructor[];
43
- }, {}, {}, {}, string, vue0.ComponentProvideOptions, true, {}, any>;
43
+ }, {}, {}, {}, string, vue9.ComponentProvideOptions, true, {}, any>;
44
44
  //#endregion
45
45
  //#region src/components/ContextStorageProvider.vue.d.ts
46
46
  declare const _default$3: typeof __VLS_export$1;
47
- declare const __VLS_export$1: vue0.DefineComponent<vue0.ExtractPropTypes<{
47
+ declare const __VLS_export$1: vue9.DefineComponent<vue9.ExtractPropTypes<{
48
48
  itemKey: {
49
49
  type: StringConstructor;
50
50
  required: true;
51
51
  };
52
- }>, () => vue0.VNode<vue0.RendererNode, vue0.RendererElement, {
52
+ }>, () => vue9.VNode<vue9.RendererNode, vue9.RendererElement, {
53
53
  [key: string]: any;
54
- }>[] | undefined, {}, {}, {}, vue0.ComponentOptionsMixin, vue0.ComponentOptionsMixin, {}, string, vue0.PublicProps, Readonly<vue0.ExtractPropTypes<{
54
+ }>[] | undefined, {}, {}, {}, vue9.ComponentOptionsMixin, vue9.ComponentOptionsMixin, {}, string, vue9.PublicProps, Readonly<vue9.ExtractPropTypes<{
55
55
  itemKey: {
56
56
  type: StringConstructor;
57
57
  required: true;
58
58
  };
59
- }>> & Readonly<{}>, {}, {}, {}, {}, string, vue0.ComponentProvideOptions, true, {}, any>;
59
+ }>> & Readonly<{}>, {}, {}, {}, {}, string, vue9.ComponentProvideOptions, true, {}, any>;
60
60
  //#endregion
61
61
  //#region src/components/ContextStorage.vue.d.ts
62
62
  declare const _default: typeof __VLS_export;
63
- declare const __VLS_export: vue0.DefineComponent<vue0.ExtractPropTypes<{
63
+ declare const __VLS_export: vue9.DefineComponent<vue9.ExtractPropTypes<{
64
64
  handlers: {
65
65
  type: PropType<ContextStorageHandlerConstructor[]>;
66
66
  default: () => ContextStorageHandlerConstructor[];
67
67
  };
68
- }>, () => vue0.VNode<vue0.RendererNode, vue0.RendererElement, {
68
+ }>, () => vue9.VNode<vue9.RendererNode, vue9.RendererElement, {
69
69
  [key: string]: any;
70
- }>[] | undefined, {}, {}, {}, vue0.ComponentOptionsMixin, vue0.ComponentOptionsMixin, {}, string, vue0.PublicProps, Readonly<vue0.ExtractPropTypes<{
70
+ }>[] | undefined, {}, {}, {}, vue9.ComponentOptionsMixin, vue9.ComponentOptionsMixin, {}, string, vue9.PublicProps, Readonly<vue9.ExtractPropTypes<{
71
71
  handlers: {
72
72
  type: PropType<ContextStorageHandlerConstructor[]>;
73
73
  default: () => ContextStorageHandlerConstructor[];
74
74
  };
75
75
  }>> & Readonly<{}>, {
76
76
  handlers: ContextStorageHandlerConstructor[];
77
- }, {}, {}, {}, string, vue0.ComponentProvideOptions, true, {}, any>;
77
+ }, {}, {}, {}, string, vue9.ComponentProvideOptions, true, {}, any>;
78
78
  //#endregion
79
79
  //#region src/plugin.d.ts
80
80
  declare const VueContextStoragePlugin: Plugin;
@@ -105,23 +105,6 @@ declare class CollectionManager {
105
105
  setActive(activeItem: CollectionManagerItem): void;
106
106
  }
107
107
  //#endregion
108
- //#region src/composables/useContextStorageActivator.d.ts
109
- declare function useContextStorageActivator(): {
110
- activate: () => void;
111
- };
112
- //#endregion
113
- //#region src/composables/useContextStorageCollection.d.ts
114
- declare function useContextStorageCollection(handlers?: ContextStorageHandlerConstructor[]): CollectionManager;
115
- //#endregion
116
- //#region src/composables/useContextStorageProvider.d.ts
117
- declare function useContextStorageProvider(key: string): void;
118
- //#endregion
119
- //#region src/symbols.d.ts
120
- declare const collection: unique symbol;
121
- declare const collectionItem: unique symbol;
122
- declare const handlers: unique symbol;
123
- declare const contextStorageQueryHandler: unique symbol;
124
- //#endregion
125
108
  //#region src/handlers/query/types.d.ts
126
109
  type QueryValue = LocationQueryValue | LocationQueryValue[];
127
110
  type DeepTransformValuesToLocationQueryValue<T> = { [K in keyof T]?: T[K] extends object ? T[K] extends Array<any> ? QueryValue : DeepTransformValuesToLocationQueryValue<T[K]> : QueryValue };
@@ -257,6 +240,149 @@ interface ContextStorageQueryRegisteredItem<T extends Record<string, unknown>> {
257
240
  watchHandle: WatchHandle;
258
241
  }
259
242
  //#endregion
243
+ //#region src/handlers/web-storage-base/types.d.ts
244
+ interface WebStorageHandlerBaseOptions {
245
+ /**
246
+ * Default: true for localStorage, false for sessionStorage
247
+ *
248
+ * If enabled - storage events will be listened to for cross-tab synchronization.
249
+ * Only works with localStorage (sessionStorage is per-tab).
250
+ */
251
+ listenToStorageEvents?: boolean;
252
+ }
253
+ interface RegisterWebStorageHandlerBaseOptions<T> {
254
+ /**
255
+ * Storage key for this data.
256
+ */
257
+ key?: string;
258
+ /**
259
+ * Optional prefix for nested data within the storage key.
260
+ * When provided, data will be stored under this prefix within the main storage object.
261
+ */
262
+ prefix?: string;
263
+ /**
264
+ * Transform function to convert deserialized storage data to the expected type.
265
+ *
266
+ * Note: If `schema` is provided, it takes priority over `transform`.
267
+ */
268
+ transform?: (deserialized: Record<string, unknown>, initialData: T) => UnwrapNestedRefs<T>;
269
+ /**
270
+ * Zod schema for automatic validation and type coercion.
271
+ *
272
+ * When provided, the schema will be used to parse and validate storage data.
273
+ * This option takes priority over the `transform` option.
274
+ *
275
+ * @example
276
+ * ```typescript
277
+ * import { z } from 'zod'
278
+ *
279
+ * const SettingsSchema = z.object({
280
+ * theme: z.enum(['light', 'dark']).default('light'),
281
+ * fontSize: z.number().int().positive().default(14),
282
+ * })
283
+ *
284
+ * useContextStorageLocalStorage(settings, {
285
+ * key: 'app-settings',
286
+ * schema: SettingsSchema,
287
+ * })
288
+ * ```
289
+ */
290
+ schema?: {
291
+ safeParse: (data: unknown) => {
292
+ success: true;
293
+ data: T;
294
+ } | {
295
+ success: false;
296
+ error: any;
297
+ };
298
+ parse: (data: unknown) => T;
299
+ };
300
+ /**
301
+ * Custom serializer function. Defaults to JSON.stringify.
302
+ */
303
+ serializer?: (data: T) => string;
304
+ /**
305
+ * Custom deserializer function. Defaults to JSON.parse.
306
+ */
307
+ deserializer?: (str: string) => unknown;
308
+ }
309
+ interface RegisterWebStorageHandlerOptions<T> extends RegisterBaseOptions, RegisterWebStorageHandlerBaseOptions<T> {}
310
+ interface IContextStorageWebStorageHandler extends ContextStorageHandler {
311
+ register: <T extends Record<string, unknown>>(data: MaybeRefOrGetter<T>, options: RegisterWebStorageHandlerOptions<T>) => () => void;
312
+ }
313
+ interface ContextStorageWebStorageRegisteredItem<T extends Record<string, unknown>> {
314
+ data: MaybeRefOrGetter<T>;
315
+ initialData: T;
316
+ options: RegisterWebStorageHandlerOptions<T>;
317
+ watchHandle: WatchHandle;
318
+ }
319
+ //#endregion
320
+ //#region src/handlers/web-storage-base/index.d.ts
321
+ declare abstract class ContextStorageWebStorageHandler implements IContextStorageWebStorageHandler {
322
+ protected enabled: boolean;
323
+ protected registered: ContextStorageWebStorageRegisteredItem<any>[];
324
+ protected initialState?: Record<string, unknown>;
325
+ protected hasAnyRegistered: boolean;
326
+ protected preventSyncToStorage: boolean;
327
+ protected abstract readonly storage: Storage;
328
+ protected abstract readonly injectionKey: InjectionKey<ContextStorageWebStorageHandler>;
329
+ protected readonly options: Required<WebStorageHandlerBaseOptions>;
330
+ private storageEventHandler;
331
+ constructor(defaultOptions: Required<WebStorageHandlerBaseOptions>);
332
+ protected initializeStorageListener(): void;
333
+ protected handleStorageEvent(event: StorageEvent): void;
334
+ getInjectionKey(): InjectionKey<ContextStorageWebStorageHandler>;
335
+ setInitialState(state: Record<string, unknown> | undefined): void;
336
+ setEnabled(state: boolean, initial: boolean): void;
337
+ syncRegisteredToStorage(): void;
338
+ syncStorageToRegisteredItem<T extends Record<string, unknown>>(item: ContextStorageWebStorageRegisteredItem<T>): void;
339
+ syncStorageToRegistered(): void;
340
+ register<T extends Record<string, unknown>>(data: MaybeRefOrGetter<T>, options: RegisterWebStorageHandlerOptions<T>): () => void;
341
+ }
342
+ /**
343
+ * Options for the web storage composable with required key
344
+ */
345
+ type UseWebStorageOptions<T> = RegisterWebStorageHandlerBaseOptions<T> & Required<Pick<RegisterWebStorageHandlerBaseOptions<T>, 'key'>>;
346
+ //#endregion
347
+ //#region src/registry.d.ts
348
+ /**
349
+ * Augmentable interface mapping handler names to their options types.
350
+ *
351
+ * Users can extend this via module declaration:
352
+ * ```typescript
353
+ * declare module 'vue-context-storage' {
354
+ * interface ContextStorageHandlerMap {
355
+ * myHandler: MyHandlerOptions
356
+ * }
357
+ * }
358
+ * ```
359
+ */
360
+ interface ContextStorageHandlerMap {
361
+ query: RegisterQueryHandlerBaseOptions<any>;
362
+ localStorage: UseWebStorageOptions<any>;
363
+ sessionStorage: UseWebStorageOptions<any>;
364
+ }
365
+ declare function defineContextStorageHandler(name: string, injectionKey: InjectionKey<ContextStorageHandler>): void;
366
+ declare function resolveHandlerInjectionKey(type: string): InjectionKey<ContextStorageHandler> | undefined;
367
+ //#endregion
368
+ //#region src/composables/useContextStorage.d.ts
369
+ declare function useContextStorage<K$1 extends keyof ContextStorageHandlerMap, T extends Record<string, unknown>>(type: K$1, data: MaybeRefOrGetter<T>, options: ContextStorageHandlerMap[K$1]): void;
370
+ declare function useContextStorage<T extends Record<string, unknown>>(type: InjectionKey<ContextStorageHandler>, data: MaybeRefOrGetter<T>, options?: Record<string, unknown>): void;
371
+ //#endregion
372
+ //#region src/composables/useContextStorageActivator.d.ts
373
+ declare function useContextStorageActivator(): {
374
+ activate: () => void;
375
+ };
376
+ //#endregion
377
+ //#region src/composables/useContextStorageCollection.d.ts
378
+ declare function useContextStorageCollection(handlers?: ContextStorageHandlerConstructor[]): CollectionManager;
379
+ //#endregion
380
+ //#region src/composables/useContextStorageProvider.d.ts
381
+ declare function useContextStorageProvider(key: string): void;
382
+ //#endregion
383
+ //#region src/symbols.d.ts
384
+ declare const contextStorageQueryHandler: unique symbol;
385
+ //#endregion
260
386
  //#region src/handlers/query/index.d.ts
261
387
  declare function useContextStorageQueryHandler<T extends Record<string, unknown>>(data: MaybeRefOrGetter<T>, options?: RegisterQueryHandlerBaseOptions<T>): void;
262
388
  declare class ContextStorageQueryHandler implements IContextStorageQueryHandler {
@@ -285,6 +411,26 @@ declare class ContextStorageQueryHandler implements IContextStorageQueryHandler
285
411
  register<T extends Record<string, unknown>>(data: MaybeRefOrGetter<T>, options: RegisterQueryHandlerOptions<T>): () => void;
286
412
  }
287
413
  //#endregion
414
+ //#region src/handlers/local-storage/index.d.ts
415
+ declare class ContextStorageLocalStorageHandler extends ContextStorageWebStorageHandler {
416
+ protected readonly storage: Storage;
417
+ protected readonly injectionKey: InjectionKey<ContextStorageLocalStorageHandler>;
418
+ static customHandlerOptions: WebStorageHandlerBaseOptions;
419
+ constructor();
420
+ static configure(options: WebStorageHandlerBaseOptions): ContextStorageHandlerConstructor;
421
+ }
422
+ declare const useContextStorageLocalStorage: <T extends Record<string, unknown>>(data: vue9.MaybeRefOrGetter<T>, options: UseWebStorageOptions<T>) => void;
423
+ //#endregion
424
+ //#region src/handlers/session-storage/index.d.ts
425
+ declare class ContextStorageSessionStorageHandler extends ContextStorageWebStorageHandler {
426
+ protected readonly storage: Storage;
427
+ protected readonly injectionKey: InjectionKey<ContextStorageSessionStorageHandler>;
428
+ static customHandlerOptions: WebStorageHandlerBaseOptions;
429
+ constructor();
430
+ static configure(options: WebStorageHandlerBaseOptions): ContextStorageHandlerConstructor;
431
+ }
432
+ declare const useContextStorageSessionStorage: <T extends Record<string, unknown>>(data: vue9.MaybeRefOrGetter<T>, options: UseWebStorageOptions<T>) => void;
433
+ //#endregion
288
434
  //#region src/handlers/query/transform-helpers.d.ts
289
435
  declare function asNumber(value: QueryValue | number | undefined): number;
290
436
  declare function asNumber(value: QueryValue | number | undefined, options: {
@@ -460,8 +606,10 @@ declare const contextStorageCollectionInjectKey: InjectionKey<CollectionManager>
460
606
  declare const contextStorageCollectionItemInjectKey: InjectionKey<CollectionManagerItem>;
461
607
  declare const contextStorageHandlersInjectKey: InjectionKey<CollectionManagerItem['handlers']>;
462
608
  declare const contextStorageQueryHandlerInjectKey: InjectionKey<InstanceType<typeof ContextStorageQueryHandler>>;
609
+ declare const contextStorageLocalStorageHandlerInjectKey: InjectionKey<InstanceType<typeof ContextStorageLocalStorageHandler>>;
610
+ declare const contextStorageSessionStorageHandlerInjectKey: InjectionKey<InstanceType<typeof ContextStorageSessionStorageHandler>>;
463
611
  //#endregion
464
612
  //#region src/constants.d.ts
465
613
  declare const defaultHandlers: ContextStorageHandlerConstructor[];
466
614
  //#endregion
467
- export { CollectionManager, type CollectionManagerItem, _default as ContextStorage, _default$1 as ContextStorageActivator, _default$2 as ContextStorageCollection, type ContextStorageHandler, type ContextStorageHandlerConstructor, _default$3 as ContextStorageProvider, ContextStorageQueryHandler, type IContextStorageQueryHandler, type QueryValue, type RegisterBaseOptions, VueContextStoragePlugin, asArray, asBoolean, asNumber, asNumberArray, asString, collection, collectionItem, contextStorageCollectionInjectKey, contextStorageCollectionItemInjectKey, contextStorageHandlersInjectKey, contextStorageQueryHandler, contextStorageQueryHandlerInjectKey, defaultHandlers, deserializeParams as deserializeQueryParams, handlers, serializeParams as serializeQueryParams, transform, useContextStorageActivator, useContextStorageCollection, useContextStorageProvider, useContextStorageQueryHandler };
615
+ export { CollectionManager, type CollectionManagerItem, _default as ContextStorage, _default$1 as ContextStorageActivator, _default$2 as ContextStorageCollection, type ContextStorageHandler, type ContextStorageHandlerConstructor, type ContextStorageHandlerMap, ContextStorageLocalStorageHandler, _default$3 as ContextStorageProvider, ContextStorageQueryHandler, ContextStorageSessionStorageHandler, type IContextStorageWebStorageHandler as IContextStorageLocalStorageHandler, type IContextStorageWebStorageHandler as IContextStorageSessionStorageHandler, type IContextStorageQueryHandler, type WebStorageHandlerBaseOptions as LocalStorageHandlerBaseOptions, type WebStorageHandlerBaseOptions as SessionStorageHandlerBaseOptions, type QueryValue, type RegisterBaseOptions, type RegisterWebStorageHandlerBaseOptions as RegisterLocalStorageHandlerBaseOptions, type RegisterWebStorageHandlerBaseOptions as RegisterSessionStorageHandlerBaseOptions, VueContextStoragePlugin, asArray, asBoolean, asNumber, asNumberArray, asString, contextStorageCollectionInjectKey, contextStorageCollectionItemInjectKey, contextStorageHandlersInjectKey, contextStorageLocalStorageHandlerInjectKey, contextStorageQueryHandlerInjectKey, contextStorageSessionStorageHandlerInjectKey, defaultHandlers, defineContextStorageHandler, deserializeParams as deserializeQueryParams, resolveHandlerInjectionKey, serializeParams as serializeQueryParams, transform, useContextStorage, useContextStorageActivator, useContextStorageCollection, useContextStorageLocalStorage, useContextStorageProvider, useContextStorageQueryHandler, useContextStorageSessionStorage };
package/dist/index.js CHANGED
@@ -59,6 +59,200 @@ var CollectionManager = class {
59
59
  }
60
60
  };
61
61
 
62
+ //#endregion
63
+ //#region src/symbols.ts
64
+ const collection = Symbol("context-storage-collection");
65
+ const collectionItem = Symbol("context-storage-collection-item");
66
+ const handlers = Symbol("context-storage-handlers");
67
+ const contextStorageQueryHandler = Symbol("context-storage-query-handler");
68
+ const contextStorageLocalStorageHandler = Symbol("context-storage-local-storage-handler");
69
+ const contextStorageSessionStorageHandler = Symbol("context-storage-session-storage-handler");
70
+
71
+ //#endregion
72
+ //#region src/handlers/web-storage-base/index.ts
73
+ var ContextStorageWebStorageHandler = class {
74
+ enabled = false;
75
+ registered = [];
76
+ initialState;
77
+ hasAnyRegistered = false;
78
+ preventSyncToStorage = false;
79
+ options;
80
+ storageEventHandler = null;
81
+ constructor(defaultOptions) {
82
+ this.options = { ...defaultOptions };
83
+ }
84
+ initializeStorageListener() {
85
+ if (this.options.listenToStorageEvents && typeof window !== "undefined") {
86
+ this.storageEventHandler = (event) => {
87
+ this.handleStorageEvent(event);
88
+ };
89
+ window.addEventListener("storage", this.storageEventHandler);
90
+ onBeforeUnmount(() => {
91
+ if (this.storageEventHandler) {
92
+ window.removeEventListener("storage", this.storageEventHandler);
93
+ this.storageEventHandler = null;
94
+ }
95
+ });
96
+ }
97
+ }
98
+ handleStorageEvent(event) {
99
+ if (!this.enabled) return;
100
+ this.registered.forEach((item) => {
101
+ if (event.key === item.options.key) this.syncStorageToRegisteredItem(item);
102
+ });
103
+ }
104
+ getInjectionKey() {
105
+ return this.injectionKey;
106
+ }
107
+ setInitialState(state) {
108
+ this.initialState = state;
109
+ }
110
+ setEnabled(state, initial) {
111
+ const prevState = this.enabled;
112
+ this.enabled = state;
113
+ if (this.hasAnyRegistered) {
114
+ if (initial) this.syncStorageToRegistered();
115
+ if (state && !prevState || !initial) this.syncRegisteredToStorage();
116
+ }
117
+ }
118
+ syncRegisteredToStorage() {
119
+ if (!this.enabled) return;
120
+ if (this.preventSyncToStorage) return;
121
+ const byKey = /* @__PURE__ */ new Map();
122
+ this.registered.forEach((item) => {
123
+ const key = item.options.key;
124
+ if (!byKey.has(key)) byKey.set(key, []);
125
+ byKey.get(key).push(item);
126
+ });
127
+ byKey.forEach((items, key) => {
128
+ let storageData = {};
129
+ try {
130
+ const existing = this.storage.getItem(key);
131
+ if (existing) storageData = JSON.parse(existing);
132
+ } catch {}
133
+ items.forEach((item) => {
134
+ const { prefix, serializer } = item.options;
135
+ const data = toValue(item.data);
136
+ if (prefix) storageData[prefix] = data;
137
+ else storageData = {
138
+ ...storageData,
139
+ ...data
140
+ };
141
+ if (serializer && !prefix) {
142
+ try {
143
+ this.storage.setItem(key, serializer(data));
144
+ } catch (e) {
145
+ console.error("[vue-context-storage] Error writing to storage", e);
146
+ }
147
+ return;
148
+ }
149
+ });
150
+ try {
151
+ this.storage.setItem(key, JSON.stringify(storageData));
152
+ } catch (e) {
153
+ console.error("[vue-context-storage] Error writing to storage", e);
154
+ }
155
+ });
156
+ }
157
+ syncStorageToRegisteredItem(item) {
158
+ const { key, prefix, deserializer } = item.options;
159
+ let stored = null;
160
+ try {
161
+ stored = this.storage.getItem(key);
162
+ } catch {
163
+ return;
164
+ }
165
+ if (stored === null) return;
166
+ let deserialized;
167
+ try {
168
+ if (deserializer) deserialized = deserializer(stored);
169
+ else deserialized = JSON.parse(stored);
170
+ } catch {
171
+ console.warn("[vue-context-storage] Failed to parse storage data for key:", key);
172
+ return;
173
+ }
174
+ if (typeof prefix === "string" && prefix.length > 0) deserialized = deserialized[prefix] || {};
175
+ if (deserialized === void 0 || deserialized === null) return;
176
+ const itemData = toValue(item.data);
177
+ if (item.options?.schema) {
178
+ const result = item.options.schema.safeParse(deserialized);
179
+ if (result.success) deserialized = result.data;
180
+ else {
181
+ console.warn("[vue-context-storage] schema parse failed", result.error);
182
+ merge(itemData, item.initialData);
183
+ return;
184
+ }
185
+ if (item.options?.transform) console.warn("[vue-context-storage] transform is not supported with schema");
186
+ } else if (item.options?.transform) deserialized = item.options.transform(deserialized, item.initialData);
187
+ else deserialized = pick(deserialized, Object.keys(item.initialData));
188
+ if (isEqual(itemData, deserialized)) return;
189
+ merge(itemData, deserialized);
190
+ }
191
+ syncStorageToRegistered() {
192
+ this.registered.forEach((item) => this.syncStorageToRegisteredItem(item));
193
+ }
194
+ register(data, options) {
195
+ if (!options.key) throw new Error("[vue-context-storage] Storage handler requires a key option");
196
+ this.hasAnyRegistered = true;
197
+ const watchHandle = watch(data, () => this.syncRegisteredToStorage(), { deep: true });
198
+ const item = {
199
+ data,
200
+ initialData: cloneDeep(toValue(data)),
201
+ options,
202
+ watchHandle
203
+ };
204
+ this.registered.push(item);
205
+ const syncCallback = () => {
206
+ this.syncStorageToRegisteredItem(item);
207
+ this.syncRegisteredToStorage();
208
+ };
209
+ queueMicrotask(syncCallback);
210
+ return () => {
211
+ watchHandle();
212
+ this.registered.splice(this.registered.indexOf(item), 1);
213
+ };
214
+ }
215
+ };
216
+ function createWebStorageComposable(injectionKey, handlerName) {
217
+ return function useContextStorageWebStorage(data, options) {
218
+ const handler = inject(injectionKey);
219
+ if (!handler) throw new Error(`[vue-context-storage] ${handlerName} is not provided`);
220
+ const uid = getCurrentInstance()?.uid || 0;
221
+ const causer = (/* @__PURE__ */ new Error()).stack?.split("\n")[2]?.trimStart() || "unknown";
222
+ const stop = handler.register(data, {
223
+ causer,
224
+ uid,
225
+ ...options
226
+ });
227
+ onBeforeUnmount(() => {
228
+ stop();
229
+ });
230
+ };
231
+ }
232
+
233
+ //#endregion
234
+ //#region src/handlers/local-storage/index.ts
235
+ var ContextStorageLocalStorageHandler = class ContextStorageLocalStorageHandler extends ContextStorageWebStorageHandler {
236
+ storage;
237
+ injectionKey;
238
+ static customHandlerOptions = {};
239
+ constructor() {
240
+ const defaultOptions = {
241
+ listenToStorageEvents: true,
242
+ ...ContextStorageLocalStorageHandler.customHandlerOptions
243
+ };
244
+ super(defaultOptions);
245
+ this.storage = localStorage;
246
+ this.injectionKey = contextStorageLocalStorageHandler;
247
+ this.initializeStorageListener();
248
+ }
249
+ static configure(options) {
250
+ ContextStorageLocalStorageHandler.customHandlerOptions = options;
251
+ return ContextStorageLocalStorageHandler;
252
+ }
253
+ };
254
+ const useContextStorageLocalStorage = createWebStorageComposable(contextStorageLocalStorageHandler, "ContextStorageLocalStorageHandler");
255
+
62
256
  //#endregion
63
257
  //#region src/handlers/query/helpers.ts
64
258
  /**
@@ -133,13 +327,6 @@ function deserializeParams(params) {
133
327
  }, {});
134
328
  }
135
329
 
136
- //#endregion
137
- //#region src/symbols.ts
138
- const collection = Symbol("context-storage-collection");
139
- const collectionItem = Symbol("context-storage-collection-item");
140
- const handlers = Symbol("context-storage-handlers");
141
- const contextStorageQueryHandler = Symbol("context-storage-query-handler");
142
-
143
330
  //#endregion
144
331
  //#region src/handlers/query/index.ts
145
332
  function useContextStorageQueryHandler(data, options) {
@@ -352,12 +539,37 @@ var ContextStorageQueryHandler = class ContextStorageQueryHandler {
352
539
  }
353
540
  };
354
541
 
542
+ //#endregion
543
+ //#region src/handlers/session-storage/index.ts
544
+ var ContextStorageSessionStorageHandler = class ContextStorageSessionStorageHandler extends ContextStorageWebStorageHandler {
545
+ storage;
546
+ injectionKey;
547
+ static customHandlerOptions = {};
548
+ constructor() {
549
+ const defaultOptions = {
550
+ listenToStorageEvents: false,
551
+ ...ContextStorageSessionStorageHandler.customHandlerOptions
552
+ };
553
+ super(defaultOptions);
554
+ this.storage = sessionStorage;
555
+ this.injectionKey = contextStorageSessionStorageHandler;
556
+ this.initializeStorageListener();
557
+ }
558
+ static configure(options) {
559
+ ContextStorageSessionStorageHandler.customHandlerOptions = options;
560
+ return ContextStorageSessionStorageHandler;
561
+ }
562
+ };
563
+ const useContextStorageSessionStorage = createWebStorageComposable(contextStorageSessionStorageHandler, "ContextStorageSessionStorageHandler");
564
+
355
565
  //#endregion
356
566
  //#region src/injectionSymbols.ts
357
567
  const contextStorageCollectionInjectKey = collection;
358
568
  const contextStorageCollectionItemInjectKey = collectionItem;
359
569
  const contextStorageHandlersInjectKey = handlers;
360
570
  const contextStorageQueryHandlerInjectKey = contextStorageQueryHandler;
571
+ const contextStorageLocalStorageHandlerInjectKey = contextStorageLocalStorageHandler;
572
+ const contextStorageSessionStorageHandlerInjectKey = contextStorageSessionStorageHandler;
361
573
 
362
574
  //#endregion
363
575
  //#region src/composables/useContextStorageActivator.ts
@@ -380,7 +592,11 @@ var ContextStorageActivator_default = ContextStorageActivator_vue_vue_type_scrip
380
592
 
381
593
  //#endregion
382
594
  //#region src/constants.ts
383
- const defaultHandlers = [ContextStorageQueryHandler];
595
+ const defaultHandlers = [
596
+ ContextStorageQueryHandler,
597
+ ContextStorageLocalStorageHandler,
598
+ ContextStorageSessionStorageHandler
599
+ ];
384
600
 
385
601
  //#endregion
386
602
  //#region src/composables/useContextStorageCollection.ts
@@ -468,8 +684,7 @@ var ContextStorage_vue_vue_type_script_lang_default = defineComponent({
468
684
  const initItem = () => {
469
685
  item.handlers.forEach((handler) => {
470
686
  const state = initialNavigatorState.get(handler.constructor);
471
- if (!state) return;
472
- handler.setInitialState?.(state);
687
+ if (state) handler.setInitialState?.(state);
473
688
  handler.setEnabled?.(true, true);
474
689
  });
475
690
  };
@@ -496,6 +711,42 @@ const VueContextStoragePlugin = { install(app) {
496
711
  app.component("ContextStorage", ContextStorage_default);
497
712
  } };
498
713
 
714
+ //#endregion
715
+ //#region src/registry.ts
716
+ const handlerRegistry = /* @__PURE__ */ new Map();
717
+ function defineContextStorageHandler(name, injectionKey) {
718
+ handlerRegistry.set(name, injectionKey);
719
+ }
720
+ function resolveHandlerInjectionKey(type) {
721
+ return handlerRegistry.get(type);
722
+ }
723
+ defineContextStorageHandler("query", contextStorageQueryHandlerInjectKey);
724
+ defineContextStorageHandler("localStorage", contextStorageLocalStorageHandlerInjectKey);
725
+ defineContextStorageHandler("sessionStorage", contextStorageSessionStorageHandlerInjectKey);
726
+
727
+ //#endregion
728
+ //#region src/composables/useContextStorage.ts
729
+ function useContextStorage(type, data, options) {
730
+ let injectionKey;
731
+ if (typeof type === "string") {
732
+ const resolved = resolveHandlerInjectionKey(type);
733
+ if (!resolved) throw new Error(`[vue-context-storage] Unknown handler type: "${type}". Use defineContextStorageHandler() to register it.`);
734
+ injectionKey = resolved;
735
+ } else injectionKey = type;
736
+ const handler = inject(injectionKey);
737
+ if (!handler) throw new Error(`[vue-context-storage] Handler not provided for type: "${String(type)}"`);
738
+ const uid = getCurrentInstance()?.uid || 0;
739
+ const causer = (/* @__PURE__ */ new Error()).stack?.split("\n")[2]?.trimStart() || "unknown";
740
+ const stop = handler.register(data, {
741
+ causer,
742
+ uid,
743
+ ...options
744
+ });
745
+ onBeforeUnmount(() => {
746
+ stop();
747
+ });
748
+ }
749
+
499
750
  //#endregion
500
751
  //#region src/handlers/query/transform-helpers.ts
501
752
  function asNumber(value, options) {
@@ -559,4 +810,4 @@ const transform = {
559
810
  };
560
811
 
561
812
  //#endregion
562
- export { CollectionManager, ContextStorage_default as ContextStorage, ContextStorageActivator_default as ContextStorageActivator, ContextStorageCollection_default as ContextStorageCollection, ContextStorageProvider_default as ContextStorageProvider, ContextStorageQueryHandler, VueContextStoragePlugin, asArray, asBoolean, asNumber, asNumberArray, asString, collection, collectionItem, contextStorageCollectionInjectKey, contextStorageCollectionItemInjectKey, contextStorageHandlersInjectKey, contextStorageQueryHandler, contextStorageQueryHandlerInjectKey, defaultHandlers, deserializeParams as deserializeQueryParams, handlers, serializeParams as serializeQueryParams, transform, useContextStorageActivator, useContextStorageCollection, useContextStorageProvider, useContextStorageQueryHandler };
813
+ export { CollectionManager, ContextStorage_default as ContextStorage, ContextStorageActivator_default as ContextStorageActivator, ContextStorageCollection_default as ContextStorageCollection, ContextStorageLocalStorageHandler, ContextStorageProvider_default as ContextStorageProvider, ContextStorageQueryHandler, ContextStorageSessionStorageHandler, VueContextStoragePlugin, asArray, asBoolean, asNumber, asNumberArray, asString, contextStorageCollectionInjectKey, contextStorageCollectionItemInjectKey, contextStorageHandlersInjectKey, contextStorageLocalStorageHandlerInjectKey, contextStorageQueryHandlerInjectKey, contextStorageSessionStorageHandlerInjectKey, defaultHandlers, defineContextStorageHandler, deserializeParams as deserializeQueryParams, resolveHandlerInjectionKey, serializeParams as serializeQueryParams, transform, useContextStorage, useContextStorageActivator, useContextStorageCollection, useContextStorageLocalStorage, useContextStorageProvider, useContextStorageQueryHandler, useContextStorageSessionStorage };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "vue-context-storage",
3
3
  "type": "module",
4
- "version": "0.1.22",
4
+ "version": "0.1.23",
5
5
  "description": "Vue 3 context storage system with URL query synchronization support",
6
6
  "author": "",
7
7
  "license": "MIT",
@@ -68,6 +68,7 @@
68
68
  "eslint-config-prettier": "^10.1.8",
69
69
  "eslint-plugin-vue": "^10.6.2",
70
70
  "happy-dom": "^20.1.0",
71
+ "highlight.js": "^11.11.1",
71
72
  "jsdom": "^27.4.0",
72
73
  "naive-ui": "^2.43.2",
73
74
  "playwright": "^1.57.0",