← back to Commercialrealestate
scripts/crcp-export.js
53 lines
// crcp-export.js — P3 federal-data EXPORT API (docs/TOOL-SPEC.md). The resell-clean Team-tier feature:
// export SEC EDGAR REIT acquisitions + HUD FHA loans as CSV/JSON. DOCTRINE: only FEDERAL public data is
// exportable (SEC + HUD = public domain, no use restriction); the LA assessor half is §408.3(c)-view-only
// and is NEVER included in an export. $0, local. Mount AFTER accounts: require('./crcp-export')(app,ROOT,acct.userOf)
'use strict';
const fs = require('fs');
const path = require('path');
module.exports = function mountExport(app, ROOT, userOf) {
const rd = f => { try { return JSON.parse(fs.readFileSync(path.join(ROOT, 'data', f), 'utf8')); } catch { return null; } };
// CSV formula-injection guard (Cody-gate): prefix a ' to any cell starting with = + - @ tab CR so a
// value like "=CMD|..." from an LLM-parsed EDGAR field can't execute when opened in Excel/Sheets.
const csvCell = v => { let s = v == null ? '' : String(v); if (/^[=+\-@\t\r]/.test(s)) s = "'" + s; return /[",\n]/.test(s) ? '"' + s.replace(/"/g, '""') + '"' : s; };
function federalRows() {
const out = [];
const edgar = rd('edgar-reit-deals.json'); const fha = rd('fha-loans.json');
for (const d of (edgar && edgar.deals) || []) out.push({
source: 'SEC EDGAR 8-K', kind: 'reit-acquisition', name: d.company, ticker: d.ticker || '',
property: d.property || '', city: d.deal_city || '', state: d.deal_state || '',
price: d.price ?? '', units: '', rate: '', date: d.filed || '', detail_url: d.filing_url || '',
});
for (const r of (fha && fha.rows) || []) out.push({
source: 'HUD FHA', kind: 'fha-insured-loan', name: r.property, ticker: '',
property: r.property || '', city: r.city || '', state: r.state || '',
price: r.originalAmount ?? '', units: r.units ?? '', rate: r.rate ?? '', date: r.originationDate || '', detail_url: '',
});
return out;
}
// GET /api/export/federal?format=csv|json[&state=CA] — signed-in only (it's a paid-tier feature;
// billing is inert so any signed-in user can pull it for now). Federal data only — resell-clean.
app.get('/api/export/federal', (req, res) => {
const u = userOf && userOf(req);
if (!u || !u.email) return res.status(401).json({ error: 'sign in — federal-data export is a signed-in feature' });
// Cody-gate: export is the Team-tier feature — enforce the tier, don't just check signed-in.
if (u.tier !== 'team') return res.status(403).json({ error: 'export is a Team-tier feature', tier: u.tier, upgrade: '/api/billing/tiers' });
let rows = federalRows();
const state = (req.query.state || '').toUpperCase();
if (state) rows = rows.filter(r => String(r.state || '').toUpperCase() === state);
const cols = ['source', 'kind', 'name', 'ticker', 'property', 'city', 'state', 'price', 'units', 'rate', 'date', 'detail_url'];
if ((req.query.format || 'json') === 'csv') {
const head = `# CRCP federal deal export — SEC EDGAR + HUD FHA (public domain, resellable). Assessor data excluded per CA R&T 408.3(c). ${rows.length} rows.\n`;
const body = [cols.join(','), ...rows.map(r => cols.map(c => csvCell(r[c])).join(','))].join('\n');
res.set('Content-Type', 'text/csv').set('Content-Disposition', 'attachment; filename="crcp-federal-deals.csv"').send(head + body);
} else {
res.json({ count: rows.length, license: 'SEC EDGAR + HUD FHA are U.S. public-domain federal records — resellable. Assessor data excluded per CA R&T 408.3(c).', rows });
}
});
console.log('[crcp-export] federal-data export API mounted (/api/export/federal, SEC+FHA only)');
};