@aiteza/n8n-nodes-aiteza 0.4.0 → 1.0.1
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.
- package/dist/credentials/AitezaOAuth2Api.credentials.js +1 -1
- package/dist/nodes/Aiteza/Aiteza.node.js +958 -169
- package/dist/nodes/Aiteza/AitezaProgress.node.js +15 -4
- package/dist/nodes/Aiteza/AitezaTrigger.node.js +2 -2
- package/dist/nodes/Aiteza/AitezaWorkflowResult.node.js +15 -4
- package/dist/nodes/Aiteza/GenericFunctions.d.ts +0 -4
- package/dist/nodes/Aiteza/GenericFunctions.js +35 -84
- package/package.json +1 -1
|
@@ -178,7 +178,9 @@ class AitezaProgress {
|
|
|
178
178
|
const callbackTokenOverride = options.callbackTokenOverride || '';
|
|
179
179
|
const timeout = options.timeout ?? 5000;
|
|
180
180
|
const failOnError = options.failOnError ?? false;
|
|
181
|
-
const callbackUrl = (callbackUrlOverride ||
|
|
181
|
+
const callbackUrl = (callbackUrlOverride ||
|
|
182
|
+
readTriggerBodyField(this, i, 'callbackUrl') ||
|
|
183
|
+
'').replace(/\/+$/, '');
|
|
182
184
|
const executionId = executionIdOverride || readTriggerBodyField(this, i, 'executionId') || '';
|
|
183
185
|
const callbackToken = callbackTokenOverride || readTriggerBodyField(this, i, 'callbackToken') || '';
|
|
184
186
|
// Build payload
|
|
@@ -197,7 +199,10 @@ class AitezaProgress {
|
|
|
197
199
|
}
|
|
198
200
|
catch (err) {
|
|
199
201
|
if (failOnError) {
|
|
200
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `The 'Additional Fields' value is not valid JSON: ${err.message}`, {
|
|
202
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `The 'Additional Fields' value is not valid JSON: ${err.message}`, {
|
|
203
|
+
itemIndex: i,
|
|
204
|
+
description: 'Please provide a valid JSON object in the \'Additional Fields\' parameter, e.g. { "percent": 42 }.',
|
|
205
|
+
});
|
|
201
206
|
}
|
|
202
207
|
}
|
|
203
208
|
}
|
|
@@ -219,7 +224,10 @@ class AitezaProgress {
|
|
|
219
224
|
? 'No callbackUrl on Aiteza Trigger body'
|
|
220
225
|
: 'No executionId on Aiteza Trigger body';
|
|
221
226
|
if (failOnError) {
|
|
222
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Cannot send progress report: ${reportMeta.reason}`, {
|
|
227
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Cannot send progress report: ${reportMeta.reason}`, {
|
|
228
|
+
itemIndex: i,
|
|
229
|
+
description: "Make sure this node is downstream of an Aiteza Trigger node that provides 'callbackUrl' and 'executionId' in its body.",
|
|
230
|
+
});
|
|
223
231
|
}
|
|
224
232
|
returnData.push({
|
|
225
233
|
json: { ...items[i].json, _progressReport: reportMeta },
|
|
@@ -247,7 +255,10 @@ class AitezaProgress {
|
|
|
247
255
|
reportMeta.error =
|
|
248
256
|
error?.message ?? error?.response?.statusText ?? 'The callback could not be delivered';
|
|
249
257
|
if (failOnError) {
|
|
250
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Progress callback could not be delivered: ${reportMeta.error}`, {
|
|
258
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Progress callback could not be delivered: ${reportMeta.error}`, {
|
|
259
|
+
itemIndex: i,
|
|
260
|
+
description: "Check that the 'callbackUrl' is reachable and the callback token is valid.",
|
|
261
|
+
});
|
|
251
262
|
}
|
|
252
263
|
}
|
|
253
264
|
returnData.push({
|
|
@@ -8,7 +8,7 @@ class AitezaTrigger {
|
|
|
8
8
|
icon: 'file:aiteza.svg',
|
|
9
9
|
group: ['trigger'],
|
|
10
10
|
version: 1,
|
|
11
|
-
description:
|
|
11
|
+
description: "Starts the workflow when an Aiteza event is received via webhook. Forwards the calling user's token to downstream Aiteza nodes so they act on behalf of the triggering user.",
|
|
12
12
|
defaults: { name: 'AITEZA Trigger' },
|
|
13
13
|
inputs: [],
|
|
14
14
|
outputs: ['main'],
|
|
@@ -59,7 +59,7 @@ class AitezaTrigger {
|
|
|
59
59
|
type: 'string',
|
|
60
60
|
default: '',
|
|
61
61
|
placeholder: 'e.g. https://aiteza.example.com',
|
|
62
|
-
description:
|
|
62
|
+
description: "Optional. If set, this URL is forwarded to downstream Aiteza nodes as '_baseUrl' so they don't need to repeat it. Without trailing slash.",
|
|
63
63
|
},
|
|
64
64
|
],
|
|
65
65
|
};
|
|
@@ -167,7 +167,9 @@ class AitezaWorkflowResult {
|
|
|
167
167
|
const callbackTokenOverride = options.callbackTokenOverride || '';
|
|
168
168
|
const timeout = options.timeout ?? 10000;
|
|
169
169
|
const failOnError = options.failOnError ?? true;
|
|
170
|
-
const callbackUrl = (callbackUrlOverride ||
|
|
170
|
+
const callbackUrl = (callbackUrlOverride ||
|
|
171
|
+
readTriggerBodyField(this, i, 'callbackUrl') ||
|
|
172
|
+
'').replace(/\/+$/, '');
|
|
171
173
|
const executionId = executionIdOverride || readTriggerBodyField(this, i, 'executionId') || '';
|
|
172
174
|
const callbackToken = callbackTokenOverride || readTriggerBodyField(this, i, 'callbackToken') || '';
|
|
173
175
|
// Build result payload
|
|
@@ -182,7 +184,10 @@ class AitezaWorkflowResult {
|
|
|
182
184
|
}
|
|
183
185
|
catch (err) {
|
|
184
186
|
if (failOnError) {
|
|
185
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `The 'Result Data' value is not valid JSON: ${err.message}`, {
|
|
187
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `The 'Result Data' value is not valid JSON: ${err.message}`, {
|
|
188
|
+
itemIndex: i,
|
|
189
|
+
description: "Please provide a valid JSON object in the 'Result Data' field, or use an expression like ={{ $json }}.",
|
|
190
|
+
});
|
|
186
191
|
}
|
|
187
192
|
resultPayload = { raw: resultDataRaw };
|
|
188
193
|
}
|
|
@@ -208,7 +213,10 @@ class AitezaWorkflowResult {
|
|
|
208
213
|
? 'No callbackUrl on Aiteza Trigger body'
|
|
209
214
|
: 'No executionId on Aiteza Trigger body';
|
|
210
215
|
if (failOnError) {
|
|
211
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Cannot send workflow result: ${reportMeta.reason}`, {
|
|
216
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Cannot send workflow result: ${reportMeta.reason}`, {
|
|
217
|
+
itemIndex: i,
|
|
218
|
+
description: "Make sure this node is downstream of an Aiteza Trigger node that provides 'callbackUrl' and 'executionId' in its body.",
|
|
219
|
+
});
|
|
212
220
|
}
|
|
213
221
|
returnData.push({
|
|
214
222
|
json: { ...items[i].json, _workflowResult: reportMeta },
|
|
@@ -236,7 +244,10 @@ class AitezaWorkflowResult {
|
|
|
236
244
|
reportMeta.error =
|
|
237
245
|
error?.message ?? error?.response?.statusText ?? 'The callback could not be delivered';
|
|
238
246
|
if (failOnError) {
|
|
239
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Workflow result could not be delivered: ${reportMeta.error}`, {
|
|
247
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Workflow result could not be delivered: ${reportMeta.error}`, {
|
|
248
|
+
itemIndex: i,
|
|
249
|
+
description: "Check that the 'callbackUrl' is reachable and the callback token is valid.",
|
|
250
|
+
});
|
|
240
251
|
}
|
|
241
252
|
}
|
|
242
253
|
returnData.push({
|
|
@@ -7,10 +7,6 @@ export declare function getUpstreamAuthToken(ef: IExecuteFunctions): string | un
|
|
|
7
7
|
export declare function getUpstreamBaseUrl(ef: IExecuteFunctions): string | undefined;
|
|
8
8
|
export declare function isJwtExpired(token: string | undefined, skewSeconds?: number): boolean;
|
|
9
9
|
export declare function aitezaApiRequest(this: IExecuteFunctions | ILoadOptionsFunctions, method: IHttpRequestMethods, endpoint: string, body?: IDataObject | IDataObject[], qs?: IDataObject, extraOpts?: Partial<IHttpRequestOptions>, authCtx?: AitezaAuthContext): Promise<any>;
|
|
10
|
-
export declare function aitezaApiRequestFullResponse(this: IExecuteFunctions, method: IHttpRequestMethods, endpoint: string, body?: IDataObject, qs?: IDataObject, extraOpts?: Partial<IHttpRequestOptions>, authCtx?: AitezaAuthContext): Promise<{
|
|
11
|
-
body: any;
|
|
12
|
-
headers: Record<string, string>;
|
|
13
|
-
}>;
|
|
14
10
|
export declare function loadDatarooms(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
15
11
|
export declare function loadDataroomsOptional(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
16
12
|
export declare function loadModels(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
@@ -4,7 +4,6 @@ exports.getUpstreamAuthToken = getUpstreamAuthToken;
|
|
|
4
4
|
exports.getUpstreamBaseUrl = getUpstreamBaseUrl;
|
|
5
5
|
exports.isJwtExpired = isJwtExpired;
|
|
6
6
|
exports.aitezaApiRequest = aitezaApiRequest;
|
|
7
|
-
exports.aitezaApiRequestFullResponse = aitezaApiRequestFullResponse;
|
|
8
7
|
exports.loadDatarooms = loadDatarooms;
|
|
9
8
|
exports.loadDataroomsOptional = loadDataroomsOptional;
|
|
10
9
|
exports.loadModels = loadModels;
|
|
@@ -16,93 +15,74 @@ exports.loadStandaloneFiles = loadStandaloneFiles;
|
|
|
16
15
|
exports.loadStandaloneImages = loadStandaloneImages;
|
|
17
16
|
exports.validateRequiredField = validateRequiredField;
|
|
18
17
|
const n8n_workflow_1 = require("n8n-workflow");
|
|
19
|
-
function
|
|
20
|
-
return typeof type === 'string' && /(^|\.)aitezaTrigger$/i.test(type);
|
|
21
|
-
}
|
|
22
|
-
function findAitezaTriggerParentName(ef) {
|
|
18
|
+
function readFromTriggerItems(ef, picker) {
|
|
23
19
|
try {
|
|
24
20
|
const currentNodeName = ef.getNode().name;
|
|
25
21
|
const parents = ef.getParentNodes(currentNodeName);
|
|
26
|
-
const trigger = parents.find((p) =>
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
catch {
|
|
30
|
-
return undefined;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
function readFromTriggerItems(ef, picker) {
|
|
34
|
-
const triggerName = findAitezaTriggerParentName(ef);
|
|
35
|
-
if (!triggerName)
|
|
36
|
-
return undefined;
|
|
37
|
-
try {
|
|
22
|
+
const trigger = parents.find((p) => /(^|\.)aitezaTrigger$/i.test(p.type) && !p.disabled);
|
|
23
|
+
if (!trigger)
|
|
24
|
+
return undefined;
|
|
38
25
|
const proxy = ef.getWorkflowDataProxy(0);
|
|
39
|
-
const triggerItems = proxy.$items(
|
|
26
|
+
const triggerItems = proxy.$items(trigger.name) ?? [];
|
|
40
27
|
for (const item of triggerItems) {
|
|
41
28
|
const value = picker(item?.json);
|
|
42
29
|
if (value !== undefined && value !== null && value !== '')
|
|
43
30
|
return value;
|
|
44
31
|
}
|
|
45
32
|
}
|
|
46
|
-
catch {
|
|
47
|
-
}
|
|
33
|
+
catch { }
|
|
48
34
|
return undefined;
|
|
49
35
|
}
|
|
50
36
|
function getUpstreamAuthToken(ef) {
|
|
51
37
|
try {
|
|
52
|
-
const
|
|
53
|
-
for (const item of items) {
|
|
38
|
+
for (const item of ef.getInputData()) {
|
|
54
39
|
const token = item.json?._authToken;
|
|
55
40
|
if (token)
|
|
56
41
|
return token;
|
|
57
42
|
}
|
|
58
43
|
}
|
|
59
|
-
catch {
|
|
60
|
-
}
|
|
44
|
+
catch { }
|
|
61
45
|
return readFromTriggerItems(ef, (json) => json?._authToken);
|
|
62
46
|
}
|
|
63
47
|
function getUpstreamBaseUrl(ef) {
|
|
64
48
|
try {
|
|
65
|
-
const
|
|
66
|
-
for (const item of items) {
|
|
49
|
+
for (const item of ef.getInputData()) {
|
|
67
50
|
const url = item.json?._baseUrl;
|
|
68
51
|
if (url)
|
|
69
52
|
return url.replace(/\/+$/, '');
|
|
70
53
|
}
|
|
71
54
|
}
|
|
72
|
-
catch {
|
|
73
|
-
|
|
74
|
-
|
|
55
|
+
catch { }
|
|
56
|
+
const fromTrigger = readFromTriggerItems(ef, (json) => {
|
|
57
|
+
const explicit = json?._baseUrl;
|
|
58
|
+
if (explicit)
|
|
59
|
+
return explicit;
|
|
60
|
+
const body = json?.body ?? {};
|
|
61
|
+
return body?.callbackUrl;
|
|
62
|
+
});
|
|
75
63
|
return fromTrigger ? fromTrigger.replace(/\/+$/, '') : undefined;
|
|
76
64
|
}
|
|
77
|
-
|
|
78
|
-
|
|
65
|
+
function isJwtExpired(token, skewSeconds = 30) {
|
|
66
|
+
if (!token)
|
|
67
|
+
return true;
|
|
79
68
|
try {
|
|
80
69
|
const payload = token.split('.')[1];
|
|
81
70
|
if (!payload)
|
|
82
|
-
return
|
|
71
|
+
return false;
|
|
83
72
|
const normalized = payload.replace(/-/g, '+').replace(/_/g, '/');
|
|
84
73
|
const padded = normalized + '='.repeat((4 - (normalized.length % 4)) % 4);
|
|
85
|
-
const decoded = globalThis.atob
|
|
86
|
-
? globalThis.atob(padded)
|
|
87
|
-
: '';
|
|
74
|
+
const decoded = globalThis.atob ? globalThis.atob(padded) : '';
|
|
88
75
|
if (!decoded)
|
|
89
|
-
return
|
|
90
|
-
|
|
76
|
+
return false;
|
|
77
|
+
const { exp } = JSON.parse(decoded);
|
|
78
|
+
if (!exp)
|
|
79
|
+
return false;
|
|
80
|
+
return exp <= Math.floor(Date.now() / 1000) + skewSeconds;
|
|
91
81
|
}
|
|
92
82
|
catch {
|
|
93
|
-
return undefined;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
function isJwtExpired(token, skewSeconds = 30) {
|
|
97
|
-
if (!token)
|
|
98
|
-
return true;
|
|
99
|
-
const payload = decodeJwtPayload(token);
|
|
100
|
-
if (!payload?.exp)
|
|
101
83
|
return false;
|
|
102
|
-
|
|
103
|
-
return payload.exp <= nowSeconds + skewSeconds;
|
|
84
|
+
}
|
|
104
85
|
}
|
|
105
|
-
// Internal helpers
|
|
106
86
|
async function resolveBaseUrl(ctx, authCtx) {
|
|
107
87
|
if (authCtx?.baseUrl)
|
|
108
88
|
return authCtx.baseUrl;
|
|
@@ -111,10 +91,7 @@ async function resolveBaseUrl(ctx, authCtx) {
|
|
|
111
91
|
}
|
|
112
92
|
async function executeRequest(ctx, options, authCtx) {
|
|
113
93
|
if (authCtx?.triggerToken) {
|
|
114
|
-
options.headers = {
|
|
115
|
-
...(options.headers ?? {}),
|
|
116
|
-
Authorization: `Bearer ${authCtx.triggerToken}`,
|
|
117
|
-
};
|
|
94
|
+
options.headers = { ...(options.headers ?? {}), Authorization: `Bearer ${authCtx.triggerToken}` };
|
|
118
95
|
return ctx.helpers.httpRequest(options);
|
|
119
96
|
}
|
|
120
97
|
return ctx.helpers.httpRequestWithAuthentication.call(ctx, 'aitezaOAuth2Api', options);
|
|
@@ -126,9 +103,8 @@ function toOptions(items, nameField = 'name') {
|
|
|
126
103
|
}));
|
|
127
104
|
}
|
|
128
105
|
function extractItems(data) {
|
|
129
|
-
return Array.isArray(data) ? data : data?.content ?? [];
|
|
106
|
+
return Array.isArray(data) ? data : (data?.content ?? []);
|
|
130
107
|
}
|
|
131
|
-
// Generic authenticated request helper
|
|
132
108
|
async function aitezaApiRequest(method, endpoint, body = {}, qs = {}, extraOpts = {}, authCtx) {
|
|
133
109
|
const baseUrl = await resolveBaseUrl(this, authCtx);
|
|
134
110
|
const options = {
|
|
@@ -137,14 +113,12 @@ async function aitezaApiRequest(method, endpoint, body = {}, qs = {}, extraOpts
|
|
|
137
113
|
json: true,
|
|
138
114
|
...extraOpts,
|
|
139
115
|
};
|
|
140
|
-
if (Object.keys(qs).length > 0)
|
|
116
|
+
if (Object.keys(qs).length > 0)
|
|
141
117
|
options.qs = qs;
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
else if (method === 'DELETE' && Object.keys(body).length > 0) {
|
|
147
|
-
options.body = body;
|
|
118
|
+
if (method !== 'GET') {
|
|
119
|
+
const bodyObj = body;
|
|
120
|
+
if (method !== 'DELETE' || Object.keys(bodyObj).length > 0)
|
|
121
|
+
options.body = bodyObj;
|
|
148
122
|
}
|
|
149
123
|
try {
|
|
150
124
|
return await executeRequest(this, options, authCtx);
|
|
@@ -161,28 +135,6 @@ async function aitezaApiRequest(method, endpoint, body = {}, qs = {}, extraOpts
|
|
|
161
135
|
});
|
|
162
136
|
}
|
|
163
137
|
}
|
|
164
|
-
// Full-response variant (gives access to response headers, e.g. X-Chat-Id)
|
|
165
|
-
async function aitezaApiRequestFullResponse(method, endpoint, body = {}, qs = {}, extraOpts = {}, authCtx) {
|
|
166
|
-
const baseUrl = await resolveBaseUrl(this, authCtx);
|
|
167
|
-
const options = {
|
|
168
|
-
method,
|
|
169
|
-
url: `${baseUrl}${endpoint}`,
|
|
170
|
-
qs,
|
|
171
|
-
json: true,
|
|
172
|
-
returnFullResponse: true,
|
|
173
|
-
...extraOpts,
|
|
174
|
-
};
|
|
175
|
-
if (method !== 'GET') {
|
|
176
|
-
options.body = body;
|
|
177
|
-
}
|
|
178
|
-
try {
|
|
179
|
-
return (await executeRequest(this, options, authCtx));
|
|
180
|
-
}
|
|
181
|
-
catch (error) {
|
|
182
|
-
throw new n8n_workflow_1.NodeApiError(this.getNode(), error);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
// loadOptions helpers
|
|
186
138
|
async function loadDatarooms() {
|
|
187
139
|
try {
|
|
188
140
|
const data = await aitezaApiRequest.call(this, 'GET', '/api/dataroom/search?q=&sortBy=recentlyUsed');
|
|
@@ -239,7 +191,6 @@ async function loadStandaloneImages() {
|
|
|
239
191
|
const data = await aitezaApiRequest.call(this, 'GET', '/api/images', {}, { size: 100 });
|
|
240
192
|
return toOptions(extractItems(data));
|
|
241
193
|
}
|
|
242
|
-
// Validation helper
|
|
243
194
|
function validateRequiredField(ef, value, fieldName) {
|
|
244
195
|
if (value === undefined || value === null || value === '') {
|
|
245
196
|
throw new n8n_workflow_1.NodeOperationError(ef.getNode(), `The '${fieldName}' field is required but was not provided.`, {
|