66 createBase64DecoderTransformStream ,
77 createBase64EncoderTransformStream ,
88} from 'cloudflare-internal:streaming-base64' ;
9- import { withSpan , type Span } from 'cloudflare-internal:tracing-helpers' ;
109
1110type Fetcher = {
1211 fetch : typeof fetch ;
@@ -122,51 +121,40 @@ class ImageTransformerImpl implements ImageTransformer {
122121 async output (
123122 options : ImageOutputOptions
124123 ) : Promise < ImageTransformationResult > {
125- return await withSpan ( 'images_output' , async ( span ) => {
126- span . setAttribute ( 'cloudflare.binding.type' , 'Images' ) ;
127- const formData = new StreamableFormData ( ) ;
124+ const formData = new StreamableFormData ( ) ;
128125
129- this . #consume( ) ;
130- formData . append ( 'image' , this . #stream, { type : 'file' } ) ;
126+ this . #consume( ) ;
127+ formData . append ( 'image' , this . #stream, { type : 'file' } ) ;
131128
132- this . #serializeTransforms( formData , span ) ;
129+ this . #serializeTransforms( formData ) ;
133130
134- span . setAttribute ( 'cloudflare.images.options.format' , options . format ) ;
135- formData . append ( 'output_format' , options . format ) ;
131+ formData . append ( 'output_format' , options . format ) ;
132+ if ( options . quality !== undefined ) {
133+ formData . append ( 'output_quality' , options . quality . toString ( ) ) ;
134+ }
136135
137- if ( options . quality !== undefined ) {
138- span . setAttribute ( 'cloudflare.images.options.quality' , options . quality ) ;
139- formData . append ( 'output_quality' , options . quality . toString ( ) ) ;
140- }
136+ if ( options . background !== undefined ) {
137+ formData . append ( 'background' , options . background ) ;
138+ }
141139
142- if ( options . background !== undefined ) {
143- span . setAttribute (
144- 'cloudflare.images.options.background' ,
145- options . background
146- ) ;
147- formData . append ( 'background' , options . background ) ;
148- }
140+ if ( options . anim !== undefined ) {
141+ formData . append ( 'anim' , options . anim . toString ( ) ) ;
142+ }
149143
150- if ( options . anim !== undefined ) {
151- span . setAttribute ( 'cloudflare.images.options.anim' , options . anim ) ;
152- formData . append ( 'anim' , options . anim . toString ( ) ) ;
144+ const response = await this . #fetcher. fetch (
145+ 'https://js.images.cloudflare.com/transform' ,
146+ {
147+ method : 'POST' ,
148+ headers : {
149+ 'content-type' : formData . contentType ( ) ,
150+ } ,
151+ body : formData . stream ( ) ,
153152 }
153+ ) ;
154154
155- const response = await this . #fetcher. fetch (
156- 'https://js.images.cloudflare.com/transform' ,
157- {
158- method : 'POST' ,
159- headers : {
160- 'content-type' : formData . contentType ( ) ,
161- } ,
162- body : formData . stream ( ) ,
163- }
164- ) ;
165-
166- await throwErrorIfErrorResponse ( 'TRANSFORM' , response , span ) ;
155+ await throwErrorIfErrorResponse ( 'TRANSFORM' , response ) ;
167156
168- return new TransformationResultImpl ( response ) ;
169- } ) ;
157+ return new TransformationResultImpl ( response ) ;
170158 }
171159
172160 #consume( ) : void {
@@ -180,7 +168,7 @@ class ImageTransformerImpl implements ImageTransformer {
180168 this . #consumed = true ;
181169 }
182170
183- #serializeTransforms( formData : StreamableFormData , span : Span ) : void {
171+ #serializeTransforms( formData : StreamableFormData ) : void {
184172 const transforms : ( TargetedTransform | DrawCommand ) [ ] = [ ] ;
185173
186174 // image 0 is the canvas, so the first draw_image has index 1
@@ -222,16 +210,6 @@ class ImageTransformerImpl implements ImageTransformer {
222210 }
223211
224212 walkTransforms ( 0 , this . #transforms) ;
225-
226- // The transforms are a set of operations which are applied to the image in order.
227- // Attaching an attribute as JSON is a little odd, but I'm not sure if there is
228- // a better way to do this.
229- if ( transforms . length > 0 ) {
230- span . setAttribute (
231- 'cloudflare.images.options.transforms' ,
232- JSON . stringify ( transforms )
233- ) ;
234- }
235213 formData . append ( 'transforms' , JSON . stringify ( transforms ) ) ;
236214 }
237215}
@@ -255,53 +233,40 @@ class ImagesBindingImpl implements ImagesBinding {
255233 stream : ReadableStream < Uint8Array > ,
256234 options ?: ImageInputOptions
257235 ) : Promise < ImageInfoResponse > {
258- return await withSpan ( 'images_info' , async ( span ) => {
259- span . setAttribute ( 'cloudflare.binding.type' , 'Images' ) ;
260- const body = new StreamableFormData ( ) ;
236+ const body = new StreamableFormData ( ) ;
261237
262- span . setAttribute (
263- 'cloudflare.images.options.encoding' ,
264- options ?. encoding ?? 'base64'
265- ) ;
266- const decodedStream =
267- options ?. encoding === 'base64'
268- ? stream . pipeThrough ( createBase64DecoderTransformStream ( ) )
269- : stream ;
270-
271- body . append ( 'image' , decodedStream , { type : 'file' } ) ;
272-
273- const response = await this . #fetcher. fetch (
274- 'https://js.images.cloudflare.com/info' ,
275- {
276- method : 'POST' ,
277- headers : {
278- 'content-type' : body . contentType ( ) ,
279- } ,
280- body : body . stream ( ) ,
281- }
282- ) ;
238+ const decodedStream =
239+ options ?. encoding === 'base64'
240+ ? stream . pipeThrough ( createBase64DecoderTransformStream ( ) )
241+ : stream ;
283242
284- await throwErrorIfErrorResponse ( 'INFO ', response , span ) ;
243+ body . append ( 'image ', decodedStream , { type : 'file' } ) ;
285244
286- const r = ( await response . json ( ) ) as RawInfoResponse ;
245+ const response = await this . #fetcher. fetch (
246+ 'https://js.images.cloudflare.com/info' ,
247+ {
248+ method : 'POST' ,
249+ headers : {
250+ 'content-type' : body . contentType ( ) ,
251+ } ,
252+ body : body . stream ( ) ,
253+ }
254+ ) ;
287255
288- span . setAttribute ( 'cloudflare.images.result.format ', r . format ) ;
256+ await throwErrorIfErrorResponse ( 'INFO ', response ) ;
289257
290- if ( 'file_size' in r ) {
291- const ret = {
292- fileSize : r . file_size ,
293- width : r . width ,
294- height : r . height ,
295- format : r . format ,
296- } ;
297- span . setAttribute ( 'cloudflare.images.result.file_size' , ret . fileSize ) ;
298- span . setAttribute ( 'cloudflare.images.result.width' , ret . width ) ;
299- span . setAttribute ( 'cloudflare.images.result.height' , ret . height ) ;
300- return ret ;
301- }
258+ const r = ( await response . json ( ) ) as RawInfoResponse ;
302259
303- return r ;
304- } ) ;
260+ if ( 'file_size' in r ) {
261+ return {
262+ fileSize : r . file_size ,
263+ width : r . width ,
264+ height : r . height ,
265+ format : r . format ,
266+ } ;
267+ }
268+
269+ return r ;
305270 }
306271
307272 input (
@@ -327,29 +292,24 @@ class ImagesErrorImpl extends Error implements ImagesError {
327292
328293async function throwErrorIfErrorResponse (
329294 operation : string ,
330- response : Response ,
331- span : Span
295+ response : Response
332296) : Promise < void > {
333297 const statusHeader = response . headers . get ( 'cf-images-binding' ) || '' ;
334298
335299 const match = / e r r = ( \d + ) / . exec ( statusHeader ) ;
336300
337301 if ( match && match [ 1 ] ) {
338- const errorMessage = await response . text ( ) ;
339- span . setAttribute ( 'cloudflare.images.error.code' , match [ 1 ] ) ;
340- span . setAttribute ( 'error.type' , errorMessage ) ;
341302 throw new ImagesErrorImpl (
342- `IMAGES_${ operation } _${ errorMessage } ` . trim ( ) ,
303+ `IMAGES_${ operation } _${ await response . text ( ) } ` . trim ( ) ,
343304 Number . parseInt ( match [ 1 ] )
344305 ) ;
345306 }
346307
347308 if ( response . status > 399 ) {
348- const errorMessage = await response . text ( ) ;
349- span . setAttribute ( 'cloudflare.images.error.code' , '9523' ) ;
350- span . setAttribute ( 'error.type' , errorMessage ) ;
351309 throw new ImagesErrorImpl (
352- `Unexpected error response ${ response . status } : ${ errorMessage . trim ( ) } ` ,
310+ `Unexpected error response ${ response . status } : ${ (
311+ await response . text ( )
312+ ) . trim ( ) } `,
353313 9523
354314 ) ;
355315 }
0 commit comments