diff --git a/backend/package.json b/backend/package.json index 2024a22..9f2c296 100755 --- a/backend/package.json +++ b/backend/package.json @@ -19,7 +19,7 @@ "test:integration:json": "jest -c jest.integration.config.js --runInBand --json --outputFile=integration-results.json", "test:integration:cov": "jest -c jest.integration.config.js --runInBand --coverage --forceExit", "bench:hashing": "tsx scripts/bench-hash-latency.ts", - "backfill:images": "tsx scripts/backfill-image-reencode.ts", + "backfill:images": "node dist/backfillImageReencode.js", "db:test:up": "docker compose -f docker-compose.test.yml up -d", "db:test:down": "docker compose -f docker-compose.test.yml down -v", "migrate:up": "node migrate.js up", diff --git a/backend/scripts/backfill-image-reencode.ts b/backend/src/backfillImageReencode.ts similarity index 78% rename from backend/scripts/backfill-image-reencode.ts rename to backend/src/backfillImageReencode.ts index c16b048..32bf5b4 100644 --- a/backend/scripts/backfill-image-reencode.ts +++ b/backend/src/backfillImageReencode.ts @@ -15,11 +15,25 @@ * - It never renames the stored file, so item_images.image_path stays correct * and no database write is needed at all. * + * It lives in src/ rather than scripts/ so that it compiles into dist and ships + * in the container image. `scripts/` is excluded by tsconfig, is never copied by + * the Dockerfile, and would need `tsx` — a devDependency that `npm install + * --omit=dev` removes. An operational task that can only be useful where the + * images are has to be somewhere the image actually carries it, which is the + * same reason `migrate.js` sits where it does. See #231. + * * Usage * ----- + * Locally, after `npm run build`: + * * npm run backfill:images # report only * npm run backfill:images -- --apply # rewrite the files * + * In a deployed container, identically — package.json ships in the image: + * + * docker exec npm run backfill:images + * docker exec npm run backfill:images -- --apply + * * Point it at QA first. Compare a handful of images by eye before production, * and take a backup that you have confirmed restores. */ @@ -27,8 +41,8 @@ import sharp from 'sharp'; import { promises as fs } from 'fs'; import path from 'path'; -import { pool } from '../src/db'; -import { needsProcessing, reencodeInPlace } from '../src/imageProcessing'; +import { pool } from './db'; +import { needsProcessing, reencodeInPlace } from './imageProcessing'; const UPLOADS_DIR = process.env.UPLOADS_DIR || '/app/uploads'; const APPLY = process.argv.includes('--apply'); @@ -152,9 +166,17 @@ async function run(): Promise { } } -run() - .catch((err) => { - console.error(err); - process.exitCode = 1; - }) - .finally(() => pool.end()); +// Guarded rather than run on import. This file lives in src/ so that it +// compiles into dist and therefore ships in the image (#231) — but that puts a +// catalogue-wide, irreversible rewrite in the same directory as the modules the +// server imports at boot. Without this guard, importing it by mistake would run +// it. Nothing imports it today; the guard is here so that staying true does not +// depend on anyone noticing. +if (require.main === module) { + run() + .catch((err) => { + console.error(err); + process.exitCode = 1; + }) + .finally(() => pool.end()); +}