Jaspers Hub

biseroff / benzinga

pluginReviewed★ 0↓ 2

Benzinga Market Data: Fetches Benzinga news, analyst ratings, earnings, guidance, dividends, splits, IPO, and economic calendars via API, with a news list view.

2.5 KB
1import { defineSource } from '@jaspers-ai/sdk'
2import { z } from 'zod'
3import { HOST, benzingaGet, isoDay } from './client'
4
5/** One story as /api/v2/news answers it. */
6interface NewsItem {
7 id: number
8 author?: string
9 created?: string
10 updated?: string
11 title?: string
12 teaser?: string
13 url?: string
14 channels?: { name: string }[]
15 stocks?: { name: string }[]
16}
17
18/** Benzinga writes dates like "Wed, 17 May 2023 14:20:15 -0400"; rows carry ISO. */
19function iso(value: string | undefined): string {
20 if (!value) return ''
21 const date = new Date(value)
22 return Number.isNaN(date.getTime()) ? value : date.toISOString()
23}
24
25function stripTags(html: string): string {
26 return html.replace(/<[^>]*>/g, '').replace(/&nbsp;/g, ' ').replace(/&amp;/g, '&').replace(/&quot;/g, '"').replace(/&#39;/g, "'").trim()
27}
28
29export const news = defineSource({
30 description:
31 'Benzinga news, newest first. Filter by tickers, channels, and date range. Rows: id, created, updated (ISO), title, teaser, author, url, tickers, channels (comma joined).',
32 hosts: [HOST],
33 input: z.object({
34 tickers: z.string().optional().describe('Comma-separated tickers, like AAPL,MSFT.'),
35 channels: z.string().optional().describe('Comma-separated channel names, like Earnings,Analyst Ratings.'),
36 dateFrom: z.string().optional().describe('Start date YYYY-MM-DD. Default 7 days ago.'),
37 dateTo: z.string().optional().describe('End date YYYY-MM-DD. Default today.'),
38 pageSize: z.number().int().min(1).max(100).default(25).describe('Items to return, up to 100.'),
39 displayOutput: z.enum(['headline', 'abstract', 'full']).default('abstract').describe('How much of each story.'),
40 }),
41 async run(args, ctx) {
42 const body = await benzingaGet(ctx, 'news', '/api/v2/news', {
43 tickers: args.tickers?.replace(/\s+/g, '').toUpperCase(),
44 channels: args.channels,
45 dateFrom: args.dateFrom ?? isoDay(-7),
46 dateTo: args.dateTo ?? isoDay(0),
47 pageSize: args.pageSize,
48 displayOutput: args.displayOutput,
49 sort: 'created:desc',
50 })
51 const items = (Array.isArray(body) ? body : []) as NewsItem[]
52 return items
53 .map((item) => ({
54 id: item.id,
55 created: iso(item.created),
56 updated: iso(item.updated),
57 title: item.title ?? '',
58 teaser: stripTags(item.teaser ?? ''),
59 author: item.author ?? '',
60 url: item.url ?? '',
61 tickers: (item.stocks ?? []).map((s) => s.name).join(','),
62 channels: (item.channels ?? []).map((c) => c.name).join(','),
63 }))
64 .sort((a, b) => b.created.localeCompare(a.created))
65 },
66})