fix(extension): normalize FC URL so credential push doesn't 405
The stored apiUrl was required to already carry the `/api` suffix, since
api.js builds requests as `${baseUrl}/credentials`. The options label read
"FC base URL", so entering the instance root -- the natural reading --
sent every request one path segment short: POST /credentials hit the Vue
SPA catch-all and came back 405, and GET /extension/manifest 404'd.
Worse, Test Connection reported success on it: the catch-all answers GET
/credentials with 200 HTML, so `r.ok` was true and the only affordance
meant to catch this misconfiguration actively masked it.
Normalize instead of validate (rules 92, 26):
- New lib/url.js: normalizeApiUrl / webRootFromApiUrl, one source shared
by the background client and the options page. Accepts either the
instance root or the API root.
- api.js normalizes on read, so configs already stored in the broken form
heal themselves without the operator reopening Settings.
- options.js stores the canonical form, echoes back what it saved, and
the test now asserts a JSON content-type -- killing the false green.
- 404/405 in request() now names the URL and points at the setting.
- Options label/placeholder state that both forms work.
Version 1.0.9 -> 1.0.10 in BOTH manifest.json and package.json; build.yml
resolves the release version from package.json, and a stale value there
would hit the cached ext-1.0.9 asset and republish the old XPI unsigned
against the new code.
Refs #2393
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Canonical FC endpoint derivation, shared by the background client and the
|
||||
* options page so a URL entered either way behaves identically.
|
||||
*
|
||||
* FC serves two things on one origin: the JSON API under `/api`, and the Vue
|
||||
* SPA from the root. `api.js` builds requests as `${baseUrl}/credentials`, so
|
||||
* the stored base URL has to carry the `/api` suffix.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Accept what an operator would naturally type — the instance root
|
||||
* (`http://curator.example.com`) or the API root (`.../api`) — and return the
|
||||
* API root either way.
|
||||
*
|
||||
* Worth normalizing rather than validating: a root-form URL doesn't fail
|
||||
* loudly, it lands on the SPA catch-all, which answers `GET /credentials` with
|
||||
* 200 HTML and rejects `POST /credentials` with 405. The operator sees a
|
||||
* working Test Connection and a broken export.
|
||||
*/
|
||||
function normalizeApiUrl(raw) {
|
||||
const trimmed = (raw || '').trim().replace(/\/+$/, '');
|
||||
if (!trimmed) return '';
|
||||
return /\/api$/i.test(trimmed) ? trimmed : `${trimmed}/api`;
|
||||
}
|
||||
|
||||
/**
|
||||
* The SPA root — where the Vue router (artist pages) and the served XPI live,
|
||||
* NOT the JSON API. Accepts either input form, same as normalizeApiUrl.
|
||||
*/
|
||||
function webRootFromApiUrl(raw) {
|
||||
return normalizeApiUrl(raw).replace(/\/api$/i, '');
|
||||
}
|
||||
Reference in New Issue
Block a user