@@ -3,12 +3,14 @@ import {
33 DeferredPromise ,
44 DELETE ,
55 GET ,
6+ POST ,
67 HttpError ,
78 KeyValueStorage ,
89 maybeApply ,
910 MiniflareDurableObject ,
1011 PUT ,
1112 RouteHandler ,
13+ KeyValueEntry ,
1214} from "miniflare:shared" ;
1315import { KVHeaders , KVLimits , KVParams } from "./constants" ;
1416import {
@@ -73,6 +75,31 @@ function secondsToMillis(seconds: number): number {
7375 return seconds * 1000 ;
7476}
7577
78+ async function processKeyValue ( obj : KeyValueEntry < unknown > | null , type : string = "text" , withMetadata : boolean = false ) {
79+ const decoder = new TextDecoder ( ) ;
80+ let r = "" ;
81+ if ( obj ?. value ) {
82+ for await ( const chunk of obj ?. value ) {
83+ r += decoder . decode ( chunk , { stream : true } ) ;
84+ }
85+ r += decoder . decode ( ) ;
86+ }
87+
88+ let val = null ;
89+ try {
90+ val = obj ?. value == null ? null : type === "json" ? JSON . parse ( r ) : r ;
91+ } catch ( err : any ) {
92+ throw new HttpError ( 400 , "At least of of the requested keys corresponds to a non-JSON value" ) ;
93+ }
94+ if ( val == null ) {
95+ return null ;
96+ }
97+ if ( withMetadata ) {
98+ return { value : val , metadata : obj ?. metadata ? JSON . stringify ( obj ?. metadata ) : null } ;
99+ }
100+ return val ;
101+ }
102+
76103export class KVNamespaceObject extends MiniflareDurableObject {
77104 #storage?: KeyValueStorage ;
78105 get storage ( ) {
@@ -81,12 +108,31 @@ export class KVNamespaceObject extends MiniflareDurableObject {
81108 }
82109
83110 @GET ( "/:key" )
111+ @POST ( "/bulk/get" )
84112 get : RouteHandler < KVParams > = async ( req , params , url ) => {
85113 // Decode URL parameters
86114 const key = decodeKey ( params , url . searchParams ) ;
87115 const cacheTtlParam = url . searchParams . get ( KVParams . CACHE_TTL ) ;
88116 const cacheTtl =
89117 cacheTtlParam === null ? undefined : parseInt ( cacheTtlParam ) ;
118+ if ( req . body != null ) { // get bulk
119+ // get bulk
120+ let r = "" ;
121+ const decoder = new TextDecoder ( ) ;
122+ for await ( const chunk of req . body ) {
123+ r += decoder . decode ( chunk , { stream : true } ) ;
124+ }
125+ r += decoder . decode ( ) ;
126+ const parsedBody = JSON . parse ( r ) ;
127+ const keys : string [ ] = parsedBody . keys ;
128+ const obj : { [ key : string ] : any } = { } ;
129+ for ( const key of keys ) {
130+ validateGetOptions ( key , { cacheTtl : parsedBody ?. cacheTtl } ) ;
131+ const entry = await this . storage . get ( key ) ;
132+ obj [ key ] = await processKeyValue ( entry , parsedBody ?. type , parsedBody ?. withMetadata ) ;
133+ }
134+ return new Response ( JSON . stringify ( obj ) ) ;
135+ }
90136
91137 // Get value from storage
92138 validateGetOptions ( key , { cacheTtl } ) ;
0 commit comments