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>
120 lines
3.5 KiB
JavaScript
120 lines
3.5 KiB
JavaScript
// 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));
|
|
}
|