chore: prepare for public release

- add repository/homepage/bugs metadata; target Directus ^11
- genericize internal deployment references
- document install, compatibility, scheduling, security
- stop tracking internal .opencode work artifacts
This commit is contained in:
Rawman Grey 2026-10-25 12:25:19 +03:00
parent c8f8bbc5ac
commit 94f197bdec
10 changed files with 181 additions and 706 deletions

View file

@ -8,29 +8,55 @@ A Directus **bundle**:
- **upload hook** — warm previews right after an image upload.
- **new-preset trigger** — `Run now` warms every preset (system + custom) for existing images.
- **backfill job** — resumable, window-aware sweep over the existing library.
- **admin module** — progress, storage breakdown, configuration, diagnostics, and API reference.
- **admin module** — progress, storage breakdown, configuration, diagnostics, and an API reference.
Target: self-hosted Directus **11.17.4** (PM2 cluster, local disk storage).
## Requirements
## Why this approach (read AGENTS.md too)
- Directus **11.x** (tested on **11.17.4**).
- Node 18+.
- A **non-sandboxed** local extension (it uses Directus's internal services at runtime — see
Compatibility).
- Local disk storage is supported out of the box; other storage drivers work for disk reporting through
the Directus storage manager.
## Why this approach
The cache file is `<filename_disk>__<object-hash(resolved transforms)>.<ext>`. The hash depends on the
RESOLVED transforms, and every `system-*` preset is `format:'auto'` — which resolves differently
server-side (jpg/png) than in a browser (avif). We therefore generate **in-process** with an explicit
`acceptFormat` (`avif` + `webp`), reproducing the browser's cache file byte-for-byte without any HTTP
request. Naive warming (or the popular community extension) silently misses.
server-side (jpg/png) than in a browser (avif). This extension therefore generates **in-process** with an
explicit `acceptFormat` (`avif` + `webp`), reproducing the browser's cache file byte-for-byte without any
HTTP request. Naive warming (and several community extensions) silently misses because of this.
## Install / build / publish
## Install
```bash
git clone https://code.at.locus.im/Rawman/directus-extension-generate-image-previews.git
cd directus-extension-generate-image-previews
npm install
npm run build
```
Copy the build into your Directus extensions directory:
```bash
cp -r dist package.json /path/to/directus/extensions/directus-extension-generate-image-previews/
```
Restart Directus (or let `EXTENSIONS_AUTO_RELOAD` pick it up). The **Image Previews** module appears in
the admin sidebar.
## Development
```bash
npm run build # emits dist/app.js + dist/api.js
npm run typecheck # 0 errors
npm test # unit tests
npm run dev # watch build
npm run publish # scp dist + package.json to the (staging) deploy target
npm run link # link into a local Directus extensions dir
```
An isolated Directus 11.17.4 stack for smoke testing lives in `dev/` — see `dev/README.md`.
## Settings
Defaults are applied automatically; everything is editable at runtime from the admin module — no rebuild.
@ -55,6 +81,8 @@ Defaults are applied automatically; everything is editable at runtime from the a
`format:'auto'` follows `formats`.
- A custom preset whose `key` equals a system key is **shadowed** (system wins, same as Directus) and is
flagged in the admin module.
- Unsupported format strings (e.g. `bmp`) fail at generation; the error is shown in Recent operations
and `GET /image-previews/ops`.
## Storage reporting
@ -63,7 +91,7 @@ Defaults are applied automatically; everything is editable at runtime from the a
## API endpoints
All require an admin session or admin token. Human-readable fields accompany machine-readable ones.
All require a Directus admin session or admin token. Human-readable fields accompany machine-readable ones.
- `GET /image-previews/status` — run progress, rate, ETA, window state, ISO + human dates
- `GET /image-previews/config`, `PUT /image-previews/config`
@ -77,16 +105,27 @@ All require an admin session or admin token. Human-readable fields accompany mac
The admin module includes a full API reference with curl examples.
## Scheduling
Scheduled runs are window-bound; an external cron can trigger them:
```bash
0 * * * * curl -fsS -X POST http://localhost:8055/image-previews/run \
-H 'Authorization: Bearer <admin-token>' -H 'Content-Type: application/json' -d '{}'
```
`Run now` in the admin module ignores the window.
## Safe testing & deployment
Never test against the prod instance.
Never test against a production instance.
- **Local / staging** (`dev/compose.dev.yml`): Directus 11.17.4 + its own postgres + volumes, on separate
ports. Shares nothing with prod. See `dev/README.md`.
ports. Shares nothing with production. See `dev/README.md`.
- **Fail-open**: entrypoints never throw into Directus core.
- **Rollout**: build → verify on staging → back up previous `dist/` → deploy → healthcheck → enable.
**Rollback**: restore previous `dist/`.
- Scripts: `dev/deploy-staging.sh`, `dev/rollback-staging.sh`, template `dev/compose.staging.yml`.
- **Rollout**: build → verify on staging → back up the previous `dist/` → deploy → healthcheck → enable.
**Rollback**: restore the previous `dist/`.
- Helpers: `dev/deploy-staging.sh`, `dev/rollback-staging.sh`, template `dev/compose.staging.yml`.
## Caveats
@ -94,9 +133,16 @@ Never test against the prod instance.
width or height exceeds `ASSETS_TRANSFORM_IMAGE_MAX_DIMENSION` (default **6000 px**). This is a Directus
env var, not something this extension imposes. To process larger images, raise it on the Directus
instance (and watch memory). Upload size limits (`FILES_MAX_UPLOAD_SIZE`, `MAX_PAYLOAD_SIZE`) are separate.
- Warm only after uploads are committed (local writes are non-atomic).
- Warm only after uploads are committed (local storage writes are non-atomic).
- In-process generation bypasses the HTTP rate limiter; bound it with `concurrency` + the window.
- Unsupported custom preset formats (e.g. `bmp`) fail at generation time; the error appears in
Recent operations / `/ops`.
- PM2 cluster: shared state is file-backed, so all workers see the same run state.
See `.opencode/goal.md` for the full contract and `.opencode/feature_list.json` for the task list.
## Compatibility
Tested against Directus **11.17.4**. The extension reads Directus's own transform pipeline and storage
manager (`@directus/api/utils/transformations`, `@directus/api/storage/index`) via runtime imports; these
are **not a public API** and may change between Directus versions. Re-verify after a Directus upgrade,
especially the hash-match gate (`resolve-plan` vs a real browser asset request).
The extension is not sandboxed: Directus's sandbox forbids importing anything except `directus:api`, which
this extension needs for storage/transform access.