useAppFetch
useAppFetch() returns the mounted surface's authenticated data-plane fetcher. Pass an app-relative path and ordinary RequestInit; Core resolves it under the selected environment's backend, injects the bearer credential, binds cancellation to the mount, and refreshes an expired credential once.
import { useState } from 'react';
import { useAppFetch } from '@sota/platform';
export function SaveSettingsButton() {
const appFetch = useAppFetch();
const [status, setStatus] = useState('idle');
async function save() {
setStatus('saving');
const response = await appFetch('/settings', {
method: 'PUT',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ digest: 'weekly' }),
});
if (!response.ok) {
setStatus('error');
return;
}
const saved = await response.json();
setStatus(saved.digest === 'weekly' ? 'saved' : 'error');
}
return <button type="button" onClick={save}>{status}</button>;
}The returned value is a standard Response; JSON parsing and domain errors remain app logic. Absolute cross-origin URLs and paths escaping the scoped base path are rejected. Do not add or persist an authorization header yourself.
| Case | Behavior |
|---|---|
| Normal response | Returned unchanged, including non-2xx status codes. |
| Expired app-data credential | Core refreshes the descriptor and retries once in the same environment. |
| Surface unmount | The request signal is aborted. |
| One-shot stream body | Core tees it before a possible credential retry. |