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,330 @@
|
|
|
1
|
+
// src/integrations/finance/stocks.ts
|
|
2
|
+
var StockClientError = class extends Error {
|
|
3
|
+
constructor(message, statusCode) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.statusCode = statusCode;
|
|
6
|
+
this.name = "StockClientError";
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
var MARKET_INDICES = {
|
|
10
|
+
"^GSPC": { name: "S&P 500", symbol: "^GSPC" },
|
|
11
|
+
"^DJI": { name: "Dow Jones Industrial Average", symbol: "^DJI" },
|
|
12
|
+
"^IXIC": { name: "NASDAQ Composite", symbol: "^IXIC" },
|
|
13
|
+
"^RUT": { name: "Russell 2000", symbol: "^RUT" },
|
|
14
|
+
"^VIX": { name: "CBOE Volatility Index", symbol: "^VIX" },
|
|
15
|
+
"^FTSE": { name: "FTSE 100", symbol: "^FTSE" },
|
|
16
|
+
"^N225": { name: "Nikkei 225", symbol: "^N225" },
|
|
17
|
+
"^HSI": { name: "Hang Seng Index", symbol: "^HSI" }
|
|
18
|
+
};
|
|
19
|
+
var StockClient = class {
|
|
20
|
+
alphaVantageApiKey;
|
|
21
|
+
alphaVantageBaseUrl = "https://www.alphavantage.co/query";
|
|
22
|
+
yahooBaseUrl = "https://query1.finance.yahoo.com/v8/finance";
|
|
23
|
+
timeout;
|
|
24
|
+
rateLimitDelay;
|
|
25
|
+
lastRequestTime = 0;
|
|
26
|
+
constructor(config = {}) {
|
|
27
|
+
this.alphaVantageApiKey = config.alphaVantageApiKey;
|
|
28
|
+
this.timeout = config.timeout ?? 1e4;
|
|
29
|
+
this.rateLimitDelay = config.rateLimitDelay ?? 500;
|
|
30
|
+
}
|
|
31
|
+
async rateLimit() {
|
|
32
|
+
const now = Date.now();
|
|
33
|
+
const timeSinceLastRequest = now - this.lastRequestTime;
|
|
34
|
+
if (timeSinceLastRequest < this.rateLimitDelay) {
|
|
35
|
+
await new Promise(
|
|
36
|
+
(resolve) => setTimeout(resolve, this.rateLimitDelay - timeSinceLastRequest)
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
this.lastRequestTime = Date.now();
|
|
40
|
+
}
|
|
41
|
+
async fetchWithTimeout(url, options = {}) {
|
|
42
|
+
const controller = new AbortController();
|
|
43
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
44
|
+
try {
|
|
45
|
+
const response = await fetch(url, {
|
|
46
|
+
...options,
|
|
47
|
+
signal: controller.signal
|
|
48
|
+
});
|
|
49
|
+
clearTimeout(timeoutId);
|
|
50
|
+
return response;
|
|
51
|
+
} catch (error) {
|
|
52
|
+
clearTimeout(timeoutId);
|
|
53
|
+
if (error.name === "AbortError") {
|
|
54
|
+
throw new StockClientError("Request timeout");
|
|
55
|
+
}
|
|
56
|
+
throw new StockClientError(
|
|
57
|
+
`Network error: ${error instanceof Error ? error.message : String(error)}`
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Get stock quote using Yahoo Finance
|
|
63
|
+
*/
|
|
64
|
+
async getQuote(symbol) {
|
|
65
|
+
await this.rateLimit();
|
|
66
|
+
const url = `${this.yahooBaseUrl}/chart/${encodeURIComponent(symbol)}?interval=1d&range=1d`;
|
|
67
|
+
const response = await this.fetchWithTimeout(url, {
|
|
68
|
+
headers: {
|
|
69
|
+
Accept: "application/json",
|
|
70
|
+
"User-Agent": "Mozilla/5.0"
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
if (!response.ok) {
|
|
74
|
+
throw new StockClientError(`Yahoo Finance API error: ${response.statusText}`, response.status);
|
|
75
|
+
}
|
|
76
|
+
const data = await response.json();
|
|
77
|
+
const result = data?.chart?.result?.[0];
|
|
78
|
+
if (!result) {
|
|
79
|
+
throw new StockClientError(`No data found for symbol: ${symbol}`);
|
|
80
|
+
}
|
|
81
|
+
const meta = result.meta;
|
|
82
|
+
const quote = result.indicators?.quote?.[0];
|
|
83
|
+
const lastPrice = meta.regularMarketPrice ?? quote?.close?.[quote.close.length - 1] ?? 0;
|
|
84
|
+
return {
|
|
85
|
+
symbol: meta.symbol,
|
|
86
|
+
name: meta.shortName ?? meta.longName ?? meta.symbol,
|
|
87
|
+
price: lastPrice,
|
|
88
|
+
change: meta.regularMarketPrice - meta.chartPreviousClose,
|
|
89
|
+
changePercent: (meta.regularMarketPrice - meta.chartPreviousClose) / meta.chartPreviousClose * 100,
|
|
90
|
+
open: meta.regularMarketOpen ?? quote?.open?.[0] ?? 0,
|
|
91
|
+
high: meta.regularMarketDayHigh ?? Math.max(...quote?.high ?? [0]),
|
|
92
|
+
low: meta.regularMarketDayLow ?? Math.min(...quote?.low?.filter((v) => v > 0) ?? [0]),
|
|
93
|
+
previousClose: meta.chartPreviousClose ?? meta.previousClose ?? 0,
|
|
94
|
+
volume: meta.regularMarketVolume ?? 0,
|
|
95
|
+
marketCap: meta.marketCap ?? 0,
|
|
96
|
+
peRatio: null,
|
|
97
|
+
// Not available in chart endpoint
|
|
98
|
+
eps: null,
|
|
99
|
+
dividend: null,
|
|
100
|
+
dividendYield: null,
|
|
101
|
+
week52High: meta.fiftyTwoWeekHigh ?? 0,
|
|
102
|
+
week52Low: meta.fiftyTwoWeekLow ?? 0,
|
|
103
|
+
exchange: meta.exchangeName ?? "",
|
|
104
|
+
lastUpdated: new Date(meta.regularMarketTime * 1e3)
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Get quotes for multiple symbols
|
|
109
|
+
*/
|
|
110
|
+
async getQuotes(symbols) {
|
|
111
|
+
const results = /* @__PURE__ */ new Map();
|
|
112
|
+
await this.rateLimit();
|
|
113
|
+
const symbolList = symbols.join(",");
|
|
114
|
+
const url = `${this.yahooBaseUrl}/chart/${encodeURIComponent(symbols[0])}?interval=1d&range=1d`;
|
|
115
|
+
for (const symbol of symbols) {
|
|
116
|
+
try {
|
|
117
|
+
const quote = await this.getQuote(symbol);
|
|
118
|
+
results.set(symbol, quote);
|
|
119
|
+
} catch (error) {
|
|
120
|
+
console.error(`Failed to get quote for ${symbol}:`, error);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return results;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Get historical data using Yahoo Finance
|
|
127
|
+
*/
|
|
128
|
+
async getHistoricalData(symbol, range = "1mo", interval = "1d") {
|
|
129
|
+
await this.rateLimit();
|
|
130
|
+
const url = `${this.yahooBaseUrl}/chart/${encodeURIComponent(symbol)}?interval=${interval}&range=${range}`;
|
|
131
|
+
const response = await this.fetchWithTimeout(url, {
|
|
132
|
+
headers: {
|
|
133
|
+
Accept: "application/json",
|
|
134
|
+
"User-Agent": "Mozilla/5.0"
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
if (!response.ok) {
|
|
138
|
+
throw new StockClientError(`Yahoo Finance API error: ${response.statusText}`, response.status);
|
|
139
|
+
}
|
|
140
|
+
const data = await response.json();
|
|
141
|
+
const result = data?.chart?.result?.[0];
|
|
142
|
+
if (!result) {
|
|
143
|
+
throw new StockClientError(`No historical data found for symbol: ${symbol}`);
|
|
144
|
+
}
|
|
145
|
+
const timestamps = result.timestamp ?? [];
|
|
146
|
+
const quote = result.indicators?.quote?.[0] ?? {};
|
|
147
|
+
const adjClose = result.indicators?.adjclose?.[0]?.adjclose ?? quote.close ?? [];
|
|
148
|
+
return timestamps.map((timestamp, i) => ({
|
|
149
|
+
date: new Date(timestamp * 1e3),
|
|
150
|
+
open: quote.open?.[i] ?? 0,
|
|
151
|
+
high: quote.high?.[i] ?? 0,
|
|
152
|
+
low: quote.low?.[i] ?? 0,
|
|
153
|
+
close: quote.close?.[i] ?? 0,
|
|
154
|
+
adjustedClose: adjClose[i] ?? quote.close?.[i] ?? 0,
|
|
155
|
+
volume: quote.volume?.[i] ?? 0
|
|
156
|
+
}));
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Get stock quote using Alpha Vantage (if API key is configured)
|
|
160
|
+
*/
|
|
161
|
+
async getQuoteAlphaVantage(symbol) {
|
|
162
|
+
if (!this.alphaVantageApiKey) {
|
|
163
|
+
throw new StockClientError("Alpha Vantage API key not configured");
|
|
164
|
+
}
|
|
165
|
+
await this.rateLimit();
|
|
166
|
+
const url = `${this.alphaVantageBaseUrl}?function=GLOBAL_QUOTE&symbol=${encodeURIComponent(symbol)}&apikey=${this.alphaVantageApiKey}`;
|
|
167
|
+
const response = await this.fetchWithTimeout(url);
|
|
168
|
+
if (!response.ok) {
|
|
169
|
+
throw new StockClientError(`Alpha Vantage API error: ${response.statusText}`, response.status);
|
|
170
|
+
}
|
|
171
|
+
const data = await response.json();
|
|
172
|
+
if (data.Note) {
|
|
173
|
+
throw new StockClientError("Alpha Vantage rate limit reached");
|
|
174
|
+
}
|
|
175
|
+
if (data["Error Message"]) {
|
|
176
|
+
throw new StockClientError(data["Error Message"]);
|
|
177
|
+
}
|
|
178
|
+
const quote = data["Global Quote"];
|
|
179
|
+
if (!quote || Object.keys(quote).length === 0) {
|
|
180
|
+
throw new StockClientError(`No data found for symbol: ${symbol}`);
|
|
181
|
+
}
|
|
182
|
+
const price = parseFloat(quote["05. price"]) || 0;
|
|
183
|
+
const previousClose = parseFloat(quote["08. previous close"]) || 0;
|
|
184
|
+
return {
|
|
185
|
+
symbol: quote["01. symbol"],
|
|
186
|
+
name: quote["01. symbol"],
|
|
187
|
+
// Alpha Vantage doesn't return name
|
|
188
|
+
price,
|
|
189
|
+
change: parseFloat(quote["09. change"]) || 0,
|
|
190
|
+
changePercent: parseFloat(quote["10. change percent"]?.replace("%", "")) || 0,
|
|
191
|
+
open: parseFloat(quote["02. open"]) || 0,
|
|
192
|
+
high: parseFloat(quote["03. high"]) || 0,
|
|
193
|
+
low: parseFloat(quote["04. low"]) || 0,
|
|
194
|
+
previousClose,
|
|
195
|
+
volume: parseInt(quote["06. volume"], 10) || 0,
|
|
196
|
+
marketCap: 0,
|
|
197
|
+
peRatio: null,
|
|
198
|
+
eps: null,
|
|
199
|
+
dividend: null,
|
|
200
|
+
dividendYield: null,
|
|
201
|
+
week52High: 0,
|
|
202
|
+
week52Low: 0,
|
|
203
|
+
exchange: "",
|
|
204
|
+
lastUpdated: new Date(quote["07. latest trading day"])
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Get historical data using Alpha Vantage
|
|
209
|
+
*/
|
|
210
|
+
async getHistoricalDataAlphaVantage(symbol, outputSize = "compact") {
|
|
211
|
+
if (!this.alphaVantageApiKey) {
|
|
212
|
+
throw new StockClientError("Alpha Vantage API key not configured");
|
|
213
|
+
}
|
|
214
|
+
await this.rateLimit();
|
|
215
|
+
const url = `${this.alphaVantageBaseUrl}?function=TIME_SERIES_DAILY_ADJUSTED&symbol=${encodeURIComponent(symbol)}&outputsize=${outputSize}&apikey=${this.alphaVantageApiKey}`;
|
|
216
|
+
const response = await this.fetchWithTimeout(url);
|
|
217
|
+
if (!response.ok) {
|
|
218
|
+
throw new StockClientError(`Alpha Vantage API error: ${response.statusText}`, response.status);
|
|
219
|
+
}
|
|
220
|
+
const data = await response.json();
|
|
221
|
+
if (data.Note) {
|
|
222
|
+
throw new StockClientError("Alpha Vantage rate limit reached");
|
|
223
|
+
}
|
|
224
|
+
if (data["Error Message"]) {
|
|
225
|
+
throw new StockClientError(data["Error Message"]);
|
|
226
|
+
}
|
|
227
|
+
const timeSeries = data["Time Series (Daily)"];
|
|
228
|
+
if (!timeSeries) {
|
|
229
|
+
throw new StockClientError(`No historical data found for symbol: ${symbol}`);
|
|
230
|
+
}
|
|
231
|
+
return Object.entries(timeSeries).map(([date, values]) => ({
|
|
232
|
+
date: new Date(date),
|
|
233
|
+
open: parseFloat(values["1. open"]) || 0,
|
|
234
|
+
high: parseFloat(values["2. high"]) || 0,
|
|
235
|
+
low: parseFloat(values["3. low"]) || 0,
|
|
236
|
+
close: parseFloat(values["4. close"]) || 0,
|
|
237
|
+
adjustedClose: parseFloat(values["5. adjusted close"]) || 0,
|
|
238
|
+
volume: parseInt(values["6. volume"], 10) || 0
|
|
239
|
+
})).sort((a, b) => a.date.getTime() - b.date.getTime());
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Search for stocks
|
|
243
|
+
*/
|
|
244
|
+
async searchStocks(query) {
|
|
245
|
+
if (!this.alphaVantageApiKey) {
|
|
246
|
+
return [];
|
|
247
|
+
}
|
|
248
|
+
await this.rateLimit();
|
|
249
|
+
const url = `${this.alphaVantageBaseUrl}?function=SYMBOL_SEARCH&keywords=${encodeURIComponent(query)}&apikey=${this.alphaVantageApiKey}`;
|
|
250
|
+
const response = await this.fetchWithTimeout(url);
|
|
251
|
+
if (!response.ok) {
|
|
252
|
+
throw new StockClientError(`Alpha Vantage API error: ${response.statusText}`, response.status);
|
|
253
|
+
}
|
|
254
|
+
const data = await response.json();
|
|
255
|
+
if (data.Note) {
|
|
256
|
+
throw new StockClientError("Alpha Vantage rate limit reached");
|
|
257
|
+
}
|
|
258
|
+
const matches = data.bestMatches ?? [];
|
|
259
|
+
return matches.map((match) => ({
|
|
260
|
+
symbol: match["1. symbol"],
|
|
261
|
+
name: match["2. name"],
|
|
262
|
+
type: match["3. type"],
|
|
263
|
+
exchange: match["4. region"],
|
|
264
|
+
region: match["4. region"]
|
|
265
|
+
}));
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Get major market indices
|
|
269
|
+
*/
|
|
270
|
+
async getMarketIndices() {
|
|
271
|
+
const indices = [];
|
|
272
|
+
for (const [symbol, info] of Object.entries(MARKET_INDICES)) {
|
|
273
|
+
try {
|
|
274
|
+
const quote = await this.getQuote(symbol);
|
|
275
|
+
indices.push({
|
|
276
|
+
symbol,
|
|
277
|
+
name: info.name,
|
|
278
|
+
value: quote.price,
|
|
279
|
+
change: quote.change,
|
|
280
|
+
changePercent: quote.changePercent
|
|
281
|
+
});
|
|
282
|
+
} catch (error) {
|
|
283
|
+
console.error(`Failed to get index ${symbol}:`, error);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return indices;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Get a formatted summary string for a stock
|
|
290
|
+
*/
|
|
291
|
+
async getFormattedSummary(symbol) {
|
|
292
|
+
const quote = await this.getQuote(symbol);
|
|
293
|
+
const changeEmoji = quote.changePercent >= 0 ? "+" : "";
|
|
294
|
+
return `${quote.name} (${quote.symbol})
|
|
295
|
+
Price: $${quote.price.toFixed(2)}
|
|
296
|
+
Change: ${changeEmoji}${quote.change.toFixed(2)} (${changeEmoji}${quote.changePercent.toFixed(2)}%)
|
|
297
|
+
Open: $${quote.open.toFixed(2)}
|
|
298
|
+
Day Range: $${quote.low.toFixed(2)} - $${quote.high.toFixed(2)}
|
|
299
|
+
52-Week Range: $${quote.week52Low.toFixed(2)} - $${quote.week52High.toFixed(2)}
|
|
300
|
+
Volume: ${quote.volume.toLocaleString()}
|
|
301
|
+
${quote.marketCap > 0 ? `Market Cap: $${(quote.marketCap / 1e9).toFixed(2)}B` : ""}
|
|
302
|
+
Exchange: ${quote.exchange}`;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Get market summary
|
|
306
|
+
*/
|
|
307
|
+
async getMarketSummary() {
|
|
308
|
+
const indices = await this.getMarketIndices();
|
|
309
|
+
let summary = "Market Summary\n";
|
|
310
|
+
summary += "==============\n\n";
|
|
311
|
+
for (const index of indices) {
|
|
312
|
+
const changeEmoji = index.changePercent >= 0 ? "+" : "";
|
|
313
|
+
summary += `${index.name}: ${index.value.toFixed(2)} (${changeEmoji}${index.changePercent.toFixed(2)}%)
|
|
314
|
+
`;
|
|
315
|
+
}
|
|
316
|
+
return summary;
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
function createStockClient(config = {}) {
|
|
320
|
+
return new StockClient(config);
|
|
321
|
+
}
|
|
322
|
+
var stocks_default = StockClient;
|
|
323
|
+
|
|
324
|
+
export {
|
|
325
|
+
StockClientError,
|
|
326
|
+
StockClient,
|
|
327
|
+
createStockClient,
|
|
328
|
+
stocks_default
|
|
329
|
+
};
|
|
330
|
+
//# sourceMappingURL=chunk-22VGGA7S.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/integrations/finance/stocks.ts"],"sourcesContent":["/**\n * Stock price tracking using Yahoo Finance and Alpha Vantage APIs\n * Yahoo Finance: Free, no API key required (unofficial)\n * Alpha Vantage: Free tier available with API key\n */\n\nexport interface StockQuote {\n symbol: string;\n name: string;\n price: number;\n change: number;\n changePercent: number;\n open: number;\n high: number;\n low: number;\n previousClose: number;\n volume: number;\n marketCap: number;\n peRatio: number | null;\n eps: number | null;\n dividend: number | null;\n dividendYield: number | null;\n week52High: number;\n week52Low: number;\n exchange: string;\n lastUpdated: Date;\n}\n\nexport interface StockHistoricalData {\n date: Date;\n open: number;\n high: number;\n low: number;\n close: number;\n adjustedClose: number;\n volume: number;\n}\n\nexport interface MarketIndex {\n symbol: string;\n name: string;\n value: number;\n change: number;\n changePercent: number;\n}\n\nexport interface StockSearchResult {\n symbol: string;\n name: string;\n type: string;\n exchange: string;\n region: string;\n}\n\nexport class StockClientError extends Error {\n constructor(\n message: string,\n public statusCode?: number\n ) {\n super(message);\n this.name = \"StockClientError\";\n }\n}\n\n// Common market indices\nconst MARKET_INDICES: Record<string, { name: string; symbol: string }> = {\n \"^GSPC\": { name: \"S&P 500\", symbol: \"^GSPC\" },\n \"^DJI\": { name: \"Dow Jones Industrial Average\", symbol: \"^DJI\" },\n \"^IXIC\": { name: \"NASDAQ Composite\", symbol: \"^IXIC\" },\n \"^RUT\": { name: \"Russell 2000\", symbol: \"^RUT\" },\n \"^VIX\": { name: \"CBOE Volatility Index\", symbol: \"^VIX\" },\n \"^FTSE\": { name: \"FTSE 100\", symbol: \"^FTSE\" },\n \"^N225\": { name: \"Nikkei 225\", symbol: \"^N225\" },\n \"^HSI\": { name: \"Hang Seng Index\", symbol: \"^HSI\" },\n};\n\nexport interface StockClientConfig {\n alphaVantageApiKey?: string;\n timeout?: number;\n rateLimitDelay?: number;\n}\n\nexport class StockClient {\n private alphaVantageApiKey?: string;\n private alphaVantageBaseUrl = \"https://www.alphavantage.co/query\";\n private yahooBaseUrl = \"https://query1.finance.yahoo.com/v8/finance\";\n private timeout: number;\n private rateLimitDelay: number;\n private lastRequestTime = 0;\n\n constructor(config: StockClientConfig = {}) {\n this.alphaVantageApiKey = config.alphaVantageApiKey;\n this.timeout = config.timeout ?? 10000;\n this.rateLimitDelay = config.rateLimitDelay ?? 500;\n }\n\n private async rateLimit(): Promise<void> {\n const now = Date.now();\n const timeSinceLastRequest = now - this.lastRequestTime;\n if (timeSinceLastRequest < this.rateLimitDelay) {\n await new Promise((resolve) =>\n setTimeout(resolve, this.rateLimitDelay - timeSinceLastRequest)\n );\n }\n this.lastRequestTime = Date.now();\n }\n\n private async fetchWithTimeout(\n url: string,\n options: RequestInit = {}\n ): Promise<Response> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(url, {\n ...options,\n signal: controller.signal,\n });\n clearTimeout(timeoutId);\n return response;\n } catch (error) {\n clearTimeout(timeoutId);\n if ((error as Error).name === \"AbortError\") {\n throw new StockClientError(\"Request timeout\");\n }\n throw new StockClientError(\n `Network error: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * Get stock quote using Yahoo Finance\n */\n async getQuote(symbol: string): Promise<StockQuote> {\n await this.rateLimit();\n\n const url = `${this.yahooBaseUrl}/chart/${encodeURIComponent(symbol)}?interval=1d&range=1d`;\n\n const response = await this.fetchWithTimeout(url, {\n headers: {\n Accept: \"application/json\",\n \"User-Agent\": \"Mozilla/5.0\",\n },\n });\n\n if (!response.ok) {\n throw new StockClientError(`Yahoo Finance API error: ${response.statusText}`, response.status);\n }\n\n const data = await response.json();\n const result = data?.chart?.result?.[0];\n\n if (!result) {\n throw new StockClientError(`No data found for symbol: ${symbol}`);\n }\n\n const meta = result.meta;\n const quote = result.indicators?.quote?.[0];\n const lastPrice = meta.regularMarketPrice ?? quote?.close?.[quote.close.length - 1] ?? 0;\n\n return {\n symbol: meta.symbol,\n name: meta.shortName ?? meta.longName ?? meta.symbol,\n price: lastPrice,\n change: meta.regularMarketPrice - meta.chartPreviousClose,\n changePercent: ((meta.regularMarketPrice - meta.chartPreviousClose) / meta.chartPreviousClose) * 100,\n open: meta.regularMarketOpen ?? quote?.open?.[0] ?? 0,\n high: meta.regularMarketDayHigh ?? Math.max(...(quote?.high ?? [0])),\n low: meta.regularMarketDayLow ?? Math.min(...(quote?.low?.filter((v: number) => v > 0) ?? [0])),\n previousClose: meta.chartPreviousClose ?? meta.previousClose ?? 0,\n volume: meta.regularMarketVolume ?? 0,\n marketCap: meta.marketCap ?? 0,\n peRatio: null, // Not available in chart endpoint\n eps: null,\n dividend: null,\n dividendYield: null,\n week52High: meta.fiftyTwoWeekHigh ?? 0,\n week52Low: meta.fiftyTwoWeekLow ?? 0,\n exchange: meta.exchangeName ?? \"\",\n lastUpdated: new Date(meta.regularMarketTime * 1000),\n };\n }\n\n /**\n * Get quotes for multiple symbols\n */\n async getQuotes(symbols: string[]): Promise<Map<string, StockQuote>> {\n const results = new Map<string, StockQuote>();\n\n // Yahoo Finance supports batch queries\n await this.rateLimit();\n const symbolList = symbols.join(\",\");\n const url = `${this.yahooBaseUrl}/chart/${encodeURIComponent(symbols[0])}?interval=1d&range=1d`;\n\n // For multiple symbols, we need to make individual requests\n // Yahoo's batch endpoint requires different handling\n for (const symbol of symbols) {\n try {\n const quote = await this.getQuote(symbol);\n results.set(symbol, quote);\n } catch (error) {\n console.error(`Failed to get quote for ${symbol}:`, error);\n }\n }\n\n return results;\n }\n\n /**\n * Get historical data using Yahoo Finance\n */\n async getHistoricalData(\n symbol: string,\n range: \"1d\" | \"5d\" | \"1mo\" | \"3mo\" | \"6mo\" | \"1y\" | \"2y\" | \"5y\" | \"10y\" | \"max\" = \"1mo\",\n interval: \"1m\" | \"5m\" | \"15m\" | \"30m\" | \"1h\" | \"1d\" | \"1wk\" | \"1mo\" = \"1d\"\n ): Promise<StockHistoricalData[]> {\n await this.rateLimit();\n\n const url = `${this.yahooBaseUrl}/chart/${encodeURIComponent(symbol)}?interval=${interval}&range=${range}`;\n\n const response = await this.fetchWithTimeout(url, {\n headers: {\n Accept: \"application/json\",\n \"User-Agent\": \"Mozilla/5.0\",\n },\n });\n\n if (!response.ok) {\n throw new StockClientError(`Yahoo Finance API error: ${response.statusText}`, response.status);\n }\n\n const data = await response.json();\n const result = data?.chart?.result?.[0];\n\n if (!result) {\n throw new StockClientError(`No historical data found for symbol: ${symbol}`);\n }\n\n const timestamps = result.timestamp ?? [];\n const quote = result.indicators?.quote?.[0] ?? {};\n const adjClose = result.indicators?.adjclose?.[0]?.adjclose ?? quote.close ?? [];\n\n return timestamps.map((timestamp: number, i: number) => ({\n date: new Date(timestamp * 1000),\n open: quote.open?.[i] ?? 0,\n high: quote.high?.[i] ?? 0,\n low: quote.low?.[i] ?? 0,\n close: quote.close?.[i] ?? 0,\n adjustedClose: adjClose[i] ?? quote.close?.[i] ?? 0,\n volume: quote.volume?.[i] ?? 0,\n }));\n }\n\n /**\n * Get stock quote using Alpha Vantage (if API key is configured)\n */\n async getQuoteAlphaVantage(symbol: string): Promise<StockQuote> {\n if (!this.alphaVantageApiKey) {\n throw new StockClientError(\"Alpha Vantage API key not configured\");\n }\n\n await this.rateLimit();\n\n const url = `${this.alphaVantageBaseUrl}?function=GLOBAL_QUOTE&symbol=${encodeURIComponent(symbol)}&apikey=${this.alphaVantageApiKey}`;\n\n const response = await this.fetchWithTimeout(url);\n\n if (!response.ok) {\n throw new StockClientError(`Alpha Vantage API error: ${response.statusText}`, response.status);\n }\n\n const data = await response.json();\n\n if (data.Note) {\n throw new StockClientError(\"Alpha Vantage rate limit reached\");\n }\n\n if (data[\"Error Message\"]) {\n throw new StockClientError(data[\"Error Message\"]);\n }\n\n const quote = data[\"Global Quote\"];\n if (!quote || Object.keys(quote).length === 0) {\n throw new StockClientError(`No data found for symbol: ${symbol}`);\n }\n\n const price = parseFloat(quote[\"05. price\"]) || 0;\n const previousClose = parseFloat(quote[\"08. previous close\"]) || 0;\n\n return {\n symbol: quote[\"01. symbol\"],\n name: quote[\"01. symbol\"], // Alpha Vantage doesn't return name\n price,\n change: parseFloat(quote[\"09. change\"]) || 0,\n changePercent: parseFloat(quote[\"10. change percent\"]?.replace(\"%\", \"\")) || 0,\n open: parseFloat(quote[\"02. open\"]) || 0,\n high: parseFloat(quote[\"03. high\"]) || 0,\n low: parseFloat(quote[\"04. low\"]) || 0,\n previousClose,\n volume: parseInt(quote[\"06. volume\"], 10) || 0,\n marketCap: 0,\n peRatio: null,\n eps: null,\n dividend: null,\n dividendYield: null,\n week52High: 0,\n week52Low: 0,\n exchange: \"\",\n lastUpdated: new Date(quote[\"07. latest trading day\"]),\n };\n }\n\n /**\n * Get historical data using Alpha Vantage\n */\n async getHistoricalDataAlphaVantage(\n symbol: string,\n outputSize: \"compact\" | \"full\" = \"compact\"\n ): Promise<StockHistoricalData[]> {\n if (!this.alphaVantageApiKey) {\n throw new StockClientError(\"Alpha Vantage API key not configured\");\n }\n\n await this.rateLimit();\n\n const url = `${this.alphaVantageBaseUrl}?function=TIME_SERIES_DAILY_ADJUSTED&symbol=${encodeURIComponent(symbol)}&outputsize=${outputSize}&apikey=${this.alphaVantageApiKey}`;\n\n const response = await this.fetchWithTimeout(url);\n\n if (!response.ok) {\n throw new StockClientError(`Alpha Vantage API error: ${response.statusText}`, response.status);\n }\n\n const data = await response.json();\n\n if (data.Note) {\n throw new StockClientError(\"Alpha Vantage rate limit reached\");\n }\n\n if (data[\"Error Message\"]) {\n throw new StockClientError(data[\"Error Message\"]);\n }\n\n const timeSeries = data[\"Time Series (Daily)\"];\n if (!timeSeries) {\n throw new StockClientError(`No historical data found for symbol: ${symbol}`);\n }\n\n return Object.entries(timeSeries)\n .map(([date, values]: [string, any]) => ({\n date: new Date(date),\n open: parseFloat(values[\"1. open\"]) || 0,\n high: parseFloat(values[\"2. high\"]) || 0,\n low: parseFloat(values[\"3. low\"]) || 0,\n close: parseFloat(values[\"4. close\"]) || 0,\n adjustedClose: parseFloat(values[\"5. adjusted close\"]) || 0,\n volume: parseInt(values[\"6. volume\"], 10) || 0,\n }))\n .sort((a, b) => a.date.getTime() - b.date.getTime());\n }\n\n /**\n * Search for stocks\n */\n async searchStocks(query: string): Promise<StockSearchResult[]> {\n if (!this.alphaVantageApiKey) {\n // Fallback: return empty if no API key\n return [];\n }\n\n await this.rateLimit();\n\n const url = `${this.alphaVantageBaseUrl}?function=SYMBOL_SEARCH&keywords=${encodeURIComponent(query)}&apikey=${this.alphaVantageApiKey}`;\n\n const response = await this.fetchWithTimeout(url);\n\n if (!response.ok) {\n throw new StockClientError(`Alpha Vantage API error: ${response.statusText}`, response.status);\n }\n\n const data = await response.json();\n\n if (data.Note) {\n throw new StockClientError(\"Alpha Vantage rate limit reached\");\n }\n\n const matches = data.bestMatches ?? [];\n\n return matches.map((match: Record<string, string>) => ({\n symbol: match[\"1. symbol\"],\n name: match[\"2. name\"],\n type: match[\"3. type\"],\n exchange: match[\"4. region\"],\n region: match[\"4. region\"],\n }));\n }\n\n /**\n * Get major market indices\n */\n async getMarketIndices(): Promise<MarketIndex[]> {\n const indices: MarketIndex[] = [];\n\n for (const [symbol, info] of Object.entries(MARKET_INDICES)) {\n try {\n const quote = await this.getQuote(symbol);\n indices.push({\n symbol,\n name: info.name,\n value: quote.price,\n change: quote.change,\n changePercent: quote.changePercent,\n });\n } catch (error) {\n console.error(`Failed to get index ${symbol}:`, error);\n }\n }\n\n return indices;\n }\n\n /**\n * Get a formatted summary string for a stock\n */\n async getFormattedSummary(symbol: string): Promise<string> {\n const quote = await this.getQuote(symbol);\n const changeEmoji = quote.changePercent >= 0 ? \"+\" : \"\";\n\n return `${quote.name} (${quote.symbol})\nPrice: $${quote.price.toFixed(2)}\nChange: ${changeEmoji}${quote.change.toFixed(2)} (${changeEmoji}${quote.changePercent.toFixed(2)}%)\nOpen: $${quote.open.toFixed(2)}\nDay Range: $${quote.low.toFixed(2)} - $${quote.high.toFixed(2)}\n52-Week Range: $${quote.week52Low.toFixed(2)} - $${quote.week52High.toFixed(2)}\nVolume: ${quote.volume.toLocaleString()}\n${quote.marketCap > 0 ? `Market Cap: $${(quote.marketCap / 1e9).toFixed(2)}B` : \"\"}\nExchange: ${quote.exchange}`;\n }\n\n /**\n * Get market summary\n */\n async getMarketSummary(): Promise<string> {\n const indices = await this.getMarketIndices();\n\n let summary = \"Market Summary\\n\";\n summary += \"==============\\n\\n\";\n\n for (const index of indices) {\n const changeEmoji = index.changePercent >= 0 ? \"+\" : \"\";\n summary += `${index.name}: ${index.value.toFixed(2)} (${changeEmoji}${index.changePercent.toFixed(2)}%)\\n`;\n }\n\n return summary;\n }\n}\n\nexport function createStockClient(config: StockClientConfig = {}): StockClient {\n return new StockClient(config);\n}\n\nexport default StockClient;\n"],"mappings":";AAsDO,IAAM,mBAAN,cAA+B,MAAM;AAAA,EAC1C,YACE,SACO,YACP;AACA,UAAM,OAAO;AAFN;AAGP,SAAK,OAAO;AAAA,EACd;AACF;AAGA,IAAM,iBAAmE;AAAA,EACvE,SAAS,EAAE,MAAM,WAAW,QAAQ,QAAQ;AAAA,EAC5C,QAAQ,EAAE,MAAM,gCAAgC,QAAQ,OAAO;AAAA,EAC/D,SAAS,EAAE,MAAM,oBAAoB,QAAQ,QAAQ;AAAA,EACrD,QAAQ,EAAE,MAAM,gBAAgB,QAAQ,OAAO;AAAA,EAC/C,QAAQ,EAAE,MAAM,yBAAyB,QAAQ,OAAO;AAAA,EACxD,SAAS,EAAE,MAAM,YAAY,QAAQ,QAAQ;AAAA,EAC7C,SAAS,EAAE,MAAM,cAAc,QAAQ,QAAQ;AAAA,EAC/C,QAAQ,EAAE,MAAM,mBAAmB,QAAQ,OAAO;AACpD;AAQO,IAAM,cAAN,MAAkB;AAAA,EACf;AAAA,EACA,sBAAsB;AAAA,EACtB,eAAe;AAAA,EACf;AAAA,EACA;AAAA,EACA,kBAAkB;AAAA,EAE1B,YAAY,SAA4B,CAAC,GAAG;AAC1C,SAAK,qBAAqB,OAAO;AACjC,SAAK,UAAU,OAAO,WAAW;AACjC,SAAK,iBAAiB,OAAO,kBAAkB;AAAA,EACjD;AAAA,EAEA,MAAc,YAA2B;AACvC,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,uBAAuB,MAAM,KAAK;AACxC,QAAI,uBAAuB,KAAK,gBAAgB;AAC9C,YAAM,IAAI;AAAA,QAAQ,CAAC,YACjB,WAAW,SAAS,KAAK,iBAAiB,oBAAoB;AAAA,MAChE;AAAA,IACF;AACA,SAAK,kBAAkB,KAAK,IAAI;AAAA,EAClC;AAAA,EAEA,MAAc,iBACZ,KACA,UAAuB,CAAC,GACL;AACnB,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,YAAY,WAAW,MAAM,WAAW,MAAM,GAAG,KAAK,OAAO;AAEnE,QAAI;AACF,YAAM,WAAW,MAAM,MAAM,KAAK;AAAA,QAChC,GAAG;AAAA,QACH,QAAQ,WAAW;AAAA,MACrB,CAAC;AACD,mBAAa,SAAS;AACtB,aAAO;AAAA,IACT,SAAS,OAAO;AACd,mBAAa,SAAS;AACtB,UAAK,MAAgB,SAAS,cAAc;AAC1C,cAAM,IAAI,iBAAiB,iBAAiB;AAAA,MAC9C;AACA,YAAM,IAAI;AAAA,QACR,kBAAkB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,MAC1E;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAS,QAAqC;AAClD,UAAM,KAAK,UAAU;AAErB,UAAM,MAAM,GAAG,KAAK,YAAY,UAAU,mBAAmB,MAAM,CAAC;AAEpE,UAAM,WAAW,MAAM,KAAK,iBAAiB,KAAK;AAAA,MAChD,SAAS;AAAA,QACP,QAAQ;AAAA,QACR,cAAc;AAAA,MAChB;AAAA,IACF,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,iBAAiB,4BAA4B,SAAS,UAAU,IAAI,SAAS,MAAM;AAAA,IAC/F;AAEA,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,UAAM,SAAS,MAAM,OAAO,SAAS,CAAC;AAEtC,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,iBAAiB,6BAA6B,MAAM,EAAE;AAAA,IAClE;AAEA,UAAM,OAAO,OAAO;AACpB,UAAM,QAAQ,OAAO,YAAY,QAAQ,CAAC;AAC1C,UAAM,YAAY,KAAK,sBAAsB,OAAO,QAAQ,MAAM,MAAM,SAAS,CAAC,KAAK;AAEvF,WAAO;AAAA,MACL,QAAQ,KAAK;AAAA,MACb,MAAM,KAAK,aAAa,KAAK,YAAY,KAAK;AAAA,MAC9C,OAAO;AAAA,MACP,QAAQ,KAAK,qBAAqB,KAAK;AAAA,MACvC,gBAAiB,KAAK,qBAAqB,KAAK,sBAAsB,KAAK,qBAAsB;AAAA,MACjG,MAAM,KAAK,qBAAqB,OAAO,OAAO,CAAC,KAAK;AAAA,MACpD,MAAM,KAAK,wBAAwB,KAAK,IAAI,GAAI,OAAO,QAAQ,CAAC,CAAC,CAAE;AAAA,MACnE,KAAK,KAAK,uBAAuB,KAAK,IAAI,GAAI,OAAO,KAAK,OAAO,CAAC,MAAc,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE;AAAA,MAC9F,eAAe,KAAK,sBAAsB,KAAK,iBAAiB;AAAA,MAChE,QAAQ,KAAK,uBAAuB;AAAA,MACpC,WAAW,KAAK,aAAa;AAAA,MAC7B,SAAS;AAAA;AAAA,MACT,KAAK;AAAA,MACL,UAAU;AAAA,MACV,eAAe;AAAA,MACf,YAAY,KAAK,oBAAoB;AAAA,MACrC,WAAW,KAAK,mBAAmB;AAAA,MACnC,UAAU,KAAK,gBAAgB;AAAA,MAC/B,aAAa,IAAI,KAAK,KAAK,oBAAoB,GAAI;AAAA,IACrD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAU,SAAqD;AACnE,UAAM,UAAU,oBAAI,IAAwB;AAG5C,UAAM,KAAK,UAAU;AACrB,UAAM,aAAa,QAAQ,KAAK,GAAG;AACnC,UAAM,MAAM,GAAG,KAAK,YAAY,UAAU,mBAAmB,QAAQ,CAAC,CAAC,CAAC;AAIxE,eAAW,UAAU,SAAS;AAC5B,UAAI;AACF,cAAM,QAAQ,MAAM,KAAK,SAAS,MAAM;AACxC,gBAAQ,IAAI,QAAQ,KAAK;AAAA,MAC3B,SAAS,OAAO;AACd,gBAAQ,MAAM,2BAA2B,MAAM,KAAK,KAAK;AAAA,MAC3D;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,kBACJ,QACA,QAAkF,OAClF,WAAsE,MACtC;AAChC,UAAM,KAAK,UAAU;AAErB,UAAM,MAAM,GAAG,KAAK,YAAY,UAAU,mBAAmB,MAAM,CAAC,aAAa,QAAQ,UAAU,KAAK;AAExG,UAAM,WAAW,MAAM,KAAK,iBAAiB,KAAK;AAAA,MAChD,SAAS;AAAA,QACP,QAAQ;AAAA,QACR,cAAc;AAAA,MAChB;AAAA,IACF,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,iBAAiB,4BAA4B,SAAS,UAAU,IAAI,SAAS,MAAM;AAAA,IAC/F;AAEA,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,UAAM,SAAS,MAAM,OAAO,SAAS,CAAC;AAEtC,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,iBAAiB,wCAAwC,MAAM,EAAE;AAAA,IAC7E;AAEA,UAAM,aAAa,OAAO,aAAa,CAAC;AACxC,UAAM,QAAQ,OAAO,YAAY,QAAQ,CAAC,KAAK,CAAC;AAChD,UAAM,WAAW,OAAO,YAAY,WAAW,CAAC,GAAG,YAAY,MAAM,SAAS,CAAC;AAE/E,WAAO,WAAW,IAAI,CAAC,WAAmB,OAAe;AAAA,MACvD,MAAM,IAAI,KAAK,YAAY,GAAI;AAAA,MAC/B,MAAM,MAAM,OAAO,CAAC,KAAK;AAAA,MACzB,MAAM,MAAM,OAAO,CAAC,KAAK;AAAA,MACzB,KAAK,MAAM,MAAM,CAAC,KAAK;AAAA,MACvB,OAAO,MAAM,QAAQ,CAAC,KAAK;AAAA,MAC3B,eAAe,SAAS,CAAC,KAAK,MAAM,QAAQ,CAAC,KAAK;AAAA,MAClD,QAAQ,MAAM,SAAS,CAAC,KAAK;AAAA,IAC/B,EAAE;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,qBAAqB,QAAqC;AAC9D,QAAI,CAAC,KAAK,oBAAoB;AAC5B,YAAM,IAAI,iBAAiB,sCAAsC;AAAA,IACnE;AAEA,UAAM,KAAK,UAAU;AAErB,UAAM,MAAM,GAAG,KAAK,mBAAmB,iCAAiC,mBAAmB,MAAM,CAAC,WAAW,KAAK,kBAAkB;AAEpI,UAAM,WAAW,MAAM,KAAK,iBAAiB,GAAG;AAEhD,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,iBAAiB,4BAA4B,SAAS,UAAU,IAAI,SAAS,MAAM;AAAA,IAC/F;AAEA,UAAM,OAAO,MAAM,SAAS,KAAK;AAEjC,QAAI,KAAK,MAAM;AACb,YAAM,IAAI,iBAAiB,kCAAkC;AAAA,IAC/D;AAEA,QAAI,KAAK,eAAe,GAAG;AACzB,YAAM,IAAI,iBAAiB,KAAK,eAAe,CAAC;AAAA,IAClD;AAEA,UAAM,QAAQ,KAAK,cAAc;AACjC,QAAI,CAAC,SAAS,OAAO,KAAK,KAAK,EAAE,WAAW,GAAG;AAC7C,YAAM,IAAI,iBAAiB,6BAA6B,MAAM,EAAE;AAAA,IAClE;AAEA,UAAM,QAAQ,WAAW,MAAM,WAAW,CAAC,KAAK;AAChD,UAAM,gBAAgB,WAAW,MAAM,oBAAoB,CAAC,KAAK;AAEjE,WAAO;AAAA,MACL,QAAQ,MAAM,YAAY;AAAA,MAC1B,MAAM,MAAM,YAAY;AAAA;AAAA,MACxB;AAAA,MACA,QAAQ,WAAW,MAAM,YAAY,CAAC,KAAK;AAAA,MAC3C,eAAe,WAAW,MAAM,oBAAoB,GAAG,QAAQ,KAAK,EAAE,CAAC,KAAK;AAAA,MAC5E,MAAM,WAAW,MAAM,UAAU,CAAC,KAAK;AAAA,MACvC,MAAM,WAAW,MAAM,UAAU,CAAC,KAAK;AAAA,MACvC,KAAK,WAAW,MAAM,SAAS,CAAC,KAAK;AAAA,MACrC;AAAA,MACA,QAAQ,SAAS,MAAM,YAAY,GAAG,EAAE,KAAK;AAAA,MAC7C,WAAW;AAAA,MACX,SAAS;AAAA,MACT,KAAK;AAAA,MACL,UAAU;AAAA,MACV,eAAe;AAAA,MACf,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,UAAU;AAAA,MACV,aAAa,IAAI,KAAK,MAAM,wBAAwB,CAAC;AAAA,IACvD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,8BACJ,QACA,aAAiC,WACD;AAChC,QAAI,CAAC,KAAK,oBAAoB;AAC5B,YAAM,IAAI,iBAAiB,sCAAsC;AAAA,IACnE;AAEA,UAAM,KAAK,UAAU;AAErB,UAAM,MAAM,GAAG,KAAK,mBAAmB,+CAA+C,mBAAmB,MAAM,CAAC,eAAe,UAAU,WAAW,KAAK,kBAAkB;AAE3K,UAAM,WAAW,MAAM,KAAK,iBAAiB,GAAG;AAEhD,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,iBAAiB,4BAA4B,SAAS,UAAU,IAAI,SAAS,MAAM;AAAA,IAC/F;AAEA,UAAM,OAAO,MAAM,SAAS,KAAK;AAEjC,QAAI,KAAK,MAAM;AACb,YAAM,IAAI,iBAAiB,kCAAkC;AAAA,IAC/D;AAEA,QAAI,KAAK,eAAe,GAAG;AACzB,YAAM,IAAI,iBAAiB,KAAK,eAAe,CAAC;AAAA,IAClD;AAEA,UAAM,aAAa,KAAK,qBAAqB;AAC7C,QAAI,CAAC,YAAY;AACf,YAAM,IAAI,iBAAiB,wCAAwC,MAAM,EAAE;AAAA,IAC7E;AAEA,WAAO,OAAO,QAAQ,UAAU,EAC7B,IAAI,CAAC,CAAC,MAAM,MAAM,OAAsB;AAAA,MACvC,MAAM,IAAI,KAAK,IAAI;AAAA,MACnB,MAAM,WAAW,OAAO,SAAS,CAAC,KAAK;AAAA,MACvC,MAAM,WAAW,OAAO,SAAS,CAAC,KAAK;AAAA,MACvC,KAAK,WAAW,OAAO,QAAQ,CAAC,KAAK;AAAA,MACrC,OAAO,WAAW,OAAO,UAAU,CAAC,KAAK;AAAA,MACzC,eAAe,WAAW,OAAO,mBAAmB,CAAC,KAAK;AAAA,MAC1D,QAAQ,SAAS,OAAO,WAAW,GAAG,EAAE,KAAK;AAAA,IAC/C,EAAE,EACD,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,QAAQ,IAAI,EAAE,KAAK,QAAQ,CAAC;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAa,OAA6C;AAC9D,QAAI,CAAC,KAAK,oBAAoB;AAE5B,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,KAAK,UAAU;AAErB,UAAM,MAAM,GAAG,KAAK,mBAAmB,oCAAoC,mBAAmB,KAAK,CAAC,WAAW,KAAK,kBAAkB;AAEtI,UAAM,WAAW,MAAM,KAAK,iBAAiB,GAAG;AAEhD,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,iBAAiB,4BAA4B,SAAS,UAAU,IAAI,SAAS,MAAM;AAAA,IAC/F;AAEA,UAAM,OAAO,MAAM,SAAS,KAAK;AAEjC,QAAI,KAAK,MAAM;AACb,YAAM,IAAI,iBAAiB,kCAAkC;AAAA,IAC/D;AAEA,UAAM,UAAU,KAAK,eAAe,CAAC;AAErC,WAAO,QAAQ,IAAI,CAAC,WAAmC;AAAA,MACrD,QAAQ,MAAM,WAAW;AAAA,MACzB,MAAM,MAAM,SAAS;AAAA,MACrB,MAAM,MAAM,SAAS;AAAA,MACrB,UAAU,MAAM,WAAW;AAAA,MAC3B,QAAQ,MAAM,WAAW;AAAA,IAC3B,EAAE;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,mBAA2C;AAC/C,UAAM,UAAyB,CAAC;AAEhC,eAAW,CAAC,QAAQ,IAAI,KAAK,OAAO,QAAQ,cAAc,GAAG;AAC3D,UAAI;AACF,cAAM,QAAQ,MAAM,KAAK,SAAS,MAAM;AACxC,gBAAQ,KAAK;AAAA,UACX;AAAA,UACA,MAAM,KAAK;AAAA,UACX,OAAO,MAAM;AAAA,UACb,QAAQ,MAAM;AAAA,UACd,eAAe,MAAM;AAAA,QACvB,CAAC;AAAA,MACH,SAAS,OAAO;AACd,gBAAQ,MAAM,uBAAuB,MAAM,KAAK,KAAK;AAAA,MACvD;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,oBAAoB,QAAiC;AACzD,UAAM,QAAQ,MAAM,KAAK,SAAS,MAAM;AACxC,UAAM,cAAc,MAAM,iBAAiB,IAAI,MAAM;AAErD,WAAO,GAAG,MAAM,IAAI,KAAK,MAAM,MAAM;AAAA,UAC/B,MAAM,MAAM,QAAQ,CAAC,CAAC;AAAA,UACtB,WAAW,GAAG,MAAM,OAAO,QAAQ,CAAC,CAAC,KAAK,WAAW,GAAG,MAAM,cAAc,QAAQ,CAAC,CAAC;AAAA,SACvF,MAAM,KAAK,QAAQ,CAAC,CAAC;AAAA,cAChB,MAAM,IAAI,QAAQ,CAAC,CAAC,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC;AAAA,kBAC5C,MAAM,UAAU,QAAQ,CAAC,CAAC,OAAO,MAAM,WAAW,QAAQ,CAAC,CAAC;AAAA,UACpE,MAAM,OAAO,eAAe,CAAC;AAAA,EACrC,MAAM,YAAY,IAAI,iBAAiB,MAAM,YAAY,KAAK,QAAQ,CAAC,CAAC,MAAM,EAAE;AAAA,YACtE,MAAM,QAAQ;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,mBAAoC;AACxC,UAAM,UAAU,MAAM,KAAK,iBAAiB;AAE5C,QAAI,UAAU;AACd,eAAW;AAEX,eAAW,SAAS,SAAS;AAC3B,YAAM,cAAc,MAAM,iBAAiB,IAAI,MAAM;AACrD,iBAAW,GAAG,MAAM,IAAI,KAAK,MAAM,MAAM,QAAQ,CAAC,CAAC,KAAK,WAAW,GAAG,MAAM,cAAc,QAAQ,CAAC,CAAC;AAAA;AAAA,IACtG;AAEA,WAAO;AAAA,EACT;AACF;AAEO,SAAS,kBAAkB,SAA4B,CAAC,GAAgB;AAC7E,SAAO,IAAI,YAAY,MAAM;AAC/B;AAEA,IAAO,iBAAQ;","names":[]}
|