2f9b8ebd02
Full-screen WooSetupGate on App mount when this browser lacks device WP user + app password. Save + Test Woo dismisses only after a successful test. Publish/test-woo auth failures reopen the gate. Server: client_for_request requires X-Woo-* on publish, taxonomy sync, and test-woo (401 woo_device_creds_required); health probe keeps Settings. Optional SLAB_WOO_ALLOW_SETTINGS_FALLBACK for legacy tests. See PROTOTYPE.md.
85 lines
2.4 KiB
TypeScript
85 lines
2.4 KiB
TypeScript
/**
|
|
* Browser-local Woo credentials (prototype per-user routing).
|
|
*
|
|
* Stored in localStorage on this device only — never written to server Settings
|
|
* via the device-creds path. Attached as X-Woo-Username / X-Woo-App-Password on
|
|
* Woo-touching API calls. See PROTOTYPE.md.
|
|
*/
|
|
|
|
const LS_USER = 'slabuploader.woo.device.username';
|
|
const LS_PASS = 'slabuploader.woo.device.appPassword';
|
|
|
|
export const HEADER_WOO_USERNAME = 'X-Woo-Username';
|
|
export const HEADER_WOO_APP_PASSWORD = 'X-Woo-App-Password';
|
|
|
|
export interface DeviceWooCreds {
|
|
username: string;
|
|
appPassword: string;
|
|
}
|
|
|
|
function safeGet(key: string): string {
|
|
try {
|
|
return (localStorage.getItem(key) || '').trim();
|
|
} catch {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
function safeSet(key: string, value: string): void {
|
|
try {
|
|
if (value) localStorage.setItem(key, value);
|
|
else localStorage.removeItem(key);
|
|
} catch {
|
|
/* private mode / quota — ignore */
|
|
}
|
|
}
|
|
|
|
export function getDeviceWooCreds(): DeviceWooCreds {
|
|
return {
|
|
username: safeGet(LS_USER),
|
|
appPassword: safeGet(LS_PASS),
|
|
};
|
|
}
|
|
|
|
/** Persist this browser's Woo login. Empty strings clear the slot. */
|
|
export function setDeviceWooCreds(creds: DeviceWooCreds): void {
|
|
safeSet(LS_USER, (creds.username || '').trim());
|
|
safeSet(LS_PASS, (creds.appPassword || '').trim());
|
|
}
|
|
|
|
export function clearDeviceWooCreds(): void {
|
|
safeSet(LS_USER, '');
|
|
safeSet(LS_PASS, '');
|
|
}
|
|
|
|
/** Headers to merge into Woo-backed fetch calls. Empty object when unset. */
|
|
export function wooOverrideHeaders(): Record<string, string> {
|
|
const { username, appPassword } = getDeviceWooCreds();
|
|
if (!username || !appPassword) return {};
|
|
return {
|
|
[HEADER_WOO_USERNAME]: username,
|
|
[HEADER_WOO_APP_PASSWORD]: appPassword,
|
|
};
|
|
}
|
|
|
|
/** Merge Content-Type / caller headers with device Woo override when present. */
|
|
export function withWooHeaders(extra?: HeadersInit): HeadersInit {
|
|
const woo = wooOverrideHeaders();
|
|
if (!extra) return woo;
|
|
if (extra instanceof Headers) {
|
|
const h = new Headers(extra);
|
|
for (const [k, v] of Object.entries(woo)) h.set(k, v);
|
|
return h;
|
|
}
|
|
if (Array.isArray(extra)) {
|
|
return [...extra, ...Object.entries(woo)];
|
|
}
|
|
return { ...extra, ...woo };
|
|
}
|
|
|
|
/** True when this browser has both device Woo username and app password. */
|
|
export function hasDeviceWooCreds(): boolean {
|
|
const { username, appPassword } = getDeviceWooCreds();
|
|
return Boolean(username && appPassword);
|
|
}
|