n8n-nodes-bgos 0.3.0 → 1.0.0
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/nodes/BGOSAction/BGOSAction.node.js +1 -1
- package/dist/nodes/BGOSAction/agentWebhook.d.ts +2 -1
- package/dist/nodes/BGOSAction/agentWebhook.js +26 -54
- package/dist/nodes/BGOSAction/handler/eventHandler.d.ts +2 -1
- package/dist/nodes/BGOSAction/handler/eventHandler.js +15 -9
- package/dist/nodes/BGOSAction/rateLimiter.d.ts +1 -1
- package/dist/nodes/BGOSAction/rateLimiter.js +5 -30
- package/dist/nodes/BGOSAction/techWebhook.d.ts +9 -8
- package/dist/nodes/BGOSAction/techWebhook.js +43 -48
- package/dist/nodes/BgosTrigger/BgosTrigger.node.js +9 -18
- package/package.json +2 -7
|
@@ -117,7 +117,7 @@ class BGOSAction {
|
|
|
117
117
|
callbackSuccess: Boolean(this.getNodeParameter('callbackSuccess', i, true)),
|
|
118
118
|
callbackError: String(this.getNodeParameter('callbackError', i, '') ?? ''),
|
|
119
119
|
};
|
|
120
|
-
const result = await
|
|
120
|
+
const result = await eventHandler_1.handleEventByType.call(this, eventType, eventData, nodeParams);
|
|
121
121
|
returnData.push({
|
|
122
122
|
json: {
|
|
123
123
|
...items[i].json,
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import type { IExecuteFunctions } from 'n8n-workflow';
|
|
2
|
+
export declare function sendMessageToAgent(this: IExecuteFunctions, webhookUrl: string, userId: string, messageData: Record<string, unknown>): Promise<unknown>;
|
|
@@ -1,66 +1,38 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.sendMessageToAgent = sendMessageToAgent;
|
|
7
|
-
const form_data_1 = __importDefault(require("form-data"));
|
|
8
|
-
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
9
|
-
const rateLimiter_1 = require("./rateLimiter");
|
|
10
|
-
const http_status_codes_1 = require("http-status-codes");
|
|
11
4
|
async function sendMessageToAgent(webhookUrl, userId, messageData) {
|
|
12
5
|
const url = `${webhookUrl}/${userId}`;
|
|
13
|
-
const formData = new form_data_1.default();
|
|
14
6
|
const msg = messageData.message;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if (
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
formData.append('isMixedAttachments', String(msg?.isMixedAttachments ?? false));
|
|
7
|
+
const payload = {};
|
|
8
|
+
const chatId = messageData.chat_id ?? msg?.chatId;
|
|
9
|
+
if (chatId != null)
|
|
10
|
+
payload.chatId = String(chatId);
|
|
11
|
+
payload.sender = msg?.sender ?? 'user';
|
|
12
|
+
payload.sentDate = msg?.sentDate ?? new Date().toISOString();
|
|
13
|
+
const text = (messageData.text ?? msg?.text);
|
|
14
|
+
if (text != null)
|
|
15
|
+
payload.text = text;
|
|
16
|
+
payload.isAudio = Boolean(msg?.isAudio ?? false);
|
|
17
|
+
payload.hasAttachment = Boolean(msg?.hasAttachment ?? false);
|
|
18
|
+
payload.duration = Number(msg?.duration ?? 0);
|
|
19
|
+
payload.isMixedAttachments = Boolean(msg?.isMixedAttachments ?? false);
|
|
29
20
|
if (msg?.audioFileName) {
|
|
30
|
-
|
|
21
|
+
payload.audioFileName = String(msg.audioFileName);
|
|
31
22
|
if (msg.audioData)
|
|
32
|
-
|
|
23
|
+
payload.audioData = String(msg.audioData);
|
|
33
24
|
if (msg.audioMimeType)
|
|
34
|
-
|
|
25
|
+
payload.audioMimeType = String(msg.audioMimeType);
|
|
35
26
|
}
|
|
36
|
-
if (msg?.files && Array.isArray(msg.files))
|
|
37
|
-
|
|
38
|
-
const response = await (0, rateLimiter_1.rateLimitedRequest)(async () => {
|
|
39
|
-
const res = await (0, node_fetch_1.default)(url, {
|
|
40
|
-
method: 'POST',
|
|
41
|
-
body: formData,
|
|
42
|
-
headers: { 'User-Agent': 'n8n-BGOS-Action/1.0' },
|
|
43
|
-
});
|
|
44
|
-
if (res.status === http_status_codes_1.StatusCodes.TOO_MANY_REQUESTS) {
|
|
45
|
-
const retryAfter = res.headers.get('retry-after');
|
|
46
|
-
const delay = retryAfter ? parseInt(retryAfter, 10) * 1000 : 1000;
|
|
47
|
-
throw Object.assign(new Error(`Rate limit exceeded. Retry after ${delay}ms`), { response: res, status: http_status_codes_1.StatusCodes.TOO_MANY_REQUESTS });
|
|
48
|
-
}
|
|
49
|
-
return res;
|
|
50
|
-
});
|
|
51
|
-
if (!response.ok && response.status !== http_status_codes_1.StatusCodes.TOO_MANY_REQUESTS) {
|
|
52
|
-
throw new Error(`HTTP error! status: ${response.status} - ${response.statusText}`);
|
|
53
|
-
}
|
|
54
|
-
const contentType = response.headers.get('content-type');
|
|
55
|
-
const isAudioResponse = contentType && (contentType.includes('audio/') || contentType.includes('application/octet-stream') || contentType.includes('binary'));
|
|
56
|
-
if (isAudioResponse) {
|
|
57
|
-
const arrayBuffer = await response.arrayBuffer();
|
|
58
|
-
const base64Audio = Buffer.from(arrayBuffer).toString('base64');
|
|
59
|
-
return { type: 'audio', data: base64Audio, contentType, audioFileName: `audio_response_${Date.now()}.mp3` };
|
|
27
|
+
if (msg?.files && Array.isArray(msg.files)) {
|
|
28
|
+
payload.files = msg.files;
|
|
60
29
|
}
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
30
|
+
const response = await this.helpers.httpRequest({
|
|
31
|
+
method: 'POST',
|
|
32
|
+
url,
|
|
33
|
+
headers: { 'User-Agent': 'n8n-BGOS-Action/1.0' },
|
|
34
|
+
body: payload,
|
|
35
|
+
json: true,
|
|
36
|
+
});
|
|
37
|
+
return response;
|
|
66
38
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { IExecuteFunctions } from 'n8n-workflow';
|
|
1
2
|
type NodeParams = {
|
|
2
3
|
operation: string;
|
|
3
4
|
webhookUrl?: string;
|
|
@@ -8,5 +9,5 @@ type NodeParams = {
|
|
|
8
9
|
callbackError?: string;
|
|
9
10
|
[key: string]: unknown;
|
|
10
11
|
};
|
|
11
|
-
export declare function handleEventByType(eventType: string, eventData: Record<string, unknown>, nodeParams: NodeParams): Promise<unknown>;
|
|
12
|
+
export declare function handleEventByType(this: IExecuteFunctions, eventType: string, eventData: Record<string, unknown>, nodeParams: NodeParams): Promise<unknown>;
|
|
12
13
|
export {};
|
|
@@ -27,7 +27,7 @@ async function handleEventByType(eventType, eventData, nodeParams) {
|
|
|
27
27
|
const webhookUrl = (nodeParams.webhookUrl ?? assistant?.webhookUrl ?? assistant?.webhook);
|
|
28
28
|
if (!webhookUrl)
|
|
29
29
|
throw new Error('Webhook URL is required.');
|
|
30
|
-
return await
|
|
30
|
+
return await agentWebhook_1.sendMessageToAgent.call(this, webhookUrl, userId, eventData);
|
|
31
31
|
}
|
|
32
32
|
case 'reportCallbackResult': {
|
|
33
33
|
const apiOptions = getApiOptions(nodeParams);
|
|
@@ -38,7 +38,13 @@ async function handleEventByType(eventType, eventData, nodeParams) {
|
|
|
38
38
|
const error = (nodeParams.callbackError ?? eventData.error);
|
|
39
39
|
if (!messageId || !optionId || !userId)
|
|
40
40
|
throw new Error('message_id, option_id and user_id are required for reportCallbackResult. Use data from button_clicked event.');
|
|
41
|
-
return await
|
|
41
|
+
return await techWebhook_1.reportCallbackResult.call(this, apiOptions, {
|
|
42
|
+
messageId: String(messageId),
|
|
43
|
+
optionId: String(optionId),
|
|
44
|
+
userId,
|
|
45
|
+
success,
|
|
46
|
+
error,
|
|
47
|
+
});
|
|
42
48
|
}
|
|
43
49
|
case 'sendMessageBackend':
|
|
44
50
|
case 'sendVoiceMessageBackend':
|
|
@@ -51,7 +57,7 @@ async function handleEventByType(eventType, eventData, nodeParams) {
|
|
|
51
57
|
const text = eventData.text ?? message?.text ?? null;
|
|
52
58
|
if (!assistantId || !chatId)
|
|
53
59
|
throw new Error('assistantId and chatId are required for send-message operations.');
|
|
54
|
-
return await
|
|
60
|
+
return await techWebhook_1.sendMessageToBackend.call(this, apiOptions, {
|
|
55
61
|
assistantId: assistantId,
|
|
56
62
|
chatId: chatId,
|
|
57
63
|
sender: (eventData.sender ?? message?.sender ?? 'assistant'),
|
|
@@ -78,7 +84,7 @@ async function handleEventByType(eventType, eventData, nodeParams) {
|
|
|
78
84
|
if (!assistant)
|
|
79
85
|
throw new Error('Assistant data is required for createAssistant operation.');
|
|
80
86
|
const { id: _id, userId: _u, ...assistantData } = assistant;
|
|
81
|
-
return await
|
|
87
|
+
return await techWebhook_1.createAssistant.call(this, getApiOptions(nodeParams), userId, assistantData);
|
|
82
88
|
}
|
|
83
89
|
case 'updateAssistant': {
|
|
84
90
|
const userId = (nodeParams.userId ?? eventData.user_id ?? eventData.userId);
|
|
@@ -90,7 +96,7 @@ async function handleEventByType(eventType, eventData, nodeParams) {
|
|
|
90
96
|
if (!assistantId)
|
|
91
97
|
throw new Error('Assistant ID is required for updateAssistant operation.');
|
|
92
98
|
const { id: _id, userId: _u, ...assistantData } = assistant;
|
|
93
|
-
return await
|
|
99
|
+
return await techWebhook_1.updateAssistant.call(this, getApiOptions(nodeParams), userId, String(assistantId), assistantData);
|
|
94
100
|
}
|
|
95
101
|
case 'deleteAssistant': {
|
|
96
102
|
const userId = (nodeParams.userId ?? eventData.user_id ?? eventData.userId);
|
|
@@ -99,7 +105,7 @@ async function handleEventByType(eventType, eventData, nodeParams) {
|
|
|
99
105
|
const assistantId = eventData.assistant_id ?? assistant?.id;
|
|
100
106
|
if (!assistantId)
|
|
101
107
|
throw new Error('Assistant ID is required for deleteAssistant operation.');
|
|
102
|
-
return await
|
|
108
|
+
return await techWebhook_1.deleteAssistant.call(this, getApiOptions(nodeParams), userId, String(assistantId));
|
|
103
109
|
}
|
|
104
110
|
case 'renameChat': {
|
|
105
111
|
const userId = (nodeParams.userId ?? eventData.user_id ?? eventData.userId);
|
|
@@ -111,7 +117,7 @@ async function handleEventByType(eventType, eventData, nodeParams) {
|
|
|
111
117
|
const newName = eventData.new_name ?? chat?.title;
|
|
112
118
|
if (!chatId || !newName)
|
|
113
119
|
throw new Error('Chat ID and new name are required for renameChat operation.');
|
|
114
|
-
return await
|
|
120
|
+
return await techWebhook_1.renameChat.call(this, getApiOptions(nodeParams), userId, String(chatId), String(newName));
|
|
115
121
|
}
|
|
116
122
|
case 'deleteChat': {
|
|
117
123
|
const userId = (nodeParams.userId ?? eventData.user_id ?? eventData.userId);
|
|
@@ -120,7 +126,7 @@ async function handleEventByType(eventType, eventData, nodeParams) {
|
|
|
120
126
|
const chatId = eventData.chat_id ?? chat?.id;
|
|
121
127
|
if (!chatId)
|
|
122
128
|
throw new Error('Chat ID is required for deleteChat operation.');
|
|
123
|
-
return await
|
|
129
|
+
return await techWebhook_1.deleteChat.call(this, getApiOptions(nodeParams), userId, String(chatId));
|
|
124
130
|
}
|
|
125
131
|
case 'saveChatHistory': {
|
|
126
132
|
const userId = (nodeParams.userId ?? eventData.user_id ?? eventData.userId);
|
|
@@ -129,7 +135,7 @@ async function handleEventByType(eventType, eventData, nodeParams) {
|
|
|
129
135
|
if (!eventData.message && !eventData.messages)
|
|
130
136
|
throw new Error('Message or messages data is required for saveChatHistory operation.');
|
|
131
137
|
const messages = (eventData.messages ?? [eventData.message]);
|
|
132
|
-
return await
|
|
138
|
+
return await techWebhook_1.saveChatHistory.call(this, getApiOptions(nodeParams), userId, messages);
|
|
133
139
|
}
|
|
134
140
|
default:
|
|
135
141
|
throw new Error(`Unsupported operation: ${operation}`);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare function retryWithBackoff<T>(fn: () => Promise<T
|
|
1
|
+
export declare function retryWithBackoff<T>(fn: () => Promise<T>): Promise<T>;
|
|
2
2
|
export declare function rateLimitedRequest<T>(fn: () => Promise<T>): Promise<T>;
|
|
@@ -1,37 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.retryWithBackoff = retryWithBackoff;
|
|
7
4
|
exports.rateLimitedRequest = rateLimitedRequest;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
reservoirRefreshAmount: 30,
|
|
13
|
-
reservoirRefreshInterval: 1000,
|
|
14
|
-
maxConcurrent: 1,
|
|
15
|
-
minTime: 1000 / 30,
|
|
16
|
-
});
|
|
17
|
-
async function retryWithBackoff(fn, maxRetries = 5, retryCount = 0) {
|
|
18
|
-
try {
|
|
19
|
-
return await fn();
|
|
20
|
-
}
|
|
21
|
-
catch (error) {
|
|
22
|
-
const err = error;
|
|
23
|
-
const status = err?.response?.status ?? err?.status;
|
|
24
|
-
const isRateLimitError = status === http_status_codes_1.StatusCodes.TOO_MANY_REQUESTS ||
|
|
25
|
-
(err?.message && String(err.message).includes(String(http_status_codes_1.StatusCodes.TOO_MANY_REQUESTS)));
|
|
26
|
-
if (isRateLimitError && retryCount < maxRetries) {
|
|
27
|
-
const retryAfter = err?.response?.headers?.get?.('retry-after');
|
|
28
|
-
const delay = retryAfter ? parseInt(retryAfter, 10) * 1000 : Math.min(1000 * 2 ** retryCount, 32000);
|
|
29
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
30
|
-
return retryWithBackoff(fn, maxRetries, retryCount + 1);
|
|
31
|
-
}
|
|
32
|
-
throw error;
|
|
33
|
-
}
|
|
5
|
+
async function retryWithBackoff(fn) {
|
|
6
|
+
// For verified community nodes, external dependencies and timers like setTimeout
|
|
7
|
+
// are restricted. Keep this helper as a simple pass-through.
|
|
8
|
+
return fn();
|
|
34
9
|
}
|
|
35
10
|
async function rateLimitedRequest(fn) {
|
|
36
|
-
return
|
|
11
|
+
return retryWithBackoff(fn);
|
|
37
12
|
}
|
|
@@ -1,20 +1,21 @@
|
|
|
1
|
+
import type { IExecuteFunctions } from 'n8n-workflow';
|
|
1
2
|
export interface BgosApiOptions {
|
|
2
3
|
baseUrl: string;
|
|
3
4
|
apiKey?: string;
|
|
4
5
|
}
|
|
5
|
-
export declare function createAssistant(options: BgosApiOptions, userId: string, assistantData: Record<string, unknown>): Promise<unknown>;
|
|
6
|
-
export declare function updateAssistant(options: BgosApiOptions, userId: string, assistantId: string | number, assistantData: Record<string, unknown>): Promise<unknown>;
|
|
7
|
-
export declare function deleteAssistant(options: BgosApiOptions, _userId: string, assistantId: string | number): Promise<{
|
|
6
|
+
export declare function createAssistant(this: IExecuteFunctions, options: BgosApiOptions, userId: string, assistantData: Record<string, unknown>): Promise<unknown>;
|
|
7
|
+
export declare function updateAssistant(this: IExecuteFunctions, options: BgosApiOptions, userId: string, assistantId: string | number, assistantData: Record<string, unknown>): Promise<unknown>;
|
|
8
|
+
export declare function deleteAssistant(this: IExecuteFunctions, options: BgosApiOptions, _userId: string, assistantId: string | number): Promise<{
|
|
8
9
|
success: boolean;
|
|
9
10
|
}>;
|
|
10
|
-
export declare function renameChat(options: BgosApiOptions, userId: string, chatId: string | number, newTitle: string): Promise<{
|
|
11
|
+
export declare function renameChat(this: IExecuteFunctions, options: BgosApiOptions, userId: string, chatId: string | number, newTitle: string): Promise<{
|
|
11
12
|
success: boolean;
|
|
12
13
|
}>;
|
|
13
|
-
export declare function deleteChat(options: BgosApiOptions, _userId: string, chatId: string | number): Promise<{
|
|
14
|
+
export declare function deleteChat(this: IExecuteFunctions, options: BgosApiOptions, _userId: string, chatId: string | number): Promise<{
|
|
14
15
|
success: boolean;
|
|
15
16
|
}>;
|
|
16
|
-
export declare function saveChatHistory(options: BgosApiOptions, _userId: string, messages: unknown[]): Promise<unknown>;
|
|
17
|
-
export declare function sendMessageToBackend(options: BgosApiOptions, payload: {
|
|
17
|
+
export declare function saveChatHistory(this: IExecuteFunctions, options: BgosApiOptions, _userId: string, messages: unknown[]): Promise<unknown>;
|
|
18
|
+
export declare function sendMessageToBackend(this: IExecuteFunctions, options: BgosApiOptions, payload: {
|
|
18
19
|
assistantId: string | number;
|
|
19
20
|
chatId: string | number;
|
|
20
21
|
sender?: string;
|
|
@@ -32,7 +33,7 @@ export declare function sendMessageToBackend(options: BgosApiOptions, payload: {
|
|
|
32
33
|
isMixedAttachments?: boolean | null;
|
|
33
34
|
[key: string]: unknown;
|
|
34
35
|
}): Promise<unknown>;
|
|
35
|
-
export declare function reportCallbackResult(options: BgosApiOptions, payload: {
|
|
36
|
+
export declare function reportCallbackResult(this: IExecuteFunctions, options: BgosApiOptions, payload: {
|
|
36
37
|
messageId: number | string;
|
|
37
38
|
optionId: number | string;
|
|
38
39
|
userId: string;
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.createAssistant = createAssistant;
|
|
7
4
|
exports.updateAssistant = updateAssistant;
|
|
@@ -11,10 +8,6 @@ exports.deleteChat = deleteChat;
|
|
|
11
8
|
exports.saveChatHistory = saveChatHistory;
|
|
12
9
|
exports.sendMessageToBackend = sendMessageToBackend;
|
|
13
10
|
exports.reportCallbackResult = reportCallbackResult;
|
|
14
|
-
/**
|
|
15
|
-
* HTTP calls to BGOS backend REST API (api/v1/assistants, chats, messages).
|
|
16
|
-
*/
|
|
17
|
-
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
18
11
|
function buildHeaders(apiKey) {
|
|
19
12
|
const headers = { 'Content-Type': 'application/json', Accept: 'application/json' };
|
|
20
13
|
if (apiKey)
|
|
@@ -23,49 +16,53 @@ function buildHeaders(apiKey) {
|
|
|
23
16
|
}
|
|
24
17
|
async function createAssistant(options, userId, assistantData) {
|
|
25
18
|
const url = `${options.baseUrl.replace(/\/$/, '')}/api/v1/assistants`;
|
|
26
|
-
|
|
19
|
+
return this.helpers.httpRequest({
|
|
27
20
|
method: 'POST',
|
|
21
|
+
url,
|
|
28
22
|
headers: buildHeaders(options.apiKey),
|
|
29
|
-
body:
|
|
23
|
+
body: { userId, ...assistantData },
|
|
24
|
+
json: true,
|
|
30
25
|
});
|
|
31
|
-
if (!response.ok)
|
|
32
|
-
throw new Error(`Failed to create assistant: ${response.status} ${response.statusText} - ${await response.text()}`);
|
|
33
|
-
return response.json();
|
|
34
26
|
}
|
|
35
27
|
async function updateAssistant(options, userId, assistantId, assistantData) {
|
|
36
28
|
const url = `${options.baseUrl.replace(/\/$/, '')}/api/v1/assistants/${assistantId}`;
|
|
37
|
-
|
|
29
|
+
return this.helpers.httpRequest({
|
|
38
30
|
method: 'PATCH',
|
|
31
|
+
url,
|
|
39
32
|
headers: buildHeaders(options.apiKey),
|
|
40
|
-
body:
|
|
33
|
+
body: { userId, ...assistantData },
|
|
34
|
+
json: true,
|
|
41
35
|
});
|
|
42
|
-
if (!response.ok)
|
|
43
|
-
throw new Error(`Failed to update assistant: ${response.status} ${response.statusText} - ${await response.text()}`);
|
|
44
|
-
return response.json();
|
|
45
36
|
}
|
|
46
37
|
async function deleteAssistant(options, _userId, assistantId) {
|
|
47
38
|
const url = `${options.baseUrl.replace(/\/$/, '')}/api/v1/assistants/${assistantId}`;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
39
|
+
await this.helpers.httpRequest({
|
|
40
|
+
method: 'DELETE',
|
|
41
|
+
url,
|
|
42
|
+
headers: buildHeaders(options.apiKey),
|
|
43
|
+
json: false,
|
|
44
|
+
});
|
|
51
45
|
return { success: true };
|
|
52
46
|
}
|
|
53
47
|
async function renameChat(options, userId, chatId, newTitle) {
|
|
54
48
|
const url = `${options.baseUrl.replace(/\/$/, '')}/api/v1/chats/${chatId}/title`;
|
|
55
|
-
|
|
49
|
+
await this.helpers.httpRequest({
|
|
56
50
|
method: 'PATCH',
|
|
51
|
+
url,
|
|
57
52
|
headers: buildHeaders(options.apiKey),
|
|
58
|
-
body:
|
|
53
|
+
body: { userId, title: newTitle },
|
|
54
|
+
json: true,
|
|
59
55
|
});
|
|
60
|
-
if (!response.ok)
|
|
61
|
-
throw new Error(`Failed to rename chat: ${response.status} ${response.statusText} - ${await response.text()}`);
|
|
62
56
|
return { success: true };
|
|
63
57
|
}
|
|
64
58
|
async function deleteChat(options, _userId, chatId) {
|
|
65
59
|
const url = `${options.baseUrl.replace(/\/$/, '')}/api/v1/chats/${chatId}`;
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
60
|
+
await this.helpers.httpRequest({
|
|
61
|
+
method: 'DELETE',
|
|
62
|
+
url,
|
|
63
|
+
headers: buildHeaders(options.apiKey),
|
|
64
|
+
json: false,
|
|
65
|
+
});
|
|
69
66
|
return { success: true };
|
|
70
67
|
}
|
|
71
68
|
async function saveChatHistory(options, _userId, messages) {
|
|
@@ -76,14 +73,13 @@ async function saveChatHistory(options, _userId, messages) {
|
|
|
76
73
|
text: (m.text ?? m.message?.text ?? ''),
|
|
77
74
|
sentDate: (m.sentDate ?? m.sent_date ?? m.message?.sentDate ?? m.timestamp ?? new Date().toISOString()),
|
|
78
75
|
}));
|
|
79
|
-
|
|
76
|
+
return this.helpers.httpRequest({
|
|
80
77
|
method: 'POST',
|
|
78
|
+
url,
|
|
81
79
|
headers: buildHeaders(options.apiKey),
|
|
82
|
-
body:
|
|
80
|
+
body: dtos,
|
|
81
|
+
json: true,
|
|
83
82
|
});
|
|
84
|
-
if (!response.ok)
|
|
85
|
-
throw new Error(`Failed to save chat history: ${response.status} ${response.statusText} - ${await response.text()}`);
|
|
86
|
-
return response.json();
|
|
87
83
|
}
|
|
88
84
|
async function sendMessageToBackend(options, payload) {
|
|
89
85
|
const url = `${options.baseUrl.replace(/\/$/, '')}/api/v1/send-message`;
|
|
@@ -105,29 +101,28 @@ async function sendMessageToBackend(options, payload) {
|
|
|
105
101
|
options: payload.options ?? [],
|
|
106
102
|
files: payload.files ?? [],
|
|
107
103
|
};
|
|
108
|
-
|
|
104
|
+
return this.helpers.httpRequest({
|
|
109
105
|
method: 'POST',
|
|
106
|
+
url,
|
|
110
107
|
headers: buildHeaders(options.apiKey),
|
|
111
|
-
body
|
|
108
|
+
body,
|
|
109
|
+
json: true,
|
|
112
110
|
});
|
|
113
|
-
if (!response.ok)
|
|
114
|
-
throw new Error(`Failed to send message to BGOS backend: ${response.status} ${response.statusText} - ${await response.text()}`);
|
|
115
|
-
return response.json();
|
|
116
111
|
}
|
|
117
112
|
async function reportCallbackResult(options, payload) {
|
|
118
113
|
const url = `${options.baseUrl.replace(/\/$/, '')}/api/v1/messages/callback-result`;
|
|
119
|
-
const
|
|
114
|
+
const body = {
|
|
115
|
+
messageId: Number(payload.messageId),
|
|
116
|
+
optionId: Number(payload.optionId),
|
|
117
|
+
userId: payload.userId,
|
|
118
|
+
success: payload.success,
|
|
119
|
+
error: payload.error,
|
|
120
|
+
};
|
|
121
|
+
return this.helpers.httpRequest({
|
|
120
122
|
method: 'POST',
|
|
123
|
+
url,
|
|
121
124
|
headers: buildHeaders(options.apiKey),
|
|
122
|
-
body
|
|
123
|
-
|
|
124
|
-
optionId: Number(payload.optionId),
|
|
125
|
-
userId: payload.userId,
|
|
126
|
-
success: payload.success,
|
|
127
|
-
error: payload.error,
|
|
128
|
-
}),
|
|
125
|
+
body,
|
|
126
|
+
json: true,
|
|
129
127
|
});
|
|
130
|
-
if (!response.ok)
|
|
131
|
-
throw new Error(`Failed to report callback result: ${response.status} ${response.statusText} - ${await response.text()}`);
|
|
132
|
-
return response.json();
|
|
133
128
|
}
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.BgosTrigger = void 0;
|
|
7
4
|
const n8n_workflow_1 = require("n8n-workflow");
|
|
8
|
-
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
9
5
|
const stubs_1 = require("./stubs");
|
|
10
6
|
class BgosTrigger {
|
|
11
7
|
description = {
|
|
@@ -95,15 +91,13 @@ class BgosTrigger {
|
|
|
95
91
|
const url = `${String(baseUrl).replace(/\/$/, '')}/api/v1/webhooks`;
|
|
96
92
|
const webhookUrl = this.getNodeWebhookUrl('default');
|
|
97
93
|
const updates = this.getNodeParameter('updates', 0);
|
|
98
|
-
const
|
|
94
|
+
const data = (await this.helpers.httpRequest({
|
|
99
95
|
method: 'POST',
|
|
96
|
+
url,
|
|
100
97
|
headers: { 'Content-Type': 'application/json', 'X-API-Key': apiKey },
|
|
101
|
-
body:
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
throw new Error(`Failed to register BGOS webhook: ${response.status} ${response.statusText} - ${await response.text()}`);
|
|
105
|
-
}
|
|
106
|
-
const data = (await response.json());
|
|
98
|
+
body: { webhookUrl, eventTypes: updates?.length ? updates : ['*'] },
|
|
99
|
+
json: true,
|
|
100
|
+
}));
|
|
107
101
|
if (data?.id != null) {
|
|
108
102
|
const staticData = this.getWorkflowStaticData('node');
|
|
109
103
|
staticData.webhookSubscriptionId = String(data.id);
|
|
@@ -120,18 +114,15 @@ class BgosTrigger {
|
|
|
120
114
|
return true;
|
|
121
115
|
const url = `${String(baseUrl).replace(/\/$/, '')}/api/v1/webhooks/${subscriptionId}`;
|
|
122
116
|
try {
|
|
123
|
-
|
|
117
|
+
await this.helpers.httpRequest({
|
|
124
118
|
method: 'DELETE',
|
|
119
|
+
url,
|
|
125
120
|
headers: { 'Content-Type': 'application/json', 'X-API-Key': apiKey },
|
|
121
|
+
json: false,
|
|
126
122
|
});
|
|
127
|
-
if (!response.ok) {
|
|
128
|
-
// eslint-disable-next-line no-console
|
|
129
|
-
console.error(`Failed to delete BGOS webhook ${subscriptionId}: ${response.status} ${response.statusText}`);
|
|
130
|
-
}
|
|
131
123
|
}
|
|
132
124
|
catch (error) {
|
|
133
|
-
//
|
|
134
|
-
console.error(`Error deleting BGOS webhook ${subscriptionId}:`, error);
|
|
125
|
+
// Best-effort cleanup; ignore errors when deleting remote webhook
|
|
135
126
|
}
|
|
136
127
|
delete staticData.webhookSubscriptionId;
|
|
137
128
|
return true;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n8n-nodes-bgos",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "n8n community nodes for BGOS (Brand Growth OS) - AI assistant chat platform",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"n8n-community-node-package",
|
|
@@ -41,12 +41,7 @@
|
|
|
41
41
|
"dist/nodes/BGOSAction/BGOSAction.node.js"
|
|
42
42
|
]
|
|
43
43
|
},
|
|
44
|
-
"dependencies": {
|
|
45
|
-
"bottleneck": "^2.19.5",
|
|
46
|
-
"form-data": "^4.0.0",
|
|
47
|
-
"http-status-codes": "^2.3.0",
|
|
48
|
-
"node-fetch": "^3.3.2"
|
|
49
|
-
},
|
|
44
|
+
"dependencies": {},
|
|
50
45
|
"devDependencies": {
|
|
51
46
|
"@types/node": "^20.0.0",
|
|
52
47
|
"@typescript-eslint/parser": "~7.18.0",
|