opensentinel 2.1.1 → 3.1.1
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 +354 -283
- package/dist/archiver-AVNBYCKQ.js +15340 -0
- package/dist/archiver-AVNBYCKQ.js.map +1 -0
- package/dist/audit-logger-OBPR7CRO.js +22 -0
- package/dist/auth-UOX5K2BE.js +18 -0
- package/dist/autonomy-ZXDBDQUJ.js +86 -0
- package/dist/autonomy-ZXDBDQUJ.js.map +1 -0
- package/dist/aws-s3-Q4LLZZPD.js +146 -0
- package/dist/aws-s3-Q4LLZZPD.js.map +1 -0
- package/dist/backup-restore-PZ7CYYB7.js +16 -0
- package/dist/blocks-R3PODY47.js +23 -0
- package/dist/bot-QRARP4UN.js +36 -0
- package/dist/brain-7XLLM3KC.js +56 -0
- package/dist/camera-monitor-M5CYKUU4.js +335 -0
- package/dist/camera-monitor-M5CYKUU4.js.map +1 -0
- package/dist/{charts-MMXM6BWW.js → charts-V7ARZNKF.js} +2 -2
- package/dist/chunk-22VGGA7S.js +330 -0
- package/dist/chunk-22VGGA7S.js.map +1 -0
- package/dist/chunk-35WYTA3C.js +382 -0
- package/dist/chunk-35WYTA3C.js.map +1 -0
- package/dist/chunk-3E2PSU2C.js +146 -0
- package/dist/chunk-3E2PSU2C.js.map +1 -0
- package/dist/{chunk-L3F43VPB.js → chunk-4GLYY4NN.js} +2 -2
- package/dist/{chunk-L3F43VPB.js.map → chunk-4GLYY4NN.js.map} +1 -1
- package/dist/{chunk-L3PDU3XN.js → chunk-4UOE5TUZ.js} +4 -4
- package/dist/{chunk-6SNHU3CY.js → chunk-66OJ3WB4.js} +2 -2
- package/dist/chunk-6KONMXQ6.js +297 -0
- package/dist/chunk-6KONMXQ6.js.map +1 -0
- package/dist/chunk-6PMVAAA7.js +196 -0
- package/dist/chunk-6PMVAAA7.js.map +1 -0
- package/dist/chunk-766ASQWE.js +32620 -0
- package/dist/chunk-766ASQWE.js.map +1 -0
- package/dist/chunk-7WQO5J2M.js +29 -0
- package/dist/chunk-7WQO5J2M.js.map +1 -0
- package/dist/chunk-APHSRMBS.js +148 -0
- package/dist/chunk-APHSRMBS.js.map +1 -0
- package/dist/{chunk-4LVWXUNC.js → chunk-AYUKPTSM.js} +57 -39
- package/dist/chunk-AYUKPTSM.js.map +1 -0
- package/dist/chunk-BIPYADGB.js +84 -0
- package/dist/chunk-BIPYADGB.js.map +1 -0
- package/dist/chunk-BRBWNV65.js +457 -0
- package/dist/chunk-BRBWNV65.js.map +1 -0
- package/dist/chunk-BXZ6EA52.js +382 -0
- package/dist/chunk-BXZ6EA52.js.map +1 -0
- package/dist/chunk-EVE7MIIY.js +290 -0
- package/dist/chunk-EVE7MIIY.js.map +1 -0
- package/dist/chunk-F3TTNID2.js +138 -0
- package/dist/chunk-F3TTNID2.js.map +1 -0
- package/dist/chunk-H5RQOFO2.js +190 -0
- package/dist/chunk-H5RQOFO2.js.map +1 -0
- package/dist/chunk-HN3F4WSW.js +145 -0
- package/dist/chunk-HN3F4WSW.js.map +1 -0
- package/dist/{chunk-6DRDKB45.js → chunk-I6BDYQIG.js} +20 -9
- package/dist/chunk-I6BDYQIG.js.map +1 -0
- package/dist/chunk-IZJMVV7O.js +347 -0
- package/dist/chunk-IZJMVV7O.js.map +1 -0
- package/dist/chunk-KM22GV7G.js +211 -0
- package/dist/chunk-KM22GV7G.js.map +1 -0
- package/dist/chunk-MGFBLVR7.js +103 -0
- package/dist/chunk-MGFBLVR7.js.map +1 -0
- package/dist/chunk-MQJ2ECQT.js +228 -0
- package/dist/chunk-MQJ2ECQT.js.map +1 -0
- package/dist/{chunk-F6QUZQGI.js → chunk-MXAPLSJ5.js} +2 -2
- package/dist/{chunk-GK3E2I7A.js → chunk-NHMBTUMW.js} +2 -2
- package/dist/chunk-NPRTSZIF.js +131 -0
- package/dist/chunk-NPRTSZIF.js.map +1 -0
- package/dist/chunk-O7IH7JTI.js +1898 -0
- package/dist/chunk-O7IH7JTI.js.map +1 -0
- package/dist/chunk-OCVQGBJK.js +293 -0
- package/dist/chunk-OCVQGBJK.js.map +1 -0
- package/dist/chunk-P6QINGFL.js +332 -0
- package/dist/chunk-P6QINGFL.js.map +1 -0
- package/dist/chunk-PHDZKPNE.js +91 -0
- package/dist/chunk-PHDZKPNE.js.map +1 -0
- package/dist/chunk-PLDDJCW6.js +49 -0
- package/dist/chunk-PTGTGXV2.js +164 -0
- package/dist/chunk-PTGTGXV2.js.map +1 -0
- package/dist/chunk-REMIY4U2.js +171 -0
- package/dist/chunk-REMIY4U2.js.map +1 -0
- package/dist/chunk-RZ4YESBG.js +141 -0
- package/dist/chunk-RZ4YESBG.js.map +1 -0
- package/dist/chunk-SAX5MHK4.js +111 -0
- package/dist/chunk-SAX5MHK4.js.map +1 -0
- package/dist/{chunk-GVJVEWHI.js → chunk-SJSUSJ47.js} +2 -2
- package/dist/chunk-SPPMCAKG.js +777 -0
- package/dist/chunk-SPPMCAKG.js.map +1 -0
- package/dist/chunk-SVAPX2XN.js +2441 -0
- package/dist/chunk-SVAPX2XN.js.map +1 -0
- package/dist/chunk-TVEWKIK3.js +452 -0
- package/dist/chunk-TVEWKIK3.js.map +1 -0
- package/dist/{chunk-HH2HBTQM.js → chunk-TYAGMJNV.js} +5 -5
- package/dist/{chunk-JXUP2X7V.js → chunk-VEHFVBLI.js} +2 -2
- package/dist/chunk-VNX5GMTN.js +128 -0
- package/dist/chunk-VNX5GMTN.js.map +1 -0
- package/dist/chunk-VRD5CYRL.js +1568 -0
- package/dist/chunk-VRD5CYRL.js.map +1 -0
- package/dist/chunk-WLUHNG6X.js +122 -0
- package/dist/chunk-WLUHNG6X.js.map +1 -0
- package/dist/chunk-WRAKK6K6.js +265 -0
- package/dist/chunk-WRAKK6K6.js.map +1 -0
- package/dist/chunk-XKYRH4FM.js +681 -0
- package/dist/chunk-XKYRH4FM.js.map +1 -0
- package/dist/{chunk-GUBEEYDW.js → chunk-XMCVRVTF.js} +2 -2
- package/dist/{chunk-GUBEEYDW.js.map → chunk-XMCVRVTF.js.map} +1 -1
- package/dist/chunk-ZLZKF2PM.js +310 -0
- package/dist/chunk-ZLZKF2PM.js.map +1 -0
- package/dist/cli.js +5 -1
- package/dist/cli.js.map +1 -1
- package/dist/client-ZQSFPMOB.js +21 -0
- package/dist/clipboard-manager-TEO2GEDN.js +24 -0
- package/dist/commands/setup.js +3 -3
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/start.js +3 -3
- package/dist/commands/status.js +2 -2
- package/dist/commands/stop.js +2 -2
- package/dist/commands/utils.js +2 -2
- package/dist/cron-explain-HHQKPD3M.js +16 -0
- package/dist/crypto-4AP47IKC.js +14 -0
- package/dist/crypto-4AP47IKC.js.map +1 -0
- package/dist/databases-37X4CI2Y.js +21 -0
- package/dist/databases-37X4CI2Y.js.map +1 -0
- package/dist/discord-B3HUPGQ6.js +70 -0
- package/dist/discord-B3HUPGQ6.js.map +1 -0
- package/dist/dist-UISMLMFN.js +21847 -0
- package/dist/dist-UISMLMFN.js.map +1 -0
- package/dist/email-K7LO2IPB.js +268 -0
- package/dist/email-K7LO2IPB.js.map +1 -0
- package/dist/enhanced-retrieval-DNLLEM4Z.js +753 -0
- package/dist/enhanced-retrieval-DNLLEM4Z.js.map +1 -0
- package/dist/enrichment-pipeline-MNHNW65K.js +13 -0
- package/dist/enrichment-pipeline-MNHNW65K.js.map +1 -0
- package/dist/entity-resolution-Y3IUWEAT.js +24 -0
- package/dist/entity-resolution-Y3IUWEAT.js.map +1 -0
- package/dist/env-IWXUVTCB.js +12 -0
- package/dist/env-IWXUVTCB.js.map +1 -0
- package/dist/google-workspace-DKWUVNGC.js +169 -0
- package/dist/google-workspace-DKWUVNGC.js.map +1 -0
- package/dist/hash-tool-ULQYD7B5.js +22 -0
- package/dist/hash-tool-ULQYD7B5.js.map +1 -0
- package/dist/heartbeat-monitor-GCISLXI3.js +22 -0
- package/dist/heartbeat-monitor-GCISLXI3.js.map +1 -0
- package/dist/image-generation-OSU7FP6F.js +486 -0
- package/dist/image-generation-OSU7FP6F.js.map +1 -0
- package/dist/imessage-NGA2XF2V.js +35 -0
- package/dist/imessage-NGA2XF2V.js.map +1 -0
- package/dist/inbox-summarizer-NRI4S7IF.js +47 -0
- package/dist/inbox-summarizer-NRI4S7IF.js.map +1 -0
- package/dist/incident-response-C5J7Q6DT.js +244 -0
- package/dist/incident-response-C5J7Q6DT.js.map +1 -0
- package/dist/inventory-manager-352OHXWD.js +24 -0
- package/dist/inventory-manager-352OHXWD.js.map +1 -0
- package/dist/jira-GSGDBMIG.js +199 -0
- package/dist/jira-GSGDBMIG.js.map +1 -0
- package/dist/json-tool-QE2SYHEG.js +26 -0
- package/dist/json-tool-QE2SYHEG.js.map +1 -0
- package/dist/key-rotation-DPHU4ZTB.js +18 -0
- package/dist/key-rotation-DPHU4ZTB.js.map +1 -0
- package/dist/lib.d.ts +603 -11
- package/dist/lib.js +161 -35
- package/dist/lib.js.map +1 -1
- package/dist/mailchimp-KKNF6QJ7.js +152 -0
- package/dist/mailchimp-KKNF6QJ7.js.map +1 -0
- package/dist/matrix-QVHG76I7.js +279 -0
- package/dist/matrix-QVHG76I7.js.map +1 -0
- package/dist/{mcp-LS7Q3Z5W.js → mcp-3JI6W7ZE.js} +3 -3
- package/dist/mcp-3JI6W7ZE.js.map +1 -0
- package/dist/microsoft365-UCBKJHNX.js +164 -0
- package/dist/microsoft365-UCBKJHNX.js.map +1 -0
- package/dist/ocr-AC7NPX33.js +22 -0
- package/dist/ocr-AC7NPX33.js.map +1 -0
- package/dist/ollama-BOAMSPLJ.js +8 -0
- package/dist/ollama-BOAMSPLJ.js.map +1 -0
- package/dist/pages-MI523RB7.js +26 -0
- package/dist/pages-MI523RB7.js.map +1 -0
- package/dist/pair-JDFTERIK.js +24 -0
- package/dist/pair-JDFTERIK.js.map +1 -0
- package/dist/pairing-IFQYCPNS.js +10 -0
- package/dist/pairing-IFQYCPNS.js.map +1 -0
- package/dist/pdf-ALQVOEJR.js +17 -0
- package/dist/pdf-ALQVOEJR.js.map +1 -0
- package/dist/presentations-DSV5IHG5.js +1002 -0
- package/dist/presentations-DSV5IHG5.js.map +1 -0
- package/dist/prometheus-JNT2BD4L.js +10 -0
- package/dist/prometheus-JNT2BD4L.js.map +1 -0
- package/dist/providers-J4LYPHDR.js +19 -0
- package/dist/providers-J4LYPHDR.js.map +1 -0
- package/dist/qr-code-WIX4PB4U.js +16 -0
- package/dist/qr-code-WIX4PB4U.js.map +1 -0
- package/dist/quickbooks-XB4NII2S.js +190 -0
- package/dist/quickbooks-XB4NII2S.js.map +1 -0
- package/dist/regex-tool-W4ABRKGK.js +24 -0
- package/dist/regex-tool-W4ABRKGK.js.map +1 -0
- package/dist/scheduler-VK4WFERV.js +63 -0
- package/dist/scheduler-VK4WFERV.js.map +1 -0
- package/dist/search-BCLBO5E3.js +25 -0
- package/dist/search-BCLBO5E3.js.map +1 -0
- package/dist/sendgrid-RNXCAFKM.js +152 -0
- package/dist/sendgrid-RNXCAFKM.js.map +1 -0
- package/dist/shopify-NCXYJB4R.js +171 -0
- package/dist/shopify-NCXYJB4R.js.map +1 -0
- package/dist/signal-6CGDFYL2.js +35 -0
- package/dist/signal-6CGDFYL2.js.map +1 -0
- package/dist/slack-IZQWIKOH.js +75 -0
- package/dist/slack-IZQWIKOH.js.map +1 -0
- package/dist/sms-M3JIOTCW.js +23 -0
- package/dist/sms-M3JIOTCW.js.map +1 -0
- package/dist/{src-K7GASHRH.js → src-VYUE6LRA.js} +138 -32
- package/dist/src-VYUE6LRA.js.map +1 -0
- package/dist/stocks-XXWBPOCU.js +14 -0
- package/dist/stocks-XXWBPOCU.js.map +1 -0
- package/dist/text-transform-6SGUA5Z4.js +22 -0
- package/dist/text-transform-6SGUA5Z4.js.map +1 -0
- package/dist/tools-2RLEI2N6.js +38 -0
- package/dist/tools-2RLEI2N6.js.map +1 -0
- package/dist/tunnel-IWMXUML4.js +301 -0
- package/dist/tunnel-IWMXUML4.js.map +1 -0
- package/dist/twilio-53GEW5JT.js +139 -0
- package/dist/twilio-53GEW5JT.js.map +1 -0
- package/dist/unit-converter-ZYXMEZOE.js +14 -0
- package/dist/unit-converter-ZYXMEZOE.js.map +1 -0
- package/dist/whatsapp-LFX6YKCM.js +35 -0
- package/dist/whatsapp-LFX6YKCM.js.map +1 -0
- package/dist/word-document-7B6SJMAY.js +902 -0
- package/dist/word-document-7B6SJMAY.js.map +1 -0
- package/dist/xero-QYO66D45.js +162 -0
- package/dist/xero-QYO66D45.js.map +1 -0
- package/dist/zapier-webhook-TBZ5YF2A.js +106 -0
- package/dist/zapier-webhook-TBZ5YF2A.js.map +1 -0
- package/drizzle/0002_mushy_master_mold.sql +140 -0
- package/drizzle/meta/0002_snapshot.json +3637 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +100 -98
- package/dist/bot-KJ26BG56.js +0 -15
- package/dist/chunk-4LVWXUNC.js.map +0 -1
- package/dist/chunk-4TG2IG5K.js +0 -5249
- package/dist/chunk-4TG2IG5K.js.map +0 -1
- package/dist/chunk-6DRDKB45.js.map +0 -1
- package/dist/chunk-CI6Q63MM.js +0 -1613
- package/dist/chunk-CI6Q63MM.js.map +0 -1
- package/dist/chunk-KHNYJY2Z.js +0 -178
- package/dist/chunk-KHNYJY2Z.js.map +0 -1
- package/dist/chunk-NSBPE2FW.js +0 -17
- package/dist/discord-ZOJFTVTB.js +0 -49
- package/dist/imessage-JFRB6EJ7.js +0 -14
- package/dist/scheduler-EZ7CZMCS.js +0 -42
- package/dist/signal-T3MCSULM.js +0 -14
- package/dist/slack-N2M4FHAJ.js +0 -54
- package/dist/src-K7GASHRH.js.map +0 -1
- package/dist/tools-24GZHYRF.js +0 -16
- package/dist/whatsapp-VCRUPAO5.js +0 -14
- /package/dist/{bot-KJ26BG56.js.map → audit-logger-OBPR7CRO.js.map} +0 -0
- /package/dist/{chunk-NSBPE2FW.js.map → auth-UOX5K2BE.js.map} +0 -0
- /package/dist/{discord-ZOJFTVTB.js.map → backup-restore-PZ7CYYB7.js.map} +0 -0
- /package/dist/{imessage-JFRB6EJ7.js.map → blocks-R3PODY47.js.map} +0 -0
- /package/dist/{mcp-LS7Q3Z5W.js.map → bot-QRARP4UN.js.map} +0 -0
- /package/dist/{scheduler-EZ7CZMCS.js.map → brain-7XLLM3KC.js.map} +0 -0
- /package/dist/{charts-MMXM6BWW.js.map → charts-V7ARZNKF.js.map} +0 -0
- /package/dist/{chunk-L3PDU3XN.js.map → chunk-4UOE5TUZ.js.map} +0 -0
- /package/dist/{chunk-6SNHU3CY.js.map → chunk-66OJ3WB4.js.map} +0 -0
- /package/dist/{chunk-F6QUZQGI.js.map → chunk-MXAPLSJ5.js.map} +0 -0
- /package/dist/{chunk-GK3E2I7A.js.map → chunk-NHMBTUMW.js.map} +0 -0
- /package/dist/{signal-T3MCSULM.js.map → chunk-PLDDJCW6.js.map} +0 -0
- /package/dist/{chunk-GVJVEWHI.js.map → chunk-SJSUSJ47.js.map} +0 -0
- /package/dist/{chunk-HH2HBTQM.js.map → chunk-TYAGMJNV.js.map} +0 -0
- /package/dist/{chunk-JXUP2X7V.js.map → chunk-VEHFVBLI.js.map} +0 -0
- /package/dist/{slack-N2M4FHAJ.js.map → client-ZQSFPMOB.js.map} +0 -0
- /package/dist/{tools-24GZHYRF.js.map → clipboard-manager-TEO2GEDN.js.map} +0 -0
- /package/dist/{whatsapp-VCRUPAO5.js.map → cron-explain-HHQKPD3M.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/intelligence/enrichment-pipeline.ts","../src/integrations/public-records/rate-limiter.ts","../src/integrations/public-records/fec-client.ts","../src/integrations/public-records/propublica990-client.ts","../src/integrations/public-records/usaspending-client.ts","../src/integrations/public-records/sec-edgar-client.ts","../src/integrations/public-records/opencorporates-client.ts","../src/integrations/public-records/index.ts","../src/integrations/neo4j/client.ts","../src/integrations/neo4j/graph-ops.ts"],"sourcesContent":["/**\n * Enrichment Pipeline\n *\n * Auto-enriches entities by querying all relevant public records APIs.\n * Creates new entities and relationships via the entity resolution pipeline.\n *\n * When a new entity is discovered (person, organization, committee, etc.),\n * this pipeline fans out to every applicable public records source, resolves\n * discovered sub-entities through the entity resolution system, and wires\n * up relationships in the knowledge graph.\n *\n * Sources:\n * - FEC / OpenFEC Campaign finance (candidates, committees, donations)\n * - ProPublica IRS 990 Tax-exempt organisation filings\n * - USAspending.gov Federal contracts and grants\n * - SEC EDGAR Corporate filings, insider transactions\n * - OpenCorporates Global corporate registry data\n */\n\nimport { db } from \"../../db\";\nimport { graphEntities } from \"../../db/schema\";\nimport { eq, sql } from \"drizzle-orm\";\nimport { PublicRecords } from \"../../integrations/public-records\";\nimport { createRelationship } from \"../../integrations/neo4j\";\nimport { resolveEntity, type EntityCandidate } from \"./entity-resolution\";\nimport { env } from \"../../config/env\";\n\nconst LOG_PREFIX = \"[OSINT:Enrich]\";\n\n// ---------------------------------------------------------------------------\n// Lazy singleton for the public records facade\n// ---------------------------------------------------------------------------\n\nlet _publicRecords: PublicRecords | null = null;\n\nfunction getPublicRecords(): PublicRecords {\n if (!_publicRecords) _publicRecords = new PublicRecords();\n return _publicRecords;\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** All source identifiers the pipeline knows about. */\nconst ALL_SOURCES = [\"fec\", \"irs990\", \"usaspending\", \"sec\", \"opencorporates\"] as const;\ntype SourceName = (typeof ALL_SOURCES)[number];\n\n/** Maximum recursive enrichment depth to prevent runaway fan-out. */\nconst MAX_DEPTH = 3;\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\nexport interface EnrichmentResult {\n entityId: string;\n entityName: string;\n sourcesQueried: string[];\n newEntitiesCreated: number;\n newRelationshipsCreated: number;\n errors: string[];\n}\n\n/** Internal bookkeeping returned by each source-specific enricher. */\ninterface SourceEnrichmentResult {\n entities: number;\n relationships: number;\n errors: string[];\n}\n\n// ---------------------------------------------------------------------------\n// Main entry point\n// ---------------------------------------------------------------------------\n\n/**\n * Enrich a single entity by querying all relevant public records APIs,\n * creating discovered sub-entities, and wiring up graph relationships.\n *\n * @param entityId The Postgres `graphEntities.id` of the entity to enrich.\n * @param sources Optional list of sources to query. Defaults to all sources.\n * @param depth Current recursion depth (callers should not set this).\n */\nexport async function enrichEntity(\n entityId: string,\n sources?: string[],\n depth: number = 1,\n): Promise<EnrichmentResult> {\n if (!env.OSINT_ENABLED) {\n console.log(`${LOG_PREFIX} OSINT is disabled — skipping enrichment`);\n return {\n entityId,\n entityName: \"\",\n sourcesQueried: [],\n newEntitiesCreated: 0,\n newRelationshipsCreated: 0,\n errors: [\"OSINT_ENABLED is false\"],\n };\n }\n\n // Load entity from DB\n const rows = await db\n .select({\n id: graphEntities.id,\n name: graphEntities.name,\n type: graphEntities.type,\n attributes: graphEntities.attributes,\n })\n .from(graphEntities)\n .where(eq(graphEntities.id, entityId))\n .limit(1);\n\n if (rows.length === 0) {\n console.log(`${LOG_PREFIX} Entity not found: ${entityId}`);\n return {\n entityId,\n entityName: \"\",\n sourcesQueried: [],\n newEntitiesCreated: 0,\n newRelationshipsCreated: 0,\n errors: [`Entity ${entityId} not found`],\n };\n }\n\n const entity = rows[0];\n const entityName = entity.name;\n const entityType = entity.type;\n const attrs = (entity.attributes as Record<string, unknown>) ?? {};\n\n console.log(\n `${LOG_PREFIX} Enriching \"${entityName}\" (${entityType}) — depth=${depth}`,\n );\n\n // Decide which sources to query\n const activeSources = (sources ?? [...ALL_SOURCES]).filter((s) =>\n ALL_SOURCES.includes(s as SourceName),\n ) as SourceName[];\n\n // Filter already-enriched sources to avoid redundant API calls\n const enrichedFrom = (attrs.enrichedFrom as string[]) ?? [];\n const pendingSources = activeSources.filter(\n (s) => !enrichedFrom.includes(s),\n );\n\n if (pendingSources.length === 0) {\n console.log(`${LOG_PREFIX} \"${entityName}\" already enriched from all requested sources`);\n return {\n entityId,\n entityName,\n sourcesQueried: [],\n newEntitiesCreated: 0,\n newRelationshipsCreated: 0,\n errors: [],\n };\n }\n\n // Fan out to source-specific enrichers\n const enricherMap: Record<\n SourceName,\n (\n id: string,\n name: string,\n type: string,\n attrs: Record<string, unknown>,\n ) => Promise<SourceEnrichmentResult>\n > = {\n fec: enrichFromFEC,\n irs990: enrichFromIRS990,\n usaspending: enrichFromUSASpending,\n sec: enrichFromSEC,\n opencorporates: enrichFromOpenCorporates,\n };\n\n let totalEntities = 0;\n let totalRelationships = 0;\n const allErrors: string[] = [];\n const queriedSources: string[] = [];\n\n // Run enrichers concurrently per source for throughput\n const enrichmentPromises = pendingSources.map(async (source) => {\n try {\n const result = await enricherMap[source](entityId, entityName, entityType, attrs);\n queriedSources.push(source);\n totalEntities += result.entities;\n totalRelationships += result.relationships;\n allErrors.push(...result.errors);\n } catch (err) {\n const msg = `${source}: ${err instanceof Error ? err.message : String(err)}`;\n console.error(`${LOG_PREFIX} Top-level enricher error — ${msg}`);\n allErrors.push(msg);\n queriedSources.push(source);\n }\n });\n\n await Promise.all(enrichmentPromises);\n\n // Record which sources we've now enriched from\n try {\n const updatedEnrichedFrom = [...new Set([...enrichedFrom, ...queriedSources])];\n await db\n .update(graphEntities)\n .set({\n attributes: {\n ...attrs,\n enrichedFrom: updatedEnrichedFrom,\n lastEnrichedAt: new Date().toISOString(),\n },\n })\n .where(eq(graphEntities.id, entityId));\n } catch (err) {\n console.error(`${LOG_PREFIX} Failed to update enrichment metadata for ${entityId}:`, err);\n }\n\n console.log(\n `${LOG_PREFIX} Enrichment complete for \"${entityName}\": ` +\n `${totalEntities} entities, ${totalRelationships} relationships, ` +\n `${allErrors.length} errors`,\n );\n\n return {\n entityId,\n entityName,\n sourcesQueried: queriedSources,\n newEntitiesCreated: totalEntities,\n newRelationshipsCreated: totalRelationships,\n errors: allErrors,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Source-specific enrichers\n// ---------------------------------------------------------------------------\n\n/**\n * Enrich an entity from FEC campaign finance data.\n *\n * - Person: look up individual donor contributions, resolve recipient committees.\n * - Organization/Committee: search for committees by name, get contributions.\n */\nasync function enrichFromFEC(\n entityId: string,\n entityName: string,\n entityType: string,\n attrs: Record<string, unknown>,\n): Promise<SourceEnrichmentResult> {\n const pr = getPublicRecords();\n let entities = 0;\n let relationships = 0;\n const errors: string[] = [];\n\n if (entityType === \"person\") {\n // Search for individual donations by this person\n try {\n const contributions = await pr.fec.getDonorLookup(entityName);\n console.log(\n `${LOG_PREFIX} FEC: found ${contributions.length} contributions for person \"${entityName}\"`,\n );\n\n // Group contributions by committee to avoid creating duplicate relationships\n const committeeMap = new Map<\n string,\n { id: string; name: string; totalAmount: number; count: number }\n >();\n\n for (const contrib of contributions) {\n if (!contrib.committeeId) continue;\n const existing = committeeMap.get(contrib.committeeId);\n if (existing) {\n existing.totalAmount += contrib.amount;\n existing.count += 1;\n } else {\n committeeMap.set(contrib.committeeId, {\n id: contrib.committeeId,\n name: contrib.committeeName,\n totalAmount: contrib.amount,\n count: 1,\n });\n }\n }\n\n for (const [fecCommitteeId, info] of committeeMap) {\n try {\n const resolved = await resolveEntity({\n name: info.name,\n type: \"committee\",\n source: \"fec\",\n identifiers: { fecId: fecCommitteeId },\n attributes: {\n fecCommitteeId: fecCommitteeId,\n },\n });\n\n if (resolved.isNew) entities++;\n\n await createRelationship(entityId, resolved.entityId, \"donated_to\", {\n strength: Math.min(100, Math.round(info.totalAmount / 100)),\n context: `${info.count} contribution(s) totaling $${info.totalAmount.toLocaleString()}`,\n attributes: {\n totalAmount: info.totalAmount,\n contributionCount: info.count,\n source: \"fec\",\n },\n source: \"fec\",\n });\n relationships++;\n } catch (err) {\n errors.push(`FEC committee resolution: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n } catch (err) {\n errors.push(`FEC donor lookup: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n // Search for this person as a candidate\n try {\n const candidates = await pr.fec.searchCandidates(entityName);\n for (const candidate of candidates.slice(0, 5)) {\n try {\n const resolved = await resolveEntity({\n name: candidate.name,\n type: \"person\",\n source: \"fec\",\n identifiers: { fecId: candidate.candidateId },\n attributes: {\n fecCandidateId: candidate.candidateId,\n party: candidate.party,\n office: candidate.office,\n state: candidate.state,\n district: candidate.district,\n },\n });\n\n // If the candidate resolved to a different entity, link them\n if (resolved.entityId !== entityId) {\n if (resolved.isNew) entities++;\n\n await createRelationship(entityId, resolved.entityId, \"related_to\", {\n context: `FEC candidate match: ${candidate.name} (${candidate.party})`,\n attributes: { source: \"fec\", matchType: \"candidate\" },\n source: \"fec\",\n });\n relationships++;\n }\n } catch (err) {\n errors.push(`FEC candidate resolution: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n } catch (err) {\n errors.push(`FEC candidate search: ${err instanceof Error ? err.message : String(err)}`);\n }\n } else if (entityType === \"organization\" || entityType === \"event\") {\n // Search for committees matching the organization name\n try {\n const committees = await pr.fec.searchCommittees(entityName);\n console.log(\n `${LOG_PREFIX} FEC: found ${committees.length} committees for org \"${entityName}\"`,\n );\n\n for (const committee of committees.slice(0, 10)) {\n try {\n const resolved = await resolveEntity({\n name: committee.name,\n type: \"committee\",\n source: \"fec\",\n identifiers: { fecId: committee.committeeId },\n attributes: {\n fecCommitteeId: committee.committeeId,\n designation: committee.designation,\n committeeType: committee.type,\n party: committee.party,\n treasurerName: committee.treasurerName,\n },\n });\n\n if (resolved.isNew) entities++;\n\n await createRelationship(entityId, resolved.entityId, \"related_to\", {\n context: `FEC committee: ${committee.name} (${committee.designation})`,\n attributes: { source: \"fec\", committeeType: committee.type },\n source: \"fec\",\n });\n relationships++;\n\n // Get contributions to this committee\n try {\n const contributions = await pr.fec.getContributions({\n committeeId: committee.committeeId,\n });\n\n // Resolve top donors as person entities\n const donorMap = new Map<string, { name: string; total: number; count: number }>();\n for (const c of contributions) {\n if (!c.contributorName) continue;\n const existing = donorMap.get(c.contributorName);\n if (existing) {\n existing.total += c.amount;\n existing.count++;\n } else {\n donorMap.set(c.contributorName, {\n name: c.contributorName,\n total: c.amount,\n count: 1,\n });\n }\n }\n\n // Only resolve the top 10 donors by total amount\n const topDonors = [...donorMap.values()]\n .sort((a, b) => b.total - a.total)\n .slice(0, 10);\n\n for (const donor of topDonors) {\n try {\n const donorResolved = await resolveEntity({\n name: donor.name,\n type: \"person\",\n source: \"fec\",\n attributes: {\n totalContributions: donor.total,\n contributionCount: donor.count,\n },\n });\n\n if (donorResolved.isNew) entities++;\n\n await createRelationship(\n donorResolved.entityId,\n resolved.entityId,\n \"donated_to\",\n {\n strength: Math.min(100, Math.round(donor.total / 100)),\n context: `${donor.count} contribution(s) totaling $${donor.total.toLocaleString()}`,\n attributes: {\n totalAmount: donor.total,\n contributionCount: donor.count,\n source: \"fec\",\n },\n source: \"fec\",\n },\n );\n relationships++;\n } catch (err) {\n errors.push(\n `FEC donor resolution (${donor.name}): ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n } catch (err) {\n errors.push(\n `FEC contributions for ${committee.committeeId}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n } catch (err) {\n errors.push(\n `FEC committee resolution (${committee.name}): ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n } catch (err) {\n errors.push(`FEC committee search: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n return { entities, relationships, errors };\n}\n\n/**\n * Enrich an entity from IRS 990 nonprofit filing data.\n *\n * Searches for nonprofits matching the entity name, retrieves filings,\n * and stores revenue/expense data as entity attributes.\n */\nasync function enrichFromIRS990(\n entityId: string,\n entityName: string,\n entityType: string,\n attrs: Record<string, unknown>,\n): Promise<SourceEnrichmentResult> {\n const pr = getPublicRecords();\n let entities = 0;\n let relationships = 0;\n const errors: string[] = [];\n\n // IRS 990 is primarily relevant for organizations\n if (entityType !== \"organization\" && entityType !== \"event\") {\n return { entities, relationships, errors };\n }\n\n try {\n const orgs = await pr.irs990.searchOrganizations(entityName);\n console.log(\n `${LOG_PREFIX} IRS990: found ${orgs.length} nonprofits for \"${entityName}\"`,\n );\n\n for (const org of orgs.slice(0, 5)) {\n if (!org.ein) continue;\n\n try {\n // Get detailed filing data\n const detail = await pr.irs990.getOrganization(org.ein);\n const recentFilings = detail.filings.slice(0, 3);\n\n // Build financial summary from filings\n const financialSummary: Record<string, unknown> = {};\n if (recentFilings.length > 0) {\n const latest = recentFilings[0];\n financialSummary.latestRevenue = latest.totalRevenue;\n financialSummary.latestExpenses = latest.totalExpenses;\n financialSummary.latestAssets = latest.totalAssets;\n financialSummary.latestLiabilities = latest.totalLiabilities;\n financialSummary.latestTaxPeriod = latest.taxPeriod;\n financialSummary.filingCount = detail.filings.length;\n }\n\n const resolved = await resolveEntity({\n name: detail.name || org.name,\n type: \"organization\",\n source: \"irs990\",\n identifiers: { ein: org.ein },\n attributes: {\n ein: org.ein,\n city: detail.city || org.city,\n state: detail.state || org.state,\n nteeCode: detail.nteeCode || org.nteeCode,\n rulingDate: detail.rulingDate || org.rulingDate,\n ...financialSummary,\n filings: recentFilings.map((f) => ({\n taxPeriod: f.taxPeriod,\n formType: f.formType,\n totalRevenue: f.totalRevenue,\n totalExpenses: f.totalExpenses,\n totalAssets: f.totalAssets,\n totalLiabilities: f.totalLiabilities,\n })),\n },\n });\n\n if (resolved.isNew) entities++;\n\n // Only create relationship if the resolved entity is different\n if (resolved.entityId !== entityId) {\n await createRelationship(entityId, resolved.entityId, \"related_to\", {\n context: `IRS 990 nonprofit: ${org.name} (EIN: ${org.ein})`,\n attributes: {\n source: \"irs990\",\n ein: org.ein,\n ...financialSummary,\n },\n source: \"irs990\",\n });\n relationships++;\n } else {\n // Same entity: update its attributes with the financial data\n try {\n await db\n .update(graphEntities)\n .set({\n attributes: {\n ...attrs,\n ein: org.ein,\n nteeCode: detail.nteeCode,\n ...financialSummary,\n irs990Filings: recentFilings.map((f) => ({\n taxPeriod: f.taxPeriod,\n formType: f.formType,\n totalRevenue: f.totalRevenue,\n totalExpenses: f.totalExpenses,\n totalAssets: f.totalAssets,\n totalLiabilities: f.totalLiabilities,\n })),\n },\n })\n .where(eq(graphEntities.id, entityId));\n } catch (err) {\n errors.push(\n `IRS990 attribute update: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n } catch (err) {\n errors.push(\n `IRS990 org detail (${org.ein}): ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n } catch (err) {\n errors.push(`IRS990 search: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n return { entities, relationships, errors };\n}\n\n/**\n * Enrich an entity from USAspending.gov federal spending data.\n *\n * Searches for federal awards involving the entity, resolves awarding\n * agencies and recipients, and creates contract/grant relationships.\n */\nasync function enrichFromUSASpending(\n entityId: string,\n entityName: string,\n entityType: string,\n attrs: Record<string, unknown>,\n): Promise<SourceEnrichmentResult> {\n const pr = getPublicRecords();\n let entities = 0;\n let relationships = 0;\n const errors: string[] = [];\n\n try {\n // Search for awards mentioning this entity as keyword or recipient\n const awards = await pr.usaspending.searchAwards({\n keyword: entityName,\n });\n\n console.log(\n `${LOG_PREFIX} USASpending: found ${awards.length} awards for \"${entityName}\"`,\n );\n\n for (const award of awards.slice(0, 15)) {\n // Resolve the award as a contract/filing entity\n try {\n const awardCandidate: EntityCandidate = {\n name: award.description || `Award ${award.awardId}`,\n type: \"contract\",\n source: \"usaspending\",\n identifiers: { uei: award.recipientUei || undefined },\n attributes: {\n awardId: award.awardId,\n awardType: award.type,\n typeDescription: award.typeDescription,\n totalObligationAmount: award.totalObligationAmount,\n totalOutlayAmount: award.totalOutlayAmount,\n startDate: award.startDate,\n endDate: award.endDate,\n placeOfPerformanceCity: award.placeOfPerformanceCity,\n placeOfPerformanceState: award.placeOfPerformanceState,\n },\n };\n\n const awardResolved = await resolveEntity(awardCandidate);\n if (awardResolved.isNew) entities++;\n\n // Resolve the recipient as an organization entity\n if (award.recipientName) {\n try {\n const recipientResolved = await resolveEntity({\n name: award.recipientName,\n type: \"organization\",\n source: \"usaspending\",\n identifiers: { uei: award.recipientUei || undefined },\n attributes: {\n uei: award.recipientUei,\n },\n });\n\n if (recipientResolved.isNew) entities++;\n\n // Recipient received the award\n await createRelationship(\n recipientResolved.entityId,\n awardResolved.entityId,\n \"awarded_contract\",\n {\n strength: Math.min(\n 100,\n Math.round(Math.abs(award.totalObligationAmount) / 10_000),\n ),\n context: `Award ${award.awardId}: $${award.totalObligationAmount.toLocaleString()}`,\n attributes: {\n amount: award.totalObligationAmount,\n awardType: award.type,\n source: \"usaspending\",\n },\n source: \"usaspending\",\n },\n );\n relationships++;\n\n // Link the original entity to the recipient if they are different\n if (recipientResolved.entityId !== entityId) {\n await createRelationship(entityId, recipientResolved.entityId, \"related_to\", {\n context: `Linked via USAspending award ${award.awardId}`,\n attributes: { source: \"usaspending\" },\n source: \"usaspending\",\n });\n relationships++;\n }\n } catch (err) {\n errors.push(\n `USASpending recipient (${award.recipientName}): ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n // Resolve the awarding agency as an organization entity\n if (award.awardingAgencyName) {\n try {\n const agencyResolved = await resolveEntity({\n name: award.awardingAgencyName,\n type: \"organization\",\n source: \"usaspending\",\n attributes: {\n agencyType: \"federal\",\n subAgency: award.awardingSubAgencyName,\n },\n });\n\n if (agencyResolved.isNew) entities++;\n\n // Agency funded the award\n await createRelationship(\n agencyResolved.entityId,\n awardResolved.entityId,\n \"funded_by\",\n {\n context: `Funded by ${award.awardingAgencyName}`,\n attributes: {\n amount: award.totalObligationAmount,\n source: \"usaspending\",\n },\n source: \"usaspending\",\n },\n );\n relationships++;\n } catch (err) {\n errors.push(\n `USASpending agency (${award.awardingAgencyName}): ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n // Funding agency (if different from awarding agency)\n if (\n award.fundingAgencyName &&\n award.fundingAgencyName !== award.awardingAgencyName\n ) {\n try {\n const fundingResolved = await resolveEntity({\n name: award.fundingAgencyName,\n type: \"organization\",\n source: \"usaspending\",\n attributes: { agencyType: \"federal\" },\n });\n\n if (fundingResolved.isNew) entities++;\n\n await createRelationship(\n fundingResolved.entityId,\n awardResolved.entityId,\n \"funded_by\",\n {\n context: `Funding agency: ${award.fundingAgencyName}`,\n attributes: { source: \"usaspending\" },\n source: \"usaspending\",\n },\n );\n relationships++;\n } catch (err) {\n errors.push(\n `USASpending funding agency (${award.fundingAgencyName}): ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n } catch (err) {\n errors.push(\n `USASpending award (${award.awardId}): ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n } catch (err) {\n errors.push(`USASpending search: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n return { entities, relationships, errors };\n}\n\n/**\n * Enrich an entity from SEC EDGAR corporate filings.\n *\n * Searches for companies matching the entity, retrieves insider transactions,\n * and resolves officers/insiders as person entities.\n */\nasync function enrichFromSEC(\n entityId: string,\n entityName: string,\n entityType: string,\n attrs: Record<string, unknown>,\n): Promise<SourceEnrichmentResult> {\n const pr = getPublicRecords();\n let entities = 0;\n let relationships = 0;\n const errors: string[] = [];\n\n // SEC is primarily relevant for organizations (companies) and persons\n if (entityType !== \"organization\" && entityType !== \"person\") {\n return { entities, relationships, errors };\n }\n\n try {\n const companies = await pr.sec.searchCompanies(entityName);\n console.log(\n `${LOG_PREFIX} SEC: found ${companies.length} companies for \"${entityName}\"`,\n );\n\n for (const company of companies.slice(0, 5)) {\n if (!company.cik) continue;\n\n try {\n // Resolve the company as an entity\n const companyResolved = await resolveEntity({\n name: company.name,\n type: \"organization\",\n source: \"sec\",\n identifiers: { cik: company.cik },\n attributes: {\n cik: company.cik,\n ticker: company.ticker,\n exchange: company.exchange,\n sic: company.sic,\n sicDescription: company.sicDescription,\n stateOfIncorporation: company.stateOfIncorporation,\n fiscalYearEnd: company.fiscalYearEnd,\n },\n });\n\n if (companyResolved.isNew) entities++;\n\n // Link entity to company if they resolved differently\n if (companyResolved.entityId !== entityId) {\n await createRelationship(entityId, companyResolved.entityId, \"related_to\", {\n context: `SEC EDGAR company match: ${company.name} (CIK: ${company.cik})`,\n attributes: { source: \"sec\", cik: company.cik, ticker: company.ticker },\n source: \"sec\",\n });\n relationships++;\n }\n\n // Get insider transactions for the company\n try {\n const transactions = await pr.sec.getInsiderTransactions(company.cik);\n console.log(\n `${LOG_PREFIX} SEC: found ${transactions.length} insider transactions for CIK ${company.cik}`,\n );\n\n // Group transactions by reporting owner to deduplicate\n const ownerMap = new Map<\n string,\n {\n name: string;\n cik: string;\n isDirector: boolean;\n isOfficer: boolean;\n officerTitle: string;\n transactionCount: number;\n totalShares: number;\n }\n >();\n\n for (const tx of transactions) {\n if (!tx.reportingOwnerName || tx.reportingOwnerName === \"See filing\")\n continue;\n\n const key = tx.reportingOwnerCik || tx.reportingOwnerName;\n const existing = ownerMap.get(key);\n if (existing) {\n existing.transactionCount++;\n existing.totalShares += Math.abs(tx.transactionShares);\n existing.isDirector = existing.isDirector || tx.isDirector;\n existing.isOfficer = existing.isOfficer || tx.isOfficer;\n if (tx.officerTitle && !existing.officerTitle) {\n existing.officerTitle = tx.officerTitle;\n }\n } else {\n ownerMap.set(key, {\n name: tx.reportingOwnerName,\n cik: tx.reportingOwnerCik,\n isDirector: tx.isDirector,\n isOfficer: tx.isOfficer,\n officerTitle: tx.officerTitle,\n transactionCount: 1,\n totalShares: Math.abs(tx.transactionShares),\n });\n }\n }\n\n // Resolve top insiders (limit to 15 to control fan-out)\n const topInsiders = [...ownerMap.values()]\n .sort((a, b) => b.totalShares - a.totalShares)\n .slice(0, 15);\n\n for (const insider of topInsiders) {\n try {\n const insiderResolved = await resolveEntity({\n name: insider.name,\n type: \"person\",\n source: \"sec\",\n identifiers: insider.cik ? { cik: insider.cik } : undefined,\n attributes: {\n isDirector: insider.isDirector,\n isOfficer: insider.isOfficer,\n officerTitle: insider.officerTitle,\n },\n });\n\n if (insiderResolved.isNew) entities++;\n\n // Create officer_of relationship\n const relType =\n insider.isOfficer || insider.isDirector\n ? \"officer_of\"\n : \"insider_transaction\";\n\n await createRelationship(\n insiderResolved.entityId,\n companyResolved.entityId,\n relType,\n {\n strength: Math.min(100, 40 + insider.transactionCount * 5),\n context: insider.officerTitle\n ? `${insider.officerTitle} — ${insider.transactionCount} transaction(s)`\n : `${insider.transactionCount} insider transaction(s)`,\n attributes: {\n isDirector: insider.isDirector,\n isOfficer: insider.isOfficer,\n officerTitle: insider.officerTitle,\n transactionCount: insider.transactionCount,\n totalShares: insider.totalShares,\n source: \"sec\",\n },\n source: \"sec\",\n },\n );\n relationships++;\n } catch (err) {\n errors.push(\n `SEC insider (${insider.name}): ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n } catch (err) {\n errors.push(\n `SEC insider transactions (CIK ${company.cik}): ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n } catch (err) {\n errors.push(\n `SEC company (${company.name}): ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n } catch (err) {\n errors.push(`SEC search: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n return { entities, relationships, errors };\n}\n\n/**\n * Enrich an entity from OpenCorporates global corporate registry.\n *\n * Searches for companies matching the entity name, retrieves officers,\n * and resolves them as person entities with officer_of relationships.\n */\nasync function enrichFromOpenCorporates(\n entityId: string,\n entityName: string,\n entityType: string,\n attrs: Record<string, unknown>,\n): Promise<SourceEnrichmentResult> {\n const pr = getPublicRecords();\n let entities = 0;\n let relationships = 0;\n const errors: string[] = [];\n\n // OpenCorporates is primarily relevant for organizations\n if (entityType !== \"organization\") {\n // For persons, try searching them as officers\n if (entityType === \"person\") {\n try {\n const officers = await pr.opencorporates.searchOfficers(entityName);\n console.log(\n `${LOG_PREFIX} OpenCorporates: found ${officers.length} officer records for person \"${entityName}\"`,\n );\n\n for (const officer of officers.slice(0, 10)) {\n if (!officer.companyName) continue;\n\n try {\n const companyResolved = await resolveEntity({\n name: officer.companyName,\n type: \"organization\",\n source: \"opencorporates\",\n attributes: {\n companyNumber: officer.companyNumber,\n jurisdictionCode: officer.jurisdictionCode,\n },\n });\n\n if (companyResolved.isNew) entities++;\n\n await createRelationship(entityId, companyResolved.entityId, \"officer_of\", {\n strength: 60,\n context: `${officer.position || \"Officer\"} at ${officer.companyName}`,\n attributes: {\n position: officer.position,\n startDate: officer.startDate,\n endDate: officer.endDate,\n nationality: officer.nationality,\n occupation: officer.occupation,\n source: \"opencorporates\",\n },\n source: \"opencorporates\",\n });\n relationships++;\n } catch (err) {\n errors.push(\n `OpenCorporates officer company (${officer.companyName}): ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n } catch (err) {\n errors.push(\n `OpenCorporates officer search: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n return { entities, relationships, errors };\n }\n\n // Other types: skip\n return { entities, relationships, errors };\n }\n\n // For organizations: search companies by name\n try {\n const companies = await pr.opencorporates.searchCompanies(entityName);\n console.log(\n `${LOG_PREFIX} OpenCorporates: found ${companies.length} companies for \"${entityName}\"`,\n );\n\n for (const company of companies.slice(0, 5)) {\n try {\n // Resolve the company entity\n const companyResolved = await resolveEntity({\n name: company.name,\n type: \"organization\",\n source: \"opencorporates\",\n attributes: {\n companyNumber: company.companyNumber,\n jurisdictionCode: company.jurisdictionCode,\n incorporationDate: company.incorporationDate,\n dissolutionDate: company.dissolutionDate,\n companyType: company.companyType,\n status: company.status,\n registeredAddress: company.registeredAddress,\n registryUrl: company.registryUrl,\n openCorporatesUrl: company.openCorporatesUrl,\n },\n });\n\n if (companyResolved.isNew) entities++;\n\n // Link to original entity if different\n if (companyResolved.entityId !== entityId) {\n await createRelationship(entityId, companyResolved.entityId, \"related_to\", {\n context: `OpenCorporates match: ${company.name} (${company.jurisdictionCode})`,\n attributes: {\n source: \"opencorporates\",\n companyNumber: company.companyNumber,\n jurisdictionCode: company.jurisdictionCode,\n },\n source: \"opencorporates\",\n });\n relationships++;\n }\n\n // Resolve officers from inline data\n const inlineOfficers = company.officers ?? [];\n for (const officer of inlineOfficers.slice(0, 15)) {\n if (!officer.name) continue;\n\n try {\n const officerResolved = await resolveEntity({\n name: officer.name,\n type: \"person\",\n source: \"opencorporates\",\n attributes: {\n position: officer.position,\n nationality: officer.nationality,\n occupation: officer.occupation,\n },\n });\n\n if (officerResolved.isNew) entities++;\n\n await createRelationship(\n officerResolved.entityId,\n companyResolved.entityId,\n \"officer_of\",\n {\n strength: 60,\n context: `${officer.position || \"Officer\"} at ${company.name}`,\n attributes: {\n position: officer.position,\n startDate: officer.startDate,\n endDate: officer.endDate,\n nationality: officer.nationality,\n occupation: officer.occupation,\n source: \"opencorporates\",\n },\n source: \"opencorporates\",\n },\n );\n relationships++;\n } catch (err) {\n errors.push(\n `OpenCorporates officer (${officer.name}): ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n // If no inline officers, try fetching them via the API\n if (\n inlineOfficers.length === 0 &&\n company.jurisdictionCode &&\n company.companyNumber\n ) {\n try {\n const detailedCompany = await pr.opencorporates.getCompany(\n company.jurisdictionCode,\n company.companyNumber,\n );\n\n for (const officer of (detailedCompany.officers ?? []).slice(0, 15)) {\n if (!officer.name) continue;\n\n try {\n const officerResolved = await resolveEntity({\n name: officer.name,\n type: \"person\",\n source: \"opencorporates\",\n attributes: {\n position: officer.position,\n nationality: officer.nationality,\n occupation: officer.occupation,\n },\n });\n\n if (officerResolved.isNew) entities++;\n\n await createRelationship(\n officerResolved.entityId,\n companyResolved.entityId,\n \"officer_of\",\n {\n strength: 60,\n context: `${officer.position || \"Officer\"} at ${company.name}`,\n attributes: {\n position: officer.position,\n startDate: officer.startDate,\n endDate: officer.endDate,\n source: \"opencorporates\",\n },\n source: \"opencorporates\",\n },\n );\n relationships++;\n } catch (err) {\n errors.push(\n `OpenCorporates officer (${officer.name}): ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n } catch (err) {\n errors.push(\n `OpenCorporates company detail (${company.companyNumber}): ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n } catch (err) {\n errors.push(\n `OpenCorporates company (${company.name}): ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n } catch (err) {\n errors.push(`OpenCorporates search: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n return { entities, relationships, errors };\n}\n\n// ---------------------------------------------------------------------------\n// Batch enrichment\n// ---------------------------------------------------------------------------\n\n/**\n * Batch-enrich entities that have not yet been enriched from all sources.\n *\n * Finds entities whose `attributes.enrichedFrom` array is missing one or\n * more of the requested sources and runs `enrichEntity` on each.\n *\n * @param opts.limit Maximum number of entities to process (default 50).\n * @param opts.sources Sources to check/enrich from (default: all sources).\n */\nexport async function batchEnrich(opts?: {\n limit?: number;\n sources?: string[];\n}): Promise<EnrichmentResult[]> {\n if (!env.OSINT_ENABLED) {\n console.log(`${LOG_PREFIX} OSINT is disabled — skipping batch enrichment`);\n return [];\n }\n\n const limit = opts?.limit ?? 50;\n const sources = (opts?.sources ?? [...ALL_SOURCES]).filter((s) =>\n ALL_SOURCES.includes(s as SourceName),\n );\n\n console.log(\n `${LOG_PREFIX} Starting batch enrichment — limit=${limit}, sources=${sources.join(\",\")}`,\n );\n\n // Find entities that need enrichment:\n // - They exist in graphEntities\n // - Their attributes.enrichedFrom does not contain all requested sources\n //\n // We use a raw SQL condition because jsonb array containment checks are\n // easier to express directly.\n const candidates = await db\n .select({\n id: graphEntities.id,\n name: graphEntities.name,\n attributes: graphEntities.attributes,\n })\n .from(graphEntities)\n .where(\n sql`(\n ${graphEntities.attributes}->>'enrichedFrom' IS NULL\n OR NOT ${graphEntities.attributes}->'enrichedFrom' @> ${JSON.stringify(sources)}::jsonb\n )`,\n )\n .limit(limit);\n\n console.log(\n `${LOG_PREFIX} Found ${candidates.length} entities needing enrichment`,\n );\n\n const results: EnrichmentResult[] = [];\n\n // Process sequentially to avoid overwhelming rate-limited APIs\n for (const candidate of candidates) {\n const enrichedFrom =\n ((candidate.attributes as Record<string, unknown>)?.enrichedFrom as string[]) ?? [];\n const missingSources = sources.filter((s) => !enrichedFrom.includes(s));\n\n if (missingSources.length === 0) continue;\n\n try {\n const result = await enrichEntity(candidate.id, missingSources, 1);\n results.push(result);\n } catch (err) {\n console.error(\n `${LOG_PREFIX} Batch enrichment failed for \"${candidate.name}\":`,\n err,\n );\n results.push({\n entityId: candidate.id,\n entityName: candidate.name,\n sourcesQueried: missingSources,\n newEntitiesCreated: 0,\n newRelationshipsCreated: 0,\n errors: [err instanceof Error ? err.message : String(err)],\n });\n }\n }\n\n const totalEntities = results.reduce((s, r) => s + r.newEntitiesCreated, 0);\n const totalRels = results.reduce((s, r) => s + r.newRelationshipsCreated, 0);\n const totalErrors = results.reduce((s, r) => s + r.errors.length, 0);\n\n console.log(\n `${LOG_PREFIX} Batch enrichment complete: ` +\n `${results.length} entities processed, ` +\n `${totalEntities} new entities, ${totalRels} new relationships, ` +\n `${totalErrors} errors`,\n );\n\n return results;\n}\n","/**\n * Shared sliding-window rate limiter for all public records APIs.\n *\n * Uses an in-memory sliding window of request timestamps to enforce\n * per-service rate limits. When the limit would be exceeded, `acquire()`\n * returns a promise that resolves once enough time has passed for a new\n * request to fit inside the window.\n */\n\nimport { env } from \"../../config/env\";\n\nexport class RateLimiter {\n /** Timestamps (ms) of requests within the current window */\n private timestamps: number[] = [];\n /** Global buffer added after each wait to avoid edge-of-window bursts */\n private bufferMs: number;\n\n constructor(\n public readonly name: string,\n public readonly maxPerWindow: number,\n public readonly windowMs: number,\n ) {\n this.bufferMs = Number(env.OSINT_RATE_LIMIT_BUFFER_MS) || 200;\n }\n\n /**\n * Acquire permission to make a request.\n * Resolves immediately if within limits, otherwise waits until a slot opens.\n */\n async acquire(): Promise<void> {\n this.pruneExpired();\n\n if (this.timestamps.length < this.maxPerWindow) {\n this.timestamps.push(Date.now());\n return;\n }\n\n // The oldest timestamp determines when the next slot opens\n const oldest = this.timestamps[0]!;\n const waitMs = oldest + this.windowMs - Date.now() + this.bufferMs;\n\n if (waitMs > 0) {\n console.log(\n `[OSINT:RateLimiter:${this.name}] Rate limit reached (${this.timestamps.length}/${this.maxPerWindow}), waiting ${waitMs}ms`,\n );\n await new Promise<void>((resolve) => setTimeout(resolve, waitMs));\n }\n\n this.pruneExpired();\n this.timestamps.push(Date.now());\n }\n\n /**\n * Number of requests remaining in the current window.\n */\n get remaining(): number {\n this.pruneExpired();\n return Math.max(0, this.maxPerWindow - this.timestamps.length);\n }\n\n /** Remove timestamps that have fallen outside the window */\n private pruneExpired(): void {\n const cutoff = Date.now() - this.windowMs;\n while (this.timestamps.length > 0 && this.timestamps[0]! < cutoff) {\n this.timestamps.shift();\n }\n }\n}\n\n/**\n * Factory function — mirrors the pattern used in other OpenSentinel integrations.\n */\nexport function createRateLimiter(\n name: string,\n maxPerWindow: number,\n windowMs: number,\n): RateLimiter {\n return new RateLimiter(name, maxPerWindow, windowMs);\n}\n","/**\n * FEC / OpenFEC API Client\n *\n * Provides access to Federal Election Commission campaign finance data\n * including candidates, committees, contributions, disbursements, and filings.\n *\n * API docs: https://api.open.fec.gov/developers/\n * Rate limit: 1000 requests per hour (with API key)\n */\n\nimport { env } from \"../../config/env\";\nimport { RateLimiter, createRateLimiter } from \"./rate-limiter\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface FECCandidate {\n candidateId: string;\n name: string;\n party: string;\n office: string; // \"H\" | \"S\" | \"P\"\n state: string;\n district: string;\n incumbentChallenger: string;\n cycles: number[];\n activeThrough: number | null;\n}\n\nexport interface FECCommittee {\n committeeId: string;\n name: string;\n designation: string;\n type: string;\n party: string;\n state: string;\n treasurerName: string;\n candidateIds: string[];\n cycles: number[];\n}\n\nexport interface FECContribution {\n committeeId: string;\n committeeName: string;\n contributorName: string;\n contributorCity: string;\n contributorState: string;\n contributorZip: string;\n contributorEmployer: string;\n contributorOccupation: string;\n amount: number;\n date: string;\n receiptType: string;\n memoText: string;\n transactionId: string;\n}\n\nexport interface FECDisbursement {\n committeeId: string;\n committeeName: string;\n recipientName: string;\n recipientCity: string;\n recipientState: string;\n amount: number;\n date: string;\n description: string;\n categoryCode: string;\n memoText: string;\n}\n\nexport interface FECFiling {\n filingId: number;\n committeeId: string;\n committeeName: string;\n formType: string;\n reportType: string;\n reportYear: number;\n coverageStartDate: string;\n coverageEndDate: string;\n totalReceipts: number;\n totalDisbursements: number;\n cashOnHandEnd: number;\n filingDate: string;\n documentUrl: string;\n}\n\nexport interface FECClientConfig {\n apiKey?: string;\n timeout?: number;\n maxPages?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Error\n// ---------------------------------------------------------------------------\n\nexport class FECClientError extends Error {\n constructor(\n message: string,\n public statusCode?: number,\n ) {\n super(message);\n this.name = \"FECClientError\";\n }\n}\n\n// ---------------------------------------------------------------------------\n// Client\n// ---------------------------------------------------------------------------\n\nconst LOG_PREFIX = \"[OSINT:FEC]\";\n\nexport class FECClient {\n private baseUrl = \"https://api.open.fec.gov/v1\";\n private apiKey: string;\n private timeout: number;\n private maxPages: number;\n private rateLimiter: RateLimiter;\n\n constructor(config: FECClientConfig = {}) {\n this.apiKey = config.apiKey ?? env.FEC_API_KEY ?? \"\";\n this.timeout = config.timeout ?? 15_000;\n this.maxPages = config.maxPages ?? 10;\n // 1000 req / hr\n this.rateLimiter = createRateLimiter(\"FEC\", 1000, 60 * 60 * 1000);\n }\n\n // -----------------------------------------------------------------------\n // Internal helpers\n // -----------------------------------------------------------------------\n\n private async request<T>(\n endpoint: string,\n params: Record<string, string | number | undefined> = {},\n ): Promise<T> {\n await this.rateLimiter.acquire();\n\n const url = new URL(`${this.baseUrl}${endpoint}`);\n url.searchParams.set(\"api_key\", this.apiKey);\n\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== \"\") {\n url.searchParams.set(key, String(value));\n }\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n console.log(`${LOG_PREFIX} GET ${endpoint}`);\n const response = await fetch(url.toString(), {\n headers: { Accept: \"application/json\" },\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const body = await response.text().catch(() => \"\");\n throw new FECClientError(\n `FEC API error ${response.status}: ${response.statusText} — ${body}`,\n response.status,\n );\n }\n\n return (await response.json()) as T;\n } catch (error) {\n clearTimeout(timeoutId);\n if (error instanceof FECClientError) throw error;\n if ((error as Error).name === \"AbortError\") {\n throw new FECClientError(\"FEC request timed out\");\n }\n throw new FECClientError(\n `FEC network error: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n /**\n * Automatically paginate through all result pages up to maxPages.\n */\n private async paginate<TItem>(\n endpoint: string,\n params: Record<string, string | number | undefined>,\n extractItems: (body: any) => TItem[],\n ): Promise<TItem[]> {\n const items: TItem[] = [];\n let page = 1;\n\n while (page <= this.maxPages) {\n const body = await this.request<any>(endpoint, {\n ...params,\n page: String(page),\n per_page: \"100\",\n });\n\n const pageItems = extractItems(body);\n items.push(...pageItems);\n\n const pagination = body.pagination;\n if (\n !pagination ||\n page >= (pagination.pages ?? 1) ||\n pageItems.length === 0\n ) {\n break;\n }\n\n page++;\n }\n\n return items;\n }\n\n // -----------------------------------------------------------------------\n // Candidates\n // -----------------------------------------------------------------------\n\n async searchCandidates(\n query: string,\n opts: { office?: string; state?: string; cycle?: number } = {},\n ): Promise<FECCandidate[]> {\n return this.paginate<FECCandidate>(\n \"/candidates/search/\",\n {\n q: query,\n office: opts.office,\n state: opts.state,\n cycle: opts.cycle,\n sort: \"name\",\n },\n (body) =>\n (body.results ?? []).map((r: any) => this.mapCandidate(r)),\n );\n }\n\n async getCandidate(candidateId: string): Promise<FECCandidate> {\n const body = await this.request<any>(`/candidate/${candidateId}/`);\n const results = body.results ?? [];\n if (results.length === 0) {\n throw new FECClientError(`Candidate ${candidateId} not found`, 404);\n }\n return this.mapCandidate(results[0]);\n }\n\n private mapCandidate(r: any): FECCandidate {\n return {\n candidateId: r.candidate_id ?? \"\",\n name: r.name ?? \"\",\n party: r.party ?? \"\",\n office: r.office ?? \"\",\n state: r.state ?? \"\",\n district: r.district ?? \"\",\n incumbentChallenger: r.incumbent_challenge ?? \"\",\n cycles: r.cycles ?? [],\n activeThrough: r.active_through ?? null,\n };\n }\n\n // -----------------------------------------------------------------------\n // Committees\n // -----------------------------------------------------------------------\n\n async searchCommittees(query: string): Promise<FECCommittee[]> {\n return this.paginate<FECCommittee>(\n \"/committees/\",\n { q: query, sort: \"name\" },\n (body) =>\n (body.results ?? []).map((r: any) => this.mapCommittee(r)),\n );\n }\n\n async getCommittee(committeeId: string): Promise<FECCommittee> {\n const body = await this.request<any>(`/committee/${committeeId}/`);\n const results = body.results ?? [];\n if (results.length === 0) {\n throw new FECClientError(`Committee ${committeeId} not found`, 404);\n }\n return this.mapCommittee(results[0]);\n }\n\n private mapCommittee(r: any): FECCommittee {\n return {\n committeeId: r.committee_id ?? \"\",\n name: r.name ?? \"\",\n designation: r.designation ?? \"\",\n type: r.committee_type ?? \"\",\n party: r.party ?? \"\",\n state: r.state ?? \"\",\n treasurerName: r.treasurer_name ?? \"\",\n candidateIds: r.candidate_ids ?? [],\n cycles: r.cycles ?? [],\n };\n }\n\n // -----------------------------------------------------------------------\n // Contributions (Schedule A)\n // -----------------------------------------------------------------------\n\n async getContributions(opts: {\n committeeId?: string;\n candidateId?: string;\n contributorName?: string;\n minAmount?: number;\n maxAmount?: number;\n cycle?: number;\n }): Promise<FECContribution[]> {\n const params: Record<string, string | number | undefined> = {\n committee_id: opts.committeeId,\n candidate_id: opts.candidateId,\n contributor_name: opts.contributorName,\n min_amount: opts.minAmount,\n max_amount: opts.maxAmount,\n two_year_transaction_period: opts.cycle,\n sort: \"-contribution_receipt_date\",\n };\n\n return this.paginate<FECContribution>(\n \"/schedules/schedule_a/\",\n params,\n (body) =>\n (body.results ?? []).map((r: any) => this.mapContribution(r)),\n );\n }\n\n async getDonorLookup(\n name: string,\n state?: string,\n ): Promise<FECContribution[]> {\n return this.getContributions({\n contributorName: name,\n ...(state ? {} : {}),\n });\n }\n\n private mapContribution(r: any): FECContribution {\n return {\n committeeId: r.committee_id ?? \"\",\n committeeName: r.committee?.name ?? r.committee_name ?? \"\",\n contributorName: r.contributor_name ?? \"\",\n contributorCity: r.contributor_city ?? \"\",\n contributorState: r.contributor_state ?? \"\",\n contributorZip: r.contributor_zip ?? \"\",\n contributorEmployer: r.contributor_employer ?? \"\",\n contributorOccupation: r.contributor_occupation ?? \"\",\n amount: r.contribution_receipt_amount ?? 0,\n date: r.contribution_receipt_date ?? \"\",\n receiptType: r.receipt_type ?? \"\",\n memoText: r.memo_text ?? \"\",\n transactionId: r.transaction_id ?? \"\",\n };\n }\n\n // -----------------------------------------------------------------------\n // Disbursements (Schedule B)\n // -----------------------------------------------------------------------\n\n async getDisbursements(\n committeeId: string,\n cycle?: number,\n ): Promise<FECDisbursement[]> {\n return this.paginate<FECDisbursement>(\n \"/schedules/schedule_b/\",\n {\n committee_id: committeeId,\n two_year_transaction_period: cycle,\n sort: \"-disbursement_date\",\n },\n (body) =>\n (body.results ?? []).map((r: any) => this.mapDisbursement(r)),\n );\n }\n\n private mapDisbursement(r: any): FECDisbursement {\n return {\n committeeId: r.committee_id ?? \"\",\n committeeName: r.committee?.name ?? r.committee_name ?? \"\",\n recipientName: r.recipient_name ?? \"\",\n recipientCity: r.recipient_city ?? \"\",\n recipientState: r.recipient_state ?? \"\",\n amount: r.disbursement_amount ?? 0,\n date: r.disbursement_date ?? \"\",\n description: r.disbursement_description ?? \"\",\n categoryCode: r.disbursement_type ?? \"\",\n memoText: r.memo_text ?? \"\",\n };\n }\n\n // -----------------------------------------------------------------------\n // Filings\n // -----------------------------------------------------------------------\n\n async getFilings(committeeId: string): Promise<FECFiling[]> {\n return this.paginate<FECFiling>(\n \"/committee/${committeeId}/filings/\".replace(\n \"${committeeId}\",\n committeeId,\n ),\n { sort: \"-receipt_date\" },\n (body) => (body.results ?? []).map((r: any) => this.mapFiling(r)),\n );\n }\n\n private mapFiling(r: any): FECFiling {\n return {\n filingId: r.filing_id ?? 0,\n committeeId: r.committee_id ?? \"\",\n committeeName: r.committee_name ?? \"\",\n formType: r.form_type ?? \"\",\n reportType: r.report_type ?? \"\",\n reportYear: r.report_year ?? 0,\n coverageStartDate: r.coverage_start_date ?? \"\",\n coverageEndDate: r.coverage_end_date ?? \"\",\n totalReceipts: r.total_receipts ?? 0,\n totalDisbursements: r.total_disbursements ?? 0,\n cashOnHandEnd: r.cash_on_hand_end_period ?? 0,\n filingDate: r.receipt_date ?? \"\",\n documentUrl: r.document_url ?? r.pdf_url ?? \"\",\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\nexport function createFECClient(config: FECClientConfig = {}): FECClient {\n return new FECClient(config);\n}\n\nexport default FECClient;\n","/**\n * ProPublica Nonprofit Explorer API Client (IRS 990 data)\n *\n * Provides access to IRS Form 990 data for US tax-exempt organizations\n * via ProPublica's free, unauthenticated API.\n *\n * API docs: https://projects.propublica.org/nonprofits/api\n * Rate limit: ~5 requests/second (undocumented; we stay conservative)\n */\n\nimport { RateLimiter, createRateLimiter } from \"./rate-limiter\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface NonprofitOrg {\n ein: string;\n name: string;\n city: string;\n state: string;\n nteeCode: string;\n subsectionCode: number | null;\n classificationCodes: string;\n rulingDate: string;\n score: number;\n}\n\nexport interface Filing990 {\n taxPeriod: string;\n taxPeriodBegin: string;\n taxPeriodEnd: string;\n formType: string;\n pdfUrl: string;\n updatedAt: string;\n totalRevenue: number;\n totalExpenses: number;\n totalAssets: number;\n totalLiabilities: number;\n}\n\nexport interface NonprofitOrgDetail {\n ein: string;\n name: string;\n city: string;\n state: string;\n nteeCode: string;\n subsectionCode: number | null;\n classificationCodes: string;\n rulingDate: string;\n filings: Filing990[];\n}\n\nexport interface ProPublica990ClientConfig {\n timeout?: number;\n maxPages?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Error\n// ---------------------------------------------------------------------------\n\nexport class ProPublica990ClientError extends Error {\n constructor(\n message: string,\n public statusCode?: number,\n ) {\n super(message);\n this.name = \"ProPublica990ClientError\";\n }\n}\n\n// ---------------------------------------------------------------------------\n// Client\n// ---------------------------------------------------------------------------\n\nconst LOG_PREFIX = \"[OSINT:IRS990]\";\n\nexport class ProPublica990Client {\n private baseUrl = \"https://projects.propublica.org/nonprofits/api/v2\";\n private timeout: number;\n private maxPages: number;\n private rateLimiter: RateLimiter;\n\n constructor(config: ProPublica990ClientConfig = {}) {\n this.timeout = config.timeout ?? 15_000;\n this.maxPages = config.maxPages ?? 10;\n // Conservative: 5 req/sec => 5 per 1000ms\n this.rateLimiter = createRateLimiter(\"ProPublica990\", 5, 1_000);\n }\n\n // -----------------------------------------------------------------------\n // Internal helpers\n // -----------------------------------------------------------------------\n\n private async request<T>(\n endpoint: string,\n params: Record<string, string | number | undefined> = {},\n ): Promise<T> {\n await this.rateLimiter.acquire();\n\n const url = new URL(`${this.baseUrl}${endpoint}`);\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== \"\") {\n url.searchParams.set(key, String(value));\n }\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n console.log(`${LOG_PREFIX} GET ${endpoint}`);\n const response = await fetch(url.toString(), {\n headers: { Accept: \"application/json\" },\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const body = await response.text().catch(() => \"\");\n throw new ProPublica990ClientError(\n `ProPublica API error ${response.status}: ${response.statusText} — ${body}`,\n response.status,\n );\n }\n\n return (await response.json()) as T;\n } catch (error) {\n clearTimeout(timeoutId);\n if (error instanceof ProPublica990ClientError) throw error;\n if ((error as Error).name === \"AbortError\") {\n throw new ProPublica990ClientError(\"ProPublica request timed out\");\n }\n throw new ProPublica990ClientError(\n `ProPublica network error: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n // -----------------------------------------------------------------------\n // Search organizations\n // -----------------------------------------------------------------------\n\n async searchOrganizations(\n query: string,\n state?: string,\n ): Promise<NonprofitOrg[]> {\n const allOrgs: NonprofitOrg[] = [];\n let page = 0;\n\n while (page < this.maxPages) {\n const body = await this.request<any>(\n `/search.json`,\n {\n q: query,\n state: state,\n page: page,\n },\n );\n\n const orgs: any[] = body.organizations ?? [];\n if (orgs.length === 0) break;\n\n for (const r of orgs) {\n allOrgs.push(this.mapOrg(r));\n }\n\n // ProPublica returns 25 results per page; if fewer we're done\n if (orgs.length < 25) break;\n page++;\n }\n\n return allOrgs;\n }\n\n // -----------------------------------------------------------------------\n // Get single organization\n // -----------------------------------------------------------------------\n\n async getOrganization(ein: string): Promise<NonprofitOrgDetail> {\n const normalizedEin = ein.replace(/-/g, \"\");\n const body = await this.request<any>(\n `/organizations/${normalizedEin}.json`,\n );\n\n const org = body.organization ?? {};\n const filings = (body.filings_with_data ?? []).map((f: any) =>\n this.mapFiling(f),\n );\n\n return {\n ein: org.ein ? String(org.ein) : normalizedEin,\n name: org.name ?? \"\",\n city: org.city ?? \"\",\n state: org.state ?? \"\",\n nteeCode: org.ntee_code ?? \"\",\n subsectionCode: org.subsection_code ?? null,\n classificationCodes: org.classification_codes ?? \"\",\n rulingDate: org.ruling_date ?? \"\",\n filings,\n };\n }\n\n // -----------------------------------------------------------------------\n // Get filings for an EIN\n // -----------------------------------------------------------------------\n\n async getFilings(ein: string): Promise<Filing990[]> {\n const detail = await this.getOrganization(ein);\n return detail.filings;\n }\n\n // -----------------------------------------------------------------------\n // Mappers\n // -----------------------------------------------------------------------\n\n private mapOrg(r: any): NonprofitOrg {\n return {\n ein: r.ein ? String(r.ein) : \"\",\n name: r.name ?? \"\",\n city: r.city ?? \"\",\n state: r.state ?? \"\",\n nteeCode: r.ntee_code ?? \"\",\n subsectionCode: r.subsection_code ?? null,\n classificationCodes: r.classification_codes ?? \"\",\n rulingDate: r.ruling_date ?? \"\",\n score: r.score ?? 0,\n };\n }\n\n private mapFiling(f: any): Filing990 {\n return {\n taxPeriod: f.tax_prd ? String(f.tax_prd) : \"\",\n taxPeriodBegin: f.tax_prd_yr ? `${f.tax_prd_yr}-01-01` : \"\",\n taxPeriodEnd: f.tax_prd ? String(f.tax_prd) : \"\",\n formType: f.formtype ?? f.form_type ?? \"\",\n pdfUrl: f.pdf_url ?? \"\",\n updatedAt: f.updated ?? \"\",\n totalRevenue: f.totrevenue ?? 0,\n totalExpenses: f.totfuncexpns ?? 0,\n totalAssets: f.totassetsend ?? 0,\n totalLiabilities: f.totliabend ?? 0,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\nexport function createProPublica990Client(\n config: ProPublica990ClientConfig = {},\n): ProPublica990Client {\n return new ProPublica990Client(config);\n}\n\nexport default ProPublica990Client;\n","/**\n * USAspending.gov API Client\n *\n * Provides access to federal spending data including awards, recipients,\n * and agency spending breakdowns.\n *\n * API docs: https://api.usaspending.gov/docs/\n * Rate limit: ~10 requests/second (no auth required, POST-based)\n */\n\nimport { RateLimiter, createRateLimiter } from \"./rate-limiter\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface FederalAward {\n awardId: string;\n generatedUniqueAwardId: string;\n type: string;\n typeDescription: string;\n description: string;\n totalObligationAmount: number;\n totalOutlayAmount: number;\n dateOfAward: string;\n startDate: string;\n endDate: string;\n recipientName: string;\n recipientUei: string;\n awardingAgencyName: string;\n awardingSubAgencyName: string;\n fundingAgencyName: string;\n placeOfPerformanceCity: string;\n placeOfPerformanceState: string;\n}\n\nexport interface RecipientProfile {\n recipientId: string;\n name: string;\n uei: string;\n duns: string;\n recipientLevel: string;\n totalTransactionAmount: number;\n totalFaceValueOfLoans: number;\n totalContractAmount: number;\n totalGrantAmount: number;\n city: string;\n state: string;\n congressionalDistrict: string;\n businessTypes: string[];\n}\n\nexport interface AgencySpending {\n agencyCode: string;\n agencyName: string;\n fiscalYear: number;\n totalBudgetaryResources: number;\n totalObligations: number;\n totalOutlays: number;\n congressionalJustificationUrl: string;\n}\n\nexport interface USASpendingSearchFilters {\n keyword?: string;\n recipient?: string;\n agency?: string;\n dateRange?: { start: string; end: string };\n awardType?: string[];\n}\n\nexport interface USASpendingClientConfig {\n timeout?: number;\n maxPages?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Error\n// ---------------------------------------------------------------------------\n\nexport class USASpendingClientError extends Error {\n constructor(\n message: string,\n public statusCode?: number,\n ) {\n super(message);\n this.name = \"USASpendingClientError\";\n }\n}\n\n// ---------------------------------------------------------------------------\n// Client\n// ---------------------------------------------------------------------------\n\nconst LOG_PREFIX = \"[OSINT:USASpending]\";\n\nexport class USASpendingClient {\n private baseUrl = \"https://api.usaspending.gov/api/v2\";\n private timeout: number;\n private maxPages: number;\n private rateLimiter: RateLimiter;\n\n constructor(config: USASpendingClientConfig = {}) {\n this.timeout = config.timeout ?? 20_000;\n this.maxPages = config.maxPages ?? 10;\n // 10 req/sec\n this.rateLimiter = createRateLimiter(\"USASpending\", 10, 1_000);\n }\n\n // -----------------------------------------------------------------------\n // Internal helpers\n // -----------------------------------------------------------------------\n\n private async post<T>(\n endpoint: string,\n body: Record<string, any>,\n ): Promise<T> {\n await this.rateLimiter.acquire();\n\n const url = `${this.baseUrl}${endpoint}`;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n console.log(`${LOG_PREFIX} POST ${endpoint}`);\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const text = await response.text().catch(() => \"\");\n throw new USASpendingClientError(\n `USAspending API error ${response.status}: ${response.statusText} — ${text}`,\n response.status,\n );\n }\n\n return (await response.json()) as T;\n } catch (error) {\n clearTimeout(timeoutId);\n if (error instanceof USASpendingClientError) throw error;\n if ((error as Error).name === \"AbortError\") {\n throw new USASpendingClientError(\"USAspending request timed out\");\n }\n throw new USASpendingClientError(\n `USAspending network error: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n private async get<T>(\n endpoint: string,\n params: Record<string, string | number | undefined> = {},\n ): Promise<T> {\n await this.rateLimiter.acquire();\n\n const url = new URL(`${this.baseUrl}${endpoint}`);\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== \"\") {\n url.searchParams.set(key, String(value));\n }\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n console.log(`${LOG_PREFIX} GET ${endpoint}`);\n const response = await fetch(url.toString(), {\n headers: { Accept: \"application/json\" },\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const text = await response.text().catch(() => \"\");\n throw new USASpendingClientError(\n `USAspending API error ${response.status}: ${response.statusText} — ${text}`,\n response.status,\n );\n }\n\n return (await response.json()) as T;\n } catch (error) {\n clearTimeout(timeoutId);\n if (error instanceof USASpendingClientError) throw error;\n if ((error as Error).name === \"AbortError\") {\n throw new USASpendingClientError(\"USAspending request timed out\");\n }\n throw new USASpendingClientError(\n `USAspending network error: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n // -----------------------------------------------------------------------\n // Awards search\n // -----------------------------------------------------------------------\n\n async searchAwards(\n filters: USASpendingSearchFilters = {},\n ): Promise<FederalAward[]> {\n const allAwards: FederalAward[] = [];\n let page = 1;\n\n while (page <= this.maxPages) {\n const apiFilters: Record<string, any> = {};\n\n if (filters.keyword) {\n apiFilters.keywords = [filters.keyword];\n }\n if (filters.recipient) {\n apiFilters.recipient_search_text = [filters.recipient];\n }\n if (filters.agency) {\n apiFilters.agencies = [\n {\n type: \"awarding\",\n tier: \"toptier\",\n name: filters.agency,\n },\n ];\n }\n if (filters.dateRange) {\n apiFilters.time_period = [\n {\n start_date: filters.dateRange.start,\n end_date: filters.dateRange.end,\n },\n ];\n }\n if (filters.awardType && filters.awardType.length > 0) {\n apiFilters.award_type_codes = filters.awardType;\n }\n\n const body = await this.post<any>(\"/search/spending_by_award/\", {\n filters: apiFilters,\n fields: [\n \"Award ID\",\n \"Description\",\n \"Award Amount\",\n \"Total Outlays\",\n \"Start Date\",\n \"End Date\",\n \"Recipient Name\",\n \"Awarding Agency\",\n \"Awarding Sub Agency\",\n \"Funding Agency\",\n \"Place of Performance City Code\",\n \"Place of Performance State Code\",\n \"generated_unique_award_id\",\n \"recipient_id\",\n \"Award Type\",\n ],\n page,\n limit: 100,\n sort: \"Award Amount\",\n order: \"desc\",\n });\n\n const results: any[] = body.results ?? [];\n if (results.length === 0) break;\n\n for (const r of results) {\n allAwards.push({\n awardId: r[\"Award ID\"] ?? \"\",\n generatedUniqueAwardId: r.generated_unique_award_id ?? \"\",\n type: r[\"Award Type\"] ?? \"\",\n typeDescription: r[\"Award Type\"] ?? \"\",\n description: r[\"Description\"] ?? \"\",\n totalObligationAmount: r[\"Award Amount\"] ?? 0,\n totalOutlayAmount: r[\"Total Outlays\"] ?? 0,\n dateOfAward: r[\"Start Date\"] ?? \"\",\n startDate: r[\"Start Date\"] ?? \"\",\n endDate: r[\"End Date\"] ?? \"\",\n recipientName: r[\"Recipient Name\"] ?? \"\",\n recipientUei: r.recipient_id ?? \"\",\n awardingAgencyName: r[\"Awarding Agency\"] ?? \"\",\n awardingSubAgencyName: r[\"Awarding Sub Agency\"] ?? \"\",\n fundingAgencyName: r[\"Funding Agency\"] ?? \"\",\n placeOfPerformanceCity: r[\"Place of Performance City Code\"] ?? \"\",\n placeOfPerformanceState: r[\"Place of Performance State Code\"] ?? \"\",\n });\n }\n\n if (!body.page_metadata || page >= (body.page_metadata.num_pages ?? 1)) {\n break;\n }\n\n page++;\n }\n\n return allAwards;\n }\n\n // -----------------------------------------------------------------------\n // Recipients\n // -----------------------------------------------------------------------\n\n async searchRecipients(query: string): Promise<RecipientProfile[]> {\n const allRecipients: RecipientProfile[] = [];\n let page = 1;\n\n while (page <= this.maxPages) {\n const body = await this.post<any>(\"/recipient/duns/\", {\n keyword: query,\n page,\n limit: 100,\n });\n\n const results: any[] = body.results ?? [];\n if (results.length === 0) break;\n\n for (const r of results) {\n allRecipients.push(this.mapRecipient(r));\n }\n\n if (results.length < 100) break;\n page++;\n }\n\n return allRecipients;\n }\n\n async getRecipient(recipientId: string): Promise<RecipientProfile> {\n const body = await this.get<any>(\n `/recipient/${encodeURIComponent(recipientId)}/`,\n );\n\n return this.mapRecipient(body);\n }\n\n private mapRecipient(r: any): RecipientProfile {\n return {\n recipientId: r.recipient_id ?? r.id ?? \"\",\n name: r.name ?? r.recipient_name ?? \"\",\n uei: r.uei ?? \"\",\n duns: r.duns ?? \"\",\n recipientLevel: r.recipient_level ?? \"\",\n totalTransactionAmount: r.total_transaction_amount ?? 0,\n totalFaceValueOfLoans: r.total_face_value_of_loans ?? 0,\n totalContractAmount: r.total_contract_amount ?? 0,\n totalGrantAmount: r.total_grant_amount ?? 0,\n city: r.location?.city_name ?? r.city ?? \"\",\n state: r.location?.state_code ?? r.state ?? \"\",\n congressionalDistrict: r.location?.congressional_code ?? \"\",\n businessTypes: r.business_types ?? [],\n };\n }\n\n // -----------------------------------------------------------------------\n // Agency spending\n // -----------------------------------------------------------------------\n\n async getAgencySpending(\n agencyCode: string,\n fiscalYear?: number,\n ): Promise<AgencySpending> {\n const fy = fiscalYear ?? new Date().getFullYear();\n\n const body = await this.get<any>(\n `/agency/${agencyCode}/`,\n { fiscal_year: fy },\n );\n\n return {\n agencyCode: body.toptier_code ?? agencyCode,\n agencyName: body.name ?? \"\",\n fiscalYear: fy,\n totalBudgetaryResources: body.budget_authority_amount ?? 0,\n totalObligations: body.obligated_amount ?? 0,\n totalOutlays: body.outlay_amount ?? 0,\n congressionalJustificationUrl: body.congressional_justification_url ?? \"\",\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\nexport function createUSASpendingClient(\n config: USASpendingClientConfig = {},\n): USASpendingClient {\n return new USASpendingClient(config);\n}\n\nexport default USASpendingClient;\n","/**\n * SEC EDGAR API Client\n *\n * Provides access to SEC filings, company data, insider transactions,\n * and structured XBRL financial data.\n *\n * API docs:\n * - Structured data: https://data.sec.gov/\n * - Full-text search: https://efts.sec.gov/LATEST/\n *\n * Rate limit: 10 requests/second. MUST include a descriptive User-Agent.\n */\n\nimport { env } from \"../../config/env\";\nimport { RateLimiter, createRateLimiter } from \"./rate-limiter\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface SECCompany {\n cik: string;\n name: string;\n ticker: string;\n exchange: string;\n sic: string;\n sicDescription: string;\n stateOfIncorporation: string;\n fiscalYearEnd: string;\n}\n\nexport interface SECFiling {\n accessionNumber: string;\n formType: string;\n filingDate: string;\n reportDate: string;\n acceptanceDateTime: string;\n primaryDocument: string;\n primaryDocDescription: string;\n filingUrl: string;\n size: number;\n}\n\nexport interface InsiderTransaction {\n accessionNumber: string;\n filingDate: string;\n reportingOwnerCik: string;\n reportingOwnerName: string;\n isDirector: boolean;\n isOfficer: boolean;\n officerTitle: string;\n transactionDate: string;\n transactionCode: string;\n transactionShares: number;\n transactionPricePerShare: number;\n sharesOwnedFollowing: number;\n directOrIndirect: string;\n}\n\nexport interface SECCompanyFacts {\n cik: string;\n entityName: string;\n facts: Record<string, Record<string, {\n label: string;\n description: string;\n units: Record<string, Array<{\n start?: string;\n end: string;\n val: number;\n accn: string;\n fy: number;\n fp: string;\n form: string;\n filed: string;\n }>>;\n }>>;\n}\n\nexport interface SECEdgarClientConfig {\n userAgent?: string;\n timeout?: number;\n maxPages?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Error\n// ---------------------------------------------------------------------------\n\nexport class SECEdgarClientError extends Error {\n constructor(\n message: string,\n public statusCode?: number,\n ) {\n super(message);\n this.name = \"SECEdgarClientError\";\n }\n}\n\n// ---------------------------------------------------------------------------\n// Client\n// ---------------------------------------------------------------------------\n\nconst LOG_PREFIX = \"[OSINT:SEC]\";\n\nexport class SECEdgarClient {\n private dataBaseUrl = \"https://data.sec.gov\";\n private searchBaseUrl = \"https://efts.sec.gov/LATEST\";\n private userAgent: string;\n private timeout: number;\n private maxPages: number;\n private rateLimiter: RateLimiter;\n\n /** Cache ticker -> CIK lookups so we don't repeat the same search */\n private tickerCikCache: Map<string, string> = new Map();\n\n constructor(config: SECEdgarClientConfig = {}) {\n this.userAgent =\n config.userAgent ?? env.SEC_EDGAR_USER_AGENT ?? \"OpenSentinel/2.1 (contact@opensentinel.ai)\";\n this.timeout = config.timeout ?? 15_000;\n this.maxPages = config.maxPages ?? 10;\n // 10 req/sec\n this.rateLimiter = createRateLimiter(\"SEC\", 10, 1_000);\n }\n\n // -----------------------------------------------------------------------\n // Internal helpers\n // -----------------------------------------------------------------------\n\n /**\n * Pad a CIK number to 10 digits with leading zeros.\n */\n private padCik(cik: string | number): string {\n return String(cik).replace(/\\D/g, \"\").padStart(10, \"0\");\n }\n\n private async fetchJson<T>(url: string): Promise<T> {\n await this.rateLimiter.acquire();\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n console.log(`${LOG_PREFIX} GET ${url}`);\n const response = await fetch(url, {\n headers: {\n \"User-Agent\": this.userAgent,\n Accept: \"application/json\",\n },\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const body = await response.text().catch(() => \"\");\n throw new SECEdgarClientError(\n `SEC EDGAR error ${response.status}: ${response.statusText} — ${body}`,\n response.status,\n );\n }\n\n return (await response.json()) as T;\n } catch (error) {\n clearTimeout(timeoutId);\n if (error instanceof SECEdgarClientError) throw error;\n if ((error as Error).name === \"AbortError\") {\n throw new SECEdgarClientError(\"SEC EDGAR request timed out\");\n }\n throw new SECEdgarClientError(\n `SEC EDGAR network error: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n // -----------------------------------------------------------------------\n // Search companies (full-text search endpoint)\n // -----------------------------------------------------------------------\n\n async searchCompanies(query: string): Promise<SECCompany[]> {\n const url = new URL(`${this.searchBaseUrl}/search-index`);\n url.searchParams.set(\"q\", query);\n url.searchParams.set(\"dateRange\", \"custom\");\n url.searchParams.set(\"forms\", \"10-K\");\n\n // EDGAR full-text search: use the company search endpoint\n const searchUrl = new URL(`${this.searchBaseUrl}/search-index`);\n searchUrl.searchParams.set(\"q\", `\"${query}\"`);\n searchUrl.searchParams.set(\"forms\", \"10-K\");\n\n // Try the company-tickers JSON first (more reliable for name lookups)\n try {\n const tickers = await this.fetchJson<Record<string, {\n cik_str: number;\n ticker: string;\n title: string;\n }>>(`${this.dataBaseUrl}/files/company_tickers.json`);\n\n const lowerQuery = query.toLowerCase();\n const matches: SECCompany[] = [];\n\n for (const entry of Object.values(tickers)) {\n if (\n entry.title.toLowerCase().includes(lowerQuery) ||\n entry.ticker.toLowerCase().includes(lowerQuery)\n ) {\n matches.push({\n cik: this.padCik(entry.cik_str),\n name: entry.title,\n ticker: entry.ticker,\n exchange: \"\",\n sic: \"\",\n sicDescription: \"\",\n stateOfIncorporation: \"\",\n fiscalYearEnd: \"\",\n });\n }\n if (matches.length >= 25) break;\n }\n\n return matches;\n } catch (error) {\n console.log(`${LOG_PREFIX} Ticker file search failed, falling back to EFTS`);\n // Fallback: use the EFTS endpoint\n const eftsBody = await this.fetchJson<any>(\n `${this.searchBaseUrl}/search-index?q=${encodeURIComponent(query)}&forms=10-K`,\n );\n\n const hits: any[] = eftsBody.hits?.hits ?? [];\n return hits.slice(0, 25).map((h: any) => ({\n cik: this.padCik(h._source?.entity_id ?? \"\"),\n name: h._source?.entity_name ?? \"\",\n ticker: \"\",\n exchange: \"\",\n sic: \"\",\n sicDescription: \"\",\n stateOfIncorporation: \"\",\n fiscalYearEnd: \"\",\n }));\n }\n }\n\n // -----------------------------------------------------------------------\n // Company filings\n // -----------------------------------------------------------------------\n\n async getCompanyFilings(\n cik: string,\n formType?: string,\n ): Promise<SECFiling[]> {\n const paddedCik = this.padCik(cik);\n const body = await this.fetchJson<any>(\n `${this.dataBaseUrl}/submissions/CIK${paddedCik}.json`,\n );\n\n const recent = body.filings?.recent ?? {};\n const accessionNumbers: string[] = recent.accessionNumber ?? [];\n const forms: string[] = recent.form ?? [];\n const filingDates: string[] = recent.filingDate ?? [];\n const reportDates: string[] = recent.reportDate ?? [];\n const acceptanceDateTimes: string[] = recent.acceptanceDateTime ?? [];\n const primaryDocuments: string[] = recent.primaryDocument ?? [];\n const primaryDocDescriptions: string[] = recent.primaryDocDescription ?? [];\n const sizes: number[] = recent.size ?? [];\n\n const allFilings: SECFiling[] = [];\n\n for (let i = 0; i < accessionNumbers.length; i++) {\n const form = forms[i] ?? \"\";\n if (formType && form !== formType) continue;\n\n const accession = accessionNumbers[i] ?? \"\";\n const accessionClean = accession.replace(/-/g, \"\");\n\n allFilings.push({\n accessionNumber: accession,\n formType: form,\n filingDate: filingDates[i] ?? \"\",\n reportDate: reportDates[i] ?? \"\",\n acceptanceDateTime: acceptanceDateTimes[i] ?? \"\",\n primaryDocument: primaryDocuments[i] ?? \"\",\n primaryDocDescription: primaryDocDescriptions[i] ?? \"\",\n filingUrl: `https://www.sec.gov/Archives/edgar/data/${parseInt(cik, 10)}/${accessionClean}/${primaryDocuments[i] ?? \"\"}`,\n size: sizes[i] ?? 0,\n });\n }\n\n // Also fetch additional filing pages if they exist\n const additionalFiles: string[] = body.filings?.files ?? [];\n let pagesLoaded = 1;\n\n for (const file of additionalFiles) {\n if (pagesLoaded >= this.maxPages) break;\n\n try {\n const additionalBody = await this.fetchJson<any>(\n `${this.dataBaseUrl}/submissions/${file}`,\n );\n\n const addAccessions: string[] = additionalBody.accessionNumber ?? [];\n const addForms: string[] = additionalBody.form ?? [];\n const addFilingDates: string[] = additionalBody.filingDate ?? [];\n const addReportDates: string[] = additionalBody.reportDate ?? [];\n const addAcceptanceDates: string[] = additionalBody.acceptanceDateTime ?? [];\n const addPrimaryDocs: string[] = additionalBody.primaryDocument ?? [];\n const addPrimaryDescriptions: string[] = additionalBody.primaryDocDescription ?? [];\n const addSizes: number[] = additionalBody.size ?? [];\n\n for (let i = 0; i < addAccessions.length; i++) {\n const form = addForms[i] ?? \"\";\n if (formType && form !== formType) continue;\n\n const accession = addAccessions[i] ?? \"\";\n const accessionClean = accession.replace(/-/g, \"\");\n\n allFilings.push({\n accessionNumber: accession,\n formType: form,\n filingDate: addFilingDates[i] ?? \"\",\n reportDate: addReportDates[i] ?? \"\",\n acceptanceDateTime: addAcceptanceDates[i] ?? \"\",\n primaryDocument: addPrimaryDocs[i] ?? \"\",\n primaryDocDescription: addPrimaryDescriptions[i] ?? \"\",\n filingUrl: `https://www.sec.gov/Archives/edgar/data/${parseInt(cik, 10)}/${accessionClean}/${addPrimaryDocs[i] ?? \"\"}`,\n size: addSizes[i] ?? 0,\n });\n }\n\n pagesLoaded++;\n } catch (error) {\n console.log(\n `${LOG_PREFIX} Failed to fetch additional filings page ${file}: ${error instanceof Error ? error.message : String(error)}`,\n );\n break;\n }\n }\n\n return allFilings;\n }\n\n // -----------------------------------------------------------------------\n // Insider transactions (Forms 3, 4, 5)\n // -----------------------------------------------------------------------\n\n async getInsiderTransactions(cik: string): Promise<InsiderTransaction[]> {\n // Get form 4 filings (most common insider transaction form)\n const filings = await this.getCompanyFilings(cik, \"4\");\n const transactions: InsiderTransaction[] = [];\n\n // Parse the filing index pages for structured ownership data\n // Use the ownership endpoint instead for bulk data\n const paddedCik = this.padCik(cik);\n\n try {\n const body = await this.fetchJson<any>(\n `${this.dataBaseUrl}/api/xbrl/companyfacts/CIK${paddedCik}.json`,\n );\n\n // Insider transactions appear in filings; return filing metadata\n for (const filing of filings.slice(0, 100)) {\n transactions.push({\n accessionNumber: filing.accessionNumber,\n filingDate: filing.filingDate,\n reportingOwnerCik: \"\",\n reportingOwnerName: filing.primaryDocDescription || \"See filing\",\n isDirector: false,\n isOfficer: false,\n officerTitle: \"\",\n transactionDate: filing.reportDate || filing.filingDate,\n transactionCode: \"\",\n transactionShares: 0,\n transactionPricePerShare: 0,\n sharesOwnedFollowing: 0,\n directOrIndirect: \"D\",\n });\n }\n } catch {\n // If XBRL endpoint fails, still return basic filing data\n for (const filing of filings.slice(0, 100)) {\n transactions.push({\n accessionNumber: filing.accessionNumber,\n filingDate: filing.filingDate,\n reportingOwnerCik: \"\",\n reportingOwnerName: filing.primaryDocDescription || \"See filing\",\n isDirector: false,\n isOfficer: false,\n officerTitle: \"\",\n transactionDate: filing.reportDate || filing.filingDate,\n transactionCode: \"\",\n transactionShares: 0,\n transactionPricePerShare: 0,\n sharesOwnedFollowing: 0,\n directOrIndirect: \"D\",\n });\n }\n }\n\n return transactions;\n }\n\n // -----------------------------------------------------------------------\n // Company facts (structured XBRL data)\n // -----------------------------------------------------------------------\n\n async getCompanyFacts(cik: string): Promise<SECCompanyFacts> {\n const paddedCik = this.padCik(cik);\n const body = await this.fetchJson<any>(\n `${this.dataBaseUrl}/api/xbrl/companyfacts/CIK${paddedCik}.json`,\n );\n\n return {\n cik: paddedCik,\n entityName: body.entityName ?? \"\",\n facts: body.facts ?? {},\n };\n }\n\n // -----------------------------------------------------------------------\n // Ticker -> CIK lookup\n // -----------------------------------------------------------------------\n\n async lookupCikByTicker(ticker: string): Promise<string | null> {\n const upperTicker = ticker.toUpperCase();\n\n // Check cache\n if (this.tickerCikCache.has(upperTicker)) {\n return this.tickerCikCache.get(upperTicker)!;\n }\n\n try {\n const tickers = await this.fetchJson<Record<string, {\n cik_str: number;\n ticker: string;\n title: string;\n }>>(`${this.dataBaseUrl}/files/company_tickers.json`);\n\n for (const entry of Object.values(tickers)) {\n if (entry.ticker.toUpperCase() === upperTicker) {\n const paddedCik = this.padCik(entry.cik_str);\n this.tickerCikCache.set(upperTicker, paddedCik);\n return paddedCik;\n }\n }\n\n return null;\n } catch (error) {\n console.log(\n `${LOG_PREFIX} Ticker lookup failed for ${ticker}: ${error instanceof Error ? error.message : String(error)}`,\n );\n return null;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\nexport function createSECEdgarClient(\n config: SECEdgarClientConfig = {},\n): SECEdgarClient {\n return new SECEdgarClient(config);\n}\n\nexport default SECEdgarClient;\n","/**\n * OpenCorporates API Client\n *\n * Provides access to the world's largest open database of companies,\n * including corporate registrations, officers, and filings across\n * multiple jurisdictions.\n *\n * API docs: https://api.opencorporates.com/documentation\n * Rate limit: 200 free requests/month (unauthenticated); higher with token.\n * Token passed as ?api_token= query param.\n */\n\nimport { env } from \"../../config/env\";\nimport { RateLimiter, createRateLimiter } from \"./rate-limiter\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface CorporateEntity {\n companyNumber: string;\n name: string;\n jurisdictionCode: string;\n incorporationDate: string;\n dissolutionDate: string;\n companyType: string;\n registryUrl: string;\n status: string;\n registeredAddress: string;\n agentName: string;\n agentAddress: string;\n officers: CorporateOfficer[];\n openCorporatesUrl: string;\n source: string;\n updatedAt: string;\n}\n\nexport interface CorporateOfficer {\n id: number;\n name: string;\n position: string;\n startDate: string;\n endDate: string;\n nationality: string;\n occupation: string;\n companyNumber: string;\n companyName: string;\n jurisdictionCode: string;\n}\n\nexport interface CorporateFiling {\n id: number;\n title: string;\n date: string;\n description: string;\n filingType: string;\n url: string;\n openCorporatesUrl: string;\n}\n\nexport interface OpenCorporatesClientConfig {\n apiToken?: string;\n timeout?: number;\n maxPages?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Error\n// ---------------------------------------------------------------------------\n\nexport class OpenCorporatesClientError extends Error {\n constructor(\n message: string,\n public statusCode?: number,\n ) {\n super(message);\n this.name = \"OpenCorporatesClientError\";\n }\n}\n\n// ---------------------------------------------------------------------------\n// Client\n// ---------------------------------------------------------------------------\n\nconst LOG_PREFIX = \"[OSINT:OpenCorporates]\";\n\nexport class OpenCorporatesClient {\n private baseUrl = \"https://api.opencorporates.com/v0.4\";\n private apiToken: string;\n private timeout: number;\n private maxPages: number;\n private rateLimiter: RateLimiter;\n\n constructor(config: OpenCorporatesClientConfig = {}) {\n this.apiToken = config.apiToken ?? env.OPENCORPORATES_API_TOKEN ?? \"\";\n this.timeout = config.timeout ?? 15_000;\n this.maxPages = config.maxPages ?? 10;\n // Conservative: ~1 req/sec for free tier (200/month is very limited)\n this.rateLimiter = createRateLimiter(\"OpenCorporates\", 1, 1_000);\n }\n\n // -----------------------------------------------------------------------\n // Internal helpers\n // -----------------------------------------------------------------------\n\n private async request<T>(\n endpoint: string,\n params: Record<string, string | number | undefined> = {},\n ): Promise<T> {\n await this.rateLimiter.acquire();\n\n const url = new URL(`${this.baseUrl}${endpoint}`);\n\n if (this.apiToken) {\n url.searchParams.set(\"api_token\", this.apiToken);\n }\n\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== \"\") {\n url.searchParams.set(key, String(value));\n }\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n console.log(`${LOG_PREFIX} GET ${endpoint}`);\n const response = await fetch(url.toString(), {\n headers: { Accept: \"application/json\" },\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const body = await response.text().catch(() => \"\");\n throw new OpenCorporatesClientError(\n `OpenCorporates API error ${response.status}: ${response.statusText} — ${body}`,\n response.status,\n );\n }\n\n return (await response.json()) as T;\n } catch (error) {\n clearTimeout(timeoutId);\n if (error instanceof OpenCorporatesClientError) throw error;\n if ((error as Error).name === \"AbortError\") {\n throw new OpenCorporatesClientError(\n \"OpenCorporates request timed out\",\n );\n }\n throw new OpenCorporatesClientError(\n `OpenCorporates network error: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n // -----------------------------------------------------------------------\n // Search companies\n // -----------------------------------------------------------------------\n\n async searchCompanies(\n query: string,\n jurisdiction?: string,\n ): Promise<CorporateEntity[]> {\n const allCompanies: CorporateEntity[] = [];\n let page = 1;\n\n while (page <= this.maxPages) {\n const params: Record<string, string | number | undefined> = {\n q: query,\n page,\n per_page: 30,\n };\n\n if (jurisdiction) {\n params.jurisdiction_code = jurisdiction;\n }\n\n const body = await this.request<any>(\"/companies/search\", params);\n const companies: any[] =\n body.results?.companies ?? [];\n\n if (companies.length === 0) break;\n\n for (const wrapper of companies) {\n const c = wrapper.company ?? wrapper;\n allCompanies.push(this.mapCompany(c));\n }\n\n // OpenCorporates returns up to 30 per page\n const totalPages = body.results?.total_pages ?? 1;\n if (page >= totalPages || companies.length < 30) break;\n page++;\n }\n\n return allCompanies;\n }\n\n // -----------------------------------------------------------------------\n // Get single company\n // -----------------------------------------------------------------------\n\n async getCompany(\n jurisdictionCode: string,\n companyNumber: string,\n ): Promise<CorporateEntity> {\n const body = await this.request<any>(\n `/companies/${encodeURIComponent(jurisdictionCode)}/${encodeURIComponent(companyNumber)}`,\n );\n\n const c = body.results?.company ?? body.company ?? {};\n return this.mapCompany(c);\n }\n\n // -----------------------------------------------------------------------\n // Search officers\n // -----------------------------------------------------------------------\n\n async searchOfficers(\n query: string,\n jurisdiction?: string,\n ): Promise<CorporateOfficer[]> {\n const allOfficers: CorporateOfficer[] = [];\n let page = 1;\n\n while (page <= this.maxPages) {\n const params: Record<string, string | number | undefined> = {\n q: query,\n page,\n per_page: 30,\n };\n\n if (jurisdiction) {\n params.jurisdiction_code = jurisdiction;\n }\n\n const body = await this.request<any>(\"/officers/search\", params);\n const officers: any[] = body.results?.officers ?? [];\n\n if (officers.length === 0) break;\n\n for (const wrapper of officers) {\n const o = wrapper.officer ?? wrapper;\n allOfficers.push(this.mapOfficer(o));\n }\n\n const totalPages = body.results?.total_pages ?? 1;\n if (page >= totalPages || officers.length < 30) break;\n page++;\n }\n\n return allOfficers;\n }\n\n // -----------------------------------------------------------------------\n // Get filings for a company\n // -----------------------------------------------------------------------\n\n async getFilings(\n jurisdictionCode: string,\n companyNumber: string,\n ): Promise<CorporateFiling[]> {\n const allFilings: CorporateFiling[] = [];\n let page = 1;\n\n while (page <= this.maxPages) {\n const body = await this.request<any>(\n `/companies/${encodeURIComponent(jurisdictionCode)}/${encodeURIComponent(companyNumber)}/filings`,\n { page, per_page: 30 },\n );\n\n const filings: any[] = body.results?.filings ?? [];\n if (filings.length === 0) break;\n\n for (const wrapper of filings) {\n const f = wrapper.filing ?? wrapper;\n allFilings.push(this.mapFiling(f));\n }\n\n const totalPages = body.results?.total_pages ?? 1;\n if (page >= totalPages || filings.length < 30) break;\n page++;\n }\n\n return allFilings;\n }\n\n // -----------------------------------------------------------------------\n // Mappers\n // -----------------------------------------------------------------------\n\n private mapCompany(c: any): CorporateEntity {\n const officers: CorporateOfficer[] = (c.officers ?? []).map(\n (wrapper: any) => {\n const o = wrapper.officer ?? wrapper;\n return this.mapOfficer(o);\n },\n );\n\n return {\n companyNumber: c.company_number ?? \"\",\n name: c.name ?? \"\",\n jurisdictionCode: c.jurisdiction_code ?? \"\",\n incorporationDate: c.incorporation_date ?? \"\",\n dissolutionDate: c.dissolution_date ?? \"\",\n companyType: c.company_type ?? \"\",\n registryUrl: c.registry_url ?? \"\",\n status: c.current_status ?? c.status ?? \"\",\n registeredAddress: c.registered_address_in_full ?? c.registered_address ?? \"\",\n agentName: c.agent_name ?? \"\",\n agentAddress: c.agent_address ?? \"\",\n officers,\n openCorporatesUrl: c.opencorporates_url ?? \"\",\n source: c.source?.publisher ?? \"\",\n updatedAt: c.updated_at ?? \"\",\n };\n }\n\n private mapOfficer(o: any): CorporateOfficer {\n const company = o.company ?? {};\n return {\n id: o.id ?? 0,\n name: o.name ?? \"\",\n position: o.position ?? \"\",\n startDate: o.start_date ?? \"\",\n endDate: o.end_date ?? \"\",\n nationality: o.nationality ?? \"\",\n occupation: o.occupation ?? \"\",\n companyNumber: company.company_number ?? \"\",\n companyName: company.name ?? \"\",\n jurisdictionCode: company.jurisdiction_code ?? \"\",\n };\n }\n\n private mapFiling(f: any): CorporateFiling {\n return {\n id: f.id ?? 0,\n title: f.title ?? \"\",\n date: f.date ?? \"\",\n description: f.description ?? \"\",\n filingType: f.filing_type ?? \"\",\n url: f.url ?? \"\",\n openCorporatesUrl: f.opencorporates_url ?? \"\",\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\nexport function createOpenCorporatesClient(\n config: OpenCorporatesClientConfig = {},\n): OpenCorporatesClient {\n return new OpenCorporatesClient(config);\n}\n\nexport default OpenCorporatesClient;\n","/**\n * Public Records Integration for OpenSentinel\n *\n * Provides access to government and public records APIs:\n * - FEC / OpenFEC — Campaign finance data\n * - ProPublica Nonprofit Explorer — IRS 990 filings\n * - USAspending.gov — Federal spending data\n * - SEC EDGAR — Corporate filings, insider transactions, XBRL data\n * - OpenCorporates — Global corporate registry data\n */\n\n// Rate limiter\nexport { RateLimiter, createRateLimiter } from \"./rate-limiter\";\n\n// FEC exports\nexport {\n FECClient,\n createFECClient,\n FECClientError,\n type FECCandidate,\n type FECCommittee,\n type FECContribution,\n type FECDisbursement,\n type FECFiling,\n type FECClientConfig,\n} from \"./fec-client\";\n\n// ProPublica 990 exports\nexport {\n ProPublica990Client,\n createProPublica990Client,\n ProPublica990ClientError,\n type NonprofitOrg,\n type NonprofitOrgDetail,\n type Filing990,\n type ProPublica990ClientConfig,\n} from \"./propublica990-client\";\n\n// USAspending exports\nexport {\n USASpendingClient,\n createUSASpendingClient,\n USASpendingClientError,\n type FederalAward,\n type RecipientProfile,\n type AgencySpending,\n type USASpendingSearchFilters,\n type USASpendingClientConfig,\n} from \"./usaspending-client\";\n\n// SEC EDGAR exports\nexport {\n SECEdgarClient,\n createSECEdgarClient,\n SECEdgarClientError,\n type SECCompany,\n type SECFiling,\n type InsiderTransaction,\n type SECCompanyFacts,\n type SECEdgarClientConfig,\n} from \"./sec-edgar-client\";\n\n// OpenCorporates exports\nexport {\n OpenCorporatesClient,\n createOpenCorporatesClient,\n OpenCorporatesClientError,\n type CorporateEntity,\n type CorporateOfficer,\n type CorporateFiling,\n type OpenCorporatesClientConfig,\n} from \"./opencorporates-client\";\n\n// ---------------------------------------------------------------------------\n// Facade\n// ---------------------------------------------------------------------------\n\nimport { FECClient, type FECClientConfig } from \"./fec-client\";\nimport {\n ProPublica990Client,\n type ProPublica990ClientConfig,\n} from \"./propublica990-client\";\nimport {\n USASpendingClient,\n type USASpendingClientConfig,\n} from \"./usaspending-client\";\nimport {\n SECEdgarClient,\n type SECEdgarClientConfig,\n} from \"./sec-edgar-client\";\nimport {\n OpenCorporatesClient,\n type OpenCorporatesClientConfig,\n} from \"./opencorporates-client\";\n\nexport interface PublicRecordsConfig {\n fec?: FECClientConfig;\n irs990?: ProPublica990ClientConfig;\n usaspending?: USASpendingClientConfig;\n sec?: SECEdgarClientConfig;\n opencorporates?: OpenCorporatesClientConfig;\n}\n\n/**\n * Main PublicRecords class that combines all public records API clients.\n * Follows the same facade pattern as the Finance integration.\n */\nexport class PublicRecords {\n public readonly fec: FECClient;\n public readonly irs990: ProPublica990Client;\n public readonly usaspending: USASpendingClient;\n public readonly sec: SECEdgarClient;\n public readonly opencorporates: OpenCorporatesClient;\n\n constructor(config: PublicRecordsConfig = {}) {\n this.fec = new FECClient(config.fec);\n this.irs990 = new ProPublica990Client(config.irs990);\n this.usaspending = new USASpendingClient(config.usaspending);\n this.sec = new SECEdgarClient(config.sec);\n this.opencorporates = new OpenCorporatesClient(config.opencorporates);\n }\n}\n\n/**\n * Factory function for creating a PublicRecords facade instance.\n */\nexport function createPublicRecords(\n config: PublicRecordsConfig = {},\n): PublicRecords {\n return new PublicRecords(config);\n}\n\nexport default PublicRecords;\n","/**\n * Neo4j Graph Database Client\n *\n * Provides a singleton driver for Neo4j, used by the OSINT knowledge-graph\n * pipeline and the general graph-ops layer. Reads connection details from\n * the shared env config (NEO4J_URI, NEO4J_USER, NEO4J_PASSWORD, NEO4J_DATABASE).\n */\n\nimport neo4j, {\n type Driver,\n type Session,\n type QueryResult,\n type RecordShape,\n} from \"neo4j-driver\";\nimport { env } from \"../../config/env\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface Neo4jConfig {\n uri?: string;\n user?: string;\n password?: string;\n database?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Client\n// ---------------------------------------------------------------------------\n\nexport class Neo4jClient {\n private driver: Driver;\n private database: string;\n\n constructor(config?: Neo4jConfig) {\n const uri = config?.uri ?? env.NEO4J_URI;\n const user = config?.user ?? env.NEO4J_USER;\n const password = config?.password ?? env.NEO4J_PASSWORD;\n this.database = config?.database ?? env.NEO4J_DATABASE;\n\n try {\n this.driver = neo4j.driver(uri, neo4j.auth.basic(user, password));\n console.log(\"[Neo4j] Driver created for\", uri);\n } catch (err) {\n console.log(\"[Neo4j] Failed to create driver:\", err);\n throw err;\n }\n }\n\n // -------------------------------------------------------------------------\n // Public helpers\n // -------------------------------------------------------------------------\n\n /**\n * Execute a read-only Cypher query and return the result records.\n */\n async runQuery<T extends RecordShape = RecordShape>(\n cypher: string,\n params?: Record<string, unknown>,\n ): Promise<QueryResult<T>> {\n const session = this.getSession(\"READ\");\n try {\n const result = await session.run<T>(cypher, params ?? {});\n return result;\n } catch (err) {\n console.log(\"[Neo4j] Read query failed:\", err);\n throw err;\n } finally {\n await session.close();\n }\n }\n\n /**\n * Execute a write Cypher query and return the result records.\n */\n async runWrite<T extends RecordShape = RecordShape>(\n cypher: string,\n params?: Record<string, unknown>,\n ): Promise<QueryResult<T>> {\n const session = this.getSession(\"WRITE\");\n try {\n const result = await session.run<T>(cypher, params ?? {});\n return result;\n } catch (err) {\n console.log(\"[Neo4j] Write query failed:\", err);\n throw err;\n } finally {\n await session.close();\n }\n }\n\n /**\n * Verify that the driver can reach the Neo4j server.\n */\n async verifyConnectivity(): Promise<boolean> {\n try {\n await this.driver.verifyConnectivity();\n console.log(\"[Neo4j] Connectivity verified\");\n return true;\n } catch (err) {\n console.log(\"[Neo4j] Connectivity check failed:\", err);\n return false;\n }\n }\n\n /**\n * Get a raw session for advanced use-cases (caller is responsible for closing).\n */\n getSession(defaultAccessMode: \"READ\" | \"WRITE\" = \"READ\"): Session {\n return this.driver.session({\n database: this.database,\n defaultAccessMode:\n defaultAccessMode === \"READ\" ? neo4j.session.READ : neo4j.session.WRITE,\n });\n }\n\n /**\n * Gracefully close the underlying driver.\n */\n async close(): Promise<void> {\n try {\n await this.driver.close();\n console.log(\"[Neo4j] Driver closed\");\n } catch (err) {\n console.log(\"[Neo4j] Error closing driver:\", err);\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Singleton factory\n// ---------------------------------------------------------------------------\n\nlet _instance: Neo4jClient | null = null;\n\n/**\n * Returns a lazily-initialised Neo4jClient singleton.\n * Optionally pass config to override env defaults (only the first call wins).\n */\nexport function getNeo4jClient(config?: Neo4jConfig): Neo4jClient {\n if (!_instance) {\n _instance = new Neo4jClient(config);\n }\n return _instance;\n}\n","/**\n * Graph CRUD Operations (Neo4j + Postgres dual-write)\n *\n * Every mutation writes to both Postgres (source of truth) and Neo4j\n * (optimised for traversal queries). Read operations pick the store\n * that best fits the access pattern: Postgres for exact lookups, Neo4j\n * for path / neighbourhood / fulltext queries.\n */\n\nimport { eq, ilike } from \"drizzle-orm\";\nimport {\n db,\n graphEntities,\n graphRelationships,\n type NewGraphEntity,\n type NewGraphRelationship,\n} from \"../../db\";\nimport { getNeo4jClient } from \"./client\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type EntityType =\n | \"person\"\n | \"organization\"\n | \"committee\"\n | \"contract\"\n | \"filing\"\n | \"location\"\n | \"topic\";\n\nexport interface GraphEntity {\n id?: string;\n pgId?: string;\n type: EntityType;\n name: string;\n aliases?: string[];\n description?: string;\n attributes?: Record<string, unknown>;\n importance?: number;\n source?: string;\n}\n\nexport interface GraphRelationship {\n id?: string;\n sourceId: string; // pgId of source entity\n targetId: string; // pgId of target entity\n type: string;\n strength?: number;\n attributes?: Record<string, unknown>;\n context?: string;\n source?: string;\n}\n\nexport interface NeighborNode {\n pgId: string;\n name: string;\n type: string;\n importance: number;\n}\n\nexport interface NeighborEdge {\n sourcePgId: string;\n targetPgId: string;\n type: string;\n strength: number;\n}\n\nexport interface NeighborResult {\n nodes: NeighborNode[];\n edges: NeighborEdge[];\n}\n\nexport interface PathResult {\n nodes: NeighborNode[];\n edges: NeighborEdge[];\n length: number;\n}\n\nexport interface Community {\n id: number;\n members: NeighborNode[];\n}\n\n// ---------------------------------------------------------------------------\n// Entity CRUD\n// ---------------------------------------------------------------------------\n\n/**\n * Create an entity in both Postgres and Neo4j.\n * Returns the Postgres UUID (pgId).\n */\nexport async function createEntity(entity: GraphEntity): Promise<string> {\n // 1. Insert into Postgres\n const [row] = await db\n .insert(graphEntities)\n .values({\n type: entity.type,\n name: entity.name,\n aliases: entity.aliases ?? [],\n description: entity.description ?? null,\n attributes: entity.attributes ?? {},\n importance: entity.importance ?? 50,\n mentionCount: 1,\n } as NewGraphEntity)\n .returning({ id: graphEntities.id });\n\n const pgId = row.id;\n\n // 2. Create in Neo4j\n try {\n const client = getNeo4jClient();\n await client.runWrite(\n `\n CREATE (e:Entity {\n pgId: $pgId,\n type: $type,\n name: $name,\n aliases: $aliases,\n description: $description,\n importance: $importance,\n source: $source\n })\n `,\n {\n pgId,\n type: entity.type,\n name: entity.name,\n aliases: entity.aliases ?? [],\n description: entity.description ?? \"\",\n importance: entity.importance ?? 50,\n source: entity.source ?? \"\",\n },\n );\n } catch (err) {\n console.log(\"[Neo4j] Failed to create entity in Neo4j (Postgres row exists):\", err);\n }\n\n return pgId;\n}\n\n/**\n * Update an entity in both stores.\n */\nexport async function updateEntity(\n pgId: string,\n updates: Partial<Omit<GraphEntity, \"id\" | \"pgId\">>,\n): Promise<void> {\n // 1. Update Postgres\n const pgUpdates: Record<string, unknown> = {};\n if (updates.type !== undefined) pgUpdates.type = updates.type;\n if (updates.name !== undefined) pgUpdates.name = updates.name;\n if (updates.aliases !== undefined) pgUpdates.aliases = updates.aliases;\n if (updates.description !== undefined) pgUpdates.description = updates.description;\n if (updates.attributes !== undefined) pgUpdates.attributes = updates.attributes;\n if (updates.importance !== undefined) pgUpdates.importance = updates.importance;\n\n if (Object.keys(pgUpdates).length > 0) {\n await db\n .update(graphEntities)\n .set(pgUpdates as any)\n .where(eq(graphEntities.id, pgId));\n }\n\n // 2. Update Neo4j\n try {\n const client = getNeo4jClient();\n const setClauses: string[] = [];\n const params: Record<string, unknown> = { pgId };\n\n if (updates.type !== undefined) {\n setClauses.push(\"e.type = $type\");\n params.type = updates.type;\n }\n if (updates.name !== undefined) {\n setClauses.push(\"e.name = $name\");\n params.name = updates.name;\n }\n if (updates.aliases !== undefined) {\n setClauses.push(\"e.aliases = $aliases\");\n params.aliases = updates.aliases;\n }\n if (updates.description !== undefined) {\n setClauses.push(\"e.description = $description\");\n params.description = updates.description;\n }\n if (updates.attributes !== undefined) {\n setClauses.push(\"e.attributes = $attributes\");\n params.attributes = JSON.stringify(updates.attributes);\n }\n if (updates.importance !== undefined) {\n setClauses.push(\"e.importance = $importance\");\n params.importance = updates.importance;\n }\n\n if (setClauses.length > 0) {\n await client.runWrite(\n `MATCH (e:Entity {pgId: $pgId}) SET ${setClauses.join(\", \")}`,\n params,\n );\n }\n } catch (err) {\n console.log(\"[Neo4j] Failed to update entity in Neo4j:\", err);\n }\n}\n\n/**\n * Delete an entity from both stores. Uses DETACH DELETE in Neo4j to\n * automatically remove connected relationships.\n */\nexport async function deleteEntity(pgId: string): Promise<void> {\n // 1. Delete from Postgres (cascade handles relationships via FK)\n await db.delete(graphEntities).where(eq(graphEntities.id, pgId));\n\n // 2. Detach-delete from Neo4j\n try {\n const client = getNeo4jClient();\n await client.runWrite(\n \"MATCH (e:Entity {pgId: $pgId}) DETACH DELETE e\",\n { pgId },\n );\n } catch (err) {\n console.log(\"[Neo4j] Failed to delete entity in Neo4j:\", err);\n }\n}\n\n/**\n * Find entities by name. When `fuzzy` is true, leverages the Neo4j fulltext\n * index for approximate matching; otherwise performs an exact (case-insensitive)\n * lookup in Postgres.\n */\nexport async function findEntitiesByName(\n name: string,\n fuzzy = false,\n): Promise<GraphEntity[]> {\n if (fuzzy) {\n try {\n const client = getNeo4jClient();\n // Escape special Lucene characters and append ~ for fuzzy\n const safeName = name.replace(/[+\\-&|!(){}[\\]^\"~*?:\\\\/]/g, \"\\\\$&\");\n const result = await client.runQuery(\n `\n CALL db.index.fulltext.queryNodes(\"entity_fulltext\", $query)\n YIELD node, score\n RETURN node.pgId AS pgId,\n node.type AS type,\n node.name AS name,\n node.aliases AS aliases,\n node.description AS description,\n node.importance AS importance,\n node.source AS source,\n score\n ORDER BY score DESC\n LIMIT 25\n `,\n { query: `${safeName}~` },\n );\n\n return result.records.map((r) => ({\n pgId: r.get(\"pgId\") as string,\n type: r.get(\"type\") as EntityType,\n name: r.get(\"name\") as string,\n aliases: r.get(\"aliases\") as string[] | undefined,\n description: r.get(\"description\") as string | undefined,\n importance: typeof r.get(\"importance\") === \"number\"\n ? (r.get(\"importance\") as number)\n : undefined,\n source: r.get(\"source\") as string | undefined,\n }));\n } catch (err) {\n console.log(\"[Neo4j] Fulltext search failed, falling back to Postgres:\", err);\n // Fall through to Postgres path below\n }\n }\n\n // Exact / ilike match in Postgres\n const rows = await db\n .select()\n .from(graphEntities)\n .where(ilike(graphEntities.name, `%${name}%`))\n .limit(25);\n\n return rows.map((r) => ({\n pgId: r.id,\n type: r.type as EntityType,\n name: r.name,\n aliases: (r.aliases as string[]) ?? [],\n description: r.description ?? undefined,\n attributes: (r.attributes as Record<string, unknown>) ?? {},\n importance: r.importance ?? 50,\n }));\n}\n\n// ---------------------------------------------------------------------------\n// Relationship CRUD\n// ---------------------------------------------------------------------------\n\n/**\n * Create a relationship in both Postgres and Neo4j.\n * Returns the Postgres UUID.\n */\nexport async function createRelationship(\n sourceId: string,\n targetId: string,\n type: string,\n attrs?: {\n strength?: number;\n bidirectional?: boolean;\n context?: string;\n attributes?: Record<string, unknown>;\n source?: string;\n },\n): Promise<string> {\n // 1. Insert into Postgres\n const [row] = await db\n .insert(graphRelationships)\n .values({\n sourceEntityId: sourceId,\n targetEntityId: targetId,\n type: type,\n strength: attrs?.strength ?? 50,\n bidirectional: attrs?.bidirectional ?? false,\n context: attrs?.context ?? null,\n attributes: attrs?.attributes ?? {},\n } as NewGraphRelationship)\n .returning({ id: graphRelationships.id });\n\n const pgId = row.id;\n\n // 2. Create in Neo4j\n try {\n const client = getNeo4jClient();\n await client.runWrite(\n `\n MATCH (a:Entity {pgId: $sourceId}), (b:Entity {pgId: $targetId})\n CREATE (a)-[r:RELATES_TO {\n pgId: $pgId,\n type: $type,\n strength: $strength,\n context: $context,\n source: $source\n }]->(b)\n `,\n {\n sourceId,\n targetId,\n pgId,\n type,\n strength: attrs?.strength ?? 50,\n context: attrs?.context ?? \"\",\n source: attrs?.source ?? \"\",\n },\n );\n } catch (err) {\n console.log(\"[Neo4j] Failed to create relationship in Neo4j:\", err);\n }\n\n return pgId;\n}\n\n/**\n * Delete a relationship from both stores.\n */\nexport async function deleteRelationship(pgId: string): Promise<void> {\n // 1. Delete from Postgres\n await db.delete(graphRelationships).where(eq(graphRelationships.id, pgId));\n\n // 2. Delete from Neo4j\n try {\n const client = getNeo4jClient();\n await client.runWrite(\n \"MATCH ()-[r:RELATES_TO {pgId: $pgId}]->() DELETE r\",\n { pgId },\n );\n } catch (err) {\n console.log(\"[Neo4j] Failed to delete relationship in Neo4j:\", err);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Graph traversal (Neo4j-only)\n// ---------------------------------------------------------------------------\n\n/**\n * Return the neighbourhood of an entity up to `depth` hops away.\n */\nexport async function getNeighbors(\n entityPgId: string,\n depth = 2,\n): Promise<NeighborResult> {\n const client = getNeo4jClient();\n\n try {\n const result = await client.runQuery(\n `\n MATCH path = (start:Entity {pgId: $pgId})-[*1..${Math.min(depth, 10)}]-(neighbor:Entity)\n WITH DISTINCT neighbor, relationships(path) AS rels, nodes(path) AS ns\n UNWIND rels AS rel\n WITH COLLECT(DISTINCT {\n pgId: neighbor.pgId,\n name: neighbor.name,\n type: neighbor.type,\n importance: neighbor.importance\n }) AS nodeList,\n COLLECT(DISTINCT {\n sourcePgId: startNode(rel).pgId,\n targetPgId: endNode(rel).pgId,\n type: rel.type,\n strength: rel.strength\n }) AS edgeList\n RETURN nodeList, edgeList\n `,\n { pgId: entityPgId },\n );\n\n if (result.records.length === 0) {\n return { nodes: [], edges: [] };\n }\n\n const record = result.records[0];\n const nodes = (record.get(\"nodeList\") as NeighborNode[]) ?? [];\n const edges = (record.get(\"edgeList\") as NeighborEdge[]) ?? [];\n\n return { nodes, edges };\n } catch (err) {\n console.log(\"[Neo4j] getNeighbors failed:\", err);\n return { nodes: [], edges: [] };\n }\n}\n\n/**\n * Find the shortest path between two entities.\n */\nexport async function findShortestPath(\n sourcePgId: string,\n targetPgId: string,\n): Promise<PathResult | null> {\n const client = getNeo4jClient();\n\n try {\n const result = await client.runQuery(\n `\n MATCH (a:Entity {pgId: $sourcePgId}), (b:Entity {pgId: $targetPgId}),\n path = shortestPath((a)-[*..15]-(b))\n WITH nodes(path) AS ns, relationships(path) AS rels, length(path) AS pathLen\n RETURN\n [n IN ns | {pgId: n.pgId, name: n.name, type: n.type, importance: n.importance}] AS nodes,\n [r IN rels | {sourcePgId: startNode(r).pgId, targetPgId: endNode(r).pgId, type: r.type, strength: r.strength}] AS edges,\n pathLen\n `,\n { sourcePgId, targetPgId },\n );\n\n if (result.records.length === 0) {\n return null;\n }\n\n const record = result.records[0];\n return {\n nodes: record.get(\"nodes\") as NeighborNode[],\n edges: record.get(\"edges\") as NeighborEdge[],\n length: typeof record.get(\"pathLen\") === \"object\"\n ? (record.get(\"pathLen\") as any).toNumber()\n : (record.get(\"pathLen\") as number),\n };\n } catch (err) {\n console.log(\"[Neo4j] findShortestPath failed:\", err);\n return null;\n }\n}\n\n/**\n * Group entities into connected components (communities).\n * Uses a simple BFS-style approach via Neo4j's connected-component pattern.\n */\nexport async function getCommunities(): Promise<Community[]> {\n const client = getNeo4jClient();\n\n try {\n const result = await client.runQuery(\n `\n MATCH (e:Entity)\n WITH collect(e) AS allNodes\n UNWIND allNodes AS node\n MATCH path = (node)-[*0..]-(connected:Entity)\n WITH node, collect(DISTINCT connected) AS component\n WITH component, component[0].pgId AS componentId\n ORDER BY size(component) DESC\n WITH DISTINCT componentId,\n [m IN component | {pgId: m.pgId, name: m.name, type: m.type, importance: m.importance}] AS members\n RETURN componentId, members\n LIMIT 100\n `,\n );\n\n return result.records.map((r, idx) => ({\n id: idx,\n members: r.get(\"members\") as NeighborNode[],\n }));\n } catch (err) {\n console.log(\"[Neo4j] getCommunities failed:\", err);\n return [];\n }\n}\n\n/**\n * Run an arbitrary **read-only** Cypher query. Useful for ad-hoc analytics\n * without having to write a dedicated function.\n */\nexport async function runCustomCypher(\n cypher: string,\n params?: Record<string, unknown>,\n): Promise<Record<string, unknown>[]> {\n const client = getNeo4jClient();\n\n try {\n const result = await client.runQuery(cypher, params);\n return result.records.map((r) => r.toObject() as Record<string, unknown>);\n } catch (err) {\n console.log(\"[Neo4j] Custom Cypher failed:\", err);\n throw err;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Bulk sync from Postgres\n// ---------------------------------------------------------------------------\n\n/**\n * Bulk-sync all graph entities and relationships for a given user from\n * Postgres into Neo4j. Existing Neo4j nodes/edges are merged (MERGE) so\n * this is safe to re-run.\n */\nexport async function syncFromPostgres(userId: string): Promise<{\n entitiesSynced: number;\n relationshipsSynced: number;\n}> {\n const client = getNeo4jClient();\n\n // 1. Load all entities for this user from Postgres\n const entities = await db\n .select()\n .from(graphEntities)\n .where(eq(graphEntities.userId, userId));\n\n let entitiesSynced = 0;\n\n for (const entity of entities) {\n try {\n await client.runWrite(\n `\n MERGE (e:Entity {pgId: $pgId})\n SET e.type = $type,\n e.name = $name,\n e.aliases = $aliases,\n e.description = $description,\n e.importance = $importance\n `,\n {\n pgId: entity.id,\n type: entity.type,\n name: entity.name,\n aliases: (entity.aliases as string[]) ?? [],\n description: entity.description ?? \"\",\n importance: entity.importance ?? 50,\n },\n );\n entitiesSynced++;\n } catch (err) {\n console.log(\"[Neo4j] Sync entity failed:\", entity.id, err);\n }\n }\n\n // 2. Load all relationships that connect those entities\n const entityIds = entities.map((e) => e.id);\n let relationshipsSynced = 0;\n\n if (entityIds.length > 0) {\n // Fetch relationships where both ends belong to this user's entity set\n const allRels = await db.select().from(graphRelationships);\n const entityIdSet = new Set(entityIds);\n const userRels = allRels.filter(\n (r) => entityIdSet.has(r.sourceEntityId) && entityIdSet.has(r.targetEntityId),\n );\n\n for (const rel of userRels) {\n try {\n await client.runWrite(\n `\n MATCH (a:Entity {pgId: $sourceId}), (b:Entity {pgId: $targetId})\n MERGE (a)-[r:RELATES_TO {pgId: $pgId}]->(b)\n SET r.type = $type,\n r.strength = $strength,\n r.context = $context\n `,\n {\n sourceId: rel.sourceEntityId,\n targetId: rel.targetEntityId,\n pgId: rel.id,\n type: rel.type,\n strength: rel.strength ?? 50,\n context: rel.context ?? \"\",\n },\n );\n relationshipsSynced++;\n } catch (err) {\n console.log(\"[Neo4j] Sync relationship failed:\", rel.id, err);\n }\n }\n }\n\n console.log(\n `[Neo4j] Sync complete for user ${userId}: ${entitiesSynced} entities, ${relationshipsSynced} relationships`,\n );\n\n return { entitiesSynced, relationshipsSynced };\n}\n"],"mappings":"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","names":["eq","LOG_PREFIX","LOG_PREFIX","LOG_PREFIX","LOG_PREFIX","LOG_PREFIX","LOG_PREFIX","eq"]}
|