//// Typed access to the Web Storage API. import gleam/dynamic/decode import gleam/json.{type Json} import gleam/result /// An error that occurs when reading. pub type ReadError { /// A value was not found with the given key. NotFound /// The found value could not be decoded. DecodeError(err: json.DecodeError) } pub type WebStorage pub opaque type TypedStorage(a) { TypedStorage( raw_storage: WebStorage, reader: decode.Decoder(a), writer: fn(a) -> Json, ) } /// Get the LocalStorage handle. /// /// Returns an error if the environment does not have LocalStorage available. @external(javascript, "./varasto_ffi.mjs", "local") pub fn local() -> Result(WebStorage, Nil) /// Get the SessionStorage handle. /// /// Returns an error if the environment does not have SessionStorage available. @external(javascript, "./varasto_ffi.mjs", "session") pub fn session() -> Result(WebStorage, Nil) /// Create a new `TypedStorage`. pub fn new( raw_storage: WebStorage, reader: decode.Decoder(a), writer: fn(a) -> Json, ) -> TypedStorage(a) { TypedStorage(raw_storage: raw_storage, reader: reader, writer: writer) } /// Get a value from the storage. pub fn get(storage: TypedStorage(a), key: String) -> Result(a, ReadError) { use str <- result.try( do_get_item(storage.raw_storage, key) |> result.replace_error(NotFound), ) json.parse(str, storage.reader) |> result.map_error(DecodeError) } /// Set a value in the storage. /// /// Returns an error if the writing quota was exceeded. pub fn set(storage: TypedStorage(a), key: String, value: a) -> Result(Nil, Nil) { let encoded = value |> storage.writer() |> json.to_string() do_set_item(storage.raw_storage, key, encoded) } /// Remove a value from the storage. pub fn remove(storage: TypedStorage(a), key: String) -> Nil { do_remove_item(storage.raw_storage, key) } /// Clear the whole storage. /// /// NOTE! This will clear the whole storage, not just values you have set. pub fn clear(storage: TypedStorage(a)) -> Nil { do_clear(storage.raw_storage) } @external(javascript, "./varasto_ffi.mjs", "get") fn do_get_item(raw_storage: WebStorage, key: String) -> Result(String, Nil) @external(javascript, "./varasto_ffi.mjs", "set") fn do_set_item( raw_storage: WebStorage, key: String, encoded: String, ) -> Result(Nil, Nil) @external(javascript, "./varasto_ffi.mjs", "remove") fn do_remove_item(raw_storage: WebStorage, key: String) -> Nil @external(javascript, "./varasto_ffi.mjs", "clear") fn do_clear(raw_storage: WebStorage) -> Nil