@everystack/server 0.2.2 → 0.2.3

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/image.ts +31 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@everystack/server",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Server runtime primitives for Lambda — event adapters, routing, SSR, image processing",
5
5
  "license": "AGPL-3.0-only",
6
6
  "publishConfig": {
package/src/image.ts CHANGED
@@ -104,8 +104,11 @@ export function parseParams(query: Record<string, string | undefined>): Transfor
104
104
  const h = parseInt(query.h, 10);
105
105
  if (h > 0 && h <= MAX_DIMENSION) params.h = h;
106
106
  }
107
- if (query.fit && VALID_FITS.includes(query.fit as any)) {
108
- params.fit = query.fit as TransformParams['fit'];
107
+ if (query.fit) {
108
+ const fit = query.fit === 'crop' ? 'cover' : query.fit;
109
+ if (VALID_FITS.includes(fit as any)) {
110
+ params.fit = fit as TransformParams['fit'];
111
+ }
109
112
  }
110
113
  if (query.fm && VALID_FORMATS.includes(query.fm as any)) {
111
114
  params.fm = query.fm as TransformParams['fm'];
@@ -151,11 +154,12 @@ export async function processImage(
151
154
 
152
155
  // Resize
153
156
  if (params.w || params.h) {
157
+ const fit = params.fit || 'cover';
154
158
  pipeline = pipeline.resize({
155
159
  width: params.w,
156
160
  height: params.h,
157
- fit: params.fit || 'cover',
158
- withoutEnlargement: true,
161
+ fit,
162
+ withoutEnlargement: fit !== 'cover' && fit !== 'fill',
159
163
  });
160
164
  }
161
165
 
@@ -268,6 +272,7 @@ export function createImageHandler(
268
272
 
269
273
  // --- Fetch original from S3 for processing ---
270
274
  let originalData: Buffer;
275
+ let originalContentType: string | undefined;
271
276
  try {
272
277
  const result = await client.send(
273
278
  new GetObjectCommand({ Bucket: bucket, Key: key })
@@ -279,6 +284,7 @@ export function createImageHandler(
279
284
  body: JSON.stringify({ error: 'Image not found' }),
280
285
  };
281
286
  }
287
+ originalContentType = result.ContentType || undefined;
282
288
  const bytes = await result.Body.transformToByteArray();
283
289
  originalData = Buffer.from(bytes);
284
290
  } catch (error: any) {
@@ -292,8 +298,28 @@ export function createImageHandler(
292
298
  throw error;
293
299
  }
294
300
 
301
+ // Pass through non-image files (fonts, CSS, etc.) without processing
302
+ const isImage = originalContentType?.startsWith('image/') ??
303
+ /\.(jpe?g|png|webp|avif|gif|tiff?|svg)$/i.test(key);
304
+ if (!isImage) {
305
+ return {
306
+ statusCode: 200,
307
+ headers: {
308
+ 'Content-Type': originalContentType || 'application/octet-stream',
309
+ ...cacheHeaders,
310
+ },
311
+ body: originalData.toString('base64'),
312
+ isBase64Encoded: true,
313
+ };
314
+ }
315
+
316
+ // No transform params — serve original image as-is (EXIF-corrected webp)
317
+ const hasTransforms = params.w || params.h || params.fit || params.fm || params.q;
318
+
295
319
  // Process with Sharp
296
- const processed = await processImage(originalData, params);
320
+ const processed = hasTransforms
321
+ ? await processImage(originalData, params)
322
+ : await processImage(originalData, { fm: 'webp', q: 80 });
297
323
 
298
324
  // --- Write rendered image to S3 cache (fire-and-forget) ---
299
325
  if (useCache && s3CacheKey) {