Chrome has no update channel for an unpacked extension, so every pull left one manual step: click reload on its card. The dashboard now publishes the version its own checkout ships at /api/autobuyer/status, and the extension reloads itself when it is behind — chrome.runtime.reload() re-reads the folder from disk, which the update check has already pulled into. It only ever runs code that is on disk, so a reload that changes nothing is reported and waited out rather than repeated; a dashboard that is behind is ignored. Also adds the deploy stack for running the dashboard on the droplet, next to the autotrader one: it joins that nginx's network and renders a server block into its conf.d rather than standing up a second ingress. AUTOFIRMER_DB moves the SQLite file onto a volume, since the working directory in a container is replaced on every deploy. And waitFor gained `hidden`: an absent gate matched on DOM presence only, so a modal that closes by going display:none could never satisfy it. The extension grew a visibility probe for this — locate cannot answer it, because absent and hidden are both errors there and a wait gate has to tell them apart. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
23 lines
936 B
TypeScript
23 lines
936 B
TypeScript
import { NextResponse } from 'next/server';
|
|
|
|
/** The Chromium extension calls these routes from a background service worker,
|
|
* whose Origin is `chrome-extension://<id>`. The id changes every time the
|
|
* unpacked extension is reloaded, so we allow any origin.
|
|
*
|
|
* That was harmless while this only ever answered on the LAN behind the
|
|
* port-3000 firewall rule. The hosted dashboard has no such fence — see
|
|
* deploy/README.md, "No login". */
|
|
export const CORS_HEADERS = {
|
|
'Access-Control-Allow-Origin': '*',
|
|
'Access-Control-Allow-Methods': 'GET, POST, PATCH, DELETE, OPTIONS',
|
|
'Access-Control-Allow-Headers': 'Content-Type',
|
|
} as const;
|
|
|
|
export function corsJson(body: unknown, init?: { status?: number }) {
|
|
return NextResponse.json(body, { status: init?.status ?? 200, headers: CORS_HEADERS });
|
|
}
|
|
|
|
export function corsPreflight() {
|
|
return new NextResponse(null, { status: 204, headers: CORS_HEADERS });
|
|
}
|