n8n-nodes-bgos 0.3.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.
Files changed (36) hide show
  1. package/LICENSE +21 -0
  2. package/LICENSE.md +21 -0
  3. package/README.md +63 -0
  4. package/dist/credentials/BgosApi.credentials.d.ts +9 -0
  5. package/dist/credentials/BgosApi.credentials.js +42 -0
  6. package/dist/icons/bgos.png +0 -0
  7. package/dist/icons/bgos.svg +5 -0
  8. package/dist/nodes/BGOSAction/BGOSAction.node.d.ts +5 -0
  9. package/dist/nodes/BGOSAction/BGOSAction.node.js +141 -0
  10. package/dist/nodes/BGOSAction/EventTypes.d.ts +21 -0
  11. package/dist/nodes/BGOSAction/EventTypes.js +25 -0
  12. package/dist/nodes/BGOSAction/agentWebhook.d.ts +1 -0
  13. package/dist/nodes/BGOSAction/agentWebhook.js +66 -0
  14. package/dist/nodes/BGOSAction/handler/eventHandler.d.ts +12 -0
  15. package/dist/nodes/BGOSAction/handler/eventHandler.js +137 -0
  16. package/dist/nodes/BGOSAction/rateLimiter.d.ts +2 -0
  17. package/dist/nodes/BGOSAction/rateLimiter.js +37 -0
  18. package/dist/nodes/BGOSAction/techWebhook.d.ts +43 -0
  19. package/dist/nodes/BGOSAction/techWebhook.js +133 -0
  20. package/dist/nodes/Bgos/Bgos.node.d.ts +4 -0
  21. package/dist/nodes/Bgos/Bgos.node.js +64 -0
  22. package/dist/nodes/Bgos/resources/assistant/index.d.ts +3 -0
  23. package/dist/nodes/Bgos/resources/assistant/index.js +362 -0
  24. package/dist/nodes/Bgos/resources/chat/index.d.ts +3 -0
  25. package/dist/nodes/Bgos/resources/chat/index.js +286 -0
  26. package/dist/nodes/Bgos/resources/message/index.d.ts +3 -0
  27. package/dist/nodes/Bgos/resources/message/index.js +881 -0
  28. package/dist/nodes/Bgos/resources/scheduledTask/index.d.ts +3 -0
  29. package/dist/nodes/Bgos/resources/scheduledTask/index.js +85 -0
  30. package/dist/nodes/Bgos/resources/user/index.d.ts +3 -0
  31. package/dist/nodes/Bgos/resources/user/index.js +158 -0
  32. package/dist/nodes/BgosTrigger/BgosTrigger.node.d.ts +12 -0
  33. package/dist/nodes/BgosTrigger/BgosTrigger.node.js +142 -0
  34. package/dist/nodes/BgosTrigger/stubs.d.ts +4 -0
  35. package/dist/nodes/BgosTrigger/stubs.js +86 -0
  36. package/package.json +71 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 BrandGrowthOS
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 BGOS Team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # n8n-nodes-bgos
2
+
3
+ Community nodes for [n8n](https://n8n.io/) to integrate with the [BGOS](https://brandgrowthos.ai) AI assistant chat platform.
4
+
5
+ ## Nodes
6
+
7
+ ### BGOS (Action Node)
8
+
9
+ Perform operations on the BGOS platform:
10
+
11
+ | Resource | Operations |
12
+ |---|---|
13
+ | **Message** | Send Message, Create, Bulk Create, Edit, Delete, Button Callback |
14
+ | **Chat** | Create, Get, Rename, Delete, Get Messages, Get Unread, Increment Unread, Mark as Read |
15
+ | **Assistant** | Create, Get, Update, Delete, Reorder, Get With Chats |
16
+ | **User** | Get or Create, Update |
17
+ | **Scheduled Task** | Get, Get User Tasks, Delete |
18
+
19
+ ### BGOS Trigger (Webhook Node)
20
+
21
+ Starts workflows when BGOS events occur. Supports 16 event types:
22
+
23
+ - `message`, `edited_message`, `voice_message`, `reply_message`
24
+ - `new_chat`, `chat_renamed`, `chat_deleted`
25
+ - `new_assistant`, `assistant_updated`, `assistant_deleted`
26
+ - `voice_started`, `voice_ended`
27
+ - `message_deleted`, `button_clicked`
28
+ - `user_created`, `user_updated`
29
+
30
+ ## Credentials
31
+
32
+ Configure with your BGOS backend URL and optional API key:
33
+
34
+ - **Base URL**: Your BGOS backend URL (default: `http://localhost:8080`)
35
+ - **API Key**: Optional, for future authentication support
36
+
37
+ ## Setup
38
+
39
+ ### In BGOS Backend
40
+
41
+ Set the `FORWARDER_WEBHOOK_URL` environment variable to your n8n webhook URL:
42
+
43
+ ```
44
+ FORWARDER_WEBHOOK_URL=https://your-n8n-instance.com/webhook/bgos-webhook
45
+ ```
46
+
47
+ ### In n8n
48
+
49
+ 1. Install the package: `pnpm install n8n-nodes-bgos`
50
+ 2. Configure BGOS API credentials with your backend URL
51
+ 3. Use the BGOS Trigger node to receive events
52
+ 4. Use the BGOS node to perform actions
53
+
54
+ ## Development
55
+
56
+ ```bash
57
+ pnpm install
58
+ pnpm build
59
+ ```
60
+
61
+ ## License
62
+
63
+ [MIT](LICENSE.md)
@@ -0,0 +1,9 @@
1
+ import { IAuthenticateGeneric, ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
2
+ export declare class BgosApi implements ICredentialType {
3
+ name: string;
4
+ displayName: string;
5
+ documentationUrl: string;
6
+ properties: INodeProperties[];
7
+ authenticate: IAuthenticateGeneric;
8
+ test: ICredentialTestRequest;
9
+ }
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BgosApi = void 0;
4
+ class BgosApi {
5
+ name = 'bgosApi';
6
+ displayName = 'BGOS API';
7
+ documentationUrl = '';
8
+ properties = [
9
+ {
10
+ displayName: 'Base URL',
11
+ name: 'baseUrl',
12
+ type: 'string',
13
+ default: 'http://localhost:8080',
14
+ required: true,
15
+ description: 'The base URL of your BGOS backend',
16
+ },
17
+ {
18
+ displayName: 'API Key',
19
+ name: 'apiKey',
20
+ type: 'string',
21
+ typeOptions: { password: true },
22
+ default: '',
23
+ description: 'API key for authentication (optional, for future use)',
24
+ },
25
+ ];
26
+ authenticate = {
27
+ type: 'generic',
28
+ properties: {
29
+ headers: {
30
+ Authorization: '={{"Bearer " + $credentials.apiKey}}',
31
+ },
32
+ },
33
+ };
34
+ test = {
35
+ request: {
36
+ baseURL: '={{$credentials.baseUrl}}',
37
+ url: '/api/v1/service-options/health',
38
+ method: 'GET',
39
+ },
40
+ };
41
+ }
42
+ exports.BgosApi = BgosApi;
Binary file
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32">
2
+ <circle cx="16" cy="16" r="16" fill="#262624"/>
3
+ <path d="M7 10C7 8.34315 8.34315 7 10 7H22C23.6569 7 25 8.34315 25 10V18C25 19.6569 23.6569 21 22 21H18L13 25V21H10C8.34315 21 7 19.6569 7 18V10Z" fill="#FFD900"/>
4
+ <text x="16" y="17.5" text-anchor="middle" font-family="Arial, sans-serif" font-weight="bold" font-size="10" fill="#262624">B</text>
5
+ </svg>
@@ -0,0 +1,5 @@
1
+ import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
2
+ export declare class BGOSAction implements INodeType {
3
+ description: INodeTypeDescription;
4
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
5
+ }
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BGOSAction = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
5
+ const eventHandler_1 = require("./handler/eventHandler");
6
+ class BGOSAction {
7
+ description = {
8
+ displayName: 'BGOS Action',
9
+ name: 'bgosAction',
10
+ icon: 'file:../../icons/bgos.png',
11
+ group: ['transform'],
12
+ version: 1,
13
+ subtitle: '={{$parameter["operation"]}}',
14
+ description: 'Process BGOS events',
15
+ defaults: { name: 'BGOS Action' },
16
+ inputs: [n8n_workflow_1.NodeConnectionTypes.Main],
17
+ outputs: [n8n_workflow_1.NodeConnectionTypes.Main],
18
+ credentials: [
19
+ {
20
+ name: 'bgosApi',
21
+ required: false,
22
+ displayOptions: {
23
+ show: {
24
+ operation: [
25
+ 'sendMessageBackend',
26
+ 'reportCallbackResult',
27
+ 'createAssistant',
28
+ 'updateAssistant',
29
+ 'deleteAssistant',
30
+ 'renameChat',
31
+ 'deleteChat',
32
+ 'saveChatHistory',
33
+ ],
34
+ },
35
+ },
36
+ },
37
+ ],
38
+ properties: [
39
+ {
40
+ displayName: 'Operation',
41
+ name: 'operation',
42
+ type: 'options',
43
+ noDataExpression: true,
44
+ options: [
45
+ { name: 'Send Message to Agent', value: 'sendMessage', description: 'Send message event to Agent webhook (Ava)' },
46
+ { name: 'Send Message to BGOS', value: 'sendMessageBackend', description: 'Send message to BGOS backend API (POST /api/v1/send-message)' },
47
+ { name: 'Send Voice Message to BGOS', value: 'sendVoiceMessageBackend', description: 'Send voice message to BGOS backend API' },
48
+ { name: 'Send File to BGOS', value: 'sendFileMessageBackend', description: 'Send file attachment(s) to BGOS backend API' },
49
+ { name: 'Send Code Artifact to BGOS', value: 'sendCodeArtifactBackend', description: 'Send code artifact to BGOS backend API' },
50
+ { name: 'Send Article to BGOS', value: 'sendArticleBackend', description: 'Send long-form article to BGOS backend API' },
51
+ { name: 'Report Callback Result', value: 'reportCallbackResult', description: 'Report success/error after processing button click' },
52
+ { name: 'Create Assistant', value: 'createAssistant', description: 'Create assistant via BGOS backend API' },
53
+ { name: 'Update Assistant', value: 'updateAssistant', description: 'Update assistant via BGOS backend API' },
54
+ { name: 'Delete Assistant', value: 'deleteAssistant', description: 'Delete assistant via BGOS backend API' },
55
+ { name: 'Rename Chat', value: 'renameChat', description: 'Rename chat via BGOS backend API' },
56
+ { name: 'Delete Chat', value: 'deleteChat', description: 'Delete chat via BGOS backend API' },
57
+ { name: 'Save Chat History', value: 'saveChatHistory', description: 'Save messages via BGOS backend API (POST /messages/bulk)' },
58
+ ],
59
+ default: 'sendMessage',
60
+ required: true,
61
+ description: 'Select operation to perform',
62
+ },
63
+ {
64
+ displayName: 'Assistant Webhook URL',
65
+ name: 'webhookUrl',
66
+ type: 'string',
67
+ default: '',
68
+ placeholder: 'https://n8n.example.com/webhook/ava',
69
+ description: 'Override assistant webhook URL for Send Message to Agent. If empty, uses webhook from trigger event.',
70
+ displayOptions: { show: { operation: ['sendMessage'] } },
71
+ },
72
+ {
73
+ displayName: 'User ID',
74
+ name: 'userId',
75
+ type: 'string',
76
+ default: '',
77
+ placeholder: 'user_xxx',
78
+ description: 'Override user ID. If empty, uses user_id from trigger event.',
79
+ },
80
+ {
81
+ displayName: 'Callback Success',
82
+ name: 'callbackSuccess',
83
+ type: 'boolean',
84
+ default: true,
85
+ description: 'Set to false to report an error.',
86
+ displayOptions: { show: { operation: ['reportCallbackResult'] } },
87
+ },
88
+ {
89
+ displayName: 'Callback Error Message',
90
+ name: 'callbackError',
91
+ type: 'string',
92
+ default: '',
93
+ placeholder: 'Optional error message when success is false',
94
+ displayOptions: { show: { operation: ['reportCallbackResult'] } },
95
+ },
96
+ ],
97
+ };
98
+ async execute() {
99
+ const items = this.getInputData();
100
+ const returnData = [];
101
+ for (let i = 0; i < items.length; i += 1) {
102
+ const operation = this.getNodeParameter('operation', i);
103
+ try {
104
+ const eventData = items[i].json;
105
+ const rawEventType = eventData.event_type;
106
+ const eventType = typeof rawEventType === 'string' ? rawEventType : String(rawEventType ?? '');
107
+ if (!eventType)
108
+ throw new Error('Event type (event_type) is required in input data');
109
+ const creds = (await this.getCredentials('bgosApi'));
110
+ const apiBaseUrl = creds?.baseUrl ?? creds?.apiUrl ?? '';
111
+ const nodeParams = {
112
+ operation,
113
+ webhookUrl: String(this.getNodeParameter('webhookUrl', i, '') ?? ''),
114
+ userId: String(this.getNodeParameter('userId', i, '') ?? ''),
115
+ apiBaseUrl,
116
+ apiKey: creds?.apiKey ?? '',
117
+ callbackSuccess: Boolean(this.getNodeParameter('callbackSuccess', i, true)),
118
+ callbackError: String(this.getNodeParameter('callbackError', i, '') ?? ''),
119
+ };
120
+ const result = await (0, eventHandler_1.handleEventByType)(eventType, eventData, nodeParams);
121
+ returnData.push({
122
+ json: {
123
+ ...items[i].json,
124
+ ...result,
125
+ },
126
+ });
127
+ }
128
+ catch (error) {
129
+ returnData.push({
130
+ json: {
131
+ ...items[i].json,
132
+ success: false,
133
+ error: error instanceof Error ? error.message : 'Unknown error',
134
+ },
135
+ });
136
+ }
137
+ }
138
+ return [returnData];
139
+ }
140
+ }
141
+ exports.BGOSAction = BGOSAction;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Event types — aligned with bgos-backend EventType (event.types.ts)
3
+ */
4
+ export declare enum EventType {
5
+ MESSAGE = "message",
6
+ EDITED_MESSAGE = "edited_message",
7
+ VOICE_MESSAGE = "voice_message",
8
+ NEW_CHAT = "new_chat",
9
+ CHAT_RENAMED = "chat_renamed",
10
+ NEW_ASSISTANT = "new_assistant",
11
+ VOICE_STARTED = "voice_started",
12
+ VOICE_ENDED = "voice_ended",
13
+ REPLY_MESSAGE = "reply_message",
14
+ MESSAGE_DELETED = "message_deleted",
15
+ CHAT_DELETED = "chat_deleted",
16
+ ASSISTANT_UPDATED = "assistant_updated",
17
+ ASSISTANT_DELETED = "assistant_deleted",
18
+ USER_CREATED = "user_created",
19
+ USER_UPDATED = "user_updated",
20
+ BUTTON_CLICKED = "button_clicked"
21
+ }
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EventType = void 0;
4
+ /**
5
+ * Event types — aligned with bgos-backend EventType (event.types.ts)
6
+ */
7
+ var EventType;
8
+ (function (EventType) {
9
+ EventType["MESSAGE"] = "message";
10
+ EventType["EDITED_MESSAGE"] = "edited_message";
11
+ EventType["VOICE_MESSAGE"] = "voice_message";
12
+ EventType["NEW_CHAT"] = "new_chat";
13
+ EventType["CHAT_RENAMED"] = "chat_renamed";
14
+ EventType["NEW_ASSISTANT"] = "new_assistant";
15
+ EventType["VOICE_STARTED"] = "voice_started";
16
+ EventType["VOICE_ENDED"] = "voice_ended";
17
+ EventType["REPLY_MESSAGE"] = "reply_message";
18
+ EventType["MESSAGE_DELETED"] = "message_deleted";
19
+ EventType["CHAT_DELETED"] = "chat_deleted";
20
+ EventType["ASSISTANT_UPDATED"] = "assistant_updated";
21
+ EventType["ASSISTANT_DELETED"] = "assistant_deleted";
22
+ EventType["USER_CREATED"] = "user_created";
23
+ EventType["USER_UPDATED"] = "user_updated";
24
+ EventType["BUTTON_CLICKED"] = "button_clicked";
25
+ })(EventType || (exports.EventType = EventType = {}));
@@ -0,0 +1 @@
1
+ export declare function sendMessageToAgent(webhookUrl: string, userId: string, messageData: Record<string, unknown>): Promise<unknown>;
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ 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
+ async function sendMessageToAgent(webhookUrl, userId, messageData) {
12
+ const url = `${webhookUrl}/${userId}`;
13
+ const formData = new form_data_1.default();
14
+ const msg = messageData.message;
15
+ if (messageData.chat_id)
16
+ formData.append('chatId', String(messageData.chat_id));
17
+ if (msg?.chatId)
18
+ formData.append('chatId', String(msg.chatId));
19
+ formData.append('sender', msg?.sender ?? 'user');
20
+ formData.append('sentDate', msg?.sentDate ?? new Date().toISOString());
21
+ if (messageData.text)
22
+ formData.append('text', String(messageData.text));
23
+ if (msg?.text)
24
+ formData.append('text', String(msg.text));
25
+ formData.append('isAudio', String(msg?.isAudio ?? false));
26
+ formData.append('hasAttachment', String(msg?.hasAttachment ?? false));
27
+ formData.append('duration', String(msg?.duration ?? 0));
28
+ formData.append('isMixedAttachments', String(msg?.isMixedAttachments ?? false));
29
+ if (msg?.audioFileName) {
30
+ formData.append('audioFileName', String(msg.audioFileName));
31
+ if (msg.audioData)
32
+ formData.append('audioData', String(msg.audioData));
33
+ if (msg.audioMimeType)
34
+ formData.append('audioMimeType', String(msg.audioMimeType));
35
+ }
36
+ if (msg?.files && Array.isArray(msg.files))
37
+ formData.append('files', JSON.stringify(msg.files));
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` };
60
+ }
61
+ const responseText = await response.text();
62
+ if (!responseText) {
63
+ return { id: '-1', chat_id: messageData.chat_id ?? msg?.chatId, sender: 'assistant', sent_date: new Date().toISOString(), text: 'Empty response from server', is_audio: false, has_attachment: false };
64
+ }
65
+ return JSON.parse(responseText);
66
+ }
@@ -0,0 +1,12 @@
1
+ type NodeParams = {
2
+ operation: string;
3
+ webhookUrl?: string;
4
+ userId?: string;
5
+ apiBaseUrl?: string;
6
+ apiKey?: string;
7
+ callbackSuccess?: boolean;
8
+ callbackError?: string;
9
+ [key: string]: unknown;
10
+ };
11
+ export declare function handleEventByType(eventType: string, eventData: Record<string, unknown>, nodeParams: NodeParams): Promise<unknown>;
12
+ export {};
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleEventByType = handleEventByType;
4
+ const EventTypes_1 = require("../EventTypes");
5
+ const agentWebhook_1 = require("../agentWebhook");
6
+ const techWebhook_1 = require("../techWebhook");
7
+ function getApiOptions(nodeParams) {
8
+ const baseUrl = nodeParams.apiBaseUrl?.trim();
9
+ if (!baseUrl) {
10
+ throw new Error('BGOS API base URL is required for this operation. Add BGOS API credentials to the node.');
11
+ }
12
+ return { baseUrl, apiKey: nodeParams.apiKey };
13
+ }
14
+ async function handleEventByType(eventType, eventData, nodeParams) {
15
+ const operation = nodeParams.operation;
16
+ const assistant = eventData.assistant;
17
+ const chat = eventData.chat;
18
+ const message = eventData.message;
19
+ switch (operation) {
20
+ case 'sendMessage': {
21
+ const userId = (nodeParams.userId ?? eventData.user_id ?? eventData.userId);
22
+ if (!userId)
23
+ throw new Error('User ID is required. We take it from the node parameters or from the event');
24
+ if (eventType !== EventTypes_1.EventType.MESSAGE && eventType !== EventTypes_1.EventType.EDITED_MESSAGE && eventType !== EventTypes_1.EventType.VOICE_MESSAGE && eventType !== EventTypes_1.EventType.REPLY_MESSAGE) {
25
+ throw new Error(`Operation 'sendMessage' can only be used with message events. Current event type: ${eventType}`);
26
+ }
27
+ const webhookUrl = (nodeParams.webhookUrl ?? assistant?.webhookUrl ?? assistant?.webhook);
28
+ if (!webhookUrl)
29
+ throw new Error('Webhook URL is required.');
30
+ return await (0, agentWebhook_1.sendMessageToAgent)(webhookUrl, userId, eventData);
31
+ }
32
+ case 'reportCallbackResult': {
33
+ const apiOptions = getApiOptions(nodeParams);
34
+ const messageId = eventData.message_id ?? eventData.messageId;
35
+ const optionId = eventData.option_id ?? eventData.optionId;
36
+ const userId = (nodeParams.userId ?? eventData.user_id ?? eventData.userId);
37
+ const success = nodeParams.callbackSuccess !== false;
38
+ const error = (nodeParams.callbackError ?? eventData.error);
39
+ if (!messageId || !optionId || !userId)
40
+ throw new Error('message_id, option_id and user_id are required for reportCallbackResult. Use data from button_clicked event.');
41
+ return await (0, techWebhook_1.reportCallbackResult)(apiOptions, { messageId: String(messageId), optionId: String(optionId), userId, success, error });
42
+ }
43
+ case 'sendMessageBackend':
44
+ case 'sendVoiceMessageBackend':
45
+ case 'sendFileMessageBackend':
46
+ case 'sendCodeArtifactBackend':
47
+ case 'sendArticleBackend': {
48
+ const apiOptions = getApiOptions(nodeParams);
49
+ const assistantId = eventData.assistantId ?? eventData.assistant_id ?? assistant?.id;
50
+ const chatId = eventData.chatId ?? eventData.chat_id ?? chat?.id ?? message?.chatId;
51
+ const text = eventData.text ?? message?.text ?? null;
52
+ if (!assistantId || !chatId)
53
+ throw new Error('assistantId and chatId are required for send-message operations.');
54
+ return await (0, techWebhook_1.sendMessageToBackend)(apiOptions, {
55
+ assistantId: assistantId,
56
+ chatId: chatId,
57
+ sender: (eventData.sender ?? message?.sender ?? 'assistant'),
58
+ text: text,
59
+ options: (eventData.options ?? eventData.messageOptions ?? []),
60
+ files: (eventData.files ?? eventData.messageFiles ?? []),
61
+ isCode: (eventData.isCode ?? message?.isCode ?? null),
62
+ artifactCode: (eventData.artifactCode ?? message?.artifactCode ?? null),
63
+ isArticle: (eventData.isArticle ?? message?.isArticle ?? null),
64
+ articleText: (eventData.articleText ?? message?.articleText ?? null),
65
+ isAudioMessage: (eventData.isAudioMessage ?? message?.isAudioMessage ?? null),
66
+ audioData: (eventData.audioData ?? message?.audioData ?? null),
67
+ audioMimeType: (eventData.audioMimeType ?? message?.audioMimeType ?? null),
68
+ audioDuration: (eventData.audioDuration ?? message?.audioDuration ?? null),
69
+ isMixedAttachments: (eventData.isMixedAttachments ?? message?.isMixedAttachments ?? null),
70
+ });
71
+ }
72
+ case 'createAssistant': {
73
+ const userId = (nodeParams.userId ?? eventData.user_id ?? eventData.userId);
74
+ if (!userId)
75
+ throw new Error('User ID is required.');
76
+ if (eventType !== EventTypes_1.EventType.NEW_ASSISTANT)
77
+ throw new Error(`Operation 'createAssistant' can only be used with NEW_ASSISTANT event. Current event type: ${eventType}`);
78
+ if (!assistant)
79
+ throw new Error('Assistant data is required for createAssistant operation.');
80
+ const { id: _id, userId: _u, ...assistantData } = assistant;
81
+ return await (0, techWebhook_1.createAssistant)(getApiOptions(nodeParams), userId, assistantData);
82
+ }
83
+ case 'updateAssistant': {
84
+ const userId = (nodeParams.userId ?? eventData.user_id ?? eventData.userId);
85
+ if (!userId)
86
+ throw new Error('User ID is required.');
87
+ if (!assistant)
88
+ throw new Error('Assistant data is required for updateAssistant operation.');
89
+ const assistantId = eventData.assistant_id ?? assistant?.id;
90
+ if (!assistantId)
91
+ throw new Error('Assistant ID is required for updateAssistant operation.');
92
+ const { id: _id, userId: _u, ...assistantData } = assistant;
93
+ return await (0, techWebhook_1.updateAssistant)(getApiOptions(nodeParams), userId, String(assistantId), assistantData);
94
+ }
95
+ case 'deleteAssistant': {
96
+ const userId = (nodeParams.userId ?? eventData.user_id ?? eventData.userId);
97
+ if (!userId)
98
+ throw new Error('User ID is required.');
99
+ const assistantId = eventData.assistant_id ?? assistant?.id;
100
+ if (!assistantId)
101
+ throw new Error('Assistant ID is required for deleteAssistant operation.');
102
+ return await (0, techWebhook_1.deleteAssistant)(getApiOptions(nodeParams), userId, String(assistantId));
103
+ }
104
+ case 'renameChat': {
105
+ const userId = (nodeParams.userId ?? eventData.user_id ?? eventData.userId);
106
+ if (!userId)
107
+ throw new Error('User ID is required.');
108
+ if (eventType !== EventTypes_1.EventType.CHAT_RENAMED)
109
+ throw new Error(`Operation 'renameChat' can only be used with CHAT_RENAMED event. Current event type: ${eventType}`);
110
+ const chatId = eventData.chat_id ?? chat?.id;
111
+ const newName = eventData.new_name ?? chat?.title;
112
+ if (!chatId || !newName)
113
+ throw new Error('Chat ID and new name are required for renameChat operation.');
114
+ return await (0, techWebhook_1.renameChat)(getApiOptions(nodeParams), userId, String(chatId), String(newName));
115
+ }
116
+ case 'deleteChat': {
117
+ const userId = (nodeParams.userId ?? eventData.user_id ?? eventData.userId);
118
+ if (!userId)
119
+ throw new Error('User ID is required.');
120
+ const chatId = eventData.chat_id ?? chat?.id;
121
+ if (!chatId)
122
+ throw new Error('Chat ID is required for deleteChat operation.');
123
+ return await (0, techWebhook_1.deleteChat)(getApiOptions(nodeParams), userId, String(chatId));
124
+ }
125
+ case 'saveChatHistory': {
126
+ const userId = (nodeParams.userId ?? eventData.user_id ?? eventData.userId);
127
+ if (!userId)
128
+ throw new Error('User ID is required.');
129
+ if (!eventData.message && !eventData.messages)
130
+ throw new Error('Message or messages data is required for saveChatHistory operation.');
131
+ const messages = (eventData.messages ?? [eventData.message]);
132
+ return await (0, techWebhook_1.saveChatHistory)(getApiOptions(nodeParams), userId, messages);
133
+ }
134
+ default:
135
+ throw new Error(`Unsupported operation: ${operation}`);
136
+ }
137
+ }
@@ -0,0 +1,2 @@
1
+ export declare function retryWithBackoff<T>(fn: () => Promise<T>, maxRetries?: number, retryCount?: number): Promise<T>;
2
+ export declare function rateLimitedRequest<T>(fn: () => Promise<T>): Promise<T>;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.retryWithBackoff = retryWithBackoff;
7
+ exports.rateLimitedRequest = rateLimitedRequest;
8
+ const bottleneck_1 = __importDefault(require("bottleneck"));
9
+ const http_status_codes_1 = require("http-status-codes");
10
+ const limiter = new bottleneck_1.default({
11
+ reservoir: 30,
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
+ }
34
+ }
35
+ async function rateLimitedRequest(fn) {
36
+ return limiter.schedule(() => retryWithBackoff(fn));
37
+ }