proto(woo): per-browser Woo creds via X-Woo-* request headers

Prototype routing so 2–3 owners can share one store URL with different WP
application passwords. Device creds live in localStorage; server uses
request override → Settings fallback and never writes overrides into the
Settings row. Inference stays on shared Settings.

See PROTOTYPE.md for UAT with two browsers and known LAN forge risk.
This commit is contained in:
grokbot_ty
2026-09-26 12:26:21 -07:00
parent fc40c66c44
commit 2f6335ec26
8 changed files with 419 additions and 31 deletions
+12 -4
View File
@@ -7,12 +7,15 @@
// publish.py POST /api/v1/slabs/{id}/publish
// inference.py POST /api/v1/slabs/{id}/inference/call1 (DISABLED 410) | call2
// settings.py GET/PUT /api/v1/settings ; POST /api/v1/settings/test-woo|test-inference
// Woo-backed calls attach X-Woo-Username / X-Woo-App-Password from localStorage when set.
// taxonomy.py GET/POST /api/v1/admin/taxonomy[.../sync]
// pricing.py CRUD /api/v1/admin/pricing[/{id}]
//
// Every non-2xx is surfaced as an ApiError carrying the backend `code` and a plain
// owner-facing `message` (QUALITY-120: raw codes/stack traces never reach the owner).
import { withWooHeaders } from './wooDeviceCreds';
export interface Slab {
id: string;
sku: string;
@@ -338,6 +341,7 @@ export interface PublishResult {
export function publishSlab(slabId: string): Promise<PublishResult> {
return fetch(`/api/v1/slabs/${encodeURIComponent(slabId)}/publish`, {
method: 'POST',
headers: withWooHeaders(),
}).then((r) => parse<PublishResult>(r));
}
@@ -448,7 +452,10 @@ export function syncTaxonomy(): Promise<{
taxonomy_anchor: string;
taxonomy_last_sync_at: string;
}> {
return fetch('/api/v1/admin/taxonomy/sync', { method: 'POST' }).then((r) => parse(r));
return fetch('/api/v1/admin/taxonomy/sync', {
method: 'POST',
headers: withWooHeaders(),
}).then((r) => parse(r));
}
// ---------------------------------------------------------------------------
@@ -542,9 +549,10 @@ export interface TestInferenceResult {
}
export function testWoo(): Promise<TestWooResult> {
return fetch('/api/v1/settings/test-woo', { method: 'POST' }).then((r) =>
parse<TestWooResult>(r),
);
return fetch('/api/v1/settings/test-woo', {
method: 'POST',
headers: withWooHeaders(),
}).then((r) => parse<TestWooResult>(r));
}
export function testInference(): Promise<TestInferenceResult> {