From 9fb813619eb2a739b88c248088d1758f890e41f8 Mon Sep 17 00:00:00 2001 From: kraktus Date: Thu, 26 Feb 2026 18:37:51 +0100 Subject: [PATCH] wip --- .../persisted-state/persisted-state.svelte.ts | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/packages/runed/src/lib/utilities/persisted-state/persisted-state.svelte.ts b/packages/runed/src/lib/utilities/persisted-state/persisted-state.svelte.ts index 6d03c747..8afeb46c 100644 --- a/packages/runed/src/lib/utilities/persisted-state/persisted-state.svelte.ts +++ b/packages/runed/src/lib/utilities/persisted-state/persisted-state.svelte.ts @@ -4,11 +4,16 @@ import { createSubscriber } from "svelte/reactivity"; type Serializer = { serialize: (value: T) => string; - deserialize: (value: string) => T | undefined; + deserialize: (value: string) => T; }; type StorageType = "local" | "session"; +declare const NO_VALUE: unique symbol; + +// different from undefined to distinguish between deserialization failure and valid undefined value +export type NoValue = typeof NO_VALUE; + function getStorage(storageType: StorageType, window: Window & typeof globalThis): Storage { switch (storageType) { case "local": @@ -55,11 +60,11 @@ type PersistedStateOptions = { function proxy( value: unknown, - root: T | undefined, + root: T | NoValue, proxies: WeakMap, subscribe: VoidFunction | undefined, update: VoidFunction | undefined, - serialize: (root?: T | undefined) => void + serialize: (root: T | NoValue) => void ): T { if (value === null || typeof value !== "object") { return value as T; @@ -96,7 +101,7 @@ function proxy( * @see {@link https://runed.dev/docs/utilities/persisted-state} */ export class PersistedState { - #current: T | undefined; + #current: T | NoValue; #key: string; #serializer: Serializer; #storage?: Storage; @@ -144,7 +149,7 @@ export class PersistedState { get current(): T { this.#subscribe?.(); - let root: T | undefined; + let root: T | NoValue = NO_VALUE; if (this.#connected) { // when we're connected to storage, we use storage as the source of truth const storageItem = this.#storage?.getItem(this.#key); @@ -174,16 +179,16 @@ export class PersistedState { this.#update?.(); }; - #deserialize(value: string): T | undefined { + #deserialize(value: string): T | NoValue { try { return this.#serializer.deserialize(value); } catch (error) { console.error(`Error when parsing "${value}" from persisted store "${this.#key}"`, error); - return; + return NO_VALUE; } } - #serialize(value: T | undefined): void { + #serialize(value: T | NoValue): void { if (!this.#connected) { // when we're not connected to storage, we only update the value in memory this.#current = value; @@ -191,7 +196,7 @@ export class PersistedState { } try { - if (value !== undefined) { + if (value !== NO_VALUE) { this.#storage?.setItem(this.#key, this.#serializer.serialize(value)); } } catch (error) {