import * as Context from "effect/Context"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; import * as Schema from "effect/Schema"; import * as SecureStore from "expo-secure-store"; const MobileSecureStorageOperation = Schema.Literals(["read", "write", "delete"]); export class MobileSecureStorageError extends Schema.TaggedError()( "MobileSecureStorageError", { operation: MobileSecureStorageOperation, key: Schema.String, cause: Schema.Defect(), }, ) { override get message(): string { return `Mobile secure storage operation ${this.operation} failed for key ${this.key}.`; } } export class MobileSecureStorage extends Context.Service< MobileSecureStorage, { readonly getItem: (key: string) => Effect.Effect; readonly setItem: (key: string, value: string) => Effect.Effect; readonly removeItem: (key: string) => Effect.Effect; } >()("@t3tools/mobile/persistence/MobileSecureStorage") {} export const make = MobileSecureStorage.of({ getItem: Effect.fn("MobileSecureStorage.getItem")((key) => Effect.tryPromise({ try: () => SecureStore.getItemAsync(key), catch: (cause) => new MobileSecureStorageError({ operation: "read", key, cause }), }), ), setItem: Effect.fn("MobileSecureStorage.setItem")((key, value) => Effect.tryPromise({ try: () => SecureStore.setItemAsync(key, value), catch: (cause) => new MobileSecureStorageError({ operation: "write", key, cause }), }), ), removeItem: Effect.fn("MobileSecureStorage.removeItem")((key) => Effect.tryPromise({ try: () => SecureStore.deleteItemAsync(key), catch: (cause) => new MobileSecureStorageError({ operation: "delete", key, cause }), }), ), }); export const layer = Layer.succeed(MobileSecureStorage, make);