n8n-nodes-apexapi 0.1.2 → 0.1.3
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,27 @@ 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 (Instagram post)', value: '1080x1080' },
|
|
122
|
+
{ name: 'Portrait 9:16 — 1080×1920 (Story / Reel / TikTok)', value: '1080x1920' },
|
|
123
|
+
{ name: 'Landscape 16:9 — 1920×1080 (YouTube / X)', value: '1920x1080' },
|
|
124
|
+
{ name: 'Landscape 1.91:1 — 1200×630 (Facebook / link share)', value: '1200x630' },
|
|
125
|
+
{ name: 'Portrait 4:5 — 1080×1350 (Instagram portrait)', value: '1080x1350' },
|
|
126
|
+
{ name: 'Portrait 2:3 — 1024×1536', value: '1024x1536' },
|
|
127
|
+
{ name: 'Landscape 3:2 — 1536×1024', value: '1536x1024' },
|
|
128
|
+
{ name: 'Custom (WIDTHxHEIGHT)…', value: 'custom' },
|
|
123
129
|
],
|
|
124
130
|
default: '1024x1024',
|
|
125
|
-
description: 'Output resolution / aspect ratio. Note: some models only support specific sizes.',
|
|
131
|
+
description: 'Output resolution / aspect ratio. Note: some models only support specific sizes. Max 4096 per side.',
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
displayName: 'Custom Size',
|
|
135
|
+
name: 'customSize',
|
|
136
|
+
type: 'string',
|
|
137
|
+
placeholder: '1024x1024',
|
|
138
|
+
displayOptions: { show: { resource: ['image'], imageSize: ['custom'] } },
|
|
139
|
+
default: '1024x1024',
|
|
140
|
+
description: 'Width×height in pixels, e.g. 1024x1024. Each side 1–4096.',
|
|
126
141
|
},
|
|
127
142
|
{
|
|
128
143
|
displayName: 'Options',
|
|
@@ -227,15 +242,33 @@ class ApexApi {
|
|
|
227
242
|
}
|
|
228
243
|
else if (resource === 'image') {
|
|
229
244
|
const options = this.getNodeParameter('options', i, {});
|
|
245
|
+
const sizeChoice = this.getNodeParameter('imageSize', i, '1024x1024');
|
|
246
|
+
const size = sizeChoice === 'custom'
|
|
247
|
+
? this.getNodeParameter('customSize', i, '1024x1024')
|
|
248
|
+
: sizeChoice;
|
|
230
249
|
const body = (0, image_1.buildImageBody)({
|
|
231
250
|
model: this.getNodeParameter('model', i),
|
|
232
251
|
prompt: this.getNodeParameter('prompt', i),
|
|
233
|
-
size
|
|
252
|
+
size,
|
|
234
253
|
n: options.n,
|
|
235
254
|
});
|
|
236
255
|
const resp = await (0, transport_1.apexApiRequest)(ctx, 'POST', '/images/generations', body);
|
|
237
256
|
const parsed = (0, image_1.parseImageResponse)(resp);
|
|
238
257
|
json = { urls: parsed.urls, response: parsed.raw };
|
|
258
|
+
// Some providers (Vertex/Imagen) return inline base64 instead of a hosted
|
|
259
|
+
// link. Emit those as n8n binary so the next node can post/upload them
|
|
260
|
+
// directly — hosted-URL providers (fal/kie) just come through in `urls`.
|
|
261
|
+
const b64Images = parsed.images.filter((im) => im.base64);
|
|
262
|
+
if (b64Images.length > 0) {
|
|
263
|
+
const binary = {};
|
|
264
|
+
for (let k = 0; k < b64Images.length; k++) {
|
|
265
|
+
const im = b64Images[k];
|
|
266
|
+
const ext = (im.mimeType ?? 'image/png').split('/')[1] ?? 'png';
|
|
267
|
+
binary[k === 0 ? 'data' : `data${k}`] = await this.helpers.prepareBinaryData(Buffer.from(im.base64, 'base64'), `image_${k}.${ext}`, im.mimeType);
|
|
268
|
+
}
|
|
269
|
+
returnData.push({ json, binary, pairedItem: { item: i } });
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
239
272
|
}
|
|
240
273
|
else {
|
|
241
274
|
// 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.3",
|
|
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
|
}
|