n8n-nodes-apexapi 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -117,12 +117,23 @@ class ApexApi {
|
|
|
117
117
|
type: 'options',
|
|
118
118
|
displayOptions: { show: { resource: ['image'] } },
|
|
119
119
|
options: [
|
|
120
|
-
{ name: 'Square
|
|
121
|
-
{ name: '
|
|
122
|
-
{ name: 'Portrait
|
|
120
|
+
{ name: 'Square 1:1 — 1024×1024', value: '1024x1024' },
|
|
121
|
+
{ name: 'Square 1:1 — 1080×1080', value: '1080x1080' },
|
|
122
|
+
{ name: 'Portrait 9:16 — 1080×1920', value: '1080x1920' },
|
|
123
|
+
{ name: 'Landscape 16:9 — 1920×1080', value: '1920x1080' },
|
|
124
|
+
{ name: 'Custom (WIDTHxHEIGHT)…', value: 'custom' },
|
|
123
125
|
],
|
|
124
126
|
default: '1024x1024',
|
|
125
|
-
description: 'Output
|
|
127
|
+
description: 'Output size / aspect ratio. Works on every model — the API adapts it per provider (exact pixels for fal/flux, nearest aspect ratio for Imagen/Gemini/GPT-Image).',
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
displayName: 'Custom Size',
|
|
131
|
+
name: 'customSize',
|
|
132
|
+
type: 'string',
|
|
133
|
+
placeholder: '1024x1024',
|
|
134
|
+
displayOptions: { show: { resource: ['image'], imageSize: ['custom'] } },
|
|
135
|
+
default: '1024x1024',
|
|
136
|
+
description: 'Width×height in pixels, e.g. 1024x1024. Each side 1–4096.',
|
|
126
137
|
},
|
|
127
138
|
{
|
|
128
139
|
displayName: 'Options',
|
|
@@ -227,15 +238,33 @@ class ApexApi {
|
|
|
227
238
|
}
|
|
228
239
|
else if (resource === 'image') {
|
|
229
240
|
const options = this.getNodeParameter('options', i, {});
|
|
241
|
+
const sizeChoice = this.getNodeParameter('imageSize', i, '1024x1024');
|
|
242
|
+
const size = sizeChoice === 'custom'
|
|
243
|
+
? this.getNodeParameter('customSize', i, '1024x1024')
|
|
244
|
+
: sizeChoice;
|
|
230
245
|
const body = (0, image_1.buildImageBody)({
|
|
231
246
|
model: this.getNodeParameter('model', i),
|
|
232
247
|
prompt: this.getNodeParameter('prompt', i),
|
|
233
|
-
size
|
|
248
|
+
size,
|
|
234
249
|
n: options.n,
|
|
235
250
|
});
|
|
236
251
|
const resp = await (0, transport_1.apexApiRequest)(ctx, 'POST', '/images/generations', body);
|
|
237
252
|
const parsed = (0, image_1.parseImageResponse)(resp);
|
|
238
253
|
json = { urls: parsed.urls, response: parsed.raw };
|
|
254
|
+
// Some providers (Vertex/Imagen) return inline base64 instead of a hosted
|
|
255
|
+
// link. Emit those as n8n binary so the next node can post/upload them
|
|
256
|
+
// directly — hosted-URL providers (fal/kie) just come through in `urls`.
|
|
257
|
+
const b64Images = parsed.images.filter((im) => im.base64);
|
|
258
|
+
if (b64Images.length > 0) {
|
|
259
|
+
const binary = {};
|
|
260
|
+
for (let k = 0; k < b64Images.length; k++) {
|
|
261
|
+
const im = b64Images[k];
|
|
262
|
+
const ext = (im.mimeType ?? 'image/png').split('/')[1] ?? 'png';
|
|
263
|
+
binary[k === 0 ? 'data' : `data${k}`] = await this.helpers.prepareBinaryData(Buffer.from(im.base64, 'base64'), `image_${k}.${ext}`, im.mimeType);
|
|
264
|
+
}
|
|
265
|
+
returnData.push({ json, binary, pairedItem: { item: i } });
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
239
268
|
}
|
|
240
269
|
else {
|
|
241
270
|
// video
|
package/dist/shared/image.js
CHANGED
|
@@ -10,11 +10,29 @@ function buildImageBody(params) {
|
|
|
10
10
|
body.n = params.n;
|
|
11
11
|
return body;
|
|
12
12
|
}
|
|
13
|
+
const DATA_URL_RE = /^data:([^;,]+);base64,(.+)$/;
|
|
14
|
+
/**
|
|
15
|
+
* Normalise the `/v1/images/generations` response. Providers return images two
|
|
16
|
+
* ways: a hosted URL (fal/kie) or inline base64 (Vertex/Imagen `data:` URLs, or
|
|
17
|
+
* `b64_json`). `urls` holds only real links; `images` holds every image with the
|
|
18
|
+
* base64 decoded out of `data:` URLs so the node can emit it as n8n binary.
|
|
19
|
+
*/
|
|
13
20
|
function parseImageResponse(resp) {
|
|
14
21
|
const r = resp;
|
|
15
22
|
const data = Array.isArray(r?.data) ? r.data : [];
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
23
|
+
const images = [];
|
|
24
|
+
for (const d of data) {
|
|
25
|
+
if (typeof d?.url === 'string') {
|
|
26
|
+
const m = d.url.match(DATA_URL_RE);
|
|
27
|
+
if (m)
|
|
28
|
+
images.push({ base64: m[2], mimeType: m[1] });
|
|
29
|
+
else
|
|
30
|
+
images.push({ url: d.url });
|
|
31
|
+
}
|
|
32
|
+
else if (typeof d?.b64_json === 'string') {
|
|
33
|
+
images.push({ base64: d.b64_json, mimeType: 'image/png' });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const urls = images.map((i) => i.url).filter((u) => typeof u === 'string');
|
|
37
|
+
return { urls, images, raw: resp };
|
|
20
38
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n8n-nodes-apexapi",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "n8n community node for ApexApi — call 14 AI providers (OpenAI, Anthropic, Google, Mistral, and more) through one OpenAI-compatible API.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"n8n-community-node-package",
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"n8n-workflow": "^1.82.0",
|
|
48
48
|
"typescript": "^5.9.3",
|
|
49
|
-
"vitest": "^3.2.4"
|
|
49
|
+
"vitest": "^3.2.4",
|
|
50
|
+
"@types/node": "^22.0.0"
|
|
50
51
|
}
|
|
51
52
|
}
|