@lyxa.ai/core 1.2.5 → 1.2.6

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.
@@ -255,7 +255,6 @@ export declare const REGISTRY: {
255
255
  }>;
256
256
  output: import("zod").ZodObject<{
257
257
  _id: import("zod").ZodUnion<[import("zod").ZodEffects<import("zod").ZodEffects<import("zod").ZodString, string, string>, import("mongoose").Types.ObjectId, string>, import("zod").ZodType<import("mongoose").Types.ObjectId, import("zod").ZodTypeDef, import("mongoose").Types.ObjectId>]>;
258
- riderId: import("zod").ZodUnion<[import("zod").ZodEffects<import("zod").ZodEffects<import("zod").ZodString, string, string>, import("mongoose").Types.ObjectId, string>, import("zod").ZodType<import("mongoose").Types.ObjectId, import("zod").ZodTypeDef, import("mongoose").Types.ObjectId>]>;
259
258
  latitude: import("zod").ZodNumber;
260
259
  longitude: import("zod").ZodNumber;
261
260
  updatedAt: import("zod").ZodEffects<import("zod").ZodEffects<import("zod").ZodUnion<[import("zod").ZodEffects<import("zod").ZodEffects<import("zod").ZodString, string, string>, Date, string>, import("zod").ZodDate]>, Date, string | Date>, Date, string | Date>;
@@ -264,13 +263,11 @@ export declare const REGISTRY: {
264
263
  updatedAt: Date;
265
264
  latitude: number;
266
265
  longitude: number;
267
- riderId: import("mongoose").Types.ObjectId;
268
266
  }, {
269
267
  _id: string | import("mongoose").Types.ObjectId;
270
268
  updatedAt: string | Date;
271
269
  latitude: number;
272
270
  longitude: number;
273
- riderId: string | import("mongoose").Types.ObjectId;
274
271
  }>;
275
272
  };
276
273
  readonly identifier: typeof RiderLocationUpdateSocketEvent.identifier;
@@ -13,7 +13,6 @@ export declare const RiderLocationUpdateSocketInputSchema: z.ZodObject<{
13
13
  }>;
14
14
  export declare const RiderLocationUpdateSocketOutputSchema: z.ZodObject<{
15
15
  _id: z.ZodUnion<[z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, import("mongoose").Types.ObjectId, string>, z.ZodType<import("mongoose").Types.ObjectId, z.ZodTypeDef, import("mongoose").Types.ObjectId>]>;
16
- riderId: z.ZodUnion<[z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, import("mongoose").Types.ObjectId, string>, z.ZodType<import("mongoose").Types.ObjectId, z.ZodTypeDef, import("mongoose").Types.ObjectId>]>;
17
16
  latitude: z.ZodNumber;
18
17
  longitude: z.ZodNumber;
19
18
  updatedAt: z.ZodEffects<z.ZodEffects<z.ZodUnion<[z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, Date, string>, z.ZodDate]>, Date, string | Date>, Date, string | Date>;
@@ -22,13 +21,11 @@ export declare const RiderLocationUpdateSocketOutputSchema: z.ZodObject<{
22
21
  updatedAt: Date;
23
22
  latitude: number;
24
23
  longitude: number;
25
- riderId: import("mongoose").Types.ObjectId;
26
24
  }, {
27
25
  _id: string | import("mongoose").Types.ObjectId;
28
26
  updatedAt: string | Date;
29
27
  latitude: number;
30
28
  longitude: number;
31
- riderId: string | import("mongoose").Types.ObjectId;
32
29
  }>;
33
30
  export type RiderLocationUpdateSocketInputDTO = DTO<typeof RiderLocationUpdateSocketInputSchema>;
34
31
  export type RiderLocationUpdateSocketOutputDTO = DTO<typeof RiderLocationUpdateSocketOutputSchema>;
@@ -46,7 +43,6 @@ export declare class RiderLocationUpdateSocketEvent extends BaseSocketEvent<type
46
43
  }>;
47
44
  output: z.ZodObject<{
48
45
  _id: z.ZodUnion<[z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, import("mongoose").Types.ObjectId, string>, z.ZodType<import("mongoose").Types.ObjectId, z.ZodTypeDef, import("mongoose").Types.ObjectId>]>;
49
- riderId: z.ZodUnion<[z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, import("mongoose").Types.ObjectId, string>, z.ZodType<import("mongoose").Types.ObjectId, z.ZodTypeDef, import("mongoose").Types.ObjectId>]>;
50
46
  latitude: z.ZodNumber;
51
47
  longitude: z.ZodNumber;
52
48
  updatedAt: z.ZodEffects<z.ZodEffects<z.ZodUnion<[z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, Date, string>, z.ZodDate]>, Date, string | Date>, Date, string | Date>;
@@ -55,13 +51,11 @@ export declare class RiderLocationUpdateSocketEvent extends BaseSocketEvent<type
55
51
  updatedAt: Date;
56
52
  latitude: number;
57
53
  longitude: number;
58
- riderId: import("mongoose").Types.ObjectId;
59
54
  }, {
60
55
  _id: string | import("mongoose").Types.ObjectId;
61
56
  updatedAt: string | Date;
62
57
  latitude: number;
63
58
  longitude: number;
64
- riderId: string | import("mongoose").Types.ObjectId;
65
59
  }>;
66
60
  };
67
61
  constructor(payload: RiderLocationUpdateSocketOutputDTO);
@@ -14,7 +14,6 @@ exports.RiderLocationUpdateSocketInputSchema = zod_1.default.object({
14
14
  });
