import {z} from 'zod' export type FilingType = '10-K' | '10-Q' | '20-F' | '8-K' | 'DEF 14A' | 'DEFA14A' | '13D' | '13G' | '3' | '4' | '5' | '13F-HR' | 'NPORT-P' | 'N-CEN' | 'EFFECT' | '25-NSE' | 'ARS'; export type FilingEvent = 'material_agreement' | 'agreement_termination' | 'bankruptcy' | 'mine_safety' | 'acquisition_disposition' | 'earnings' | 'debt_obligation' | 'debt_acceleration' | 'restructuring' | 'impairment' | 'delisting' | 'unregistered_sale' | 'rights_modification' | 'auditor_change' | 'restatement' | 'control_change' | 'officer_change' | 'bylaws_amendment' | 'trading_suspension' | 'ethics_amendment' | 'shell_status_change' | 'shareholder_vote' | 'shareholder_nomination' | 'abs_material' | 'servicer_change' | 'credit_enhancement' | 'distribution_failure' | 'securities_act_update' | 'reg_fd' | 'other' | 'financial_exhibits'; export type GetApiApiFilingsArgs = {symbol?: string | undefined, cik?: number | undefined, cusip?: string | undefined, composite_figi?: string | undefined, share_class_figi?: string | undefined, type?: FilingType | undefined, event?: FilingEvent | undefined, page?: number | undefined, pageSize?: number | undefined}; export type GetApiApiFilingsOptions = {baseUrl?: string | undefined, bearerAuth?: string | undefined, fetch?: typeof fetch | undefined}; export const acceptedAt = z.string(); export const filingInfo = z.object({type: z.string(), accessionNumber: z.string(), url: z.string(), dateFiled: z.string(), acceptedAt: acceptedAt.optional(), xbrl: z.boolean(), amendment: z.boolean(), periodEndDate: z.string().optional(), documents: z.array(z.string()).optional(), title: z.string().optional(), items: z.array(z.string()).optional(), events: z.array(z.string()).optional()}); export const getApiApiFilingsResponse = z.object({page: z.number().int().optional(), pageSize: z.number().int().optional(), totalPages: z.number().int().optional(), totalResults: z.number().int().optional(), data: z.array(filingInfo).optional()}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * Search filings * * GET /api/filings */ export const getApiApiFilings = async (args: GetApiApiFilingsArgs, options?: GetApiApiFilingsOptions) => { const {baseUrl = "https://api.stockfit.io/v1", fetch: fetchFn = fetch, bearerAuth} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") if (args.symbol != null) query.append("symbol", String(args.symbol)) if (args.cik != null) query.append("cik", String(args.cik)) if (args.cusip != null) query.append("cusip", String(args.cusip)) if (args.composite_figi != null) query.append("composite_figi", String(args.composite_figi)) if (args.share_class_figi != null) query.append("share_class_figi", String(args.share_class_figi)) if (args.type != null) query.append("type", String(args.type)) if (args.event != null) query.append("event", String(args.event)) if (args.page != null) query.append("page", String(args.page)) if (args.pageSize != null) query.append("pageSize", String(args.pageSize)) if (bearerAuth !== undefined) headers.set('authorization', `Bearer ${bearerAuth}`) const url = `${baseUrl.replace(/\/+$/, '')}/api/filings${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "GET", headers}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(getApiApiFilingsResponse, await res.json()) };