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>
46 lines
1.9 KiB
HTML
46 lines
1.9 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<title>FabledCurator — Settings</title>
|
|
<style>
|
|
body { font: 14px/1.4 system-ui, sans-serif; max-width: 520px; margin: 32px auto; padding: 0 16px; }
|
|
h1 { font-family: Georgia, serif; font-size: 20px; }
|
|
label { display: block; font-weight: 500; margin: 16px 0 6px; }
|
|
input { width: 100%; padding: 8px; box-sizing: border-box; font: inherit; }
|
|
.hint { color: #666; font-size: 12px; margin-top: 4px; }
|
|
.row { display: flex; gap: 8px; margin-top: 16px; }
|
|
button { padding: 8px 16px; cursor: pointer; font: inherit; }
|
|
button.primary { background: #F4BA7A; color: #14171A; border: none; border-radius: 4px; }
|
|
button.test { background: none; border: 1px solid #ccc; border-radius: 4px; }
|
|
.status { margin-top: 16px; padding: 8px 12px; border-radius: 4px; }
|
|
.status.ok { background: #DFF5DF; color: #2B6A2B; }
|
|
.status.err { background: #FBE1E1; color: #862525; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>FabledCurator extension</h1>
|
|
|
|
<label for="api-url">FC instance URL</label>
|
|
<input id="api-url" type="url" placeholder="http://curator.example.com" />
|
|
<div class="hint">
|
|
Your FabledCurator address — with or without the trailing <code>/api</code>; both work.
|
|
Find it on FC → Settings → Maintenance → Browser extension.
|
|
</div>
|
|
|
|
<label for="api-key">Extension API key</label>
|
|
<input id="api-key" type="password" placeholder="paste from FC Settings card" />
|
|
<div class="hint">Generate or rotate on FC → Settings → Maintenance → Browser extension.</div>
|
|
|
|
<div class="row">
|
|
<button class="primary" id="save-btn">Save</button>
|
|
<button class="test" id="test-btn">Test connection</button>
|
|
</div>
|
|
|
|
<div id="status" class="status" style="display:none;"></div>
|
|
|
|
<script src="../lib/url.js"></script>
|
|
<script src="options.js"></script>
|
|
</body>
|
|
</html>
|