n8n-nodes-federal-spending-forensic-api 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +152 -0
- package/dist/credentials/ApifyApi.credentials.d.ts +8 -0
- package/dist/credentials/ApifyApi.credentials.js +29 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +7 -0
- package/dist/nodes/FederalSpendingForensic/FederalSpendingForensic.node.d.ts +5 -0
- package/dist/nodes/FederalSpendingForensic/FederalSpendingForensic.node.js +600 -0
- package/dist/nodes/FederalSpendingForensic/federalSpendingForensic.svg +43 -0
- package/package.json +64 -0
package/README.md
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# n8n-nodes-federal-spending-forensic-api
|
|
2
|
+
|
|
3
|
+
**Forensic Federal Spending Intelligence for n8n**
|
|
4
|
+
|
|
5
|
+
Uncover the **$195 BILLION USASpending blind spot** with AI-powered forensic analysis. This n8n community node provides access to the Federal Spending Forensic API - the "Bloomberg Gov killer" that exposes contract opportunities competitors don't even know exist.
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
## Why This Node?
|
|
10
|
+
|
|
11
|
+
The official USASpending API has critical gaps:
|
|
12
|
+
- **49 agencies** don't report properly (GAO-24-106214)
|
|
13
|
+
- **$195 BILLION** COVID spending discrepancy
|
|
14
|
+
- Complex POST requests with aggressive rate limits
|
|
15
|
+
- No built-in forensic analysis
|
|
16
|
+
|
|
17
|
+
This node solves all of that with:
|
|
18
|
+
- 🎯 **Recompete Radar™** - Find contracts expiring in your industry
|
|
19
|
+
- 🏷️ **Set-Aside Scanner™** - $150B+ in small business opportunities
|
|
20
|
+
- 📈 **Contract Growth Tracker™** - Flag suspicious modification patterns
|
|
21
|
+
- 🏛️ **SAM.gov Integration** - Live RFPs, RFIs, and solicitations
|
|
22
|
+
- 🔍 **FPDS Cross-Reference** - "Dark money" discrepancy detection
|
|
23
|
+
|
|
24
|
+
## Operations
|
|
25
|
+
|
|
26
|
+
### Search Contracts
|
|
27
|
+
Query federal contract awards with filters for agency, NAICS, keywords, recipient, and more.
|
|
28
|
+
|
|
29
|
+
### Recompete Radar
|
|
30
|
+
**Pipeline gold.** Find contracts expiring within your specified window (30-730 days). Perfect for BD teams tracking recompete opportunities.
|
|
31
|
+
|
|
32
|
+
### Set-Aside Scanner
|
|
33
|
+
Access the **$150B+ small business market**:
|
|
34
|
+
- 8(a) Business Development
|
|
35
|
+
- HUBZone
|
|
36
|
+
- SDVOSB (Service-Disabled Veteran)
|
|
37
|
+
- WOSB/EDWOSB (Women-Owned)
|
|
38
|
+
- Small Disadvantaged Business
|
|
39
|
+
|
|
40
|
+
### Contract Growth Tracker
|
|
41
|
+
Forensic analysis to find contracts that grew **200%+** from original value - indicators of poor planning, scope creep, or incumbent lock-in.
|
|
42
|
+
|
|
43
|
+
### SAM.gov Opportunities
|
|
44
|
+
Search live solicitations, RFPs, RFIs, and Sources Sought notices directly from SAM.gov. Requires a free SAM.gov API key.
|
|
45
|
+
|
|
46
|
+
### Entity Verification
|
|
47
|
+
Verify contractor SAM.gov registration status, check for exclusions/debarments, and validate entity information.
|
|
48
|
+
|
|
49
|
+
### Agency Profile
|
|
50
|
+
Get agency spending profiles with GAO audit findings and reporting status.
|
|
51
|
+
|
|
52
|
+
### Forensic Audit
|
|
53
|
+
Full forensic analysis with cross-referencing across multiple data sources.
|
|
54
|
+
|
|
55
|
+
## Installation
|
|
56
|
+
|
|
57
|
+
### In n8n (Recommended)
|
|
58
|
+
|
|
59
|
+
1. Go to **Settings** > **Community Nodes**
|
|
60
|
+
2. Click **Install**
|
|
61
|
+
3. Enter: `n8n-nodes-federal-spending-forensic-api`
|
|
62
|
+
4. Click **Install**
|
|
63
|
+
|
|
64
|
+
### Manual Installation
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
npm install n8n-nodes-federal-spending-forensic-api
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Credentials
|
|
71
|
+
|
|
72
|
+
This node requires an **Apify API Token**:
|
|
73
|
+
|
|
74
|
+
1. Create a free account at [apify.com](https://apify.com)
|
|
75
|
+
2. Go to Settings > Integrations
|
|
76
|
+
3. Copy your API token
|
|
77
|
+
4. Add credentials in n8n: **Apify API**
|
|
78
|
+
|
|
79
|
+
For SAM.gov features, you'll also need a **SAM.gov API Key**:
|
|
80
|
+
1. Register at [api.sam.gov](https://api.sam.gov)
|
|
81
|
+
2. Request API access
|
|
82
|
+
3. Enter the key in the node parameters
|
|
83
|
+
|
|
84
|
+
## Example Workflows
|
|
85
|
+
|
|
86
|
+
### Daily Recompete Alert
|
|
87
|
+
```
|
|
88
|
+
Schedule Trigger → Federal Spending Forensic (Recompete Radar) → IF (urgency = HIGH) → Slack Notification
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Set-Aside Opportunity Pipeline
|
|
92
|
+
```
|
|
93
|
+
Federal Spending Forensic (Set-Aside Scanner) → Airtable/Salesforce → Email Alert
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Contractor Due Diligence
|
|
97
|
+
```
|
|
98
|
+
Webhook → Federal Spending Forensic (Entity Verify) → IF (exclusion) → Alert
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Output Examples
|
|
102
|
+
|
|
103
|
+
### Contract Search
|
|
104
|
+
```json
|
|
105
|
+
{
|
|
106
|
+
"awardId": "W911QX24F0053",
|
|
107
|
+
"recipientName": "PALANTIR USG INC",
|
|
108
|
+
"awardAmount": 292680000,
|
|
109
|
+
"awardingAgency": "Department of Defense",
|
|
110
|
+
"description": "MAVEN SMART SYSTEM",
|
|
111
|
+
"discrepancyScore": 14,
|
|
112
|
+
"forensicFlags": [
|
|
113
|
+
{
|
|
114
|
+
"type": "late_reporting",
|
|
115
|
+
"message": "Award data was reported 1580 days after start date"
|
|
116
|
+
}
|
|
117
|
+
]
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Recompete Radar
|
|
122
|
+
```json
|
|
123
|
+
{
|
|
124
|
+
"awardId": "70RTAC21FC0000006",
|
|
125
|
+
"recipientName": "CACI NSS, LLC",
|
|
126
|
+
"awardAmount": 215290000,
|
|
127
|
+
"daysUntilExpiration": 33,
|
|
128
|
+
"urgency": "HIGH",
|
|
129
|
+
"endDate": "2026-03-01"
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Pricing
|
|
134
|
+
|
|
135
|
+
The underlying Apify actor uses pay-per-result pricing:
|
|
136
|
+
- **$0.03 per result**
|
|
137
|
+
- First results free (Apify free tier)
|
|
138
|
+
- No Bloomberg Gov subscription ($7,500+/year) required!
|
|
139
|
+
|
|
140
|
+
## Support
|
|
141
|
+
|
|
142
|
+
- **Documentation**: [Apify Actor Documentation](https://apify.com/ai_solutionist/federal-spending-forensic-api)
|
|
143
|
+
- **Issues**: [GitHub Issues](https://github.com/ai-solutionist/n8n-nodes-federal-spending-forensic-api/issues)
|
|
144
|
+
- **Author**: Jason Pellerin - [jasonpellerin.com](https://jasonpellerin.com)
|
|
145
|
+
|
|
146
|
+
## License
|
|
147
|
+
|
|
148
|
+
MIT
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
*"The official USASpending API has a $195B blind spot. This node uses forensic cross-referencing to find the 'Dark Money' contracts the government forgot to report. Stop fighting for the visible 70%—snatch the 30% that requires forensic extraction."*
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { IAuthenticateGeneric, ICredentialType, INodeProperties } from 'n8n-workflow';
|
|
2
|
+
export declare class ApifyApi implements ICredentialType {
|
|
3
|
+
name: string;
|
|
4
|
+
displayName: string;
|
|
5
|
+
documentationUrl: string;
|
|
6
|
+
properties: INodeProperties[];
|
|
7
|
+
authenticate: IAuthenticateGeneric;
|
|
8
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ApifyApi = void 0;
|
|
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
|
+
description: 'Your Apify API token from https://console.apify.com/settings/integrations',
|
|
17
|
+
},
|
|
18
|
+
];
|
|
19
|
+
this.authenticate = {
|
|
20
|
+
type: 'generic',
|
|
21
|
+
properties: {
|
|
22
|
+
headers: {
|
|
23
|
+
Authorization: '={{"Bearer " + $credentials.apiToken}}',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
exports.ApifyApi = ApifyApi;
|
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.ApifyApi = exports.FederalSpendingForensic = void 0;
|
|
4
|
+
const FederalSpendingForensic_node_1 = require("./nodes/FederalSpendingForensic/FederalSpendingForensic.node");
|
|
5
|
+
Object.defineProperty(exports, "FederalSpendingForensic", { enumerable: true, get: function () { return FederalSpendingForensic_node_1.FederalSpendingForensic; } });
|
|
6
|
+
const ApifyApi_credentials_1 = require("./credentials/ApifyApi.credentials");
|
|
7
|
+
Object.defineProperty(exports, "ApifyApi", { enumerable: true, get: function () { return ApifyApi_credentials_1.ApifyApi; } });
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
|
|
2
|
+
export declare class FederalSpendingForensic implements INodeType {
|
|
3
|
+
description: INodeTypeDescription;
|
|
4
|
+
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
5
|
+
}
|
|
@@ -0,0 +1,600 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FederalSpendingForensic = void 0;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
class FederalSpendingForensic {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.description = {
|
|
8
|
+
displayName: 'Federal Spending Forensic API',
|
|
9
|
+
name: 'federalSpendingForensic',
|
|
10
|
+
icon: 'file:federalSpendingForensic.svg',
|
|
11
|
+
group: ['transform'],
|
|
12
|
+
version: 1,
|
|
13
|
+
subtitle: '={{$parameter["operation"]}}',
|
|
14
|
+
description: 'Forensic federal spending intelligence - Uncover the $195B USASpending blind spot',
|
|
15
|
+
defaults: {
|
|
16
|
+
name: 'Federal Spending Forensic',
|
|
17
|
+
},
|
|
18
|
+
inputs: ['main'],
|
|
19
|
+
outputs: ['main'],
|
|
20
|
+
credentials: [
|
|
21
|
+
{
|
|
22
|
+
name: 'apifyApi',
|
|
23
|
+
required: true,
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
properties: [
|
|
27
|
+
// ==========================================
|
|
28
|
+
// OPERATION SELECTOR
|
|
29
|
+
// ==========================================
|
|
30
|
+
{
|
|
31
|
+
displayName: 'Operation',
|
|
32
|
+
name: 'operation',
|
|
33
|
+
type: 'options',
|
|
34
|
+
noDataExpression: true,
|
|
35
|
+
options: [
|
|
36
|
+
{
|
|
37
|
+
name: 'Search Contracts',
|
|
38
|
+
value: 'contracts',
|
|
39
|
+
description: 'Search federal contract awards',
|
|
40
|
+
action: 'Search federal contracts',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: 'Recompete Radar',
|
|
44
|
+
value: 'recompete',
|
|
45
|
+
description: 'Find contracts expiring soon (pipeline opportunities)',
|
|
46
|
+
action: 'Find recompete opportunities',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: 'Set-Aside Scanner',
|
|
50
|
+
value: 'setAside',
|
|
51
|
+
description: 'Find small business set-aside opportunities',
|
|
52
|
+
action: 'Scan set-aside contracts',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: 'Contract Growth Tracker',
|
|
56
|
+
value: 'contractGrowth',
|
|
57
|
+
description: 'Find contracts with suspicious growth patterns',
|
|
58
|
+
action: 'Track contract growth anomalies',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: 'SAM.gov Opportunities',
|
|
62
|
+
value: 'samOpportunities',
|
|
63
|
+
description: 'Search live RFPs and solicitations',
|
|
64
|
+
action: 'Search SAM gov opportunities',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: 'Entity Verification',
|
|
68
|
+
value: 'entityVerify',
|
|
69
|
+
description: 'Verify contractor SAM.gov registration',
|
|
70
|
+
action: 'Verify entity registration',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: 'Agency Profile',
|
|
74
|
+
value: 'agencies',
|
|
75
|
+
description: 'Get agency spending profiles and GAO findings',
|
|
76
|
+
action: 'Get agency profile',
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: 'Forensic Audit',
|
|
80
|
+
value: 'forensicAudit',
|
|
81
|
+
description: 'Full forensic analysis with cross-referencing',
|
|
82
|
+
action: 'Run forensic audit',
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: 'Get Run Status',
|
|
86
|
+
value: 'getStatus',
|
|
87
|
+
description: 'Check the status of a running extraction',
|
|
88
|
+
action: 'Get run status',
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
default: 'contracts',
|
|
92
|
+
},
|
|
93
|
+
// ==========================================
|
|
94
|
+
// COMMON FILTERS
|
|
95
|
+
// ==========================================
|
|
96
|
+
{
|
|
97
|
+
displayName: 'Agency',
|
|
98
|
+
name: 'agency',
|
|
99
|
+
type: 'options',
|
|
100
|
+
options: [
|
|
101
|
+
{ name: 'All Agencies', value: 'all' },
|
|
102
|
+
{ name: 'Department of Defense', value: 'Department of Defense' },
|
|
103
|
+
{ name: 'Department of Homeland Security', value: 'Department of Homeland Security' },
|
|
104
|
+
{ name: 'Department of Health and Human Services', value: 'Department of Health and Human Services' },
|
|
105
|
+
{ name: 'Department of Veterans Affairs', value: 'Department of Veterans Affairs' },
|
|
106
|
+
{ name: 'Department of Energy', value: 'Department of Energy' },
|
|
107
|
+
{ name: 'Department of Justice', value: 'Department of Justice' },
|
|
108
|
+
{ name: 'Department of Transportation', value: 'Department of Transportation' },
|
|
109
|
+
{ name: 'National Aeronautics and Space Administration', value: 'National Aeronautics and Space Administration' },
|
|
110
|
+
{ name: 'General Services Administration', value: 'General Services Administration' },
|
|
111
|
+
],
|
|
112
|
+
default: 'all',
|
|
113
|
+
displayOptions: {
|
|
114
|
+
show: {
|
|
115
|
+
operation: ['contracts', 'recompete', 'setAside', 'contractGrowth', 'forensicAudit', 'agencies', 'samOpportunities'],
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
description: 'Filter by federal agency',
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
displayName: 'Fiscal Year',
|
|
122
|
+
name: 'fiscalYear',
|
|
123
|
+
type: 'number',
|
|
124
|
+
default: 2024,
|
|
125
|
+
typeOptions: {
|
|
126
|
+
minValue: 2015,
|
|
127
|
+
maxValue: 2026,
|
|
128
|
+
},
|
|
129
|
+
displayOptions: {
|
|
130
|
+
show: {
|
|
131
|
+
operation: ['contracts', 'recompete', 'setAside', 'contractGrowth', 'forensicAudit', 'agencies'],
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
description: 'Federal fiscal year (October 1 - September 30)',
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
displayName: 'Keywords',
|
|
138
|
+
name: 'keywords',
|
|
139
|
+
type: 'string',
|
|
140
|
+
default: '',
|
|
141
|
+
displayOptions: {
|
|
142
|
+
show: {
|
|
143
|
+
operation: ['contracts', 'recompete', 'setAside', 'forensicAudit', 'samOpportunities'],
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
description: 'Search keywords (comma-separated)',
|
|
147
|
+
placeholder: 'cybersecurity, IT services',
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
displayName: 'NAICS Code',
|
|
151
|
+
name: 'naicsCode',
|
|
152
|
+
type: 'string',
|
|
153
|
+
default: '',
|
|
154
|
+
displayOptions: {
|
|
155
|
+
show: {
|
|
156
|
+
operation: ['contracts', 'setAside', 'samOpportunities'],
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
description: 'North American Industry Classification Code (e.g., 541512)',
|
|
160
|
+
placeholder: '541512',
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
displayName: 'Max Results',
|
|
164
|
+
name: 'maxResults',
|
|
165
|
+
type: 'number',
|
|
166
|
+
default: 50,
|
|
167
|
+
typeOptions: {
|
|
168
|
+
minValue: 1,
|
|
169
|
+
maxValue: 500,
|
|
170
|
+
},
|
|
171
|
+
displayOptions: {
|
|
172
|
+
show: {
|
|
173
|
+
operation: ['contracts', 'recompete', 'setAside', 'contractGrowth', 'forensicAudit', 'samOpportunities'],
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
description: 'Maximum number of results to return',
|
|
177
|
+
},
|
|
178
|
+
// ==========================================
|
|
179
|
+
// RECOMPETE RADAR OPTIONS
|
|
180
|
+
// ==========================================
|
|
181
|
+
{
|
|
182
|
+
displayName: 'Expiring Within (Days)',
|
|
183
|
+
name: 'expiringWithinDays',
|
|
184
|
+
type: 'number',
|
|
185
|
+
default: 180,
|
|
186
|
+
typeOptions: {
|
|
187
|
+
minValue: 30,
|
|
188
|
+
maxValue: 730,
|
|
189
|
+
},
|
|
190
|
+
displayOptions: {
|
|
191
|
+
show: {
|
|
192
|
+
operation: ['recompete'],
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
description: 'Find contracts expiring within this many days',
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
displayName: 'Minimum Award Amount',
|
|
199
|
+
name: 'minAwardAmount',
|
|
200
|
+
type: 'number',
|
|
201
|
+
default: 0,
|
|
202
|
+
displayOptions: {
|
|
203
|
+
show: {
|
|
204
|
+
operation: ['recompete', 'contracts'],
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
description: 'Minimum contract value in USD',
|
|
208
|
+
},
|
|
209
|
+
// ==========================================
|
|
210
|
+
// SET-ASIDE SCANNER OPTIONS
|
|
211
|
+
// ==========================================
|
|
212
|
+
{
|
|
213
|
+
displayName: 'Set-Aside Type',
|
|
214
|
+
name: 'setAsideType',
|
|
215
|
+
type: 'options',
|
|
216
|
+
options: [
|
|
217
|
+
{ name: 'All Set-Asides', value: 'all' },
|
|
218
|
+
{ name: '8(a) Business Development', value: '8a' },
|
|
219
|
+
{ name: 'HUBZone', value: 'hubzone' },
|
|
220
|
+
{ name: 'SDVOSB (Service-Disabled Veteran)', value: 'sdvosb' },
|
|
221
|
+
{ name: 'WOSB (Women-Owned)', value: 'wosb' },
|
|
222
|
+
{ name: 'EDWOSB (Economically Disadvantaged Women)', value: 'edwosb' },
|
|
223
|
+
{ name: 'Small Business Set-Aside', value: 'small_business' },
|
|
224
|
+
{ name: 'SDB (Small Disadvantaged Business)', value: 'sdb' },
|
|
225
|
+
],
|
|
226
|
+
default: 'all',
|
|
227
|
+
displayOptions: {
|
|
228
|
+
show: {
|
|
229
|
+
operation: ['setAside', 'samOpportunities'],
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
description: 'Filter by small business program',
|
|
233
|
+
},
|
|
234
|
+
// ==========================================
|
|
235
|
+
// CONTRACT GROWTH OPTIONS
|
|
236
|
+
// ==========================================
|
|
237
|
+
{
|
|
238
|
+
displayName: 'Minimum Growth Percentage',
|
|
239
|
+
name: 'minGrowthPercent',
|
|
240
|
+
type: 'number',
|
|
241
|
+
default: 200,
|
|
242
|
+
typeOptions: {
|
|
243
|
+
minValue: 100,
|
|
244
|
+
maxValue: 1000,
|
|
245
|
+
},
|
|
246
|
+
displayOptions: {
|
|
247
|
+
show: {
|
|
248
|
+
operation: ['contractGrowth'],
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
description: 'Flag contracts that grew by this percentage or more',
|
|
252
|
+
},
|
|
253
|
+
// ==========================================
|
|
254
|
+
// SAM.GOV OPTIONS
|
|
255
|
+
// ==========================================
|
|
256
|
+
{
|
|
257
|
+
displayName: 'SAM.gov API Key',
|
|
258
|
+
name: 'samGovApiKey',
|
|
259
|
+
type: 'string',
|
|
260
|
+
typeOptions: {
|
|
261
|
+
password: true,
|
|
262
|
+
},
|
|
263
|
+
default: '',
|
|
264
|
+
displayOptions: {
|
|
265
|
+
show: {
|
|
266
|
+
operation: ['samOpportunities', 'entityVerify'],
|
|
267
|
+
},
|
|
268
|
+
},
|
|
269
|
+
description: 'Your SAM.gov API key (get free at api.sam.gov)',
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
displayName: 'Notice Type',
|
|
273
|
+
name: 'samNoticeType',
|
|
274
|
+
type: 'options',
|
|
275
|
+
options: [
|
|
276
|
+
{ name: 'All Types', value: 'all' },
|
|
277
|
+
{ name: 'Solicitation (RFP/RFQ)', value: 'o' },
|
|
278
|
+
{ name: 'Presolicitation', value: 'p' },
|
|
279
|
+
{ name: 'Combined Synopsis/Solicitation', value: 'k' },
|
|
280
|
+
{ name: 'Sources Sought / RFI', value: 'r' },
|
|
281
|
+
{ name: 'Award Notice', value: 'a' },
|
|
282
|
+
],
|
|
283
|
+
default: 'all',
|
|
284
|
+
displayOptions: {
|
|
285
|
+
show: {
|
|
286
|
+
operation: ['samOpportunities'],
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
description: 'Filter SAM.gov notices by type',
|
|
290
|
+
},
|
|
291
|
+
// ==========================================
|
|
292
|
+
// ENTITY VERIFICATION
|
|
293
|
+
// ==========================================
|
|
294
|
+
{
|
|
295
|
+
displayName: 'Entity Name or UEI',
|
|
296
|
+
name: 'recipientName',
|
|
297
|
+
type: 'string',
|
|
298
|
+
default: '',
|
|
299
|
+
required: true,
|
|
300
|
+
displayOptions: {
|
|
301
|
+
show: {
|
|
302
|
+
operation: ['entityVerify'],
|
|
303
|
+
},
|
|
304
|
+
},
|
|
305
|
+
description: 'Company name or 12-character UEI to verify',
|
|
306
|
+
placeholder: 'ACME Corporation or ABC123DEF456',
|
|
307
|
+
},
|
|
308
|
+
// ==========================================
|
|
309
|
+
// GET STATUS
|
|
310
|
+
// ==========================================
|
|
311
|
+
{
|
|
312
|
+
displayName: 'Run ID',
|
|
313
|
+
name: 'runId',
|
|
314
|
+
type: 'string',
|
|
315
|
+
default: '',
|
|
316
|
+
required: true,
|
|
317
|
+
displayOptions: {
|
|
318
|
+
show: {
|
|
319
|
+
operation: ['getStatus'],
|
|
320
|
+
},
|
|
321
|
+
},
|
|
322
|
+
description: 'The ID of the actor run to check',
|
|
323
|
+
},
|
|
324
|
+
// ==========================================
|
|
325
|
+
// ADVANCED OPTIONS
|
|
326
|
+
// ==========================================
|
|
327
|
+
{
|
|
328
|
+
displayName: 'Wait for Completion',
|
|
329
|
+
name: 'waitForCompletion',
|
|
330
|
+
type: 'boolean',
|
|
331
|
+
default: true,
|
|
332
|
+
displayOptions: {
|
|
333
|
+
hide: {
|
|
334
|
+
operation: ['getStatus'],
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
description: 'Whether to wait for extraction to complete',
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
displayName: 'Advanced Options',
|
|
341
|
+
name: 'advancedOptions',
|
|
342
|
+
type: 'collection',
|
|
343
|
+
placeholder: 'Add Option',
|
|
344
|
+
default: {},
|
|
345
|
+
displayOptions: {
|
|
346
|
+
hide: {
|
|
347
|
+
operation: ['getStatus', 'entityVerify'],
|
|
348
|
+
},
|
|
349
|
+
},
|
|
350
|
+
options: [
|
|
351
|
+
{
|
|
352
|
+
displayName: 'Recipient Name',
|
|
353
|
+
name: 'recipientName',
|
|
354
|
+
type: 'string',
|
|
355
|
+
default: '',
|
|
356
|
+
description: 'Filter by contractor name',
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
displayName: 'Recipient State',
|
|
360
|
+
name: 'recipientState',
|
|
361
|
+
type: 'string',
|
|
362
|
+
default: '',
|
|
363
|
+
description: 'Filter by contractor state (2-letter code)',
|
|
364
|
+
placeholder: 'CO',
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
displayName: 'Place of Performance State',
|
|
368
|
+
name: 'placeOfPerformanceState',
|
|
369
|
+
type: 'string',
|
|
370
|
+
default: '',
|
|
371
|
+
description: 'Filter by work location state',
|
|
372
|
+
placeholder: 'CO',
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
displayName: 'PSC Code',
|
|
376
|
+
name: 'pscCode',
|
|
377
|
+
type: 'string',
|
|
378
|
+
default: '',
|
|
379
|
+
description: 'Product/Service Code filter',
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
displayName: 'Enable Forensic Flags',
|
|
383
|
+
name: 'enableForensicFlags',
|
|
384
|
+
type: 'boolean',
|
|
385
|
+
default: true,
|
|
386
|
+
description: 'Whether to analyze for discrepancies and anomalies',
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
displayName: 'Trace Sub-Awards',
|
|
390
|
+
name: 'traceSubAwards',
|
|
391
|
+
type: 'boolean',
|
|
392
|
+
default: false,
|
|
393
|
+
description: 'Whether to extract prime-to-sub contractor relationships',
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
displayName: 'Timeout (seconds)',
|
|
397
|
+
name: 'timeout',
|
|
398
|
+
type: 'number',
|
|
399
|
+
default: 300,
|
|
400
|
+
description: 'Maximum time to wait for completion',
|
|
401
|
+
},
|
|
402
|
+
],
|
|
403
|
+
},
|
|
404
|
+
],
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
async execute() {
|
|
408
|
+
const items = this.getInputData();
|
|
409
|
+
const returnData = [];
|
|
410
|
+
const operation = this.getNodeParameter('operation', 0);
|
|
411
|
+
const credentials = await this.getCredentials('apifyApi');
|
|
412
|
+
const baseUrl = 'https://api.apify.com/v2';
|
|
413
|
+
const actorId = 'ai_solutionist~federal-spending-forensic-api';
|
|
414
|
+
for (let i = 0; i < items.length; i++) {
|
|
415
|
+
try {
|
|
416
|
+
if (operation === 'getStatus') {
|
|
417
|
+
const runId = this.getNodeParameter('runId', i);
|
|
418
|
+
const response = await this.helpers.httpRequest({
|
|
419
|
+
method: 'GET',
|
|
420
|
+
url: `${baseUrl}/actor-runs/${runId}`,
|
|
421
|
+
headers: {
|
|
422
|
+
Authorization: `Bearer ${credentials.apiToken}`,
|
|
423
|
+
},
|
|
424
|
+
json: true,
|
|
425
|
+
});
|
|
426
|
+
returnData.push({
|
|
427
|
+
json: {
|
|
428
|
+
runId,
|
|
429
|
+
status: response.data.status,
|
|
430
|
+
startedAt: response.data.startedAt,
|
|
431
|
+
finishedAt: response.data.finishedAt,
|
|
432
|
+
datasetId: response.data.defaultDatasetId,
|
|
433
|
+
isFinished: ['SUCCEEDED', 'FAILED', 'ABORTED', 'TIMED-OUT'].includes(response.data.status),
|
|
434
|
+
},
|
|
435
|
+
});
|
|
436
|
+
continue;
|
|
437
|
+
}
|
|
438
|
+
// Build input payload for actor
|
|
439
|
+
const waitForCompletion = this.getNodeParameter('waitForCompletion', i);
|
|
440
|
+
const advancedOptions = this.getNodeParameter('advancedOptions', i, {});
|
|
441
|
+
const input = {
|
|
442
|
+
searchMode: operation,
|
|
443
|
+
maxResults: this.getNodeParameter('maxResults', i, 50),
|
|
444
|
+
enableForensicFlags: advancedOptions.enableForensicFlags !== false,
|
|
445
|
+
};
|
|
446
|
+
// Add common parameters
|
|
447
|
+
if (['contracts', 'recompete', 'setAside', 'contractGrowth', 'forensicAudit', 'agencies', 'samOpportunities'].includes(operation)) {
|
|
448
|
+
const agency = this.getNodeParameter('agency', i, 'all');
|
|
449
|
+
if (agency !== 'all') {
|
|
450
|
+
input.agency = agency;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
if (['contracts', 'recompete', 'setAside', 'contractGrowth', 'forensicAudit', 'agencies'].includes(operation)) {
|
|
454
|
+
input.fiscalYear = this.getNodeParameter('fiscalYear', i, 2024);
|
|
455
|
+
}
|
|
456
|
+
if (['contracts', 'recompete', 'setAside', 'forensicAudit', 'samOpportunities'].includes(operation)) {
|
|
457
|
+
const keywords = this.getNodeParameter('keywords', i, '');
|
|
458
|
+
if (keywords) {
|
|
459
|
+
input.keywords = keywords;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
if (['contracts', 'setAside', 'samOpportunities'].includes(operation)) {
|
|
463
|
+
const naicsCode = this.getNodeParameter('naicsCode', i, '');
|
|
464
|
+
if (naicsCode) {
|
|
465
|
+
input.naicsCode = naicsCode;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
// Operation-specific parameters
|
|
469
|
+
if (operation === 'recompete') {
|
|
470
|
+
input.expiringWithinDays = this.getNodeParameter('expiringWithinDays', i, 180);
|
|
471
|
+
const minAmount = this.getNodeParameter('minAwardAmount', i, 0);
|
|
472
|
+
if (minAmount > 0) {
|
|
473
|
+
input.minAwardAmount = minAmount;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
if (operation === 'setAside' || operation === 'samOpportunities') {
|
|
477
|
+
const setAsideType = this.getNodeParameter('setAsideType', i, 'all');
|
|
478
|
+
if (setAsideType !== 'all') {
|
|
479
|
+
input.setAsideType = setAsideType;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
if (operation === 'contractGrowth') {
|
|
483
|
+
input.minGrowthPercent = this.getNodeParameter('minGrowthPercent', i, 200);
|
|
484
|
+
}
|
|
485
|
+
if (operation === 'samOpportunities' || operation === 'entityVerify') {
|
|
486
|
+
const samKey = this.getNodeParameter('samGovApiKey', i, '');
|
|
487
|
+
if (samKey) {
|
|
488
|
+
input.samGovApiKey = samKey;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
if (operation === 'samOpportunities') {
|
|
492
|
+
const noticeType = this.getNodeParameter('samNoticeType', i, 'all');
|
|
493
|
+
if (noticeType !== 'all') {
|
|
494
|
+
input.samNoticeType = noticeType;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
if (operation === 'entityVerify') {
|
|
498
|
+
input.recipientName = this.getNodeParameter('recipientName', i);
|
|
499
|
+
}
|
|
500
|
+
// Add advanced options
|
|
501
|
+
if (advancedOptions.recipientName) {
|
|
502
|
+
input.recipientName = advancedOptions.recipientName;
|
|
503
|
+
}
|
|
504
|
+
if (advancedOptions.recipientState) {
|
|
505
|
+
input.recipientState = advancedOptions.recipientState;
|
|
506
|
+
}
|
|
507
|
+
if (advancedOptions.placeOfPerformanceState) {
|
|
508
|
+
input.placeOfPerformanceState = advancedOptions.placeOfPerformanceState;
|
|
509
|
+
}
|
|
510
|
+
if (advancedOptions.pscCode) {
|
|
511
|
+
input.pscCode = advancedOptions.pscCode;
|
|
512
|
+
}
|
|
513
|
+
if (advancedOptions.traceSubAwards) {
|
|
514
|
+
input.traceSubAwards = advancedOptions.traceSubAwards;
|
|
515
|
+
}
|
|
516
|
+
// Start the actor run
|
|
517
|
+
const startResponse = await this.helpers.httpRequest({
|
|
518
|
+
method: 'POST',
|
|
519
|
+
url: `${baseUrl}/acts/${actorId}/runs`,
|
|
520
|
+
headers: {
|
|
521
|
+
Authorization: `Bearer ${credentials.apiToken}`,
|
|
522
|
+
'Content-Type': 'application/json',
|
|
523
|
+
},
|
|
524
|
+
body: input,
|
|
525
|
+
json: true,
|
|
526
|
+
});
|
|
527
|
+
const runId = startResponse.data.id;
|
|
528
|
+
const datasetId = startResponse.data.defaultDatasetId;
|
|
529
|
+
if (!waitForCompletion) {
|
|
530
|
+
returnData.push({
|
|
531
|
+
json: {
|
|
532
|
+
success: true,
|
|
533
|
+
status: 'RUNNING',
|
|
534
|
+
runId,
|
|
535
|
+
datasetId,
|
|
536
|
+
operation,
|
|
537
|
+
message: 'Extraction started. Use "Get Run Status" to check progress.',
|
|
538
|
+
},
|
|
539
|
+
});
|
|
540
|
+
continue;
|
|
541
|
+
}
|
|
542
|
+
// Poll for completion
|
|
543
|
+
const timeout = (advancedOptions.timeout || 300) * 1000;
|
|
544
|
+
const startTime = Date.now();
|
|
545
|
+
let status = 'RUNNING';
|
|
546
|
+
while (status === 'RUNNING' && Date.now() - startTime < timeout) {
|
|
547
|
+
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
548
|
+
const statusResponse = await this.helpers.httpRequest({
|
|
549
|
+
method: 'GET',
|
|
550
|
+
url: `${baseUrl}/actor-runs/${runId}`,
|
|
551
|
+
headers: {
|
|
552
|
+
Authorization: `Bearer ${credentials.apiToken}`,
|
|
553
|
+
},
|
|
554
|
+
json: true,
|
|
555
|
+
});
|
|
556
|
+
status = statusResponse.data.status;
|
|
557
|
+
}
|
|
558
|
+
if (status !== 'SUCCEEDED') {
|
|
559
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Extraction failed with status: ${status}`, { itemIndex: i });
|
|
560
|
+
}
|
|
561
|
+
// Fetch results
|
|
562
|
+
const resultsResponse = await this.helpers.httpRequest({
|
|
563
|
+
method: 'GET',
|
|
564
|
+
url: `${baseUrl}/datasets/${datasetId}/items`,
|
|
565
|
+
headers: {
|
|
566
|
+
Authorization: `Bearer ${credentials.apiToken}`,
|
|
567
|
+
},
|
|
568
|
+
json: true,
|
|
569
|
+
});
|
|
570
|
+
const results = Array.isArray(resultsResponse) ? resultsResponse : [resultsResponse];
|
|
571
|
+
// Return each result as a separate item
|
|
572
|
+
for (const result of results) {
|
|
573
|
+
returnData.push({
|
|
574
|
+
json: {
|
|
575
|
+
...result,
|
|
576
|
+
_operation: operation,
|
|
577
|
+
_runId: runId,
|
|
578
|
+
_datasetId: datasetId,
|
|
579
|
+
},
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
catch (error) {
|
|
584
|
+
if (this.continueOnFail()) {
|
|
585
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
586
|
+
returnData.push({
|
|
587
|
+
json: {
|
|
588
|
+
error: errorMessage,
|
|
589
|
+
},
|
|
590
|
+
pairedItem: { item: i },
|
|
591
|
+
});
|
|
592
|
+
continue;
|
|
593
|
+
}
|
|
594
|
+
throw error;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
return [returnData];
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
exports.FederalSpendingForensic = FederalSpendingForensic;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="bgGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
4
|
+
<stop offset="0%" style="stop-color:#1a237e;stop-opacity:1" />
|
|
5
|
+
<stop offset="100%" style="stop-color:#0d47a1;stop-opacity:1" />
|
|
6
|
+
</linearGradient>
|
|
7
|
+
<linearGradient id="goldGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
8
|
+
<stop offset="0%" style="stop-color:#ffd700;stop-opacity:1" />
|
|
9
|
+
<stop offset="100%" style="stop-color:#ffb300;stop-opacity:1" />
|
|
10
|
+
</linearGradient>
|
|
11
|
+
</defs>
|
|
12
|
+
|
|
13
|
+
<!-- Background circle -->
|
|
14
|
+
<circle cx="50" cy="50" r="48" fill="url(#bgGrad)" stroke="#0d47a1" stroke-width="2"/>
|
|
15
|
+
|
|
16
|
+
<!-- Capitol building dome -->
|
|
17
|
+
<path d="M50 18 L50 25 M35 35 Q50 20 65 35 L65 45 L35 45 Z"
|
|
18
|
+
fill="white" stroke="white" stroke-width="1"/>
|
|
19
|
+
|
|
20
|
+
<!-- Building columns -->
|
|
21
|
+
<rect x="30" y="45" width="40" height="25" fill="white"/>
|
|
22
|
+
<rect x="33" y="48" width="4" height="20" fill="url(#bgGrad)"/>
|
|
23
|
+
<rect x="40" y="48" width="4" height="20" fill="url(#bgGrad)"/>
|
|
24
|
+
<rect x="48" y="48" width="4" height="20" fill="url(#bgGrad)"/>
|
|
25
|
+
<rect x="56" y="48" width="4" height="20" fill="url(#bgGrad)"/>
|
|
26
|
+
<rect x="63" y="48" width="4" height="20" fill="url(#bgGrad)"/>
|
|
27
|
+
|
|
28
|
+
<!-- Base -->
|
|
29
|
+
<rect x="25" y="68" width="50" height="5" fill="white"/>
|
|
30
|
+
|
|
31
|
+
<!-- Magnifying glass -->
|
|
32
|
+
<circle cx="68" cy="68" r="15" fill="none" stroke="url(#goldGrad)" stroke-width="4"/>
|
|
33
|
+
<line x1="79" y1="79" x2="88" y2="88" stroke="url(#goldGrad)" stroke-width="4" stroke-linecap="round"/>
|
|
34
|
+
|
|
35
|
+
<!-- Dollar sign inside magnifier -->
|
|
36
|
+
<text x="68" y="73" font-family="Arial, sans-serif" font-size="16" font-weight="bold"
|
|
37
|
+
fill="url(#goldGrad)" text-anchor="middle">$</text>
|
|
38
|
+
|
|
39
|
+
<!-- Alert indicator -->
|
|
40
|
+
<circle cx="78" cy="22" r="10" fill="#f44336"/>
|
|
41
|
+
<text x="78" y="27" font-family="Arial, sans-serif" font-size="14" font-weight="bold"
|
|
42
|
+
fill="white" text-anchor="middle">!</text>
|
|
43
|
+
</svg>
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "n8n-nodes-federal-spending-forensic-api",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "n8n community node for Federal Spending Forensic API - Uncover $195B USASpending blind spot with AI-powered forensic intelligence",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"n8n-community-node-package",
|
|
7
|
+
"n8n",
|
|
8
|
+
"federal-contracts",
|
|
9
|
+
"government-spending",
|
|
10
|
+
"usaspending",
|
|
11
|
+
"sam-gov",
|
|
12
|
+
"b2g",
|
|
13
|
+
"procurement",
|
|
14
|
+
"forensic",
|
|
15
|
+
"apify",
|
|
16
|
+
"recompete",
|
|
17
|
+
"set-aside",
|
|
18
|
+
"small-business"
|
|
19
|
+
],
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"homepage": "https://jasonpellerin.com",
|
|
22
|
+
"author": {
|
|
23
|
+
"name": "Jason Pellerin",
|
|
24
|
+
"email": "jason@jasonpellerin.com",
|
|
25
|
+
"url": "https://jasonpellerinfreelance.com"
|
|
26
|
+
},
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/ai-solutionist/n8n-nodes-federal-spending-forensic-api.git"
|
|
30
|
+
},
|
|
31
|
+
"main": "index.js",
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsc && gulp build:icons",
|
|
34
|
+
"dev": "tsc --watch",
|
|
35
|
+
"format": "prettier nodes credentials --write",
|
|
36
|
+
"lint": "eslint nodes credentials package.json",
|
|
37
|
+
"lintfix": "eslint nodes credentials package.json --fix",
|
|
38
|
+
"prepublishOnly": "npm run build"
|
|
39
|
+
},
|
|
40
|
+
"files": [
|
|
41
|
+
"dist"
|
|
42
|
+
],
|
|
43
|
+
"n8n": {
|
|
44
|
+
"n8nNodesApiVersion": 1,
|
|
45
|
+
"credentials": [
|
|
46
|
+
"dist/credentials/ApifyApi.credentials.js"
|
|
47
|
+
],
|
|
48
|
+
"nodes": [
|
|
49
|
+
"dist/nodes/FederalSpendingForensic/FederalSpendingForensic.node.js"
|
|
50
|
+
]
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@types/node": "^20.10.0",
|
|
54
|
+
"@typescript-eslint/parser": "^6.0.0",
|
|
55
|
+
"eslint": "^8.56.0",
|
|
56
|
+
"gulp": "^4.0.2",
|
|
57
|
+
"n8n-workflow": "^1.0.0",
|
|
58
|
+
"prettier": "^3.1.0",
|
|
59
|
+
"typescript": "^5.3.0"
|
|
60
|
+
},
|
|
61
|
+
"peerDependencies": {
|
|
62
|
+
"n8n-workflow": "*"
|
|
63
|
+
}
|
|
64
|
+
}
|