n8n-nodes-apivault-tech-stack-lookup 0.2.0 → 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.
package/README.md CHANGED
@@ -1,61 +1,11 @@
1
- # n8n-nodes-apivault-tech-stack-lookup
1
+ # BuiltWith Alternative — Tech Stack Leads & Lookup (60M) — n8n node
2
2
 
3
- An [n8n](https://n8n.io) community node for **BuiltWith Alternative — Tech Stack Leads & Lookup (60M)**, powered by the [`apivault_labs/tech-stack-lookup` Apify Actor](https://apify.com/apivault_labs/tech-stack-lookup).
3
+ Calls the hosted [Apify Actor](https://apify.com/apivault_labs/tech-stack-lookup). Requires your own Apify credential; Apify run charges apply.
4
4
 
5
- Technology leads and tech stack lookup across 60M+ websites. BuiltWith alternative to find websites by technology, check domains, discover Shopify and Klaviyo leads, build lookalike audiences and monitor stack changes. AI/MCP-ready output for B2B sales.
5
+ Install `n8n-nodes-apivault-tech-stack-lookup` through Settings → Community nodes → Install in self-hosted n8n.
6
6
 
7
- The node is a thin connector: collection, analysis, retries and billing run in the hosted Actor. It contains no private scraper implementation or embedded credentials.
7
+ ## Upgrade compatibility
8
8
 
9
- ## Installation
9
+ Existing node names, credential type and input parameter names are retained. Existing version 1 workflows keep their previous charge behavior unless an event cap is selected. New version 2 nodes default to a $0.05 event charge cap and 1,000 downloaded rows; platform usage can be charged separately. Select Read Existing Run and provide the Run ID to resume without starting a paid duplicate. Full output includes run metadata, SUMMARY and ERRORS when available. Dataset rows retain their original fields and paired input item. Actor build is latest.
10
10
 
11
- 1. Open **Settings → Community Nodes** in your n8n instance.
12
- 2. Select **Install**.
13
- 3. Enter `n8n-nodes-apivault-tech-stack-lookup` and confirm.
14
-
15
- ## Credentials
16
-
17
- Create an **Apify API** credential in n8n and paste your personal token from [Apify Console → Integrations](https://console.apify.com/account/integrations). The token is sent to Apify as a bearer credential and is never bundled with this package.
18
-
19
- ## Usage
20
-
21
- Add **BuiltWith Alternative — Tech Stack Leads & Lookup (60M)** to a workflow, fill the public Actor inputs below, and execute the node. Every Dataset result becomes one n8n item, so it can flow into Sheets, databases, CRMs, alerts or your own code. The node respects n8n's **Continue On Fail** behavior.
22
-
23
- | Input | Type | Description |
24
- |---|---|---|
25
- | `mode` | `string` | find requires technologies, technologyPreset or opportunityPreset; detect requires domains; lookalike requires seed domains; monitor requires domains and a stable monitorName; cata |
26
- | `domains` | `array` | Required when mode is detect, lookalike or monitor; ignored otherwise. Accepts hostnames or URLs. Unknown domains are skipped without a result charge. |
27
- | `technologyPreset` | `string` | Used only when mode=find. Optional shortcut combined with custom Technologies. |
28
- | `opportunityPreset` | `string` | Used only when mode=find. Returns matching leads, missing technology, opportunity score and suggested pitch. |
29
- | `technologies` | `array` | Used only when mode=find. Enter complete product names such as Klaviyo, Stripe, Shopify Plus, HubSpot or Cloudflare. AI agents should prefer technologyPreset for one popular techno |
30
- | `matchMode` | `string` | Used only when mode=find. any = at least one technology (OR); all = every technology (AND). |
31
- | `excludeTechnologies` | `array` | Used only when mode=find. Exclude sites using any listed technology; e.g. Klaviyo leads without Yotpo. |
32
- | `category` | `string` | Used only when mode=find. Limit matching to one stack layer; any is recommended because a product may appear in multiple layers. |
33
- | `country` | `array` | One or more ISO-2 country codes, e.g. US, DE, GB. Type each code and press Enter. Empty — no country filter. |
34
- | `vertical` | `string` | Keep only sites in this industry, e.g. Fashion, Technology, Health, or Food. Leave empty to include every industry. |
35
- | `hasEmail` | `boolean` | Keep only sites where the Emails field is not empty. |
36
- | `hasPhone` | `boolean` | Keep only sites where the Telephones field is not empty. |
37
- | `newWithinDays` | `integer` | Return websites first added to the index within the last N days. Use 7 for a weekly new-lead feed. Set 0 to disable. |
38
- | `lastIndexedWithinDays` | `integer` | Keep websites whose record was indexed within the last N days. Useful for recently refreshed data. Set 0 to disable. |
39
- | `lastFoundWithinDays` | `integer` | Keep websites last observed within the previous N days. Use this to prefer recently confirmed leads. Set 0 to disable. |
40
- | `sortBy` | `string` | Order rows by this column before applying the limit, so you get the top leads instead of an arbitrary slice. Empty — no ordering. |
41
- | `sortDesc` | `boolean` | Highest values first (recommended for scores/traffic/revenue). |
42
- | `dedupeByDomain` | `boolean` | Return each normalized Root Domain only once across all data segments. Recommended for lead exports. |
43
- | `outputPreset` | `string` | essential is recommended for AI and most lead exports; contacts returns contact fields; tech_stack returns technology fields; opportunity returns sales-gap fields; full returns all |
44
- | `countOnly` | `boolean` | Preview stored in COUNT_SUMMARY without per-result charges. Actor start and platform usage may still apply. Counts matching segment rows; the same domain may occur in multiple segm |
45
- | `maxItems` | `integer` | Upper limit across all data segments. AI/MCP calls should normally request 5–50 rows; bulk exports can request up to 250000 and paginate with offset. |
46
- | `offset` | `integer` | Skip the first N matching rows, then return the next batch. Use it to export more than one run allows: run 1 with Offset 0, run 2 with Offset = the rows you already got, and so on. |
47
- | `columns` | `array` | Optional exact field list. When provided, it overrides Output detail. Leave empty to use outputPreset; each website remains one result row. |
48
-
49
- ## Pricing
50
-
51
- The package is free. Actor runs are billed by Apify using the pricing shown on the [Actor page](https://apify.com/apivault_labs/tech-stack-lookup); platform usage may also apply.
52
-
53
- ## Resources
54
-
55
- - [Actor and live input schema](https://apify.com/apivault_labs/tech-stack-lookup)
56
- - [Source repository](https://github.com/apivault-labs/n8n-nodes-apivault-tech-stack-lookup)
57
- - [n8n community-node documentation](https://docs.n8n.io/integrations/community-nodes/)
58
-
59
- ## License
60
-
61
- MIT. The hosted Actor is a separate paid service governed by Apify terms.
11
+ Runtime dependencies: none. n8n Cloud availability requires separate n8n verification.
@@ -1,6 +1,10 @@
1
1
  import type { IAuthenticateGeneric, ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
2
2
  export declare class ApifyApi implements ICredentialType {
3
3
  name: string;
4
+ icon: {
5
+ readonly light: "file:apivault.svg";
6
+ readonly dark: "file:apivault.svg";
7
+ };
4
8
  displayName: string;
5
9
  documentationUrl: string;
6
10
  properties: INodeProperties[];
@@ -2,27 +2,25 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ApifyApi = void 0;
4
4
  class ApifyApi {
5
- constructor() {
6
- this.name = 'apifyApi';
7
- this.displayName = 'Apify API';
8
- this.documentationUrl = 'https://docs.apify.com/platform/integrations/api';
9
- this.properties = [
10
- {
11
- displayName: 'API Token',
12
- name: 'apiToken',
13
- type: 'string',
14
- typeOptions: { password: true },
15
- default: '',
16
- required: true,
17
- description: 'Your personal Apify API token (Apify Console -> Settings -> Integrations).',
18
- },
19
- ];
20
- this.authenticate = {
21
- type: 'generic',
22
- properties: { headers: { Authorization: '=Bearer {{$credentials.apiToken}}' } },
23
- };
24
- this.test = { request: { baseURL: 'https://api.apify.com/v2', url: '/users/me' } };
25
- }
5
+ name = 'apifyApi';
6
+ icon = { light: 'file:apivault.svg', dark: 'file:apivault.svg' };
7
+ displayName = 'Apify API';
8
+ documentationUrl = 'https://docs.apify.com/platform/integrations/api';
9
+ properties = [
10
+ {
11
+ displayName: 'API Token',
12
+ name: 'apiToken',
13
+ type: 'string',
14
+ typeOptions: { password: true },
15
+ default: '',
16
+ required: true,
17
+ description: 'Your personal Apify API token (Apify Console -> Settings -> Integrations).',
18
+ },
19
+ ];
20
+ authenticate = {
21
+ type: 'generic',
22
+ properties: { headers: { Authorization: '=Bearer {{$credentials.apiToken}}' } },
23
+ };
24
+ test = { request: { baseURL: 'https://api.apify.com/v2', url: '/users/me' } };
26
25
  }
27
26
  exports.ApifyApi = ApifyApi;
28
- //# sourceMappingURL=ApifyApi.credentials.js.map
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect width="64" height="64" rx="14" fill="#4f46e5"/><path d="M16 48 28 16h8l12 32H38l-2-7H26l-2 7zm12-15h6l-3-10z" fill="white"/></svg>
@@ -2,26 +2,47 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TechStackLookup = void 0;
4
4
  const n8n_workflow_1 = require("n8n-workflow");
5
- const ACTOR_ID = 'apivault_labs~tech-stack-lookup';
5
+ const actorTransport_1 = require("../helpers/actorTransport");
6
+ const ACTOR_ID = 'GgG3Xran5X3zZxpRZ';
6
7
  class TechStackLookup {
7
- constructor() {
8
- this.description = {
9
- displayName: 'BuiltWith Alternative — Tech Stack Leads & Lookup (60M)',
10
- name: 'techStackLookup',
11
- icon: 'file:techstacklookup.svg',
12
- group: ['transform'],
13
- version: 1,
14
- description: 'Technology leads and tech stack lookup across 60M+ websites. BuiltWith alternative to find websites by technology, check domains, discover Shopify and Klaviyo leads, build lookalike audiences and monitor stack changes. AI/MCP-ready output for B2B sales.',
15
- defaults: { name: 'BuiltWith Alternative — Tech Stack Leads & Lookup (60M)' },
16
- inputs: [n8n_workflow_1.NodeConnectionTypes.Main],
17
- outputs: [n8n_workflow_1.NodeConnectionTypes.Main],
18
- usableAsTool: true,
19
- credentials: [{ name: 'apifyApi', required: true }],
20
- properties: [
8
+ description = {
9
+ "displayName": "BuiltWith Alternative — Tech Stack Leads & Lookup (60M)",
10
+ "name": "techStackLookup",
11
+ "icon": {
12
+ "light": "file:techstacklookup.svg",
13
+ "dark": "file:techstacklookup.svg"
14
+ },
15
+ "subtitle": "={{$parameter[\"apivaultMode\"]}}",
16
+ "group": [
17
+ "transform"
18
+ ],
19
+ "version": [
20
+ 1,
21
+ 2
22
+ ],
23
+ "description": "Run BuiltWith Alternative through the hosted Apify Actor and read its results",
24
+ "defaults": {
25
+ "name": "BuiltWith Alternative — Tech Stack Leads & Lookup (60M)"
26
+ },
27
+ "inputs": [
28
+ n8n_workflow_1.NodeConnectionTypes.Main
29
+ ],
30
+ "outputs": [
31
+ n8n_workflow_1.NodeConnectionTypes.Main
32
+ ],
33
+ "usableAsTool": true,
34
+ "credentials": [
35
+ {
36
+ "name": "apifyApi",
37
+ "required": true
38
+ }
39
+ ],
40
+ "defaultVersion": 2,
41
+ properties: [...actorTransport_1.executionProperties, ...[
21
42
  {
22
43
  "displayName": "🔀 What do you want to do?",
23
44
  "name": "mode",
24
- "description": "find requires technologies, technologyPreset or opportunityPreset; detect requires domains; lookalike requires seed domains; monitor requires domains and a stable monitorName; catalog needs no other input.",
45
+ "description": "Actor input: 🔀 What do you want to do?",
25
46
  "type": "options",
26
47
  "options": [
27
48
  {
@@ -45,19 +66,33 @@ class TechStackLookup {
45
66
  "value": "catalog"
46
67
  }
47
68
  ],
48
- "default": "find"
69
+ "default": "find",
70
+ "displayOptions": {
71
+ "show": {
72
+ "apivaultMode": [
73
+ "run"
74
+ ]
75
+ }
76
+ }
49
77
  },
50
78
  {
51
79
  "displayName": "🌐 Domains (Detect / Lookalike / Monitor only)",
52
80
  "name": "domains",
53
- "description": "Required when mode is detect, lookalike or monitor; ignored otherwise. Accepts hostnames or URLs. Unknown domains are skipped without a result charge. (comma or new-line separated)",
81
+ "description": "Actor input: 🌐 Domains (Detect / Lookalike / Monitor only)",
54
82
  "type": "string",
55
- "default": ""
83
+ "default": "",
84
+ "displayOptions": {
85
+ "show": {
86
+ "apivaultMode": [
87
+ "run"
88
+ ]
89
+ }
90
+ }
56
91
  },
57
92
  {
58
93
  "displayName": "⚡ Popular technology preset",
59
94
  "name": "technologyPreset",
60
- "description": "Used only when mode=find. Optional shortcut combined with custom Technologies.",
95
+ "description": "Actor input: ⚡ Popular technology preset",
61
96
  "type": "options",
62
97
  "options": [
63
98
  {
@@ -121,12 +156,19 @@ class TechStackLookup {
121
156
  "value": "Gorgias"
122
157
  }
123
158
  ],
124
- "default": "Shopify"
159
+ "default": "Shopify",
160
+ "displayOptions": {
161
+ "show": {
162
+ "apivaultMode": [
163
+ "run"
164
+ ]
165
+ }
166
+ }
125
167
  },
126
168
  {
127
169
  "displayName": "🎯 Sales opportunity preset",
128
170
  "name": "opportunityPreset",
129
- "description": "Used only when mode=find. Returns matching leads, missing technology, opportunity score and suggested pitch.",
171
+ "description": "Actor input: 🎯 Sales opportunity preset",
130
172
  "type": "options",
131
173
  "options": [
132
174
  {
@@ -154,19 +196,33 @@ class TechStackLookup {
154
196
  "value": "stripe_without_paypal"
155
197
  }
156
198
  ],
157
- "default": "shopify_without_klaviyo"
199
+ "default": "shopify_without_klaviyo",
200
+ "displayOptions": {
201
+ "show": {
202
+ "apivaultMode": [
203
+ "run"
204
+ ]
205
+ }
206
+ }
158
207
  },
159
208
  {
160
209
  "displayName": "✅ Technologies to include",
161
210
  "name": "technologies",
162
- "description": "Used only when mode=find. Enter complete product names such as Klaviyo, Stripe, Shopify Plus, HubSpot or Cloudflare. AI agents should prefer technologyPreset for one popular technology and technologies for custom or multiple values. (comma or new-line separated)",
211
+ "description": "Actor input: ✅ Technologies to include",
163
212
  "type": "string",
164
- "default": ""
213
+ "default": "",
214
+ "displayOptions": {
215
+ "show": {
216
+ "apivaultMode": [
217
+ "run"
218
+ ]
219
+ }
220
+ }
165
221
  },
166
222
  {
167
223
  "displayName": "🔗 Match logic",
168
224
  "name": "matchMode",
169
- "description": "Used only when mode=find. any = at least one technology (OR); all = every technology (AND).",
225
+ "description": "Actor input: 🔗 Match logic",
170
226
  "type": "options",
171
227
  "options": [
172
228
  {
@@ -178,19 +234,33 @@ class TechStackLookup {
178
234
  "value": "all"
179
235
  }
180
236
  ],
181
- "default": "any"
237
+ "default": "any",
238
+ "displayOptions": {
239
+ "show": {
240
+ "apivaultMode": [
241
+ "run"
242
+ ]
243
+ }
244
+ }
182
245
  },
183
246
  {
184
247
  "displayName": "🚫 Technologies to exclude",
185
248
  "name": "excludeTechnologies",
186
- "description": "Used only when mode=find. Exclude sites using any listed technology; e.g. Klaviyo leads without Yotpo. (comma or new-line separated)",
249
+ "description": "Actor input: 🚫 Technologies to exclude",
187
250
  "type": "string",
188
- "default": ""
251
+ "default": "",
252
+ "displayOptions": {
253
+ "show": {
254
+ "apivaultMode": [
255
+ "run"
256
+ ]
257
+ }
258
+ }
189
259
  },
190
260
  {
191
261
  "displayName": "🧩 Technology category",
192
262
  "name": "category",
193
- "description": "Used only when mode=find. Limit matching to one stack layer; any is recommended because a product may appear in multiple layers.",
263
+ "description": "Actor input: 🧩 Technology category",
194
264
  "type": "options",
195
265
  "options": [
196
266
  {
@@ -226,73 +296,129 @@ class TechStackLookup {
226
296
  "value": "ai"
227
297
  }
228
298
  ],
229
- "default": "any"
299
+ "default": "any",
300
+ "displayOptions": {
301
+ "show": {
302
+ "apivaultMode": [
303
+ "run"
304
+ ]
305
+ }
306
+ }
230
307
  },
231
308
  {
232
309
  "displayName": "🌍 Countries (ISO-2)",
233
310
  "name": "country",
234
- "description": "One or more ISO-2 country codes, e.g. US, DE, GB. Type each code and press Enter. Empty — no country filter. (comma or new-line separated)",
311
+ "description": "Actor input: 🌍 Countries (ISO-2)",
235
312
  "type": "string",
236
- "default": ""
313
+ "default": "",
314
+ "displayOptions": {
315
+ "show": {
316
+ "apivaultMode": [
317
+ "run"
318
+ ]
319
+ }
320
+ }
237
321
  },
238
322
  {
239
323
  "displayName": "🏷️ Industry / vertical",
240
324
  "name": "vertical",
241
- "description": "Keep only sites in this industry, e.g. Fashion, Technology, Health, or Food. Leave empty to include every industry.",
325
+ "description": "Actor input: 🏷️ Industry / vertical",
242
326
  "type": "string",
243
- "default": ""
327
+ "default": "",
328
+ "displayOptions": {
329
+ "show": {
330
+ "apivaultMode": [
331
+ "run"
332
+ ]
333
+ }
334
+ }
244
335
  },
245
336
  {
246
337
  "displayName": "📧 Only websites with email",
247
338
  "name": "hasEmail",
248
- "description": "Keep only sites where the Emails field is not empty.",
339
+ "description": "Actor input: 📧 Only websites with email",
249
340
  "type": "boolean",
250
- "default": false
341
+ "default": false,
342
+ "displayOptions": {
343
+ "show": {
344
+ "apivaultMode": [
345
+ "run"
346
+ ]
347
+ }
348
+ }
251
349
  },
252
350
  {
253
351
  "displayName": "📞 Only websites with phone",
254
352
  "name": "hasPhone",
255
- "description": "Keep only sites where the Telephones field is not empty.",
353
+ "description": "Actor input: 📞 Only websites with phone",
256
354
  "type": "boolean",
257
- "default": false
355
+ "default": false,
356
+ "displayOptions": {
357
+ "show": {
358
+ "apivaultMode": [
359
+ "run"
360
+ ]
361
+ }
362
+ }
258
363
  },
259
364
  {
260
365
  "displayName": "🆕 First indexed within days",
261
366
  "name": "newWithinDays",
262
- "description": "Return websites first added to the index within the last N days. Use 7 for a weekly new-lead feed. Set 0 to disable.",
367
+ "description": "Actor input: 🆕 First indexed within days",
263
368
  "type": "number",
264
369
  "default": 0,
265
370
  "typeOptions": {
266
371
  "minValue": 0,
267
372
  "maxValue": 3650
373
+ },
374
+ "displayOptions": {
375
+ "show": {
376
+ "apivaultMode": [
377
+ "run"
378
+ ]
379
+ }
268
380
  }
269
381
  },
270
382
  {
271
383
  "displayName": "🔄 Re-indexed within days",
272
384
  "name": "lastIndexedWithinDays",
273
- "description": "Keep websites whose record was indexed within the last N days. Useful for recently refreshed data. Set 0 to disable.",
385
+ "description": "Actor input: 🔄 Re-indexed within days",
274
386
  "type": "number",
275
387
  "default": 0,
276
388
  "typeOptions": {
277
389
  "minValue": 0,
278
390
  "maxValue": 3650
391
+ },
392
+ "displayOptions": {
393
+ "show": {
394
+ "apivaultMode": [
395
+ "run"
396
+ ]
397
+ }
279
398
  }
280
399
  },
281
400
  {
282
401
  "displayName": "✅ Last confirmed within days",
283
402
  "name": "lastFoundWithinDays",
284
- "description": "Keep websites last observed within the previous N days. Use this to prefer recently confirmed leads. Set 0 to disable.",
403
+ "description": "Actor input: ✅ Last confirmed within days",
285
404
  "type": "number",
286
405
  "default": 0,
287
406
  "typeOptions": {
288
407
  "minValue": 0,
289
408
  "maxValue": 3650
409
+ },
410
+ "displayOptions": {
411
+ "show": {
412
+ "apivaultMode": [
413
+ "run"
414
+ ]
415
+ }
290
416
  }
291
417
  },
292
418
  {
293
419
  "displayName": "📊 Sort results by",
294
420
  "name": "sortBy",
295
- "description": "Order rows by this column before applying the limit, so you get the top leads instead of an arbitrary slice. Empty — no ordering.",
421
+ "description": "Actor input: 📊 Sort results by",
296
422
  "type": "options",
297
423
  "options": [
298
424
  {
@@ -344,26 +470,47 @@ class TechStackLookup {
344
470
  "value": "Last Found"
345
471
  }
346
472
  ],
347
- "default": "Overall Score"
473
+ "default": "Overall Score",
474
+ "displayOptions": {
475
+ "show": {
476
+ "apivaultMode": [
477
+ "run"
478
+ ]
479
+ }
480
+ }
348
481
  },
349
482
  {
350
483
  "displayName": "⬇️ Highest values first",
351
484
  "name": "sortDesc",
352
- "description": "Highest values first (recommended for scores/traffic/revenue).",
485
+ "description": "Actor input: ⬇️ Highest values first",
353
486
  "type": "boolean",
354
- "default": true
487
+ "default": true,
488
+ "displayOptions": {
489
+ "show": {
490
+ "apivaultMode": [
491
+ "run"
492
+ ]
493
+ }
494
+ }
355
495
  },
356
496
  {
357
497
  "displayName": "🧹 Remove duplicate domains",
358
498
  "name": "dedupeByDomain",
359
- "description": "Return each normalized Root Domain only once across all data segments. Recommended for lead exports.",
499
+ "description": "Actor input: 🧹 Remove duplicate domains",
360
500
  "type": "boolean",
361
- "default": true
501
+ "default": true,
502
+ "displayOptions": {
503
+ "show": {
504
+ "apivaultMode": [
505
+ "run"
506
+ ]
507
+ }
508
+ }
362
509
  },
363
510
  {
364
511
  "displayName": "📋 Output detail",
365
512
  "name": "outputPreset",
366
- "description": "essential is recommended for AI and most lead exports; contacts returns contact fields; tech_stack returns technology fields; opportunity returns sales-gap fields; full returns all source and derived fields. Ignored when columns is provided.",
513
+ "description": "Actor input: 📋 Output detail",
367
514
  "type": "options",
368
515
  "options": [
369
516
  {
@@ -387,143 +534,149 @@ class TechStackLookup {
387
534
  "value": "full"
388
535
  }
389
536
  ],
390
- "default": "essential"
537
+ "default": "essential",
538
+ "displayOptions": {
539
+ "show": {
540
+ "apivaultMode": [
541
+ "run"
542
+ ]
543
+ }
544
+ }
391
545
  },
392
546
  {
393
547
  "displayName": "🔢 Preview audience size only",
394
548
  "name": "countOnly",
395
- "description": "Preview stored in COUNT_SUMMARY without per-result charges. Actor start and platform usage may still apply. Counts matching segment rows; the same domain may occur in multiple segments, so this is an upper bound for unique websites.",
549
+ "description": "Actor input: 🔢 Preview audience size only",
396
550
  "type": "boolean",
397
- "default": false
551
+ "default": false,
552
+ "displayOptions": {
553
+ "show": {
554
+ "apivaultMode": [
555
+ "run"
556
+ ]
557
+ }
558
+ }
398
559
  },
399
560
  {
400
561
  "displayName": "📦 Maximum websites (5–50 for AI)",
401
562
  "name": "maxItems",
402
- "description": "Upper limit across all data segments. AI/MCP calls should normally request 5–50 rows; bulk exports can request up to 250000 and paginate with offset.",
563
+ "description": "Actor input: 📦 Maximum websites (5–50 for AI)",
403
564
  "type": "number",
404
565
  "default": 50,
405
566
  "typeOptions": {
406
567
  "minValue": 1,
407
568
  "maxValue": 250000
569
+ },
570
+ "displayOptions": {
571
+ "show": {
572
+ "apivaultMode": [
573
+ "run"
574
+ ]
575
+ }
408
576
  }
409
577
  },
410
578
  {
411
579
  "displayName": "➡️ Offset (skip first N)",
412
580
  "name": "offset",
413
- "description": "Skip the first N matching rows, then return the next batch. Use it to export more than one run allows: run 1 with Offset 0, run 2 with Offset = the rows you already got, and so on. Set a Sort by column for stable pagination.",
581
+ "description": "Actor input: ➡️ Offset (skip first N)",
414
582
  "type": "number",
415
583
  "default": 0,
416
584
  "typeOptions": {
417
585
  "minValue": 0
586
+ },
587
+ "displayOptions": {
588
+ "show": {
589
+ "apivaultMode": [
590
+ "run"
591
+ ]
592
+ }
418
593
  }
419
594
  },
420
595
  {
421
596
  "displayName": "🗂️ Custom output columns (optional)",
422
597
  "name": "columns",
423
- "description": "Optional exact field list. When provided, it overrides Output detail. Leave empty to use outputPreset; each website remains one result row. (comma or new-line separated)",
598
+ "description": "Actor input: 🗂️ Custom output columns (optional)",
424
599
  "type": "string",
425
- "default": ""
600
+ "default": "",
601
+ "displayOptions": {
602
+ "show": {
603
+ "apivaultMode": [
604
+ "run"
605
+ ]
606
+ }
607
+ }
426
608
  }
427
- ],
428
- };
429
- }
609
+ ]]
610
+ };
430
611
  async execute() {
431
- var _b;
432
- const items = this.getInputData();
433
- const returnData = [];
434
- for (let i = 0; i < items.length; i++) {
612
+ const output = [];
613
+ for (let i = 0; i < this.getInputData().length; i++) {
435
614
  try {
436
- const body = {};
437
- body["mode"] = this.getNodeParameter("mode", i);
438
- {
439
- const _v = this.getNodeParameter("domains", i, '');
440
- const _a = _v.split(/[,\n]/).map(s => s.trim()).filter(s => s.length > 0);
441
- if (_a.length)
442
- body["domains"] = _a;
443
- }
444
- body["technologyPreset"] = this.getNodeParameter("technologyPreset", i);
445
- body["opportunityPreset"] = this.getNodeParameter("opportunityPreset", i);
446
- {
447
- const _v = this.getNodeParameter("technologies", i, '');
448
- const _a = _v.split(/[,\n]/).map(s => s.trim()).filter(s => s.length > 0);
449
- if (_a.length)
450
- body["technologies"] = _a;
451
- }
452
- body["matchMode"] = this.getNodeParameter("matchMode", i);
453
- {
454
- const _v = this.getNodeParameter("excludeTechnologies", i, '');
455
- const _a = _v.split(/[,\n]/).map(s => s.trim()).filter(s => s.length > 0);
456
- if (_a.length)
457
- body["excludeTechnologies"] = _a;
458
- }
459
- body["category"] = this.getNodeParameter("category", i);
460
- {
461
- const _v = this.getNodeParameter("country", i, '');
462
- const _a = _v.split(/[,\n]/).map(s => s.trim()).filter(s => s.length > 0);
463
- if (_a.length)
464
- body["country"] = _a;
465
- }
466
- body["vertical"] = this.getNodeParameter("vertical", i);
467
- body["hasEmail"] = this.getNodeParameter("hasEmail", i);
468
- body["hasPhone"] = this.getNodeParameter("hasPhone", i);
469
- body["newWithinDays"] = this.getNodeParameter("newWithinDays", i);
470
- body["lastIndexedWithinDays"] = this.getNodeParameter("lastIndexedWithinDays", i);
471
- body["lastFoundWithinDays"] = this.getNodeParameter("lastFoundWithinDays", i);
472
- body["sortBy"] = this.getNodeParameter("sortBy", i);
473
- body["sortDesc"] = this.getNodeParameter("sortDesc", i);
474
- body["dedupeByDomain"] = this.getNodeParameter("dedupeByDomain", i);
475
- body["outputPreset"] = this.getNodeParameter("outputPreset", i);
476
- body["countOnly"] = this.getNodeParameter("countOnly", i);
477
- body["maxItems"] = this.getNodeParameter("maxItems", i);
478
- body["offset"] = this.getNodeParameter("offset", i);
479
- {
480
- const _v = this.getNodeParameter("columns", i, '');
481
- const _a = _v.split(/[,\n]/).map(s => s.trim()).filter(s => s.length > 0);
482
- if (_a.length)
483
- body["columns"] = _a;
484
- }
485
- const options = {
486
- method: 'POST',
487
- url: `https://api.apify.com/v2/acts/${ACTOR_ID}/runs`,
488
- body,
489
- json: true,
490
- };
491
- const started = await this.helpers.requestWithAuthentication.call(this, 'apifyApi', options);
492
- const runId = (_b = started === null || started === void 0 ? void 0 : started.data) === null || _b === void 0 ? void 0 : _b.id;
493
- if (!runId)
494
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Apify did not return a run ID', { itemIndex: i });
495
- let run = started.data;
496
- const deadline = Date.now() + 60 * 60 * 1000;
497
- while (!['SUCCEEDED', 'FAILED', 'ABORTED', 'TIMED-OUT'].includes(run.status)) {
498
- if (Date.now() >= deadline)
499
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Waiting timed out; check the existing run in Apify before retrying', { itemIndex: i });
500
- const polled = await this.helpers.requestWithAuthentication.call(this, 'apifyApi', { method: 'GET', url: `https://api.apify.com/v2/actor-runs/${runId}?waitForFinish=20`, json: true });
501
- run = polled.data;
502
- }
503
- if (run.status !== 'SUCCEEDED')
504
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Apify run ended with status ' + run.status, { itemIndex: i });
505
- let offset = 0;
506
- while (true) {
507
- const page = await this.helpers.requestWithAuthentication.call(this, 'apifyApi', { method: 'GET', url: `https://api.apify.com/v2/datasets/${run.defaultDatasetId}/items?clean=1&limit=1000&offset=${offset}`, json: true });
508
- if (!Array.isArray(page))
509
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Unexpected Dataset response', { itemIndex: i });
510
- for (const result of page)
511
- returnData.push({ json: result, pairedItem: { item: i } });
512
- offset += page.length;
513
- if (page.length < 1000)
514
- break;
515
- }
615
+ const body = this.getNodeParameter('apivaultMode', i, 'run') === 'read' ? {} : (() => {
616
+ const body = {};
617
+ body["mode"] = this.getNodeParameter("mode", i);
618
+ {
619
+ const _v = this.getNodeParameter("domains", i, '');
620
+ const _a = _v.split(/[,\n]/).map(s => s.trim()).filter(s => s.length > 0);
621
+ if (_a.length)
622
+ body["domains"] = _a;
623
+ }
624
+ body["technologyPreset"] = this.getNodeParameter("technologyPreset", i);
625
+ body["opportunityPreset"] = this.getNodeParameter("opportunityPreset", i);
626
+ {
627
+ const _v = this.getNodeParameter("technologies", i, '');
628
+ const _a = _v.split(/[,\n]/).map(s => s.trim()).filter(s => s.length > 0);
629
+ if (_a.length)
630
+ body["technologies"] = _a;
631
+ }
632
+ body["matchMode"] = this.getNodeParameter("matchMode", i);
633
+ {
634
+ const _v = this.getNodeParameter("excludeTechnologies", i, '');
635
+ const _a = _v.split(/[,\n]/).map(s => s.trim()).filter(s => s.length > 0);
636
+ if (_a.length)
637
+ body["excludeTechnologies"] = _a;
638
+ }
639
+ body["category"] = this.getNodeParameter("category", i);
640
+ {
641
+ const _v = this.getNodeParameter("country", i, '');
642
+ const _a = _v.split(/[,\n]/).map(s => s.trim()).filter(s => s.length > 0);
643
+ if (_a.length)
644
+ body["country"] = _a;
645
+ }
646
+ body["vertical"] = this.getNodeParameter("vertical", i);
647
+ body["hasEmail"] = this.getNodeParameter("hasEmail", i);
648
+ body["hasPhone"] = this.getNodeParameter("hasPhone", i);
649
+ body["newWithinDays"] = this.getNodeParameter("newWithinDays", i);
650
+ body["lastIndexedWithinDays"] = this.getNodeParameter("lastIndexedWithinDays", i);
651
+ body["lastFoundWithinDays"] = this.getNodeParameter("lastFoundWithinDays", i);
652
+ body["sortBy"] = this.getNodeParameter("sortBy", i);
653
+ body["sortDesc"] = this.getNodeParameter("sortDesc", i);
654
+ body["dedupeByDomain"] = this.getNodeParameter("dedupeByDomain", i);
655
+ body["outputPreset"] = this.getNodeParameter("outputPreset", i);
656
+ body["countOnly"] = this.getNodeParameter("countOnly", i);
657
+ body["maxItems"] = this.getNodeParameter("maxItems", i);
658
+ body["offset"] = this.getNodeParameter("offset", i);
659
+ {
660
+ const _v = this.getNodeParameter("columns", i, '');
661
+ const _a = _v.split(/[,\n]/).map(s => s.trim()).filter(s => s.length > 0);
662
+ if (_a.length)
663
+ body["columns"] = _a;
664
+ }
665
+ return body;
666
+ })();
667
+ const results = await (0, actorTransport_1.runActor)(this, i, ACTOR_ID, body);
668
+ for (const result of results)
669
+ output.push({ json: result, pairedItem: { item: i } });
516
670
  }
517
671
  catch (error) {
518
- if (this.continueOnFail()) {
519
- returnData.push({ json: { error: error.message }, pairedItem: { item: i } });
520
- continue;
521
- }
522
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), error, { itemIndex: i });
672
+ const message = error instanceof actorTransport_1.SafeActorError ? error.message : 'Could not finish the Actor request. Check inputs and credentials; use Read Existing Run if a run was already started';
673
+ if (this.continueOnFail())
674
+ output.push({ json: { error: message }, pairedItem: { item: i } });
675
+ else
676
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), message, { itemIndex: i });
523
677
  }
524
678
  }
525
- return [returnData];
679
+ return [output];
526
680
  }
527
681
  }
528
682
  exports.TechStackLookup = TechStackLookup;
529
- //# sourceMappingURL=TechStackLookup.node.js.map
@@ -0,0 +1,9 @@
1
+ import type { IExecuteFunctions, INodeProperties, IDataObject } from 'n8n-workflow';
2
+ import { NodeOperationError } from 'n8n-workflow';
3
+ export declare class SafeActorError extends NodeOperationError {
4
+ readonly runId: string;
5
+ constructor(context: IExecuteFunctions, runId: string, item: number);
6
+ }
7
+ export declare const executionProperties: INodeProperties[];
8
+ export declare function runActor(context: IExecuteFunctions, item: number, actorId: string, body: Record<string, unknown>): Promise<IDataObject[]>;
9
+ export declare function legacyRequest(context: IExecuteFunctions, item: number, raw: unknown): Promise<any>;
@@ -0,0 +1,155 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.executionProperties = exports.SafeActorError = void 0;
4
+ exports.runActor = runActor;
5
+ exports.legacyRequest = legacyRequest;
6
+ const n8n_workflow_1 = require("n8n-workflow");
7
+ const API = 'https://api.apify.com/v2';
8
+ const id = (value) => {
9
+ if (typeof value !== 'string' || !/^[A-Za-z0-9_-]{1,100}$/.test(value))
10
+ throw new Error('Invalid Apify identifier');
11
+ return value;
12
+ };
13
+ class SafeActorError extends n8n_workflow_1.NodeOperationError {
14
+ runId;
15
+ constructor(context, runId, item) {
16
+ super(context.getNode(), runId ? `Could not finish reading run ${runId}; select Read Existing Run to resume` : 'Could not start or read the Actor. Check inputs and credentials before retrying', { itemIndex: item });
17
+ this.runId = runId;
18
+ }
19
+ }
20
+ exports.SafeActorError = SafeActorError;
21
+ exports.executionProperties = [
22
+ { displayName: 'Run Mode', name: 'apivaultMode', type: 'options', noDataExpression: true,
23
+ options: [{ name: 'Run Actor', value: 'run', action: 'Run the actor' }, { name: 'Read Existing Run', value: 'read', action: 'Read an existing run' }], default: 'run' },
24
+ { displayName: 'Execution Options', name: 'apivaultExecution', type: 'collection', placeholder: 'Add Option', default: {}, options: [
25
+ { displayName: 'Run ID', name: 'runId', type: 'string', default: '', description: 'Existing Apify run to resume without starting a paid duplicate' },
26
+ { displayName: 'Maximum Event Charge (USD)', name: 'maxTotalChargeUsd', type: 'number', default: 0.05,
27
+ typeOptions: { minValue: 0.001, maxValue: 1000, numberPrecision: 3 }, description: 'Event charge cap. Platform usage may be billed separately.' },
28
+ { displayName: 'Maximum Rows to Read', name: 'maxRows', type: 'number', default: 1000,
29
+ typeOptions: { minValue: 1, maxValue: 100000, numberPrecision: 0 }, description: 'Download cap only. Actor input limits control paid collection.' },
30
+ { displayName: 'Output', name: 'output', type: 'options', default: 'rows',
31
+ options: [{ name: 'Dataset Rows', value: 'rows' }, { name: 'Run, Rows and Diagnostics', value: 'full' }], description: 'Include SUMMARY and ERRORS to inspect partial or empty results' },
32
+ ] },
33
+ ];
34
+ async function runActor(context, item, actorId, body) {
35
+ let runId = '';
36
+ try {
37
+ const mode = context.getNodeParameter('apivaultMode', item, 'run');
38
+ const options = context.getNodeParameter('apivaultExecution', item, {});
39
+ const legacy = context.getNode().typeVersion < 2;
40
+ const maxRows = options.maxRows ?? (legacy ? 100000 : 1000);
41
+ if (!Number.isInteger(maxRows) || maxRows < 1 || maxRows > 100000)
42
+ throw new Error('Invalid row limit');
43
+ const request = async (requestOptions) => context.helpers.httpRequestWithAuthentication.call(context, 'apifyApi', requestOptions);
44
+ if (mode === 'run') {
45
+ const cap = options.maxTotalChargeUsd ?? (legacy ? undefined : 0.05);
46
+ if (cap !== undefined && (!Number.isFinite(cap) || cap <= 0 || cap > 1000))
47
+ throw new Error('Invalid event charge cap');
48
+ // Legacy workflows retain their existing charge behavior unless a cap is selected.
49
+ const qs = { build: 'latest' };
50
+ if (cap !== undefined)
51
+ qs.maxTotalChargeUsd = cap;
52
+ // Never retry POST: a duplicate could create a second paid Actor run.
53
+ const started = await request({ method: 'POST', url: `${API}/acts/${id(actorId)}/runs`, body: body, qs, json: true });
54
+ runId = id(started?.data?.id);
55
+ }
56
+ else if (mode === 'read')
57
+ runId = id(options.runId);
58
+ else
59
+ throw new Error('Unsupported run mode');
60
+ const deadline = Date.now() + 10 * 60 * 1000;
61
+ let run;
62
+ while (true) {
63
+ if (Date.now() >= deadline)
64
+ throw new Error('Waiting timed out');
65
+ const response = await request({ method: 'GET', url: `${API}/actor-runs/${runId}`, qs: { waitForFinish: 20 }, json: true });
66
+ run = response.data;
67
+ if (run.status === 'SUCCEEDED')
68
+ break;
69
+ if (['FAILED', 'TIMED-OUT', 'ABORTED'].includes(run.status))
70
+ throw new Error('Run did not succeed');
71
+ }
72
+ const datasetId = id(run.defaultDatasetId);
73
+ const dataset = await request({ method: 'GET', url: `${API}/datasets/${datasetId}`, json: true });
74
+ const rows = [];
75
+ while (rows.length < maxRows) {
76
+ const limit = Math.min(1000, maxRows - rows.length);
77
+ const page = await request({ method: 'GET', url: `${API}/datasets/${datasetId}/items`, qs: { clean: true, offset: rows.length, limit }, json: true });
78
+ if (!Array.isArray(page) || page.length > limit)
79
+ throw new Error('Invalid Dataset response');
80
+ rows.push(...page);
81
+ if (page.length < limit)
82
+ break;
83
+ }
84
+ const truncated = (dataset.data?.itemCount ?? rows.length) > rows.length;
85
+ if (options.output === 'full') {
86
+ const storeId = id(run.defaultKeyValueStoreId);
87
+ const records = {};
88
+ for (const key of ['SUMMARY', 'ERRORS']) {
89
+ try {
90
+ records[key] = await request({ method: 'GET', url: `${API}/key-value-stores/${storeId}/records/${key}`, json: true });
91
+ }
92
+ catch (error) {
93
+ const e = error;
94
+ if (e.statusCode === 404 || e.response?.status === 404)
95
+ records[key] = null;
96
+ else
97
+ throw new n8n_workflow_1.NodeOperationError(context.getNode(), 'Diagnostics unavailable');
98
+ }
99
+ }
100
+ return [{ runId, datasetId, status: run.status, rows, summary: records.SUMMARY ?? null, errors: records.ERRORS ?? null, truncated }];
101
+ }
102
+ return rows.map(row => ({ ...row, _apifyRunId: runId, _apifyTruncated: truncated }));
103
+ }
104
+ catch {
105
+ const safeError = new SafeActorError(context, runId, item);
106
+ throw safeError;
107
+ }
108
+ }
109
+ // Keep specialized legacy output modes (including asynchronous start and MCP_RESPONSE).
110
+ async function legacyRequest(context, item, raw) {
111
+ const options = raw;
112
+ const controls = context.getNodeParameter('apivaultExecution', item, {});
113
+ const request = async (value) => context.helpers.httpRequestWithAuthentication.call(context, 'apifyApi', value);
114
+ if (options.method === 'POST' && options.url.endsWith('/runs')) {
115
+ const qs = { ...(options.qs ?? {}) };
116
+ const wait = qs.waitForFinish;
117
+ delete qs.waitForFinish;
118
+ const cap = controls.maxTotalChargeUsd ?? (context.getNode().typeVersion < 2 ? undefined : 0.05);
119
+ if (cap !== undefined) {
120
+ if (!Number.isFinite(cap) || cap <= 0 || cap > 1000)
121
+ throw new Error('Invalid event charge cap');
122
+ qs.maxTotalChargeUsd = cap;
123
+ }
124
+ const started = await request({ ...options, qs });
125
+ if (!wait)
126
+ return started;
127
+ const runId = id(started?.data?.id);
128
+ const deadline = Date.now() + 10 * 60 * 1000;
129
+ while (Date.now() < deadline) {
130
+ const result = await request({ method: 'GET', url: `${API}/actor-runs/${runId}`, qs: { waitForFinish: 20 }, json: true });
131
+ if (result.data.status === 'SUCCEEDED')
132
+ return result;
133
+ if (['FAILED', 'TIMED-OUT', 'ABORTED'].includes(result.data.status))
134
+ throw new Error('Run did not succeed');
135
+ }
136
+ throw new Error('Waiting timed out');
137
+ }
138
+ if (options.method === 'GET' && /\/datasets\/[A-Za-z0-9_-]+\/items$/.test(options.url)) {
139
+ const maxRows = controls.maxRows ?? (context.getNode().typeVersion < 2 ? 100000 : 1000);
140
+ if (!Number.isInteger(maxRows) || maxRows < 1 || maxRows > 100000)
141
+ throw new Error('Invalid row limit');
142
+ const rows = [];
143
+ while (rows.length < maxRows) {
144
+ const limit = Math.min(1000, maxRows - rows.length);
145
+ const page = await request({ ...options, qs: { ...(options.qs ?? {}), offset: rows.length, limit } });
146
+ if (!Array.isArray(page) || page.length > limit)
147
+ throw new Error('Invalid Dataset response');
148
+ rows.push(...page);
149
+ if (page.length < limit)
150
+ break;
151
+ }
152
+ return rows;
153
+ }
154
+ return request(options);
155
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "n8n-nodes-apivault-tech-stack-lookup",
3
- "version": "0.2.0",
4
- "description": "n8n community node for BuiltWith Alternative — Tech Stack Leads & Lookup (60M) — backed by the Apify Actor apivault_labs/tech-stack-lookup. No login. Pay-as-you-go via Apify.",
3
+ "version": "0.3.0",
4
+ "description": "Run BuiltWith Alternative through the hosted Apify Actor and read its results",
5
5
  "license": "MIT",
6
6
  "homepage": "https://apify.com/apivault_labs/tech-stack-lookup",
7
7
  "keywords": [
@@ -15,20 +15,24 @@
15
15
  "workflow-automation"
16
16
  ],
17
17
  "author": {
18
- "name": "apivault_labs"
18
+ "name": "ApiVault Labs",
19
+ "email": "68965192+apivault-labs@users.noreply.github.com"
19
20
  },
20
21
  "repository": {
21
22
  "type": "git",
22
- "url": "https://github.com/apivault-labs/n8n-nodes-apivault-tech-stack-lookup.git"
23
+ "url": "git+https://github.com/apivault-labs/apivault-labs.git",
24
+ "directory": "community-nodes/n8n-nodes-apivault-tech-stack-lookup"
23
25
  },
24
26
  "main": "index.js",
25
27
  "scripts": {
26
- "build": "tsc && copyfiles \"nodes/**/*.svg\" dist",
27
- "dev": "tsc --watch",
28
+ "build": "tsc && node scripts/copy-icons.cjs",
29
+ "lint": "n8n-node lint",
30
+ "test": "node test/contract.cjs",
28
31
  "prepublishOnly": "npm run build"
29
32
  },
30
33
  "files": [
31
- "dist"
34
+ "dist",
35
+ "examples"
32
36
  ],
33
37
  "n8n": {
34
38
  "n8nNodesApiVersion": 1,
@@ -40,12 +44,12 @@
40
44
  ]
41
45
  },
42
46
  "devDependencies": {
43
- "@types/node": "^20.10.0",
44
- "copyfiles": "^2.4.1",
45
- "n8n-workflow": "*",
46
- "typescript": "^5.4.0"
47
+ "@n8n/node-cli": "0.52.2",
48
+ "n8n-workflow": "2.16.0",
49
+ "typescript": "npm:@typescript/typescript6@6.0.2",
50
+ "@types/node": "^22.0.0"
47
51
  },
48
52
  "peerDependencies": {
49
53
  "n8n-workflow": "*"
50
54
  }
51
- }
55
+ }
@@ -1 +0,0 @@
1
- {"version":3,"file":"ApifyApi.credentials.js","sourceRoot":"","sources":["../../credentials/ApifyApi.credentials.ts"],"names":[],"mappings":";;;AAOA,MAAa,QAAQ;IAArB;QACC,SAAI,GAAG,UAAU,CAAC;QAClB,gBAAW,GAAG,WAAW,CAAC;QAC1B,qBAAgB,GAAG,kDAAkD,CAAC;QACtE,eAAU,GAAsB;YAC/B;gBACC,WAAW,EAAE,WAAW;gBACxB,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE,4EAA4E;aACzF;SACD,CAAC;QACF,iBAAY,GAAyB;YACpC,IAAI,EAAE,SAAS;YACf,UAAU,EAAE,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,mCAAmC,EAAE,EAAE;SAC/E,CAAC;QACF,SAAI,GAA2B,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,0BAA0B,EAAE,GAAG,EAAE,WAAW,EAAE,EAAE,CAAC;IACvG,CAAC;CAAA;AApBD,4BAoBC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"TechStackLookup.node.js","sourceRoot":"","sources":["../../../nodes/TechStackLookup/TechStackLookup.node.ts"],"names":[],"mappings":"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"}