/**
* SEC EDGAR XBRL company facts connector.
*
* Returns the full XBRL fact set for one company, optionally narrowed
* to a comma-separated list of concept tags (e.g. "Revenues,Assets").
* Backed by https://data.sec.gov/api/xbrl/companyfacts/CIK{cik}.json.
*
* Implementation reuses the canonical `secFinancials` function from
* sec-edgar.ts so there is exactly one HTTP / rate-limit / error-
* translation path against EDGAR.
*/
import {
RetrievalError,
type FetchParams,
type RawPayload,
type RetrievalConnector,
} from '../interface.js';
import { secFinancials } from './sec-edgar.js';
export class SecFinancialsConnector implements RetrievalConnector {
readonly name = 'sec-financials';
readonly authRequired = false;
readonly rateLimit = { requestsPerSecond: 10, burstSize: 10 };
async isAvailable(): Promise<boolean> {
return true;
}
async fetch(params: FetchParams): Promise<RawPayload> {
const cik = params.entity?.id;
if (typeof cik !== 'string' || !cik.trim()) {
throw new RetrievalError(
'invalid-request',
'sec-financials: entity.id (CIK) is required (any numeric form; will be padded).',
);
}
const concepts =
typeof params.query?.concepts === 'string'
? (params.query.concepts as string)
: Array.isArray(params.query?.concepts)
? (params.query!.concepts as readonly string[]).join(',')
: undefined;
const facts = await secFinancials(cik, concepts);
return {
source: this.name,
sourceUrl: facts.sourceUrl,
capturedAt: facts.capturedAt,
contentType: 'application/json',
rawContent: JSON.stringify(facts),
metadata: {
cik: facts.cik,
entity: cik,
conceptsFilter: facts.conceptsFilter ?? null,
availableConcepts: facts.availableConcepts ?? null,
},
};
}
}
/** Re-export the underlying standalone fetcher for callers that don't
* go through the dispatcher. */
export { secFinancials };
export type { SecCompanyFacts } from './sec-edgar.js';