@finlight/n8n-nodes-finlight 0.1.4 → 0.1.5

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.
@@ -16,151 +16,174 @@ class FinlightArticleSearch {
16
16
  inputs: [n8n_workflow_1.NodeConnectionTypes.Main],
17
17
  outputs: [n8n_workflow_1.NodeConnectionTypes.Main],
18
18
  icon: "file:../finlight.svg",
19
- credentials: [
20
- {
21
- name: "finlightApi",
22
- required: true,
23
- },
24
- ],
19
+ credentials: [{ name: "finlightApi", required: true }],
25
20
  properties: [
21
+ // ---- Operation ----
26
22
  {
27
- displayName: "Query",
28
- name: "query",
29
- type: "string",
30
- required: false,
31
- default: "",
23
+ displayName: "Operation",
24
+ name: "operation",
25
+ type: "options",
26
+ options: [
27
+ {
28
+ name: "Search Articles",
29
+ value: "search",
30
+ description: "Search articles using the finlight REST API",
31
+ action: "Search articles",
32
+ },
33
+ ],
34
+ default: "search",
32
35
  },
36
+ // ---- All optional inputs grouped ----
33
37
  {
34
- displayName: "Sources",
35
- name: "sources",
36
- type: "fixedCollection",
37
- placeholder: "Add Source",
38
+ displayName: "Additional Options",
39
+ name: "additionalOptions",
40
+ type: "collection",
41
+ placeholder: "Add option",
38
42
  default: {},
39
- typeOptions: {
40
- multipleValues: true,
41
- },
42
43
  options: [
43
44
  {
44
- name: "sourceList",
45
- displayName: "Source List",
46
- values: [
45
+ displayName: "Query",
46
+ name: "query",
47
+ type: "string",
48
+ default: "",
49
+ placeholder: "earnings OR guidance AND (NVIDIA OR ticker:NVDA)",
50
+ description: "Full-text query to filter articles",
51
+ },
52
+ {
53
+ displayName: "From (ISO date)",
54
+ name: "from",
55
+ type: "string",
56
+ default: "",
57
+ description: "Start of date range, e.g. 2025-09-01T00:00:00Z",
58
+ },
59
+ {
60
+ displayName: "To (ISO date)",
61
+ name: "to",
62
+ type: "string",
63
+ default: "",
64
+ description: "End of date range, e.g. 2025-09-06T23:59:59Z",
65
+ },
66
+ {
67
+ displayName: "Sources",
68
+ name: "sources",
69
+ type: "fixedCollection",
70
+ placeholder: "Add Source",
71
+ default: {},
72
+ typeOptions: { multipleValues: true },
73
+ options: [
47
74
  {
48
- displayName: "Source",
49
- name: "source",
50
- type: "string",
51
- default: "",
75
+ name: "sourceList",
76
+ displayName: "Source List",
77
+ values: [
78
+ {
79
+ displayName: "Source",
80
+ name: "source",
81
+ type: "string",
82
+ default: "",
83
+ placeholder: "reuters.com",
84
+ },
85
+ ],
52
86
  },
53
87
  ],
54
88
  },
55
- ],
56
- },
57
- {
58
- displayName: "Exclude Sources",
59
- name: "excludeSources",
60
- type: "fixedCollection",
61
- placeholder: "Exclude Source",
62
- default: {},
63
- typeOptions: {
64
- multipleValues: true,
65
- },
66
- options: [
67
89
  {
68
- name: "sourceList",
69
- displayName: "Source List",
70
- values: [
90
+ displayName: "Exclude Sources",
91
+ name: "excludeSources",
92
+ type: "fixedCollection",
93
+ placeholder: "Exclude Source",
94
+ default: {},
95
+ typeOptions: { multipleValues: true },
96
+ options: [
71
97
  {
72
- displayName: "Source",
73
- name: "source",
74
- type: "string",
75
- default: "",
98
+ name: "sourceList",
99
+ displayName: "Source List",
100
+ values: [
101
+ {
102
+ displayName: "Source",
103
+ name: "source",
104
+ type: "string",
105
+ default: "",
106
+ placeholder: "example.com",
107
+ },
108
+ ],
76
109
  },
77
110
  ],
78
111
  },
79
- ],
80
- },
81
- {
82
- displayName: "From (ISO date)",
83
- name: "from",
84
- type: "string",
85
- default: "",
86
- },
87
- {
88
- displayName: "To (ISO date)",
89
- name: "to",
90
- type: "string",
91
- default: "",
92
- },
93
- {
94
- displayName: "Language",
95
- name: "language",
96
- type: "string",
97
- default: "en",
98
- },
99
- {
100
- displayName: "Order",
101
- name: "order",
102
- type: "options",
103
- options: [
104
- { name: "DESC", value: "DESC" },
105
- { name: "ASC", value: "ASC" },
106
- ],
107
- default: "DESC",
108
- },
109
- {
110
- displayName: "Page Size",
111
- name: "pageSize",
112
- type: "number",
113
- default: 20,
114
- typeOptions: { minValue: 1, maxValue: 100 },
115
- },
116
- {
117
- displayName: "Page",
118
- name: "page",
119
- type: "number",
120
- default: 1,
121
- typeOptions: { minValue: 1 },
122
- },
123
- {
124
- displayName: "Include Content",
125
- name: "includeContent",
126
- type: "boolean",
127
- default: false,
128
- },
129
- {
130
- displayName: "Include Entities",
131
- name: "includeEntities",
132
- type: "boolean",
133
- default: false,
134
- },
135
- {
136
- displayName: "Exclude Empty Content",
137
- name: "excludeEmptyContent",
138
- type: "boolean",
139
- default: false,
140
- },
141
- {
142
- displayName: "Tickers",
143
- name: "tickers",
144
- type: "fixedCollection",
145
- placeholder: "Add Ticker",
146
- default: {},
147
- typeOptions: {
148
- multipleValues: true,
149
- },
150
- options: [
151
112
  {
152
- name: "tickerList",
153
- displayName: "Ticker List",
154
- values: [
113
+ displayName: "Tickers",
114
+ name: "tickers",
115
+ type: "fixedCollection",
116
+ placeholder: "Add Ticker",
117
+ default: {},
118
+ typeOptions: { multipleValues: true },
119
+ options: [
155
120
  {
156
- displayName: "Ticker",
157
- name: "ticker",
158
- type: "string",
159
- default: "",
121
+ name: "tickerList",
122
+ displayName: "Ticker List",
123
+ values: [
124
+ {
125
+ displayName: "Ticker",
126
+ name: "ticker",
127
+ type: "string",
128
+ default: "",
129
+ placeholder: "AAPL",
130
+ },
131
+ ],
160
132
  },
161
133
  ],
162
134
  },
135
+ {
136
+ displayName: "Language",
137
+ name: "language",
138
+ type: "string",
139
+ default: "en",
140
+ },
141
+ {
142
+ displayName: "Order",
143
+ name: "order",
144
+ type: "options",
145
+ options: [
146
+ { name: "DESC", value: "DESC" },
147
+ { name: "ASC", value: "ASC" },
148
+ ],
149
+ default: "DESC",
150
+ },
151
+ {
152
+ displayName: "Page Size",
153
+ name: "pageSize",
154
+ type: "number",
155
+ default: 20,
156
+ typeOptions: { minValue: 1, maxValue: 100 },
157
+ },
158
+ {
159
+ displayName: "Page",
160
+ name: "page",
161
+ type: "number",
162
+ default: 1,
163
+ typeOptions: { minValue: 1 },
164
+ },
165
+ {
166
+ displayName: "Include Content",
167
+ name: "includeContent",
168
+ type: "boolean",
169
+ default: false,
170
+ },
171
+ {
172
+ displayName: "Include Entities",
173
+ name: "includeEntities",
174
+ type: "boolean",
175
+ default: false,
176
+ },
177
+ {
178
+ displayName: "Exclude Empty Content",
179
+ name: "excludeEmptyContent",
180
+ type: "boolean",
181
+ default: false,
182
+ },
163
183
  ],
184
+ displayOptions: {
185
+ show: { operation: ["search"] },
186
+ },
164
187
  },
165
188
  ],
166
189
  };
@@ -170,35 +193,45 @@ class FinlightArticleSearch {
170
193
  const returnData = [];
171
194
  const apiKey = (await this.getCredentials("finlightApi"));
172
195
  for (let i = 0; i < items.length; i++) {
196
+ const operation = this.getNodeParameter("operation", i);
197
+ if (operation !== "search") {
198
+ throw new Error(`Unknown operation: ${operation}`);
199
+ }
200
+ // Build the body from optional collection only
201
+ const additional = (this.getNodeParameter("additionalOptions", i, {}) || {});
173
202
  const body = {};
174
- const query = this.getNodeParameter("query", i);
175
- if (query)
176
- body.query = query;
177
- const from = this.getNodeParameter("from", i);
178
- if (from)
179
- body.from = from;
180
- const to = this.getNodeParameter("to", i);
181
- if (to)
182
- body.to = to;
183
- const sourcesRaw = this.getNodeParameter("sources.sourceList", i, []);
184
- if (sourcesRaw.length) {
203
+ if (additional.query)
204
+ body.query = additional.query;
205
+ if (additional.from)
206
+ body.from = additional.from;
207
+ if (additional.to)
208
+ body.to = additional.to;
209
+ const sourcesRaw = additional.sources?.sourceList || [];
210
+ if (sourcesRaw.length)
185
211
  body.sources = sourcesRaw.map(s => s.source);
186
- }
187
- const excludeSourcesRaw = this.getNodeParameter("excludeSources.sourceList", i, []);
188
- if (excludeSourcesRaw.length) {
212
+ const excludeSourcesRaw = additional.excludeSources?.sourceList || [];
213
+ if (excludeSourcesRaw.length)
189
214
  body.excludeSources = excludeSourcesRaw.map(s => s.source);
190
- }
191
- const tickersRaw = this.getNodeParameter("tickers.tickerList", i, []);
192
- if (tickersRaw.length) {
215
+ const tickersRaw = additional.tickers?.tickerList || [];
216
+ if (tickersRaw.length)
193
217
  body.tickers = tickersRaw.map(t => t.ticker);
194
- }
195
- body.language = this.getNodeParameter("language", i);
196
- body.order = this.getNodeParameter("order", i);
197
- body.pageSize = this.getNodeParameter("pageSize", i);
198
- body.page = this.getNodeParameter("page", i);
199
- body.includeContent = this.getNodeParameter("includeContent", i);
200
- body.includeEntities = this.getNodeParameter("includeEntities", i);
201
- body.excludeEmptyContent = this.getNodeParameter("excludeEmptyContent", i);
218
+ // Defaults if not provided (harmless if user leaves everything empty)
219
+ body.language = additional.language !== undefined ? additional.language : "en";
220
+ body.order = additional.order !== undefined ? additional.order : "DESC";
221
+ body.pageSize = additional.pageSize !== undefined ? Number(additional.pageSize) : 20;
222
+ body.page = additional.page !== undefined ? Number(additional.page) : 1;
223
+ if (typeof additional.includeContent === "boolean")
224
+ body.includeContent = additional.includeContent;
225
+ else
226
+ body.includeContent = false;
227
+ if (typeof additional.includeEntities === "boolean")
228
+ body.includeEntities = additional.includeEntities;
229
+ else
230
+ body.includeEntities = false;
231
+ if (typeof additional.excludeEmptyContent === "boolean")
232
+ body.excludeEmptyContent = additional.excludeEmptyContent;
233
+ else
234
+ body.excludeEmptyContent = false;
202
235
  const response = await this.helpers.httpRequest({
203
236
  method: "POST",
204
237
  url: "https://api.finlight.me/v2/articles",
@@ -209,7 +242,7 @@ class FinlightArticleSearch {
209
242
  body,
210
243
  json: true,
211
244
  });
212
- returnData.push(...(Array.isArray(response.articles) ? response.articles : [response]));
245
+ returnData.push(...(Array.isArray(response?.articles) ? response.articles : [response]));
213
246
  }
214
247
  return [this.helpers.returnJsonArray(returnData)];
215
248
  }
@@ -9,7 +9,7 @@ class FinlightApi {
9
9
  {
10
10
  displayName: "API Key",
11
11
  name: "apiKey",
12
- type: "string",
12
+ type: "credentials",
13
13
  default: "",
14
14
  },
15
15
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finlight/n8n-nodes-finlight",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Official n8n integration for finlight: real-time finance and news API",
5
5
  "author": {
6
6
  "name": "Ali Büyükkakac",
@@ -28,7 +28,6 @@
28
28
  "@typescript-eslint/parser": "^8.38.0",
29
29
  "eslint": "^9.32.0",
30
30
  "eslint-plugin-n8n-nodes-base": "^1.16.3",
31
- "n8n-core": "^1.14.1",
32
31
  "jest": "^29.4.0",
33
32
  "n8n-workflow": "*",
34
33
  "ts-jest": "^29.4.0",