105 lines
2.8 KiB
JavaScript
105 lines
2.8 KiB
JavaScript
export const createOpenCodeNetworkRuntime = (deps) => {
|
|
const {
|
|
state,
|
|
getOpenCodeAuthHeaders,
|
|
} = deps;
|
|
|
|
const normalizeApiPrefix = (prefix) => {
|
|
if (!prefix) {
|
|
return '';
|
|
}
|
|
|
|
if (prefix.includes('://')) {
|
|
try {
|
|
const parsed = new URL(prefix);
|
|
return normalizeApiPrefix(parsed.pathname);
|
|
} catch {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
const trimmed = prefix.trim();
|
|
if (!trimmed || trimmed === '/') {
|
|
return '';
|
|
}
|
|
const withLeading = trimmed.startsWith('/') ? trimmed : `/${trimmed}`;
|
|
return withLeading.endsWith('/') ? withLeading.slice(0, -1) : withLeading;
|
|
};
|
|
|
|
const waitForReady = async (url, timeoutMs = 10000) => {
|
|
const start = Date.now();
|
|
while (Date.now() - start < timeoutMs) {
|
|
let timeout = null;
|
|
try {
|
|
const controller = new AbortController();
|
|
timeout = setTimeout(() => controller.abort(), 3000);
|
|
const response = await fetch(`${url.replace(/\/+$/, '')}/api/health`, {
|
|
method: 'GET',
|
|
headers: {
|
|
Accept: 'application/json',
|
|
...getOpenCodeAuthHeaders(),
|
|
},
|
|
signal: controller.signal,
|
|
});
|
|
clearTimeout(timeout);
|
|
timeout = null;
|
|
|
|
if (response.ok) {
|
|
const body = await response.json().catch(() => null);
|
|
if (body?.healthy === true) {
|
|
return true;
|
|
}
|
|
}
|
|
} catch {
|
|
} finally {
|
|
if (timeout) {
|
|
clearTimeout(timeout);
|
|
}
|
|
}
|
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
}
|
|
return false;
|
|
};
|
|
|
|
const setDetectedOpenCodeApiPrefix = () => {
|
|
state.openCodeApiPrefix = '';
|
|
state.openCodeApiPrefixDetected = true;
|
|
if (state.openCodeApiDetectionTimer) {
|
|
clearTimeout(state.openCodeApiDetectionTimer);
|
|
state.openCodeApiDetectionTimer = null;
|
|
}
|
|
};
|
|
|
|
const buildOpenCodeUrl = (path, prefixOverride) => {
|
|
if (!state.openCodePort) {
|
|
throw new Error('OpenCode port is not available');
|
|
}
|
|
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
|
|
const prefix = normalizeApiPrefix(prefixOverride !== undefined ? prefixOverride : '');
|
|
const fullPath = `${prefix}${normalizedPath}`;
|
|
const base = state.openCodeBaseUrl ?? `http://localhost:${state.openCodePort}`;
|
|
return `${base}${fullPath}`;
|
|
};
|
|
|
|
const detectOpenCodeApiPrefix = () => {
|
|
state.openCodeApiPrefixDetected = true;
|
|
state.openCodeApiPrefix = '';
|
|
return true;
|
|
};
|
|
|
|
const ensureOpenCodeApiPrefix = () => detectOpenCodeApiPrefix();
|
|
|
|
const scheduleOpenCodeApiDetection = () => {
|
|
return;
|
|
};
|
|
|
|
return {
|
|
waitForReady,
|
|
normalizeApiPrefix,
|
|
setDetectedOpenCodeApiPrefix,
|
|
buildOpenCodeUrl,
|
|
ensureOpenCodeApiPrefix,
|
|
scheduleOpenCodeApiDetection,
|
|
};
|
|
};
|