15
15
  exports.RiderLocationUpdateSocketOutputSchema = zod_1.default.object({
16
16
  _id: validation_1.IdSchema,
17
- riderId: validation_1.ZodValidation.objectId('riderId'),
18
17
  latitude: validation_1.ZodValidation.number('latitude'),
19
18
  longitude: validation_1.ZodValidation.number('longitude'),
20
19
  updatedAt: validation_1.ZodValidation.date('updatedAt'),
@@ -1 +1 @@
1
- {"version":3,"file":"rider-location-update.socket.event.js","sourceRoot":"/","sources":["libraries/socket/events/rider-location-update.socket.event.ts"],"names":[],"mappings":";;;;;;AAAA,8CAAoB;AACpB,wDAAqD;AACrD,8DAA6E;AAC7E,kDAA0D;AAE7C,QAAA,oCAAoC,GAAG,aAAC,CAAC,MAAM,CAAC;IAC5D,OAAO,EAAE,0BAAa,CAAC,QAAQ,CAAC,SAAS,CAAC;IAC1C,OAAO,EAAE,0BAAa,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE;CACrD,CAAC,CAAC;AAEU,QAAA,qCAAqC,GAAG,aAAC,CAAC,MAAM,CAAC;IAC7D,GAAG,EAAE,qBAAQ;IACb,OAAO,EAAE,0BAAa,CAAC,QAAQ,CAAC,SAAS,CAAC;IAC1C,QAAQ,EAAE,0BAAa,CAAC,MAAM,CAAC,UAAU,CAAC;IAC1C,SAAS,EAAE,0BAAa,CAAC,MAAM,CAAC,WAAW,CAAC;IAC5C,SAAS,EAAE,0BAAa,CAAC,IAAI,CAAC,WAAW,CAAC;CAC1C,CAAC,CAAC;AAKH,MAAa,8BAA+B,SAAQ,iCAGnD;IACA,MAAM,CAAU,OAAO,GAAG;QACzB,KAAK,EAAE,4CAAoC;QAC3C,MAAM,EAAE,6CAAqC;KAC7C,CAAC;IAEF,YAAY,OAA2C;QACtD,KAAK,CAAC,sBAAe,CAAC,qBAAqB,EAAE,8BAA8B,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC/F,CAAC;IAED,MAAM,CAAC,UAAU,CAAC,KAA2D;QAC5E,OAAO,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;IACjC,CAAC;;AAfF,wEAgBC","sourcesContent":["import z from 'zod';\nimport { BaseSocketEvent } from '../BaseSocketEvent';\nimport { DTO, IdSchema, ZodValidation } from '../../../utilities/validation';\nimport { SocketEventType } from '../../../utilities/enum';\n\nexport const RiderLocationUpdateSocketInputSchema = z.object({\n\triderId: ZodValidation.objectId('riderId'),\n\torderId: ZodValidation.objectId('orderId').optional(),\n});\n\nexport const RiderLocationUpdateSocketOutputSchema = z.object({\n\t_id: IdSchema,\n\triderId: ZodValidation.objectId('riderId'),\n\tlatitude: ZodValidation.number('latitude'),\n\tlongitude: ZodValidation.number('longitude'),\n\tupdatedAt: ZodValidation.date('updatedAt'),\n});\n\nexport type RiderLocationUpdateSocketInputDTO = DTO<typeof RiderLocationUpdateSocketInputSchema>;\nexport type RiderLocationUpdateSocketOutputDTO = DTO<typeof RiderLocationUpdateSocketOutputSchema>;\n\nexport class RiderLocationUpdateSocketEvent extends BaseSocketEvent<\n\ttypeof RiderLocationUpdateSocketInputSchema,\n\ttypeof RiderLocationUpdateSocketOutputSchema\n> {\n\tstatic readonly schemas = {\n\t\tinput: RiderLocationUpdateSocketInputSchema,\n\t\toutput: RiderLocationUpdateSocketOutputSchema,\n\t};\n\n\tconstructor(payload: RiderLocationUpdateSocketOutputDTO) {\n\t\tsuper(SocketEventType.RIDER_LOCATION_UPDATE, RiderLocationUpdateSocketEvent.schemas, payload);\n\t}\n\n\tstatic identifier(input: z.infer<typeof RiderLocationUpdateSocketInputSchema>): string {\n\t\treturn input.riderId.toString();\n\t}\n}\n"]}
1
+ {"version":3,"file":"rider-location-update.socket.event.js","sourceRoot":"/","sources":["libraries/socket/events/rider-location-update.socket.event.ts"],"names":[],"mappings":";;;;;;AAAA,8CAAoB;AACpB,wDAAqD;AACrD,8DAA6E;AAC7E,kDAA0D;AAE7C,QAAA,oCAAoC,GAAG,aAAC,CAAC,MAAM,CAAC;IAC5D,OAAO,EAAE,0BAAa,CAAC,QAAQ,CAAC,SAAS,CAAC;IAC1C,OAAO,EAAE,0BAAa,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE;CACrD,CAAC,CAAC;AAEU,QAAA,qCAAqC,GAAG,aAAC,CAAC,MAAM,CAAC;IAC7D,GAAG,EAAE,qBAAQ;IACb,QAAQ,EAAE,0BAAa,CAAC,MAAM,CAAC,UAAU,CAAC;IAC1C,SAAS,EAAE,0BAAa,CAAC,MAAM,CAAC,WAAW,CAAC;IAC5C,SAAS,EAAE,0BAAa,CAAC,IAAI,CAAC,WAAW,CAAC;CAC1C,CAAC,CAAC;AAKH,MAAa,8BAA+B,SAAQ,iCAGnD;IACA,MAAM,CAAU,OAAO,GAAG;QACzB,KAAK,EAAE,4CAAoC;QAC3C,MAAM,EAAE,6CAAqC;KAC7C,CAAC;IAEF,YAAY,OAA2C;QACtD,KAAK,CAAC,sBAAe,CAAC,qBAAqB,EAAE,8BAA8B,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC/F,CAAC;IAED,MAAM,CAAC,UAAU,CAAC,KAA2D;QAC5E,OAAO,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;IACjC,CAAC;;AAfF,wEAgBC","sourcesContent":["import z from 'zod';\nimport { BaseSocketEvent } from '../BaseSocketEvent';\nimport { DTO, IdSchema, ZodValidation } from '../../../utilities/validation';\nimport { SocketEventType } from '../../../utilities/enum';\n\nexport const RiderLocationUpdateSocketInputSchema = z.object({\n\triderId: ZodValidation.objectId('riderId'),\n\torderId: ZodValidation.objectId('orderId').optional(),\n});\n\nexport const RiderLocationUpdateSocketOutputSchema = z.object({\n\t_id: IdSchema,\n\tlatitude: ZodValidation.number('latitude'),\n\tlongitude: ZodValidation.number('longitude'),\n\tupdatedAt: ZodValidation.date('updatedAt'),\n});\n\nexport type RiderLocationUpdateSocketInputDTO = DTO<typeof RiderLocationUpdateSocketInputSchema>;\nexport type RiderLocationUpdateSocketOutputDTO = DTO<typeof RiderLocationUpdateSocketOutputSchema>;\n\nexport class RiderLocationUpdateSocketEvent extends BaseSocketEvent<\n\ttypeof RiderLocationUpdateSocketInputSchema,\n\ttypeof RiderLocationUpdateSocketOutputSchema\n> {\n\tstatic readonly schemas = {\n\t\tinput: RiderLocationUpdateSocketInputSchema,\n\t\toutput: RiderLocationUpdateSocketOutputSchema,\n\t};\n\n\tconstructor(payload: RiderLocationUpdateSocketOutputDTO) {\n\t\tsuper(SocketEventType.RIDER_LOCATION_UPDATE, RiderLocationUpdateSocketEvent.schemas, payload);\n\t}\n\n\tstatic identifier(input: z.infer<typeof RiderLocationUpdateSocketInputSchema>): string {\n\t\treturn input.riderId.toString();\n\t}\n}\n"]}
@@ -27,7 +27,7 @@ export declare class UploadService {
27
27
  }>;
28
28
  extractFilenameFromUrl(url: string): string;
29
29
  deleteFileByUrl(url: string): Promise<void>;
30
- downloadImage(url: string): Promise<Buffer>;
30
+ downloadImage(url: string, retryTimes?: number): Promise<Buffer>;
31
31
  private uploadToGCS;
32
32
  uploadProcessedImageToWebp(buffer: Buffer, originalFilename: string, options?: {
33
33
  quality?: number;
@@ -176,21 +176,23 @@ class UploadService {
176
176
  }
177
177
  await file.delete();
178
178
  }
179
- async downloadImage(url) {
179
+ async downloadImage(url, retryTimes = 0) {
180
+ const attemptDownload = async () => {
181
+ const response = await axios_1.default.get(url, {
182
+ responseType: 'arraybuffer',
183
+ timeout: 10000,
184
+ maxRedirects: 3,
185
+ validateStatus: status => status >= 200 && status < 400,
186
+ });
187
+ return Buffer.from(response.data, 'binary');
188
+ };
180
189
  try {
181
- const buffer = await (0, p_retry_1.default)(async () => {
182
- const response = await axios_1.default.get(url, {
183
- responseType: 'arraybuffer',
184
- timeout: 10000,
185
- maxRedirects: 3,
186
- validateStatus: status => status >= 200 && status < 400,
187
- });
188
- return Buffer.from(response.data, 'binary');
189
- }, {
190
- retries: 2,
190
+ const buffer = await (0, p_retry_1.default)(attemptDownload, {
191
+ retries: retryTimes,
191
192
  factor: 2,
192
193
  minTimeout: 1000,
193
194
  maxTimeout: 5000,
195
+ randomize: true,
194
196
  onFailedAttempt: (error) => {
195
197
  console.warn(`[downloadImage] Attempt ${error.attemptNumber} failed (${error.retriesLeft} retries left): ${error.message}`);
196
198
  },
@@ -201,20 +203,20 @@ class UploadService {
201
203
  if (axios_1.default.isAxiosError(error)) {
202
204
  const status = error.response?.status;
203
205
  let reason = 'Image download failed';
204
- if (status === 403) {
205
- reason = 'Image URL is not valid or access forbidden (403)';
206
- }
207
- else if (status === 404) {
208
- reason = 'Image not found (404)';
209
- }
210
- else if (status === 429) {
211
- reason = 'Too many requests (429) — rate limited by server';
212
- }
213
- else if (status) {
214
- reason = `Image download failed with status ${status}`;
215
- }
216
- else {
217
- reason = `Network or unknown error: ${error.message}`;
206
+ switch (status) {
207
+ case 403:
208
+ reason = 'Image URL is not valid or access forbidden (403)';
209
+ break;
210
+ case 404:
211
+ reason = 'Image not found (404)';
212
+ break;
213
+ case 429:
214
+ reason = 'Too many requests (429) — rate limited by server';
215
+ break;
216
+ default:
217
+ reason = status
218
+ ? `Image download failed with status ${status}`
219
+ : `Network or unknown error: ${error.message}`;
218
220
  }
219
221
  throw new Error(reason);
220
222
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"/","sources":["libraries/upload/index.ts"],"names":[],"mappings":"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","sourcesContent":["import axios from 'axios';\nimport sharp from 'sharp';\nimport moment from 'moment';\nimport path from 'path';\nimport { getLibraries } from '../../index';\nimport mime from 'mime-types';\nimport FileType from 'file-type';\nimport pRetry from 'p-retry';\n\nfunction makeSlug(input: string): string {\n\treturn input\n\t\t.toLowerCase()\n\t\t.replace(/[^a-z0-9]+/g, '-')\n\t\t.replace(/(^-|-$)/g, '');\n}\n\nexport class UploadService {\n\tprivate bucket;\n\tprivate readonly websiteName;\n\n\tconstructor(bucketName?: string) {\n\t\tif (!bucketName) {\n\t\t\tbucketName = 'lyxa-global';\n\t\t}\n\n\t\tthis.bucket = getLibraries().getFirebaseService().superApp.storage().bucket(bucketName);\n\t\tthis.websiteName = 'lyxa-' + getLibraries().getConfigurationService().options.tenet;\n\t}\n\n\t/**\n\t * Generates a unique filename using the original filename.\n\t */\n\tprivate generateFilename(originalFilename: string, extension?: string): string {\n\t\tconst nameWithoutExt = path.parse(originalFilename).name;\n\t\tconst newExtension = extension || path.extname(originalFilename);\n\t\tconst timestamp = moment().format('DDMMYYHmmss');\n\t\tconst randomId = Math.floor(Math.random() * 100);\n\t\tconst baseName = `${makeSlug(nameWithoutExt)}-${this.websiteName}-${timestamp}-${randomId}`;\n\t\treturn baseName + newExtension;\n\t}\n\n\t/**\n\t * Uploads an image buffer after processing it with Sharp.\n\t * An optional destinationPath can be provided (e.g., 'images/product.jpg').\n\t */\n\tasync uploadImage(buffer: Buffer, originalFilename: string): Promise<{ filename: string; url: string }> {\n\t\tlet fileType: string | undefined;\n\n\t\ttry {\n\t\t\t// Detect actual file type\n\t\t\tfileType = (await FileType.fileTypeFromBuffer(buffer))?.ext;\n\t\t\tif (!fileType) throw new Error('Unable to detect image type');\n\n\t\t\tconst newFilename = this.generateFilename(originalFilename);\n\t\t\tconst extension = path.extname(newFilename).toLowerCase();\n\t\t\tlet processedImage: sharp.Sharp;\n\t\t\tlet contentType: string;\n\t\t\tif (extension === '.png') {\n\t\t\t\tprocessedImage = sharp(buffer).png({ quality: 80 });\n\t\t\t\tcontentType = 'image/png';\n\t\t\t} else if (extension === '.webp') {\n\t\t\t\tprocessedImage = sharp(buffer).webp({ quality: 80 });\n\t\t\t\tcontentType = 'image/webp';\n\t\t\t} else {\n\t\t\t\tprocessedImage = sharp(buffer).jpeg({ quality: 80 });\n\t\t\t\tcontentType = 'image/jpeg';\n\t\t\t}\n\n\t\t\tconst file = this.bucket.file(newFilename);\n\t\t\treturn await new Promise((resolve, reject) => {\n\t\t\t\tconst blobStream = file.createWriteStream({\n\t\t\t\t\tresumable: false,\n\t\t\t\t\tcontentType,\n\t\t\t\t});\n\n\t\t\t\tprocessedImage.on('error', (err: Error) => {\n\t\t\t\t\treject(err);\n\t\t\t\t});\n\n\t\t\t\tblobStream.on('error', (err: Error) => {\n\t\t\t\t\treject(err);\n\t\t\t\t});\n\n\t\t\t\tblobStream.on('finish', async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait file.makePublic();\n\t\t\t\t\t\tconst publicUrl = `https://storage.googleapis.com/${this.bucket.name}/${file.name}`;\n\t\t\t\t\t\tresolve({ filename: file.name, url: publicUrl });\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\treject(err);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tprocessedImage.pipe(blobStream);\n\t\t\t});\n\t\t} catch (err: any) {\n\t\t\tconsole.error('Image upload failed:', err);\n\t\t\tif (fileType) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`${fileType.toUpperCase()} format not supported. Please use JPEG, PNG, or WebP format instead.`\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow new Error(`Image upload failed: ${err.message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Transcodes (resizes) an image buffer into multiple resolutions.\n\t * An optional destinationPrefix can be provided to force a specific path or filename base.\n\t *\n\t * For example, if destinationPrefix is 'images/product', then the original might be\n\t * uploaded as 'images/product.jpg' and the resized versions as 'images/product-480.jpg', etc.\n\t */\n\tasync transcodeImage(\n\t\tbuffer: Buffer,\n\t\toriginalFilename: string,\n\t\tresolutions: number[]\n\t): Promise<{\n\t\toriginalUrl: string;\n\t\tresizedResults: Array<{ resolution: number; url: string }>;\n\t}> {\n\t\tconst extension = path.extname(originalFilename);\n\t\tconst contentType = `image/${extension.replace('.', '') || 'jpeg'}`;\n\t\tconst timestamp = moment().format('DDMMYYHmmss');\n\t\tconst randomId = Math.floor(Math.random() * 100);\n\n\t\tconst baseFilename = `${makeSlug(path.parse(originalFilename).name)}-${this.websiteName}-${timestamp}-${randomId}`;\n\n\t\tconst originalFileName = `${baseFilename}${extension}`;\n\t\tconst originalUrl = await this.uploadBuffer(buffer, originalFileName, contentType);\n\n\t\tconst metadata = await sharp(buffer).metadata();\n\t\tconst isLandscape = metadata.width && metadata.height ? metadata.width > metadata.height : true;\n\n\t\tconst resizedResults = await Promise.all(\n\t\t\tresolutions.map(async resolution => {\n\t\t\t\tconst resizeOptions = isLandscape ? { width: resolution } : { height: resolution };\n\t\t\t\tconst formatKey = (extension.replace('.', '') || 'jpeg') as keyof sharp.FormatEnum;\n\t\t\t\tconst resizedBuffer = await sharp(buffer)\n\t\t\t\t\t.resize({\n\t\t\t\t\t\t...resizeOptions,\n\t\t\t\t\t\twithoutEnlargement: true,\n\t\t\t\t\t})\n\t\t\t\t\t.toFormat(formatKey, { quality: 80 })\n\t\t\t\t\t.toBuffer();\n\t\t\t\tconst resizedFilename = `${baseFilename}-${resolution}${extension}`;\n\t\t\t\tconst resizedUrl = await this.uploadBuffer(resizedBuffer, resizedFilename, contentType);\n\t\t\t\treturn { resolution, url: resizedUrl };\n\t\t\t})\n\t\t);\n\n\t\treturn { originalUrl, resizedResults };\n\t}\n\n\t/**\n\t * Helper function to upload a buffer to a specified filename.\n\t */\n\tprivate async uploadBuffer(buffer: Buffer, filename: string, contentType: string): Promise<string> {\n\t\tconst file = this.bucket.file(filename);\n\t\tawait file.save(buffer, {\n\t\t\tresumable: false,\n\t\t\tcontentType,\n\t\t});\n\t\tawait file.makePublic();\n\t\treturn `https://storage.googleapis.com/${this.bucket.name}/${file.name}`;\n\t}\n\n\tasync getListFiles(): Promise<Array<{ name: string; url: string }>> {\n\t\tconst [files] = await this.bucket.getFiles();\n\t\treturn files.map(file => ({\n\t\t\tname: file.name!,\n\t\t\turl: file.metadata.mediaLink!,\n\t\t}));\n\t}\n\n\tasync downloadFile(filename: string): Promise<Buffer> {\n\t\tconst file = this.bucket.file(filename);\n\t\tconst [buffer] = await file.download();\n\t\treturn buffer;\n\t}\n\n\tasync deleteFile(filename: string): Promise<void> {\n\t\tconst file = this.bucket.file(filename);\n\t\tconst [exists] = await file.exists();\n\t\tif (!exists) {\n\t\t\tthrow new Error('File does not exist.');\n\t\t}\n\t\tawait file.delete();\n\t}\n\n\tasync getPublicUrlFromFilename(filename: string): Promise<{ status: boolean; url: string }> {\n\t\tconst file = this.bucket.file(filename);\n\t\tconst [exists] = await file.exists();\n\n\t\tif (!exists) {\n\t\t\treturn { status: false, url: '' };\n\t\t}\n\n\t\treturn {\n\t\t\tstatus: true,\n\t\t\turl: `https://storage.googleapis.com/${this.bucket.name}/${filename}`,\n\t\t};\n\t}\n\n\tpublic extractFilenameFromUrl(url: string): string {\n\t\ttry {\n\t\t\tconst urlObj = new URL(url);\n\t\t\tconst pathParts = urlObj.pathname.split('/');\n\t\t\treturn decodeURIComponent(pathParts[pathParts.length - 1]);\n\t\t} catch (err) {\n\t\t\tthrow new Error(`Invalid URL: ${url}`);\n\t\t}\n\t}\n\n\tasync deleteFileByUrl(url: string): Promise<void> {\n\t\tconst filename = this.extractFilenameFromUrl(url);\n\t\tconst file = this.bucket.file(filename);\n\t\tconst [exists] = await file.exists();\n\t\tif (!exists) {\n\t\t\tthrow new Error('File does not exist.');\n\t\t}\n\t\tawait file.delete();\n\t}\n\n\tasync downloadImage(url: string): Promise<Buffer> {\n\t\ttry {\n\t\t\t// Retry up to 2 times with exponential backoff\n\t\t\tconst buffer = await pRetry(\n\t\t\t\tasync () => {\n\t\t\t\t\tconst response = await axios.get(url, {\n\t\t\t\t\t\tresponseType: 'arraybuffer',\n\t\t\t\t\t\ttimeout: 10000, // 10s timeout for efficiency\n\t\t\t\t\t\tmaxRedirects: 3,\n\t\t\t\t\t\tvalidateStatus: status => status >= 200 && status < 400,\n\t\t\t\t\t});\n\t\t\t\t\treturn Buffer.from(response.data, 'binary');\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tretries: 2, // 1 original + 2 retries = 3 total attempts\n\t\t\t\t\tfactor: 2, // Slightly faster backoff growth\n\t\t\t\t\tminTimeout: 1000, // Start after 1s\n\t\t\t\t\tmaxTimeout: 5000, // Cap delay at 5s\n\t\t\t\t\tonFailedAttempt: (error: any) => {\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t`[downloadImage] Attempt ${error.attemptNumber} failed (${error.retriesLeft} retries left): ${error.message}`\n\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t);\n\n\t\t\treturn buffer;\n\t\t} catch (error: any) {\n\t\t\tif (axios.isAxiosError(error)) {\n\t\t\t\tconst status = error.response?.status;\n\t\t\t\tlet reason = 'Image download failed';\n\n\t\t\t\tif (status === 403) {\n\t\t\t\t\treason = 'Image URL is not valid or access forbidden (403)';\n\t\t\t\t} else if (status === 404) {\n\t\t\t\t\treason = 'Image not found (404)';\n\t\t\t\t} else if (status === 429) {\n\t\t\t\t\treason = 'Too many requests (429) — rate limited by server';\n\t\t\t\t} else if (status) {\n\t\t\t\t\treason = `Image download failed with status ${status}`;\n\t\t\t\t} else {\n\t\t\t\t\treason = `Network or unknown error: ${error.message}`;\n\t\t\t\t}\n\n\t\t\t\tthrow new Error(reason);\n\t\t\t}\n\n\t\t\t// Non-Axios error (timeout, DNS, etc.)\n\t\t\tthrow new Error(`Unexpected error downloading image: ${error.message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Uploads a buffer to Google Cloud Storage and makes it public\n\t */\n\tprivate async uploadToGCS(\n\t\tbuffer: Buffer,\n\t\tfilename: string,\n\t\tcontentType: string\n\t): Promise<{ filename: string; url: string }> {\n\t\tconst file = this.bucket.file(filename);\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\t// Create a write stream to upload the file\n\t\t\tconst blobStream = file.createWriteStream({\n\t\t\t\tresumable: false,\n\t\t\t\tcontentType,\n\t\t\t});\n\n\t\t\tblobStream.on('error', reject);\n\n\t\t\tblobStream.on('finish', async () => {\n\t\t\t\ttry {\n\t\t\t\t\t// Make the file publicly accessible\n\t\t\t\t\tawait file.makePublic();\n\t\t\t\t\tconst publicUrl = `https://storage.googleapis.com/${this.bucket.name}/${file.name}`;\n\t\t\t\t\tresolve({ filename: file.name, url: publicUrl });\n\t\t\t\t} catch (err) {\n\t\t\t\t\treject(err);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Start uploading the buffer\n\t\t\tblobStream.end(buffer);\n\t\t});\n\t}\n\n\t/**\n\t * Uploads and converts an image to WebP format, resizes if needed, and uploads to GCS\n\t */\n\tasync uploadProcessedImageToWebp(\n\t\tbuffer: Buffer,\n\t\toriginalFilename: string,\n\t\toptions?: { quality?: number; width?: number; height?: number }\n\t): Promise<{ filename: string; url: string }> {\n\t\tlet fileType: string | undefined;\n\n\t\ttry {\n\t\t\tconst newFilename = this.generateFilename(originalFilename, '.webp');\n\t\t\tconst quality = options?.quality ?? 80;\n\n\t\t\t// Detect actual file type\n\t\t\tfileType = (await FileType.fileTypeFromBuffer(buffer))?.ext;\n\t\t\tif (!fileType) throw new Error('Unable to detect image type');\n\n\t\t\t// Get original image dimensions if width or height is missing\n\t\t\tconst metadata = await sharp(buffer).metadata();\n\t\t\tconst width = options?.width || metadata.width;\n\t\t\tconst height = options?.height || metadata.height;\n\n\t\t\t// Convert to WebP and resize\n\t\t\tconst processedImage: sharp.Sharp = sharp(buffer)\n\t\t\t\t.resize(width, height, { fit: 'inside' })\n\t\t\t\t.webp({ quality });\n\n\t\t\tconst file = this.bucket.file(newFilename);\n\n\t\t\treturn await new Promise((resolve, reject) => {\n\t\t\t\tconst blobStream = file.createWriteStream({\n\t\t\t\t\tresumable: false,\n\t\t\t\t\tcontentType: 'image/webp',\n\t\t\t\t});\n\n\t\t\t\tprocessedImage.on('error', (err: Error) => {\n\t\t\t\t\treject(err);\n\t\t\t\t});\n\n\t\t\t\tblobStream.on('error', (err: Error) => {\n\t\t\t\t\treject(err);\n\t\t\t\t});\n\n\t\t\t\tblobStream.on('finish', async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait file.makePublic();\n\t\t\t\t\t\tconst publicUrl = `https://storage.googleapis.com/${this.bucket.name}/${file.name}`;\n\t\t\t\t\t\tresolve({ filename: file.name, url: publicUrl });\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\treject(err);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tprocessedImage.pipe(blobStream);\n\t\t\t});\n\t\t} catch (err: any) {\n\t\t\tconsole.error('Processed image upload failed:', err);\n\t\t\tif (fileType) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`${fileType.toUpperCase()} format not supported. Please use JPEG, PNG, or WebP format instead.`\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow new Error(`Processed image upload failed: ${err.message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Uploads any supported file type to GCS and returns its public URL\n\t */\n\tasync uploadFile(\n\t\tbuffer: Buffer,\n\t\toriginalFilename: string,\n\t\toptions?: {\n\t\t\tquality?: number;\n\t\t\twidth?: number;\n\t\t\theight?: number;\n\t\t\twithExtension?: boolean;\n\t\t\twithOriginalFilename?: boolean;\n\t\t}\n\t): Promise<{ filename: string; url: string }> {\n\t\tconst newFilename = options?.withOriginalFilename\n\t\t\t? originalFilename\n\t\t\t: this.generateFilename(originalFilename);\n\t\tconst extension = path.extname(newFilename).toLowerCase();\n\n\t\t// Guess the MIME type using the mime-types library\n\t\tconst contentType = mime.lookup(extension) || 'application/octet-stream';\n\n\t\t// Special image handling (compression)\n\t\tif (contentType.startsWith('image/')) {\n\t\t\tif (options?.withExtension) {\n\t\t\t\treturn this.uploadImage(buffer, originalFilename);\n\t\t\t} else {\n\t\t\t\treturn this.uploadProcessedImageToWebp(buffer, originalFilename, options);\n\t\t\t}\n\t\t}\n\n\t\treturn this.uploadToGCS(buffer, newFilename, contentType);\n\t}\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"/","sources":["libraries/upload/index.ts"],"names":[],"mappings":"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","sourcesContent":["import axios from 'axios';\nimport sharp from 'sharp';\nimport moment from 'moment';\nimport path from 'path';\nimport { getLibraries } from '../../index';\nimport mime from 'mime-types';\nimport FileType from 'file-type';\nimport pRetry from 'p-retry';\n\nfunction makeSlug(input: string): string {\n\treturn input\n\t\t.toLowerCase()\n\t\t.replace(/[^a-z0-9]+/g, '-')\n\t\t.replace(/(^-|-$)/g, '');\n}\n\nexport class UploadService {\n\tprivate bucket;\n\tprivate readonly websiteName;\n\n\tconstructor(bucketName?: string) {\n\t\tif (!bucketName) {\n\t\t\tbucketName = 'lyxa-global';\n\t\t}\n\n\t\tthis.bucket = getLibraries().getFirebaseService().superApp.storage().bucket(bucketName);\n\t\tthis.websiteName = 'lyxa-' + getLibraries().getConfigurationService().options.tenet;\n\t}\n\n\t/**\n\t * Generates a unique filename using the original filename.\n\t */\n\tprivate generateFilename(originalFilename: string, extension?: string): string {\n\t\tconst nameWithoutExt = path.parse(originalFilename).name;\n\t\tconst newExtension = extension || path.extname(originalFilename);\n\t\tconst timestamp = moment().format('DDMMYYHmmss');\n\t\tconst randomId = Math.floor(Math.random() * 100);\n\t\tconst baseName = `${makeSlug(nameWithoutExt)}-${this.websiteName}-${timestamp}-${randomId}`;\n\t\treturn baseName + newExtension;\n\t}\n\n\t/**\n\t * Uploads an image buffer after processing it with Sharp.\n\t * An optional destinationPath can be provided (e.g., 'images/product.jpg').\n\t */\n\tasync uploadImage(buffer: Buffer, originalFilename: string): Promise<{ filename: string; url: string }> {\n\t\tlet fileType: string | undefined;\n\n\t\ttry {\n\t\t\t// Detect actual file type\n\t\t\tfileType = (await FileType.fileTypeFromBuffer(buffer))?.ext;\n\t\t\tif (!fileType) throw new Error('Unable to detect image type');\n\n\t\t\tconst newFilename = this.generateFilename(originalFilename);\n\t\t\tconst extension = path.extname(newFilename).toLowerCase();\n\t\t\tlet processedImage: sharp.Sharp;\n\t\t\tlet contentType: string;\n\t\t\tif (extension === '.png') {\n\t\t\t\tprocessedImage = sharp(buffer).png({ quality: 80 });\n\t\t\t\tcontentType = 'image/png';\n\t\t\t} else if (extension === '.webp') {\n\t\t\t\tprocessedImage = sharp(buffer).webp({ quality: 80 });\n\t\t\t\tcontentType = 'image/webp';\n\t\t\t} else {\n\t\t\t\tprocessedImage = sharp(buffer).jpeg({ quality: 80 });\n\t\t\t\tcontentType = 'image/jpeg';\n\t\t\t}\n\n\t\t\tconst file = this.bucket.file(newFilename);\n\t\t\treturn await new Promise((resolve, reject) => {\n\t\t\t\tconst blobStream = file.createWriteStream({\n\t\t\t\t\tresumable: false,\n\t\t\t\t\tcontentType,\n\t\t\t\t});\n\n\t\t\t\tprocessedImage.on('error', (err: Error) => {\n\t\t\t\t\treject(err);\n\t\t\t\t});\n\n\t\t\t\tblobStream.on('error', (err: Error) => {\n\t\t\t\t\treject(err);\n\t\t\t\t});\n\n\t\t\t\tblobStream.on('finish', async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait file.makePublic();\n\t\t\t\t\t\tconst publicUrl = `https://storage.googleapis.com/${this.bucket.name}/${file.name}`;\n\t\t\t\t\t\tresolve({ filename: file.name, url: publicUrl });\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\treject(err);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tprocessedImage.pipe(blobStream);\n\t\t\t});\n\t\t} catch (err: any) {\n\t\t\tconsole.error('Image upload failed:', err);\n\t\t\tif (fileType) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`${fileType.toUpperCase()} format not supported. Please use JPEG, PNG, or WebP format instead.`\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow new Error(`Image upload failed: ${err.message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Transcodes (resizes) an image buffer into multiple resolutions.\n\t * An optional destinationPrefix can be provided to force a specific path or filename base.\n\t *\n\t * For example, if destinationPrefix is 'images/product', then the original might be\n\t * uploaded as 'images/product.jpg' and the resized versions as 'images/product-480.jpg', etc.\n\t */\n\tasync transcodeImage(\n\t\tbuffer: Buffer,\n\t\toriginalFilename: string,\n\t\tresolutions: number[]\n\t): Promise<{\n\t\toriginalUrl: string;\n\t\tresizedResults: Array<{ resolution: number; url: string }>;\n\t}> {\n\t\tconst extension = path.extname(originalFilename);\n\t\tconst contentType = `image/${extension.replace('.', '') || 'jpeg'}`;\n\t\tconst timestamp = moment().format('DDMMYYHmmss');\n\t\tconst randomId = Math.floor(Math.random() * 100);\n\n\t\tconst baseFilename = `${makeSlug(path.parse(originalFilename).name)}-${this.websiteName}-${timestamp}-${randomId}`;\n\n\t\tconst originalFileName = `${baseFilename}${extension}`;\n\t\tconst originalUrl = await this.uploadBuffer(buffer, originalFileName, contentType);\n\n\t\tconst metadata = await sharp(buffer).metadata();\n\t\tconst isLandscape = metadata.width && metadata.height ? metadata.width > metadata.height : true;\n\n\t\tconst resizedResults = await Promise.all(\n\t\t\tresolutions.map(async resolution => {\n\t\t\t\tconst resizeOptions = isLandscape ? { width: resolution } : { height: resolution };\n\t\t\t\tconst formatKey = (extension.replace('.', '') || 'jpeg') as keyof sharp.FormatEnum;\n\t\t\t\tconst resizedBuffer = await sharp(buffer)\n\t\t\t\t\t.resize({\n\t\t\t\t\t\t...resizeOptions,\n\t\t\t\t\t\twithoutEnlargement: true,\n\t\t\t\t\t})\n\t\t\t\t\t.toFormat(formatKey, { quality: 80 })\n\t\t\t\t\t.toBuffer();\n\t\t\t\tconst resizedFilename = `${baseFilename}-${resolution}${extension}`;\n\t\t\t\tconst resizedUrl = await this.uploadBuffer(resizedBuffer, resizedFilename, contentType);\n\t\t\t\treturn { resolution, url: resizedUrl };\n\t\t\t})\n\t\t);\n\n\t\treturn { originalUrl, resizedResults };\n\t}\n\n\t/**\n\t * Helper function to upload a buffer to a specified filename.\n\t */\n\tprivate async uploadBuffer(buffer: Buffer, filename: string, contentType: string): Promise<string> {\n\t\tconst file = this.bucket.file(filename);\n\t\tawait file.save(buffer, {\n\t\t\tresumable: false,\n\t\t\tcontentType,\n\t\t});\n\t\tawait file.makePublic();\n\t\treturn `https://storage.googleapis.com/${this.bucket.name}/${file.name}`;\n\t}\n\n\tasync getListFiles(): Promise<Array<{ name: string; url: string }>> {\n\t\tconst [files] = await this.bucket.getFiles();\n\t\treturn files.map(file => ({\n\t\t\tname: file.name!,\n\t\t\turl: file.metadata.mediaLink!,\n\t\t}));\n\t}\n\n\tasync downloadFile(filename: string): Promise<Buffer> {\n\t\tconst file = this.bucket.file(filename);\n\t\tconst [buffer] = await file.download();\n\t\treturn buffer;\n\t}\n\n\tasync deleteFile(filename: string): Promise<void> {\n\t\tconst file = this.bucket.file(filename);\n\t\tconst [exists] = await file.exists();\n\t\tif (!exists) {\n\t\t\tthrow new Error('File does not exist.');\n\t\t}\n\t\tawait file.delete();\n\t}\n\n\tasync getPublicUrlFromFilename(filename: string): Promise<{ status: boolean; url: string }> {\n\t\tconst file = this.bucket.file(filename);\n\t\tconst [exists] = await file.exists();\n\n\t\tif (!exists) {\n\t\t\treturn { status: false, url: '' };\n\t\t}\n\n\t\treturn {\n\t\t\tstatus: true,\n\t\t\turl: `https://storage.googleapis.com/${this.bucket.name}/${filename}`,\n\t\t};\n\t}\n\n\tpublic extractFilenameFromUrl(url: string): string {\n\t\ttry {\n\t\t\tconst urlObj = new URL(url);\n\t\t\tconst pathParts = urlObj.pathname.split('/');\n\t\t\treturn decodeURIComponent(pathParts[pathParts.length - 1]);\n\t\t} catch (err) {\n\t\t\tthrow new Error(`Invalid URL: ${url}`);\n\t\t}\n\t}\n\n\tasync deleteFileByUrl(url: string): Promise<void> {\n\t\tconst filename = this.extractFilenameFromUrl(url);\n\t\tconst file = this.bucket.file(filename);\n\t\tconst [exists] = await file.exists();\n\t\tif (!exists) {\n\t\t\tthrow new Error('File does not exist.');\n\t\t}\n\t\tawait file.delete();\n\t}\n\n\tasync downloadImage(url: string, retryTimes = 0): Promise<Buffer> {\n\t\tconst attemptDownload = async (): Promise<Buffer> => {\n\t\t\tconst response = await axios.get(url, {\n\t\t\t\tresponseType: 'arraybuffer',\n\t\t\t\ttimeout: 10000,\n\t\t\t\tmaxRedirects: 3,\n\t\t\t\tvalidateStatus: status => status >= 200 && status < 400,\n\t\t\t});\n\t\t\treturn Buffer.from(response.data, 'binary');\n\t\t};\n\n\t\ttry {\n\t\t\tconst buffer = await pRetry(attemptDownload, {\n\t\t\t\tretries: retryTimes,\n\t\t\t\tfactor: 2,\n\t\t\t\tminTimeout: 1000,\n\t\t\t\tmaxTimeout: 5000,\n\t\t\t\trandomize: true, // adds jitter for better efficiency\n\t\t\t\tonFailedAttempt: (error: any) => {\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`[downloadImage] Attempt ${error.attemptNumber} failed (${error.retriesLeft} retries left): ${error.message}`\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t});\n\n\t\t\treturn buffer;\n\t\t} catch (error: any) {\n\t\t\tif (axios.isAxiosError(error)) {\n\t\t\t\tconst status = error.response?.status;\n\t\t\t\tlet reason = 'Image download failed';\n\n\t\t\t\tswitch (status) {\n\t\t\t\t\tcase 403:\n\t\t\t\t\t\treason = 'Image URL is not valid or access forbidden (403)';\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 404:\n\t\t\t\t\t\treason = 'Image not found (404)';\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 429:\n\t\t\t\t\t\treason = 'Too many requests (429) — rate limited by server';\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treason = status\n\t\t\t\t\t\t\t? `Image download failed with status ${status}`\n\t\t\t\t\t\t\t: `Network or unknown error: ${error.message}`;\n\t\t\t\t}\n\n\t\t\t\tthrow new Error(reason);\n\t\t\t}\n\n\t\t\tthrow new Error(`Unexpected error downloading image: ${error.message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Uploads a buffer to Google Cloud Storage and makes it public\n\t */\n\tprivate async uploadToGCS(\n\t\tbuffer: Buffer,\n\t\tfilename: string,\n\t\tcontentType: string\n\t): Promise<{ filename: string; url: string }> {\n\t\tconst file = this.bucket.file(filename);\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\t// Create a write stream to upload the file\n\t\t\tconst blobStream = file.createWriteStream({\n\t\t\t\tresumable: false,\n\t\t\t\tcontentType,\n\t\t\t});\n\n\t\t\tblobStream.on('error', reject);\n\n\t\t\tblobStream.on('finish', async () => {\n\t\t\t\ttry {\n\t\t\t\t\t// Make the file publicly accessible\n\t\t\t\t\tawait file.makePublic();\n\t\t\t\t\tconst publicUrl = `https://storage.googleapis.com/${this.bucket.name}/${file.name}`;\n\t\t\t\t\tresolve({ filename: file.name, url: publicUrl });\n\t\t\t\t} catch (err) {\n\t\t\t\t\treject(err);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Start uploading the buffer\n\t\t\tblobStream.end(buffer);\n\t\t});\n\t}\n\n\t/**\n\t * Uploads and converts an image to WebP format, resizes if needed, and uploads to GCS\n\t */\n\tasync uploadProcessedImageToWebp(\n\t\tbuffer: Buffer,\n\t\toriginalFilename: string,\n\t\toptions?: { quality?: number; width?: number; height?: number }\n\t): Promise<{ filename: string; url: string }> {\n\t\tlet fileType: string | undefined;\n\n\t\ttry {\n\t\t\tconst newFilename = this.generateFilename(originalFilename, '.webp');\n\t\t\tconst quality = options?.quality ?? 80;\n\n\t\t\t// Detect actual file type\n\t\t\tfileType = (await FileType.fileTypeFromBuffer(buffer))?.ext;\n\t\t\tif (!fileType) throw new Error('Unable to detect image type');\n\n\t\t\t// Get original image dimensions if width or height is missing\n\t\t\tconst metadata = await sharp(buffer).metadata();\n\t\t\tconst width = options?.width || metadata.width;\n\t\t\tconst height = options?.height || metadata.height;\n\n\t\t\t// Convert to WebP and resize\n\t\t\tconst processedImage: sharp.Sharp = sharp(buffer)\n\t\t\t\t.resize(width, height, { fit: 'inside' })\n\t\t\t\t.webp({ quality });\n\n\t\t\tconst file = this.bucket.file(newFilename);\n\n\t\t\treturn await new Promise((resolve, reject) => {\n\t\t\t\tconst blobStream = file.createWriteStream({\n\t\t\t\t\tresumable: false,\n\t\t\t\t\tcontentType: 'image/webp',\n\t\t\t\t});\n\n\t\t\t\tprocessedImage.on('error', (err: Error) => {\n\t\t\t\t\treject(err);\n\t\t\t\t});\n\n\t\t\t\tblobStream.on('error', (err: Error) => {\n\t\t\t\t\treject(err);\n\t\t\t\t});\n\n\t\t\t\tblobStream.on('finish', async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait file.makePublic();\n\t\t\t\t\t\tconst publicUrl = `https://storage.googleapis.com/${this.bucket.name}/${file.name}`;\n\t\t\t\t\t\tresolve({ filename: file.name, url: publicUrl });\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\treject(err);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tprocessedImage.pipe(blobStream);\n\t\t\t});\n\t\t} catch (err: any) {\n\t\t\tconsole.error('Processed image upload failed:', err);\n\t\t\tif (fileType) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`${fileType.toUpperCase()} format not supported. Please use JPEG, PNG, or WebP format instead.`\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow new Error(`Processed image upload failed: ${err.message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Uploads any supported file type to GCS and returns its public URL\n\t */\n\tasync uploadFile(\n\t\tbuffer: Buffer,\n\t\toriginalFilename: string,\n\t\toptions?: {\n\t\t\tquality?: number;\n\t\t\twidth?: number;\n\t\t\theight?: number;\n\t\t\twithExtension?: boolean;\n\t\t\twithOriginalFilename?: boolean;\n\t\t}\n\t): Promise<{ filename: string; url: string }> {\n\t\tconst newFilename = options?.withOriginalFilename\n\t\t\t? originalFilename\n\t\t\t: this.generateFilename(originalFilename);\n\t\tconst extension = path.extname(newFilename).toLowerCase();\n\n\t\t// Guess the MIME type using the mime-types library\n\t\tconst contentType = mime.lookup(extension) || 'application/octet-stream';\n\n\t\t// Special image handling (compression)\n\t\tif (contentType.startsWith('image/')) {\n\t\t\tif (options?.withExtension) {\n\t\t\t\treturn this.uploadImage(buffer, originalFilename);\n\t\t\t} else {\n\t\t\t\treturn this.uploadProcessedImageToWebp(buffer, originalFilename, options);\n\t\t\t}\n\t\t}\n\n\t\treturn this.uploadToGCS(buffer, newFilename, contentType);\n\t}\n}\n"]}
@@ -22,7 +22,7 @@ Perfect for sharing types between frontend and backend applications.
22
22
 
23
23
  ## Version
24
24
 
25
- Version: 1.2.5
25
+ Version: 1.2.6
26
26
 
27
27
  ## Dependencies
28
28
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lyxa.ai/types",
3
- "version": "1.2.5",
3
+ "version": "1.2.6",
4
4
  "description": "Lyxa type definitions and validation schemas for both frontend and backend",
5
5
  "author": "elie <42282499+Internalizable@users.noreply.github.com>",
6
6
  "license": "MIT",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lyxa.ai/core",
3
- "version": "1.2.5",
3
+ "version": "1.2.6",
4
4
  "description": "The Core system of the Lyxa services.",
5
5
  "author": "elie <42282499+Internalizable@users.noreply.github.com>",
6
6
  "license": "MIT",