import KvStorage from "cloudflare-kv-storage-rest" ; import fetch from "node-fetch" ; import FormData from "form-data" ; import { env , hasCloudFlareEnv } from "./env" ; import { kvsEnvStorage } from "@kvs/env" ; import * as fs from "fs" ; import path from "path" ; export type KVValue < Value > = Promise < Value | null > ; export type KVValueWithMetadata < Value , Metadata > = Promise < { value : Value | null ; metadata : Metadata | null ; } > ; export interface KVNamespace { get ( key ) : KVValue < string > ; get ( key , type ) : KVValue < string > ; get < ExpectedValue = unknown > ( key , type ) : KVValue < ExpectedValue > ; get ( key , type ) : KVValue < ArrayBuffer > ; get ( key , type ) : KVValue < ReadableStream > ; getWithMetadata < Metadata = unknown > ( key ) : KVValueWithMetadata < string , Metadata > ; getWithMetadata < Metadata = unknown > ( key , type ) : KVValueWithMetadata < string , Metadata > ; getWithMetadata < ExpectedValue = unknown , Metadata = unknown > ( key , type ) : KVValueWithMetadata < ExpectedValue , Metadata > ; getWithMetadata < Metadata = unknown > ( key , type ) : KVValueWithMetadata < ArrayBuffer , Metadata > ; getWithMetadata < Metadata = unknown > ( key , type ) : KVValueWithMetadata < ReadableStream , Metadata > ; put ( key , value , options ? ) : Promise < void > ; delete ( key ) : Promise < void > ; list ( options ? ) : Promise < { keys : { name : string ; expiration ? : number ; metadata ? : unknown ; } [ ] ; list_complete : boolean ; cursor : string ; } > ; } type Storage < V > = { /**
     * Returns the value associated to the key.
     * If the key does not exist, returns `undefined`.
     */ get : ( key : string ) => Promise < V | undefined > ; /**
     * Sets the value for the key in the storage. Returns the storage.
     */ set : ( key : string , value : V ) => Promise < void > ; /**
     * Returns a boolean asserting whether a value has been associated to the key in the storage.
     */ has : ( key : string ) => Promise < boolean > ; list : ( { prefix , limit , cursor } : { prefix : string ; limit : number ; cursor ? : string ; } ) => Promise < { keys : { name : string ; expiration ? : number ; metadata ? : unknown ; } [ ] ; list_complete : boolean ; cursor : string ; } > ; } ; const createLocalStorage = async < V > ( ) : Promise < Storage < V > > => { const cacheDir = path . resolve ( process . cwd ( ) , ".cache" , "kvs" ) ; await fs . promises . mkdir ( cacheDir , { recursive : true } ) ; const storage = await kvsEnvStorage < any > ( { name : "KVS" , version : 1 , storeFilePath : cacheDir } ) ; return { /**
         * Returns the value associated to the key.
         * If the key does not exist, returns `undefined`.
         */ get : async ( key ) : Promise < V | undefined > => { return storage . get ( key ) ; } , /**
         * Sets the value for the key in the storage. Returns the storage.
         */ set : async ( key , value ) : Promise < void > => { await storage . set ( String ( key ) , value ) ; return ; } , /**
         * Returns a boolean asserting whether a value has been associated to the key in the storage.
         */ has : async ( key ) : Promise < boolean > => { const value = await storage . get ( String ( key ) ) ; return value !== null ; } , list : async ( { prefix , limit } ) : Promise < { keys : { name : string ; expiration ? : number ; metadata ? : unknown ; } [ ] ; list_complete : boolean ; cursor : string ; } > => { const out = [ ] ; for await ( const [ key ] of storage ) { if ( key . startsWith ( prefix ) && out . length < limit ) out . push ( { name : key } ) ; } return { keys : out , list_complete : true , cursor : "" } ; } } ; } ; export const createKVS = async < V > ( ) : Promise < Storage < V > > => { if ( ! hasCloudFlareEnv ( ) ) { return createLocalStorage < V > ( ) ; } const kvStorage = new KvStorage ( { namespace : env . CF_namespace_user ! , accountId : env . CF_accountId ! , authEmail : env . CF_authEmail , authKey : env . CF_authKey ! , fetch , FormData } ) as KVNamespace ; return { /**
         * Returns the value associated to the key.
         * If the key does not exist, returns `undefined`.
         */ get : async ( key ) : Promise < V | undefined > => { const value = await kvStorage . get ( String ( key ) ) ; return value !== null ? JSON . parse ( value ) : undefined ; } , /**
         * Sets the value for the key in the storage. Returns the storage.
         */ set : async ( key , value ) : Promise < void > => { return kvStorage . put ( String ( key ) , JSON . stringify ( value ) ) ; } , /**
         * Returns a boolean asserting whether a value has been associated to the key in the storage.
         */ has : async ( key ) : Promise < boolean > => { const value = await kvStorage . get ( String ( key ) ) ; return value !== null ; } , list : async ( { prefix , limit } ) : Promise < { keys : { name : string ; expiration ? : number ; metadata ? : unknown ; } [ ] ; list_complete : boolean ; cursor : string ; } > => { return kvStorage . list ( { prefix : prefix , limit } ) ; } } ; } ;