Every performance decision here was made from a Lighthouse run somebody did by hand in DevTools and typed into a conversation. That loop is slow and it is lossy: nothing measured after a build, so three real defects sat live for weeks — a `sizes` that overstated a column by 48px, font preloads that had gone missing, an LCP image left lazy by a rename. api/lighthouse.ts runs it: both form factors in about 20 seconds, four categories, the five metrics, and every failing audit with the resources it names. A finding that says "Improve image delivery — 32 KiB" is not actionable; the same finding with the URL and the size served is a one-line fix. The browser is looked for in three places before anything is downloaded — CHROME_PATH, chrome-launcher's own search, then the Chrome-family binaries by name, which is what finds the Brave already on this machine. chrome-launcher THROWS rather than returning null when it finds nothing, so an unguarded call never reaches the fallback; that is caught. Only if all three miss does @puppeteer/browsers fetch one, as a library call rather than a postinstall, because bun does not run postinstall for an untrusted package and a silent no-op there would surface as a failure at the first audit. First result: Total Blocking Time is 0 ms on both form factors, down from 130. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
115 lines
5.5 KiB
TypeScript
115 lines
5.5 KiB
TypeScript
import type { PluginManifest } from '@@/plugins/manifest';
|
|
|
|
/**
|
|
* Fofos — the fofos website's admin, inside Officer.
|
|
*
|
|
* ── What it replaces ──
|
|
*
|
|
* A server-rendered admin on its own subdomain with its own argon2 passwords, its own session cookie
|
|
* and its own `/admin/setup` bootstrap. Every part of that duplicated something Officer already does,
|
|
* and none of it could be shared: giving somebody access to the machine still meant giving them
|
|
* access to the admin, separately, by hand. That is the whole reason this is a plugin.
|
|
*
|
|
* ── It holds no content ──
|
|
*
|
|
* fofos owns its own database and its own media store, and this reads and writes them over HTTP. The
|
|
* only thing in Officer's database is the connection — a URL and a token.
|
|
*
|
|
* That is a deliberate property rather than a convenience. **Deleting this plugin cannot lose a
|
|
* photograph or a line of the client's copy**, with the "delete its data" checkbox ticked or not,
|
|
* because none of it was ever here. The alternative — a `db/schema.ts` carrying fofos's own tables —
|
|
* would have put every one of them under an installer that is allowed to drop them.
|
|
*
|
|
* ── The permission is grantable; the credential is not ──
|
|
*
|
|
* Reading and editing the site is exactly what a member might be brought in to do. The TOKEN is a
|
|
* different matter: it is unrestricted write authority over everything the public sees, so `/_config`
|
|
* is `ownerOnly` — the split that field exists for, and the same shape proxy-manager and Jellyfin use
|
|
* for the same reason.
|
|
*
|
|
* ── No `screens` ──
|
|
*
|
|
* One screen at the mount prefix, labelled `label`: the sections are panels of one workspace, and
|
|
* `screens` is for a plugin contributing genuinely separate destinations with their own dock tiles.
|
|
*
|
|
* They are URLs under it, though — `/fofos-admin/layout/header`, `/fofos-admin/pages/home`. The
|
|
* platform hands this plugin the whole subtree and nothing more; which paths exist and what they mean
|
|
* is web/routes.ts, here, where it belongs.
|
|
*/
|
|
export const manifest: PluginManifest = {
|
|
publisher: 'officerdev',
|
|
version: '2026.08.29.26',
|
|
platform: '>=1.0.0',
|
|
|
|
label: 'Fofos',
|
|
summary: "The fofos website's content — pages, galleries, drops and collabs",
|
|
/** one website's admin, and useless without that website. */
|
|
tags: ['Personal'],
|
|
icon: 'PenLine',
|
|
color: '#c2410c',
|
|
|
|
// Nothing to declare. It talks HTTP to fofos and stores one row; there is no host binary anywhere
|
|
// on the path, and fofos itself is a separate deployment rather than something this installs.
|
|
|
|
/*
|
|
The rich text editor for the site's copy.
|
|
|
|
Declared here rather than added to the platform's package.json, which is frozen and shared: these
|
|
are installed into `plugins/node_modules/` alongside every other plugin's, so nothing about this
|
|
plugin's editor can move a version the platform depends on.
|
|
|
|
`@tiptap/extension-text-align` was already in the platform's dependencies with nothing importing
|
|
it — a leftover from an earlier attempt. It is asked for here too, so this plugin's copy is
|
|
resolved by the same rule as the rest rather than by whatever happens to be up the tree.
|
|
*/
|
|
npmDependencies: {
|
|
'@tiptap/react': '^3.15.3',
|
|
'@tiptap/starter-kit': '^3.15.3',
|
|
'@tiptap/pm': '^3.15.3',
|
|
'@tiptap/extension-text-align': '^3.15.3',
|
|
'@tiptap/extension-link': '^3.15.3',
|
|
/*
|
|
Lighthouse, so the site can be MEASURED from the panel that builds it.
|
|
|
|
Every performance decision on this site so far — the `sizes` a column declares, which image is
|
|
preloaded, whether the lightbox is parsed at load — was made by reading a report somebody ran by
|
|
hand in DevTools and typed back. That is slow and it is lossy: three real defects (a `sizes` that
|
|
overstated a column, font preloads that had gone missing, an LCP marked lazy) sat live for weeks
|
|
because nothing measured after a build.
|
|
|
|
A big tree, and worth saying so given bunfig.toml: ~100 transitive packages. It brings its own
|
|
`chrome-launcher` and `puppeteer-core`, so neither is asked for here.
|
|
|
|
`@sentry/node` arrives with it. Lighthouse's error reporting is opt-in — off unless
|
|
`--enable-error-reporting` — and this never passes it. See api/lighthouse.ts.
|
|
*/
|
|
lighthouse: '^13.4.1',
|
|
/*
|
|
Fetches a Chrome BINARY, at runtime rather than in a postinstall.
|
|
|
|
Lighthouse needs a browser and this machine has none: Ubuntu 24.04's apt `chromium` is the snap
|
|
stub the iris manifest warns about, and there is no Chrome repo. Puppeteer's own download runs in
|
|
a postinstall, which bun does not execute for an untrusted package — it would silently install
|
|
nothing and fail at the first audit.
|
|
|
|
So the download is a library call the plugin makes, once, when it first needs a browser. Explicit,
|
|
observable, and it narrates — see api/lighthouse.ts.
|
|
*/
|
|
'@puppeteer/browsers': '^3.2.2',
|
|
},
|
|
|
|
permissions: [
|
|
{
|
|
key: 'fofos-admin',
|
|
label: 'Fofos',
|
|
description: 'Edit the fofos website — pages, galleries, drops, collabs and the messages people send',
|
|
|
|
// Where the fofos URL and token are set, and the probe that checks them. Prefix-matched, so
|
|
// `/_config/test` is covered too — deliberately, because that request carries the token in its
|
|
// BODY. A member who could call it would have an oracle pointed at a credential that can
|
|
// rewrite the whole public site.
|
|
ownerOnly: ['/_config'],
|
|
},
|
|
],
|
|
};
|