fix: cast to IDataObject to satisfy n8n-workflow types

This commit is contained in:
2026-03-08 15:08:14 +00:00
parent 69b021e1c9
commit c08cd87c56

View File

@@ -1,4 +1,5 @@
import { import {
IDataObject,
IExecuteFunctions, IExecuteFunctions,
INodeExecutionData, INodeExecutionData,
INodeType, INodeType,
@@ -57,96 +58,30 @@ export class WizPixelFlow implements INodeType {
], ],
default: 'render', default: 'render',
}, },
{ { displayName: 'Template ID', name: 'templateId', type: 'string', default: '', required: true, displayOptions: { show: { operation: ['render'] } }, description: 'The ID of the Flow template to render' },
displayName: 'Template ID', { displayName: 'Output Formats', name: 'outputFormats', type: 'multiOptions', options: OUTPUT_FORMATS, default: ['leaderboard_728x90', 'medium_rectangle_300x250'], required: true, displayOptions: { show: { operation: ['render'] } } },
name: 'templateId', { displayName: 'Locales', name: 'locales', type: 'string', default: 'en', displayOptions: { show: { operation: ['render'] } }, description: 'Comma-separated locale codes, e.g. en,it,fr' },
type: 'string', { displayName: 'Variables (JSON)', name: 'variables', type: 'json', default: '{}', displayOptions: { show: { operation: ['render'] } }, description: 'Key/value pairs for {{variable}} substitution' },
default: '', { displayName: 'Include Video (MP4)', name: 'includeVideo', type: 'boolean', default: false, displayOptions: { show: { operation: ['render'] } } },
required: true, { displayName: 'Wait for Completion', name: 'waitForCompletion', type: 'boolean', default: true, displayOptions: { show: { operation: ['render'] } }, description: 'Poll until done and return ZIP download URL' },
displayOptions: { show: { operation: ['render'] } }, { displayName: 'Poll Interval (seconds)', name: 'pollInterval', type: 'number', default: 5, displayOptions: { show: { operation: ['render'], waitForCompletion: [true] } } },
description: 'The ID of the Flow template to render', { displayName: 'Max Wait (seconds)', name: 'maxWait', type: 'number', default: 300, displayOptions: { show: { operation: ['render'], waitForCompletion: [true] } } },
}, { displayName: 'Job ID', name: 'jobId', type: 'string', default: '', required: true, displayOptions: { show: { operation: ['getJob'] } } },
{ { displayName: 'Limit', name: 'limit', type: 'number', default: 50, typeOptions: { minValue: 1, maxValue: 200 }, displayOptions: { show: { operation: ['listTemplates'] } } },
displayName: 'Output Formats',
name: 'outputFormats',
type: 'multiOptions',
options: OUTPUT_FORMATS,
default: ['leaderboard_728x90', 'medium_rectangle_300x250'],
required: true,
displayOptions: { show: { operation: ['render'] } },
},
{
displayName: 'Locales',
name: 'locales',
type: 'string',
default: 'en',
displayOptions: { show: { operation: ['render'] } },
description: 'Comma-separated locale codes, e.g. en,it,fr',
},
{
displayName: 'Variables (JSON)',
name: 'variables',
type: 'json',
default: '{}',
displayOptions: { show: { operation: ['render'] } },
description: 'Key/value pairs to substitute into {{variable}} placeholders',
},
{
displayName: 'Include Video (MP4)',
name: 'includeVideo',
type: 'boolean',
default: false,
displayOptions: { show: { operation: ['render'] } },
},
{
displayName: 'Wait for Completion',
name: 'waitForCompletion',
type: 'boolean',
default: true,
displayOptions: { show: { operation: ['render'] } },
description: 'Poll until the job is done and return the ZIP download URL',
},
{
displayName: 'Poll Interval (seconds)',
name: 'pollInterval',
type: 'number',
default: 5,
displayOptions: { show: { operation: ['render'], waitForCompletion: [true] } },
},
{
displayName: 'Max Wait (seconds)',
name: 'maxWait',
type: 'number',
default: 300,
displayOptions: { show: { operation: ['render'], waitForCompletion: [true] } },
},
{
displayName: 'Job ID',
name: 'jobId',
type: 'string',
default: '',
required: true,
displayOptions: { show: { operation: ['getJob'] } },
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
default: 50,
typeOptions: { minValue: 1, maxValue: 200 },
displayOptions: { show: { operation: ['listTemplates'] } },
},
], ],
}; };
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> { async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const credentials = await this.getCredentials('wizPixelFlowApi'); const credentials = await this.getCredentials('wizPixelFlowApi');
const baseUrl = (credentials.baseUrl as string).replace(/\/$/, ''); const baseUrl = (credentials.baseUrl as string).replace(/\/$/, '');
const apiKey = credentials.apiKey as string; const apiKey = credentials.apiKey as string;
const headers = { 'X-WPF-API-Key': apiKey, 'Content-Type': 'application/json' }; const headers = { 'X-WPF-API-Key': apiKey, 'Content-Type': 'application/json' };
const items = this.getInputData(); const items = this.getInputData();
const returnData: INodeExecutionData[] = []; const returnData: INodeExecutionData[] = [];
const parse = (r: unknown): IDataObject =>
(typeof r === 'string' ? JSON.parse(r) : r) as IDataObject;
for (let i = 0; i < items.length; i++) { for (let i = 0; i < items.length; i++) {
const operation = this.getNodeParameter('operation', i) as string; const operation = this.getNodeParameter('operation', i) as string;
try { try {
@@ -162,32 +97,28 @@ export class WizPixelFlow implements INodeType {
const locales = localesRaw.split(',').map((l) => l.trim()).filter(Boolean); const locales = localesRaw.split(',').map((l) => l.trim()).filter(Boolean);
const variables = typeof variablesRaw === 'string' ? JSON.parse(variablesRaw) : variablesRaw; const variables = typeof variablesRaw === 'string' ? JSON.parse(variablesRaw) : variablesRaw;
const body = { template_id: templateId, formats: outputFormats, locales, variables, include_video: includeVideo }; const body = { template_id: templateId, formats: outputFormats, locales, variables, include_video: includeVideo };
const submitResp = await this.helpers.httpRequest({ method: 'POST', url: `${baseUrl}/render`, headers, body: JSON.stringify(body) }); const submitted = parse(await this.helpers.httpRequest({ method: 'POST', url: `${baseUrl}/render`, headers, body: JSON.stringify(body) }));
const parsed = typeof submitResp === 'string' ? JSON.parse(submitResp) : submitResp; const jobId = submitted.job_id as string;
const jobId = parsed.job_id; if (!waitForCompletion) { returnData.push({ json: submitted }); continue; }
if (!waitForCompletion) { returnData.push({ json: parsed }); continue; }
const deadline = Date.now() + maxWait * 1000; const deadline = Date.now() + maxWait * 1000;
let jobData: Record<string, unknown> = {}; let jobData: IDataObject = {};
while (Date.now() < deadline) { while (Date.now() < deadline) {
await new Promise((r) => setTimeout(r, pollInterval * 1000)); await new Promise((r) => setTimeout(r, pollInterval * 1000));
const pollResp = await this.helpers.httpRequest({ method: 'GET', url: `${baseUrl}/jobs/${jobId}`, headers }); jobData = parse(await this.helpers.httpRequest({ method: 'GET', url: `${baseUrl}/jobs/${jobId}`, headers }));
jobData = typeof pollResp === 'string' ? JSON.parse(pollResp) : pollResp; const job = jobData.job as IDataObject | undefined;
const job = (jobData as { job?: { status?: string } }).job;
if (job?.status === 'done' || job?.status === 'failed') break; if (job?.status === 'done' || job?.status === 'failed') break;
} }
returnData.push({ json: jobData }); returnData.push({ json: jobData });
} else if (operation === 'getJob') { } else if (operation === 'getJob') {
const jobId = this.getNodeParameter('jobId', i) as string; const jobId = this.getNodeParameter('jobId', i) as string;
const resp = await this.helpers.httpRequest({ method: 'GET', url: `${baseUrl}/jobs/${jobId}`, headers }); returnData.push({ json: parse(await this.helpers.httpRequest({ method: 'GET', url: `${baseUrl}/jobs/${jobId}`, headers })) });
returnData.push({ json: typeof resp === 'string' ? JSON.parse(resp) : resp });
} else if (operation === 'listTemplates') { } else if (operation === 'listTemplates') {
const limit = this.getNodeParameter('limit', i) as number; const limit = this.getNodeParameter('limit', i) as number;
const resp = await this.helpers.httpRequest({ method: 'GET', url: `${baseUrl}/templates?limit=${limit}`, headers }); returnData.push({ json: parse(await this.helpers.httpRequest({ method: 'GET', url: `${baseUrl}/templates?limit=${limit}`, headers })) });
returnData.push({ json: typeof resp === 'string' ? JSON.parse(resp) : resp });
} }
} catch (error) { } catch (error) {
if (this.continueOnFail()) { if (this.continueOnFail()) {
returnData.push({ json: { error: (error as Error).message }, pairedItem: i }); returnData.push({ json: { error: (error as Error).message } as IDataObject, pairedItem: i });
} else { } else {
throw new NodeOperationError(this.getNode(), error as Error, { itemIndex: i }); throw new NodeOperationError(this.getNode(), error as Error, { itemIndex: i });
} }