@uploadista/flow-images-sharp 0.0.20-beta.8 → 0.0.20-beta.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`node:stream`),l=require(`@uploadista/core/errors`),u=require(`@uploadista/core/flow`),d=require(`@uploadista/observability`),f=require(`effect`),p=require(`sharp`);p=s(p);const m=e=>{switch(e){case`fill`:return`cover`;case`contain`:return`contain`}},h=(e,t,n,r,i,a=0,o=0)=>{let s=0,c=0;switch(e){case`top-left`:s=o,c=a;break;case`top-right`:s=o,c=t-r-a;break;case`bottom-left`:s=n-i-o,c=a;break;case`bottom-right`:s=n-i-o,c=t-r-a;break;case`center`:s=Math.floor((n-i)/2)+o,c=Math.floor((t-r)/2)+a;break}return{top:s,left:c}},g=f.Layer.succeed(u.ImagePlugin,u.ImagePlugin.of({optimize:(e,{quality:t,format:n})=>f.Effect.gen(function*(){let r=yield*f.Effect.tryPromise({try:async()=>await(0,p.default)(e).toFormat(n,{quality:t}).toBuffer(),catch:e=>l.UploadistaError.fromCode(`UNKNOWN_ERROR`,{cause:e})});return new Uint8Array(r)}).pipe((0,d.withOperationSpan)(`image`,`optimize`,{"image.format":n,"image.quality":t,"image.input_size":e.byteLength})),resize:(e,{width:t,height:n,fit:r})=>f.Effect.gen(function*(){if(!t&&!n)throw Error(`Either width or height must be specified for resize`);let i=m(r),a=yield*f.Effect.tryPromise({try:async()=>await(0,p.default)(e).resize(t,n,{fit:i}).toBuffer(),catch:e=>l.UploadistaError.fromCode(`UNKNOWN_ERROR`,{cause:e})});return new Uint8Array(a)}).pipe((0,d.withOperationSpan)(`image`,`resize`,{"image.width":t,"image.height":n,"image.fit":r,"image.input_size":e.byteLength})),transform:(e,t)=>f.Effect.gen(function*(){let n=(0,p.default)(e);switch(t.type){case`resize`:{let e=m(t.fit);n=n.resize(t.width,t.height,{fit:e});break}case`blur`:n=n.blur(t.sigma);break;case`rotate`:{let e=t.background?{background:t.background}:void 0;n=n.rotate(t.angle,e);break}case`flip`:n=t.direction===`horizontal`?n.flop():n.flip();break;case`grayscale`:n=n.grayscale();break;case`sepia`:n=n.tint({r:112,g:66,b:20});break;case`brightness`:{let e=1+t.value/100;n=n.modulate({brightness:e});break}case`contrast`:{let e=1+t.value/100;n=n.linear(e,0);break}case`sharpen`:n=t.sigma===void 0?n.sharpen():n.sharpen({sigma:t.sigma});break;case`watermark`:{let e=yield*f.Effect.tryPromise({try:async()=>{let e=await fetch(t.imagePath);if(!e.ok)throw Error(`Failed to fetch watermark: ${e.statusText}`);let n=await e.arrayBuffer();return Buffer.from(n)},catch:e=>l.UploadistaError.fromCode(`FILE_NOT_FOUND`,{body:`Watermark image not found or failed to fetch: ${t.imagePath}`,cause:e})}).pipe((0,d.withOperationSpan)(`image`,`fetch-watermark`,{"image.watermark_url":t.imagePath})),r=yield*f.Effect.tryPromise({try:async()=>await n.metadata(),catch:e=>l.UploadistaError.fromCode(`UNKNOWN_ERROR`,{body:`Failed to read image metadata`,cause:e})}),i=yield*f.Effect.tryPromise({try:async()=>await(0,p.default)(e).metadata(),catch:e=>l.UploadistaError.fromCode(`UNKNOWN_ERROR`,{body:`Failed to read watermark metadata`,cause:e})});if(!r.width||!r.height||!i.width||!i.height)return yield*f.Effect.fail(l.UploadistaError.fromCode(`UNKNOWN_ERROR`,{body:`Could not determine image or watermark dimensions`}));let{top:a,left:o}=h(t.position,r.width,r.height,i.width,i.height,t.offsetX,t.offsetY),s=yield*f.Effect.tryPromise({try:async()=>await(0,p.default)(e).composite([{input:Buffer.from([255,255,255,Math.round(t.opacity*255)]),raw:{width:1,height:1,channels:4},tile:!0,blend:`dest-in`}]).toBuffer(),catch:e=>l.UploadistaError.fromCode(`UNKNOWN_ERROR`,{body:`Failed to apply watermark opacity`,cause:e})});n=n.composite([{input:s,top:a,left:o}]);break}case`logo`:{let e=yield*f.Effect.tryPromise({try:async()=>{let e=await fetch(t.imagePath);if(!e.ok)throw Error(`Failed to fetch logo: ${e.statusText}`);let n=await e.arrayBuffer();return Buffer.from(n)},catch:e=>l.UploadistaError.fromCode(`FILE_NOT_FOUND`,{body:`Logo image not found or failed to fetch: ${t.imagePath}`,cause:e})}).pipe((0,d.withOperationSpan)(`image`,`fetch-logo`,{"image.logo_url":t.imagePath})),r=yield*f.Effect.tryPromise({try:async()=>await n.metadata(),catch:e=>l.UploadistaError.fromCode(`UNKNOWN_ERROR`,{body:`Failed to read image metadata`,cause:e})}),i=yield*f.Effect.tryPromise({try:async()=>await(0,p.default)(e).metadata(),catch:e=>l.UploadistaError.fromCode(`UNKNOWN_ERROR`,{body:`Failed to read logo metadata`,cause:e})});if(!r.width||!r.height||!i.width||!i.height)return yield*f.Effect.fail(l.UploadistaError.fromCode(`UNKNOWN_ERROR`,{body:`Could not determine image or logo dimensions`}));let a=Math.round(i.width*t.scale),o=Math.round(i.height*t.scale),s=yield*f.Effect.tryPromise({try:async()=>await(0,p.default)(e).resize(a,o).toBuffer(),catch:e=>l.UploadistaError.fromCode(`UNKNOWN_ERROR`,{body:`Failed to scale logo`,cause:e})}),{top:c,left:u}=h(t.position,r.width,r.height,a,o,t.offsetX,t.offsetY);n=n.composite([{input:s,top:c,left:u}]);break}case`text`:{let e=yield*f.Effect.tryPromise({try:async()=>await n.metadata(),catch:e=>l.UploadistaError.fromCode(`UNKNOWN_ERROR`,{body:`Failed to read image metadata`,cause:e})});if(!e.width||!e.height)return yield*f.Effect.fail(l.UploadistaError.fromCode(`UNKNOWN_ERROR`,{body:`Could not determine image dimensions`}));let r=t.fontFamily||`sans-serif`,i=t.text.length*t.fontSize*.6,a=t.fontSize,{top:o,left:s}=h(t.position,e.width,e.height,i,a,t.offsetX,t.offsetY),c=`
1
+ var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`node:stream`),l=require(`@uploadista/core/errors`),u=require(`@uploadista/core/flow`),d=require(`@uploadista/observability`),f=require(`effect`),p=require(`sharp`);p=s(p);const m=e=>{switch(e){case`fill`:return`cover`;case`contain`:return`contain`}},h=(e,t,n,r,i,a=0,o=0)=>{let s=0,c=0;switch(e){case`top-left`:s=o,c=a;break;case`top-right`:s=o,c=t-r-a;break;case`bottom-left`:s=n-i-o,c=a;break;case`bottom-right`:s=n-i-o,c=t-r-a;break;case`center`:s=Math.floor((n-i)/2)+o,c=Math.floor((t-r)/2)+a;break}return{top:s,left:c}},g=()=>f.Layer.succeed(u.ImagePlugin,u.ImagePlugin.of({optimize:(e,{quality:t,format:n})=>f.Effect.gen(function*(){let r=yield*f.Effect.tryPromise({try:async()=>await(0,p.default)(e).toFormat(n,{quality:t}).toBuffer(),catch:e=>l.UploadistaError.fromCode(`UNKNOWN_ERROR`,{cause:e})});return new Uint8Array(r)}).pipe((0,d.withOperationSpan)(`image`,`optimize`,{"image.format":n,"image.quality":t,"image.input_size":e.byteLength})),resize:(e,{width:t,height:n,fit:r})=>f.Effect.gen(function*(){if(!t&&!n)throw Error(`Either width or height must be specified for resize`);let i=m(r),a=yield*f.Effect.tryPromise({try:async()=>await(0,p.default)(e).resize(t,n,{fit:i}).toBuffer(),catch:e=>l.UploadistaError.fromCode(`UNKNOWN_ERROR`,{cause:e})});return new Uint8Array(a)}).pipe((0,d.withOperationSpan)(`image`,`resize`,{"image.width":t,"image.height":n,"image.fit":r,"image.input_size":e.byteLength})),transform:(e,t)=>f.Effect.gen(function*(){let n=(0,p.default)(e);switch(t.type){case`resize`:{let e=m(t.fit);n=n.resize(t.width,t.height,{fit:e});break}case`blur`:n=n.blur(t.sigma);break;case`rotate`:{let e=t.background?{background:t.background}:void 0;n=n.rotate(t.angle,e);break}case`flip`:n=t.direction===`horizontal`?n.flop():n.flip();break;case`grayscale`:n=n.grayscale();break;case`sepia`:n=n.tint({r:112,g:66,b:20});break;case`brightness`:{let e=1+t.value/100;n=n.modulate({brightness:e});break}case`contrast`:{let e=1+t.value/100;n=n.linear(e,0);break}case`sharpen`:n=t.sigma===void 0?n.sharpen():n.sharpen({sigma:t.sigma});break;case`watermark`:{let e=yield*f.Effect.tryPromise({try:async()=>{let e=await fetch(t.imagePath);if(!e.ok)throw Error(`Failed to fetch watermark: ${e.statusText}`);let n=await e.arrayBuffer();return Buffer.from(n)},catch:e=>l.UploadistaError.fromCode(`FILE_NOT_FOUND`,{body:`Watermark image not found or failed to fetch: ${t.imagePath}`,cause:e})}).pipe((0,d.withOperationSpan)(`image`,`fetch-watermark`,{"image.watermark_url":t.imagePath})),r=yield*f.Effect.tryPromise({try:async()=>await n.metadata(),catch:e=>l.UploadistaError.fromCode(`UNKNOWN_ERROR`,{body:`Failed to read image metadata`,cause:e})}),i=yield*f.Effect.tryPromise({try:async()=>await(0,p.default)(e).metadata(),catch:e=>l.UploadistaError.fromCode(`UNKNOWN_ERROR`,{body:`Failed to read watermark metadata`,cause:e})});if(!r.width||!r.height||!i.width||!i.height)return yield*f.Effect.fail(l.UploadistaError.fromCode(`UNKNOWN_ERROR`,{body:`Could not determine image or watermark dimensions`}));let{top:a,left:o}=h(t.position,r.width,r.height,i.width,i.height,t.offsetX,t.offsetY),s=yield*f.Effect.tryPromise({try:async()=>await(0,p.default)(e).composite([{input:Buffer.from([255,255,255,Math.round(t.opacity*255)]),raw:{width:1,height:1,channels:4},tile:!0,blend:`dest-in`}]).toBuffer(),catch:e=>l.UploadistaError.fromCode(`UNKNOWN_ERROR`,{body:`Failed to apply watermark opacity`,cause:e})});n=n.composite([{input:s,top:a,left:o}]);break}case`logo`:{let e=yield*f.Effect.tryPromise({try:async()=>{let e=await fetch(t.imagePath);if(!e.ok)throw Error(`Failed to fetch logo: ${e.statusText}`);let n=await e.arrayBuffer();return Buffer.from(n)},catch:e=>l.UploadistaError.fromCode(`FILE_NOT_FOUND`,{body:`Logo image not found or failed to fetch: ${t.imagePath}`,cause:e})}).pipe((0,d.withOperationSpan)(`image`,`fetch-logo`,{"image.logo_url":t.imagePath})),r=yield*f.Effect.tryPromise({try:async()=>await n.metadata(),catch:e=>l.UploadistaError.fromCode(`UNKNOWN_ERROR`,{body:`Failed to read image metadata`,cause:e})}),i=yield*f.Effect.tryPromise({try:async()=>await(0,p.default)(e).metadata(),catch:e=>l.UploadistaError.fromCode(`UNKNOWN_ERROR`,{body:`Failed to read logo metadata`,cause:e})});if(!r.width||!r.height||!i.width||!i.height)return yield*f.Effect.fail(l.UploadistaError.fromCode(`UNKNOWN_ERROR`,{body:`Could not determine image or logo dimensions`}));let a=Math.round(i.width*t.scale),o=Math.round(i.height*t.scale),s=yield*f.Effect.tryPromise({try:async()=>await(0,p.default)(e).resize(a,o).toBuffer(),catch:e=>l.UploadistaError.fromCode(`UNKNOWN_ERROR`,{body:`Failed to scale logo`,cause:e})}),{top:c,left:u}=h(t.position,r.width,r.height,a,o,t.offsetX,t.offsetY);n=n.composite([{input:s,top:c,left:u}]);break}case`text`:{let e=yield*f.Effect.tryPromise({try:async()=>await n.metadata(),catch:e=>l.UploadistaError.fromCode(`UNKNOWN_ERROR`,{body:`Failed to read image metadata`,cause:e})});if(!e.width||!e.height)return yield*f.Effect.fail(l.UploadistaError.fromCode(`UNKNOWN_ERROR`,{body:`Could not determine image dimensions`}));let r=t.fontFamily||`sans-serif`,i=t.text.length*t.fontSize*.6,a=t.fontSize,{top:o,left:s}=h(t.position,e.width,e.height,i,a,t.offsetX,t.offsetY),c=`
2
2
  <svg width="${e.width}" height="${e.height}">
3
3
  <text
4
4
  x="${s}"
package/dist/index.d.cts CHANGED
@@ -2,7 +2,7 @@ import { ImagePlugin } from "@uploadista/core/flow";
2
2
  import { Layer } from "effect";
3
3
 
4
4
  //#region src/image-plugin.d.ts
5
- declare const imagePlugin: Layer.Layer<ImagePlugin, never, never>;
5
+ declare const imagePlugin: () => Layer.Layer<ImagePlugin, never, never>;
6
6
  //#endregion
7
7
  export { imagePlugin };
8
8
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/image-plugin.ts"],"sourcesContent":[],"mappings":";;;;cA8Da,aAAW,KAAA,CAAA,MAAA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/image-plugin.ts"],"sourcesContent":[],"mappings":";;;;cA8Da,mBAAW,KAAA,CAAA,MAAA"}
package/dist/index.d.mts CHANGED
@@ -2,7 +2,7 @@ import { ImagePlugin } from "@uploadista/core/flow";
2
2
  import { Layer } from "effect";
3
3
 
4
4
  //#region src/image-plugin.d.ts
5
- declare const imagePlugin: Layer.Layer<ImagePlugin, never, never>;
5
+ declare const imagePlugin: () => Layer.Layer<ImagePlugin, never, never>;
6
6
  //#endregion
7
7
  export { imagePlugin };
8
8
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/image-plugin.ts"],"sourcesContent":[],"mappings":";;;;cA8Da,aAAW,KAAA,CAAA,MAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/image-plugin.ts"],"sourcesContent":[],"mappings":";;;;cA8Da,mBAAW,KAAA,CAAA,MAAA"}
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import{PassThrough as e}from"node:stream";import{UploadistaError as t}from"@uploadista/core/errors";import{ImagePlugin as n}from"@uploadista/core/flow";import{withOperationSpan as r}from"@uploadista/observability";import{Effect as i,Layer as a,Stream as o}from"effect";import s from"sharp";const c=e=>{switch(e){case`fill`:return`cover`;case`contain`:return`contain`}},l=(e,t,n,r,i,a=0,o=0)=>{let s=0,c=0;switch(e){case`top-left`:s=o,c=a;break;case`top-right`:s=o,c=t-r-a;break;case`bottom-left`:s=n-i-o,c=a;break;case`bottom-right`:s=n-i-o,c=t-r-a;break;case`center`:s=Math.floor((n-i)/2)+o,c=Math.floor((t-r)/2)+a;break}return{top:s,left:c}},u=a.succeed(n,n.of({optimize:(e,{quality:n,format:a})=>i.gen(function*(){let r=yield*i.tryPromise({try:async()=>await s(e).toFormat(a,{quality:n}).toBuffer(),catch:e=>t.fromCode(`UNKNOWN_ERROR`,{cause:e})});return new Uint8Array(r)}).pipe(r(`image`,`optimize`,{"image.format":a,"image.quality":n,"image.input_size":e.byteLength})),resize:(e,{width:n,height:a,fit:o})=>i.gen(function*(){if(!n&&!a)throw Error(`Either width or height must be specified for resize`);let r=c(o),l=yield*i.tryPromise({try:async()=>await s(e).resize(n,a,{fit:r}).toBuffer(),catch:e=>t.fromCode(`UNKNOWN_ERROR`,{cause:e})});return new Uint8Array(l)}).pipe(r(`image`,`resize`,{"image.width":n,"image.height":a,"image.fit":o,"image.input_size":e.byteLength})),transform:(e,n)=>i.gen(function*(){let a=s(e);switch(n.type){case`resize`:{let e=c(n.fit);a=a.resize(n.width,n.height,{fit:e});break}case`blur`:a=a.blur(n.sigma);break;case`rotate`:{let e=n.background?{background:n.background}:void 0;a=a.rotate(n.angle,e);break}case`flip`:a=n.direction===`horizontal`?a.flop():a.flip();break;case`grayscale`:a=a.grayscale();break;case`sepia`:a=a.tint({r:112,g:66,b:20});break;case`brightness`:{let e=1+n.value/100;a=a.modulate({brightness:e});break}case`contrast`:{let e=1+n.value/100;a=a.linear(e,0);break}case`sharpen`:a=n.sigma===void 0?a.sharpen():a.sharpen({sigma:n.sigma});break;case`watermark`:{let e=yield*i.tryPromise({try:async()=>{let e=await fetch(n.imagePath);if(!e.ok)throw Error(`Failed to fetch watermark: ${e.statusText}`);let t=await e.arrayBuffer();return Buffer.from(t)},catch:e=>t.fromCode(`FILE_NOT_FOUND`,{body:`Watermark image not found or failed to fetch: ${n.imagePath}`,cause:e})}).pipe(r(`image`,`fetch-watermark`,{"image.watermark_url":n.imagePath})),o=yield*i.tryPromise({try:async()=>await a.metadata(),catch:e=>t.fromCode(`UNKNOWN_ERROR`,{body:`Failed to read image metadata`,cause:e})}),c=yield*i.tryPromise({try:async()=>await s(e).metadata(),catch:e=>t.fromCode(`UNKNOWN_ERROR`,{body:`Failed to read watermark metadata`,cause:e})});if(!o.width||!o.height||!c.width||!c.height)return yield*i.fail(t.fromCode(`UNKNOWN_ERROR`,{body:`Could not determine image or watermark dimensions`}));let{top:u,left:d}=l(n.position,o.width,o.height,c.width,c.height,n.offsetX,n.offsetY),f=yield*i.tryPromise({try:async()=>await s(e).composite([{input:Buffer.from([255,255,255,Math.round(n.opacity*255)]),raw:{width:1,height:1,channels:4},tile:!0,blend:`dest-in`}]).toBuffer(),catch:e=>t.fromCode(`UNKNOWN_ERROR`,{body:`Failed to apply watermark opacity`,cause:e})});a=a.composite([{input:f,top:u,left:d}]);break}case`logo`:{let e=yield*i.tryPromise({try:async()=>{let e=await fetch(n.imagePath);if(!e.ok)throw Error(`Failed to fetch logo: ${e.statusText}`);let t=await e.arrayBuffer();return Buffer.from(t)},catch:e=>t.fromCode(`FILE_NOT_FOUND`,{body:`Logo image not found or failed to fetch: ${n.imagePath}`,cause:e})}).pipe(r(`image`,`fetch-logo`,{"image.logo_url":n.imagePath})),o=yield*i.tryPromise({try:async()=>await a.metadata(),catch:e=>t.fromCode(`UNKNOWN_ERROR`,{body:`Failed to read image metadata`,cause:e})}),c=yield*i.tryPromise({try:async()=>await s(e).metadata(),catch:e=>t.fromCode(`UNKNOWN_ERROR`,{body:`Failed to read logo metadata`,cause:e})});if(!o.width||!o.height||!c.width||!c.height)return yield*i.fail(t.fromCode(`UNKNOWN_ERROR`,{body:`Could not determine image or logo dimensions`}));let u=Math.round(c.width*n.scale),d=Math.round(c.height*n.scale),f=yield*i.tryPromise({try:async()=>await s(e).resize(u,d).toBuffer(),catch:e=>t.fromCode(`UNKNOWN_ERROR`,{body:`Failed to scale logo`,cause:e})}),{top:p,left:m}=l(n.position,o.width,o.height,u,d,n.offsetX,n.offsetY);a=a.composite([{input:f,top:p,left:m}]);break}case`text`:{let e=yield*i.tryPromise({try:async()=>await a.metadata(),catch:e=>t.fromCode(`UNKNOWN_ERROR`,{body:`Failed to read image metadata`,cause:e})});if(!e.width||!e.height)return yield*i.fail(t.fromCode(`UNKNOWN_ERROR`,{body:`Could not determine image dimensions`}));let r=n.fontFamily||`sans-serif`,o=n.text.length*n.fontSize*.6,s=n.fontSize,{top:c,left:u}=l(n.position,e.width,e.height,o,s,n.offsetX,n.offsetY),d=`
1
+ import{PassThrough as e}from"node:stream";import{UploadistaError as t}from"@uploadista/core/errors";import{ImagePlugin as n}from"@uploadista/core/flow";import{withOperationSpan as r}from"@uploadista/observability";import{Effect as i,Layer as a,Stream as o}from"effect";import s from"sharp";const c=e=>{switch(e){case`fill`:return`cover`;case`contain`:return`contain`}},l=(e,t,n,r,i,a=0,o=0)=>{let s=0,c=0;switch(e){case`top-left`:s=o,c=a;break;case`top-right`:s=o,c=t-r-a;break;case`bottom-left`:s=n-i-o,c=a;break;case`bottom-right`:s=n-i-o,c=t-r-a;break;case`center`:s=Math.floor((n-i)/2)+o,c=Math.floor((t-r)/2)+a;break}return{top:s,left:c}},u=()=>a.succeed(n,n.of({optimize:(e,{quality:n,format:a})=>i.gen(function*(){let r=yield*i.tryPromise({try:async()=>await s(e).toFormat(a,{quality:n}).toBuffer(),catch:e=>t.fromCode(`UNKNOWN_ERROR`,{cause:e})});return new Uint8Array(r)}).pipe(r(`image`,`optimize`,{"image.format":a,"image.quality":n,"image.input_size":e.byteLength})),resize:(e,{width:n,height:a,fit:o})=>i.gen(function*(){if(!n&&!a)throw Error(`Either width or height must be specified for resize`);let r=c(o),l=yield*i.tryPromise({try:async()=>await s(e).resize(n,a,{fit:r}).toBuffer(),catch:e=>t.fromCode(`UNKNOWN_ERROR`,{cause:e})});return new Uint8Array(l)}).pipe(r(`image`,`resize`,{"image.width":n,"image.height":a,"image.fit":o,"image.input_size":e.byteLength})),transform:(e,n)=>i.gen(function*(){let a=s(e);switch(n.type){case`resize`:{let e=c(n.fit);a=a.resize(n.width,n.height,{fit:e});break}case`blur`:a=a.blur(n.sigma);break;case`rotate`:{let e=n.background?{background:n.background}:void 0;a=a.rotate(n.angle,e);break}case`flip`:a=n.direction===`horizontal`?a.flop():a.flip();break;case`grayscale`:a=a.grayscale();break;case`sepia`:a=a.tint({r:112,g:66,b:20});break;case`brightness`:{let e=1+n.value/100;a=a.modulate({brightness:e});break}case`contrast`:{let e=1+n.value/100;a=a.linear(e,0);break}case`sharpen`:a=n.sigma===void 0?a.sharpen():a.sharpen({sigma:n.sigma});break;case`watermark`:{let e=yield*i.tryPromise({try:async()=>{let e=await fetch(n.imagePath);if(!e.ok)throw Error(`Failed to fetch watermark: ${e.statusText}`);let t=await e.arrayBuffer();return Buffer.from(t)},catch:e=>t.fromCode(`FILE_NOT_FOUND`,{body:`Watermark image not found or failed to fetch: ${n.imagePath}`,cause:e})}).pipe(r(`image`,`fetch-watermark`,{"image.watermark_url":n.imagePath})),o=yield*i.tryPromise({try:async()=>await a.metadata(),catch:e=>t.fromCode(`UNKNOWN_ERROR`,{body:`Failed to read image metadata`,cause:e})}),c=yield*i.tryPromise({try:async()=>await s(e).metadata(),catch:e=>t.fromCode(`UNKNOWN_ERROR`,{body:`Failed to read watermark metadata`,cause:e})});if(!o.width||!o.height||!c.width||!c.height)return yield*i.fail(t.fromCode(`UNKNOWN_ERROR`,{body:`Could not determine image or watermark dimensions`}));let{top:u,left:d}=l(n.position,o.width,o.height,c.width,c.height,n.offsetX,n.offsetY),f=yield*i.tryPromise({try:async()=>await s(e).composite([{input:Buffer.from([255,255,255,Math.round(n.opacity*255)]),raw:{width:1,height:1,channels:4},tile:!0,blend:`dest-in`}]).toBuffer(),catch:e=>t.fromCode(`UNKNOWN_ERROR`,{body:`Failed to apply watermark opacity`,cause:e})});a=a.composite([{input:f,top:u,left:d}]);break}case`logo`:{let e=yield*i.tryPromise({try:async()=>{let e=await fetch(n.imagePath);if(!e.ok)throw Error(`Failed to fetch logo: ${e.statusText}`);let t=await e.arrayBuffer();return Buffer.from(t)},catch:e=>t.fromCode(`FILE_NOT_FOUND`,{body:`Logo image not found or failed to fetch: ${n.imagePath}`,cause:e})}).pipe(r(`image`,`fetch-logo`,{"image.logo_url":n.imagePath})),o=yield*i.tryPromise({try:async()=>await a.metadata(),catch:e=>t.fromCode(`UNKNOWN_ERROR`,{body:`Failed to read image metadata`,cause:e})}),c=yield*i.tryPromise({try:async()=>await s(e).metadata(),catch:e=>t.fromCode(`UNKNOWN_ERROR`,{body:`Failed to read logo metadata`,cause:e})});if(!o.width||!o.height||!c.width||!c.height)return yield*i.fail(t.fromCode(`UNKNOWN_ERROR`,{body:`Could not determine image or logo dimensions`}));let u=Math.round(c.width*n.scale),d=Math.round(c.height*n.scale),f=yield*i.tryPromise({try:async()=>await s(e).resize(u,d).toBuffer(),catch:e=>t.fromCode(`UNKNOWN_ERROR`,{body:`Failed to scale logo`,cause:e})}),{top:p,left:m}=l(n.position,o.width,o.height,u,d,n.offsetX,n.offsetY);a=a.composite([{input:f,top:p,left:m}]);break}case`text`:{let e=yield*i.tryPromise({try:async()=>await a.metadata(),catch:e=>t.fromCode(`UNKNOWN_ERROR`,{body:`Failed to read image metadata`,cause:e})});if(!e.width||!e.height)return yield*i.fail(t.fromCode(`UNKNOWN_ERROR`,{body:`Could not determine image dimensions`}));let r=n.fontFamily||`sans-serif`,o=n.text.length*n.fontSize*.6,s=n.fontSize,{top:c,left:u}=l(n.position,e.width,e.height,o,s,n.offsetX,n.offsetY),d=`
2
2
  <svg width="${e.width}" height="${e.height}">
3
3
  <text
4
4
  x="${u}"
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["chunks: Uint8Array[]","outputChunks: Buffer[]"],"sources":["../src/image-plugin.ts"],"sourcesContent":["import { PassThrough } from \"node:stream\";\nimport { UploadistaError } from \"@uploadista/core/errors\";\nimport {\n ImagePlugin,\n type OptimizeParams,\n type ResizeParams,\n type Transformation,\n} from \"@uploadista/core/flow\";\nimport { withOperationSpan } from \"@uploadista/observability\";\nimport { Effect, Layer, Stream } from \"effect\";\nimport sharp from \"sharp\";\n\nconst mapFitToSharp = (fit: \"fill\" | \"contain\" | \"cover\") => {\n switch (fit) {\n case \"fill\":\n return \"cover\";\n case \"contain\":\n return \"contain\";\n }\n};\n\n/**\n * Calculate position coordinates for overlays based on position string and offsets.\n */\nconst calculateOverlayPosition = (\n position: string,\n imageWidth: number,\n imageHeight: number,\n overlayWidth: number,\n overlayHeight: number,\n offsetX = 0,\n offsetY = 0,\n): { top: number; left: number } => {\n let top = 0;\n let left = 0;\n\n switch (position) {\n case \"top-left\":\n top = offsetY;\n left = offsetX;\n break;\n case \"top-right\":\n top = offsetY;\n left = imageWidth - overlayWidth - offsetX;\n break;\n case \"bottom-left\":\n top = imageHeight - overlayHeight - offsetY;\n left = offsetX;\n break;\n case \"bottom-right\":\n top = imageHeight - overlayHeight - offsetY;\n left = imageWidth - overlayWidth - offsetX;\n break;\n case \"center\":\n top = Math.floor((imageHeight - overlayHeight) / 2) + offsetY;\n left = Math.floor((imageWidth - overlayWidth) / 2) + offsetX;\n break;\n }\n\n return { top, left };\n};\n\nexport const imagePlugin = Layer.succeed(\n ImagePlugin,\n ImagePlugin.of({\n optimize: (inputBytes, { quality, format }) => {\n return Effect.gen(function* () {\n const outputBytes = yield* Effect.tryPromise({\n try: async () =>\n await sharp(inputBytes).toFormat(format, { quality }).toBuffer(),\n catch: (error) => {\n return UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n cause: error,\n });\n },\n });\n return new Uint8Array(outputBytes);\n }).pipe(\n withOperationSpan(\"image\", \"optimize\", {\n \"image.format\": format,\n \"image.quality\": quality,\n \"image.input_size\": inputBytes.byteLength,\n }),\n );\n },\n resize: (inputBytes, { width, height, fit }) => {\n return Effect.gen(function* () {\n if (!width && !height) {\n throw new Error(\n \"Either width or height must be specified for resize\",\n );\n }\n\n const sharpFit = mapFitToSharp(fit);\n const outputBytes = yield* Effect.tryPromise({\n try: async () =>\n await sharp(inputBytes)\n .resize(width, height, { fit: sharpFit })\n .toBuffer(),\n catch: (error) => {\n return UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n cause: error,\n });\n },\n });\n\n return new Uint8Array(outputBytes);\n }).pipe(\n withOperationSpan(\"image\", \"resize\", {\n \"image.width\": width,\n \"image.height\": height,\n \"image.fit\": fit,\n \"image.input_size\": inputBytes.byteLength,\n }),\n );\n },\n transform: (inputBytes, transformation) => {\n return Effect.gen(function* () {\n let pipeline = sharp(inputBytes);\n\n switch (transformation.type) {\n case \"resize\": {\n const sharpFit = mapFitToSharp(transformation.fit);\n pipeline = pipeline.resize(\n transformation.width,\n transformation.height,\n {\n fit: sharpFit,\n },\n );\n break;\n }\n\n case \"blur\": {\n pipeline = pipeline.blur(transformation.sigma);\n break;\n }\n\n case \"rotate\": {\n const options = transformation.background\n ? { background: transformation.background }\n : undefined;\n pipeline = pipeline.rotate(transformation.angle, options);\n break;\n }\n\n case \"flip\": {\n if (transformation.direction === \"horizontal\") {\n pipeline = pipeline.flop();\n } else {\n pipeline = pipeline.flip();\n }\n break;\n }\n\n case \"grayscale\": {\n pipeline = pipeline.grayscale();\n break;\n }\n\n case \"sepia\": {\n // Apply sepia tone using tint\n pipeline = pipeline.tint({ r: 112, g: 66, b: 20 });\n break;\n }\n\n case \"brightness\": {\n // Convert -100 to +100 range to multiplier (0 to 2)\n const multiplier = 1 + transformation.value / 100;\n pipeline = pipeline.modulate({ brightness: multiplier });\n break;\n }\n\n case \"contrast\": {\n // Convert -100 to +100 range to linear adjustment\n const a = 1 + transformation.value / 100;\n pipeline = pipeline.linear(a, 0);\n break;\n }\n\n case \"sharpen\": {\n if (transformation.sigma !== undefined) {\n pipeline = pipeline.sharpen({ sigma: transformation.sigma });\n } else {\n pipeline = pipeline.sharpen();\n }\n break;\n }\n\n case \"watermark\": {\n // Fetch watermark image from URL\n const watermarkBuffer = yield* Effect.tryPromise({\n try: async () => {\n const response = await fetch(transformation.imagePath);\n if (!response.ok) {\n throw new Error(\n `Failed to fetch watermark: ${response.statusText}`,\n );\n }\n const arrayBuffer = await response.arrayBuffer();\n return Buffer.from(arrayBuffer);\n },\n catch: (error) => {\n return UploadistaError.fromCode(\"FILE_NOT_FOUND\", {\n body: `Watermark image not found or failed to fetch: ${transformation.imagePath}`,\n cause: error,\n });\n },\n }).pipe(\n withOperationSpan(\"image\", \"fetch-watermark\", {\n \"image.watermark_url\": transformation.imagePath,\n }),\n );\n\n // Get image metadata to calculate positioning\n const metadata = yield* Effect.tryPromise({\n try: async () => await pipeline.metadata(),\n catch: (error) => {\n return UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: \"Failed to read image metadata\",\n cause: error,\n });\n },\n });\n\n // Get watermark metadata\n const watermarkMetadata = yield* Effect.tryPromise({\n try: async () => await sharp(watermarkBuffer).metadata(),\n catch: (error) => {\n return UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: \"Failed to read watermark metadata\",\n cause: error,\n });\n },\n });\n\n if (\n !metadata.width ||\n !metadata.height ||\n !watermarkMetadata.width ||\n !watermarkMetadata.height\n ) {\n return yield* Effect.fail(\n UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: \"Could not determine image or watermark dimensions\",\n }),\n );\n }\n\n const { top, left } = calculateOverlayPosition(\n transformation.position,\n metadata.width,\n metadata.height,\n watermarkMetadata.width,\n watermarkMetadata.height,\n transformation.offsetX,\n transformation.offsetY,\n );\n\n // Apply watermark with opacity\n const watermarkWithOpacity = yield* Effect.tryPromise({\n try: async () =>\n await sharp(watermarkBuffer)\n .composite([\n {\n input: Buffer.from([\n 255,\n 255,\n 255,\n Math.round(transformation.opacity * 255),\n ]),\n raw: {\n width: 1,\n height: 1,\n channels: 4,\n },\n tile: true,\n blend: \"dest-in\",\n },\n ])\n .toBuffer(),\n catch: (error) => {\n return UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: \"Failed to apply watermark opacity\",\n cause: error,\n });\n },\n });\n\n pipeline = pipeline.composite([\n {\n input: watermarkWithOpacity,\n top,\n left,\n },\n ]);\n break;\n }\n\n case \"logo\": {\n // Fetch logo image from URL\n const logoBuffer = yield* Effect.tryPromise({\n try: async () => {\n const response = await fetch(transformation.imagePath);\n if (!response.ok) {\n throw new Error(\n `Failed to fetch logo: ${response.statusText}`,\n );\n }\n const arrayBuffer = await response.arrayBuffer();\n return Buffer.from(arrayBuffer);\n },\n catch: (error) => {\n return UploadistaError.fromCode(\"FILE_NOT_FOUND\", {\n body: `Logo image not found or failed to fetch: ${transformation.imagePath}`,\n cause: error,\n });\n },\n }).pipe(\n withOperationSpan(\"image\", \"fetch-logo\", {\n \"image.logo_url\": transformation.imagePath,\n }),\n );\n\n // Get image metadata\n const metadata = yield* Effect.tryPromise({\n try: async () => await pipeline.metadata(),\n catch: (error) => {\n return UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: \"Failed to read image metadata\",\n cause: error,\n });\n },\n });\n\n // Get logo metadata\n const logoMetadata = yield* Effect.tryPromise({\n try: async () => await sharp(logoBuffer).metadata(),\n catch: (error) => {\n return UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: \"Failed to read logo metadata\",\n cause: error,\n });\n },\n });\n\n if (\n !metadata.width ||\n !metadata.height ||\n !logoMetadata.width ||\n !logoMetadata.height\n ) {\n return yield* Effect.fail(\n UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: \"Could not determine image or logo dimensions\",\n }),\n );\n }\n\n // Scale logo\n const scaledLogoWidth = Math.round(\n logoMetadata.width * transformation.scale,\n );\n const scaledLogoHeight = Math.round(\n logoMetadata.height * transformation.scale,\n );\n\n const scaledLogo = yield* Effect.tryPromise({\n try: async () =>\n await sharp(logoBuffer)\n .resize(scaledLogoWidth, scaledLogoHeight)\n .toBuffer(),\n catch: (error) => {\n return UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: \"Failed to scale logo\",\n cause: error,\n });\n },\n });\n\n const { top, left } = calculateOverlayPosition(\n transformation.position,\n metadata.width,\n metadata.height,\n scaledLogoWidth,\n scaledLogoHeight,\n transformation.offsetX,\n transformation.offsetY,\n );\n\n pipeline = pipeline.composite([\n {\n input: scaledLogo,\n top,\n left,\n },\n ]);\n break;\n }\n\n case \"text\": {\n // Get image metadata\n const metadata = yield* Effect.tryPromise({\n try: async () => await pipeline.metadata(),\n catch: (error) => {\n return UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: \"Failed to read image metadata\",\n cause: error,\n });\n },\n });\n\n if (!metadata.width || !metadata.height) {\n return yield* Effect.fail(\n UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: \"Could not determine image dimensions\",\n }),\n );\n }\n\n // Create SVG text overlay\n const fontFamily = transformation.fontFamily || \"sans-serif\";\n\n // Estimate text dimensions (rough approximation)\n const textWidth =\n transformation.text.length * transformation.fontSize * 0.6;\n const textHeight = transformation.fontSize;\n\n const { top, left } = calculateOverlayPosition(\n transformation.position,\n metadata.width,\n metadata.height,\n textWidth,\n textHeight,\n transformation.offsetX,\n transformation.offsetY,\n );\n\n // Create positioned SVG\n const positionedSvg = `\n <svg width=\"${metadata.width}\" height=\"${metadata.height}\">\n <text\n x=\"${left}\"\n y=\"${top + transformation.fontSize}\"\n font-family=\"${fontFamily}\"\n font-size=\"${transformation.fontSize}\"\n fill=\"${transformation.color}\"\n >${transformation.text}</text>\n </svg>\n `;\n\n pipeline = pipeline.composite([\n {\n input: Buffer.from(positionedSvg),\n top: 0,\n left: 0,\n },\n ]);\n break;\n }\n\n default: {\n // TypeScript should ensure this is unreachable\n return yield* Effect.fail(\n UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: `Unsupported transformation type: ${(transformation as { type: string }).type}`,\n }),\n );\n }\n }\n\n // Convert pipeline to buffer\n const outputBytes = yield* Effect.tryPromise({\n try: async () => await pipeline.toBuffer(),\n catch: (error) => {\n return UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: `Failed to apply transformation: ${transformation.type}`,\n cause: error,\n });\n },\n });\n\n return new Uint8Array(outputBytes);\n }).pipe(\n withOperationSpan(\"image\", \"transform\", {\n \"image.transformation_type\": transformation.type,\n \"image.input_size\": inputBytes.byteLength,\n }),\n );\n },\n\n /**\n * Indicates that this plugin supports streaming operations.\n */\n supportsStreaming: true,\n\n /**\n * Streaming optimization using Sharp's pipeline.\n *\n * Collects input stream chunks, processes through Sharp, and returns\n * the result as a stream. This avoids double-buffering when combined\n * with streaming DataStore reads.\n */\n optimizeStream: (\n inputStream: Stream.Stream<Uint8Array, UploadistaError>,\n { quality, format }: OptimizeParams,\n ): Effect.Effect<\n Stream.Stream<Uint8Array, UploadistaError>,\n UploadistaError\n > => {\n return Effect.gen(function* () {\n // Collect input stream to buffer (Sharp needs full image to decode)\n const chunks: Uint8Array[] = [];\n yield* Stream.runForEach(inputStream, (chunk) =>\n Effect.sync(() => {\n chunks.push(chunk);\n }),\n );\n\n // Combine chunks\n const totalLength = chunks.reduce((sum, c) => sum + c.byteLength, 0);\n const inputBuffer = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n inputBuffer.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n // Process through Sharp and output as stream\n return Stream.async<Uint8Array, UploadistaError>((emit) => {\n const sharpInstance = sharp(inputBuffer).toFormat(format, {\n quality,\n });\n\n // Use Sharp's streaming output\n const outputStream = new PassThrough();\n const outputChunks: Buffer[] = [];\n\n sharpInstance\n .pipe(outputStream)\n .on(\"data\", (chunk: Buffer) => {\n outputChunks.push(chunk);\n })\n .on(\"end\", () => {\n // Emit all collected chunks as a single Uint8Array\n const outputBuffer = Buffer.concat(outputChunks);\n emit.single(new Uint8Array(outputBuffer));\n emit.end();\n })\n .on(\"error\", (error: Error) => {\n emit.fail(\n UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: `Sharp streaming optimization failed: ${error.message}`,\n cause: error,\n }),\n );\n });\n\n // Cleanup\n return Effect.sync(() => {\n outputStream.destroy();\n });\n });\n }).pipe(\n withOperationSpan(\"image\", \"optimize-stream\", {\n \"image.format\": format,\n \"image.quality\": quality,\n }),\n );\n },\n\n /**\n * Streaming resize using Sharp's pipeline.\n *\n * Collects input stream chunks, processes through Sharp's resize,\n * and returns the result as a stream.\n */\n resizeStream: (\n inputStream: Stream.Stream<Uint8Array, UploadistaError>,\n { width, height, fit }: ResizeParams,\n ): Effect.Effect<\n Stream.Stream<Uint8Array, UploadistaError>,\n UploadistaError\n > => {\n return Effect.gen(function* () {\n if (!width && !height) {\n return yield* Effect.fail(\n UploadistaError.fromCode(\"VALIDATION_ERROR\", {\n body: \"Either width or height must be specified for resize\",\n }),\n );\n }\n\n // Collect input stream to buffer (Sharp needs full image to decode)\n const chunks: Uint8Array[] = [];\n yield* Stream.runForEach(inputStream, (chunk) =>\n Effect.sync(() => {\n chunks.push(chunk);\n }),\n );\n\n // Combine chunks\n const totalLength = chunks.reduce((sum, c) => sum + c.byteLength, 0);\n const inputBuffer = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n inputBuffer.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n const sharpFit = mapFitToSharp(fit);\n\n // Process through Sharp and output as stream\n return Stream.async<Uint8Array, UploadistaError>((emit) => {\n const sharpInstance = sharp(inputBuffer).resize(width, height, {\n fit: sharpFit,\n });\n\n // Use Sharp's streaming output\n const outputStream = new PassThrough();\n const outputChunks: Buffer[] = [];\n\n sharpInstance\n .pipe(outputStream)\n .on(\"data\", (chunk: Buffer) => {\n outputChunks.push(chunk);\n })\n .on(\"end\", () => {\n // Emit all collected chunks as a single Uint8Array\n const outputBuffer = Buffer.concat(outputChunks);\n emit.single(new Uint8Array(outputBuffer));\n emit.end();\n })\n .on(\"error\", (error: Error) => {\n emit.fail(\n UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: `Sharp streaming resize failed: ${error.message}`,\n cause: error,\n }),\n );\n });\n\n // Cleanup\n return Effect.sync(() => {\n outputStream.destroy();\n });\n });\n }).pipe(\n withOperationSpan(\"image\", \"resize-stream\", {\n \"image.width\": width,\n \"image.height\": height,\n \"image.fit\": fit,\n }),\n );\n },\n\n /**\n * Streaming transformation using Sharp's pipeline.\n *\n * Collects input stream chunks, applies the transformation,\n * and returns the result as a stream.\n */\n transformStream: (\n inputStream: Stream.Stream<Uint8Array, UploadistaError>,\n transformation: Transformation,\n ): Effect.Effect<\n Stream.Stream<Uint8Array, UploadistaError>,\n UploadistaError\n > => {\n return Effect.gen(function* () {\n // Collect input stream to buffer (Sharp needs full image to decode)\n const chunks: Uint8Array[] = [];\n yield* Stream.runForEach(inputStream, (chunk) =>\n Effect.sync(() => {\n chunks.push(chunk);\n }),\n );\n\n // Combine chunks\n const totalLength = chunks.reduce((sum, c) => sum + c.byteLength, 0);\n const inputBuffer = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n inputBuffer.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n // Apply transformation (reuse buffered transform logic)\n let pipeline = sharp(inputBuffer);\n\n switch (transformation.type) {\n case \"resize\": {\n const sharpFit = mapFitToSharp(transformation.fit);\n pipeline = pipeline.resize(\n transformation.width,\n transformation.height,\n { fit: sharpFit },\n );\n break;\n }\n\n case \"blur\": {\n pipeline = pipeline.blur(transformation.sigma);\n break;\n }\n\n case \"rotate\": {\n const options = transformation.background\n ? { background: transformation.background }\n : undefined;\n pipeline = pipeline.rotate(transformation.angle, options);\n break;\n }\n\n case \"flip\": {\n if (transformation.direction === \"horizontal\") {\n pipeline = pipeline.flop();\n } else {\n pipeline = pipeline.flip();\n }\n break;\n }\n\n case \"grayscale\": {\n pipeline = pipeline.grayscale();\n break;\n }\n\n case \"sepia\": {\n pipeline = pipeline.tint({ r: 112, g: 66, b: 20 });\n break;\n }\n\n case \"brightness\": {\n const multiplier = 1 + transformation.value / 100;\n pipeline = pipeline.modulate({ brightness: multiplier });\n break;\n }\n\n case \"contrast\": {\n const a = 1 + transformation.value / 100;\n pipeline = pipeline.linear(a, 0);\n break;\n }\n\n case \"sharpen\": {\n if (transformation.sigma !== undefined) {\n pipeline = pipeline.sharpen({ sigma: transformation.sigma });\n } else {\n pipeline = pipeline.sharpen();\n }\n break;\n }\n\n case \"watermark\":\n case \"logo\":\n case \"text\": {\n // These transformations require async operations and metadata lookups\n // Fall back to the buffered transform for these complex cases\n return yield* Effect.fail(\n UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: `Streaming not supported for ${transformation.type} transformation. Use buffered mode.`,\n }),\n );\n }\n\n default: {\n return yield* Effect.fail(\n UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: `Unsupported transformation type: ${(transformation as { type: string }).type}`,\n }),\n );\n }\n }\n\n // Process through Sharp and output as stream\n return Stream.async<Uint8Array, UploadistaError>((emit) => {\n // Use Sharp's streaming output\n const outputStream = new PassThrough();\n const outputChunks: Buffer[] = [];\n\n pipeline\n .pipe(outputStream)\n .on(\"data\", (chunk: Buffer) => {\n outputChunks.push(chunk);\n })\n .on(\"end\", () => {\n // Emit all collected chunks as a single Uint8Array\n const outputBuffer = Buffer.concat(outputChunks);\n emit.single(new Uint8Array(outputBuffer));\n emit.end();\n })\n .on(\"error\", (error: Error) => {\n emit.fail(\n UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: `Sharp streaming transform failed: ${error.message}`,\n cause: error,\n }),\n );\n });\n\n // Cleanup\n return Effect.sync(() => {\n outputStream.destroy();\n });\n });\n }).pipe(\n withOperationSpan(\"image\", \"transform-stream\", {\n \"image.transformation_type\": transformation.type,\n }),\n );\n },\n }),\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["chunks: Uint8Array[]","outputChunks: Buffer[]"],"sources":["../src/image-plugin.ts"],"sourcesContent":["import { PassThrough } from \"node:stream\";\nimport { UploadistaError } from \"@uploadista/core/errors\";\nimport {\n ImagePlugin,\n type OptimizeParams,\n type ResizeParams,\n type Transformation,\n} from \"@uploadista/core/flow\";\nimport { withOperationSpan } from \"@uploadista/observability\";\nimport { Effect, Layer, Stream } from \"effect\";\nimport sharp from \"sharp\";\n\nconst mapFitToSharp = (fit: \"fill\" | \"contain\" | \"cover\") => {\n switch (fit) {\n case \"fill\":\n return \"cover\";\n case \"contain\":\n return \"contain\";\n }\n};\n\n/**\n * Calculate position coordinates for overlays based on position string and offsets.\n */\nconst calculateOverlayPosition = (\n position: string,\n imageWidth: number,\n imageHeight: number,\n overlayWidth: number,\n overlayHeight: number,\n offsetX = 0,\n offsetY = 0,\n): { top: number; left: number } => {\n let top = 0;\n let left = 0;\n\n switch (position) {\n case \"top-left\":\n top = offsetY;\n left = offsetX;\n break;\n case \"top-right\":\n top = offsetY;\n left = imageWidth - overlayWidth - offsetX;\n break;\n case \"bottom-left\":\n top = imageHeight - overlayHeight - offsetY;\n left = offsetX;\n break;\n case \"bottom-right\":\n top = imageHeight - overlayHeight - offsetY;\n left = imageWidth - overlayWidth - offsetX;\n break;\n case \"center\":\n top = Math.floor((imageHeight - overlayHeight) / 2) + offsetY;\n left = Math.floor((imageWidth - overlayWidth) / 2) + offsetX;\n break;\n }\n\n return { top, left };\n};\n\nexport const imagePlugin = () =>\n Layer.succeed(\n ImagePlugin,\n ImagePlugin.of({\n optimize: (inputBytes, { quality, format }) => {\n return Effect.gen(function* () {\n const outputBytes = yield* Effect.tryPromise({\n try: async () =>\n await sharp(inputBytes).toFormat(format, { quality }).toBuffer(),\n catch: (error) => {\n return UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n cause: error,\n });\n },\n });\n return new Uint8Array(outputBytes);\n }).pipe(\n withOperationSpan(\"image\", \"optimize\", {\n \"image.format\": format,\n \"image.quality\": quality,\n \"image.input_size\": inputBytes.byteLength,\n }),\n );\n },\n resize: (inputBytes, { width, height, fit }) => {\n return Effect.gen(function* () {\n if (!width && !height) {\n throw new Error(\n \"Either width or height must be specified for resize\",\n );\n }\n\n const sharpFit = mapFitToSharp(fit);\n const outputBytes = yield* Effect.tryPromise({\n try: async () =>\n await sharp(inputBytes)\n .resize(width, height, { fit: sharpFit })\n .toBuffer(),\n catch: (error) => {\n return UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n cause: error,\n });\n },\n });\n\n return new Uint8Array(outputBytes);\n }).pipe(\n withOperationSpan(\"image\", \"resize\", {\n \"image.width\": width,\n \"image.height\": height,\n \"image.fit\": fit,\n \"image.input_size\": inputBytes.byteLength,\n }),\n );\n },\n transform: (inputBytes, transformation) => {\n return Effect.gen(function* () {\n let pipeline = sharp(inputBytes);\n\n switch (transformation.type) {\n case \"resize\": {\n const sharpFit = mapFitToSharp(transformation.fit);\n pipeline = pipeline.resize(\n transformation.width,\n transformation.height,\n {\n fit: sharpFit,\n },\n );\n break;\n }\n\n case \"blur\": {\n pipeline = pipeline.blur(transformation.sigma);\n break;\n }\n\n case \"rotate\": {\n const options = transformation.background\n ? { background: transformation.background }\n : undefined;\n pipeline = pipeline.rotate(transformation.angle, options);\n break;\n }\n\n case \"flip\": {\n if (transformation.direction === \"horizontal\") {\n pipeline = pipeline.flop();\n } else {\n pipeline = pipeline.flip();\n }\n break;\n }\n\n case \"grayscale\": {\n pipeline = pipeline.grayscale();\n break;\n }\n\n case \"sepia\": {\n // Apply sepia tone using tint\n pipeline = pipeline.tint({ r: 112, g: 66, b: 20 });\n break;\n }\n\n case \"brightness\": {\n // Convert -100 to +100 range to multiplier (0 to 2)\n const multiplier = 1 + transformation.value / 100;\n pipeline = pipeline.modulate({ brightness: multiplier });\n break;\n }\n\n case \"contrast\": {\n // Convert -100 to +100 range to linear adjustment\n const a = 1 + transformation.value / 100;\n pipeline = pipeline.linear(a, 0);\n break;\n }\n\n case \"sharpen\": {\n if (transformation.sigma !== undefined) {\n pipeline = pipeline.sharpen({ sigma: transformation.sigma });\n } else {\n pipeline = pipeline.sharpen();\n }\n break;\n }\n\n case \"watermark\": {\n // Fetch watermark image from URL\n const watermarkBuffer = yield* Effect.tryPromise({\n try: async () => {\n const response = await fetch(transformation.imagePath);\n if (!response.ok) {\n throw new Error(\n `Failed to fetch watermark: ${response.statusText}`,\n );\n }\n const arrayBuffer = await response.arrayBuffer();\n return Buffer.from(arrayBuffer);\n },\n catch: (error) => {\n return UploadistaError.fromCode(\"FILE_NOT_FOUND\", {\n body: `Watermark image not found or failed to fetch: ${transformation.imagePath}`,\n cause: error,\n });\n },\n }).pipe(\n withOperationSpan(\"image\", \"fetch-watermark\", {\n \"image.watermark_url\": transformation.imagePath,\n }),\n );\n\n // Get image metadata to calculate positioning\n const metadata = yield* Effect.tryPromise({\n try: async () => await pipeline.metadata(),\n catch: (error) => {\n return UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: \"Failed to read image metadata\",\n cause: error,\n });\n },\n });\n\n // Get watermark metadata\n const watermarkMetadata = yield* Effect.tryPromise({\n try: async () => await sharp(watermarkBuffer).metadata(),\n catch: (error) => {\n return UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: \"Failed to read watermark metadata\",\n cause: error,\n });\n },\n });\n\n if (\n !metadata.width ||\n !metadata.height ||\n !watermarkMetadata.width ||\n !watermarkMetadata.height\n ) {\n return yield* Effect.fail(\n UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: \"Could not determine image or watermark dimensions\",\n }),\n );\n }\n\n const { top, left } = calculateOverlayPosition(\n transformation.position,\n metadata.width,\n metadata.height,\n watermarkMetadata.width,\n watermarkMetadata.height,\n transformation.offsetX,\n transformation.offsetY,\n );\n\n // Apply watermark with opacity\n const watermarkWithOpacity = yield* Effect.tryPromise({\n try: async () =>\n await sharp(watermarkBuffer)\n .composite([\n {\n input: Buffer.from([\n 255,\n 255,\n 255,\n Math.round(transformation.opacity * 255),\n ]),\n raw: {\n width: 1,\n height: 1,\n channels: 4,\n },\n tile: true,\n blend: \"dest-in\",\n },\n ])\n .toBuffer(),\n catch: (error) => {\n return UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: \"Failed to apply watermark opacity\",\n cause: error,\n });\n },\n });\n\n pipeline = pipeline.composite([\n {\n input: watermarkWithOpacity,\n top,\n left,\n },\n ]);\n break;\n }\n\n case \"logo\": {\n // Fetch logo image from URL\n const logoBuffer = yield* Effect.tryPromise({\n try: async () => {\n const response = await fetch(transformation.imagePath);\n if (!response.ok) {\n throw new Error(\n `Failed to fetch logo: ${response.statusText}`,\n );\n }\n const arrayBuffer = await response.arrayBuffer();\n return Buffer.from(arrayBuffer);\n },\n catch: (error) => {\n return UploadistaError.fromCode(\"FILE_NOT_FOUND\", {\n body: `Logo image not found or failed to fetch: ${transformation.imagePath}`,\n cause: error,\n });\n },\n }).pipe(\n withOperationSpan(\"image\", \"fetch-logo\", {\n \"image.logo_url\": transformation.imagePath,\n }),\n );\n\n // Get image metadata\n const metadata = yield* Effect.tryPromise({\n try: async () => await pipeline.metadata(),\n catch: (error) => {\n return UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: \"Failed to read image metadata\",\n cause: error,\n });\n },\n });\n\n // Get logo metadata\n const logoMetadata = yield* Effect.tryPromise({\n try: async () => await sharp(logoBuffer).metadata(),\n catch: (error) => {\n return UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: \"Failed to read logo metadata\",\n cause: error,\n });\n },\n });\n\n if (\n !metadata.width ||\n !metadata.height ||\n !logoMetadata.width ||\n !logoMetadata.height\n ) {\n return yield* Effect.fail(\n UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: \"Could not determine image or logo dimensions\",\n }),\n );\n }\n\n // Scale logo\n const scaledLogoWidth = Math.round(\n logoMetadata.width * transformation.scale,\n );\n const scaledLogoHeight = Math.round(\n logoMetadata.height * transformation.scale,\n );\n\n const scaledLogo = yield* Effect.tryPromise({\n try: async () =>\n await sharp(logoBuffer)\n .resize(scaledLogoWidth, scaledLogoHeight)\n .toBuffer(),\n catch: (error) => {\n return UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: \"Failed to scale logo\",\n cause: error,\n });\n },\n });\n\n const { top, left } = calculateOverlayPosition(\n transformation.position,\n metadata.width,\n metadata.height,\n scaledLogoWidth,\n scaledLogoHeight,\n transformation.offsetX,\n transformation.offsetY,\n );\n\n pipeline = pipeline.composite([\n {\n input: scaledLogo,\n top,\n left,\n },\n ]);\n break;\n }\n\n case \"text\": {\n // Get image metadata\n const metadata = yield* Effect.tryPromise({\n try: async () => await pipeline.metadata(),\n catch: (error) => {\n return UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: \"Failed to read image metadata\",\n cause: error,\n });\n },\n });\n\n if (!metadata.width || !metadata.height) {\n return yield* Effect.fail(\n UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: \"Could not determine image dimensions\",\n }),\n );\n }\n\n // Create SVG text overlay\n const fontFamily = transformation.fontFamily || \"sans-serif\";\n\n // Estimate text dimensions (rough approximation)\n const textWidth =\n transformation.text.length * transformation.fontSize * 0.6;\n const textHeight = transformation.fontSize;\n\n const { top, left } = calculateOverlayPosition(\n transformation.position,\n metadata.width,\n metadata.height,\n textWidth,\n textHeight,\n transformation.offsetX,\n transformation.offsetY,\n );\n\n // Create positioned SVG\n const positionedSvg = `\n <svg width=\"${metadata.width}\" height=\"${metadata.height}\">\n <text\n x=\"${left}\"\n y=\"${top + transformation.fontSize}\"\n font-family=\"${fontFamily}\"\n font-size=\"${transformation.fontSize}\"\n fill=\"${transformation.color}\"\n >${transformation.text}</text>\n </svg>\n `;\n\n pipeline = pipeline.composite([\n {\n input: Buffer.from(positionedSvg),\n top: 0,\n left: 0,\n },\n ]);\n break;\n }\n\n default: {\n // TypeScript should ensure this is unreachable\n return yield* Effect.fail(\n UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: `Unsupported transformation type: ${(transformation as { type: string }).type}`,\n }),\n );\n }\n }\n\n // Convert pipeline to buffer\n const outputBytes = yield* Effect.tryPromise({\n try: async () => await pipeline.toBuffer(),\n catch: (error) => {\n return UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: `Failed to apply transformation: ${transformation.type}`,\n cause: error,\n });\n },\n });\n\n return new Uint8Array(outputBytes);\n }).pipe(\n withOperationSpan(\"image\", \"transform\", {\n \"image.transformation_type\": transformation.type,\n \"image.input_size\": inputBytes.byteLength,\n }),\n );\n },\n\n /**\n * Indicates that this plugin supports streaming operations.\n */\n supportsStreaming: true,\n\n /**\n * Streaming optimization using Sharp's pipeline.\n *\n * Collects input stream chunks, processes through Sharp, and returns\n * the result as a stream. This avoids double-buffering when combined\n * with streaming DataStore reads.\n */\n optimizeStream: (\n inputStream: Stream.Stream<Uint8Array, UploadistaError>,\n { quality, format }: OptimizeParams,\n ): Effect.Effect<\n Stream.Stream<Uint8Array, UploadistaError>,\n UploadistaError\n > => {\n return Effect.gen(function* () {\n // Collect input stream to buffer (Sharp needs full image to decode)\n const chunks: Uint8Array[] = [];\n yield* Stream.runForEach(inputStream, (chunk) =>\n Effect.sync(() => {\n chunks.push(chunk);\n }),\n );\n\n // Combine chunks\n const totalLength = chunks.reduce((sum, c) => sum + c.byteLength, 0);\n const inputBuffer = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n inputBuffer.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n // Process through Sharp and output as stream\n return Stream.async<Uint8Array, UploadistaError>((emit) => {\n const sharpInstance = sharp(inputBuffer).toFormat(format, {\n quality,\n });\n\n // Use Sharp's streaming output\n const outputStream = new PassThrough();\n const outputChunks: Buffer[] = [];\n\n sharpInstance\n .pipe(outputStream)\n .on(\"data\", (chunk: Buffer) => {\n outputChunks.push(chunk);\n })\n .on(\"end\", () => {\n // Emit all collected chunks as a single Uint8Array\n const outputBuffer = Buffer.concat(outputChunks);\n emit.single(new Uint8Array(outputBuffer));\n emit.end();\n })\n .on(\"error\", (error: Error) => {\n emit.fail(\n UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: `Sharp streaming optimization failed: ${error.message}`,\n cause: error,\n }),\n );\n });\n\n // Cleanup\n return Effect.sync(() => {\n outputStream.destroy();\n });\n });\n }).pipe(\n withOperationSpan(\"image\", \"optimize-stream\", {\n \"image.format\": format,\n \"image.quality\": quality,\n }),\n );\n },\n\n /**\n * Streaming resize using Sharp's pipeline.\n *\n * Collects input stream chunks, processes through Sharp's resize,\n * and returns the result as a stream.\n */\n resizeStream: (\n inputStream: Stream.Stream<Uint8Array, UploadistaError>,\n { width, height, fit }: ResizeParams,\n ): Effect.Effect<\n Stream.Stream<Uint8Array, UploadistaError>,\n UploadistaError\n > => {\n return Effect.gen(function* () {\n if (!width && !height) {\n return yield* Effect.fail(\n UploadistaError.fromCode(\"VALIDATION_ERROR\", {\n body: \"Either width or height must be specified for resize\",\n }),\n );\n }\n\n // Collect input stream to buffer (Sharp needs full image to decode)\n const chunks: Uint8Array[] = [];\n yield* Stream.runForEach(inputStream, (chunk) =>\n Effect.sync(() => {\n chunks.push(chunk);\n }),\n );\n\n // Combine chunks\n const totalLength = chunks.reduce((sum, c) => sum + c.byteLength, 0);\n const inputBuffer = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n inputBuffer.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n const sharpFit = mapFitToSharp(fit);\n\n // Process through Sharp and output as stream\n return Stream.async<Uint8Array, UploadistaError>((emit) => {\n const sharpInstance = sharp(inputBuffer).resize(width, height, {\n fit: sharpFit,\n });\n\n // Use Sharp's streaming output\n const outputStream = new PassThrough();\n const outputChunks: Buffer[] = [];\n\n sharpInstance\n .pipe(outputStream)\n .on(\"data\", (chunk: Buffer) => {\n outputChunks.push(chunk);\n })\n .on(\"end\", () => {\n // Emit all collected chunks as a single Uint8Array\n const outputBuffer = Buffer.concat(outputChunks);\n emit.single(new Uint8Array(outputBuffer));\n emit.end();\n })\n .on(\"error\", (error: Error) => {\n emit.fail(\n UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: `Sharp streaming resize failed: ${error.message}`,\n cause: error,\n }),\n );\n });\n\n // Cleanup\n return Effect.sync(() => {\n outputStream.destroy();\n });\n });\n }).pipe(\n withOperationSpan(\"image\", \"resize-stream\", {\n \"image.width\": width,\n \"image.height\": height,\n \"image.fit\": fit,\n }),\n );\n },\n\n /**\n * Streaming transformation using Sharp's pipeline.\n *\n * Collects input stream chunks, applies the transformation,\n * and returns the result as a stream.\n */\n transformStream: (\n inputStream: Stream.Stream<Uint8Array, UploadistaError>,\n transformation: Transformation,\n ): Effect.Effect<\n Stream.Stream<Uint8Array, UploadistaError>,\n UploadistaError\n > => {\n return Effect.gen(function* () {\n // Collect input stream to buffer (Sharp needs full image to decode)\n const chunks: Uint8Array[] = [];\n yield* Stream.runForEach(inputStream, (chunk) =>\n Effect.sync(() => {\n chunks.push(chunk);\n }),\n );\n\n // Combine chunks\n const totalLength = chunks.reduce((sum, c) => sum + c.byteLength, 0);\n const inputBuffer = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n inputBuffer.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n // Apply transformation (reuse buffered transform logic)\n let pipeline = sharp(inputBuffer);\n\n switch (transformation.type) {\n case \"resize\": {\n const sharpFit = mapFitToSharp(transformation.fit);\n pipeline = pipeline.resize(\n transformation.width,\n transformation.height,\n { fit: sharpFit },\n );\n break;\n }\n\n case \"blur\": {\n pipeline = pipeline.blur(transformation.sigma);\n break;\n }\n\n case \"rotate\": {\n const options = transformation.background\n ? { background: transformation.background }\n : undefined;\n pipeline = pipeline.rotate(transformation.angle, options);\n break;\n }\n\n case \"flip\": {\n if (transformation.direction === \"horizontal\") {\n pipeline = pipeline.flop();\n } else {\n pipeline = pipeline.flip();\n }\n break;\n }\n\n case \"grayscale\": {\n pipeline = pipeline.grayscale();\n break;\n }\n\n case \"sepia\": {\n pipeline = pipeline.tint({ r: 112, g: 66, b: 20 });\n break;\n }\n\n case \"brightness\": {\n const multiplier = 1 + transformation.value / 100;\n pipeline = pipeline.modulate({ brightness: multiplier });\n break;\n }\n\n case \"contrast\": {\n const a = 1 + transformation.value / 100;\n pipeline = pipeline.linear(a, 0);\n break;\n }\n\n case \"sharpen\": {\n if (transformation.sigma !== undefined) {\n pipeline = pipeline.sharpen({ sigma: transformation.sigma });\n } else {\n pipeline = pipeline.sharpen();\n }\n break;\n }\n\n case \"watermark\":\n case \"logo\":\n case \"text\": {\n // These transformations require async operations and metadata lookups\n // Fall back to the buffered transform for these complex cases\n return yield* Effect.fail(\n UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: `Streaming not supported for ${transformation.type} transformation. Use buffered mode.`,\n }),\n );\n }\n\n default: {\n return yield* Effect.fail(\n UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: `Unsupported transformation type: ${(transformation as { type: string }).type}`,\n }),\n );\n }\n }\n\n // Process through Sharp and output as stream\n return Stream.async<Uint8Array, UploadistaError>((emit) => {\n // Use Sharp's streaming output\n const outputStream = new PassThrough();\n const outputChunks: Buffer[] = [];\n\n pipeline\n .pipe(outputStream)\n .on(\"data\", (chunk: Buffer) => {\n outputChunks.push(chunk);\n })\n .on(\"end\", () => {\n // Emit all collected chunks as a single Uint8Array\n const outputBuffer = Buffer.concat(outputChunks);\n emit.single(new Uint8Array(outputBuffer));\n emit.end();\n })\n .on(\"error\", (error: Error) => {\n emit.fail(\n UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n body: `Sharp streaming transform failed: ${error.message}`,\n cause: error,\n }),\n );\n });\n\n // Cleanup\n return Effect.sync(() => {\n outputStream.destroy();\n });\n });\n }).pipe(\n withOperationSpan(\"image\", \"transform-stream\", {\n \"image.transformation_type\": transformation.type,\n }),\n );\n },\n }),\n );\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@uploadista/flow-images-sharp",
3
3
  "type": "module",
4
- "version": "0.0.20-beta.8",
4
+ "version": "0.0.20-beta.9",
5
5
  "description": "Sharp image processing service for Uploadista Flow",
6
6
  "license": "MIT",
7
7
  "author": "Uploadista",
@@ -16,8 +16,8 @@
16
16
  "dependencies": {
17
17
  "sharp": "0.34.5",
18
18
  "tinycolor2": "1.6.0",
19
- "@uploadista/core": "0.0.20-beta.8",
20
- "@uploadista/observability": "0.0.20-beta.8"
19
+ "@uploadista/core": "0.0.20-beta.9",
20
+ "@uploadista/observability": "0.0.20-beta.9"
21
21
  },
22
22
  "peerDependencies": {
23
23
  "effect": "^3.0.0",
@@ -31,7 +31,7 @@
31
31
  "tsdown": "0.18.0",
32
32
  "vitest": "4.0.15",
33
33
  "zod": "4.2.0",
34
- "@uploadista/typescript-config": "0.0.20-beta.8"
34
+ "@uploadista/typescript-config": "0.0.20-beta.9"
35
35
  },
36
36
  "scripts": {
37
37
  "build": "tsc --noEmit && tsdown",