@@ -113,6 +113,79 @@ async function wait(milliseconds) {
113113 } ) ;
114114}
115115
116+ async function callBatch ( POST , baseUrl , requests , boundary = "boundary" ) {
117+ const payload = [ ] ;
118+ for ( const request of requests ) {
119+ payload . push ( `--${ boundary } ` , "Content-Type: application/http" , "" ) ;
120+ payload . push ( `${ request . method } ${ request . url } HTTP/1.1` ) ;
121+ payload . push ( ...( request . headers ?? [ ] ) ) ;
122+ if ( request . body ) {
123+ if ( ! request . headers . find ( ( header ) => {
124+ return header . startsWith ( "Content-Type:" ) ;
125+ } ) ) {
126+ payload . push ( "Content-Type: application/json" ) ;
127+ }
128+ payload . push ( JSON . stringify ( request . body ) ) ;
129+ } else {
130+ payload . push ( "" ) ;
131+ }
132+ }
133+ payload . push ( `--${ boundary } --` ) ;
134+ const response = await POST ( baseUrl , payload . join ( "\r\n" ) , {
135+ headers : {
136+ "Content-Type" : `multipart/mixed; boundary=${ boundary } ` ,
137+ } ,
138+ } ) ;
139+ if ( ! [ 200 , 202 ] . includes ( response . status ) ) {
140+ const message = `Unexpected status \nActual: ${ response . status } , Expected: 202` ;
141+ throw new Error ( message ) ;
142+ }
143+ return {
144+ status : response . status ,
145+ data : splitMultipartResponse ( response . data , boundary ) ,
146+ } ;
147+ }
148+
149+ function splitMultipartResponse ( body , boundary ) {
150+ body = Array . isArray ( body ) ? body . join ( "" ) : body ;
151+ return body
152+ . split ( new RegExp ( `(?:^|\r\n)--${ boundary } (?:\r\n|--\r\n$|--$)` ) )
153+ . slice ( 1 , - 1 )
154+ . map ( ( part ) => {
155+ const [ _meta , ..._rest ] = part . split ( "\r\n\r\n" ) ;
156+ const multipart = _meta . match ( / c o n t e n t - t y p e : \s * m u l t i p a r t \/ m i x e d ; \s * b o u n d a r y = ( [ \w - ] * ) / i) ;
157+ if ( multipart !== null ) {
158+ const subBoundary = multipart [ 1 ] ;
159+ return splitMultipartResponse ( _rest . join ( "\r\n\r\n" ) , subBoundary ) ;
160+ } else {
161+ const contentId = _meta . match ( / c o n t e n t - i d : \s * ( \w + ) / i) || undefined ;
162+ const contentTransferEncoding = _meta . match ( / c o n t e n t - t r a n s f e r - e n c o d i n g : \s * ( \w + ) / i) || undefined ;
163+ const [ _info , _body ] = _rest ;
164+ const body = _body && _body . startsWith ( "{" ) ? JSON . parse ( _body ) : _body ;
165+ const [ _status , ..._headers ] = _info . split ( "\r\n" ) ;
166+ const [ _statusCode , statusText ] = _status . split ( / \s + / ) . slice ( 1 ) ;
167+ const statusCode = parseInt ( _statusCode ) ;
168+ const headers = { } ;
169+ _headers . forEach ( ( _header ) => {
170+ const splitPos = _header . indexOf ( ": " ) ;
171+ if ( splitPos > 0 ) {
172+ headers [ _header . slice ( 0 , splitPos ) ] = _header . slice ( splitPos + 2 ) ;
173+ }
174+ } ) ;
175+ return {
176+ status : statusCode ,
177+ statusCode,
178+ statusText,
179+ headers,
180+ body : statusCode < 400 ? body : undefined ,
181+ error : statusCode >= 400 ? body : undefined ,
182+ contentId : contentId && contentId [ 1 ] ,
183+ contentTransferEncoding : contentTransferEncoding && contentTransferEncoding [ 1 ] ,
184+ } ;
185+ }
186+ } ) ;
187+ }
188+
116189module . exports = {
117190 authorization : {
118191 default : ALICE ,
@@ -125,4 +198,5 @@ module.exports = {
125198 processOutbox,
126199 connectToWS,
127200 wait,
201+ callBatch
128202} ;
0 commit comments