n8n-nodes-kroki
Version:
n8n community node for Kroki diagram conversion service
374 lines • 16.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Kroki = void 0;
const n8n_workflow_1 = require("n8n-workflow");
const buffer_1 = require("buffer");
function getMimeType(outputFormat) {
switch (outputFormat) {
case 'png':
return 'image/png';
case 'svg':
return 'image/svg+xml';
case 'pdf':
return 'application/pdf';
default:
return 'application/octet-stream';
}
}
class Kroki {
constructor() {
this.description = {
displayName: 'Kroki',
name: 'kroki',
icon: { light: 'file:kroki.svg', dark: 'file:kroki.svg' },
group: ['transform'],
version: 1,
subtitle: '={{$parameter["diagramType"] + " to " + $parameter["outputFormat"]}}',
description: 'Convert text-based diagrams to images using Kroki API',
defaults: {
name: 'Kroki',
},
inputs: ["main"],
outputs: ["main"],
usableAsTool: true,
properties: [
{
displayName: 'Diagram Type',
name: 'diagramType',
type: 'options',
noDataExpression: true,
options: [
{
name: 'ActDiag',
value: 'actdiag',
description: 'Activity diagrams',
},
{
name: 'BlockDiag',
value: 'blockdiag',
description: 'BlockDiag diagrams',
},
{
name: 'C4 PlantUML',
value: 'c4plantuml',
description: 'C4 model diagrams',
},
{
name: 'D2',
value: 'd2',
description: 'D2 declarative diagrams',
},
{
name: 'DBML',
value: 'dbml',
description: 'Database markup language',
},
{
name: 'Ditaa',
value: 'ditaa',
description: 'Ditaa ASCII art diagrams',
},
{
name: 'Excalidraw',
value: 'excalidraw',
description: 'Excalidraw diagrams',
},
{
name: 'GraphViz',
value: 'graphviz',
description: 'GraphViz DOT diagrams',
},
{
name: 'Mermaid',
value: 'mermaid',
description: 'Mermaid diagrams (flowcharts, sequence, gantt, etc.)',
},
{
name: 'Nomnoml',
value: 'nomnoml',
description: 'Nomnoml UML diagrams',
},
{
name: 'NwDiag',
value: 'nwdiag',
description: 'Network diagrams',
},
{
name: 'Pikchr',
value: 'pikchr',
description: 'Pikchr diagrams',
},
{
name: 'PlantUML',
value: 'plantuml',
description: 'PlantUML diagrams',
},
{
name: 'SeqDiag',
value: 'seqdiag',
description: 'Sequence diagrams',
},
{
name: 'Structurizr',
value: 'structurizr',
description: 'Structurizr diagrams',
},
{
name: 'Svgbob',
value: 'svgbob',
description: 'Svgbob ASCII art',
},
{
name: 'TikZ',
value: 'tikz',
description: 'TikZ diagrams',
},
{
name: 'UMLet',
value: 'umlet',
description: 'UMLet diagrams',
},
{
name: 'Vega',
value: 'vega',
description: 'Vega visualization',
},
{
name: 'Vega-Lite',
value: 'vegalite',
description: 'Vega-Lite visualization',
},
{
name: 'WaveDrom',
value: 'wavedrom',
description: 'WaveDrom digital timing diagrams',
},
{
name: 'WireViz',
value: 'wireviz',
description: 'WireViz cable diagrams',
},
],
default: 'mermaid',
description: 'Type of diagram to convert',
},
{
displayName: 'Output Format',
name: 'outputFormat',
type: 'options',
noDataExpression: true,
options: [
{
name: 'PNG',
value: 'png',
description: 'High-quality raster image format',
},
{
name: 'SVG',
value: 'svg',
description: 'Scalable vector graphics format',
},
{
name: 'PDF',
value: 'pdf',
description: 'Portable document format',
},
],
default: 'png',
description: 'Output image format',
},
{
displayName: 'Diagram Source',
name: 'diagramSource',
type: 'string',
typeOptions: {
editor: 'codeNodeEditor',
editorLanguage: 'text',
},
default: '',
placeholder: 'Enter your diagram source code here...',
description: 'The source code of the diagram to convert',
required: true,
},
{
displayName: 'Kroki Server',
name: 'krokiServer',
type: 'options',
options: [
{
name: 'Public Service (kroki.io)',
value: 'public',
description: 'Use the public Kroki service at kroki.io',
},
{
name: 'Custom Server',
value: 'custom',
description: 'Use a custom Kroki server',
},
],
default: 'public',
description: 'Kroki server to use for conversion',
},
{
displayName: 'Custom Server URL',
name: 'customServerUrl',
type: 'string',
default: '',
placeholder: 'https://your-kroki-server.com',
description: 'URL of your custom Kroki server',
displayOptions: {
show: {
krokiServer: ['custom'],
},
},
required: true,
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
options: [
{
displayName: 'Timeout',
name: 'timeout',
type: 'number',
default: 30000,
description: 'Request timeout in milliseconds',
typeOptions: {
minValue: 1000,
maxValue: 300000,
},
},
{
displayName: 'Binary Property Name',
name: 'binaryPropertyName',
type: 'string',
default: 'data',
description: 'Name of the binary property to store the generated image',
},
],
},
],
};
}
async execute() {
var _a;
const items = this.getInputData();
const returnData = [];
for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
try {
const diagramType = this.getNodeParameter('diagramType', itemIndex);
const outputFormat = this.getNodeParameter('outputFormat', itemIndex);
const diagramSource = this.getNodeParameter('diagramSource', itemIndex);
const krokiServer = this.getNodeParameter('krokiServer', itemIndex);
const customServerUrl = this.getNodeParameter('customServerUrl', itemIndex, '');
const options = this.getNodeParameter('options', itemIndex, {});
if (!diagramSource.trim()) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Diagram source is required', { itemIndex });
}
const baseUrl = krokiServer === 'custom' ? customServerUrl.replace(/\/$/, '') : 'https://kroki.io';
if (krokiServer === 'custom' && !customServerUrl.trim()) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Custom server URL is required when using custom server option', { itemIndex });
}
if (krokiServer === 'custom') {
if (!customServerUrl.match(/^https?:\/\/.+/)) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Invalid custom server URL format', {
itemIndex,
});
}
}
const url = `${baseUrl}/${diagramType}/${outputFormat}`;
const timeout = options.timeout || 30000;
const binaryPropertyName = options.binaryPropertyName || 'data';
const responseBody = await this.helpers.request({
method: 'POST',
url: url,
body: diagramSource,
headers: {
'Content-Type': 'text/plain',
},
timeout: timeout,
encoding: null,
});
const mimeType = getMimeType(outputFormat);
const debugInfo = {
bodyType: typeof responseBody,
bodyConstructor: (_a = responseBody === null || responseBody === void 0 ? void 0 : responseBody.constructor) === null || _a === void 0 ? void 0 : _a.name,
bodyLength: (responseBody === null || responseBody === void 0 ? void 0 : responseBody.length) || (responseBody === null || responseBody === void 0 ? void 0 : responseBody.byteLength) || 0,
isBuffer: buffer_1.Buffer.isBuffer(responseBody),
url: url,
diagramLength: diagramSource.length,
};
if (outputFormat === 'svg' && typeof responseBody === 'string') {
debugInfo.firstChars = responseBody.substring(0, 100);
}
else if (buffer_1.Buffer.isBuffer(responseBody)) {
debugInfo.firstBytes = responseBody.slice(0, 16).toString('hex');
debugInfo.startsWithPNG = responseBody.slice(0, 4).toString('hex') === '89504e47';
}
let base64Data;
if (buffer_1.Buffer.isBuffer(responseBody)) {
base64Data = responseBody.toString('base64');
}
else if (typeof responseBody === 'string') {
base64Data = buffer_1.Buffer.from(responseBody, 'utf8').toString('base64');
}
else {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Unexpected response type: ${typeof responseBody}`, { itemIndex });
}
const binaryData = {
data: base64Data,
mimeType,
fileName: `diagram.${outputFormat}`,
fileExtension: outputFormat,
};
const returnItem = {
json: {
diagramType,
outputFormat,
fileName: `diagram.${outputFormat}`,
mimeType,
success: true,
bodyType: debugInfo.bodyType,
bodyConstructor: debugInfo.bodyConstructor,
bodyLength: debugInfo.bodyLength,
isBuffer: debugInfo.isBuffer,
startsWithPNG: debugInfo.startsWithPNG,
firstBytes: debugInfo.firstBytes,
url: debugInfo.url,
diagramLength: debugInfo.diagramLength,
debug: debugInfo,
},
binary: {
[binaryPropertyName]: binaryData,
},
pairedItem: itemIndex,
};
returnData.push(returnItem);
}
catch (error) {
if (this.continueOnFail()) {
returnData.push({
json: {
error: error.message,
success: false,
},
pairedItem: itemIndex,
});
}
else {
if (error.context) {
error.context.itemIndex = itemIndex;
throw error;
}
throw new n8n_workflow_1.NodeOperationError(this.getNode(), error, { itemIndex });
}
}
}
return [returnData];
}
}
exports.Kroki = Kroki;
//# sourceMappingURL=Kroki.node.js.map