build: refresh release artifacts after image variants and upload compression

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
mahmood
2026-11-14 15:12:15 +03:30
co-authored by Cursor
parent 3fe0a930c7
commit 2760b0d2b5
234 changed files with 450 additions and 221 deletions
+240 -12
View File
@@ -93325,6 +93325,165 @@ var require_upload_path = __commonJS({
}
});
// dist/modules/admin-uploads/image-variants.service.js
var require_image_variants_service = __commonJS({
"dist/modules/admin-uploads/image-variants.service.js"(exports2) {
"use strict";
var __decorate4 = exports2 && exports2.__decorate || function(decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var ImageVariantService_1;
Object.defineProperty(exports2, "__esModule", { value: true });
exports2.ImageVariantService = exports2.ORIGINAL_CEILING_BYTES = exports2.ORIGINAL_TARGET_BYTES = exports2.IMAGE_WIDTHS = void 0;
var common_12 = require_common();
var promises_1 = require("node:fs/promises");
var node_path_12 = require("node:path");
var upload_path_1 = require_upload_path();
exports2.IMAGE_WIDTHS = [200, 400, 600, 800, 1200, 1600];
var WARM_WIDTHS = [600, 1600];
var RESIZABLE = /* @__PURE__ */ new Set([".jpg", ".jpeg", ".png", ".webp", ".avif"]);
var RESIZABLE_MIME = /* @__PURE__ */ new Set(["image/jpeg", "image/png", "image/webp", "image/avif"]);
var WEBP_QUALITY = 78;
exports2.ORIGINAL_TARGET_BYTES = 500 * 1024;
exports2.ORIGINAL_CEILING_BYTES = 1024 * 1024;
var ORIGINAL_ATTEMPTS = [
{ side: 2e3, quality: 82 },
{ side: 2e3, quality: 72 },
{ side: 1600, quality: 72 },
{ side: 1600, quality: 62 },
{ side: 1280, quality: 60 }
];
var ImageVariantService = ImageVariantService_1 = class ImageVariantService {
logger = new common_12.Logger(ImageVariantService_1.name);
cacheDir = (0, node_path_12.join)((0, upload_path_1.getUploadDir)(), ".variants");
inFlight = /* @__PURE__ */ new Map();
sharp;
static snapWidth(raw) {
const n = Number(raw);
if (!Number.isFinite(n) || n <= 0)
return 800;
return exports2.IMAGE_WIDTHS.find((w) => w >= n) ?? exports2.IMAGE_WIDTHS[exports2.IMAGE_WIDTHS.length - 1];
}
static isResizable(filename) {
return RESIZABLE.has((0, node_path_12.extname)(filename).toLowerCase());
}
async resolve(filename, width) {
const original = (0, upload_path_1.resolveStoredUpload)(filename);
if (!original)
return null;
const fallback = {
path: original,
type: (0, upload_path_1.mimeForUpload)(original) ?? "application/octet-stream",
optimized: false
};
if (!ImageVariantService_1.isResizable(original))
return fallback;
const variant = await this.variant(original, width);
if (!variant)
return fallback;
const [v, o] = await Promise.all([(0, promises_1.stat)(variant), (0, promises_1.stat)(original)]);
if (v.size >= o.size)
return fallback;
return { path: variant, type: "image/webp", optimized: true };
}
/**
* Shrinks an uploaded raster image before it is written to disk, so an 8 MB
* phone photo is stored as a WebP of roughly ORIGINAL_TARGET_BYTES. Returns
* null — store the upload as-is — when the file is already small, is not a
* resizable format, sharp is missing, or re-encoding would not make it smaller.
*/
async compressUpload(buffer, mimeType, filename) {
if (buffer.length <= exports2.ORIGINAL_TARGET_BYTES)
return null;
if (!RESIZABLE_MIME.has(mimeType))
return null;
const sharp = this.loadSharp();
if (!sharp)
return null;
let smallest = null;
try {
for (const { side, quality } of ORIGINAL_ATTEMPTS) {
const out = await sharp(buffer, { failOn: "none" }).rotate().resize({ width: side, height: side, fit: "inside", withoutEnlargement: true }).webp({ quality }).toBuffer();
if (!smallest || out.length < smallest.length)
smallest = out;
if (out.length <= exports2.ORIGINAL_TARGET_BYTES)
break;
}
} catch (err) {
this.logger.warn(`compress failed for ${filename}: ${err.message}`);
return null;
}
if (!smallest || smallest.length >= buffer.length)
return null;
if (smallest.length > exports2.ORIGINAL_CEILING_BYTES) {
this.logger.warn(`${filename} is still ${smallest.length} bytes after compression`);
}
return { buffer: smallest, ext: ".webp", mimeType: "image/webp" };
}
/** Fire-and-forget pre-render for a freshly stored upload. */
warm(filename) {
if (!ImageVariantService_1.isResizable(filename))
return;
for (const width of WARM_WIDTHS)
void this.resolve(filename, width);
}
async variant(original, width) {
const target = (0, node_path_12.join)(this.cacheDir, String(width), `${(0, node_path_12.basename)(original)}.webp`);
if (await isFresh(target, original))
return target;
const pending = this.inFlight.get(target);
if (pending)
return pending;
const job = this.render(original, target, width).finally(() => this.inFlight.delete(target));
this.inFlight.set(target, job);
return job;
}
async render(original, target, width) {
const sharp = this.loadSharp();
if (!sharp)
return null;
const tmp = `${target}.${process.pid}.${Date.now()}.tmp`;
try {
await (0, promises_1.mkdir)((0, node_path_12.dirname)(target), { recursive: true });
await sharp(original, { failOn: "none" }).rotate().resize({ width, withoutEnlargement: true }).webp({ quality: WEBP_QUALITY }).toFile(tmp);
await (0, promises_1.rename)(tmp, target);
return target;
} catch (err) {
this.logger.warn(`resize failed for ${(0, node_path_12.basename)(original)} @${width}: ${err.message}`);
await (0, promises_1.unlink)(tmp).catch(() => void 0);
return null;
}
}
loadSharp() {
if (this.sharp !== void 0)
return this.sharp;
try {
this.sharp = require("sharp");
} catch {
this.sharp = null;
this.logger.warn("sharp is not installed; images are served without resizing");
}
return this.sharp;
}
};
exports2.ImageVariantService = ImageVariantService;
exports2.ImageVariantService = ImageVariantService = ImageVariantService_1 = __decorate4([
(0, common_12.Injectable)()
], ImageVariantService);
async function isFresh(target, original) {
try {
const [t, o] = await Promise.all([(0, promises_1.stat)(target), (0, promises_1.stat)(original)]);
return t.mtimeMs >= o.mtimeMs;
} catch {
return false;
}
}
}
});
// dist/modules/admin-uploads/admin-uploads.service.js
var require_admin_uploads_service = __commonJS({
"dist/modules/admin-uploads/admin-uploads.service.js"(exports2) {
@@ -93346,12 +93505,14 @@ var require_admin_uploads_service = __commonJS({
var promises_1 = require("node:fs/promises");
var node_path_12 = require("node:path");
var prisma_service_1 = require_prisma_service();
var image_variants_service_1 = require_image_variants_service();
var upload_path_1 = require_upload_path();
var AdminUploadsService = class AdminUploadsService {
static {
AdminUploadsService_1 = this;
}
prisma;
variants;
/** Matches legacy's flat public/storage directory. */
dir = (0, upload_path_1.getUploadDir)();
/** Mirrors legacy's `type` field: 1 = image, 2 = any other document. */
@@ -93359,28 +93520,32 @@ var require_admin_uploads_service = __commonJS({
static ALLOWED = /^(image\/(jpeg|png|gif|webp|svg\+xml)|application\/pdf)$/;
/** 8 MB. Legacy relied on PHP's upload_max_filesize; this makes it explicit. */
static MAX_BYTES = 8 * 1024 * 1024;
constructor(prisma) {
constructor(prisma, variants) {
this.prisma = prisma;
this.variants = variants;
}
async store(file2, purpose, actorAdminUserId) {
if (!file2)
throw new common_12.BadRequestException("\u0641\u0627\u06CC\u0644\u06CC \u0627\u0631\u0633\u0627\u0644 \u0646\u0634\u062F\u0647 \u0627\u0633\u062A");
throw new common_12.BadRequestException("\u0641\u0627\u06CC\u0644\u06CC \u0627\u0646\u062A\u062E\u0627\u0628 \u0646\u0634\u062F\u0647 \u0627\u0633\u062A");
if (file2.size > AdminUploadsService_1.MAX_BYTES) {
throw new common_12.BadRequestException("\u062D\u062C\u0645 \u0641\u0627\u06CC\u0644 \u0628\u06CC\u0634 \u0627\u0632 \u062D\u062F \u0645\u062C\u0627\u0632 \u0627\u0633\u062A (\u06F8 \u0645\u06AF\u0627\u0628\u0627\u06CC\u062A)");
throw new common_12.BadRequestException("\u062D\u062C\u0645 \u0641\u0627\u06CC\u0644 \u0628\u06CC\u0634\u062A\u0631 \u0627\u0632 \u06F8 \u0645\u06AF\u0627\u0628\u0627\u06CC\u062A \u0627\u0633\u062A\u061B \u0641\u0627\u06CC\u0644 \u06A9\u0648\u0686\u06A9\u200C\u062A\u0631\u06CC \u0627\u0646\u062A\u062E\u0627\u0628 \u06A9\u0646\u06CC\u062F");
}
if (!AdminUploadsService_1.ALLOWED.test(file2.mimetype)) {
throw new common_12.BadRequestException("\u0646\u0648\u0639 \u0641\u0627\u06CC\u0644 \u0645\u062C\u0627\u0632 \u0646\u06CC\u0633\u062A");
throw new common_12.BadRequestException("\u0627\u06CC\u0646 \u0646\u0648\u0639 \u0641\u0627\u06CC\u0644 \u067E\u0634\u062A\u06CC\u0628\u0627\u0646\u06CC \u0646\u0645\u06CC\u200C\u0634\u0648\u062F\u061B \u0641\u0642\u0637 JPG\u060C PNG\u060C WebP\u060C GIF\u060C SVG \u06CC\u0627 PDF");
}
const ext = (0, node_path_12.extname)(file2.originalname).toLowerCase();
const compressed = await this.variants.compressUpload(file2.buffer, file2.mimetype, file2.originalname);
const buffer = compressed?.buffer ?? file2.buffer;
const ext = compressed?.ext ?? (0, node_path_12.extname)(file2.originalname).toLowerCase();
const stored = (0, node_crypto_1.createHash)("md5").update(`${Date.now()}${file2.originalname}${(0, node_crypto_1.randomUUID)()}`).digest("hex") + ext;
await (0, promises_1.mkdir)(this.dir, { recursive: true });
await (0, promises_1.writeFile)((0, node_path_12.join)(this.dir, stored), file2.buffer);
await (0, promises_1.writeFile)((0, node_path_12.join)(this.dir, stored), buffer);
this.variants.warm(stored);
return this.prisma.uploadedFile.create({
data: {
url: `/uploads/${stored}`,
originalName: file2.originalname,
mimeType: file2.mimetype,
sizeBytes: file2.size,
mimeType: compressed?.mimeType ?? file2.mimetype,
sizeBytes: buffer.length,
purpose: purpose ?? null,
uploadedByAdminId: actorAdminUserId
}
@@ -93400,7 +93565,10 @@ var require_admin_uploads_service = __commonJS({
exports2.AdminUploadsService = AdminUploadsService;
exports2.AdminUploadsService = AdminUploadsService = AdminUploadsService_1 = __decorate4([
(0, common_12.Injectable)(),
__metadata3("design:paramtypes", [prisma_service_1.PrismaService])
__metadata3("design:paramtypes", [
prisma_service_1.PrismaService,
image_variants_service_1.ImageVariantService
])
], AdminUploadsService);
}
});
@@ -93468,6 +93636,64 @@ var require_admin_uploads_controller = __commonJS({
}
});
// dist/modules/admin-uploads/public-images.controller.js
var require_public_images_controller = __commonJS({
"dist/modules/admin-uploads/public-images.controller.js"(exports2) {
"use strict";
var __decorate4 = exports2 && exports2.__decorate || function(decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata3 = exports2 && exports2.__metadata || function(k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param3 = exports2 && exports2.__param || function(paramIndex, decorator) {
return function(target, key) {
decorator(target, key, paramIndex);
};
};
Object.defineProperty(exports2, "__esModule", { value: true });
exports2.PublicImagesController = void 0;
var common_12 = require_common();
var node_fs_1 = require("node:fs");
var guards_1 = require_guards2();
var image_variants_service_1 = require_image_variants_service();
var PublicImagesController = class PublicImagesController {
variants;
constructor(variants) {
this.variants = variants;
}
async serve(filename, w, res) {
const image = await this.variants.resolve(filename, image_variants_service_1.ImageVariantService.snapWidth(w));
if (!image)
throw new common_12.NotFoundException("\u0641\u0627\u06CC\u0644 \u06CC\u0627\u0641\u062A \u0646\u0634\u062F");
res.setHeader("Cache-Control", image.optimized ? "public, max-age=31536000, immutable" : "public, max-age=86400");
return new common_12.StreamableFile((0, node_fs_1.createReadStream)(image.path), {
type: image.type,
disposition: "inline"
});
}
};
exports2.PublicImagesController = PublicImagesController;
__decorate4([
(0, common_12.Get)(":filename"),
__param3(0, (0, common_12.Param)("filename")),
__param3(1, (0, common_12.Query)("w")),
__param3(2, (0, common_12.Res)({ passthrough: true })),
__metadata3("design:type", Function),
__metadata3("design:paramtypes", [String, Object, Object]),
__metadata3("design:returntype", Promise)
], PublicImagesController.prototype, "serve", null);
exports2.PublicImagesController = PublicImagesController = __decorate4([
(0, guards_1.Public)(),
(0, common_12.Controller)("img"),
__metadata3("design:paramtypes", [image_variants_service_1.ImageVariantService])
], PublicImagesController);
}
});
// dist/modules/admin-uploads/public-uploads.controller.js
var require_public_uploads_controller = __commonJS({
"dist/modules/admin-uploads/public-uploads.controller.js"(exports2) {
@@ -93534,17 +93760,19 @@ var require_admin_uploads_module = __commonJS({
var common_12 = require_common();
var prisma_module_1 = require_prisma_module();
var admin_uploads_controller_1 = require_admin_uploads_controller();
var public_images_controller_1 = require_public_images_controller();
var public_uploads_controller_1 = require_public_uploads_controller();
var admin_uploads_service_1 = require_admin_uploads_service();
var image_variants_service_1 = require_image_variants_service();
var AdminUploadsModule = class AdminUploadsModule {
};
exports2.AdminUploadsModule = AdminUploadsModule;
exports2.AdminUploadsModule = AdminUploadsModule = __decorate4([
(0, common_12.Module)({
imports: [prisma_module_1.PrismaModule],
controllers: [admin_uploads_controller_1.AdminUploadsController, public_uploads_controller_1.PublicUploadsController],
providers: [admin_uploads_service_1.AdminUploadsService],
exports: [admin_uploads_service_1.AdminUploadsService]
controllers: [admin_uploads_controller_1.AdminUploadsController, public_uploads_controller_1.PublicUploadsController, public_images_controller_1.PublicImagesController],
providers: [admin_uploads_service_1.AdminUploadsService, image_variants_service_1.ImageVariantService],
exports: [admin_uploads_service_1.AdminUploadsService, image_variants_service_1.ImageVariantService]
})
], AdminUploadsModule);
}