the development server gets av-club too
The cropper needs an encoder, and only the build was told where one is. That made development the one place the old behaviour survived: the framing approved in the admin, the picture dev showed, and the file that shipped would have been three different things — which is the class of bug this whole change exists to remove. The port is ephemeral by design, so it is read at start rather than written to a file. av-club moving leaves dev pointing at a port that has gone; restarting dev from the panel fixes it, and startServer already deletes and re-creates precisely so a changed port is picked up. /images/ gets a year and immutable in the nginx config. Earned rather than assumed: the filename is a hash of the original, the framing, the slot and the width, so the bytes at a URL cannot legitimately change. That is the difference from /derived/, which is rewritten in place and therefore capped at thirty days. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,8 @@ import { randomBytes } from 'node:crypto';
|
|||||||
import { encryptSecret, decryptSecret } from 'officerdb/crypto';
|
import { encryptSecret, decryptSecret } from 'officerdb/crypto';
|
||||||
import { readDatabases } from './databases';
|
import { readDatabases } from './databases';
|
||||||
import { closeDevPort, openDevPort } from './firewall';
|
import { closeDevPort, openDevPort } from './firewall';
|
||||||
|
import { sidecarPort } from '@@/sidecar-registry';
|
||||||
|
import { getOwnerUser } from 'officerdb';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The site's DEVELOPMENT server, under pm2.
|
* The site's DEVELOPMENT server, under pm2.
|
||||||
@@ -300,6 +302,31 @@ export async function startServer(which: ServerName): Promise<{ ok: boolean; out
|
|||||||
POSTGRES_URL_DEV: url.toString(),
|
POSTGRES_URL_DEV: url.toString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
How the development server reaches av-club — the same two values the BUILD gets, for the same
|
||||||
|
reason and by the same route.
|
||||||
|
|
||||||
|
The site crops each placement to the exact shape and size its slot renders at, rather than shipping
|
||||||
|
a whole photograph and asking CSS to hide most of it. Given only to the build, that would make
|
||||||
|
development the one place the old behaviour survived: the crop you approved in the admin, the
|
||||||
|
picture dev showed you, and the file that actually shipped would be three different things. That is
|
||||||
|
precisely the class of bug this whole change exists to remove, so dev runs the same path.
|
||||||
|
|
||||||
|
The port is EPHEMERAL by design — av-club binds whatever is free and reports it — so this is read
|
||||||
|
at start rather than written into a file. A restart of av-club therefore leaves dev pointing at a
|
||||||
|
port that has moved, and the fix is to restart dev from the panel, which is where its environment
|
||||||
|
is assembled anyway. Worth knowing rather than worth engineering around: `startServer` deletes and
|
||||||
|
re-creates the process precisely so a changed port is picked up.
|
||||||
|
*/
|
||||||
|
const avClubPort = sidecarPort('av-club');
|
||||||
|
// av-club resolves every path against a user's own media directory, so it has to be told who this is
|
||||||
|
// working for. The owner, because that is whose root location this plugin administers.
|
||||||
|
const owner = await getOwnerUser();
|
||||||
|
if (avClubPort && owner?.email) {
|
||||||
|
env.AV_CLUB_URL = `http://127.0.0.1:${avClubPort}`;
|
||||||
|
env.AV_CLUB_USER = owner.email;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Open the firewall to the proxy BEFORE starting, so the port is reachable the moment it binds.
|
Open the firewall to the proxy BEFORE starting, so the port is reachable the moment it binds.
|
||||||
|
|
||||||
|
|||||||
+14
-1
@@ -209,7 +209,11 @@ export async function buildSite(secrets: {
|
|||||||
* compression, and no cache headers at all, so every asset carried a TTL of zero and a returning
|
* compression, and no cache headers at all, so every asset carried a TTL of zero and a returning
|
||||||
* visitor re-downloaded the whole site.
|
* visitor re-downloaded the whole site.
|
||||||
*
|
*
|
||||||
* ── Three lifetimes, because there are three kinds of file ──
|
* ── Four lifetimes, because there are four kinds of file ──
|
||||||
|
*
|
||||||
|
* `images/` are placements cropped to their slot, named by a hash of everything that decides their
|
||||||
|
* bytes. A year, immutable, and earned: the file at that URL cannot change, because a change produces
|
||||||
|
* a different name. This is exactly what `derived/` cannot have.
|
||||||
*
|
*
|
||||||
* `derived/` renditions are rebuilt IN PLACE — av-club replaces the contents of `1280.webp` rather
|
* `derived/` renditions are rebuilt IN PLACE — av-club replaces the contents of `1280.webp` rather
|
||||||
* than writing a new name. So they cannot be `immutable`, however much they look like they could be:
|
* than writing a new name. So they cannot be `immutable`, however much they look like they could be:
|
||||||
@@ -258,6 +262,15 @@ const NGINX_CONF = `server {
|
|||||||
add_header Cache-Control "public";
|
add_header Cache-Control "public";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Placements cropped to their slot. A year and immutable, and this one is EARNED rather than assumed:
|
||||||
|
# the filename is a hash of the original, the framing, the slot and the width, so the bytes at a given
|
||||||
|
# URL can never legitimately change. A re-crop is a different name, and the HTML that carries it is
|
||||||
|
# revalidated every visit. This is the difference from /derived/ above, which is rewritten in place.
|
||||||
|
location ^~ /images/ {
|
||||||
|
expires 1y;
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
}
|
||||||
|
|
||||||
location ^~ /media/ {
|
location ^~ /media/ {
|
||||||
expires 30d;
|
expires 30d;
|
||||||
add_header Cache-Control "public";
|
add_header Cache-Control "public";
|
||||||
|
|||||||
Reference in New Issue
Block a user