refactor(web): extract shared apiFetch helper, remove secret from webhook client type
This commit is contained in:
parent
fe2ab6010e
commit
38a15c0595
@ -2,29 +2,7 @@
|
|||||||
* Agent Inbox API client — talks to ChronoMind backend (port 4011).
|
* Agent Inbox API client — talks to ChronoMind backend (port 4011).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getBackendBaseURL } from './product-config';
|
import { apiFetch } from './api-helpers';
|
||||||
|
|
||||||
function getToken(): string | null {
|
|
||||||
if (typeof window === 'undefined') return null;
|
|
||||||
return localStorage.getItem('chronomind_access_token');
|
|
||||||
}
|
|
||||||
|
|
||||||
async function apiFetch<T>(path: string, opts?: RequestInit): Promise<T> {
|
|
||||||
const token = getToken();
|
|
||||||
const res = await fetch(`${getBackendBaseURL()}${path}`, {
|
|
||||||
...opts,
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
||||||
...(opts?.headers ?? {}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (!res.ok) {
|
|
||||||
const body = await res.text().catch(() => '');
|
|
||||||
throw new Error(`${res.status}: ${body}`);
|
|
||||||
}
|
|
||||||
return res.json() as Promise<T>;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Types ──
|
// ── Types ──
|
||||||
|
|
||||||
|
|||||||
29
web/src/lib/api-helpers.ts
Normal file
29
web/src/lib/api-helpers.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* Shared API helpers for ChronoMind web clients.
|
||||||
|
*
|
||||||
|
* Provides a common fetch wrapper with auth token injection.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { getBackendBaseURL } from './product-config';
|
||||||
|
|
||||||
|
export function getAccessToken(): string | null {
|
||||||
|
if (typeof window === 'undefined') return null;
|
||||||
|
return localStorage.getItem('chronomind_access_token');
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function apiFetch<T>(path: string, opts?: RequestInit): Promise<T> {
|
||||||
|
const token = getAccessToken();
|
||||||
|
const res = await fetch(`${getBackendBaseURL()}${path}`, {
|
||||||
|
...opts,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
||||||
|
...(opts?.headers ?? {}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!res.ok) {
|
||||||
|
const body = await res.text().catch(() => '');
|
||||||
|
throw new Error(`${res.status}: ${body}`);
|
||||||
|
}
|
||||||
|
return res.json() as Promise<T>;
|
||||||
|
}
|
||||||
@ -2,29 +2,7 @@
|
|||||||
* Day Planner API client — talks to ChronoMind backend (port 4011).
|
* Day Planner API client — talks to ChronoMind backend (port 4011).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getBackendBaseURL } from './product-config';
|
import { apiFetch } from './api-helpers';
|
||||||
|
|
||||||
function getToken(): string | null {
|
|
||||||
if (typeof window === 'undefined') return null;
|
|
||||||
return localStorage.getItem('chronomind_access_token');
|
|
||||||
}
|
|
||||||
|
|
||||||
async function apiFetch<T>(path: string, opts?: RequestInit): Promise<T> {
|
|
||||||
const token = getToken();
|
|
||||||
const res = await fetch(`${getBackendBaseURL()}${path}`, {
|
|
||||||
...opts,
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
||||||
...(opts?.headers ?? {}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (!res.ok) {
|
|
||||||
const body = await res.text().catch(() => '');
|
|
||||||
throw new Error(`${res.status}: ${body}`);
|
|
||||||
}
|
|
||||||
return res.json() as Promise<T>;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Types ──
|
// ── Types ──
|
||||||
|
|
||||||
|
|||||||
@ -2,29 +2,7 @@
|
|||||||
* Webhook management API client — talks to ChronoMind backend.
|
* Webhook management API client — talks to ChronoMind backend.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getBackendBaseURL } from './product-config';
|
import { apiFetch } from './api-helpers';
|
||||||
|
|
||||||
function getToken(): string | null {
|
|
||||||
if (typeof window === 'undefined') return null;
|
|
||||||
return localStorage.getItem('chronomind_access_token');
|
|
||||||
}
|
|
||||||
|
|
||||||
async function apiFetch<T>(path: string, opts?: RequestInit): Promise<T> {
|
|
||||||
const token = getToken();
|
|
||||||
const res = await fetch(`${getBackendBaseURL()}${path}`, {
|
|
||||||
...opts,
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
||||||
...(opts?.headers ?? {}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (!res.ok) {
|
|
||||||
const body = await res.text().catch(() => '');
|
|
||||||
throw new Error(`${res.status}: ${body}`);
|
|
||||||
}
|
|
||||||
return res.json() as Promise<T>;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Types ──
|
// ── Types ──
|
||||||
|
|
||||||
@ -33,7 +11,6 @@ export interface WebhookSubscription {
|
|||||||
url: string;
|
url: string;
|
||||||
events: string[];
|
events: string[];
|
||||||
active: boolean;
|
active: boolean;
|
||||||
secret: string;
|
|
||||||
description?: string;
|
description?: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
consecutiveFailures: number;
|
consecutiveFailures: number;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user