UNPKG

@proofkit/fmodata

Version:
253 lines (252 loc) 7.39 kB
function generateBoundary(prefix = "batch_") { const randomHex = Array.from( { length: 32 }, () => Math.floor(Math.random() * 16).toString(16) ).join(""); return `${prefix}${randomHex}`; } async function requestToConfig(request) { const headers = {}; request.headers.forEach((value, key) => { headers[key] = value; }); let body; if (request.body) { const clonedRequest = request.clone(); body = await clonedRequest.text(); } return { method: request.method, url: request.url, body, headers }; } function formatSubRequest(request, baseUrl) { const lines = []; lines.push("Content-Type: application/http"); lines.push("Content-Transfer-Encoding: binary"); lines.push(""); const fullUrl = request.url.startsWith("http") ? request.url : `${baseUrl}${request.url}`; lines.push(`${request.method} ${fullUrl} HTTP/1.1`); if (request.body) { if (request.headers) { for (const [key, value] of Object.entries(request.headers)) { if (key.toLowerCase() !== "authorization") { lines.push(`${key}: ${value}`); } } } const hasContentType = request.headers && Object.keys(request.headers).some( (k) => k.toLowerCase() === "content-type" ); if (!hasContentType) { lines.push("Content-Type: application/json"); } const hasContentLength = request.headers && Object.keys(request.headers).some( (k) => k.toLowerCase() === "content-length" ); if (!hasContentLength) { lines.push(`Content-Length: ${request.body.length}`); } lines.push(""); lines.push(request.body); } else { lines.push(""); lines.push(""); } return lines.join("\r\n"); } function formatChangeset(requests, baseUrl, changesetBoundary) { const lines = []; lines.push(`Content-Type: multipart/mixed; boundary=${changesetBoundary}`); lines.push(""); for (const request of requests) { lines.push(`--${changesetBoundary}`); lines.push(formatSubRequest(request, baseUrl)); } lines.push(`--${changesetBoundary}--`); return lines.join("\r\n"); } async function formatBatchRequestFromNative(requests, baseUrl, batchBoundary) { const boundary = batchBoundary || generateBoundary("batch_"); const lines = []; for (const item of requests) { if (Array.isArray(item)) { const changesetBoundary = generateBoundary("changeset_"); const changesetConfigs = []; for (const request of item) { changesetConfigs.push(await requestToConfig(request)); } lines.push(`--${boundary}`); lines.push(formatChangeset(changesetConfigs, baseUrl, changesetBoundary)); } else { const config = await requestToConfig(item); if (config.method === "GET") { lines.push(`--${boundary}`); lines.push(formatSubRequest(config, baseUrl)); } else { const changesetBoundary = generateBoundary("changeset_"); lines.push(`--${boundary}`); lines.push(formatChangeset([config], baseUrl, changesetBoundary)); } } } lines.push(`--${boundary}--`); return { body: lines.join("\r\n"), boundary }; } function extractBoundary(contentType) { const match = contentType.match(/boundary=([^;]+)/); return match && match[1] ? match[1].trim() : null; } function parseStatusLine(line) { var _a; const match = line.match(/HTTP\/\d\.\d\s+(\d+)\s*(.*)/); if (!match || !match[1]) { return { status: 0, statusText: "" }; } return { status: parseInt(match[1], 10), statusText: ((_a = match[2]) == null ? void 0 : _a.trim()) || "" }; } function parseHeaders(lines) { const headers = {}; for (const line of lines) { const colonIndex = line.indexOf(":"); if (colonIndex > 0) { const key = line.substring(0, colonIndex).trim(); const value = line.substring(colonIndex + 1).trim(); headers[key.toLowerCase()] = value; } } return headers; } function parseHttpResponse(part) { const lines = part.split(/\r\n/); let statusLineIndex = -1; for (let i = 0; i < lines.length; i++) { const line = lines[i]; if (line && line.startsWith("HTTP/")) { statusLineIndex = i; break; } } if (statusLineIndex === -1) { return { status: 0, statusText: "Invalid response", headers: {}, body: null }; } const statusLine = lines[statusLineIndex]; if (!statusLine) { return { status: 0, statusText: "Invalid response", headers: {}, body: null }; } const { status, statusText } = parseStatusLine(statusLine); const headerLines = []; let bodyStartIndex = lines.length; let foundEmptyLine = false; for (let i = statusLineIndex + 1; i < lines.length; i++) { const line = lines[i]; if (line === "") { bodyStartIndex = i + 1; foundEmptyLine = true; break; } if (line && line.startsWith("--")) { break; } if (line) { headerLines.push(line); } } const headers = parseHeaders(headerLines); let bodyText = ""; if (foundEmptyLine && bodyStartIndex < lines.length) { const bodyLines = lines.slice(bodyStartIndex); const bodyLinesFiltered = []; for (const line of bodyLines) { if (line.startsWith("--")) { break; } bodyLinesFiltered.push(line); } bodyText = bodyLinesFiltered.join("\r\n").trim(); } let body = null; if (bodyText) { try { body = JSON.parse(bodyText); } catch { body = bodyText; } } return { status, statusText, headers, body }; } function parseBatchResponse(responseText, contentType) { var _a; const boundary = extractBoundary(contentType); if (!boundary) { throw new Error("Could not extract boundary from Content-Type header"); } const results = []; const boundaryPattern = `--${boundary}`; const parts = responseText.split(boundaryPattern); for (const part of parts) { const trimmedPart = part.trim(); if (!trimmedPart || trimmedPart === "--") { continue; } if (trimmedPart.includes("Content-Type: multipart/mixed")) { const changesetContentTypeMatch = trimmedPart.match( /Content-Type: multipart\/mixed;\s*boundary=([^\r\n]+)/ ); if (changesetContentTypeMatch) { const changesetBoundary = (_a = changesetContentTypeMatch == null ? void 0 : changesetContentTypeMatch[1]) == null ? void 0 : _a.trim(); const changesetPattern = `--${changesetBoundary}`; const changesetParts = trimmedPart.split(changesetPattern); for (const changesetPart of changesetParts) { const trimmedChangesetPart = changesetPart.trim(); if (!trimmedChangesetPart || trimmedChangesetPart === "--") { continue; } if (trimmedChangesetPart.startsWith("Content-Type: multipart/mixed")) { continue; } const response = parseHttpResponse(trimmedChangesetPart); if (response.status > 0) { results.push(response); } } } } else { const response = parseHttpResponse(trimmedPart); if (response.status > 0) { results.push(response); } } } return results; } export { extractBoundary, formatBatchRequestFromNative, generateBoundary, parseBatchResponse }; //# sourceMappingURL=batch-request.js.map