{"version":3,"file":"storage.cjs","names":[],"sources":["../../src/utils/storage.ts"],"sourcesContent":["/** How a {@link createJsonStorage} store turns values into text and back. */\nexport interface StorageCodec {\n    /** Encode a value for storage. */\n    serialize: <T>(value: T) => string;\n    /** Decode a stored string. */\n    deserialize: <T>(raw: string) => T;\n}\n\n/** The surface every store built by {@link createJsonStorage} exposes. */\nexport interface JsonStorage {\n    /**\n     * Read and decode a key.\n     *\n     * The value is decoded by the store's codec — JSON for {@link storage} —\n     * which is what makes a key written as a bare string unreadable here: it is\n     * not the shape this method writes. {@link JsonStorage.getRaw} reads those.\n     *\n     * @typeParam T - The expected value shape.\n     * @param key - Storage key.\n     * @param fallback - Returned when the key is absent, unreadable, or corrupt.\n     * @returns The stored value, or `fallback`.\n     */\n    get<T>(key: string, fallback: T): T;\n    /**\n     * Encode and write a key.\n     *\n     * The value is **encoded** — `set(\"theme\", \"dark\")` stores `\"dark\"` with the\n     * quotes, not `dark`. That matters when an existing key is being adopted:\n     * whatever read it before will no longer recognise what this writes, and the\n     * old value will no longer parse here. {@link JsonStorage.setRaw} is the\n     * passthrough.\n     *\n     * @typeParam T - The value being stored.\n     * @param key - Storage key.\n     * @param value - Any value the codec can represent.\n     */\n    set<T>(key: string, value: T): void;\n    /**\n     * Read a key exactly as `localStorage` holds it, with no decoding.\n     *\n     * The escape hatch {@link JsonStorage.get} cannot be: `get` runs the codec,\n     * so a key holding a bare `dark` — written by another library, by the app\n     * before it adopted this wrapper, or by the SDK's own `ThemeProvider` —\n     * fails to parse and comes back as the fallback. Reading that key is a\n     * different operation, not a variant of the same one.\n     *\n     * @param key - Storage key.\n     * @returns The stored string, or `null` when the key is absent or storage is\n     *   unavailable.\n     */\n    getRaw(key: string): string | null;\n    /**\n     * Write a string exactly as given, with no encoding.\n     *\n     * The counterpart of {@link JsonStorage.getRaw}, and what keeps adoption from\n     * being a silent migration: `set(\"theme\", \"dark\")` stores `\"dark\"` **with the\n     * quotes**, which the app's previous reader no longer recognises.\n     *\n     * @param key - Storage key.\n     * @param value - The exact string to store.\n     */\n    setRaw(key: string, value: string): void;\n    /**\n     * Delete a key.\n     *\n     * @param key - Storage key.\n     */\n    remove(key: string): void;\n}\n\nconst jsonCodec: StorageCodec = {\n    serialize: (value) => JSON.stringify(value),\n    deserialize: (raw) => JSON.parse(raw),\n};\n\n/**\n * Encode with the codec, degrading to plain JSON when the codec itself fails.\n *\n * A codec that throws — a compressor running out of room on a huge value —\n * should cost size, not the record: a slightly larger row still loads, an absent\n * one does not. `null` means not even JSON could represent the value, which is\n * the one case where dropping the write is the only option left.\n *\n * @param codec - The store's codec.\n * @param value - The value to encode.\n * @returns The encoded string, or `null` when the value cannot be represented.\n */\nfunction encode<T>(codec: StorageCodec, value: T): string | null {\n    try {\n        return codec.serialize(value);\n    } catch {\n        try {\n            return JSON.stringify(value);\n        } catch {\n            return null;\n        }\n    }\n}\n\n/**\n * Build a typed `localStorage` wrapper around a codec.\n *\n * One implementation behind every store the SDK ships, so they cannot drift in\n * surface. {@link storage} and {@link compressedStorage} are both this function —\n * before it, the compressed one was a hand-written copy of the same guards and\n * had no `remove`, while its own docstring promised the two were interchangeable\n * at the call site. They were not, and the promise failed exactly where somebody\n * followed it.\n *\n * @example\n * const session = createJsonStorage();\n * session.set(\"draft\", { title: \"Sem título\" });\n *\n * @example\n * const packed = createJsonStorage(compressedStorageCodec);\n *\n * @param codec - Encoder pair. Defaults to plain JSON.\n * @returns A store with `get` / `set` / `getRaw` / `setRaw` / `remove`.\n *\n * @tempest-limits empty-catch — every method is best-effort by contract:\n * `localStorage` throws on quota exhaustion, in Safari private mode, and when a\n * cross-origin frame has storage blocked. A caller persisting a preference has no\n * recovery to run and no user-facing message to show, so the write is dropped and\n * the app keeps the value in memory for the session.\n */\nexport function createJsonStorage(codec: StorageCodec = jsonCodec): JsonStorage {\n    return {\n        get<T>(key: string, fallback: T): T {\n            if (typeof window === \"undefined\") return fallback;\n            try {\n                const raw = window.localStorage.getItem(key);\n                return raw === null ? fallback : codec.deserialize<T>(raw);\n            } catch {\n                return fallback;\n            }\n        },\n\n        set<T>(key: string, value: T): void {\n            if (typeof window === \"undefined\") return;\n            const encoded = encode(codec, value);\n            if (encoded === null) return;\n            try {\n                window.localStorage.setItem(key, encoded);\n            } catch {\n                /* empty */\n            }\n        },\n\n        getRaw(key: string): string | null {\n            if (typeof window === \"undefined\") return null;\n            try {\n                return window.localStorage.getItem(key);\n            } catch {\n                return null;\n            }\n        },\n\n        setRaw(key: string, value: string): void {\n            if (typeof window === \"undefined\") return;\n            try {\n                window.localStorage.setItem(key, value);\n            } catch {\n                /* empty */\n            }\n        },\n\n        remove(key: string): void {\n            if (typeof window === \"undefined\") return;\n            try {\n                window.localStorage.removeItem(key);\n            } catch {\n                /* empty */\n            }\n        },\n    };\n}\n\n/**\n * Typed wrapper around `localStorage` that JSON-encodes values and silently\n * handles environments where storage is unavailable (SSR, private mode).\n *\n * `get`/`set` encode; `getRaw`/`setRaw` do not. Reach for the raw pair when the\n * key is shared with something that does not speak JSON — an existing key in an\n * app adopting this wrapper, a key another library owns, or the theme\n * preference the SDK's own `ThemeProvider` stores as a bare string.\n */\nexport const storage: JsonStorage = createJsonStorage();\n"],"mappings":"AAsEA,IAAM,EAA0B,CAC5B,UAAY,GAAU,KAAK,UAAU,CAAK,EAC1C,YAAc,GAAQ,KAAK,MAAM,CAAG,CACxC,EAcA,SAAS,EAAU,EAAqB,EAAyB,CAC7D,GAAI,CACA,OAAO,EAAM,UAAU,CAAK,CAChC,MAAQ,CACJ,GAAI,CACA,OAAO,KAAK,UAAU,CAAK,CAC/B,MAAQ,CACJ,OAAO,IACX,CACJ,CACJ,CA4BA,SAAgB,EAAkB,EAAsB,EAAwB,CAC5E,MAAO,CACH,IAAO,EAAa,EAAgB,CAChC,GAAI,OAAO,OAAW,IAAa,OAAO,EAC1C,GAAI,CACA,IAAM,EAAM,OAAO,aAAa,QAAQ,CAAG,EAC3C,OAAO,IAAQ,KAAO,EAAW,EAAM,YAAe,CAAG,CAC7D,MAAQ,CACJ,OAAO,CACX,CACJ,EAEA,IAAO,EAAa,EAAgB,CAChC,GAAI,OAAO,OAAW,IAAa,OACnC,IAAM,EAAU,EAAO,EAAO,CAAK,EAC/B,OAAY,KAChB,GAAI,CACA,OAAO,aAAa,QAAQ,EAAK,CAAO,CAC5C,MAAQ,CAER,CACJ,EAEA,OAAO,EAA4B,CAC/B,GAAI,OAAO,OAAW,IAAa,OAAO,KAC1C,GAAI,CACA,OAAO,OAAO,aAAa,QAAQ,CAAG,CAC1C,MAAQ,CACJ,OAAO,IACX,CACJ,EAEA,OAAO,EAAa,EAAqB,CACjC,YAAO,OAAW,KACtB,GAAI,CACA,OAAO,aAAa,QAAQ,EAAK,CAAK,CAC1C,MAAQ,CAER,CACJ,EAEA,OAAO,EAAmB,CAClB,YAAO,OAAW,KACtB,GAAI,CACA,OAAO,aAAa,WAAW,CAAG,CACtC,MAAQ,CAER,CACJ,CACJ,CACJ,CAWA,IAAa,EAAuB,EAAkB"}