opensentinel 3.1.1 → 3.7.0
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 +138 -83
- package/dist/agent-manager-JZ4IM7XI.js +39 -0
- package/dist/agent-processor-DDDHC2SO.js +281 -0
- package/dist/agent-processor-DDDHC2SO.js.map +1 -0
- package/dist/agent-types-2T4PXLFQ.js +12 -0
- package/dist/alerting-LK7VVYTX.js +699 -0
- package/dist/alerting-LK7VVYTX.js.map +1 -0
- package/dist/analysis-agent-JWN2GXYE.js +288 -0
- package/dist/analysis-agent-JWN2GXYE.js.map +1 -0
- package/dist/analyzer-OTWE3ARE.js +22 -0
- package/dist/{archiver-AVNBYCKQ.js → archiver-FPGKRP6P.js} +2 -2
- package/dist/{audit-logger-OBPR7CRO.js → audit-logger-CI4WZQPD.js} +6 -5
- package/dist/{auth-UOX5K2BE.js → auth-PH5IHISW.js} +2 -2
- package/dist/{autonomy-ZXDBDQUJ.js → autonomy-N7W5XPLX.js} +4 -3
- package/dist/autonomy-N7W5XPLX.js.map +1 -0
- package/dist/{aws-s3-Q4LLZZPD.js → aws-s3-QZMURYXB.js} +2 -2
- package/dist/{backup-restore-PZ7CYYB7.js → backup-restore-72OQTZO3.js} +2 -2
- package/dist/{blocks-R3PODY47.js → blocks-YOWOESDD.js} +4 -4
- package/dist/bot-VDHBGUVI.js +47 -0
- package/dist/brain-6QTXN4QP.js +66 -0
- package/dist/{camera-monitor-M5CYKUU4.js → camera-monitor-LHTUWHEL.js} +2 -2
- package/dist/{charts-V7ARZNKF.js → charts-FJ32GQK7.js} +2 -2
- package/dist/{chunk-WRAKK6K6.js → chunk-2I5QHYG6.js} +5 -3
- package/dist/chunk-2I5QHYG6.js.map +1 -0
- package/dist/{chunk-TVEWKIK3.js → chunk-2WTKTG2C.js} +2 -2
- package/dist/chunk-3AWAWRWB.js +143 -0
- package/dist/chunk-3AWAWRWB.js.map +1 -0
- package/dist/{chunk-ZLZKF2PM.js → chunk-4KIHDIXZ.js} +43 -2
- package/dist/chunk-4KIHDIXZ.js.map +1 -0
- package/dist/{chunk-EVE7MIIY.js → chunk-4WH6MFEW.js} +15 -16
- package/dist/chunk-4WH6MFEW.js.map +1 -0
- package/dist/{chunk-I6BDYQIG.js → chunk-56UJS2LA.js} +6 -6
- package/dist/chunk-56UJS2LA.js.map +1 -0
- package/dist/chunk-5BTVJR7R.js +37 -0
- package/dist/chunk-5BTVJR7R.js.map +1 -0
- package/dist/chunk-5JJTLWOR.js +1021 -0
- package/dist/chunk-5JJTLWOR.js.map +1 -0
- package/dist/chunk-66SAOZPU.js +236 -0
- package/dist/chunk-66SAOZPU.js.map +1 -0
- package/dist/chunk-6HGMRR4J.js +113 -0
- package/dist/chunk-6HGMRR4J.js.map +1 -0
- package/dist/chunk-6W6PTJFT.js +181 -0
- package/dist/chunk-6W6PTJFT.js.map +1 -0
- package/dist/chunk-6ZNCY2GI.js +418 -0
- package/dist/chunk-6ZNCY2GI.js.map +1 -0
- package/dist/chunk-7BNFELEK.js +31 -0
- package/dist/chunk-7BNFELEK.js.map +1 -0
- package/dist/chunk-ADTDYJO7.js +265 -0
- package/dist/chunk-ADTDYJO7.js.map +1 -0
- package/dist/{chunk-OCVQGBJK.js → chunk-BBN4VCNK.js} +6 -4
- package/dist/chunk-BBN4VCNK.js.map +1 -0
- package/dist/{chunk-SJSUSJ47.js → chunk-BNZHWAZC.js} +2 -2
- package/dist/chunk-C6PELIHS.js +60 -0
- package/dist/chunk-C6PELIHS.js.map +1 -0
- package/dist/{chunk-MQJ2ECQT.js → chunk-CUPEENUY.js} +3 -3
- package/dist/{chunk-NHMBTUMW.js → chunk-CWT6CAE5.js} +2 -2
- package/dist/{chunk-4GLYY4NN.js → chunk-CZTMGHUC.js} +8 -2
- package/dist/chunk-CZTMGHUC.js.map +1 -0
- package/dist/{chunk-RZ4YESBG.js → chunk-DOYGMNMK.js} +1 -1
- package/dist/chunk-DOYGMNMK.js.map +1 -0
- package/dist/chunk-DTISLIMB.js +89 -0
- package/dist/chunk-DTISLIMB.js.map +1 -0
- package/dist/{chunk-SPPMCAKG.js → chunk-GBVJTRXS.js} +2 -2
- package/dist/chunk-GBVJTRXS.js.map +1 -0
- package/dist/{chunk-AYUKPTSM.js → chunk-GJETKBOY.js} +96 -218
- package/dist/chunk-GJETKBOY.js.map +1 -0
- package/dist/{chunk-BXZ6EA52.js → chunk-GW6V4D43.js} +57 -3
- package/dist/chunk-GW6V4D43.js.map +1 -0
- package/dist/{chunk-6PMVAAA7.js → chunk-HJSEEFO3.js} +3 -3
- package/dist/{chunk-TYAGMJNV.js → chunk-HQZQFEAX.js} +5 -5
- package/dist/{chunk-MXAPLSJ5.js → chunk-J4JW73TT.js} +2 -2
- package/dist/{chunk-VEHFVBLI.js → chunk-JHYYFPKX.js} +2 -2
- package/dist/chunk-LFDXEYYB.js +150 -0
- package/dist/chunk-LFDXEYYB.js.map +1 -0
- package/dist/chunk-MIC5IBQF.js +386 -0
- package/dist/chunk-MIC5IBQF.js.map +1 -0
- package/dist/chunk-ODCFS5WD.js +463 -0
- package/dist/chunk-ODCFS5WD.js.map +1 -0
- package/dist/{chunk-XMCVRVTF.js → chunk-P64EV4YY.js} +1 -1
- package/dist/chunk-P64EV4YY.js.map +1 -0
- package/dist/chunk-PBOCSGNL.js +84 -0
- package/dist/chunk-PBOCSGNL.js.map +1 -0
- package/dist/{chunk-66OJ3WB4.js → chunk-PD3CTDO6.js} +2 -2
- package/dist/chunk-QPY3WRVM.js +647 -0
- package/dist/chunk-QPY3WRVM.js.map +1 -0
- package/dist/chunk-S2EOIVF4.js +3907 -0
- package/dist/chunk-S2EOIVF4.js.map +1 -0
- package/dist/chunk-SDLOMKCW.js +213 -0
- package/dist/chunk-SDLOMKCW.js.map +1 -0
- package/dist/chunk-TKBVW7ZJ.js +162 -0
- package/dist/chunk-TKBVW7ZJ.js.map +1 -0
- package/dist/{chunk-BRBWNV65.js → chunk-U2X2J3FI.js} +3 -3
- package/dist/chunk-U2X2J3FI.js.map +1 -0
- package/dist/{chunk-PLDDJCW6.js → chunk-UP2VWCW5.js} +1 -12
- package/dist/{chunk-SVAPX2XN.js → chunk-V3OKHQUX.js} +9 -7
- package/dist/{chunk-SVAPX2XN.js.map → chunk-V3OKHQUX.js.map} +1 -1
- package/dist/{chunk-4UOE5TUZ.js → chunk-WMDVOWN6.js} +4 -4
- package/dist/chunk-WMFYI7XC.js +564 -0
- package/dist/chunk-WMFYI7XC.js.map +1 -0
- package/dist/chunk-WZAH34TG.js +129 -0
- package/dist/chunk-WZAH34TG.js.map +1 -0
- package/dist/{chunk-H5RQOFO2.js → chunk-X6Q3K3L2.js} +6 -6
- package/dist/chunk-X6Q3K3L2.js.map +1 -0
- package/dist/chunk-XTX7EK43.js +134 -0
- package/dist/chunk-XTX7EK43.js.map +1 -0
- package/dist/chunk-YEDEAX6Y.js +194 -0
- package/dist/chunk-YEDEAX6Y.js.map +1 -0
- package/dist/{chunk-XKYRH4FM.js → chunk-ZIBRVA3Y.js} +70 -30
- package/dist/chunk-ZIBRVA3Y.js.map +1 -0
- package/dist/chunk-ZIYTHUM5.js +457 -0
- package/dist/chunk-ZIYTHUM5.js.map +1 -0
- package/dist/{chunk-766ASQWE.js → chunk-ZMML6T63.js} +2711 -2329
- package/dist/chunk-ZMML6T63.js.map +1 -0
- package/dist/chunk-ZVHG4KF2.js +380 -0
- package/dist/chunk-ZVHG4KF2.js.map +1 -0
- package/dist/chunker-K6WTR62A.js +12 -0
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/{client-ZQSFPMOB.js → client-FOIYPOZQ.js} +5 -6
- package/dist/{clipboard-manager-TEO2GEDN.js → clipboard-manager-4SBNESGZ.js} +2 -2
- package/dist/coding-agent-DESSU3AC.js +233 -0
- package/dist/coding-agent-DESSU3AC.js.map +1 -0
- package/dist/commands/setup.js +2 -2
- 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/cost-tracker-KZQSTSE2.js +11 -0
- package/dist/{cron-explain-HHQKPD3M.js → cron-explain-UOOOYWZZ.js} +2 -2
- package/dist/{crypto-4AP47IKC.js → crypto-2VG3RJR2.js} +2 -2
- package/dist/{databases-37X4CI2Y.js → databases-XDPMG5AV.js} +4 -4
- package/dist/db-I7MNG6CL.js +83 -0
- package/dist/discord-6UQHCN27.js +81 -0
- package/dist/documents-PFHSK7SZ.js +184 -0
- package/dist/documents-PFHSK7SZ.js.map +1 -0
- package/dist/docx-parser-EXL4TN5E.js +16 -0
- package/dist/{email-K7LO2IPB.js → email-6OIN4SYL.js} +34 -25
- package/dist/email-6OIN4SYL.js.map +1 -0
- package/dist/{enhanced-retrieval-DNLLEM4Z.js → enhanced-retrieval-JWX2HWU4.js} +12 -8
- package/dist/{enhanced-retrieval-DNLLEM4Z.js.map → enhanced-retrieval-JWX2HWU4.js.map} +1 -1
- package/dist/enrichment-pipeline-7FE5R5ZI.js +14 -0
- package/dist/{entity-resolution-Y3IUWEAT.js → entity-resolution-7Z6STVXX.js} +6 -5
- package/dist/env-GN5VHI43.js +12 -0
- package/dist/error-tracker-64DEH3D7.js +32 -0
- package/dist/finnhub-X7ZMQSXF.js +178 -0
- package/dist/finnhub-X7ZMQSXF.js.map +1 -0
- package/dist/fred-TMUF3J2V.js +203 -0
- package/dist/fred-TMUF3J2V.js.map +1 -0
- package/dist/github-DUWSXCNP.js +833 -0
- package/dist/github-DUWSXCNP.js.map +1 -0
- package/dist/{google-workspace-DKWUVNGC.js → google-workspace-TSZPZK5G.js} +2 -2
- package/dist/graph-client-NB475AK5.js +17 -0
- package/dist/{hash-tool-ULQYD7B5.js → hash-tool-ENAB5LWH.js} +2 -2
- package/dist/{heartbeat-monitor-GCISLXI3.js → heartbeat-monitor-KRDYTDBF.js} +2 -2
- package/dist/hooks-N4MIFBVM.js +14 -0
- package/dist/{image-generation-OSU7FP6F.js → image-generation-MDE6AVQO.js} +2 -2
- package/dist/imessage-DSGSGUZS.js +44 -0
- package/dist/inbox-summarizer-F2KAU72V.js +56 -0
- package/dist/{incident-response-C5J7Q6DT.js → incident-response-E3UGMX5G.js} +8 -6
- package/dist/incident-response-E3UGMX5G.js.map +1 -0
- package/dist/{inventory-manager-352OHXWD.js → inventory-manager-C67BSZM6.js} +2 -2
- package/dist/{jira-GSGDBMIG.js → jira-PAGZWUBJ.js} +2 -2
- package/dist/{json-tool-QE2SYHEG.js → json-tool-4FK5RNER.js} +2 -2
- package/dist/{key-rotation-DPHU4ZTB.js → key-rotation-WCC5FOYS.js} +2 -2
- package/dist/knowledge-base-5SMMOGQJ.js +46 -0
- package/dist/lib.d.ts +94 -1
- package/dist/lib.js +83 -66
- package/dist/lib.js.map +1 -1
- package/dist/{mailchimp-KKNF6QJ7.js → mailchimp-ZFYDC44J.js} +2 -2
- package/dist/{matrix-QVHG76I7.js → matrix-WYGEOZL5.js} +30 -21
- package/dist/{matrix-QVHG76I7.js.map → matrix-WYGEOZL5.js.map} +1 -1
- package/dist/{mcp-3JI6W7ZE.js → mcp-DJ2QDA6A.js} +3 -3
- package/dist/metrics-BH3ZLGEV.js +25 -0
- package/dist/{microsoft365-UCBKJHNX.js → microsoft365-6G2IJMWC.js} +2 -2
- package/dist/multi-user-XAEMB244.js +411 -0
- package/dist/multi-user-XAEMB244.js.map +1 -0
- package/dist/oauth-UPJYFOVU.js +34 -0
- package/dist/{ocr-AC7NPX33.js → ocr-UONKTQU7.js} +6 -4
- package/dist/{ollama-BOAMSPLJ.js → ollama-J7CU45WT.js} +2 -2
- package/dist/osint-agent-RL5XPBRQ.js +189 -0
- package/dist/osint-agent-RL5XPBRQ.js.map +1 -0
- package/dist/{pages-MI523RB7.js → pages-XDE7JRCA.js} +5 -5
- package/dist/{pair-JDFTERIK.js → pair-YZJFQUU5.js} +2 -2
- package/dist/{pairing-IFQYCPNS.js → pairing-77N47RAT.js} +2 -2
- package/dist/{pdf-ALQVOEJR.js → pdf-67HGXCFJ.js} +3 -3
- package/dist/pdf-parser-YLMTTYHL.js +14 -0
- package/dist/{presentations-DSV5IHG5.js → presentations-UOET2FVZ.js} +3 -3
- package/dist/presentations-UOET2FVZ.js.map +1 -0
- package/dist/{prometheus-JNT2BD4L.js → prometheus-YETCZO4I.js} +2 -2
- package/dist/prometheus-YETCZO4I.js.map +1 -0
- package/dist/{providers-J4LYPHDR.js → providers-2YQ6E3IF.js} +6 -4
- package/dist/providers-2YQ6E3IF.js.map +1 -0
- package/dist/{qr-code-WIX4PB4U.js → qr-code-6WZJHRKL.js} +2 -2
- package/dist/qr-code-6WZJHRKL.js.map +1 -0
- package/dist/{quickbooks-XB4NII2S.js → quickbooks-N675W7IK.js} +2 -2
- package/dist/{regex-tool-W4ABRKGK.js → regex-tool-6Q63LQ7B.js} +2 -2
- package/dist/regex-tool-6Q63LQ7B.js.map +1 -0
- package/dist/research-agent-WCRSY3UZ.js +168 -0
- package/dist/research-agent-WCRSY3UZ.js.map +1 -0
- package/dist/risk-engine-YKCPT5D5.js +10 -0
- package/dist/risk-engine-YKCPT5D5.js.map +1 -0
- package/dist/scheduler-6PLLAQI7.js +74 -0
- package/dist/scheduler-6PLLAQI7.js.map +1 -0
- package/dist/schema-ETY7L2VA.js +78 -0
- package/dist/schema-ETY7L2VA.js.map +1 -0
- package/dist/{search-BCLBO5E3.js → search-GMLKBHSW.js} +4 -4
- package/dist/search-GMLKBHSW.js.map +1 -0
- package/dist/{sendgrid-RNXCAFKM.js → sendgrid-QGJIVPWV.js} +2 -2
- package/dist/sharepoint-V5P4Q62L.js +30 -0
- package/dist/sharepoint-V5P4Q62L.js.map +1 -0
- package/dist/{shopify-NCXYJB4R.js → shopify-ON2PAU27.js} +2 -2
- package/dist/signal-7D5EPGVL.js +44 -0
- package/dist/signal-7D5EPGVL.js.map +1 -0
- package/dist/slack-KSS6YK5Z.js +86 -0
- package/dist/slack-KSS6YK5Z.js.map +1 -0
- package/dist/{sms-M3JIOTCW.js → sms-CSUCC7HL.js} +4 -4
- package/dist/sms-CSUCC7HL.js.map +1 -0
- package/dist/{src-VYUE6LRA.js → src-GO7GGW7O.js} +190 -52
- package/dist/src-GO7GGW7O.js.map +1 -0
- package/dist/{stocks-XXWBPOCU.js → stocks-4M4HZWZS.js} +2 -2
- package/dist/stocks-4M4HZWZS.js.map +1 -0
- package/dist/text-extractor-OAUBAW5P.js +12 -0
- package/dist/text-extractor-OAUBAW5P.js.map +1 -0
- package/dist/{text-transform-6SGUA5Z4.js → text-transform-HCLCUDFZ.js} +2 -2
- package/dist/text-transform-HCLCUDFZ.js.map +1 -0
- package/dist/token-store-SEWRX6RE.js +20 -0
- package/dist/token-store-SEWRX6RE.js.map +1 -0
- package/dist/tools-PJZ6RI4P.js +47 -0
- package/dist/tools-PJZ6RI4P.js.map +1 -0
- package/dist/{tunnel-IWMXUML4.js → tunnel-XOUVVRAK.js} +4 -2
- package/dist/tunnel-XOUVVRAK.js.map +1 -0
- package/dist/{twilio-53GEW5JT.js → twilio-3L7DUNYQ.js} +2 -2
- package/dist/{unit-converter-ZYXMEZOE.js → unit-converter-LYPAHU64.js} +2 -2
- package/dist/unit-converter-LYPAHU64.js.map +1 -0
- package/dist/whatsapp-DWXK25V2.js +44 -0
- package/dist/whatsapp-DWXK25V2.js.map +1 -0
- package/dist/{word-document-7B6SJMAY.js → word-document-AV3YB4L2.js} +4 -4
- package/dist/word-document-AV3YB4L2.js.map +1 -0
- package/dist/workflow-store-5Y56GUP7.js +373 -0
- package/dist/workflow-store-5Y56GUP7.js.map +1 -0
- package/dist/writing-agent-VDGLNOGO.js +243 -0
- package/dist/writing-agent-VDGLNOGO.js.map +1 -0
- package/dist/{xero-QYO66D45.js → xero-UHAHVYSD.js} +2 -2
- package/dist/{zapier-webhook-TBZ5YF2A.js → zapier-webhook-NIELLTXR.js} +2 -2
- package/drizzle/0002_mushy_master_mold.sql +139 -139
- package/drizzle/0003_overjoyed_rhodey.sql +46 -0
- package/drizzle/meta/0002_snapshot.json +3636 -3636
- package/drizzle/meta/0003_snapshot.json +3946 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +110 -100
- package/dist/autonomy-ZXDBDQUJ.js.map +0 -1
- package/dist/bot-QRARP4UN.js +0 -36
- package/dist/brain-7XLLM3KC.js +0 -56
- package/dist/chunk-4GLYY4NN.js.map +0 -1
- package/dist/chunk-766ASQWE.js.map +0 -1
- package/dist/chunk-AYUKPTSM.js.map +0 -1
- package/dist/chunk-BRBWNV65.js.map +0 -1
- package/dist/chunk-BXZ6EA52.js.map +0 -1
- package/dist/chunk-EVE7MIIY.js.map +0 -1
- package/dist/chunk-H5RQOFO2.js.map +0 -1
- package/dist/chunk-I6BDYQIG.js.map +0 -1
- package/dist/chunk-IZJMVV7O.js +0 -347
- package/dist/chunk-IZJMVV7O.js.map +0 -1
- package/dist/chunk-O7IH7JTI.js +0 -1898
- package/dist/chunk-O7IH7JTI.js.map +0 -1
- package/dist/chunk-OCVQGBJK.js.map +0 -1
- package/dist/chunk-RZ4YESBG.js.map +0 -1
- package/dist/chunk-SPPMCAKG.js.map +0 -1
- package/dist/chunk-VRD5CYRL.js +0 -1568
- package/dist/chunk-VRD5CYRL.js.map +0 -1
- package/dist/chunk-WRAKK6K6.js.map +0 -1
- package/dist/chunk-XKYRH4FM.js.map +0 -1
- package/dist/chunk-XMCVRVTF.js.map +0 -1
- package/dist/chunk-ZLZKF2PM.js.map +0 -1
- package/dist/discord-B3HUPGQ6.js +0 -70
- package/dist/dist-UISMLMFN.js +0 -21847
- package/dist/dist-UISMLMFN.js.map +0 -1
- package/dist/email-K7LO2IPB.js.map +0 -1
- package/dist/enrichment-pipeline-MNHNW65K.js +0 -13
- package/dist/env-IWXUVTCB.js +0 -12
- package/dist/imessage-NGA2XF2V.js +0 -35
- package/dist/inbox-summarizer-NRI4S7IF.js +0 -47
- package/dist/incident-response-C5J7Q6DT.js.map +0 -1
- package/dist/presentations-DSV5IHG5.js.map +0 -1
- package/dist/scheduler-VK4WFERV.js +0 -63
- package/dist/signal-6CGDFYL2.js +0 -35
- package/dist/slack-IZQWIKOH.js +0 -75
- package/dist/src-VYUE6LRA.js.map +0 -1
- package/dist/tools-2RLEI2N6.js +0 -38
- package/dist/tunnel-IWMXUML4.js.map +0 -1
- package/dist/whatsapp-LFX6YKCM.js +0 -35
- package/dist/word-document-7B6SJMAY.js.map +0 -1
- /package/dist/{audit-logger-OBPR7CRO.js.map → agent-manager-JZ4IM7XI.js.map} +0 -0
- /package/dist/{auth-UOX5K2BE.js.map → agent-types-2T4PXLFQ.js.map} +0 -0
- /package/dist/{backup-restore-PZ7CYYB7.js.map → analyzer-OTWE3ARE.js.map} +0 -0
- /package/dist/{archiver-AVNBYCKQ.js.map → archiver-FPGKRP6P.js.map} +0 -0
- /package/dist/{blocks-R3PODY47.js.map → audit-logger-CI4WZQPD.js.map} +0 -0
- /package/dist/{bot-QRARP4UN.js.map → auth-PH5IHISW.js.map} +0 -0
- /package/dist/{aws-s3-Q4LLZZPD.js.map → aws-s3-QZMURYXB.js.map} +0 -0
- /package/dist/{brain-7XLLM3KC.js.map → backup-restore-72OQTZO3.js.map} +0 -0
- /package/dist/{chunk-PLDDJCW6.js.map → blocks-YOWOESDD.js.map} +0 -0
- /package/dist/{client-ZQSFPMOB.js.map → bot-VDHBGUVI.js.map} +0 -0
- /package/dist/{clipboard-manager-TEO2GEDN.js.map → brain-6QTXN4QP.js.map} +0 -0
- /package/dist/{camera-monitor-M5CYKUU4.js.map → camera-monitor-LHTUWHEL.js.map} +0 -0
- /package/dist/{charts-V7ARZNKF.js.map → charts-FJ32GQK7.js.map} +0 -0
- /package/dist/{chunk-TVEWKIK3.js.map → chunk-2WTKTG2C.js.map} +0 -0
- /package/dist/{chunk-SJSUSJ47.js.map → chunk-BNZHWAZC.js.map} +0 -0
- /package/dist/{chunk-MQJ2ECQT.js.map → chunk-CUPEENUY.js.map} +0 -0
- /package/dist/{chunk-NHMBTUMW.js.map → chunk-CWT6CAE5.js.map} +0 -0
- /package/dist/{chunk-6PMVAAA7.js.map → chunk-HJSEEFO3.js.map} +0 -0
- /package/dist/{chunk-TYAGMJNV.js.map → chunk-HQZQFEAX.js.map} +0 -0
- /package/dist/{chunk-MXAPLSJ5.js.map → chunk-J4JW73TT.js.map} +0 -0
- /package/dist/{chunk-VEHFVBLI.js.map → chunk-JHYYFPKX.js.map} +0 -0
- /package/dist/{chunk-66OJ3WB4.js.map → chunk-PD3CTDO6.js.map} +0 -0
- /package/dist/{cron-explain-HHQKPD3M.js.map → chunk-UP2VWCW5.js.map} +0 -0
- /package/dist/{chunk-4UOE5TUZ.js.map → chunk-WMDVOWN6.js.map} +0 -0
- /package/dist/{crypto-4AP47IKC.js.map → chunker-K6WTR62A.js.map} +0 -0
- /package/dist/{databases-37X4CI2Y.js.map → client-FOIYPOZQ.js.map} +0 -0
- /package/dist/{discord-B3HUPGQ6.js.map → clipboard-manager-4SBNESGZ.js.map} +0 -0
- /package/dist/{enrichment-pipeline-MNHNW65K.js.map → cost-tracker-KZQSTSE2.js.map} +0 -0
- /package/dist/{entity-resolution-Y3IUWEAT.js.map → cron-explain-UOOOYWZZ.js.map} +0 -0
- /package/dist/{env-IWXUVTCB.js.map → crypto-2VG3RJR2.js.map} +0 -0
- /package/dist/{hash-tool-ULQYD7B5.js.map → databases-XDPMG5AV.js.map} +0 -0
- /package/dist/{heartbeat-monitor-GCISLXI3.js.map → db-I7MNG6CL.js.map} +0 -0
- /package/dist/{imessage-NGA2XF2V.js.map → discord-6UQHCN27.js.map} +0 -0
- /package/dist/{inbox-summarizer-NRI4S7IF.js.map → docx-parser-EXL4TN5E.js.map} +0 -0
- /package/dist/{inventory-manager-352OHXWD.js.map → enrichment-pipeline-7FE5R5ZI.js.map} +0 -0
- /package/dist/{json-tool-QE2SYHEG.js.map → entity-resolution-7Z6STVXX.js.map} +0 -0
- /package/dist/{key-rotation-DPHU4ZTB.js.map → env-GN5VHI43.js.map} +0 -0
- /package/dist/{mcp-3JI6W7ZE.js.map → error-tracker-64DEH3D7.js.map} +0 -0
- /package/dist/{google-workspace-DKWUVNGC.js.map → google-workspace-TSZPZK5G.js.map} +0 -0
- /package/dist/{ocr-AC7NPX33.js.map → graph-client-NB475AK5.js.map} +0 -0
- /package/dist/{ollama-BOAMSPLJ.js.map → hash-tool-ENAB5LWH.js.map} +0 -0
- /package/dist/{pages-MI523RB7.js.map → heartbeat-monitor-KRDYTDBF.js.map} +0 -0
- /package/dist/{pairing-IFQYCPNS.js.map → hooks-N4MIFBVM.js.map} +0 -0
- /package/dist/{image-generation-OSU7FP6F.js.map → image-generation-MDE6AVQO.js.map} +0 -0
- /package/dist/{pdf-ALQVOEJR.js.map → imessage-DSGSGUZS.js.map} +0 -0
- /package/dist/{prometheus-JNT2BD4L.js.map → inbox-summarizer-F2KAU72V.js.map} +0 -0
- /package/dist/{providers-J4LYPHDR.js.map → inventory-manager-C67BSZM6.js.map} +0 -0
- /package/dist/{jira-GSGDBMIG.js.map → jira-PAGZWUBJ.js.map} +0 -0
- /package/dist/{qr-code-WIX4PB4U.js.map → json-tool-4FK5RNER.js.map} +0 -0
- /package/dist/{regex-tool-W4ABRKGK.js.map → key-rotation-WCC5FOYS.js.map} +0 -0
- /package/dist/{scheduler-VK4WFERV.js.map → knowledge-base-5SMMOGQJ.js.map} +0 -0
- /package/dist/{mailchimp-KKNF6QJ7.js.map → mailchimp-ZFYDC44J.js.map} +0 -0
- /package/dist/{search-BCLBO5E3.js.map → mcp-DJ2QDA6A.js.map} +0 -0
- /package/dist/{signal-6CGDFYL2.js.map → metrics-BH3ZLGEV.js.map} +0 -0
- /package/dist/{microsoft365-UCBKJHNX.js.map → microsoft365-6G2IJMWC.js.map} +0 -0
- /package/dist/{slack-IZQWIKOH.js.map → oauth-UPJYFOVU.js.map} +0 -0
- /package/dist/{sms-M3JIOTCW.js.map → ocr-UONKTQU7.js.map} +0 -0
- /package/dist/{stocks-XXWBPOCU.js.map → ollama-J7CU45WT.js.map} +0 -0
- /package/dist/{text-transform-6SGUA5Z4.js.map → pages-XDE7JRCA.js.map} +0 -0
- /package/dist/{pair-JDFTERIK.js.map → pair-YZJFQUU5.js.map} +0 -0
- /package/dist/{tools-2RLEI2N6.js.map → pairing-77N47RAT.js.map} +0 -0
- /package/dist/{unit-converter-ZYXMEZOE.js.map → pdf-67HGXCFJ.js.map} +0 -0
- /package/dist/{whatsapp-LFX6YKCM.js.map → pdf-parser-YLMTTYHL.js.map} +0 -0
- /package/dist/{quickbooks-XB4NII2S.js.map → quickbooks-N675W7IK.js.map} +0 -0
- /package/dist/{sendgrid-RNXCAFKM.js.map → sendgrid-QGJIVPWV.js.map} +0 -0
- /package/dist/{shopify-NCXYJB4R.js.map → shopify-ON2PAU27.js.map} +0 -0
- /package/dist/{twilio-53GEW5JT.js.map → twilio-3L7DUNYQ.js.map} +0 -0
- /package/dist/{xero-QYO66D45.js.map → xero-UHAHVYSD.js.map} +0 -0
- /package/dist/{zapier-webhook-TBZ5YF2A.js.map → zapier-webhook-NIELLTXR.js.map} +0 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// src/core/ml/linear-regression.ts
|
|
2
|
+
var LinearRegression = class _LinearRegression {
|
|
3
|
+
slope = 0;
|
|
4
|
+
intercept = 0;
|
|
5
|
+
rSquared = 0;
|
|
6
|
+
standardError = 0;
|
|
7
|
+
n = 0;
|
|
8
|
+
meanX = 0;
|
|
9
|
+
sumXXDeviation = 0;
|
|
10
|
+
trained = false;
|
|
11
|
+
/**
|
|
12
|
+
* Fit the model to data.
|
|
13
|
+
* @param x Independent variable values
|
|
14
|
+
* @param y Dependent variable values
|
|
15
|
+
*/
|
|
16
|
+
fit(x, y) {
|
|
17
|
+
if (x.length !== y.length || x.length < 2) {
|
|
18
|
+
return { slope: 0, intercept: 0, rSquared: 0, standardError: 0, n: 0 };
|
|
19
|
+
}
|
|
20
|
+
this.n = x.length;
|
|
21
|
+
this.meanX = x.reduce((s, v) => s + v, 0) / this.n;
|
|
22
|
+
const meanY = y.reduce((s, v) => s + v, 0) / this.n;
|
|
23
|
+
let sumXYDeviation = 0;
|
|
24
|
+
this.sumXXDeviation = 0;
|
|
25
|
+
for (let i = 0; i < this.n; i++) {
|
|
26
|
+
const dx = x[i] - this.meanX;
|
|
27
|
+
const dy = y[i] - meanY;
|
|
28
|
+
sumXYDeviation += dx * dy;
|
|
29
|
+
this.sumXXDeviation += dx * dx;
|
|
30
|
+
}
|
|
31
|
+
this.slope = this.sumXXDeviation > 0 ? sumXYDeviation / this.sumXXDeviation : 0;
|
|
32
|
+
this.intercept = meanY - this.slope * this.meanX;
|
|
33
|
+
let ssRes = 0;
|
|
34
|
+
let ssTot = 0;
|
|
35
|
+
for (let i = 0; i < this.n; i++) {
|
|
36
|
+
const predicted = this.slope * x[i] + this.intercept;
|
|
37
|
+
ssRes += (y[i] - predicted) ** 2;
|
|
38
|
+
ssTot += (y[i] - meanY) ** 2;
|
|
39
|
+
}
|
|
40
|
+
this.rSquared = ssTot > 0 ? 1 - ssRes / ssTot : 0;
|
|
41
|
+
this.standardError = this.n > 2 ? Math.sqrt(ssRes / (this.n - 2)) : 0;
|
|
42
|
+
this.trained = true;
|
|
43
|
+
return {
|
|
44
|
+
slope: this.slope,
|
|
45
|
+
intercept: this.intercept,
|
|
46
|
+
rSquared: this.rSquared,
|
|
47
|
+
standardError: this.standardError,
|
|
48
|
+
n: this.n
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Predict y for a given x, with confidence interval.
|
|
53
|
+
*/
|
|
54
|
+
predict(x) {
|
|
55
|
+
if (!this.trained) return { value: 0, lower95: 0, upper95: 0 };
|
|
56
|
+
const value = this.slope * x + this.intercept;
|
|
57
|
+
const t = 1.96;
|
|
58
|
+
const dx = x - this.meanX;
|
|
59
|
+
const predictionSE = this.standardError * Math.sqrt(
|
|
60
|
+
1 + 1 / this.n + (this.sumXXDeviation > 0 ? dx * dx / this.sumXXDeviation : 0)
|
|
61
|
+
);
|
|
62
|
+
return {
|
|
63
|
+
value,
|
|
64
|
+
lower95: value - t * predictionSE,
|
|
65
|
+
upper95: value + t * predictionSE
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Predict multiple values.
|
|
70
|
+
*/
|
|
71
|
+
predictBatch(xValues) {
|
|
72
|
+
return xValues.map((x) => this.predict(x));
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Forecast future values for a time series.
|
|
76
|
+
* @param historicalY Array of historical values (assumes x = 0, 1, 2, ...)
|
|
77
|
+
* @param stepsAhead How many steps to forecast
|
|
78
|
+
*/
|
|
79
|
+
static forecast(historicalY, stepsAhead) {
|
|
80
|
+
const x = historicalY.map((_, i) => i);
|
|
81
|
+
const model = new _LinearRegression();
|
|
82
|
+
model.fit(x, historicalY);
|
|
83
|
+
const predictions = [];
|
|
84
|
+
for (let i = 0; i < stepsAhead; i++) {
|
|
85
|
+
predictions.push(model.predict(historicalY.length + i));
|
|
86
|
+
}
|
|
87
|
+
return predictions;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Detect trend direction and strength.
|
|
91
|
+
*/
|
|
92
|
+
static detectTrend(values) {
|
|
93
|
+
if (values.length < 2) return { direction: "flat", strength: 0, slopePerUnit: 0 };
|
|
94
|
+
const x = values.map((_, i) => i);
|
|
95
|
+
const model = new _LinearRegression();
|
|
96
|
+
const result = model.fit(x, values);
|
|
97
|
+
const avgValue = values.reduce((s, v) => s + v, 0) / values.length;
|
|
98
|
+
const normalizedSlope = avgValue !== 0 ? result.slope / avgValue : 0;
|
|
99
|
+
let direction;
|
|
100
|
+
if (Math.abs(normalizedSlope) < 0.01) {
|
|
101
|
+
direction = "flat";
|
|
102
|
+
} else {
|
|
103
|
+
direction = normalizedSlope > 0 ? "up" : "down";
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
direction,
|
|
107
|
+
strength: result.rSquared,
|
|
108
|
+
slopePerUnit: result.slope
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
getResult() {
|
|
112
|
+
if (!this.trained) return null;
|
|
113
|
+
return {
|
|
114
|
+
slope: this.slope,
|
|
115
|
+
intercept: this.intercept,
|
|
116
|
+
rSquared: this.rSquared,
|
|
117
|
+
standardError: this.standardError,
|
|
118
|
+
n: this.n
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
isReady() {
|
|
122
|
+
return this.trained;
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export {
|
|
127
|
+
LinearRegression
|
|
128
|
+
};
|
|
129
|
+
//# sourceMappingURL=chunk-WZAH34TG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/ml/linear-regression.ts"],"sourcesContent":["/**\r\n * Linear Regression — Prediction & Forecasting (Algorithm #1)\r\n *\r\n * Pure TypeScript implementation. No external dependencies.\r\n *\r\n * How it works:\r\n * - Ordinary Least Squares (OLS) for single variable\r\n * - Fits y = mx + b to minimize sum of squared errors\r\n * - Supports confidence intervals and R² scoring\r\n *\r\n * Used in: cost-tracker.ts (cost forecasting),\r\n * pattern-analyzer.ts (trend detection)\r\n */\r\n\r\nexport interface RegressionResult {\r\n /** Slope (m in y = mx + b) */\r\n slope: number;\r\n /** Intercept (b in y = mx + b) */\r\n intercept: number;\r\n /** R² score (0–1, higher = better fit) */\r\n rSquared: number;\r\n /** Standard error of the estimate */\r\n standardError: number;\r\n /** Number of data points used */\r\n n: number;\r\n}\r\n\r\nexport interface Prediction {\r\n /** Predicted value */\r\n value: number;\r\n /** Lower bound of 95% confidence interval */\r\n lower95: number;\r\n /** Upper bound of 95% confidence interval */\r\n upper95: number;\r\n}\r\n\r\nexport class LinearRegression {\r\n private slope = 0;\r\n private intercept = 0;\r\n private rSquared = 0;\r\n private standardError = 0;\r\n private n = 0;\r\n private meanX = 0;\r\n private sumXXDeviation = 0;\r\n private trained = false;\r\n\r\n /**\r\n * Fit the model to data.\r\n * @param x Independent variable values\r\n * @param y Dependent variable values\r\n */\r\n fit(x: number[], y: number[]): RegressionResult {\r\n if (x.length !== y.length || x.length < 2) {\r\n return { slope: 0, intercept: 0, rSquared: 0, standardError: 0, n: 0 };\r\n }\r\n\r\n this.n = x.length;\r\n\r\n // Compute means\r\n this.meanX = x.reduce((s, v) => s + v, 0) / this.n;\r\n const meanY = y.reduce((s, v) => s + v, 0) / this.n;\r\n\r\n // Compute slope and intercept using OLS\r\n let sumXYDeviation = 0;\r\n this.sumXXDeviation = 0;\r\n\r\n for (let i = 0; i < this.n; i++) {\r\n const dx = x[i] - this.meanX;\r\n const dy = y[i] - meanY;\r\n sumXYDeviation += dx * dy;\r\n this.sumXXDeviation += dx * dx;\r\n }\r\n\r\n this.slope = this.sumXXDeviation > 0 ? sumXYDeviation / this.sumXXDeviation : 0;\r\n this.intercept = meanY - this.slope * this.meanX;\r\n\r\n // Compute R² and standard error\r\n let ssRes = 0;\r\n let ssTot = 0;\r\n for (let i = 0; i < this.n; i++) {\r\n const predicted = this.slope * x[i] + this.intercept;\r\n ssRes += (y[i] - predicted) ** 2;\r\n ssTot += (y[i] - meanY) ** 2;\r\n }\r\n\r\n this.rSquared = ssTot > 0 ? 1 - ssRes / ssTot : 0;\r\n this.standardError = this.n > 2 ? Math.sqrt(ssRes / (this.n - 2)) : 0;\r\n this.trained = true;\r\n\r\n return {\r\n slope: this.slope,\r\n intercept: this.intercept,\r\n rSquared: this.rSquared,\r\n standardError: this.standardError,\r\n n: this.n,\r\n };\r\n }\r\n\r\n /**\r\n * Predict y for a given x, with confidence interval.\r\n */\r\n predict(x: number): Prediction {\r\n if (!this.trained) return { value: 0, lower95: 0, upper95: 0 };\r\n\r\n const value = this.slope * x + this.intercept;\r\n\r\n // 95% prediction interval (t ≈ 1.96 for large n)\r\n const t = 1.96;\r\n const dx = x - this.meanX;\r\n const predictionSE = this.standardError * Math.sqrt(\r\n 1 + 1 / this.n + (this.sumXXDeviation > 0 ? (dx * dx) / this.sumXXDeviation : 0)\r\n );\r\n\r\n return {\r\n value,\r\n lower95: value - t * predictionSE,\r\n upper95: value + t * predictionSE,\r\n };\r\n }\r\n\r\n /**\r\n * Predict multiple values.\r\n */\r\n predictBatch(xValues: number[]): Prediction[] {\r\n return xValues.map((x) => this.predict(x));\r\n }\r\n\r\n /**\r\n * Forecast future values for a time series.\r\n * @param historicalY Array of historical values (assumes x = 0, 1, 2, ...)\r\n * @param stepsAhead How many steps to forecast\r\n */\r\n static forecast(historicalY: number[], stepsAhead: number): Prediction[] {\r\n const x = historicalY.map((_, i) => i);\r\n const model = new LinearRegression();\r\n model.fit(x, historicalY);\r\n\r\n const predictions: Prediction[] = [];\r\n for (let i = 0; i < stepsAhead; i++) {\r\n predictions.push(model.predict(historicalY.length + i));\r\n }\r\n return predictions;\r\n }\r\n\r\n /**\r\n * Detect trend direction and strength.\r\n */\r\n static detectTrend(values: number[]): {\r\n direction: \"up\" | \"down\" | \"flat\";\r\n strength: number;\r\n slopePerUnit: number;\r\n } {\r\n if (values.length < 2) return { direction: \"flat\", strength: 0, slopePerUnit: 0 };\r\n\r\n const x = values.map((_, i) => i);\r\n const model = new LinearRegression();\r\n const result = model.fit(x, values);\r\n\r\n const avgValue = values.reduce((s, v) => s + v, 0) / values.length;\r\n const normalizedSlope = avgValue !== 0 ? result.slope / avgValue : 0;\r\n\r\n let direction: \"up\" | \"down\" | \"flat\";\r\n if (Math.abs(normalizedSlope) < 0.01) {\r\n direction = \"flat\";\r\n } else {\r\n direction = normalizedSlope > 0 ? \"up\" : \"down\";\r\n }\r\n\r\n return {\r\n direction,\r\n strength: result.rSquared,\r\n slopePerUnit: result.slope,\r\n };\r\n }\r\n\r\n getResult(): RegressionResult | null {\r\n if (!this.trained) return null;\r\n return {\r\n slope: this.slope,\r\n intercept: this.intercept,\r\n rSquared: this.rSquared,\r\n standardError: this.standardError,\r\n n: this.n,\r\n };\r\n }\r\n\r\n isReady(): boolean {\r\n return this.trained;\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getNotionClient,
|
|
3
3
|
init_client
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-C6PELIHS.js";
|
|
5
5
|
|
|
6
6
|
// src/integrations/notion/search.ts
|
|
7
7
|
init_client();
|
|
@@ -30,8 +30,8 @@ function pageToSearchResult(page) {
|
|
|
30
30
|
createdTime: page.created_time,
|
|
31
31
|
lastEditedTime: page.last_edited_time,
|
|
32
32
|
archived: page.archived,
|
|
33
|
-
icon: page.icon?.type === "emoji" ? page.icon.emoji : page.icon?.type === "external" ? page.icon.external
|
|
34
|
-
cover: page.cover?.type === "external" ? page.cover.external
|
|
33
|
+
icon: page.icon?.type === "emoji" ? page.icon.emoji : page.icon?.type === "external" ? page.icon.external?.url : void 0,
|
|
34
|
+
cover: page.cover?.type === "external" ? page.cover.external?.url : page.cover?.type === "file" ? page.cover.file?.url : void 0,
|
|
35
35
|
parent
|
|
36
36
|
};
|
|
37
37
|
}
|
|
@@ -51,8 +51,8 @@ function databaseToSearchResult(database) {
|
|
|
51
51
|
createdTime: database.created_time,
|
|
52
52
|
lastEditedTime: database.last_edited_time,
|
|
53
53
|
isInline: database.is_inline,
|
|
54
|
-
icon: database.icon?.type === "emoji" ? database.icon.emoji : database.icon?.type === "external" ? database.icon.external
|
|
55
|
-
cover: database.cover?.type === "external" ? database.cover.external
|
|
54
|
+
icon: database.icon?.type === "emoji" ? database.icon.emoji : database.icon?.type === "external" ? database.icon.external?.url : void 0,
|
|
55
|
+
cover: database.cover?.type === "external" ? database.cover.external?.url : database.cover?.type === "file" ? database.cover.file?.url : void 0,
|
|
56
56
|
parent
|
|
57
57
|
};
|
|
58
58
|
}
|
|
@@ -187,4 +187,4 @@ export {
|
|
|
187
187
|
getRecentlyEditedDatabases,
|
|
188
188
|
fullTextSearch
|
|
189
189
|
};
|
|
190
|
-
//# sourceMappingURL=chunk-
|
|
190
|
+
//# sourceMappingURL=chunk-X6Q3K3L2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/integrations/notion/search.ts"],"sourcesContent":["import { getNotionClient } from \"./client\";\r\n\r\n/**\r\n * Search functionality for Notion workspace\r\n * Supports searching across pages and databases\r\n */\r\n\r\n// Type definitions for API responses\r\ninterface PageObjectResponse {\r\n object: \"page\";\r\n id: string;\r\n url: string;\r\n created_time: string;\r\n last_edited_time: string;\r\n archived: boolean;\r\n icon?: { type: string; emoji?: string; external?: { url: string } };\r\n cover?: { type: string; external?: { url: string }; file?: { url: string } };\r\n parent: { type: string; page_id?: string; database_id?: string };\r\n properties: Record<string, any>;\r\n}\r\n\r\ninterface DatabaseObjectResponse {\r\n object: \"database\";\r\n id: string;\r\n url: string;\r\n title: Array<{ plain_text: string }>;\r\n description: Array<{ plain_text: string }>;\r\n created_time: string;\r\n last_edited_time: string;\r\n is_inline: boolean;\r\n icon?: { type: string; emoji?: string; external?: { url: string } };\r\n cover?: { type: string; external?: { url: string }; file?: { url: string } };\r\n parent: { type: string; page_id?: string };\r\n}\r\n\r\ninterface SearchParams {\r\n query?: string;\r\n filter?: any;\r\n sort?: any;\r\n start_cursor?: string;\r\n page_size?: number;\r\n}\r\n\r\nexport type SearchObjectType = \"page\" | \"database\";\r\n\r\nexport interface SearchOptions {\r\n query?: string;\r\n filter?: {\r\n value: SearchObjectType;\r\n property: \"object\";\r\n };\r\n sort?: {\r\n direction: \"ascending\" | \"descending\";\r\n timestamp: \"last_edited_time\";\r\n };\r\n startCursor?: string;\r\n pageSize?: number;\r\n}\r\n\r\nexport interface SearchResultPage {\r\n type: \"page\";\r\n id: string;\r\n url: string;\r\n title: string;\r\n createdTime: string;\r\n lastEditedTime: string;\r\n archived: boolean;\r\n icon?: string;\r\n cover?: string;\r\n parent: {\r\n type: \"page\" | \"database\" | \"workspace\";\r\n id?: string;\r\n };\r\n}\r\n\r\nexport interface SearchResultDatabase {\r\n type: \"database\";\r\n id: string;\r\n url: string;\r\n title: string;\r\n description: string;\r\n createdTime: string;\r\n lastEditedTime: string;\r\n isInline: boolean;\r\n icon?: string;\r\n cover?: string;\r\n parent: {\r\n type: \"page\" | \"workspace\";\r\n id?: string;\r\n };\r\n}\r\n\r\nexport type SearchResult = SearchResultPage | SearchResultDatabase;\r\n\r\nexport interface SearchResponse {\r\n results: SearchResult[];\r\n hasMore: boolean;\r\n nextCursor: string | null;\r\n}\r\n\r\n/**\r\n * Extract title from page properties\r\n */\r\nfunction extractPageTitle(properties: Record<string, any>): string {\r\n for (const value of Object.values(properties)) {\r\n if (value?.type === \"title\" && Array.isArray(value.title)) {\r\n return value.title.map((t: any) => t.plain_text || \"\").join(\"\");\r\n }\r\n }\r\n return \"Untitled\";\r\n}\r\n\r\n/**\r\n * Convert page response to search result\r\n */\r\nfunction pageToSearchResult(page: PageObjectResponse): SearchResultPage {\r\n let parent: SearchResultPage[\"parent\"];\r\n\r\n if (page.parent.type === \"page_id\") {\r\n parent = { type: \"page\", id: page.parent.page_id };\r\n } else if (page.parent.type === \"database_id\") {\r\n parent = { type: \"database\", id: page.parent.database_id };\r\n } else {\r\n parent = { type: \"workspace\" };\r\n }\r\n\r\n return {\r\n type: \"page\",\r\n id: page.id,\r\n url: page.url,\r\n title: extractPageTitle(page.properties),\r\n createdTime: page.created_time,\r\n lastEditedTime: page.last_edited_time,\r\n archived: page.archived,\r\n icon:\r\n page.icon?.type === \"emoji\"\r\n ? page.icon.emoji\r\n : page.icon?.type === \"external\"\r\n ? page.icon.external?.url\r\n : undefined,\r\n cover:\r\n page.cover?.type === \"external\"\r\n ? page.cover.external?.url\r\n : page.cover?.type === \"file\"\r\n ? page.cover.file?.url\r\n : undefined,\r\n parent,\r\n };\r\n}\r\n\r\n/**\r\n * Convert database response to search result\r\n */\r\nfunction databaseToSearchResult(\r\n database: DatabaseObjectResponse\r\n): SearchResultDatabase {\r\n let parent: SearchResultDatabase[\"parent\"];\r\n\r\n if (database.parent.type === \"page_id\") {\r\n parent = { type: \"page\", id: database.parent.page_id };\r\n } else {\r\n parent = { type: \"workspace\" };\r\n }\r\n\r\n return {\r\n type: \"database\",\r\n id: database.id,\r\n url: database.url,\r\n title: database.title.map((t) => t.plain_text).join(\"\"),\r\n description: database.description.map((t) => t.plain_text).join(\"\"),\r\n createdTime: database.created_time,\r\n lastEditedTime: database.last_edited_time,\r\n isInline: database.is_inline,\r\n icon:\r\n database.icon?.type === \"emoji\"\r\n ? database.icon.emoji\r\n : database.icon?.type === \"external\"\r\n ? database.icon.external?.url\r\n : undefined,\r\n cover:\r\n database.cover?.type === \"external\"\r\n ? database.cover.external?.url\r\n : database.cover?.type === \"file\"\r\n ? database.cover.file?.url\r\n : undefined,\r\n parent,\r\n };\r\n}\r\n\r\n/**\r\n * Search across the entire Notion workspace\r\n */\r\nexport async function search(options: SearchOptions = {}): Promise<SearchResponse> {\r\n const notion = getNotionClient();\r\n\r\n const params: SearchParams = {};\r\n\r\n if (options.query) {\r\n params.query = options.query;\r\n }\r\n\r\n if (options.filter) {\r\n // Map 'database' to 'data_source' for newer SDK versions\r\n const filterValue = options.filter.value === \"database\" ? \"data_source\" : options.filter.value;\r\n params.filter = { value: filterValue, property: options.filter.property };\r\n }\r\n\r\n if (options.sort) {\r\n params.sort = options.sort;\r\n }\r\n\r\n if (options.startCursor) {\r\n params.start_cursor = options.startCursor;\r\n }\r\n\r\n if (options.pageSize) {\r\n params.page_size = options.pageSize;\r\n }\r\n\r\n const response = await notion.search(params as any);\r\n\r\n const results: SearchResult[] = response.results.map((item: any) => {\r\n if (item.object === \"page\") {\r\n return pageToSearchResult(item as PageObjectResponse);\r\n } else {\r\n return databaseToSearchResult(item as DatabaseObjectResponse);\r\n }\r\n });\r\n\r\n return {\r\n results,\r\n hasMore: response.has_more,\r\n nextCursor: response.next_cursor,\r\n };\r\n}\r\n\r\n/**\r\n * Search for pages only\r\n */\r\nexport async function searchPages(\r\n query?: string,\r\n options: Omit<SearchOptions, \"filter\"> = {}\r\n): Promise<SearchResultPage[]> {\r\n const response = await search({\r\n ...options,\r\n query,\r\n filter: { value: \"page\", property: \"object\" },\r\n });\r\n\r\n return response.results.filter(\r\n (r): r is SearchResultPage => r.type === \"page\"\r\n );\r\n}\r\n\r\n/**\r\n * Search for databases only\r\n */\r\nexport async function searchDatabases(\r\n query?: string,\r\n options: Omit<SearchOptions, \"filter\"> = {}\r\n): Promise<SearchResultDatabase[]> {\r\n const response = await search({\r\n ...options,\r\n query,\r\n filter: { value: \"database\", property: \"object\" },\r\n });\r\n\r\n return response.results.filter(\r\n (r): r is SearchResultDatabase => r.type === \"database\"\r\n );\r\n}\r\n\r\n/**\r\n * Search all results (handles pagination)\r\n */\r\nexport async function searchAll(\r\n query?: string,\r\n options: Omit<SearchOptions, \"startCursor\" | \"pageSize\"> = {}\r\n): Promise<SearchResult[]> {\r\n const allResults: SearchResult[] = [];\r\n let cursor: string | undefined;\r\n\r\n do {\r\n const response = await search({\r\n ...options,\r\n query,\r\n startCursor: cursor,\r\n pageSize: 100,\r\n });\r\n allResults.push(...response.results);\r\n cursor = response.nextCursor ?? undefined;\r\n } while (cursor);\r\n\r\n return allResults;\r\n}\r\n\r\n/**\r\n * Find a page by title\r\n */\r\nexport async function findPageByTitle(\r\n title: string,\r\n exactMatch: boolean = false\r\n): Promise<SearchResultPage | null> {\r\n const pages = await searchPages(title);\r\n\r\n if (exactMatch) {\r\n return pages.find((p) => p.title === title) || null;\r\n }\r\n\r\n return pages[0] || null;\r\n}\r\n\r\n/**\r\n * Find a database by title\r\n */\r\nexport async function findDatabaseByTitle(\r\n title: string,\r\n exactMatch: boolean = false\r\n): Promise<SearchResultDatabase | null> {\r\n const databases = await searchDatabases(title);\r\n\r\n if (exactMatch) {\r\n return databases.find((d) => d.title === title) || null;\r\n }\r\n\r\n return databases[0] || null;\r\n}\r\n\r\n/**\r\n * Get recently edited pages\r\n */\r\nexport async function getRecentlyEditedPages(\r\n limit: number = 10\r\n): Promise<SearchResultPage[]> {\r\n const response = await search({\r\n filter: { value: \"page\", property: \"object\" },\r\n sort: { direction: \"descending\", timestamp: \"last_edited_time\" },\r\n pageSize: limit,\r\n });\r\n\r\n return response.results.filter(\r\n (r): r is SearchResultPage => r.type === \"page\"\r\n );\r\n}\r\n\r\n/**\r\n * Get recently edited databases\r\n */\r\nexport async function getRecentlyEditedDatabases(\r\n limit: number = 10\r\n): Promise<SearchResultDatabase[]> {\r\n const response = await search({\r\n filter: { value: \"database\", property: \"object\" },\r\n sort: { direction: \"descending\", timestamp: \"last_edited_time\" },\r\n pageSize: limit,\r\n });\r\n\r\n return response.results.filter(\r\n (r): r is SearchResultDatabase => r.type === \"database\"\r\n );\r\n}\r\n\r\n/**\r\n * Full text search in workspace\r\n * Returns pages and databases matching the query\r\n */\r\nexport async function fullTextSearch(\r\n query: string,\r\n options: {\r\n objectType?: SearchObjectType;\r\n limit?: number;\r\n sortByRelevance?: boolean;\r\n } = {}\r\n): Promise<SearchResult[]> {\r\n const searchOptions: SearchOptions = {\r\n query,\r\n pageSize: options.limit ?? 20,\r\n };\r\n\r\n if (options.objectType) {\r\n searchOptions.filter = { value: options.objectType, property: \"object\" };\r\n }\r\n\r\n if (!options.sortByRelevance) {\r\n searchOptions.sort = {\r\n direction: \"descending\",\r\n timestamp: \"last_edited_time\",\r\n };\r\n }\r\n\r\n const response = await search(searchOptions);\r\n return response.results;\r\n}\r\n"],"mappings":";;;;;;AAAA;AAuGA,SAAS,iBAAiB,YAAyC;AACjE,aAAW,SAAS,OAAO,OAAO,UAAU,GAAG;AAC7C,QAAI,OAAO,SAAS,WAAW,MAAM,QAAQ,MAAM,KAAK,GAAG;AACzD,aAAO,MAAM,MAAM,IAAI,CAAC,MAAW,EAAE,cAAc,EAAE,EAAE,KAAK,EAAE;AAAA,IAChE;AAAA,EACF;AACA,SAAO;AACT;AAKA,SAAS,mBAAmB,MAA4C;AACtE,MAAI;AAEJ,MAAI,KAAK,OAAO,SAAS,WAAW;AAClC,aAAS,EAAE,MAAM,QAAQ,IAAI,KAAK,OAAO,QAAQ;AAAA,EACnD,WAAW,KAAK,OAAO,SAAS,eAAe;AAC7C,aAAS,EAAE,MAAM,YAAY,IAAI,KAAK,OAAO,YAAY;AAAA,EAC3D,OAAO;AACL,aAAS,EAAE,MAAM,YAAY;AAAA,EAC/B;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,IAAI,KAAK;AAAA,IACT,KAAK,KAAK;AAAA,IACV,OAAO,iBAAiB,KAAK,UAAU;AAAA,IACvC,aAAa,KAAK;AAAA,IAClB,gBAAgB,KAAK;AAAA,IACrB,UAAU,KAAK;AAAA,IACf,MACE,KAAK,MAAM,SAAS,UAChB,KAAK,KAAK,QACV,KAAK,MAAM,SAAS,aAClB,KAAK,KAAK,UAAU,MACpB;AAAA,IACR,OACE,KAAK,OAAO,SAAS,aACjB,KAAK,MAAM,UAAU,MACrB,KAAK,OAAO,SAAS,SACnB,KAAK,MAAM,MAAM,MACjB;AAAA,IACR;AAAA,EACF;AACF;AAKA,SAAS,uBACP,UACsB;AACtB,MAAI;AAEJ,MAAI,SAAS,OAAO,SAAS,WAAW;AACtC,aAAS,EAAE,MAAM,QAAQ,IAAI,SAAS,OAAO,QAAQ;AAAA,EACvD,OAAO;AACL,aAAS,EAAE,MAAM,YAAY;AAAA,EAC/B;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,IAAI,SAAS;AAAA,IACb,KAAK,SAAS;AAAA,IACd,OAAO,SAAS,MAAM,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE;AAAA,IACtD,aAAa,SAAS,YAAY,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE;AAAA,IAClE,aAAa,SAAS;AAAA,IACtB,gBAAgB,SAAS;AAAA,IACzB,UAAU,SAAS;AAAA,IACnB,MACE,SAAS,MAAM,SAAS,UACpB,SAAS,KAAK,QACd,SAAS,MAAM,SAAS,aACtB,SAAS,KAAK,UAAU,MACxB;AAAA,IACR,OACE,SAAS,OAAO,SAAS,aACrB,SAAS,MAAM,UAAU,MACzB,SAAS,OAAO,SAAS,SACvB,SAAS,MAAM,MAAM,MACrB;AAAA,IACR;AAAA,EACF;AACF;AAKA,eAAsB,OAAO,UAAyB,CAAC,GAA4B;AACjF,QAAM,SAAS,gBAAgB;AAE/B,QAAM,SAAuB,CAAC;AAE9B,MAAI,QAAQ,OAAO;AACjB,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAEA,MAAI,QAAQ,QAAQ;AAElB,UAAM,cAAc,QAAQ,OAAO,UAAU,aAAa,gBAAgB,QAAQ,OAAO;AACzF,WAAO,SAAS,EAAE,OAAO,aAAa,UAAU,QAAQ,OAAO,SAAS;AAAA,EAC1E;AAEA,MAAI,QAAQ,MAAM;AAChB,WAAO,OAAO,QAAQ;AAAA,EACxB;AAEA,MAAI,QAAQ,aAAa;AACvB,WAAO,eAAe,QAAQ;AAAA,EAChC;AAEA,MAAI,QAAQ,UAAU;AACpB,WAAO,YAAY,QAAQ;AAAA,EAC7B;AAEA,QAAM,WAAW,MAAM,OAAO,OAAO,MAAa;AAElD,QAAM,UAA0B,SAAS,QAAQ,IAAI,CAAC,SAAc;AAClE,QAAI,KAAK,WAAW,QAAQ;AAC1B,aAAO,mBAAmB,IAA0B;AAAA,IACtD,OAAO;AACL,aAAO,uBAAuB,IAA8B;AAAA,IAC9D;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA,SAAS,SAAS;AAAA,IAClB,YAAY,SAAS;AAAA,EACvB;AACF;AAKA,eAAsB,YACpB,OACA,UAAyC,CAAC,GACb;AAC7B,QAAM,WAAW,MAAM,OAAO;AAAA,IAC5B,GAAG;AAAA,IACH;AAAA,IACA,QAAQ,EAAE,OAAO,QAAQ,UAAU,SAAS;AAAA,EAC9C,CAAC;AAED,SAAO,SAAS,QAAQ;AAAA,IACtB,CAAC,MAA6B,EAAE,SAAS;AAAA,EAC3C;AACF;AAKA,eAAsB,gBACpB,OACA,UAAyC,CAAC,GACT;AACjC,QAAM,WAAW,MAAM,OAAO;AAAA,IAC5B,GAAG;AAAA,IACH;AAAA,IACA,QAAQ,EAAE,OAAO,YAAY,UAAU,SAAS;AAAA,EAClD,CAAC;AAED,SAAO,SAAS,QAAQ;AAAA,IACtB,CAAC,MAAiC,EAAE,SAAS;AAAA,EAC/C;AACF;AAKA,eAAsB,UACpB,OACA,UAA2D,CAAC,GACnC;AACzB,QAAM,aAA6B,CAAC;AACpC,MAAI;AAEJ,KAAG;AACD,UAAM,WAAW,MAAM,OAAO;AAAA,MAC5B,GAAG;AAAA,MACH;AAAA,MACA,aAAa;AAAA,MACb,UAAU;AAAA,IACZ,CAAC;AACD,eAAW,KAAK,GAAG,SAAS,OAAO;AACnC,aAAS,SAAS,cAAc;AAAA,EAClC,SAAS;AAET,SAAO;AACT;AAKA,eAAsB,gBACpB,OACA,aAAsB,OACY;AAClC,QAAM,QAAQ,MAAM,YAAY,KAAK;AAErC,MAAI,YAAY;AACd,WAAO,MAAM,KAAK,CAAC,MAAM,EAAE,UAAU,KAAK,KAAK;AAAA,EACjD;AAEA,SAAO,MAAM,CAAC,KAAK;AACrB;AAKA,eAAsB,oBACpB,OACA,aAAsB,OACgB;AACtC,QAAM,YAAY,MAAM,gBAAgB,KAAK;AAE7C,MAAI,YAAY;AACd,WAAO,UAAU,KAAK,CAAC,MAAM,EAAE,UAAU,KAAK,KAAK;AAAA,EACrD;AAEA,SAAO,UAAU,CAAC,KAAK;AACzB;AAKA,eAAsB,uBACpB,QAAgB,IACa;AAC7B,QAAM,WAAW,MAAM,OAAO;AAAA,IAC5B,QAAQ,EAAE,OAAO,QAAQ,UAAU,SAAS;AAAA,IAC5C,MAAM,EAAE,WAAW,cAAc,WAAW,mBAAmB;AAAA,IAC/D,UAAU;AAAA,EACZ,CAAC;AAED,SAAO,SAAS,QAAQ;AAAA,IACtB,CAAC,MAA6B,EAAE,SAAS;AAAA,EAC3C;AACF;AAKA,eAAsB,2BACpB,QAAgB,IACiB;AACjC,QAAM,WAAW,MAAM,OAAO;AAAA,IAC5B,QAAQ,EAAE,OAAO,YAAY,UAAU,SAAS;AAAA,IAChD,MAAM,EAAE,WAAW,cAAc,WAAW,mBAAmB;AAAA,IAC/D,UAAU;AAAA,EACZ,CAAC;AAED,SAAO,SAAS,QAAQ;AAAA,IACtB,CAAC,MAAiC,EAAE,SAAS;AAAA,EAC/C;AACF;AAMA,eAAsB,eACpB,OACA,UAII,CAAC,GACoB;AACzB,QAAM,gBAA+B;AAAA,IACnC;AAAA,IACA,UAAU,QAAQ,SAAS;AAAA,EAC7B;AAEA,MAAI,QAAQ,YAAY;AACtB,kBAAc,SAAS,EAAE,OAAO,QAAQ,YAAY,UAAU,SAAS;AAAA,EACzE;AAEA,MAAI,CAAC,QAAQ,iBAAiB;AAC5B,kBAAc,OAAO;AAAA,MACnB,WAAW;AAAA,MACX,WAAW;AAAA,IACb;AAAA,EACF;AAEA,QAAM,WAAW,MAAM,OAAO,aAAa;AAC3C,SAAO,SAAS;AAClB;","names":[]}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__require
|
|
3
|
+
} from "./chunk-UP2VWCW5.js";
|
|
4
|
+
|
|
5
|
+
// src/integrations/documents/pdf-parser.ts
|
|
6
|
+
import * as fs from "fs/promises";
|
|
7
|
+
import * as path from "path";
|
|
8
|
+
var pdf = __require("pdf-parse");
|
|
9
|
+
async function parsePDF(input, options = {}) {
|
|
10
|
+
let buffer;
|
|
11
|
+
if (typeof input === "string") {
|
|
12
|
+
const absolutePath = path.isAbsolute(input) ? input : path.resolve(input);
|
|
13
|
+
buffer = await fs.readFile(absolutePath);
|
|
14
|
+
} else {
|
|
15
|
+
buffer = input;
|
|
16
|
+
}
|
|
17
|
+
const pageTexts = [];
|
|
18
|
+
let currentPage = 0;
|
|
19
|
+
const parseOptions = {
|
|
20
|
+
// Custom page renderer to capture individual page text
|
|
21
|
+
pagerender: (pageData) => {
|
|
22
|
+
return pageData.getTextContent().then((textContent) => {
|
|
23
|
+
currentPage++;
|
|
24
|
+
if (options.pageRange) {
|
|
25
|
+
const [start, end] = options.pageRange;
|
|
26
|
+
if (currentPage < start || currentPage > end) {
|
|
27
|
+
return "";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (options.maxPages && currentPage > options.maxPages) {
|
|
31
|
+
return "";
|
|
32
|
+
}
|
|
33
|
+
const pageText = textContent.items.map((item) => {
|
|
34
|
+
if (item.str) {
|
|
35
|
+
return item.str;
|
|
36
|
+
}
|
|
37
|
+
return "";
|
|
38
|
+
}).join("");
|
|
39
|
+
pageTexts.push(pageText);
|
|
40
|
+
return pageText;
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
if (options.maxPages) {
|
|
45
|
+
parseOptions.max = options.maxPages;
|
|
46
|
+
}
|
|
47
|
+
const result = await pdf(buffer, parseOptions);
|
|
48
|
+
const metadata = {};
|
|
49
|
+
if (result.info) {
|
|
50
|
+
metadata.title = result.info.Title || void 0;
|
|
51
|
+
metadata.author = result.info.Author || void 0;
|
|
52
|
+
metadata.subject = result.info.Subject || void 0;
|
|
53
|
+
metadata.creator = result.info.Creator || void 0;
|
|
54
|
+
metadata.producer = result.info.Producer || void 0;
|
|
55
|
+
if (result.info.CreationDate) {
|
|
56
|
+
metadata.creationDate = parsePDFDate(result.info.CreationDate);
|
|
57
|
+
}
|
|
58
|
+
if (result.info.ModDate) {
|
|
59
|
+
metadata.modificationDate = parsePDFDate(result.info.ModDate);
|
|
60
|
+
}
|
|
61
|
+
if (result.info.Keywords) {
|
|
62
|
+
metadata.keywords = result.info.Keywords.split(/[,;]/).map(
|
|
63
|
+
(k) => k.trim()
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
text: result.text,
|
|
69
|
+
metadata,
|
|
70
|
+
pageCount: result.numpages,
|
|
71
|
+
pages: pageTexts.length > 0 ? pageTexts : [result.text]
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function parsePDFDate(dateStr) {
|
|
75
|
+
if (!dateStr) return void 0;
|
|
76
|
+
const cleanDate = dateStr.replace(/^D:/, "");
|
|
77
|
+
const match = cleanDate.match(
|
|
78
|
+
/^(\d{4})(\d{2})?(\d{2})?(\d{2})?(\d{2})?(\d{2})?([+-Z])?(\d{2})?'?(\d{2})?'?$/
|
|
79
|
+
);
|
|
80
|
+
if (!match) {
|
|
81
|
+
const parsed = new Date(dateStr);
|
|
82
|
+
return isNaN(parsed.getTime()) ? void 0 : parsed;
|
|
83
|
+
}
|
|
84
|
+
const year = parseInt(match[1], 10);
|
|
85
|
+
const month = parseInt(match[2] || "01", 10) - 1;
|
|
86
|
+
const day = parseInt(match[3] || "01", 10);
|
|
87
|
+
const hour = parseInt(match[4] || "00", 10);
|
|
88
|
+
const minute = parseInt(match[5] || "00", 10);
|
|
89
|
+
const second = parseInt(match[6] || "00", 10);
|
|
90
|
+
const date = new Date(year, month, day, hour, minute, second);
|
|
91
|
+
if (match[7] && match[7] !== "Z" && match[8] && match[9]) {
|
|
92
|
+
const tzSign = match[7] === "+" ? -1 : 1;
|
|
93
|
+
const tzHours = parseInt(match[8], 10);
|
|
94
|
+
const tzMinutes = parseInt(match[9], 10);
|
|
95
|
+
date.setMinutes(date.getMinutes() + tzSign * (tzHours * 60 + tzMinutes));
|
|
96
|
+
}
|
|
97
|
+
return date;
|
|
98
|
+
}
|
|
99
|
+
async function extractPDFPages(input, startPage, endPage) {
|
|
100
|
+
const result = await parsePDF(input, {
|
|
101
|
+
pageRange: [startPage, endPage]
|
|
102
|
+
});
|
|
103
|
+
return result.pages;
|
|
104
|
+
}
|
|
105
|
+
async function getPDFMetadata(input) {
|
|
106
|
+
const result = await parsePDF(input, { maxPages: 1 });
|
|
107
|
+
return {
|
|
108
|
+
metadata: result.metadata,
|
|
109
|
+
pageCount: result.pageCount
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
async function isValidPDF(input) {
|
|
113
|
+
try {
|
|
114
|
+
let buffer;
|
|
115
|
+
if (typeof input === "string") {
|
|
116
|
+
const absolutePath = path.isAbsolute(input) ? input : path.resolve(input);
|
|
117
|
+
buffer = await fs.readFile(absolutePath);
|
|
118
|
+
} else {
|
|
119
|
+
buffer = input;
|
|
120
|
+
}
|
|
121
|
+
const header = buffer.slice(0, 5).toString("ascii");
|
|
122
|
+
return header === "%PDF-";
|
|
123
|
+
} catch {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export {
|
|
129
|
+
parsePDF,
|
|
130
|
+
extractPDFPages,
|
|
131
|
+
getPDFMetadata,
|
|
132
|
+
isValidPDF
|
|
133
|
+
};
|
|
134
|
+
//# sourceMappingURL=chunk-XTX7EK43.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/integrations/documents/pdf-parser.ts"],"sourcesContent":["/**\n * PDF Parser for OpenSentinel Document Ingestion\n *\n * Extracts text content from PDF files using pdf-parse.\n */\n\n// pdf-parse doesn't have proper ESM exports, use require\nconst pdf = require(\"pdf-parse\");\nimport * as fs from \"fs/promises\";\nimport * as path from \"path\";\n\nexport interface PDFParseResult {\n text: string;\n metadata: PDFMetadata;\n pageCount: number;\n pages: string[];\n}\n\nexport interface PDFMetadata {\n title?: string;\n author?: string;\n subject?: string;\n creator?: string;\n producer?: string;\n creationDate?: Date;\n modificationDate?: Date;\n keywords?: string[];\n}\n\nexport interface PDFParseOptions {\n /** Maximum number of pages to parse (0 = all) */\n maxPages?: number;\n /** Page range to parse (e.g., [1, 5] for pages 1-5) */\n pageRange?: [number, number];\n}\n\n/**\n * Parse a PDF file and extract its text content\n */\nexport async function parsePDF(\n input: string | Buffer,\n options: PDFParseOptions = {}\n): Promise<PDFParseResult> {\n let buffer: Buffer;\n\n if (typeof input === \"string\") {\n // Input is a file path\n const absolutePath = path.isAbsolute(input) ? input : path.resolve(input);\n buffer = await fs.readFile(absolutePath);\n } else {\n buffer = input;\n }\n\n const pageTexts: string[] = [];\n let currentPage = 0;\n\n const parseOptions: any = {\n // Custom page renderer to capture individual page text\n pagerender: (pageData: any) => {\n return pageData.getTextContent().then((textContent: any) => {\n currentPage++;\n\n // Apply page range filter\n if (options.pageRange) {\n const [start, end] = options.pageRange;\n if (currentPage < start || currentPage > end) {\n return \"\";\n }\n }\n\n // Apply max pages filter\n if (options.maxPages && currentPage > options.maxPages) {\n return \"\";\n }\n\n // Extract text from page\n const pageText = textContent.items\n .map((item: any) => {\n if (item.str) {\n return item.str;\n }\n return \"\";\n })\n .join(\"\");\n\n pageTexts.push(pageText);\n return pageText;\n });\n },\n };\n\n // Apply max pages limit\n if (options.maxPages) {\n parseOptions.max = options.maxPages;\n }\n\n const result = await pdf(buffer, parseOptions);\n\n // Extract metadata\n const metadata: PDFMetadata = {};\n\n if (result.info) {\n metadata.title = result.info.Title || undefined;\n metadata.author = result.info.Author || undefined;\n metadata.subject = result.info.Subject || undefined;\n metadata.creator = result.info.Creator || undefined;\n metadata.producer = result.info.Producer || undefined;\n\n if (result.info.CreationDate) {\n metadata.creationDate = parsePDFDate(result.info.CreationDate);\n }\n if (result.info.ModDate) {\n metadata.modificationDate = parsePDFDate(result.info.ModDate);\n }\n if (result.info.Keywords) {\n metadata.keywords = result.info.Keywords.split(/[,;]/).map((k: string) =>\n k.trim()\n );\n }\n }\n\n return {\n text: result.text,\n metadata,\n pageCount: result.numpages,\n pages: pageTexts.length > 0 ? pageTexts : [result.text],\n };\n}\n\n/**\n * Parse PDF date string to Date object\n * PDF dates are in format: D:YYYYMMDDHHmmSS+HH'mm'\n */\nfunction parsePDFDate(dateStr: string): Date | undefined {\n if (!dateStr) return undefined;\n\n // Remove 'D:' prefix if present\n const cleanDate = dateStr.replace(/^D:/, \"\");\n\n // Extract components using regex\n const match = cleanDate.match(\n /^(\\d{4})(\\d{2})?(\\d{2})?(\\d{2})?(\\d{2})?(\\d{2})?([+-Z])?(\\d{2})?'?(\\d{2})?'?$/\n );\n\n if (!match) {\n // Try parsing as ISO date\n const parsed = new Date(dateStr);\n return isNaN(parsed.getTime()) ? undefined : parsed;\n }\n\n const year = parseInt(match[1], 10);\n const month = parseInt(match[2] || \"01\", 10) - 1;\n const day = parseInt(match[3] || \"01\", 10);\n const hour = parseInt(match[4] || \"00\", 10);\n const minute = parseInt(match[5] || \"00\", 10);\n const second = parseInt(match[6] || \"00\", 10);\n\n const date = new Date(year, month, day, hour, minute, second);\n\n // Handle timezone offset\n if (match[7] && match[7] !== \"Z\" && match[8] && match[9]) {\n const tzSign = match[7] === \"+\" ? -1 : 1;\n const tzHours = parseInt(match[8], 10);\n const tzMinutes = parseInt(match[9], 10);\n date.setMinutes(date.getMinutes() + tzSign * (tzHours * 60 + tzMinutes));\n }\n\n return date;\n}\n\n/**\n * Extract text from specific pages of a PDF\n */\nexport async function extractPDFPages(\n input: string | Buffer,\n startPage: number,\n endPage: number\n): Promise<string[]> {\n const result = await parsePDF(input, {\n pageRange: [startPage, endPage],\n });\n return result.pages;\n}\n\n/**\n * Get PDF metadata without extracting full text\n */\nexport async function getPDFMetadata(\n input: string | Buffer\n): Promise<{ metadata: PDFMetadata; pageCount: number }> {\n const result = await parsePDF(input, { maxPages: 1 });\n return {\n metadata: result.metadata,\n pageCount: result.pageCount,\n };\n}\n\n/**\n * Check if a file is a valid PDF\n */\nexport async function isValidPDF(input: string | Buffer): Promise<boolean> {\n try {\n let buffer: Buffer;\n\n if (typeof input === \"string\") {\n const absolutePath = path.isAbsolute(input) ? input : path.resolve(input);\n buffer = await fs.readFile(absolutePath);\n } else {\n buffer = input;\n }\n\n // Check PDF magic number\n const header = buffer.slice(0, 5).toString(\"ascii\");\n return header === \"%PDF-\";\n } catch {\n return false;\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import {
|
|
2
|
+
db
|
|
3
|
+
} from "./chunk-5BTVJR7R.js";
|
|
4
|
+
import {
|
|
5
|
+
metrics
|
|
6
|
+
} from "./chunk-ZIBRVA3Y.js";
|
|
7
|
+
|
|
8
|
+
// src/core/observability/metrics.ts
|
|
9
|
+
import { eq, and, gte, lte, desc } from "drizzle-orm";
|
|
10
|
+
var metricBuffer = [];
|
|
11
|
+
var flushTimer = null;
|
|
12
|
+
var FLUSH_INTERVAL = 5e3;
|
|
13
|
+
var MAX_BUFFER_SIZE = 100;
|
|
14
|
+
async function recordMetric(entry) {
|
|
15
|
+
metricBuffer.push(entry);
|
|
16
|
+
if (metricBuffer.length >= MAX_BUFFER_SIZE) {
|
|
17
|
+
await flushMetrics();
|
|
18
|
+
} else if (!flushTimer) {
|
|
19
|
+
flushTimer = setTimeout(flushMetrics, FLUSH_INTERVAL);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
async function flushMetrics() {
|
|
23
|
+
if (flushTimer) {
|
|
24
|
+
clearTimeout(flushTimer);
|
|
25
|
+
flushTimer = null;
|
|
26
|
+
}
|
|
27
|
+
if (metricBuffer.length === 0) return;
|
|
28
|
+
const toInsert = metricBuffer;
|
|
29
|
+
metricBuffer = [];
|
|
30
|
+
try {
|
|
31
|
+
await db.insert(metrics).values(
|
|
32
|
+
toInsert.map((m) => ({
|
|
33
|
+
name: m.name,
|
|
34
|
+
value: m.value,
|
|
35
|
+
unit: m.unit,
|
|
36
|
+
tags: m.tags
|
|
37
|
+
}))
|
|
38
|
+
);
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error("[Metrics] Failed to flush metrics:", error);
|
|
41
|
+
metricBuffer = [...toInsert, ...metricBuffer].slice(0, MAX_BUFFER_SIZE * 2);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
var metric = {
|
|
45
|
+
latency: (value, tags) => recordMetric({ name: "response_latency", value, unit: "ms", tags }),
|
|
46
|
+
tokens: (input, output, tags) => {
|
|
47
|
+
recordMetric({ name: "token_usage_input", value: input, unit: "tokens", tags });
|
|
48
|
+
recordMetric({ name: "token_usage_output", value: output, unit: "tokens", tags });
|
|
49
|
+
},
|
|
50
|
+
toolDuration: (toolName, durationMs, success) => {
|
|
51
|
+
recordMetric({
|
|
52
|
+
name: "tool_duration",
|
|
53
|
+
value: durationMs,
|
|
54
|
+
unit: "ms",
|
|
55
|
+
tags: { tool: toolName }
|
|
56
|
+
});
|
|
57
|
+
recordMetric({
|
|
58
|
+
name: success ? "tool_success" : "tool_failure",
|
|
59
|
+
value: 1,
|
|
60
|
+
unit: "count",
|
|
61
|
+
tags: { tool: toolName }
|
|
62
|
+
});
|
|
63
|
+
},
|
|
64
|
+
apiRequest: (endpoint, statusCode) => recordMetric({
|
|
65
|
+
name: "api_request",
|
|
66
|
+
value: 1,
|
|
67
|
+
unit: "count",
|
|
68
|
+
tags: { endpoint, status: String(statusCode) }
|
|
69
|
+
}),
|
|
70
|
+
telegramMessage: () => recordMetric({ name: "telegram_message", value: 1, unit: "count" }),
|
|
71
|
+
memoryOperation: (operation, durationMs) => recordMetric({
|
|
72
|
+
name: operation === "search" ? "memory_search" : "memory_store",
|
|
73
|
+
value: durationMs,
|
|
74
|
+
unit: "ms"
|
|
75
|
+
}),
|
|
76
|
+
agentOperation: (operation, agentType) => recordMetric({
|
|
77
|
+
name: operation === "spawn" ? "agent_spawn" : "agent_complete",
|
|
78
|
+
value: 1,
|
|
79
|
+
unit: "count",
|
|
80
|
+
tags: { type: agentType }
|
|
81
|
+
}),
|
|
82
|
+
pluginOperation: (operation, pluginId) => recordMetric({
|
|
83
|
+
name: `plugin_${operation}`,
|
|
84
|
+
value: 1,
|
|
85
|
+
unit: "count",
|
|
86
|
+
tags: { plugin: pluginId }
|
|
87
|
+
}),
|
|
88
|
+
error: (source) => recordMetric({
|
|
89
|
+
name: "error_count",
|
|
90
|
+
value: 1,
|
|
91
|
+
unit: "count",
|
|
92
|
+
tags: { source }
|
|
93
|
+
})
|
|
94
|
+
};
|
|
95
|
+
async function queryMetrics(query = {}) {
|
|
96
|
+
const { name, startDate, endDate } = query;
|
|
97
|
+
let conditions = [];
|
|
98
|
+
if (name) {
|
|
99
|
+
conditions.push(eq(metrics.name, name));
|
|
100
|
+
}
|
|
101
|
+
if (startDate) {
|
|
102
|
+
conditions.push(gte(metrics.timestamp, startDate));
|
|
103
|
+
}
|
|
104
|
+
if (endDate) {
|
|
105
|
+
conditions.push(lte(metrics.timestamp, endDate));
|
|
106
|
+
}
|
|
107
|
+
let q = db.select().from(metrics);
|
|
108
|
+
if (conditions.length > 0) {
|
|
109
|
+
q = q.where(and(...conditions));
|
|
110
|
+
}
|
|
111
|
+
return q.orderBy(desc(metrics.timestamp)).limit(1e3);
|
|
112
|
+
}
|
|
113
|
+
async function getMetricAggregates(name, startDate, endDate) {
|
|
114
|
+
const results = await db.select().from(metrics).where(
|
|
115
|
+
and(
|
|
116
|
+
eq(metrics.name, name),
|
|
117
|
+
gte(metrics.timestamp, startDate),
|
|
118
|
+
lte(metrics.timestamp, endDate)
|
|
119
|
+
)
|
|
120
|
+
).orderBy(metrics.value);
|
|
121
|
+
if (results.length === 0) {
|
|
122
|
+
return {
|
|
123
|
+
name,
|
|
124
|
+
count: 0,
|
|
125
|
+
sum: 0,
|
|
126
|
+
avg: 0,
|
|
127
|
+
min: 0,
|
|
128
|
+
max: 0
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
const values = results.map((r) => r.value);
|
|
132
|
+
const sum = values.reduce((a, b) => a + b, 0);
|
|
133
|
+
return {
|
|
134
|
+
name,
|
|
135
|
+
count: values.length,
|
|
136
|
+
sum,
|
|
137
|
+
avg: sum / values.length,
|
|
138
|
+
min: values[0],
|
|
139
|
+
max: values[values.length - 1],
|
|
140
|
+
p50: values[Math.floor(values.length * 0.5)],
|
|
141
|
+
p95: values[Math.floor(values.length * 0.95)],
|
|
142
|
+
p99: values[Math.floor(values.length * 0.99)]
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
async function getMetricTimeSeries(name, startDate, endDate, bucketMinutes = 60) {
|
|
146
|
+
const results = await db.select().from(metrics).where(
|
|
147
|
+
and(
|
|
148
|
+
eq(metrics.name, name),
|
|
149
|
+
gte(metrics.timestamp, startDate),
|
|
150
|
+
lte(metrics.timestamp, endDate)
|
|
151
|
+
)
|
|
152
|
+
).orderBy(metrics.timestamp);
|
|
153
|
+
const bucketMs = bucketMinutes * 60 * 1e3;
|
|
154
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
155
|
+
for (const result of results) {
|
|
156
|
+
const bucketTime = Math.floor(result.timestamp.getTime() / bucketMs) * bucketMs;
|
|
157
|
+
if (!buckets.has(bucketTime)) {
|
|
158
|
+
buckets.set(bucketTime, []);
|
|
159
|
+
}
|
|
160
|
+
buckets.get(bucketTime).push(result.value);
|
|
161
|
+
}
|
|
162
|
+
return Array.from(buckets.entries()).map(([time, values]) => ({
|
|
163
|
+
bucket: new Date(time),
|
|
164
|
+
count: values.length,
|
|
165
|
+
avg: values.reduce((a, b) => a + b, 0) / values.length
|
|
166
|
+
})).sort((a, b) => a.bucket.getTime() - b.bucket.getTime());
|
|
167
|
+
}
|
|
168
|
+
function getSystemMetrics() {
|
|
169
|
+
return {
|
|
170
|
+
memoryUsage: process.memoryUsage(),
|
|
171
|
+
uptime: process.uptime(),
|
|
172
|
+
platform: process.platform
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
async function cleanupOldMetrics(daysToKeep = 30) {
|
|
176
|
+
const cutoff = new Date(Date.now() - daysToKeep * 24 * 60 * 60 * 1e3);
|
|
177
|
+
await db.delete(metrics).where(lte(metrics.timestamp, cutoff));
|
|
178
|
+
return 0;
|
|
179
|
+
}
|
|
180
|
+
process.on("beforeExit", async () => {
|
|
181
|
+
await flushMetrics();
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
export {
|
|
185
|
+
recordMetric,
|
|
186
|
+
flushMetrics,
|
|
187
|
+
metric,
|
|
188
|
+
queryMetrics,
|
|
189
|
+
getMetricAggregates,
|
|
190
|
+
getMetricTimeSeries,
|
|
191
|
+
getSystemMetrics,
|
|
192
|
+
cleanupOldMetrics
|
|
193
|
+
};
|
|
194
|
+
//# sourceMappingURL=chunk-YEDEAX6Y.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/observability/metrics.ts"],"sourcesContent":["import { db } from \"../../db\";\nimport { metrics, NewMetric } from \"../../db/schema\";\nimport { eq, and, gte, lte, desc, sql } from \"drizzle-orm\";\n\nexport type MetricName =\n | \"response_latency\"\n | \"token_usage_input\"\n | \"token_usage_output\"\n | \"tool_duration\"\n | \"tool_success\"\n | \"tool_failure\"\n | \"api_request\"\n | \"telegram_message\"\n | \"memory_search\"\n | \"memory_store\"\n | \"agent_spawn\"\n | \"agent_complete\"\n | \"plugin_enable\"\n | \"plugin_disable\"\n | \"plugin_load\"\n | \"plugin_unload\"\n | \"plugin_tool_execute\"\n | \"error_count\";\n\nexport type MetricUnit = \"ms\" | \"tokens\" | \"count\" | \"bytes\" | \"percent\";\n\nexport interface MetricEntry {\n name: MetricName;\n value: number;\n unit?: MetricUnit;\n tags?: Record<string, string>;\n}\n\n// In-memory buffer for batching metrics\nlet metricBuffer: MetricEntry[] = [];\nlet flushTimer: Timer | null = null;\nconst FLUSH_INTERVAL = 5000; // 5 seconds\nconst MAX_BUFFER_SIZE = 100;\n\nexport async function recordMetric(entry: MetricEntry): Promise<void> {\n metricBuffer.push(entry);\n\n // Flush if buffer is full\n if (metricBuffer.length >= MAX_BUFFER_SIZE) {\n await flushMetrics();\n } else if (!flushTimer) {\n // Start flush timer\n flushTimer = setTimeout(flushMetrics, FLUSH_INTERVAL);\n }\n}\n\nexport async function flushMetrics(): Promise<void> {\n if (flushTimer) {\n clearTimeout(flushTimer);\n flushTimer = null;\n }\n\n if (metricBuffer.length === 0) return;\n\n const toInsert = metricBuffer;\n metricBuffer = [];\n\n try {\n await db.insert(metrics).values(\n toInsert.map((m) => ({\n name: m.name,\n value: m.value,\n unit: m.unit,\n tags: m.tags,\n }))\n );\n } catch (error) {\n console.error(\"[Metrics] Failed to flush metrics:\", error);\n // Put metrics back in buffer for retry\n metricBuffer = [...toInsert, ...metricBuffer].slice(0, MAX_BUFFER_SIZE * 2);\n }\n}\n\n// Convenience functions\nexport const metric = {\n latency: (value: number, tags?: Record<string, string>) =>\n recordMetric({ name: \"response_latency\", value, unit: \"ms\", tags }),\n\n tokens: (input: number, output: number, tags?: Record<string, string>) => {\n recordMetric({ name: \"token_usage_input\", value: input, unit: \"tokens\", tags });\n recordMetric({ name: \"token_usage_output\", value: output, unit: \"tokens\", tags });\n },\n\n toolDuration: (toolName: string, durationMs: number, success: boolean) => {\n recordMetric({\n name: \"tool_duration\",\n value: durationMs,\n unit: \"ms\",\n tags: { tool: toolName },\n });\n recordMetric({\n name: success ? \"tool_success\" : \"tool_failure\",\n value: 1,\n unit: \"count\",\n tags: { tool: toolName },\n });\n },\n\n apiRequest: (endpoint: string, statusCode: number) =>\n recordMetric({\n name: \"api_request\",\n value: 1,\n unit: \"count\",\n tags: { endpoint, status: String(statusCode) },\n }),\n\n telegramMessage: () =>\n recordMetric({ name: \"telegram_message\", value: 1, unit: \"count\" }),\n\n memoryOperation: (operation: \"search\" | \"store\", durationMs: number) =>\n recordMetric({\n name: operation === \"search\" ? \"memory_search\" : \"memory_store\",\n value: durationMs,\n unit: \"ms\",\n }),\n\n agentOperation: (operation: \"spawn\" | \"complete\", agentType: string) =>\n recordMetric({\n name: operation === \"spawn\" ? \"agent_spawn\" : \"agent_complete\",\n value: 1,\n unit: \"count\",\n tags: { type: agentType },\n }),\n\n pluginOperation: (operation: \"enable\" | \"disable\" | \"load\" | \"unload\" | \"tool_execute\", pluginId: string) =>\n recordMetric({\n name: `plugin_${operation}` as MetricName,\n value: 1,\n unit: \"count\",\n tags: { plugin: pluginId },\n }),\n\n error: (source: string) =>\n recordMetric({\n name: \"error_count\",\n value: 1,\n unit: \"count\",\n tags: { source },\n }),\n};\n\n// Query functions\nexport interface MetricQuery {\n name?: MetricName;\n startDate?: Date;\n endDate?: Date;\n tags?: Record<string, string>;\n}\n\nexport async function queryMetrics(query: MetricQuery = {}) {\n const { name, startDate, endDate } = query;\n\n let conditions = [];\n\n if (name) {\n conditions.push(eq(metrics.name, name));\n }\n\n if (startDate) {\n conditions.push(gte(metrics.timestamp, startDate));\n }\n\n if (endDate) {\n conditions.push(lte(metrics.timestamp, endDate));\n }\n\n let q = db.select().from(metrics);\n\n if (conditions.length > 0) {\n q = q.where(and(...conditions)) as typeof q;\n }\n\n return q.orderBy(desc(metrics.timestamp)).limit(1000);\n}\n\nexport interface AggregatedMetric {\n name: string;\n count: number;\n sum: number;\n avg: number;\n min: number;\n max: number;\n p50?: number;\n p95?: number;\n p99?: number;\n}\n\nexport async function getMetricAggregates(\n name: MetricName,\n startDate: Date,\n endDate: Date\n): Promise<AggregatedMetric> {\n const results = await db\n .select()\n .from(metrics)\n .where(\n and(\n eq(metrics.name, name),\n gte(metrics.timestamp, startDate),\n lte(metrics.timestamp, endDate)\n )\n )\n .orderBy(metrics.value);\n\n if (results.length === 0) {\n return {\n name,\n count: 0,\n sum: 0,\n avg: 0,\n min: 0,\n max: 0,\n };\n }\n\n const values = results.map((r) => r.value);\n const sum = values.reduce((a, b) => a + b, 0);\n\n return {\n name,\n count: values.length,\n sum,\n avg: sum / values.length,\n min: values[0],\n max: values[values.length - 1],\n p50: values[Math.floor(values.length * 0.5)],\n p95: values[Math.floor(values.length * 0.95)],\n p99: values[Math.floor(values.length * 0.99)],\n };\n}\n\nexport async function getMetricTimeSeries(\n name: MetricName,\n startDate: Date,\n endDate: Date,\n bucketMinutes: number = 60\n): Promise<Array<{ bucket: Date; count: number; avg: number }>> {\n const results = await db\n .select()\n .from(metrics)\n .where(\n and(\n eq(metrics.name, name),\n gte(metrics.timestamp, startDate),\n lte(metrics.timestamp, endDate)\n )\n )\n .orderBy(metrics.timestamp);\n\n // Group into time buckets\n const bucketMs = bucketMinutes * 60 * 1000;\n const buckets = new Map<number, number[]>();\n\n for (const result of results) {\n const bucketTime = Math.floor(result.timestamp.getTime() / bucketMs) * bucketMs;\n if (!buckets.has(bucketTime)) {\n buckets.set(bucketTime, []);\n }\n buckets.get(bucketTime)!.push(result.value);\n }\n\n return Array.from(buckets.entries())\n .map(([time, values]) => ({\n bucket: new Date(time),\n count: values.length,\n avg: values.reduce((a, b) => a + b, 0) / values.length,\n }))\n .sort((a, b) => a.bucket.getTime() - b.bucket.getTime());\n}\n\n// System status metrics\nexport function getSystemMetrics(): {\n memoryUsage: NodeJS.MemoryUsage;\n uptime: number;\n platform: string;\n} {\n return {\n memoryUsage: process.memoryUsage(),\n uptime: process.uptime(),\n platform: process.platform,\n };\n}\n\n// Cleanup old metrics\nexport async function cleanupOldMetrics(daysToKeep: number = 30): Promise<number> {\n const cutoff = new Date(Date.now() - daysToKeep * 24 * 60 * 60 * 1000);\n await db.delete(metrics).where(lte(metrics.timestamp, cutoff));\n return 0; // Cleanup completed\n}\n\n// Ensure metrics are flushed on shutdown\nprocess.on(\"beforeExit\", async () => {\n await flushMetrics();\n});\n"],"mappings":"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","names":[]}
|