'use strict'; const FormData = require('form-data'); const { requestStream } = require('./http-client'); function collaboraBase(config) { return (config.collaboraUrl || '').replace(/\/$/, ''); } function tlsOptions(config) { return config.verifyTls !== false && config.verifyTls !== 'false'; } function buildMultipart(fields) { const form = new FormData(); for (const field of fields) { if (field.buffer) { form.append(field.name, field.buffer, { filename: field.filename || 'document.bin', contentType: field.contentType || 'application/octet-stream' }); } else if (field.value !== undefined) { form.append(field.name, String(field.value)); } } return form; } async function postMultipart(config, endpoint, fields) { const form = buildMultipart(fields); const url = `${collaboraBase(config)}${endpoint}`; const res = await requestStream( { url, method: 'POST', headers: form.getHeaders(), rejectUnauthorized: tlsOptions(config) }, (req) => form.pipe(req) ); if (res.statusCode < 200 || res.statusCode >= 300) { const snippet = res.body.toString('utf8').slice(0, 300); throw new Error(`Collabora ${endpoint} misslyckades (${res.statusCode}): ${snippet}`); } if (!res.body || res.body.length === 0) { throw new Error(`Collabora ${endpoint} returnerade tomt svar — kontrollera intern URL och post_allow`); } return { buffer: res.body, contentType: res.headers['content-type'], statusCode: res.statusCode }; } async function convertTo(config, { buffer, filename, format, extraFields = [] }) { const fmt = String(format || 'pdf').toLowerCase(); const fields = [ { name: 'data', buffer, filename: filename || 'document.bin' }, ...extraFields ]; try { return await postMultipart(config, `/cool/convert-to/${fmt}`, fields); } catch (err) { fields.push({ name: 'format', value: fmt }); return postMultipart(config, '/cool/convert-to', fields); } } async function extractStructure(config, { buffer, filename, filter }) { const fields = [{ name: 'data', buffer, filename: filename || 'document.bin' }]; if (filter) { fields.push({ name: 'filter', value: typeof filter === 'string' ? filter : JSON.stringify(filter) }); } const res = await postMultipart(config, '/cool/extract-document-structure', fields); try { return JSON.parse(res.buffer.toString('utf8')); } catch { return { raw: res.buffer.toString('utf8') }; } } async function transformStructure(config, { buffer, filename, transform }) { const fields = [ { name: 'data', buffer, filename: filename || 'document.bin' }, { name: 'transform', value: typeof transform === 'string' ? transform : JSON.stringify(transform) } ]; const res = await postMultipart(config, '/cool/transform-document-structure', fields); return { buffer: res.buffer, contentType: res.contentType }; } async function getCapabilities(config) { const url = `${collaboraBase(config)}/hosting/capabilities`; const { requestBuffer } = require('./http-client'); const res = await requestBuffer({ url, method: 'GET', rejectUnauthorized: tlsOptions(config) }); if (res.statusCode < 200 || res.statusCode >= 300) { throw new Error(`Capabilities misslyckades (${res.statusCode})`); } return JSON.parse(res.body.toString('utf8')); } async function getDiscovery(config) { const url = `${collaboraBase(config)}/hosting/discovery`; const { requestBuffer } = require('./http-client'); const res = await requestBuffer({ url, method: 'GET', rejectUnauthorized: tlsOptions(config) }); if (res.statusCode < 200 || res.statusCode >= 300) { throw new Error(`Discovery misslyckades (${res.statusCode})`); } return res.body.toString('utf8'); } module.exports = { convertTo, extractStructure, transformStructure, getCapabilities, getDiscovery, postMultipart };