@comandosai/n8n-nodes-rss-bridge 0.1.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/README.md +62 -0
- package/RSS.svg +6 -0
- package/RSSS.png +0 -0
- package/credentials/ComandosApi.credentials.ts +19 -0
- package/dist/credentials/ComandosApi.credentials.d.ts +7 -0
- package/dist/credentials/ComandosApi.credentials.js +23 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +7 -0
- package/dist/nodes/ComandosRssBridge.node.d.ts +5 -0
- package/dist/nodes/ComandosRssBridge.node.js +171 -0
- package/dist/nodes/RSSS.png +0 -0
- package/index.ts +4 -0
- package/nodes/ComandosRssBridge.node.ts +195 -0
- package/package.json +27 -0
- package/tsconfig.json +15 -0
package/README.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Commandos RSS (кастомная нода n8n)
|
|
2
|
+
|
|
3
|
+
Нода выполняет два последовательных запроса в Commandos API: `detect`, затем `collect`.
|
|
4
|
+
Оба запроса должны работать синхронно через вебхук `comandos_rss`.
|
|
5
|
+
|
|
6
|
+
## Где находится
|
|
7
|
+
|
|
8
|
+
- Код ноды: `/root/sandbox/nodes/rss-bridge`
|
|
9
|
+
- Пакет: `@comandosai/n8n-nodes-rss-bridge`
|
|
10
|
+
|
|
11
|
+
## Требования
|
|
12
|
+
|
|
13
|
+
- n8n (dev окружение)
|
|
14
|
+
- Node.js 18+
|
|
15
|
+
- Доступ к Commandos API (`https://api.comandos.ai`)
|
|
16
|
+
- `RSS_BRIDGE` включён в `SYNC_PROCESS_TYPES` на API (иначе API вернёт `taskId` вместо ответа).
|
|
17
|
+
|
|
18
|
+
## Доступ
|
|
19
|
+
|
|
20
|
+
Нода работает только через Commandos API и требует лицензионный ключ.
|
|
21
|
+
Без ключа запросы не будут выполнены.
|
|
22
|
+
|
|
23
|
+
## Подключение в n8n-dev
|
|
24
|
+
|
|
25
|
+
В `docker-compose` уже настроено:
|
|
26
|
+
|
|
27
|
+
- монтирование `/root/sandbox/nodes` в `/custom/commandos`
|
|
28
|
+
- переменная `N8N_CUSTOM_EXTENSIONS=/custom/commandos`
|
|
29
|
+
|
|
30
|
+
После изменений перезапусти n8n.
|
|
31
|
+
|
|
32
|
+
## Credentials
|
|
33
|
+
|
|
34
|
+
Тип: `Commandos API`
|
|
35
|
+
|
|
36
|
+
Поля:
|
|
37
|
+
- `License Key` — передаётся как `X-License-Key` в API
|
|
38
|
+
|
|
39
|
+
## Параметры
|
|
40
|
+
|
|
41
|
+
- `URL список` — строка с URL, разделители: перенос строки, запятая, точка с запятой
|
|
42
|
+
- `Период` — `Часы` или `Дни`
|
|
43
|
+
- `Значение периода (0-100)` — 0 отключает фильтрацию
|
|
44
|
+
- `Точка отсчета (ISO, опционально)` — если не задано, используется текущее время сервера
|
|
45
|
+
|
|
46
|
+
## Выход
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"detect": { ... },
|
|
51
|
+
"collect": { ... }
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Сборка
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npm install
|
|
59
|
+
npm run build
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
После сборки перезапусти n8n, чтобы нода появилась в списке.
|
package/RSS.svg
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128">
|
|
2
|
+
<rect width="128" height="128" rx="16" fill="#ff8a00" />
|
|
3
|
+
<circle cx="32" cy="96" r="10" fill="#ffffff" />
|
|
4
|
+
<path d="M24 68a36 36 0 0 1 36 36" fill="none" stroke="#ffffff" stroke-width="12" stroke-linecap="round" />
|
|
5
|
+
<path d="M24 44a60 60 0 0 1 60 60" fill="none" stroke="#ffffff" stroke-width="12" stroke-linecap="round" />
|
|
6
|
+
</svg>
|
package/RSSS.png
ADDED
|
Binary file
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
|
2
|
+
|
|
3
|
+
export class ComandosApi implements ICredentialType {
|
|
4
|
+
name = 'comandosApi';
|
|
5
|
+
displayName = 'Comandos API';
|
|
6
|
+
documentationUrl = 'https://api.comandos.ai';
|
|
7
|
+
properties: INodeProperties[] = [
|
|
8
|
+
{
|
|
9
|
+
displayName: 'License Key',
|
|
10
|
+
name: 'licenseKey',
|
|
11
|
+
type: 'string',
|
|
12
|
+
default: '',
|
|
13
|
+
required: true,
|
|
14
|
+
typeOptions: {
|
|
15
|
+
password: true,
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
];
|
|
19
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ComandosApi = void 0;
|
|
4
|
+
class ComandosApi {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.name = 'comandosApi';
|
|
7
|
+
this.displayName = 'Comandos API';
|
|
8
|
+
this.documentationUrl = 'https://api.comandos.ai';
|
|
9
|
+
this.properties = [
|
|
10
|
+
{
|
|
11
|
+
displayName: 'License Key',
|
|
12
|
+
name: 'licenseKey',
|
|
13
|
+
type: 'string',
|
|
14
|
+
default: '',
|
|
15
|
+
required: true,
|
|
16
|
+
typeOptions: {
|
|
17
|
+
password: true,
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.ComandosApi = ComandosApi;
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ComandosApi = exports.ComandosRssBridge = void 0;
|
|
4
|
+
const ComandosRssBridge_node_1 = require("./nodes/ComandosRssBridge.node");
|
|
5
|
+
Object.defineProperty(exports, "ComandosRssBridge", { enumerable: true, get: function () { return ComandosRssBridge_node_1.ComandosRssBridge; } });
|
|
6
|
+
const ComandosApi_credentials_1 = require("./credentials/ComandosApi.credentials");
|
|
7
|
+
Object.defineProperty(exports, "ComandosApi", { enumerable: true, get: function () { return ComandosApi_credentials_1.ComandosApi; } });
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
|
|
2
|
+
export declare class ComandosRssBridge implements INodeType {
|
|
3
|
+
description: INodeTypeDescription;
|
|
4
|
+
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
5
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ComandosRssBridge = void 0;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const COMANDOS_API_URL = String(process.env.COMANDOS_API_BASE_URL || process.env.COMMANDOS_API_BASE_URL || "https://api.comandos.ai").trim();
|
|
6
|
+
const splitUrls = (raw) => raw
|
|
7
|
+
.split(/[\n,;]+/)
|
|
8
|
+
.map((entry) => entry.trim())
|
|
9
|
+
.filter((entry) => entry.length > 0);
|
|
10
|
+
const normalizeUrls = (value) => {
|
|
11
|
+
if (Array.isArray(value)) {
|
|
12
|
+
return value.map((entry) => String(entry || '').trim()).filter((entry) => entry.length > 0);
|
|
13
|
+
}
|
|
14
|
+
if (typeof value === 'string') {
|
|
15
|
+
return splitUrls(value);
|
|
16
|
+
}
|
|
17
|
+
return [];
|
|
18
|
+
};
|
|
19
|
+
const normalizeSinceValue = (value, itemIndex, node) => {
|
|
20
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
const raw = String(value || '').trim();
|
|
24
|
+
if (raw === '') {
|
|
25
|
+
return 0;
|
|
26
|
+
}
|
|
27
|
+
if (!/^\d+$/.test(raw)) {
|
|
28
|
+
throw new n8n_workflow_1.NodeOperationError(node.getNode(), 'Значение периода должно быть числом', {
|
|
29
|
+
itemIndex,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
return Number(raw);
|
|
33
|
+
};
|
|
34
|
+
class ComandosRssBridge {
|
|
35
|
+
constructor() {
|
|
36
|
+
this.description = {
|
|
37
|
+
displayName: 'Comandos RSS',
|
|
38
|
+
name: 'comandosRssBridge',
|
|
39
|
+
group: ['transform'],
|
|
40
|
+
version: 1,
|
|
41
|
+
description: 'Последовательные запросы detect + collect через Comandos API',
|
|
42
|
+
defaults: {
|
|
43
|
+
name: 'Comandos RSS',
|
|
44
|
+
},
|
|
45
|
+
icon: 'file:RSSS.png',
|
|
46
|
+
inputs: ['main'],
|
|
47
|
+
outputs: ['main'],
|
|
48
|
+
credentials: [
|
|
49
|
+
{
|
|
50
|
+
name: 'comandosApi',
|
|
51
|
+
required: true,
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
properties: [
|
|
55
|
+
{
|
|
56
|
+
displayName: 'URL список',
|
|
57
|
+
name: 'urls',
|
|
58
|
+
type: 'string',
|
|
59
|
+
default: '',
|
|
60
|
+
placeholder: 'https://t.me/ai_comandos\nhttps://www.youtube.com/@kokorevinvest',
|
|
61
|
+
typeOptions: {
|
|
62
|
+
rows: 6,
|
|
63
|
+
},
|
|
64
|
+
description: 'URL можно разделять переносом строки, запятой или точкой с запятой',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
displayName: 'Период',
|
|
68
|
+
name: 'sinceUnit',
|
|
69
|
+
type: 'options',
|
|
70
|
+
options: [
|
|
71
|
+
{ name: 'Часы', value: 'hours' },
|
|
72
|
+
{ name: 'Дни', value: 'days' },
|
|
73
|
+
],
|
|
74
|
+
default: 'days',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
displayName: 'Значение периода (0-100)',
|
|
78
|
+
name: 'sinceValue',
|
|
79
|
+
type: 'number',
|
|
80
|
+
default: 5,
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
displayName: 'Точка отсчета (ISO, опционально)',
|
|
84
|
+
name: 'now',
|
|
85
|
+
type: 'string',
|
|
86
|
+
default: '',
|
|
87
|
+
placeholder: '2026-01-03T12:00:00+00:00',
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
async execute() {
|
|
93
|
+
const items = this.getInputData();
|
|
94
|
+
const credentials = await this.getCredentials('comandosApi');
|
|
95
|
+
const licenseKey = String(credentials.licenseKey || '').trim();
|
|
96
|
+
if (!licenseKey) {
|
|
97
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Лицензионный ключ обязателен');
|
|
98
|
+
}
|
|
99
|
+
const results = [];
|
|
100
|
+
for (let i = 0; i < items.length; i += 1) {
|
|
101
|
+
const rawUrls = this.getNodeParameter('urls', i);
|
|
102
|
+
const sinceUnit = String(this.getNodeParameter('sinceUnit', i) || 'days');
|
|
103
|
+
const sinceValue = normalizeSinceValue(this.getNodeParameter('sinceValue', i), i, this);
|
|
104
|
+
const now = String(this.getNodeParameter('now', i) || '').trim();
|
|
105
|
+
const urls = normalizeUrls(rawUrls);
|
|
106
|
+
if (urls.length === 0) {
|
|
107
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Нужно указать хотя бы один URL', {
|
|
108
|
+
itemIndex: i,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
if (sinceValue < 0 || sinceValue > 100) {
|
|
112
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Значение периода должно быть в диапазоне 0-100', {
|
|
113
|
+
itemIndex: i,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
const detectResponse = await this.helpers.request({
|
|
117
|
+
method: 'POST',
|
|
118
|
+
url: `${COMANDOS_API_URL}/tasks`,
|
|
119
|
+
json: true,
|
|
120
|
+
headers: {
|
|
121
|
+
'Content-Type': 'application/json',
|
|
122
|
+
'X-License-Key': licenseKey,
|
|
123
|
+
},
|
|
124
|
+
body: {
|
|
125
|
+
process_type: 'RSS_BRIDGE',
|
|
126
|
+
payload: {
|
|
127
|
+
action: 'detect',
|
|
128
|
+
urls,
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
if (detectResponse && detectResponse.taskId) {
|
|
133
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'RSS_BRIDGE должен работать синхронно. Добавьте RSS_BRIDGE в SYNC_PROCESS_TYPES на API.', { itemIndex: i });
|
|
134
|
+
}
|
|
135
|
+
const detections = Array.isArray(detectResponse === null || detectResponse === void 0 ? void 0 : detectResponse.detections)
|
|
136
|
+
? detectResponse.detections
|
|
137
|
+
: [];
|
|
138
|
+
const collectPayload = {
|
|
139
|
+
action: 'collect',
|
|
140
|
+
urls,
|
|
141
|
+
detections,
|
|
142
|
+
since_value: sinceValue,
|
|
143
|
+
since_unit: sinceUnit,
|
|
144
|
+
};
|
|
145
|
+
if (now) {
|
|
146
|
+
collectPayload.now = now;
|
|
147
|
+
}
|
|
148
|
+
const collectResponse = await this.helpers.request({
|
|
149
|
+
method: 'POST',
|
|
150
|
+
url: `${COMANDOS_API_URL}/tasks`,
|
|
151
|
+
json: true,
|
|
152
|
+
headers: {
|
|
153
|
+
'Content-Type': 'application/json',
|
|
154
|
+
'X-License-Key': licenseKey,
|
|
155
|
+
},
|
|
156
|
+
body: {
|
|
157
|
+
process_type: 'RSS_BRIDGE',
|
|
158
|
+
payload: collectPayload,
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
results.push({
|
|
162
|
+
json: {
|
|
163
|
+
detect: detectResponse,
|
|
164
|
+
collect: collectResponse,
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
return [results];
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
exports.ComandosRssBridge = ComandosRssBridge;
|
|
Binary file
|
package/index.ts
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
IDataObject,
|
|
3
|
+
IExecuteFunctions,
|
|
4
|
+
INodeExecutionData,
|
|
5
|
+
INodeType,
|
|
6
|
+
INodeTypeDescription,
|
|
7
|
+
} from 'n8n-workflow';
|
|
8
|
+
import { NodeOperationError } from 'n8n-workflow';
|
|
9
|
+
|
|
10
|
+
const COMANDOS_API_URL = String(process.env.COMANDOS_API_BASE_URL || process.env.COMMANDOS_API_BASE_URL || "https://api.comandos.ai").trim();
|
|
11
|
+
|
|
12
|
+
const splitUrls = (raw: string): string[] =>
|
|
13
|
+
raw
|
|
14
|
+
.split(/[\n,;]+/)
|
|
15
|
+
.map((entry) => entry.trim())
|
|
16
|
+
.filter((entry) => entry.length > 0);
|
|
17
|
+
|
|
18
|
+
const normalizeUrls = (value: unknown): string[] => {
|
|
19
|
+
if (Array.isArray(value)) {
|
|
20
|
+
return value.map((entry) => String(entry || '').trim()).filter((entry) => entry.length > 0);
|
|
21
|
+
}
|
|
22
|
+
if (typeof value === 'string') {
|
|
23
|
+
return splitUrls(value);
|
|
24
|
+
}
|
|
25
|
+
return [];
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const normalizeSinceValue = (value: unknown, itemIndex: number, node: IExecuteFunctions): number => {
|
|
29
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
const raw = String(value || '').trim();
|
|
33
|
+
if (raw === '') {
|
|
34
|
+
return 0;
|
|
35
|
+
}
|
|
36
|
+
if (!/^\d+$/.test(raw)) {
|
|
37
|
+
throw new NodeOperationError(node.getNode(), 'Значение периода должно быть числом', {
|
|
38
|
+
itemIndex,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
return Number(raw);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export class ComandosRssBridge implements INodeType {
|
|
45
|
+
description: INodeTypeDescription = {
|
|
46
|
+
displayName: 'Comandos RSS',
|
|
47
|
+
name: 'comandosRssBridge',
|
|
48
|
+
group: ['transform'],
|
|
49
|
+
version: 1,
|
|
50
|
+
description: 'Последовательные запросы detect + collect через Comandos API',
|
|
51
|
+
defaults: {
|
|
52
|
+
name: 'Comandos RSS',
|
|
53
|
+
},
|
|
54
|
+
icon: 'file:RSSS.png',
|
|
55
|
+
inputs: ['main'],
|
|
56
|
+
outputs: ['main'],
|
|
57
|
+
credentials: [
|
|
58
|
+
{
|
|
59
|
+
name: 'comandosApi',
|
|
60
|
+
required: true,
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
properties: [
|
|
64
|
+
{
|
|
65
|
+
displayName: 'URL список',
|
|
66
|
+
name: 'urls',
|
|
67
|
+
type: 'string',
|
|
68
|
+
default: '',
|
|
69
|
+
placeholder: 'https://t.me/ai_comandos\nhttps://www.youtube.com/@kokorevinvest',
|
|
70
|
+
typeOptions: {
|
|
71
|
+
rows: 6,
|
|
72
|
+
},
|
|
73
|
+
description: 'URL можно разделять переносом строки, запятой или точкой с запятой',
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
displayName: 'Период',
|
|
77
|
+
name: 'sinceUnit',
|
|
78
|
+
type: 'options',
|
|
79
|
+
options: [
|
|
80
|
+
{ name: 'Часы', value: 'hours' },
|
|
81
|
+
{ name: 'Дни', value: 'days' },
|
|
82
|
+
],
|
|
83
|
+
default: 'days',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
displayName: 'Значение периода (0-100)',
|
|
87
|
+
name: 'sinceValue',
|
|
88
|
+
type: 'number',
|
|
89
|
+
default: 5,
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
displayName: 'Точка отсчета (ISO, опционально)',
|
|
93
|
+
name: 'now',
|
|
94
|
+
type: 'string',
|
|
95
|
+
default: '',
|
|
96
|
+
placeholder: '2026-01-03T12:00:00+00:00',
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
|
102
|
+
const items = this.getInputData();
|
|
103
|
+
const credentials = await this.getCredentials('comandosApi');
|
|
104
|
+
const licenseKey = String(credentials.licenseKey || '').trim();
|
|
105
|
+
|
|
106
|
+
if (!licenseKey) {
|
|
107
|
+
throw new NodeOperationError(this.getNode(), 'Лицензионный ключ обязателен');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const results: INodeExecutionData[] = [];
|
|
111
|
+
|
|
112
|
+
for (let i = 0; i < items.length; i += 1) {
|
|
113
|
+
const rawUrls = this.getNodeParameter('urls', i);
|
|
114
|
+
const sinceUnit = String(this.getNodeParameter('sinceUnit', i) || 'days');
|
|
115
|
+
const sinceValue = normalizeSinceValue(this.getNodeParameter('sinceValue', i), i, this);
|
|
116
|
+
const now = String(this.getNodeParameter('now', i) || '').trim();
|
|
117
|
+
const urls = normalizeUrls(rawUrls);
|
|
118
|
+
|
|
119
|
+
if (urls.length === 0) {
|
|
120
|
+
throw new NodeOperationError(this.getNode(), 'Нужно указать хотя бы один URL', {
|
|
121
|
+
itemIndex: i,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
if (sinceValue < 0 || sinceValue > 100) {
|
|
125
|
+
throw new NodeOperationError(this.getNode(), 'Значение периода должно быть в диапазоне 0-100', {
|
|
126
|
+
itemIndex: i,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const detectResponse = await this.helpers.request({
|
|
131
|
+
method: 'POST',
|
|
132
|
+
url: `${COMANDOS_API_URL}/tasks`,
|
|
133
|
+
json: true,
|
|
134
|
+
headers: {
|
|
135
|
+
'Content-Type': 'application/json',
|
|
136
|
+
'X-License-Key': licenseKey,
|
|
137
|
+
},
|
|
138
|
+
body: {
|
|
139
|
+
process_type: 'RSS_BRIDGE',
|
|
140
|
+
payload: {
|
|
141
|
+
action: 'detect',
|
|
142
|
+
urls,
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
if (detectResponse && (detectResponse as IDataObject).taskId) {
|
|
148
|
+
throw new NodeOperationError(
|
|
149
|
+
this.getNode(),
|
|
150
|
+
'RSS_BRIDGE должен работать синхронно. Добавьте RSS_BRIDGE в SYNC_PROCESS_TYPES на API.',
|
|
151
|
+
{ itemIndex: i },
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const detections = Array.isArray((detectResponse as IDataObject)?.detections)
|
|
156
|
+
? ((detectResponse as IDataObject).detections as IDataObject[])
|
|
157
|
+
: [];
|
|
158
|
+
|
|
159
|
+
const collectPayload: IDataObject = {
|
|
160
|
+
action: 'collect',
|
|
161
|
+
urls,
|
|
162
|
+
detections,
|
|
163
|
+
since_value: sinceValue,
|
|
164
|
+
since_unit: sinceUnit,
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
if (now) {
|
|
168
|
+
collectPayload.now = now;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const collectResponse = await this.helpers.request({
|
|
172
|
+
method: 'POST',
|
|
173
|
+
url: `${COMANDOS_API_URL}/tasks`,
|
|
174
|
+
json: true,
|
|
175
|
+
headers: {
|
|
176
|
+
'Content-Type': 'application/json',
|
|
177
|
+
'X-License-Key': licenseKey,
|
|
178
|
+
},
|
|
179
|
+
body: {
|
|
180
|
+
process_type: 'RSS_BRIDGE',
|
|
181
|
+
payload: collectPayload,
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
results.push({
|
|
186
|
+
json: {
|
|
187
|
+
detect: detectResponse as IDataObject,
|
|
188
|
+
collect: collectResponse as IDataObject,
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return [results];
|
|
194
|
+
}
|
|
195
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@comandosai/n8n-nodes-rss-bridge",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Comandos RSS Bridge custom node",
|
|
5
|
+
"author": "Comandos AI",
|
|
6
|
+
"license": "UNLICENSED",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc -p tsconfig.json && mkdir -p dist/nodes && cp -f RSSS.png dist/nodes/"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"n8n-workflow": "^1.0.0"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@types/node": "^18.19.0",
|
|
17
|
+
"typescript": "^5.4.5"
|
|
18
|
+
},
|
|
19
|
+
"n8n": {
|
|
20
|
+
"nodes": [
|
|
21
|
+
"dist/nodes/ComandosRssBridge.node.js"
|
|
22
|
+
],
|
|
23
|
+
"credentials": [
|
|
24
|
+
"dist/credentials/ComandosApi.credentials.js"
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2019",
|
|
4
|
+
"module": "CommonJS",
|
|
5
|
+
"lib": ["ES2019"],
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"rootDir": ".",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"resolveJsonModule": true,
|
|
12
|
+
"skipLibCheck": true
|
|
13
|
+
},
|
|
14
|
+
"include": ["nodes/**/*.ts", "credentials/**/*.ts", "index.ts"]
|
|
15
|
+
}
|