feat: refactor api() to accept optional baseUrl for cross-origin requests
Add 4th parameter `baseUrl` to `api()`. When provided, strips trailing slash and prepends to path, and sets `credentials: 'include'` for cross-origin cookie sending. Behavior is unchanged when no baseUrl is given (backward compatible). Export `api` in module.exports. All 135 tests pass. 🤖 Generated with Amplifier <https://github.com/microsoft/amplifier> Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
This commit is contained in:
@@ -157,13 +157,18 @@ function isMobile() {
|
||||
}
|
||||
|
||||
// ─── Fetch wrapper ────────────────────────────────────────────────────────────
|
||||
async function api(method, path, body) {
|
||||
async function api(method, path, body, baseUrl) {
|
||||
const opts = { method, headers: {} };
|
||||
if (body !== undefined) {
|
||||
opts.headers['Content-Type'] = 'application/json';
|
||||
opts.body = JSON.stringify(body);
|
||||
}
|
||||
const res = await fetch(path, opts);
|
||||
let url = path;
|
||||
if (baseUrl) {
|
||||
url = baseUrl.replace(/\/+$/, '') + path;
|
||||
opts.credentials = 'include';
|
||||
}
|
||||
const res = await fetch(url, opts);
|
||||
if (!res.ok) {
|
||||
throw new Error(`HTTP ${res.status}: ${res.statusText}`);
|
||||
}
|
||||
@@ -1711,6 +1716,8 @@ if (typeof module !== 'undefined' && module.exports) {
|
||||
// Server settings
|
||||
loadServerSettings,
|
||||
patchServerSetting,
|
||||
// Fetch wrapper
|
||||
api,
|
||||
// Header + button with inline name input
|
||||
showNewSessionInput,
|
||||
showFabSessionInput,
|
||||
|
||||
@@ -1928,6 +1928,58 @@ test('buildSidebarHTML includes sidebar-delete button with data-session attribut
|
||||
assert.ok(html.includes('data-session="my-session"'), 'sidebar-delete button must have data-session attribute');
|
||||
});
|
||||
|
||||
// --- api ---
|
||||
|
||||
test('api with no baseUrl uses relative path', async () => {
|
||||
const calls = [];
|
||||
const origFetch = globalThis.fetch;
|
||||
globalThis.fetch = async (url, opts) => {
|
||||
calls.push({ url, opts });
|
||||
return { ok: true };
|
||||
};
|
||||
|
||||
await app.api('GET', '/api/sessions');
|
||||
|
||||
assert.strictEqual(calls.length, 1, 'should call fetch once');
|
||||
assert.strictEqual(calls[0].url, '/api/sessions', 'url should be relative path');
|
||||
assert.ok(!calls[0].opts.credentials, 'credentials should not be set without baseUrl');
|
||||
|
||||
globalThis.fetch = origFetch;
|
||||
});
|
||||
|
||||
test('api with baseUrl prepends it to path and sets credentials include', async () => {
|
||||
const calls = [];
|
||||
const origFetch = globalThis.fetch;
|
||||
globalThis.fetch = async (url, opts) => {
|
||||
calls.push({ url, opts });
|
||||
return { ok: true };
|
||||
};
|
||||
|
||||
await app.api('GET', '/api/sessions', undefined, 'https://remote.example.com');
|
||||
|
||||
assert.strictEqual(calls.length, 1, 'should call fetch once');
|
||||
assert.strictEqual(calls[0].url, 'https://remote.example.com/api/sessions', 'url should prepend baseUrl');
|
||||
assert.strictEqual(calls[0].opts.credentials, 'include', 'credentials should be include for cross-origin');
|
||||
|
||||
globalThis.fetch = origFetch;
|
||||
});
|
||||
|
||||
test('api with baseUrl and trailing slash does not double-slash', async () => {
|
||||
const calls = [];
|
||||
const origFetch = globalThis.fetch;
|
||||
globalThis.fetch = async (url, opts) => {
|
||||
calls.push({ url, opts });
|
||||
return { ok: true };
|
||||
};
|
||||
|
||||
await app.api('GET', '/api/sessions', undefined, 'https://remote.example.com/');
|
||||
|
||||
assert.strictEqual(calls.length, 1, 'should call fetch once');
|
||||
assert.strictEqual(calls[0].url, 'https://remote.example.com/api/sessions', 'trailing slash on baseUrl should not create double-slash');
|
||||
|
||||
globalThis.fetch = origFetch;
|
||||
});
|
||||
|
||||
test('createNewSession polls for session before auto-opening (not immediate setTimeout openSession)', () => {
|
||||
// The old behavior was: setTimeout(() => openSession(...), 500) immediately after POST.
|
||||
// The new behavior must use a polling interval to wait for the session to appear in
|
||||
|
||||
Reference in New Issue
Block a user