Initial release — Crucix Intelligence Engine v2.0.0
26-source OSINT intelligence engine with live Jarvis dashboard, auto-refresh via SSE, optional LLM layer (4 providers), delta/memory system, and Telegram breaking news alerts. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
119
apis/sources/usaspending.mjs
Normal file
119
apis/sources/usaspending.mjs
Normal file
@@ -0,0 +1,119 @@
|
||||
// USAspending — Federal spending, defense contracts, procurement signals
|
||||
// No auth required. Updated daily.
|
||||
|
||||
import { safeFetch, daysAgo } from '../utils/fetch.mjs';
|
||||
|
||||
const BASE = 'https://api.usaspending.gov/api/v2';
|
||||
|
||||
// Award type codes — required by the spending_by_award endpoint
|
||||
// Contracts: A=BPA Call, B=Purchase Order, C=Delivery Order, D=Definitive Contract
|
||||
// Grants: 02=Block Grant, 03=Formula Grant, 04=Project Grant, 05=Cooperative Agreement
|
||||
// Direct payments: 06=Direct Payment (unrestricted), 07=Direct Payment (specified use)
|
||||
// Loans: 08=Direct Loan, 09=Guaranteed/Insured Loan
|
||||
// IDVs: IDV_A=GWAC, IDV_B=IDC, IDV_B_A=IDC / IDV, IDV_B_B=IDC / Multiple Award,
|
||||
// IDV_B_C=IDC / FSS, IDV_C=FSS, IDV_D=BOA, IDV_E=BPA
|
||||
const CONTRACT_CODES = ['A', 'B', 'C', 'D'];
|
||||
const ALL_AWARD_CODES = ['A', 'B', 'C', 'D', '02', '03', '04', '05', '06', '07', '08', '09'];
|
||||
|
||||
// Search recent awards/contracts
|
||||
export async function searchAwards(opts = {}) {
|
||||
const {
|
||||
keywords = ['defense', 'military'],
|
||||
limit = 20,
|
||||
sortField = 'Award Amount',
|
||||
order = 'desc',
|
||||
awardTypeCodes = CONTRACT_CODES,
|
||||
days = 30,
|
||||
} = opts;
|
||||
|
||||
const body = {
|
||||
filters: {
|
||||
keywords,
|
||||
time_period: [{ start_date: daysAgo(days), end_date: daysAgo(0) }],
|
||||
award_type_codes: awardTypeCodes,
|
||||
},
|
||||
fields: [
|
||||
'Award ID',
|
||||
'Recipient Name',
|
||||
'Award Amount',
|
||||
'Description',
|
||||
'Awarding Agency',
|
||||
'Start Date',
|
||||
'Award Type',
|
||||
],
|
||||
limit,
|
||||
page: 1,
|
||||
sort: sortField,
|
||||
order,
|
||||
};
|
||||
|
||||
try {
|
||||
const controller = new AbortController();
|
||||
const timer = setTimeout(() => controller.abort(), 15000);
|
||||
const res = await fetch(`${BASE}/search/spending_by_award/`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(body),
|
||||
signal: controller.signal,
|
||||
});
|
||||
clearTimeout(timer);
|
||||
if (!res.ok) {
|
||||
const errBody = await res.text().catch(() => '');
|
||||
return { error: `HTTP ${res.status}: ${errBody.slice(0, 300)}`, results: [] };
|
||||
}
|
||||
return res.json();
|
||||
} catch (e) {
|
||||
return { error: e.message, results: [] };
|
||||
}
|
||||
}
|
||||
|
||||
// Get top agencies by spending
|
||||
export async function getAgencySpending() {
|
||||
return safeFetch(`${BASE}/references/toptier_agencies/`);
|
||||
}
|
||||
|
||||
// Search for defense-specific spending
|
||||
export async function getDefenseSpending(days = 30) {
|
||||
return searchAwards({
|
||||
keywords: ['defense', 'military', 'missile', 'ammunition', 'aircraft', 'naval'],
|
||||
limit: 20,
|
||||
sortField: 'Award Amount',
|
||||
order: 'desc',
|
||||
awardTypeCodes: CONTRACT_CODES,
|
||||
days,
|
||||
});
|
||||
}
|
||||
|
||||
// Briefing
|
||||
export async function briefing() {
|
||||
const [defense, agencies] = await Promise.all([
|
||||
getDefenseSpending(14),
|
||||
getAgencySpending(),
|
||||
]);
|
||||
|
||||
return {
|
||||
source: 'USAspending',
|
||||
timestamp: new Date().toISOString(),
|
||||
recentDefenseContracts: (defense?.results || []).slice(0, 10).map(r => ({
|
||||
awardId: r['Award ID'],
|
||||
recipient: r['Recipient Name'],
|
||||
amount: r['Award Amount'],
|
||||
description: r['Description'],
|
||||
agency: r['Awarding Agency'],
|
||||
date: r['Start Date'],
|
||||
type: r['Award Type'],
|
||||
})),
|
||||
topAgencies: (agencies?.results || []).slice(0, 10).map(a => ({
|
||||
name: a.agency_name,
|
||||
budget: a.budget_authority_amount,
|
||||
obligations: a.obligated_amount,
|
||||
outlays: a.outlay_amount,
|
||||
})),
|
||||
...(defense?.error ? { defenseError: defense.error } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
if (process.argv[1]?.endsWith('usaspending.mjs')) {
|
||||
const data = await briefing();
|
||||
console.log(JSON.stringify(data, null, 2));
|
||||
}
|
||||
Reference in New Issue
Block a user