openfda-mcp-server 1.0.0 → 1.2.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.
Files changed (40) hide show
  1. package/README.md +110 -19
  2. package/dist/defineProperty-BEGP2H1W.js +1 -0
  3. package/dist/handlers/bulk-data-handlers.d.ts +108 -0
  4. package/dist/handlers/bulk-data-handlers.js +2 -0
  5. package/dist/handlers/bulk-data-handlers.js.map +1 -0
  6. package/dist/handlers/device-handlers.d.ts +1 -1
  7. package/dist/handlers/device-handlers.js +2 -1
  8. package/dist/handlers/device-handlers.js.map +1 -0
  9. package/dist/handlers/drug-handlers.d.ts +16 -1
  10. package/dist/handlers/drug-handlers.js +2 -1
  11. package/dist/handlers/drug-handlers.js.map +1 -0
  12. package/dist/index.js +1 -1
  13. package/dist/index.js.map +1 -1
  14. package/dist/lib.d.ts +4 -2
  15. package/dist/lib.js +1 -1
  16. package/dist/server.d.ts +1 -2
  17. package/dist/server.js +1 -1
  18. package/dist/server.js.map +1 -1
  19. package/dist/tools/index.d.ts +215 -360
  20. package/dist/tools/index.js +2 -1
  21. package/dist/tools/index.js.map +1 -0
  22. package/dist/types/fda.d.ts +59 -1
  23. package/dist/utils/api-client.d.ts +0 -1
  24. package/dist/utils/api-client.js +2 -1
  25. package/dist/utils/api-client.js.map +1 -0
  26. package/dist/utils/bulk-data-client.d.ts +24 -0
  27. package/dist/utils/bulk-data-client.js +4 -0
  28. package/dist/utils/bulk-data-client.js.map +1 -0
  29. package/dist/utils/logger.d.ts +1 -1
  30. package/dist/utils/logger.js +1 -1
  31. package/dist/utils/logger.js.map +1 -1
  32. package/package.json +29 -25
  33. package/dist/api-client-BGnUXMwX.js +0 -2
  34. package/dist/api-client-BGnUXMwX.js.map +0 -1
  35. package/dist/device-handlers-D01LfIJk.js +0 -2
  36. package/dist/device-handlers-D01LfIJk.js.map +0 -1
  37. package/dist/drug-handlers-Fz_6NLl5.js +0 -2
  38. package/dist/drug-handlers-Fz_6NLl5.js.map +0 -1
  39. package/dist/tools-Bh3wjIRH.js +0 -2
  40. package/dist/tools-Bh3wjIRH.js.map +0 -1
@@ -1 +1,2 @@
1
- import{a as e,c as t,d as n,i as r,l as i,n as a,o,r as s,s as c,t as l,u}from"../tools-Bh3wjIRH.js";export{l as searchDevice510KSchema,a as searchDeviceAdverseEventsSchema,s as searchDeviceClassificationsSchema,r as searchDeviceEnforcementSchema,e as searchDrugAdverseEventsSchema,o as searchDrugEnforcementSchema,c as searchDrugLabelsSchema,t as searchDrugNDCSchema,i as searchDrugShortagesSchema,u as searchDrugsFDASchema,n as toolSchemas};
1
+ import{z as e}from"zod";const t={limit:e.number().int().min(1).max(100).optional().describe(`Maximum results to return (1-100, default 10)`),skip:e.number().int().min(0).optional().describe(`Number of results to skip for pagination`)},n={dateFrom:e.string().optional().describe(`Start date (YYYY-MM-DD or YYYYMMDD format)`),dateTo:e.string().optional().describe(`End date (YYYY-MM-DD or YYYYMMDD format)`)},r=e.object({safetyReportId:e.string().optional().describe(`Unique safety report ID for retrieving a specific adverse event report`),drugName:e.string().optional().describe(`Drug or product name to search`),reaction:e.string().optional().describe(`Adverse reaction to search (e.g., 'headache', 'nausea')`),manufacturer:e.string().optional().describe(`Drug manufacturer name`),serious:e.boolean().optional().describe(`Filter for serious adverse events only`),...n,...t}),i=[`indications_and_usage`,`dosage_and_administration`,`contraindications`,`warnings`,`warnings_and_cautions`,`adverse_reactions`,`drug_interactions`,`clinical_pharmacology`,`mechanism_of_action`,`pharmacokinetics`,`overdosage`,`description`,`how_supplied`,`storage_and_handling`,`boxed_warning`],a=e.object({setId:e.string().optional().describe(`Unique label identifier (set_id) for retrieving a specific drug label`),drugName:e.string().optional().describe(`Drug brand or generic name`),indication:e.string().optional().describe(`Medical indication or use case`),activeIngredient:e.string().optional().describe(`Active ingredient/substance name`),route:e.string().optional().describe(`Route of administration (e.g., 'oral', 'intravenous')`),hasBoxedWarning:e.boolean().optional().describe(`Filter for drugs with boxed warnings (most serious safety warnings)`),sections:e.array(e.enum(i)).optional().describe(`Specific label sections to return (e.g., ['indications_and_usage', 'warnings', 'adverse_reactions'])`),...t}),o=e.object({productNdc:e.string().optional().describe(`National Drug Code (NDC)`),brandName:e.string().optional().describe(`Drug brand name`),genericName:e.string().optional().describe(`Drug generic name`),labelerName:e.string().optional().describe(`Drug labeler/manufacturer name`),dosageForm:e.string().optional().describe(`Dosage form (e.g., 'tablet', 'capsule', 'injection')`),route:e.string().optional().describe(`Route of administration`),...t}),s=e.object({recallingFirm:e.string().optional().describe(`Name of the recalling company`),classification:e.enum([`Class I`,`Class II`,`Class III`]).optional().describe(`Recall classification (I=most serious, III=least)`),status:e.enum([`Ongoing`,`Completed`,`Terminated`,`Pending`]).optional().describe(`Recall status`),state:e.string().optional().describe(`US state code (e.g., 'CA', 'NY')`),...n,...t}),c=e.object({sponsorName:e.string().optional().describe(`Drug sponsor/company name`),applicationNumber:e.string().optional().describe(`FDA application number (e.g., 'NDA012345')`),brandName:e.string().optional().describe(`Drug brand name`),marketingStatus:e.string().optional().describe(`Marketing status (e.g., 'Prescription', 'OTC')`),...t}),l=e.object({genericName:e.string().optional().describe(`Generic drug name`),status:e.enum([`Current`,`Resolved`]).optional().describe(`Shortage status`),...t}),u=e.object({deviceName:e.string().optional().describe(`Device name to search`),applicant:e.string().optional().describe(`Applicant/company name`),productCode:e.string().optional().describe(`FDA product code`),clearanceType:e.string().optional().describe(`Clearance type (e.g., 'Traditional', 'Special')`),decisionDateFrom:e.string().optional().describe(`Decision date range start (YYYY-MM-DD)`),decisionDateTo:e.string().optional().describe(`Decision date range end (YYYY-MM-DD)`),...t}),d=e.object({deviceName:e.string().optional().describe(`Device name to search`),deviceClass:e.enum([`1`,`2`,`3`]).optional().describe(`Device class (1=lowest risk, 3=highest)`),medicalSpecialty:e.string().optional().describe(`Medical specialty code`),productCode:e.string().optional().describe(`FDA product code`),regulationNumber:e.string().optional().describe(`CFR regulation number`),...t}),f=e.object({reportNumber:e.string().optional().describe(`MDR report number for retrieving a specific device adverse event report`),deviceName:e.string().optional().describe(`Device generic name`),brandName:e.string().optional().describe(`Device brand name`),manufacturerName:e.string().optional().describe(`Device manufacturer name`),eventType:e.enum([`Injury`,`Malfunction`,`Death`,`Other`]).optional().describe(`Type of adverse event`),...n,...t}),p=e.object({recallingFirm:e.string().optional().describe(`Name of the recalling company`),productDescription:e.string().optional().describe(`Product description keywords`),classification:e.enum([`Class I`,`Class II`,`Class III`]).optional().describe(`Recall classification (I=most serious)`),status:e.enum([`Ongoing`,`Completed`,`Terminated`,`Pending`]).optional().describe(`Recall status`),...n,...t}),m=e.object({drugName:e.string().optional().describe(`Drug trade name or ingredient to search`),applicant:e.string().optional().describe(`Applicant/company name`),applNo:e.string().optional().describe(`FDA application number`),teCode:e.string().optional().describe(`Therapeutic equivalence code (e.g., 'AB', 'BX')`),...t}),h=e.object({drugName:e.string().optional().describe(`Drug trade name or ingredient to search`),applNo:e.string().optional().describe(`FDA application number`),patentNo:e.string().optional().describe(`Patent number`),...t}),g=e.object({productName:e.string().optional().describe(`Product proprietary or proper name to search`),applicant:e.string().optional().describe(`Applicant/company name`),blaNumber:e.string().optional().describe(`Biologics License Application (BLA) number`),licenseType:e.enum([`351(a)`,`351(k)`]).optional().describe(`License type: 351(a) for originator, 351(k) for biosimilar`),biosimilar:e.boolean().optional().describe(`Filter for biosimilar products`),interchangeable:e.boolean().optional().describe(`Filter for interchangeable products`),...t}),_=e.object({drugName:e.string().optional().describe(`Drug trade name or ingredient to search`),applNo:e.string().optional().describe(`FDA application number`),includeExclusivity:e.boolean().optional().default(!0).describe(`Include exclusivity data (default: true)`),includePurpleBook:e.boolean().optional().default(!1).describe(`Include Purple Book biologics data (default: false)`),...t}),v={searchDrugAdverseEvents:r,searchDrugLabels:a,searchDrugNDC:o,searchDrugEnforcement:s,searchDrugsFDA:c,searchDrugShortages:l,searchDevice510K:u,searchDeviceClassifications:d,searchDeviceAdverseEvents:f,searchDeviceEnforcement:p,searchOrangeBook:m,searchOrangeBookPatents:h,searchPurpleBook:g,searchDrugPatentExpiry:_};export{i as labelSections,u as searchDevice510KSchema,f as searchDeviceAdverseEventsSchema,d as searchDeviceClassificationsSchema,p as searchDeviceEnforcementSchema,r as searchDrugAdverseEventsSchema,s as searchDrugEnforcementSchema,a as searchDrugLabelsSchema,o as searchDrugNDCSchema,_ as searchDrugPatentExpirySchema,l as searchDrugShortagesSchema,c as searchDrugsFDASchema,h as searchOrangeBookPatentsSchema,m as searchOrangeBookSchema,g as searchPurpleBookSchema,v as toolSchemas};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/tools/index.ts"],"sourcesContent":["/**\n * MCP Tool Definitions\n * Zod schemas for all FDA MCP tools\n */\n\nimport { z } from \"zod\"\n\n// Common pagination schema\nconst paginationSchema = {\n limit: z.number().int().min(1).max(100).optional().describe(\"Maximum results to return (1-100, default 10)\"),\n skip: z.number().int().min(0).optional().describe(\"Number of results to skip for pagination\"),\n}\n\n// Date range schema\nconst dateRangeSchema = {\n dateFrom: z.string().optional().describe(\"Start date (YYYY-MM-DD or YYYYMMDD format)\"),\n dateTo: z.string().optional().describe(\"End date (YYYY-MM-DD or YYYYMMDD format)\"),\n}\n\n// Drug Tool Schemas\n\nexport const searchDrugAdverseEventsSchema = z.object({\n safetyReportId: z\n .string()\n .optional()\n .describe(\"Unique safety report ID for retrieving a specific adverse event report\"),\n drugName: z.string().optional().describe(\"Drug or product name to search\"),\n reaction: z.string().optional().describe(\"Adverse reaction to search (e.g., 'headache', 'nausea')\"),\n manufacturer: z.string().optional().describe(\"Drug manufacturer name\"),\n serious: z.boolean().optional().describe(\"Filter for serious adverse events only\"),\n ...dateRangeSchema,\n ...paginationSchema,\n})\n\n// Available label sections for filtering\nexport const labelSections = [\n \"indications_and_usage\",\n \"dosage_and_administration\",\n \"contraindications\",\n \"warnings\",\n \"warnings_and_cautions\",\n \"adverse_reactions\",\n \"drug_interactions\",\n \"clinical_pharmacology\",\n \"mechanism_of_action\",\n \"pharmacokinetics\",\n \"overdosage\",\n \"description\",\n \"how_supplied\",\n \"storage_and_handling\",\n \"boxed_warning\",\n] as const\n\nexport const searchDrugLabelsSchema = z.object({\n setId: z.string().optional().describe(\"Unique label identifier (set_id) for retrieving a specific drug label\"),\n drugName: z.string().optional().describe(\"Drug brand or generic name\"),\n indication: z.string().optional().describe(\"Medical indication or use case\"),\n activeIngredient: z.string().optional().describe(\"Active ingredient/substance name\"),\n route: z.string().optional().describe(\"Route of administration (e.g., 'oral', 'intravenous')\"),\n hasBoxedWarning: z\n .boolean()\n .optional()\n .describe(\"Filter for drugs with boxed warnings (most serious safety warnings)\"),\n sections: z\n .array(z.enum(labelSections))\n .optional()\n .describe(\"Specific label sections to return (e.g., ['indications_and_usage', 'warnings', 'adverse_reactions'])\"),\n ...paginationSchema,\n})\n\nexport const searchDrugNDCSchema = z.object({\n productNdc: z.string().optional().describe(\"National Drug Code (NDC)\"),\n brandName: z.string().optional().describe(\"Drug brand name\"),\n genericName: z.string().optional().describe(\"Drug generic name\"),\n labelerName: z.string().optional().describe(\"Drug labeler/manufacturer name\"),\n dosageForm: z.string().optional().describe(\"Dosage form (e.g., 'tablet', 'capsule', 'injection')\"),\n route: z.string().optional().describe(\"Route of administration\"),\n ...paginationSchema,\n})\n\nexport const searchDrugEnforcementSchema = z.object({\n recallingFirm: z.string().optional().describe(\"Name of the recalling company\"),\n classification: z\n .enum([\"Class I\", \"Class II\", \"Class III\"])\n .optional()\n .describe(\"Recall classification (I=most serious, III=least)\"),\n status: z.enum([\"Ongoing\", \"Completed\", \"Terminated\", \"Pending\"]).optional().describe(\"Recall status\"),\n state: z.string().optional().describe(\"US state code (e.g., 'CA', 'NY')\"),\n ...dateRangeSchema,\n ...paginationSchema,\n})\n\nexport const searchDrugsFDASchema = z.object({\n sponsorName: z.string().optional().describe(\"Drug sponsor/company name\"),\n applicationNumber: z.string().optional().describe(\"FDA application number (e.g., 'NDA012345')\"),\n brandName: z.string().optional().describe(\"Drug brand name\"),\n marketingStatus: z.string().optional().describe(\"Marketing status (e.g., 'Prescription', 'OTC')\"),\n ...paginationSchema,\n})\n\nexport const searchDrugShortagesSchema = z.object({\n genericName: z.string().optional().describe(\"Generic drug name\"),\n status: z.enum([\"Current\", \"Resolved\"]).optional().describe(\"Shortage status\"),\n ...paginationSchema,\n})\n\n// Device Tool Schemas\n\nexport const searchDevice510KSchema = z.object({\n deviceName: z.string().optional().describe(\"Device name to search\"),\n applicant: z.string().optional().describe(\"Applicant/company name\"),\n productCode: z.string().optional().describe(\"FDA product code\"),\n clearanceType: z.string().optional().describe(\"Clearance type (e.g., 'Traditional', 'Special')\"),\n decisionDateFrom: z.string().optional().describe(\"Decision date range start (YYYY-MM-DD)\"),\n decisionDateTo: z.string().optional().describe(\"Decision date range end (YYYY-MM-DD)\"),\n ...paginationSchema,\n})\n\nexport const searchDeviceClassificationsSchema = z.object({\n deviceName: z.string().optional().describe(\"Device name to search\"),\n deviceClass: z.enum([\"1\", \"2\", \"3\"]).optional().describe(\"Device class (1=lowest risk, 3=highest)\"),\n medicalSpecialty: z.string().optional().describe(\"Medical specialty code\"),\n productCode: z.string().optional().describe(\"FDA product code\"),\n regulationNumber: z.string().optional().describe(\"CFR regulation number\"),\n ...paginationSchema,\n})\n\nexport const searchDeviceAdverseEventsSchema = z.object({\n reportNumber: z\n .string()\n .optional()\n .describe(\"MDR report number for retrieving a specific device adverse event report\"),\n deviceName: z.string().optional().describe(\"Device generic name\"),\n brandName: z.string().optional().describe(\"Device brand name\"),\n manufacturerName: z.string().optional().describe(\"Device manufacturer name\"),\n eventType: z.enum([\"Injury\", \"Malfunction\", \"Death\", \"Other\"]).optional().describe(\"Type of adverse event\"),\n ...dateRangeSchema,\n ...paginationSchema,\n})\n\nexport const searchDeviceEnforcementSchema = z.object({\n recallingFirm: z.string().optional().describe(\"Name of the recalling company\"),\n productDescription: z.string().optional().describe(\"Product description keywords\"),\n classification: z\n .enum([\"Class I\", \"Class II\", \"Class III\"])\n .optional()\n .describe(\"Recall classification (I=most serious)\"),\n status: z.enum([\"Ongoing\", \"Completed\", \"Terminated\", \"Pending\"]).optional().describe(\"Recall status\"),\n ...dateRangeSchema,\n ...paginationSchema,\n})\n\n// Bulk Data Tool Schemas (Orange Book & Purple Book)\n\nexport const searchOrangeBookSchema = z.object({\n drugName: z.string().optional().describe(\"Drug trade name or ingredient to search\"),\n applicant: z.string().optional().describe(\"Applicant/company name\"),\n applNo: z.string().optional().describe(\"FDA application number\"),\n teCode: z.string().optional().describe(\"Therapeutic equivalence code (e.g., 'AB', 'BX')\"),\n ...paginationSchema,\n})\n\nexport const searchOrangeBookPatentsSchema = z.object({\n drugName: z.string().optional().describe(\"Drug trade name or ingredient to search\"),\n applNo: z.string().optional().describe(\"FDA application number\"),\n patentNo: z.string().optional().describe(\"Patent number\"),\n ...paginationSchema,\n})\n\nexport const searchPurpleBookSchema = z.object({\n productName: z.string().optional().describe(\"Product proprietary or proper name to search\"),\n applicant: z.string().optional().describe(\"Applicant/company name\"),\n blaNumber: z.string().optional().describe(\"Biologics License Application (BLA) number\"),\n licenseType: z\n .enum([\"351(a)\", \"351(k)\"])\n .optional()\n .describe(\"License type: 351(a) for originator, 351(k) for biosimilar\"),\n biosimilar: z.boolean().optional().describe(\"Filter for biosimilar products\"),\n interchangeable: z.boolean().optional().describe(\"Filter for interchangeable products\"),\n ...paginationSchema,\n})\n\nexport const searchDrugPatentExpirySchema = z.object({\n drugName: z.string().optional().describe(\"Drug trade name or ingredient to search\"),\n applNo: z.string().optional().describe(\"FDA application number\"),\n includeExclusivity: z.boolean().optional().default(true).describe(\"Include exclusivity data (default: true)\"),\n includePurpleBook: z\n .boolean()\n .optional()\n .default(false)\n .describe(\"Include Purple Book biologics data (default: false)\"),\n ...paginationSchema,\n})\n\n// Export all schemas for use in tool registration\nexport const toolSchemas = {\n searchDrugAdverseEvents: searchDrugAdverseEventsSchema,\n searchDrugLabels: searchDrugLabelsSchema,\n searchDrugNDC: searchDrugNDCSchema,\n searchDrugEnforcement: searchDrugEnforcementSchema,\n searchDrugsFDA: searchDrugsFDASchema,\n searchDrugShortages: searchDrugShortagesSchema,\n searchDevice510K: searchDevice510KSchema,\n searchDeviceClassifications: searchDeviceClassificationsSchema,\n searchDeviceAdverseEvents: searchDeviceAdverseEventsSchema,\n searchDeviceEnforcement: searchDeviceEnforcementSchema,\n searchOrangeBook: searchOrangeBookSchema,\n searchOrangeBookPatents: searchOrangeBookPatentsSchema,\n searchPurpleBook: searchPurpleBookSchema,\n searchDrugPatentExpiry: searchDrugPatentExpirySchema,\n}\n\n// Export inferred types\nexport type SearchDrugAdverseEventsParams = z.infer<typeof searchDrugAdverseEventsSchema>\nexport type SearchDrugLabelsParams = z.infer<typeof searchDrugLabelsSchema>\nexport type SearchDrugNDCParams = z.infer<typeof searchDrugNDCSchema>\nexport type SearchDrugEnforcementParams = z.infer<typeof searchDrugEnforcementSchema>\nexport type SearchDrugsFDAParams = z.infer<typeof searchDrugsFDASchema>\nexport type SearchDrugShortagesParams = z.infer<typeof searchDrugShortagesSchema>\nexport type SearchDevice510KParams = z.infer<typeof searchDevice510KSchema>\nexport type SearchDeviceClassificationsParams = z.infer<typeof searchDeviceClassificationsSchema>\nexport type SearchDeviceAdverseEventsParams = z.infer<typeof searchDeviceAdverseEventsSchema>\nexport type SearchDeviceEnforcementParams = z.infer<typeof searchDeviceEnforcementSchema>\nexport type SearchOrangeBookParams = z.infer<typeof searchOrangeBookSchema>\nexport type SearchOrangeBookPatentsParams = z.infer<typeof searchOrangeBookPatentsSchema>\nexport type SearchPurpleBookParams = z.infer<typeof searchPurpleBookSchema>\nexport type SearchDrugPatentExpiryParams = z.infer<typeof searchDrugPatentExpirySchema>\nexport type LabelSection = (typeof labelSections)[number]\n"],"mappings":"wBAQA,MAAM,EAAmB,CACvB,MAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,gDAAgD,CAC5G,KAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,2CAA2C,CAC9F,CAGK,EAAkB,CACtB,SAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,6CAA6C,CACtF,OAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,2CAA2C,CACnF,CAIY,EAAgC,EAAE,OAAO,CACpD,eAAgB,EACb,QAAQ,CACR,UAAU,CACV,SAAS,yEAAyE,CACrF,SAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,iCAAiC,CAC1E,SAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,0DAA0D,CACnG,aAAc,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,yBAAyB,CACtE,QAAS,EAAE,SAAS,CAAC,UAAU,CAAC,SAAS,yCAAyC,CAClF,GAAG,EACH,GAAG,EACJ,CAAC,CAGW,EAAgB,CAC3B,wBACA,4BACA,oBACA,WACA,wBACA,oBACA,oBACA,wBACA,sBACA,mBACA,aACA,cACA,eACA,uBACA,gBACD,CAEY,EAAyB,EAAE,OAAO,CAC7C,MAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,wEAAwE,CAC9G,SAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,6BAA6B,CACtE,WAAY,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,iCAAiC,CAC5E,iBAAkB,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,mCAAmC,CACpF,MAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,wDAAwD,CAC9F,gBAAiB,EACd,SAAS,CACT,UAAU,CACV,SAAS,sEAAsE,CAClF,SAAU,EACP,MAAM,EAAE,KAAK,EAAc,CAAC,CAC5B,UAAU,CACV,SAAS,uGAAuG,CACnH,GAAG,EACJ,CAAC,CAEW,EAAsB,EAAE,OAAO,CAC1C,WAAY,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,2BAA2B,CACtE,UAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,kBAAkB,CAC5D,YAAa,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,oBAAoB,CAChE,YAAa,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,iCAAiC,CAC7E,WAAY,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,uDAAuD,CAClG,MAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,0BAA0B,CAChE,GAAG,EACJ,CAAC,CAEW,EAA8B,EAAE,OAAO,CAClD,cAAe,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,gCAAgC,CAC9E,eAAgB,EACb,KAAK,CAAC,UAAW,WAAY,YAAY,CAAC,CAC1C,UAAU,CACV,SAAS,oDAAoD,CAChE,OAAQ,EAAE,KAAK,CAAC,UAAW,YAAa,aAAc,UAAU,CAAC,CAAC,UAAU,CAAC,SAAS,gBAAgB,CACtG,MAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,mCAAmC,CACzE,GAAG,EACH,GAAG,EACJ,CAAC,CAEW,EAAuB,EAAE,OAAO,CAC3C,YAAa,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,4BAA4B,CACxE,kBAAmB,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,6CAA6C,CAC/F,UAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,kBAAkB,CAC5D,gBAAiB,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,iDAAiD,CACjG,GAAG,EACJ,CAAC,CAEW,EAA4B,EAAE,OAAO,CAChD,YAAa,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,oBAAoB,CAChE,OAAQ,EAAE,KAAK,CAAC,UAAW,WAAW,CAAC,CAAC,UAAU,CAAC,SAAS,kBAAkB,CAC9E,GAAG,EACJ,CAAC,CAIW,EAAyB,EAAE,OAAO,CAC7C,WAAY,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,wBAAwB,CACnE,UAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,yBAAyB,CACnE,YAAa,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,mBAAmB,CAC/D,cAAe,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,kDAAkD,CAChG,iBAAkB,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,yCAAyC,CAC1F,eAAgB,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,uCAAuC,CACtF,GAAG,EACJ,CAAC,CAEW,EAAoC,EAAE,OAAO,CACxD,WAAY,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,wBAAwB,CACnE,YAAa,EAAE,KAAK,CAAC,IAAK,IAAK,IAAI,CAAC,CAAC,UAAU,CAAC,SAAS,0CAA0C,CACnG,iBAAkB,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,yBAAyB,CAC1E,YAAa,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,mBAAmB,CAC/D,iBAAkB,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,wBAAwB,CACzE,GAAG,EACJ,CAAC,CAEW,EAAkC,EAAE,OAAO,CACtD,aAAc,EACX,QAAQ,CACR,UAAU,CACV,SAAS,0EAA0E,CACtF,WAAY,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,sBAAsB,CACjE,UAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,oBAAoB,CAC9D,iBAAkB,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,2BAA2B,CAC5E,UAAW,EAAE,KAAK,CAAC,SAAU,cAAe,QAAS,QAAQ,CAAC,CAAC,UAAU,CAAC,SAAS,wBAAwB,CAC3G,GAAG,EACH,GAAG,EACJ,CAAC,CAEW,EAAgC,EAAE,OAAO,CACpD,cAAe,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,gCAAgC,CAC9E,mBAAoB,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,+BAA+B,CAClF,eAAgB,EACb,KAAK,CAAC,UAAW,WAAY,YAAY,CAAC,CAC1C,UAAU,CACV,SAAS,yCAAyC,CACrD,OAAQ,EAAE,KAAK,CAAC,UAAW,YAAa,aAAc,UAAU,CAAC,CAAC,UAAU,CAAC,SAAS,gBAAgB,CACtG,GAAG,EACH,GAAG,EACJ,CAAC,CAIW,EAAyB,EAAE,OAAO,CAC7C,SAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,0CAA0C,CACnF,UAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,yBAAyB,CACnE,OAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,yBAAyB,CAChE,OAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,kDAAkD,CACzF,GAAG,EACJ,CAAC,CAEW,EAAgC,EAAE,OAAO,CACpD,SAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,0CAA0C,CACnF,OAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,yBAAyB,CAChE,SAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,gBAAgB,CACzD,GAAG,EACJ,CAAC,CAEW,EAAyB,EAAE,OAAO,CAC7C,YAAa,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,+CAA+C,CAC3F,UAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,yBAAyB,CACnE,UAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,6CAA6C,CACvF,YAAa,EACV,KAAK,CAAC,SAAU,SAAS,CAAC,CAC1B,UAAU,CACV,SAAS,6DAA6D,CACzE,WAAY,EAAE,SAAS,CAAC,UAAU,CAAC,SAAS,iCAAiC,CAC7E,gBAAiB,EAAE,SAAS,CAAC,UAAU,CAAC,SAAS,sCAAsC,CACvF,GAAG,EACJ,CAAC,CAEW,EAA+B,EAAE,OAAO,CACnD,SAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,0CAA0C,CACnF,OAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,yBAAyB,CAChE,mBAAoB,EAAE,SAAS,CAAC,UAAU,CAAC,QAAQ,GAAK,CAAC,SAAS,2CAA2C,CAC7G,kBAAmB,EAChB,SAAS,CACT,UAAU,CACV,QAAQ,GAAM,CACd,SAAS,sDAAsD,CAClE,GAAG,EACJ,CAAC,CAGW,EAAc,CACzB,wBAAyB,EACzB,iBAAkB,EAClB,cAAe,EACf,sBAAuB,EACvB,eAAgB,EAChB,oBAAqB,EACrB,iBAAkB,EAClB,4BAA6B,EAC7B,0BAA2B,EAC3B,wBAAyB,EACzB,iBAAkB,EAClB,wBAAyB,EACzB,iBAAkB,EAClB,uBAAwB,EACzB"}
@@ -130,6 +130,7 @@ type DrugLabel = {
130
130
  purpose?: string[];
131
131
  indications_and_usage?: string[];
132
132
  warnings?: string[];
133
+ boxed_warning?: string[];
133
134
  do_not_use?: string[];
134
135
  ask_doctor?: string[];
135
136
  ask_doctor_or_pharmacist?: string[];
@@ -416,7 +417,64 @@ type FDAToolResponse<T> = {
416
417
  authenticated: boolean;
417
418
  rateLimit: string;
418
419
  };
420
+ dataSource?: {
421
+ name: string;
422
+ lastUpdated: string;
423
+ url: string;
424
+ };
425
+ };
426
+ type OrangeBookProduct = {
427
+ ingredient: string;
428
+ dfRoute: string;
429
+ tradeName: string;
430
+ applicant: string;
431
+ applType: string;
432
+ applNo: string;
433
+ productNo: string;
434
+ teCode: string;
435
+ approvalDate: string;
436
+ rld: string;
437
+ rs: string;
438
+ type: string;
439
+ applicantFullName: string;
440
+ };
441
+ type OrangeBookPatent = {
442
+ applType: string;
443
+ applNo: string;
444
+ productNo: string;
445
+ patentNo: string;
446
+ patentExpireDate: string;
447
+ drugSubstanceFlag: string;
448
+ drugProductFlag: string;
449
+ patentUseCode: string;
450
+ delistFlag: string;
451
+ submissionDate: string;
452
+ };
453
+ type OrangeBookExclusivity = {
454
+ applType: string;
455
+ applNo: string;
456
+ productNo: string;
457
+ exclusivityCode: string;
458
+ exclusivityDate: string;
459
+ };
460
+ type PurpleBookEntry = {
461
+ blaNumber: string;
462
+ proprietaryName: string;
463
+ properName: string;
464
+ applicant: string;
465
+ blaType: string;
466
+ strength: string;
467
+ dosageForm: string;
468
+ route: string;
469
+ productPresentation: string;
470
+ status: string;
471
+ licensingStatus: string;
472
+ referenceProductBla: string;
473
+ referenceProductProprietaryName: string;
474
+ biosimilar: boolean;
475
+ interchangeable: boolean;
476
+ approvalDate: string;
419
477
  };
420
478
  //#endregion
421
- export { Device510K, DeviceAdverseEvent, DeviceClassification, DeviceEnforcement, DrugAdverseEvent, DrugEnforcement, DrugLabel, DrugNDC, DrugShortage, DrugsFDA, FDAResponse, FDAToolResponse, OpenFDAFields, SearchParams };
479
+ export { Device510K, DeviceAdverseEvent, DeviceClassification, DeviceEnforcement, DrugAdverseEvent, DrugEnforcement, DrugLabel, DrugNDC, DrugShortage, DrugsFDA, FDAResponse, FDAToolResponse, OpenFDAFields, OrangeBookExclusivity, OrangeBookPatent, OrangeBookProduct, PurpleBookEntry, SearchParams };
422
480
  //# sourceMappingURL=fda.d.ts.map
@@ -1,7 +1,6 @@
1
1
  import { Device510K, DeviceAdverseEvent, DeviceClassification, DeviceEnforcement, DrugAdverseEvent, DrugEnforcement, DrugLabel, DrugNDC, DrugShortage, DrugsFDA, FDAResponse, SearchParams } from "../types/fda.js";
2
2
 
3
3
  //#region src/utils/api-client.d.ts
4
-
5
4
  declare class FDAAPIClient {
6
5
  private apiKey;
7
6
  private baseUrl;
@@ -1 +1,2 @@
1
- import"./logger.js";import{n as e,t}from"../api-client-BGnUXMwX.js";export{t as FDAAPIClient,e as fdaAPIClient};
1
+ import{loggers as e}from"./logger.js";import{t}from"../defineProperty-BEGP2H1W.js";var n=class{constructor(){t(this,`apiKey`,void 0),t(this,`baseUrl`,void 0),this.apiKey=process.env.OPENFDA_API_KEY,this.baseUrl=`https://api.fda.gov`}buildSearchParams(e){let t=new URLSearchParams;e.search&&t.set(`search`,e.search),e.count&&t.set(`count`,e.count);let n=Math.min(e.limit??10,100);return t.set(`limit`,String(n)),e.skip!==void 0&&e.skip>0&&t.set(`skip`,String(e.skip)),this.apiKey&&t.set(`api_key`,this.apiKey),t}async request(t,n){let r=this.buildSearchParams(n),i=`${this.baseUrl}${t}?${r.toString()}`;e.api(`Request: ${i.replace(this.apiKey??``,`[REDACTED]`)}`);try{let t=await fetch(i);if(!t.ok){let e=await t.json().catch(()=>({}));if(t.status===429)throw Error(`Rate limit exceeded. Consider using an API key for higher limits.`);if(t.status===404)return{results:[]};throw t.status===400?Error(`Invalid request: ${e.error?.message??`Bad request parameters`}`):Error(`FDA API error: ${t.status} ${t.statusText}`)}let n=await t.json();return e.api(`Response: ${n.meta?.results?.total??0} total results`),n}catch(e){throw e instanceof Error?e:Error(`Failed to fetch from FDA API: ${String(e)}`,{cause:e})}}getRateLimitInfo(){return{authenticated:!!this.apiKey,rateLimit:this.apiKey?`240/minute, 120,000/hour`:`40/minute, 1,000/hour`}}async searchDrugAdverseEvents(e){return this.request(`/drug/event.json`,e)}async searchDrugLabels(e){return this.request(`/drug/label.json`,e)}async searchDrugNDC(e){return this.request(`/drug/ndc.json`,e)}async searchDrugEnforcement(e){return this.request(`/drug/enforcement.json`,e)}async searchDrugsFDA(e){return this.request(`/drug/drugsfda.json`,e)}async searchDrugShortages(e){return this.request(`/drug/shortages.json`,e)}async searchDevice510K(e){return this.request(`/device/510k.json`,e)}async searchDeviceClassifications(e){return this.request(`/device/classification.json`,e)}async searchDeviceAdverseEvents(e){return this.request(`/device/event.json`,e)}async searchDeviceEnforcement(e){return this.request(`/device/enforcement.json`,e)}};const r=new n;export{n as FDAAPIClient,r as fdaAPIClient};
2
+ //# sourceMappingURL=api-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.js","names":[],"sources":["../../src/utils/api-client.ts"],"sourcesContent":["/**\n * FDA API Client\n * HTTP client for interacting with FDA OpenAPI endpoints\n */\n\nimport type {\n Device510K,\n DeviceAdverseEvent,\n DeviceClassification,\n DeviceEnforcement,\n DrugAdverseEvent,\n DrugEnforcement,\n DrugLabel,\n DrugNDC,\n DrugsFDA,\n DrugShortage,\n FDAResponse,\n SearchParams,\n} from \"../types/fda.js\"\nimport { loggers } from \"./logger.js\"\n\nconst FDA_BASE_URL = \"https://api.fda.gov\"\nconst DEFAULT_LIMIT = 10\nconst MAX_LIMIT = 100\n\ntype FDAEndpoint =\n | \"/drug/event.json\"\n | \"/drug/label.json\"\n | \"/drug/ndc.json\"\n | \"/drug/enforcement.json\"\n | \"/drug/drugsfda.json\"\n | \"/drug/shortages.json\"\n | \"/device/510k.json\"\n | \"/device/classification.json\"\n | \"/device/event.json\"\n | \"/device/enforcement.json\"\n\nexport class FDAAPIClient {\n private apiKey: string | undefined\n private baseUrl: string\n\n constructor() {\n this.apiKey = process.env.OPENFDA_API_KEY\n this.baseUrl = FDA_BASE_URL\n }\n\n /**\n * Build URL search parameters for the FDA API\n */\n private buildSearchParams(params: SearchParams): URLSearchParams {\n const urlParams = new URLSearchParams()\n\n if (params.search) {\n urlParams.set(\"search\", params.search)\n }\n\n if (params.count) {\n urlParams.set(\"count\", params.count)\n }\n\n const limit = Math.min(params.limit ?? DEFAULT_LIMIT, MAX_LIMIT)\n urlParams.set(\"limit\", String(limit))\n\n if (params.skip !== undefined && params.skip > 0) {\n urlParams.set(\"skip\", String(params.skip))\n }\n\n if (this.apiKey) {\n urlParams.set(\"api_key\", this.apiKey)\n }\n\n return urlParams\n }\n\n /**\n * Make a request to an FDA API endpoint\n */\n private async request<T>(endpoint: FDAEndpoint, params: SearchParams): Promise<FDAResponse<T>> {\n const urlParams = this.buildSearchParams(params)\n const url = `${this.baseUrl}${endpoint}?${urlParams.toString()}`\n\n loggers.api(`Request: ${url.replace(this.apiKey ?? \"\", \"[REDACTED]\")}`)\n\n try {\n const response = await fetch(url)\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}))\n\n if (response.status === 429) {\n throw new Error(\"Rate limit exceeded. Consider using an API key for higher limits.\")\n }\n if (response.status === 404) {\n return { results: [] } // No results found\n }\n if (response.status === 400) {\n throw new Error(\n `Invalid request: ${(errorData as { error?: { message?: string } }).error?.message ?? \"Bad request parameters\"}`,\n )\n }\n\n throw new Error(`FDA API error: ${response.status} ${response.statusText}`)\n }\n\n const data = (await response.json()) as FDAResponse<T>\n loggers.api(`Response: ${data.meta?.results?.total ?? 0} total results`)\n return data\n } catch (error) {\n if (error instanceof Error) {\n throw error\n }\n throw new Error(`Failed to fetch from FDA API: ${String(error)}`, { cause: error })\n }\n }\n\n /**\n * Get rate limit info based on authentication status\n */\n getRateLimitInfo(): { authenticated: boolean; rateLimit: string } {\n return {\n authenticated: !!this.apiKey,\n rateLimit: this.apiKey ? \"240/minute, 120,000/hour\" : \"40/minute, 1,000/hour\",\n }\n }\n\n // Drug endpoints\n\n async searchDrugAdverseEvents(params: SearchParams): Promise<FDAResponse<DrugAdverseEvent>> {\n return this.request<DrugAdverseEvent>(\"/drug/event.json\", params)\n }\n\n async searchDrugLabels(params: SearchParams): Promise<FDAResponse<DrugLabel>> {\n return this.request<DrugLabel>(\"/drug/label.json\", params)\n }\n\n async searchDrugNDC(params: SearchParams): Promise<FDAResponse<DrugNDC>> {\n return this.request<DrugNDC>(\"/drug/ndc.json\", params)\n }\n\n async searchDrugEnforcement(params: SearchParams): Promise<FDAResponse<DrugEnforcement>> {\n return this.request<DrugEnforcement>(\"/drug/enforcement.json\", params)\n }\n\n async searchDrugsFDA(params: SearchParams): Promise<FDAResponse<DrugsFDA>> {\n return this.request<DrugsFDA>(\"/drug/drugsfda.json\", params)\n }\n\n async searchDrugShortages(params: SearchParams): Promise<FDAResponse<DrugShortage>> {\n return this.request<DrugShortage>(\"/drug/shortages.json\", params)\n }\n\n // Device endpoints\n\n async searchDevice510K(params: SearchParams): Promise<FDAResponse<Device510K>> {\n return this.request<Device510K>(\"/device/510k.json\", params)\n }\n\n async searchDeviceClassifications(params: SearchParams): Promise<FDAResponse<DeviceClassification>> {\n return this.request<DeviceClassification>(\"/device/classification.json\", params)\n }\n\n async searchDeviceAdverseEvents(params: SearchParams): Promise<FDAResponse<DeviceAdverseEvent>> {\n return this.request<DeviceAdverseEvent>(\"/device/event.json\", params)\n }\n\n async searchDeviceEnforcement(params: SearchParams): Promise<FDAResponse<DeviceEnforcement>> {\n return this.request<DeviceEnforcement>(\"/device/enforcement.json\", params)\n }\n}\n\n// Singleton instance\nexport const fdaAPIClient = new FDAAPIClient()\n"],"mappings":"mFAqCA,IAAa,EAAb,KAA0B,CAIxB,aAAc,QAHN,SAAA,IAAA,GAA0B,QAC1B,UAAA,IAAA,GAAe,CAGrB,KAAK,OAAS,QAAQ,IAAI,gBAC1B,KAAK,QAAU,sBAMjB,kBAA0B,EAAuC,CAC/D,IAAM,EAAY,IAAI,gBAElB,EAAO,QACT,EAAU,IAAI,SAAU,EAAO,OAAO,CAGpC,EAAO,OACT,EAAU,IAAI,QAAS,EAAO,MAAM,CAGtC,IAAM,EAAQ,KAAK,IAAI,EAAO,OAAS,GAAe,IAAU,CAWhE,OAVA,EAAU,IAAI,QAAS,OAAO,EAAM,CAAC,CAEjC,EAAO,OAAS,IAAA,IAAa,EAAO,KAAO,GAC7C,EAAU,IAAI,OAAQ,OAAO,EAAO,KAAK,CAAC,CAGxC,KAAK,QACP,EAAU,IAAI,UAAW,KAAK,OAAO,CAGhC,EAMT,MAAc,QAAW,EAAuB,EAA+C,CAC7F,IAAM,EAAY,KAAK,kBAAkB,EAAO,CAC1C,EAAM,GAAG,KAAK,UAAU,EAAS,GAAG,EAAU,UAAU,GAE9D,EAAQ,IAAI,YAAY,EAAI,QAAQ,KAAK,QAAU,GAAI,aAAa,GAAG,CAEvE,GAAI,CACF,IAAM,EAAW,MAAM,MAAM,EAAI,CAEjC,GAAI,CAAC,EAAS,GAAI,CAChB,IAAM,EAAY,MAAM,EAAS,MAAM,CAAC,WAAa,EAAE,EAAE,CAEzD,GAAI,EAAS,SAAW,IACtB,MAAU,MAAM,oEAAoE,CAEtF,GAAI,EAAS,SAAW,IACtB,MAAO,CAAE,QAAS,EAAE,CAAE,CAQxB,MANI,EAAS,SAAW,IACZ,MACR,oBAAqB,EAA+C,OAAO,SAAW,2BACvF,CAGO,MAAM,kBAAkB,EAAS,OAAO,GAAG,EAAS,aAAa,CAG7E,IAAM,EAAQ,MAAM,EAAS,MAAM,CAEnC,OADA,EAAQ,IAAI,aAAa,EAAK,MAAM,SAAS,OAAS,EAAE,gBAAgB,CACjE,QACA,EAAO,CAId,MAHI,aAAiB,MACb,EAEE,MAAM,iCAAiC,OAAO,EAAM,GAAI,CAAE,MAAO,EAAO,CAAC,EAOvF,kBAAkE,CAChE,MAAO,CACL,cAAe,CAAC,CAAC,KAAK,OACtB,UAAW,KAAK,OAAS,2BAA6B,wBACvD,CAKH,MAAM,wBAAwB,EAA8D,CAC1F,OAAO,KAAK,QAA0B,mBAAoB,EAAO,CAGnE,MAAM,iBAAiB,EAAuD,CAC5E,OAAO,KAAK,QAAmB,mBAAoB,EAAO,CAG5D,MAAM,cAAc,EAAqD,CACvE,OAAO,KAAK,QAAiB,iBAAkB,EAAO,CAGxD,MAAM,sBAAsB,EAA6D,CACvF,OAAO,KAAK,QAAyB,yBAA0B,EAAO,CAGxE,MAAM,eAAe,EAAsD,CACzE,OAAO,KAAK,QAAkB,sBAAuB,EAAO,CAG9D,MAAM,oBAAoB,EAA0D,CAClF,OAAO,KAAK,QAAsB,uBAAwB,EAAO,CAKnE,MAAM,iBAAiB,EAAwD,CAC7E,OAAO,KAAK,QAAoB,oBAAqB,EAAO,CAG9D,MAAM,4BAA4B,EAAkE,CAClG,OAAO,KAAK,QAA8B,8BAA+B,EAAO,CAGlF,MAAM,0BAA0B,EAAgE,CAC9F,OAAO,KAAK,QAA4B,qBAAsB,EAAO,CAGvE,MAAM,wBAAwB,EAA+D,CAC3F,OAAO,KAAK,QAA2B,2BAA4B,EAAO,GAK9E,MAAa,EAAe,IAAI"}
@@ -0,0 +1,24 @@
1
+ import { OrangeBookExclusivity, OrangeBookPatent, OrangeBookProduct, PurpleBookEntry } from "../types/fda.js";
2
+
3
+ //#region src/utils/bulk-data-client.d.ts
4
+ type OrangeBookData = {
5
+ products: OrangeBookProduct[];
6
+ patents: OrangeBookPatent[];
7
+ exclusivities: OrangeBookExclusivity[];
8
+ };
9
+ declare class BulkDataClient {
10
+ private orangeBookCache;
11
+ private purpleBookCache;
12
+ private isCacheValid;
13
+ downloadBinary(url: string): Promise<Uint8Array>;
14
+ parseTildeDelimited<T extends Record<string, string>>(text: string): T[];
15
+ parseCSV<T extends Record<string, string>>(text: string): T[];
16
+ private parseCSVLine;
17
+ getOrangeBookData(): Promise<OrangeBookData>;
18
+ getPurpleBookData(): Promise<PurpleBookEntry[]>;
19
+ clearCache(): void;
20
+ }
21
+ declare const bulkDataClient: BulkDataClient;
22
+ //#endregion
23
+ export { BulkDataClient, bulkDataClient };
24
+ //# sourceMappingURL=bulk-data-client.d.ts.map
@@ -0,0 +1,4 @@
1
+ import{loggers as e}from"./logger.js";import{t}from"../defineProperty-BEGP2H1W.js";import{unzipSync as n}from"fflate";var r=class{constructor(){t(this,`orangeBookCache`,void 0),t(this,`purpleBookCache`,void 0)}isCacheValid(e){return e?Date.now()-e.fetchedAt<e.ttlMs:!1}async downloadBinary(t){e.bulk(`Downloading: ${t}`);let n=await fetch(t);if(!n.ok)throw Error(`Failed to download ${t}: ${n.status} ${n.statusText}`);let r=await n.arrayBuffer();return new Uint8Array(r)}parseTildeDelimited(e){let t=e.split(`
2
+ `).filter(e=>e.trim()!==``);if(t.length<2)return[];let n=t[0].split(`~`).map(e=>e.trim()),r=[];for(let e=1;e<t.length;e++){let i=t[e].split(`~`),a={};for(let e=0;e<n.length;e++)a[n[e]]=(i[e]??``).trim();r.push(a)}return r}parseCSV(e){let t=e.split(`
3
+ `).filter(e=>e.trim()!==``);if(t.length<2)return[];let n=this.parseCSVLine(t[0]),r=[];for(let e=1;e<t.length;e++){let i=this.parseCSVLine(t[e]),a={};for(let e=0;e<n.length;e++)a[n[e]]=(i[e]??``).trim();r.push(a)}return r}parseCSVLine(e){let t=[],n=``,r=!1;for(let i=0;i<e.length;i++){let a=e[i];r?a===`"`?i+1<e.length&&e[i+1]===`"`?(n+=`"`,i++):r=!1:n+=a:a===`"`?r=!0:a===`,`?(t.push(n.trim()),n=``):n+=a}return t.push(n.trim()),t}async getOrangeBookData(){if(this.isCacheValid(this.orangeBookCache))return e.bulk(`Using cached Orange Book data`),this.orangeBookCache.data;e.bulk(`Downloading Orange Book ZIP...`);let t=n(await this.downloadBinary(`https://www.fda.gov/media/76860/download`)),r=new TextDecoder(`utf-8`),i=[],a=[],o=[];for(let[n,s]of Object.entries(t)){let t=n.toLowerCase(),c=r.decode(s);t.includes(`products`)?(i=this.parseTildeDelimited(c).map(e=>({ingredient:e.Ingredient??e.ingredient??``,dfRoute:e[`DF;Route`]??e[`df;route`]??e.DF_Route??``,tradeName:e.Trade_Name??e.trade_name??``,applicant:e.Applicant??e.applicant??``,applType:e.Appl_Type??e.appl_type??``,applNo:e.Appl_No??e.appl_no??``,productNo:e.Product_No??e.product_no??``,teCode:e.TE_Code??e.te_code??``,approvalDate:e.Approval_Date??e.approval_date??``,rld:e.RLD??e.rld??``,rs:e.RS??e.rs??``,type:e.Type??e.type??``,applicantFullName:e.Applicant_Full_Name??e.applicant_full_name??``})),e.bulk(`Parsed ${i.length} Orange Book products`)):t.includes(`patent`)?(a=this.parseTildeDelimited(c).map(e=>({applType:e.Appl_Type??e.appl_type??``,applNo:e.Appl_No??e.appl_no??``,productNo:e.Product_No??e.product_no??``,patentNo:e.Patent_No??e.patent_no??``,patentExpireDate:e.Patent_Expire_Date_Text??e.patent_expire_date_text??``,drugSubstanceFlag:e.Drug_Substance_Flag??e.drug_substance_flag??``,drugProductFlag:e.Drug_Product_Flag??e.drug_product_flag??``,patentUseCode:e.Patent_Use_Code??e.patent_use_code??``,delistFlag:e.Delist_Flag??e.delist_flag??``,submissionDate:e.Submission_Date??e.submission_date??``})),e.bulk(`Parsed ${a.length} Orange Book patents`)):t.includes(`exclusivity`)&&(o=this.parseTildeDelimited(c).map(e=>({applType:e.Appl_Type??e.appl_type??``,applNo:e.Appl_No??e.appl_no??``,productNo:e.Product_No??e.product_no??``,exclusivityCode:e.Exclusivity_Code??e.exclusivity_code??``,exclusivityDate:e.Exclusivity_Date??e.exclusivity_date??``})),e.bulk(`Parsed ${o.length} Orange Book exclusivities`))}let s={products:i,patents:a,exclusivities:o};return this.orangeBookCache={data:s,fetchedAt:Date.now(),ttlMs:1440*60*1e3},s}async getPurpleBookData(){if(this.isCacheValid(this.purpleBookCache))return e.bulk(`Using cached Purple Book data`),this.purpleBookCache.data;e.bulk(`Fetching Purple Book data from API...`);let t=await fetch(`https://purplebooksearch.fda.gov/api/v1/fdaproducts?token=18dd75c5-23c2-4318-970b-ca97c34470cb`);if(!t.ok)throw Error(`Failed to fetch Purple Book data: ${t.status} ${t.statusText}`);let n=await t.json();e.bulk(`Received ${n.length} Purple Book entries from API`);let r=n.map(e=>({blaNumber:e.bla_number??``,proprietaryName:e.proprietary_name??``,properName:e.proper_name??``,applicant:e.applicant??``,blaType:e.license_type??``,strength:e.strength??``,dosageForm:e.dosage_form??``,route:e.route_of_administration??``,productPresentation:e.product_presentation??``,status:e.status??``,licensingStatus:e.licensure??``,referenceProductBla:e.ref_product_proper_name?.trim()??``,referenceProductProprietaryName:e.ref_prod_proprietary_name??``,biosimilar:(e.license_type??``)===`351(k)`,interchangeable:(e.interchangeable_approval_date??``).trim()!==``,approvalDate:e.approval_date??e.date_of_first_licensure??``}));return this.purpleBookCache={data:r,fetchedAt:Date.now(),ttlMs:10080*60*1e3},r}clearCache(){this.orangeBookCache=void 0,this.purpleBookCache=void 0}};const i=new r;export{r as BulkDataClient,i as bulkDataClient};
4
+ //# sourceMappingURL=bulk-data-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bulk-data-client.js","names":[],"sources":["../../src/utils/bulk-data-client.ts"],"sourcesContent":["/**\n * Bulk Data Client\n * Downloads and parses FDA Orange Book and Purple Book data files\n */\n\nimport { unzipSync } from \"fflate\"\n\nimport type { OrangeBookExclusivity, OrangeBookPatent, OrangeBookProduct, PurpleBookEntry } from \"../types/fda.js\"\nimport { loggers } from \"./logger.js\"\n\nconst ORANGE_BOOK_ZIP_URL = \"https://www.fda.gov/media/76860/download\"\nconst PURPLE_BOOK_API_URL = \"https://purplebooksearch.fda.gov/api/v1/fdaproducts\"\nconst PURPLE_BOOK_API_TOKEN = \"18dd75c5-23c2-4318-970b-ca97c34470cb\"\n\ntype CacheEntry<T> = {\n data: T\n fetchedAt: number\n ttlMs: number\n}\n\ntype OrangeBookData = {\n products: OrangeBookProduct[]\n patents: OrangeBookPatent[]\n exclusivities: OrangeBookExclusivity[]\n}\n\nexport class BulkDataClient {\n private orangeBookCache: CacheEntry<OrangeBookData> | undefined\n private purpleBookCache: CacheEntry<PurpleBookEntry[]> | undefined\n\n private isCacheValid<T>(entry: CacheEntry<T> | undefined): entry is CacheEntry<T> {\n if (!entry) return false\n return Date.now() - entry.fetchedAt < entry.ttlMs\n }\n\n async downloadBinary(url: string): Promise<Uint8Array> {\n loggers.bulk(`Downloading: ${url}`)\n const response = await fetch(url)\n if (!response.ok) {\n throw new Error(`Failed to download ${url}: ${response.status} ${response.statusText}`)\n }\n const buffer = await response.arrayBuffer()\n return new Uint8Array(buffer)\n }\n\n parseTildeDelimited<T extends Record<string, string>>(text: string): T[] {\n const lines = text.split(\"\\n\").filter((line) => line.trim() !== \"\")\n if (lines.length < 2) return []\n\n const headers = lines[0].split(\"~\").map((h) => h.trim())\n const results: T[] = []\n\n for (let i = 1; i < lines.length; i++) {\n const values = lines[i].split(\"~\")\n const record: Record<string, string> = {}\n for (let j = 0; j < headers.length; j++) {\n record[headers[j]] = (values[j] ?? \"\").trim()\n }\n results.push(record as T)\n }\n\n return results\n }\n\n parseCSV<T extends Record<string, string>>(text: string): T[] {\n const lines = text.split(\"\\n\").filter((line) => line.trim() !== \"\")\n if (lines.length < 2) return []\n\n const headers = this.parseCSVLine(lines[0])\n const results: T[] = []\n\n for (let i = 1; i < lines.length; i++) {\n const values = this.parseCSVLine(lines[i])\n const record: Record<string, string> = {}\n for (let j = 0; j < headers.length; j++) {\n record[headers[j]] = (values[j] ?? \"\").trim()\n }\n results.push(record as T)\n }\n\n return results\n }\n\n private parseCSVLine(line: string): string[] {\n const result: string[] = []\n let current = \"\"\n let inQuotes = false\n\n for (let i = 0; i < line.length; i++) {\n const char = line[i]\n if (inQuotes) {\n if (char === '\"') {\n if (i + 1 < line.length && line[i + 1] === '\"') {\n current += '\"'\n i++\n } else {\n inQuotes = false\n }\n } else {\n current += char\n }\n } else {\n if (char === '\"') {\n inQuotes = true\n } else if (char === \",\") {\n result.push(current.trim())\n current = \"\"\n } else {\n current += char\n }\n }\n }\n result.push(current.trim())\n return result\n }\n\n async getOrangeBookData(): Promise<OrangeBookData> {\n if (this.isCacheValid(this.orangeBookCache)) {\n loggers.bulk(\"Using cached Orange Book data\")\n return this.orangeBookCache.data\n }\n\n loggers.bulk(\"Downloading Orange Book ZIP...\")\n const zipData = await this.downloadBinary(ORANGE_BOOK_ZIP_URL)\n const files = unzipSync(zipData)\n\n const decoder = new TextDecoder(\"utf-8\")\n let products: OrangeBookProduct[] = []\n let patents: OrangeBookPatent[] = []\n let exclusivities: OrangeBookExclusivity[] = []\n\n for (const [filename, content] of Object.entries(files)) {\n const lowerName = filename.toLowerCase()\n const text = decoder.decode(content)\n\n if (lowerName.includes(\"products\")) {\n products = this.parseTildeDelimited<Record<string, string>>(text).map((r) => ({\n ingredient: r[\"Ingredient\"] ?? r[\"ingredient\"] ?? \"\",\n dfRoute: r[\"DF;Route\"] ?? r[\"df;route\"] ?? r[\"DF_Route\"] ?? \"\",\n tradeName: r[\"Trade_Name\"] ?? r[\"trade_name\"] ?? \"\",\n applicant: r[\"Applicant\"] ?? r[\"applicant\"] ?? \"\",\n applType: r[\"Appl_Type\"] ?? r[\"appl_type\"] ?? \"\",\n applNo: r[\"Appl_No\"] ?? r[\"appl_no\"] ?? \"\",\n productNo: r[\"Product_No\"] ?? r[\"product_no\"] ?? \"\",\n teCode: r[\"TE_Code\"] ?? r[\"te_code\"] ?? \"\",\n approvalDate: r[\"Approval_Date\"] ?? r[\"approval_date\"] ?? \"\",\n rld: r[\"RLD\"] ?? r[\"rld\"] ?? \"\",\n rs: r[\"RS\"] ?? r[\"rs\"] ?? \"\",\n type: r[\"Type\"] ?? r[\"type\"] ?? \"\",\n applicantFullName: r[\"Applicant_Full_Name\"] ?? r[\"applicant_full_name\"] ?? \"\",\n }))\n loggers.bulk(`Parsed ${products.length} Orange Book products`)\n } else if (lowerName.includes(\"patent\")) {\n patents = this.parseTildeDelimited<Record<string, string>>(text).map((r) => ({\n applType: r[\"Appl_Type\"] ?? r[\"appl_type\"] ?? \"\",\n applNo: r[\"Appl_No\"] ?? r[\"appl_no\"] ?? \"\",\n productNo: r[\"Product_No\"] ?? r[\"product_no\"] ?? \"\",\n patentNo: r[\"Patent_No\"] ?? r[\"patent_no\"] ?? \"\",\n patentExpireDate: r[\"Patent_Expire_Date_Text\"] ?? r[\"patent_expire_date_text\"] ?? \"\",\n drugSubstanceFlag: r[\"Drug_Substance_Flag\"] ?? r[\"drug_substance_flag\"] ?? \"\",\n drugProductFlag: r[\"Drug_Product_Flag\"] ?? r[\"drug_product_flag\"] ?? \"\",\n patentUseCode: r[\"Patent_Use_Code\"] ?? r[\"patent_use_code\"] ?? \"\",\n delistFlag: r[\"Delist_Flag\"] ?? r[\"delist_flag\"] ?? \"\",\n submissionDate: r[\"Submission_Date\"] ?? r[\"submission_date\"] ?? \"\",\n }))\n loggers.bulk(`Parsed ${patents.length} Orange Book patents`)\n } else if (lowerName.includes(\"exclusivity\")) {\n exclusivities = this.parseTildeDelimited<Record<string, string>>(text).map((r) => ({\n applType: r[\"Appl_Type\"] ?? r[\"appl_type\"] ?? \"\",\n applNo: r[\"Appl_No\"] ?? r[\"appl_no\"] ?? \"\",\n productNo: r[\"Product_No\"] ?? r[\"product_no\"] ?? \"\",\n exclusivityCode: r[\"Exclusivity_Code\"] ?? r[\"exclusivity_code\"] ?? \"\",\n exclusivityDate: r[\"Exclusivity_Date\"] ?? r[\"exclusivity_date\"] ?? \"\",\n }))\n loggers.bulk(`Parsed ${exclusivities.length} Orange Book exclusivities`)\n }\n }\n\n const data: OrangeBookData = { products, patents, exclusivities }\n\n this.orangeBookCache = {\n data,\n fetchedAt: Date.now(),\n ttlMs: 24 * 60 * 60 * 1000, // 24 hours\n }\n\n return data\n }\n\n async getPurpleBookData(): Promise<PurpleBookEntry[]> {\n if (this.isCacheValid(this.purpleBookCache)) {\n loggers.bulk(\"Using cached Purple Book data\")\n return this.purpleBookCache.data\n }\n\n loggers.bulk(\"Fetching Purple Book data from API...\")\n\n const url = `${PURPLE_BOOK_API_URL}?token=${PURPLE_BOOK_API_TOKEN}`\n const response = await fetch(url)\n\n if (!response.ok) {\n throw new Error(`Failed to fetch Purple Book data: ${response.status} ${response.statusText}`)\n }\n\n const rawEntries = (await response.json()) as Array<Record<string, string>>\n loggers.bulk(`Received ${rawEntries.length} Purple Book entries from API`)\n\n const entries: PurpleBookEntry[] = rawEntries.map((r) => ({\n blaNumber: r.bla_number ?? \"\",\n proprietaryName: r.proprietary_name ?? \"\",\n properName: r.proper_name ?? \"\",\n applicant: r.applicant ?? \"\",\n blaType: r.license_type ?? \"\",\n strength: r.strength ?? \"\",\n dosageForm: r.dosage_form ?? \"\",\n route: r.route_of_administration ?? \"\",\n productPresentation: r.product_presentation ?? \"\",\n status: r.status ?? \"\",\n licensingStatus: r.licensure ?? \"\",\n referenceProductBla: r.ref_product_proper_name?.trim() ?? \"\",\n referenceProductProprietaryName: r.ref_prod_proprietary_name ?? \"\",\n biosimilar: (r.license_type ?? \"\") === \"351(k)\",\n interchangeable: (r.interchangeable_approval_date ?? \"\").trim() !== \"\",\n approvalDate: r.approval_date ?? r.date_of_first_licensure ?? \"\",\n }))\n\n this.purpleBookCache = {\n data: entries,\n fetchedAt: Date.now(),\n ttlMs: 7 * 24 * 60 * 60 * 1000, // 7 days\n }\n\n return entries\n }\n\n clearCache(): void {\n this.orangeBookCache = undefined\n this.purpleBookCache = undefined\n }\n}\n\n// Singleton instance\nexport const bulkDataClient = new BulkDataClient()\n"],"mappings":"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"}
@@ -1,13 +1,13 @@
1
1
  import debug from "debug";
2
2
 
3
3
  //#region src/utils/logger.d.ts
4
-
5
4
  declare const loggers: {
6
5
  core: debug.Debugger;
7
6
  api: debug.Debugger;
8
7
  tools: debug.Debugger;
9
8
  main: debug.Debugger;
10
9
  fastmcp: debug.Debugger;
10
+ bulk: debug.Debugger;
11
11
  };
12
12
  //#endregion
13
13
  export { loggers };
@@ -1,2 +1,2 @@
1
- import e from"debug";const t={core:e(`openfda-mcp:core`),api:e(`openfda-mcp:api`),tools:e(`openfda-mcp:tools`),main:e(`openfda-mcp:main`),fastmcp:e(`openfda-mcp:fastmcp`)};export{t as loggers};
1
+ import e from"debug";const t={core:e(`openfda-mcp:core`),api:e(`openfda-mcp:api`),tools:e(`openfda-mcp:tools`),main:e(`openfda-mcp:main`),fastmcp:e(`openfda-mcp:fastmcp`),bulk:e(`openfda-mcp:bulk`)};export{t as loggers};
2
2
  //# sourceMappingURL=logger.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"logger.js","names":[],"sources":["../../src/utils/logger.ts"],"sourcesContent":["/**\n * Logger utility for OpenFDA MCP Server\n * Uses debug module for namespace-based logging\n *\n * Enable with: DEBUG=openfda-mcp:* <command>\n */\n\nimport debug from \"debug\"\n\nexport const loggers = {\n core: debug(\"openfda-mcp:core\"),\n api: debug(\"openfda-mcp:api\"),\n tools: debug(\"openfda-mcp:tools\"),\n main: debug(\"openfda-mcp:main\"),\n fastmcp: debug(\"openfda-mcp:fastmcp\"),\n}\n"],"mappings":"qBASA,MAAa,EAAU,CACrB,KAAM,EAAM,mBAAmB,CAC/B,IAAK,EAAM,kBAAkB,CAC7B,MAAO,EAAM,oBAAoB,CACjC,KAAM,EAAM,mBAAmB,CAC/B,QAAS,EAAM,sBAAsB,CACtC"}
1
+ {"version":3,"file":"logger.js","names":[],"sources":["../../src/utils/logger.ts"],"sourcesContent":["/**\n * Logger utility for OpenFDA MCP Server\n * Uses debug module for namespace-based logging\n *\n * Enable with: DEBUG=openfda-mcp:* <command>\n */\n\nimport debug from \"debug\"\n\nexport const loggers = {\n core: debug(\"openfda-mcp:core\"),\n api: debug(\"openfda-mcp:api\"),\n tools: debug(\"openfda-mcp:tools\"),\n main: debug(\"openfda-mcp:main\"),\n fastmcp: debug(\"openfda-mcp:fastmcp\"),\n bulk: debug(\"openfda-mcp:bulk\"),\n}\n"],"mappings":"qBASA,MAAa,EAAU,CACrB,KAAM,EAAM,mBAAmB,CAC/B,IAAK,EAAM,kBAAkB,CAC7B,MAAO,EAAM,oBAAoB,CACjC,KAAM,EAAM,mBAAmB,CAC/B,QAAS,EAAM,sBAAsB,CACrC,KAAM,EAAM,mBAAmB,CAChC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openfda-mcp-server",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "MCP server for querying U.S. FDA public datasets - drugs, devices, adverse events, recalls, and more",
5
5
  "keywords": [
6
6
  "mcp",
@@ -13,22 +13,40 @@
13
13
  ],
14
14
  "author": "jordan.burke@gmail.com",
15
15
  "license": "MIT",
16
- "homepage": "https://github.com/jordanburke/openfda-mcp-server",
16
+ "homepage": "https://github.com/sapientsai/openfda-mcp-server",
17
17
  "repository": {
18
18
  "type": "git",
19
- "url": "https://github.com/jordanburke/openfda-mcp-server"
19
+ "url": "https://github.com/sapientsai/openfda-mcp-server"
20
+ },
21
+ "scripts": {
22
+ "validate": "ts-builds validate",
23
+ "format": "ts-builds format",
24
+ "format:check": "ts-builds format:check",
25
+ "lint": "ts-builds lint",
26
+ "lint:check": "ts-builds lint:check",
27
+ "typecheck": "ts-builds typecheck",
28
+ "test": "ts-builds test",
29
+ "test:watch": "ts-builds test:watch",
30
+ "test:coverage": "ts-builds test:coverage",
31
+ "build": "ts-builds build",
32
+ "dev": "ts-builds dev",
33
+ "serve:test": "tsx src/index.ts",
34
+ "serve:test:http": "tsx src/index.ts --transport http",
35
+ "prepublishOnly": "pnpm validate"
20
36
  },
21
37
  "dependencies": {
22
- "@jordanburke/fastmcp": "^3.26.700",
23
- "commander": "^14.0.2",
38
+ "commander": "^14.0.3",
24
39
  "debug": "^4.4.3",
25
- "zod": "^3.25.76"
40
+ "fastmcp": "^3.34.0",
41
+ "fflate": "^0.8.2",
42
+ "functype": "^0.49.0",
43
+ "zod": "^4.3.6"
26
44
  },
27
45
  "devDependencies": {
28
46
  "@types/debug": "^4.1.12",
29
- "@types/node": "^24.10.4",
30
- "ts-builds": "^2.1.0",
31
- "tsdown": "^0.18.4",
47
+ "@types/node": "^24.12.0",
48
+ "ts-builds": "^2.5.0",
49
+ "tsdown": "^0.21.2",
32
50
  "tsx": "^4.21.0"
33
51
  },
34
52
  "type": "module",
@@ -53,19 +71,5 @@
53
71
  "dist"
54
72
  ],
55
73
  "prettier": "ts-builds/prettier",
56
- "scripts": {
57
- "validate": "ts-builds validate",
58
- "format": "ts-builds format",
59
- "format:check": "ts-builds format:check",
60
- "lint": "ts-builds lint",
61
- "lint:check": "ts-builds lint:check",
62
- "typecheck": "ts-builds typecheck",
63
- "test": "ts-builds test",
64
- "test:watch": "ts-builds test:watch",
65
- "test:coverage": "ts-builds test:coverage",
66
- "build": "ts-builds build",
67
- "dev": "ts-builds dev",
68
- "serve:test": "tsx src/index.ts",
69
- "serve:test:http": "tsx src/index.ts --transport http"
70
- }
71
- }
74
+ "packageManager": "pnpm@10.32.1+sha512.a706938f0e89ac1456b6563eab4edf1d1faf3368d1191fc5c59790e96dc918e4456ab2e67d613de1043d2e8c81f87303e6b40d4ffeca9df15ef1ad567348f2be"
75
+ }
@@ -1,2 +0,0 @@
1
- import{loggers as e}from"./utils/logger.js";function t(e){"@babel/helpers - typeof";return t=typeof Symbol==`function`&&typeof Symbol.iterator==`symbol`?function(e){return typeof e}:function(e){return e&&typeof Symbol==`function`&&e.constructor===Symbol&&e!==Symbol.prototype?`symbol`:typeof e},t(e)}function n(e,n){if(t(e)!=`object`||!e)return e;var r=e[Symbol.toPrimitive];if(r!==void 0){var i=r.call(e,n||`default`);if(t(i)!=`object`)return i;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(n===`string`?String:Number)(e)}function r(e){var r=n(e,`string`);return t(r)==`symbol`?r:r+``}function i(e,t,n){return(t=r(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var a=class{constructor(){i(this,`apiKey`,void 0),i(this,`baseUrl`,void 0),this.apiKey=process.env.OPENFDA_API_KEY,this.baseUrl=`https://api.fda.gov`}buildSearchParams(e){let t=new URLSearchParams;e.search&&t.set(`search`,e.search),e.count&&t.set(`count`,e.count);let n=Math.min(e.limit??10,100);return t.set(`limit`,String(n)),e.skip!==void 0&&e.skip>0&&t.set(`skip`,String(e.skip)),this.apiKey&&t.set(`api_key`,this.apiKey),t}async request(t,n){let r=this.buildSearchParams(n),i=`${this.baseUrl}${t}?${r.toString()}`;e.api(`Request: ${i.replace(this.apiKey??``,`[REDACTED]`)}`);try{let t=await fetch(i);if(!t.ok){let e=await t.json().catch(()=>({}));if(t.status===429)throw Error(`Rate limit exceeded. Consider using an API key for higher limits.`);if(t.status===404)return{results:[]};throw t.status===400?Error(`Invalid request: ${e.error?.message??`Bad request parameters`}`):Error(`FDA API error: ${t.status} ${t.statusText}`)}let n=await t.json();return e.api(`Response: ${n.meta?.results?.total??0} total results`),n}catch(e){throw e instanceof Error?e:Error(`Failed to fetch from FDA API: ${String(e)}`)}}getRateLimitInfo(){return{authenticated:!!this.apiKey,rateLimit:this.apiKey?`240/minute, 120,000/hour`:`40/minute, 1,000/hour`}}async searchDrugAdverseEvents(e){return this.request(`/drug/event.json`,e)}async searchDrugLabels(e){return this.request(`/drug/label.json`,e)}async searchDrugNDC(e){return this.request(`/drug/ndc.json`,e)}async searchDrugEnforcement(e){return this.request(`/drug/enforcement.json`,e)}async searchDrugsFDA(e){return this.request(`/drug/drugsfda.json`,e)}async searchDrugShortages(e){return this.request(`/drug/shortages.json`,e)}async searchDevice510K(e){return this.request(`/device/510k.json`,e)}async searchDeviceClassifications(e){return this.request(`/device/classification.json`,e)}async searchDeviceAdverseEvents(e){return this.request(`/device/event.json`,e)}async searchDeviceEnforcement(e){return this.request(`/device/enforcement.json`,e)}};const o=new a;export{o as n,a as t};
2
- //# sourceMappingURL=api-client-BGnUXMwX.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"api-client-BGnUXMwX.js","names":[],"sources":["../src/utils/api-client.ts"],"sourcesContent":["/**\n * FDA API Client\n * HTTP client for interacting with FDA OpenAPI endpoints\n */\n\nimport type {\n Device510K,\n DeviceAdverseEvent,\n DeviceClassification,\n DeviceEnforcement,\n DrugAdverseEvent,\n DrugEnforcement,\n DrugLabel,\n DrugNDC,\n DrugsFDA,\n DrugShortage,\n FDAResponse,\n SearchParams,\n} from \"../types/fda.js\"\nimport { loggers } from \"./logger.js\"\n\nconst FDA_BASE_URL = \"https://api.fda.gov\"\nconst DEFAULT_LIMIT = 10\nconst MAX_LIMIT = 100\n\ntype FDAEndpoint =\n | \"/drug/event.json\"\n | \"/drug/label.json\"\n | \"/drug/ndc.json\"\n | \"/drug/enforcement.json\"\n | \"/drug/drugsfda.json\"\n | \"/drug/shortages.json\"\n | \"/device/510k.json\"\n | \"/device/classification.json\"\n | \"/device/event.json\"\n | \"/device/enforcement.json\"\n\nexport class FDAAPIClient {\n private apiKey: string | undefined\n private baseUrl: string\n\n constructor() {\n this.apiKey = process.env.OPENFDA_API_KEY\n this.baseUrl = FDA_BASE_URL\n }\n\n /**\n * Build URL search parameters for the FDA API\n */\n private buildSearchParams(params: SearchParams): URLSearchParams {\n const urlParams = new URLSearchParams()\n\n if (params.search) {\n urlParams.set(\"search\", params.search)\n }\n\n if (params.count) {\n urlParams.set(\"count\", params.count)\n }\n\n const limit = Math.min(params.limit ?? DEFAULT_LIMIT, MAX_LIMIT)\n urlParams.set(\"limit\", String(limit))\n\n if (params.skip !== undefined && params.skip > 0) {\n urlParams.set(\"skip\", String(params.skip))\n }\n\n if (this.apiKey) {\n urlParams.set(\"api_key\", this.apiKey)\n }\n\n return urlParams\n }\n\n /**\n * Make a request to an FDA API endpoint\n */\n private async request<T>(endpoint: FDAEndpoint, params: SearchParams): Promise<FDAResponse<T>> {\n const urlParams = this.buildSearchParams(params)\n const url = `${this.baseUrl}${endpoint}?${urlParams.toString()}`\n\n loggers.api(`Request: ${url.replace(this.apiKey ?? \"\", \"[REDACTED]\")}`)\n\n try {\n const response = await fetch(url)\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}))\n\n if (response.status === 429) {\n throw new Error(\"Rate limit exceeded. Consider using an API key for higher limits.\")\n }\n if (response.status === 404) {\n return { results: [] } // No results found\n }\n if (response.status === 400) {\n throw new Error(\n `Invalid request: ${(errorData as { error?: { message?: string } }).error?.message ?? \"Bad request parameters\"}`,\n )\n }\n\n throw new Error(`FDA API error: ${response.status} ${response.statusText}`)\n }\n\n const data = (await response.json()) as FDAResponse<T>\n loggers.api(`Response: ${data.meta?.results?.total ?? 0} total results`)\n return data\n } catch (error) {\n if (error instanceof Error) {\n throw error\n }\n throw new Error(`Failed to fetch from FDA API: ${String(error)}`)\n }\n }\n\n /**\n * Get rate limit info based on authentication status\n */\n getRateLimitInfo(): { authenticated: boolean; rateLimit: string } {\n return {\n authenticated: !!this.apiKey,\n rateLimit: this.apiKey ? \"240/minute, 120,000/hour\" : \"40/minute, 1,000/hour\",\n }\n }\n\n // Drug endpoints\n\n async searchDrugAdverseEvents(params: SearchParams): Promise<FDAResponse<DrugAdverseEvent>> {\n return this.request<DrugAdverseEvent>(\"/drug/event.json\", params)\n }\n\n async searchDrugLabels(params: SearchParams): Promise<FDAResponse<DrugLabel>> {\n return this.request<DrugLabel>(\"/drug/label.json\", params)\n }\n\n async searchDrugNDC(params: SearchParams): Promise<FDAResponse<DrugNDC>> {\n return this.request<DrugNDC>(\"/drug/ndc.json\", params)\n }\n\n async searchDrugEnforcement(params: SearchParams): Promise<FDAResponse<DrugEnforcement>> {\n return this.request<DrugEnforcement>(\"/drug/enforcement.json\", params)\n }\n\n async searchDrugsFDA(params: SearchParams): Promise<FDAResponse<DrugsFDA>> {\n return this.request<DrugsFDA>(\"/drug/drugsfda.json\", params)\n }\n\n async searchDrugShortages(params: SearchParams): Promise<FDAResponse<DrugShortage>> {\n return this.request<DrugShortage>(\"/drug/shortages.json\", params)\n }\n\n // Device endpoints\n\n async searchDevice510K(params: SearchParams): Promise<FDAResponse<Device510K>> {\n return this.request<Device510K>(\"/device/510k.json\", params)\n }\n\n async searchDeviceClassifications(params: SearchParams): Promise<FDAResponse<DeviceClassification>> {\n return this.request<DeviceClassification>(\"/device/classification.json\", params)\n }\n\n async searchDeviceAdverseEvents(params: SearchParams): Promise<FDAResponse<DeviceAdverseEvent>> {\n return this.request<DeviceAdverseEvent>(\"/device/event.json\", params)\n }\n\n async searchDeviceEnforcement(params: SearchParams): Promise<FDAResponse<DeviceEnforcement>> {\n return this.request<DeviceEnforcement>(\"/device/enforcement.json\", params)\n }\n}\n\n// Singleton instance\nexport const fdaAPIClient = new FDAAPIClient()\n"],"mappings":"guBAqCA,IAAa,EAAb,KAA0B,CAIxB,aAAc,QAHN,SAAA,IAAA,GAAA,QACA,UAAA,IAAA,GAAA,CAGN,KAAK,OAAS,QAAQ,IAAI,gBAC1B,KAAK,QAAU,sBAMjB,kBAA0B,EAAuC,CAC/D,IAAM,EAAY,IAAI,gBAElB,EAAO,QACT,EAAU,IAAI,SAAU,EAAO,OAAO,CAGpC,EAAO,OACT,EAAU,IAAI,QAAS,EAAO,MAAM,CAGtC,IAAM,EAAQ,KAAK,IAAI,EAAO,OAAS,GAAe,IAAU,CAWhE,OAVA,EAAU,IAAI,QAAS,OAAO,EAAM,CAAC,CAEjC,EAAO,OAAS,IAAA,IAAa,EAAO,KAAO,GAC7C,EAAU,IAAI,OAAQ,OAAO,EAAO,KAAK,CAAC,CAGxC,KAAK,QACP,EAAU,IAAI,UAAW,KAAK,OAAO,CAGhC,EAMT,MAAc,QAAW,EAAuB,EAA+C,CAC7F,IAAM,EAAY,KAAK,kBAAkB,EAAO,CAC1C,EAAM,GAAG,KAAK,UAAU,EAAS,GAAG,EAAU,UAAU,GAE9D,EAAQ,IAAI,YAAY,EAAI,QAAQ,KAAK,QAAU,GAAI,aAAa,GAAG,CAEvE,GAAI,CACF,IAAM,EAAW,MAAM,MAAM,EAAI,CAEjC,GAAI,CAAC,EAAS,GAAI,CAChB,IAAM,EAAY,MAAM,EAAS,MAAM,CAAC,WAAa,EAAE,EAAE,CAEzD,GAAI,EAAS,SAAW,IACtB,MAAU,MAAM,oEAAoE,CAEtF,GAAI,EAAS,SAAW,IACtB,MAAO,CAAE,QAAS,EAAE,CAAE,CAQxB,MANI,EAAS,SAAW,IACZ,MACR,oBAAqB,EAA+C,OAAO,SAAW,2BACvF,CAGO,MAAM,kBAAkB,EAAS,OAAO,GAAG,EAAS,aAAa,CAG7E,IAAM,EAAQ,MAAM,EAAS,MAAM,CAEnC,OADA,EAAQ,IAAI,aAAa,EAAK,MAAM,SAAS,OAAS,EAAE,gBAAgB,CACjE,QACA,EAAO,CAId,MAHI,aAAiB,MACb,EAEE,MAAM,iCAAiC,OAAO,EAAM,GAAG,EAOrE,kBAAkE,CAChE,MAAO,CACL,cAAe,CAAC,CAAC,KAAK,OACtB,UAAW,KAAK,OAAS,2BAA6B,wBACvD,CAKH,MAAM,wBAAwB,EAA8D,CAC1F,OAAO,KAAK,QAA0B,mBAAoB,EAAO,CAGnE,MAAM,iBAAiB,EAAuD,CAC5E,OAAO,KAAK,QAAmB,mBAAoB,EAAO,CAG5D,MAAM,cAAc,EAAqD,CACvE,OAAO,KAAK,QAAiB,iBAAkB,EAAO,CAGxD,MAAM,sBAAsB,EAA6D,CACvF,OAAO,KAAK,QAAyB,yBAA0B,EAAO,CAGxE,MAAM,eAAe,EAAsD,CACzE,OAAO,KAAK,QAAkB,sBAAuB,EAAO,CAG9D,MAAM,oBAAoB,EAA0D,CAClF,OAAO,KAAK,QAAsB,uBAAwB,EAAO,CAKnE,MAAM,iBAAiB,EAAwD,CAC7E,OAAO,KAAK,QAAoB,oBAAqB,EAAO,CAG9D,MAAM,4BAA4B,EAAkE,CAClG,OAAO,KAAK,QAA8B,8BAA+B,EAAO,CAGlF,MAAM,0BAA0B,EAAgE,CAC9F,OAAO,KAAK,QAA4B,qBAAsB,EAAO,CAGvE,MAAM,wBAAwB,EAA+D,CAC3F,OAAO,KAAK,QAA2B,2BAA4B,EAAO,GAK9E,MAAa,EAAe,IAAI"}
@@ -1,2 +0,0 @@
1
- import{loggers as e}from"./utils/logger.js";import{n as t}from"./api-client-BGnUXMwX.js";function n(e,t,n){if(!(!t&&!n))return`${e}:[${t?.replace(/-/g,``)??`*`}+TO+${n?.replace(/-/g,``)??`*`}]`}function r(e){return e.replace(/[+\-&|!(){}[\]^"~*?:\\]/g,`\\$&`).replace(/\s+/g,`+`)}function i(e){let t=e.filter(e=>e.value!==void 0&&e.value.trim()!==``);return t.length===0?``:t.map(e=>`${e.field}:"${r(e.value)}"`).join(`+AND+`)}function a(e,t=200){if(e)return e.length>t?e.substring(0,t)+`...`:e}function o(e){return{kNumber:e.k_number,deviceName:e.device_name??e.openfda?.device_name,applicant:e.applicant,productCode:e.product_code,clearanceType:e.clearance_type,decisionCode:e.decision_code,decisionDescription:e.decision_description,decisionDate:e.decision_date,dateReceived:e.date_received,city:e.city,state:e.state,country:e.country_code}}async function s(r){e.tools(`searchDevice510K`,r);try{let e={search:[i([{field:`device_name`,value:r.deviceName},{field:`applicant`,value:r.applicant},{field:`product_code`,value:r.productCode},{field:`clearance_type`,value:r.clearanceType}]),n(`decision_date`,r.decisionDateFrom,r.decisionDateTo)].filter(Boolean).join(`+AND+`)||void 0,limit:r.limit,skip:r.skip},a=await t.searchDevice510K(e),s=a.results??[];return{success:!0,data:s.map(o),totalResults:a.meta?.results?.total,displayedResults:s.length,searchParams:e,apiUsage:t.getRateLimitInfo()}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}function c(e){return{deviceName:e.device_name,deviceClass:e.device_class,definition:a(e.definition),medicalSpecialty:e.medical_specialty,medicalSpecialtyDescription:e.medical_specialty_description,productCode:e.product_code,regulationNumber:e.regulation_number,gmpExempt:e.gmp_exempt_flag===`Y`,implant:e.implant_flag===`Y`,lifeSustaining:e.life_sustain_support_flag===`Y`}}async function l(n){e.tools(`searchDeviceClassifications`,n);try{let e={search:i([{field:`device_name`,value:n.deviceName},{field:`device_class`,value:n.deviceClass},{field:`medical_specialty`,value:n.medicalSpecialty},{field:`product_code`,value:n.productCode},{field:`regulation_number`,value:n.regulationNumber}])||void 0,limit:n.limit,skip:n.skip},r=await t.searchDeviceClassifications(e),a=r.results??[];return{success:!0,data:a.map(c),totalResults:r.meta?.results?.total,displayedResults:a.length,searchParams:e,apiUsage:t.getRateLimitInfo()}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}function u(e){return{reportNumber:e.report_number,dateOfEvent:e.date_of_event,dateReceived:e.date_received,eventType:e.event_type,adverseEventFlag:e.adverse_event_flag===`Y`,productProblemFlag:e.product_problem_flag===`Y`,devices:e.device?.slice(0,3).map(e=>({brandName:e.brand_name,genericName:e.generic_name,manufacturerName:e.manufacturer_d_name,modelNumber:e.model_number,productCode:e.device_report_product_code,deviceClass:e.openfda?.device_class}))??[],mdrText:e.mdr_text?.slice(0,2).map(e=>({textType:e.text_type_code,text:a(e.text,300)}))??[]}}async function d(r){e.tools(`searchDeviceAdverseEvents`,r);try{let e={search:[i([{field:`device.generic_name`,value:r.deviceName},{field:`device.brand_name`,value:r.brandName},{field:`device.manufacturer_d_name`,value:r.manufacturerName},{field:`event_type`,value:r.eventType}]),n(`date_received`,r.dateFrom,r.dateTo)].filter(Boolean).join(`+AND+`)||void 0,limit:r.limit,skip:r.skip},a=await t.searchDeviceAdverseEvents(e),o=a.results??[];return{success:!0,data:o.map(u),totalResults:a.meta?.results?.total,displayedResults:o.length,searchParams:e,apiUsage:t.getRateLimitInfo()}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}function f(e){return{recallNumber:e.recall_number,recallingFirm:e.recalling_firm,classification:e.classification,status:e.status,productDescription:a(e.product_description),reasonForRecall:a(e.reason_for_recall),recallInitiationDate:e.recall_initiation_date,distributionPattern:a(e.distribution_pattern),city:e.city,state:e.state,deviceName:e.openfda?.device_name,deviceClass:e.openfda?.device_class}}async function p(r){e.tools(`searchDeviceEnforcement`,r);try{let e={search:[i([{field:`recalling_firm`,value:r.recallingFirm},{field:`product_description`,value:r.productDescription},{field:`classification`,value:r.classification},{field:`status`,value:r.status}]),n(`recall_initiation_date`,r.dateFrom,r.dateTo)].filter(Boolean).join(`+AND+`)||void 0,limit:r.limit,skip:r.skip},a=await t.searchDeviceEnforcement(e),o=a.results??[];return{success:!0,data:o.map(f),totalResults:a.meta?.results?.total,displayedResults:o.length,searchParams:e,apiUsage:t.getRateLimitInfo()}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}export{p as i,d as n,l as r,s as t};
2
- //# sourceMappingURL=device-handlers-D01LfIJk.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"device-handlers-D01LfIJk.js","names":["searchParams: SearchParams"],"sources":["../src/handlers/device-handlers.ts"],"sourcesContent":["/**\n * Device Handlers\n * Query handlers for FDA device-related endpoints\n */\n\nimport type {\n Device510K,\n DeviceAdverseEvent,\n DeviceClassification,\n DeviceEnforcement,\n FDAToolResponse,\n SearchParams,\n} from \"../types/fda.js\"\nimport { fdaAPIClient } from \"../utils/api-client.js\"\nimport { loggers } from \"../utils/logger.js\"\n\n// Helper to build date range query\nfunction buildDateQuery(field: string, dateFrom?: string, dateTo?: string): string | undefined {\n if (!dateFrom && !dateTo) return undefined\n\n // FDA date format is YYYYMMDD\n const from = dateFrom?.replace(/-/g, \"\") ?? \"*\"\n const to = dateTo?.replace(/-/g, \"\") ?? \"*\"\n\n return `${field}:[${from}+TO+${to}]`\n}\n\n// Helper to escape special characters in search terms\nfunction escapeSearchTerm(term: string): string {\n return term.replace(/[+\\-&|!(){}[\\]^\"~*?:\\\\]/g, \"\\\\$&\").replace(/\\s+/g, \"+\")\n}\n\n// Helper to build a search query from multiple terms\nfunction buildSearchQuery(terms: Array<{ field: string; value?: string }>): string {\n const validTerms = terms.filter((t) => t.value !== undefined && t.value.trim() !== \"\")\n if (validTerms.length === 0) return \"\"\n\n return validTerms.map((t) => `${t.field}:\"${escapeSearchTerm(t.value!)}\"`).join(\"+AND+\")\n}\n\n// Format truncated text\nfunction truncateText(text: string | undefined, maxLength = 200): string | undefined {\n if (!text) return undefined\n return text.length > maxLength ? text.substring(0, maxLength) + \"...\" : text\n}\n\n// Device 510(k) Handler\nexport type Device510KParams = {\n deviceName?: string\n applicant?: string\n productCode?: string\n clearanceType?: string\n decisionDateFrom?: string\n decisionDateTo?: string\n limit?: number\n skip?: number\n}\n\ntype FormattedDevice510K = {\n kNumber: string | undefined\n deviceName: string | undefined\n applicant: string | undefined\n productCode: string | undefined\n clearanceType: string | undefined\n decisionCode: string | undefined\n decisionDescription: string | undefined\n decisionDate: string | undefined\n dateReceived: string | undefined\n city: string | undefined\n state: string | undefined\n country: string | undefined\n}\n\nfunction formatDevice510K(device: Device510K): FormattedDevice510K {\n return {\n kNumber: device.k_number,\n deviceName: device.device_name ?? device.openfda?.device_name,\n applicant: device.applicant,\n productCode: device.product_code,\n clearanceType: device.clearance_type,\n decisionCode: device.decision_code,\n decisionDescription: device.decision_description,\n decisionDate: device.decision_date,\n dateReceived: device.date_received,\n city: device.city,\n state: device.state,\n country: device.country_code,\n }\n}\n\nexport async function handleSearchDevice510K(\n params: Device510KParams,\n): Promise<FDAToolResponse<FormattedDevice510K[]>> {\n loggers.tools(\"searchDevice510K\", params)\n\n try {\n const searchTerms: Array<{ field: string; value?: string }> = [\n { field: \"device_name\", value: params.deviceName },\n { field: \"applicant\", value: params.applicant },\n { field: \"product_code\", value: params.productCode },\n { field: \"clearance_type\", value: params.clearanceType },\n ]\n\n const searchQuery = buildSearchQuery(searchTerms)\n const dateQuery = buildDateQuery(\"decision_date\", params.decisionDateFrom, params.decisionDateTo)\n const fullQuery = [searchQuery, dateQuery].filter(Boolean).join(\"+AND+\")\n\n const searchParams: SearchParams = {\n search: fullQuery || undefined,\n limit: params.limit,\n skip: params.skip,\n }\n\n const response = await fdaAPIClient.searchDevice510K(searchParams)\n const results = response.results ?? []\n\n return {\n success: true,\n data: results.map(formatDevice510K),\n totalResults: response.meta?.results?.total,\n displayedResults: results.length,\n searchParams,\n apiUsage: fdaAPIClient.getRateLimitInfo(),\n }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n }\n }\n}\n\n// Device Classification Handler\nexport type DeviceClassificationParams = {\n deviceName?: string\n deviceClass?: \"1\" | \"2\" | \"3\"\n medicalSpecialty?: string\n productCode?: string\n regulationNumber?: string\n limit?: number\n skip?: number\n}\n\ntype FormattedDeviceClassification = {\n deviceName: string | undefined\n deviceClass: string | undefined\n definition: string | undefined\n medicalSpecialty: string | undefined\n medicalSpecialtyDescription: string | undefined\n productCode: string | undefined\n regulationNumber: string | undefined\n gmpExempt: boolean\n implant: boolean\n lifeSustaining: boolean\n}\n\nfunction formatDeviceClassification(classification: DeviceClassification): FormattedDeviceClassification {\n return {\n deviceName: classification.device_name,\n deviceClass: classification.device_class,\n definition: truncateText(classification.definition),\n medicalSpecialty: classification.medical_specialty,\n medicalSpecialtyDescription: classification.medical_specialty_description,\n productCode: classification.product_code,\n regulationNumber: classification.regulation_number,\n gmpExempt: classification.gmp_exempt_flag === \"Y\",\n implant: classification.implant_flag === \"Y\",\n lifeSustaining: classification.life_sustain_support_flag === \"Y\",\n }\n}\n\nexport async function handleSearchDeviceClassifications(\n params: DeviceClassificationParams,\n): Promise<FDAToolResponse<FormattedDeviceClassification[]>> {\n loggers.tools(\"searchDeviceClassifications\", params)\n\n try {\n const searchTerms: Array<{ field: string; value?: string }> = [\n { field: \"device_name\", value: params.deviceName },\n { field: \"device_class\", value: params.deviceClass },\n { field: \"medical_specialty\", value: params.medicalSpecialty },\n { field: \"product_code\", value: params.productCode },\n { field: \"regulation_number\", value: params.regulationNumber },\n ]\n\n const searchQuery = buildSearchQuery(searchTerms)\n\n const searchParams: SearchParams = {\n search: searchQuery || undefined,\n limit: params.limit,\n skip: params.skip,\n }\n\n const response = await fdaAPIClient.searchDeviceClassifications(searchParams)\n const results = response.results ?? []\n\n return {\n success: true,\n data: results.map(formatDeviceClassification),\n totalResults: response.meta?.results?.total,\n displayedResults: results.length,\n searchParams,\n apiUsage: fdaAPIClient.getRateLimitInfo(),\n }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n }\n }\n}\n\n// Device Adverse Events (MDR) Handler\nexport type DeviceAdverseEventsParams = {\n deviceName?: string\n brandName?: string\n manufacturerName?: string\n eventType?: \"Injury\" | \"Malfunction\" | \"Death\" | \"Other\"\n dateFrom?: string\n dateTo?: string\n limit?: number\n skip?: number\n}\n\ntype FormattedDeviceAdverseEvent = {\n reportNumber: string | undefined\n dateOfEvent: string | undefined\n dateReceived: string | undefined\n eventType: string | undefined\n adverseEventFlag: boolean\n productProblemFlag: boolean\n devices: Array<{\n brandName: string | undefined\n genericName: string | undefined\n manufacturerName: string | undefined\n modelNumber: string | undefined\n productCode: string | undefined\n deviceClass: string | undefined\n }>\n mdrText: Array<{\n textType: string | undefined\n text: string | undefined\n }>\n}\n\nfunction formatDeviceAdverseEvent(event: DeviceAdverseEvent): FormattedDeviceAdverseEvent {\n return {\n reportNumber: event.report_number,\n dateOfEvent: event.date_of_event,\n dateReceived: event.date_received,\n eventType: event.event_type,\n adverseEventFlag: event.adverse_event_flag === \"Y\",\n productProblemFlag: event.product_problem_flag === \"Y\",\n devices:\n event.device?.slice(0, 3).map((d) => ({\n brandName: d.brand_name,\n genericName: d.generic_name,\n manufacturerName: d.manufacturer_d_name,\n modelNumber: d.model_number,\n productCode: d.device_report_product_code,\n deviceClass: d.openfda?.device_class,\n })) ?? [],\n mdrText:\n event.mdr_text?.slice(0, 2).map((t) => ({\n textType: t.text_type_code,\n text: truncateText(t.text, 300),\n })) ?? [],\n }\n}\n\nexport async function handleSearchDeviceAdverseEvents(\n params: DeviceAdverseEventsParams,\n): Promise<FDAToolResponse<FormattedDeviceAdverseEvent[]>> {\n loggers.tools(\"searchDeviceAdverseEvents\", params)\n\n try {\n const searchTerms: Array<{ field: string; value?: string }> = [\n { field: \"device.generic_name\", value: params.deviceName },\n { field: \"device.brand_name\", value: params.brandName },\n { field: \"device.manufacturer_d_name\", value: params.manufacturerName },\n { field: \"event_type\", value: params.eventType },\n ]\n\n const searchQuery = buildSearchQuery(searchTerms)\n const dateQuery = buildDateQuery(\"date_received\", params.dateFrom, params.dateTo)\n const fullQuery = [searchQuery, dateQuery].filter(Boolean).join(\"+AND+\")\n\n const searchParams: SearchParams = {\n search: fullQuery || undefined,\n limit: params.limit,\n skip: params.skip,\n }\n\n const response = await fdaAPIClient.searchDeviceAdverseEvents(searchParams)\n const results = response.results ?? []\n\n return {\n success: true,\n data: results.map(formatDeviceAdverseEvent),\n totalResults: response.meta?.results?.total,\n displayedResults: results.length,\n searchParams,\n apiUsage: fdaAPIClient.getRateLimitInfo(),\n }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n }\n }\n}\n\n// Device Enforcement (Recalls) Handler\nexport type DeviceEnforcementParams = {\n recallingFirm?: string\n productDescription?: string\n classification?: \"Class I\" | \"Class II\" | \"Class III\"\n status?: \"Ongoing\" | \"Completed\" | \"Terminated\" | \"Pending\"\n dateFrom?: string\n dateTo?: string\n limit?: number\n skip?: number\n}\n\ntype FormattedDeviceEnforcement = {\n recallNumber: string | undefined\n recallingFirm: string | undefined\n classification: string | undefined\n status: string | undefined\n productDescription: string | undefined\n reasonForRecall: string | undefined\n recallInitiationDate: string | undefined\n distributionPattern: string | undefined\n city: string | undefined\n state: string | undefined\n deviceName: string | undefined\n deviceClass: string | undefined\n}\n\nfunction formatDeviceEnforcement(recall: DeviceEnforcement): FormattedDeviceEnforcement {\n return {\n recallNumber: recall.recall_number,\n recallingFirm: recall.recalling_firm,\n classification: recall.classification,\n status: recall.status,\n productDescription: truncateText(recall.product_description),\n reasonForRecall: truncateText(recall.reason_for_recall),\n recallInitiationDate: recall.recall_initiation_date,\n distributionPattern: truncateText(recall.distribution_pattern),\n city: recall.city,\n state: recall.state,\n deviceName: recall.openfda?.device_name,\n deviceClass: recall.openfda?.device_class,\n }\n}\n\nexport async function handleSearchDeviceEnforcement(\n params: DeviceEnforcementParams,\n): Promise<FDAToolResponse<FormattedDeviceEnforcement[]>> {\n loggers.tools(\"searchDeviceEnforcement\", params)\n\n try {\n const searchTerms: Array<{ field: string; value?: string }> = [\n { field: \"recalling_firm\", value: params.recallingFirm },\n { field: \"product_description\", value: params.productDescription },\n { field: \"classification\", value: params.classification },\n { field: \"status\", value: params.status },\n ]\n\n const searchQuery = buildSearchQuery(searchTerms)\n const dateQuery = buildDateQuery(\"recall_initiation_date\", params.dateFrom, params.dateTo)\n const fullQuery = [searchQuery, dateQuery].filter(Boolean).join(\"+AND+\")\n\n const searchParams: SearchParams = {\n search: fullQuery || undefined,\n limit: params.limit,\n skip: params.skip,\n }\n\n const response = await fdaAPIClient.searchDeviceEnforcement(searchParams)\n const results = response.results ?? []\n\n return {\n success: true,\n data: results.map(formatDeviceEnforcement),\n totalResults: response.meta?.results?.total,\n displayedResults: results.length,\n searchParams,\n apiUsage: fdaAPIClient.getRateLimitInfo(),\n }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n }\n }\n}\n"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{loggers as e}from"./utils/logger.js";import{n as t}from"./api-client-BGnUXMwX.js";function n(e,t,n){if(!(!t&&!n))return`${e}:[${t?.replace(/-/g,``)??`*`}+TO+${n?.replace(/-/g,``)??`*`}]`}function r(e){return e.replace(/[+\-&|!(){}[\]^"~*?:\\]/g,`\\$&`).replace(/\s+/g,`+`)}function i(e){let t=e.filter(e=>e.value!==void 0&&e.value.trim()!==``);return t.length===0?``:t.map(e=>`${e.field}:"${r(e.value)}"`).join(`+AND+`)}function a(e,t=200){if(e)return e.length>t?e.substring(0,t)+`...`:e}function o(e){return{reportId:e.safetyreportid,receiveDate:e.receivedate,serious:e.serious===`1`,drugs:e.patient?.drug?.slice(0,3).map(e=>({name:e.medicinalproduct??e.activesubstance?.activesubstancename,indication:e.drugindication,route:e.drugadministrationroute}))??[],reactions:e.patient?.reaction?.slice(0,3).map(e=>({reaction:e.reactionmeddrapt,outcome:e.reactionoutcome}))??[],patient:{age:e.patient?.patientonsetage?`${e.patient.patientonsetage} ${e.patient.patientonsetageunit??``}`:void 0,sex:e.patient?.patientsex===`1`?`Male`:e.patient?.patientsex===`2`?`Female`:void 0,weight:e.patient?.patientweight?`${e.patient.patientweight} kg`:void 0}}}async function s(r){e.tools(`searchDrugAdverseEvents`,r);try{let e=[{field:`patient.drug.medicinalproduct`,value:r.drugName},{field:`patient.reaction.reactionmeddrapt`,value:r.reaction},{field:`patient.drug.openfda.manufacturer_name`,value:r.manufacturer}];r.serious!==void 0&&e.push({field:`serious`,value:r.serious?`1`:`2`});let a={search:[i(e),n(`receivedate`,r.dateFrom,r.dateTo)].filter(Boolean).join(`+AND+`)||void 0,limit:r.limit,skip:r.skip},s=await t.searchDrugAdverseEvents(a),c=s.results??[];return{success:!0,data:c.map(o),totalResults:s.meta?.results?.total,displayedResults:c.length,searchParams:a,apiUsage:t.getRateLimitInfo()}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}function c(e){return{brandName:e.openfda?.brand_name?.[0],genericName:e.openfda?.generic_name?.[0],manufacturer:e.openfda?.manufacturer_name?.[0],activeIngredients:e.openfda?.substance_name?.slice(0,5)??[],indications:a(e.indications_and_usage?.[0]),warnings:a(e.warnings?.[0]),dosageAndAdministration:a(e.dosage_and_administration?.[0]),route:e.openfda?.route?.slice(0,3)??[]}}async function l(n){e.tools(`searchDrugLabels`,n);try{let e={search:i([{field:`openfda.brand_name`,value:n.drugName},{field:`indications_and_usage`,value:n.indication},{field:`openfda.substance_name`,value:n.activeIngredient},{field:`openfda.route`,value:n.route}])||void 0,limit:n.limit,skip:n.skip},r=await t.searchDrugLabels(e),a=r.results??[];return{success:!0,data:a.map(c),totalResults:r.meta?.results?.total,displayedResults:a.length,searchParams:e,apiUsage:t.getRateLimitInfo()}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}function u(e){return{productNdc:e.product_ndc,brandName:e.brand_name,genericName:e.generic_name,labelerName:e.labeler_name,dosageForm:e.dosage_form,route:e.route??[],activeIngredients:e.active_ingredients?.slice(0,3).map(e=>({name:e.name,strength:e.strength}))??[],marketingStartDate:e.marketing_start_date,productType:e.product_type}}async function d(n){e.tools(`searchDrugNDC`,n);try{let e={search:i([{field:`product_ndc`,value:n.productNdc},{field:`brand_name`,value:n.brandName},{field:`generic_name`,value:n.genericName},{field:`labeler_name`,value:n.labelerName},{field:`dosage_form`,value:n.dosageForm},{field:`route`,value:n.route}])||void 0,limit:n.limit,skip:n.skip},r=await t.searchDrugNDC(e),a=r.results??[];return{success:!0,data:a.map(u),totalResults:r.meta?.results?.total,displayedResults:a.length,searchParams:e,apiUsage:t.getRateLimitInfo()}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}function f(e){return{recallNumber:e.recall_number,recallingFirm:e.recalling_firm,classification:e.classification,status:e.status,productDescription:a(e.product_description),reasonForRecall:a(e.reason_for_recall),recallInitiationDate:e.recall_initiation_date,distributionPattern:a(e.distribution_pattern),city:e.city,state:e.state}}async function p(r){e.tools(`searchDrugEnforcement`,r);try{let e={search:[i([{field:`recalling_firm`,value:r.recallingFirm},{field:`classification`,value:r.classification},{field:`status`,value:r.status},{field:`state`,value:r.state}]),n(`recall_initiation_date`,r.dateFrom,r.dateTo)].filter(Boolean).join(`+AND+`)||void 0,limit:r.limit,skip:r.skip},a=await t.searchDrugEnforcement(e),o=a.results??[];return{success:!0,data:o.map(f),totalResults:a.meta?.results?.total,displayedResults:o.length,searchParams:e,apiUsage:t.getRateLimitInfo()}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}function m(e){let t=e.submissions?.[0];return{applicationNumber:e.application_number,sponsorName:e.sponsor_name,products:e.products?.slice(0,3).map(e=>({brandName:e.brand_name,dosageForm:e.dosage_form,route:e.route,marketingStatus:e.marketing_status,activeIngredients:e.active_ingredients?.slice(0,3).map(e=>({name:e.name,strength:e.strength}))??[]}))??[],latestSubmission:t?{type:t.submission_type,status:t.submission_status,statusDate:t.submission_status_date}:void 0}}async function h(n){e.tools(`searchDrugsFDA`,n);try{let e={search:i([{field:`sponsor_name`,value:n.sponsorName},{field:`application_number`,value:n.applicationNumber},{field:`products.brand_name`,value:n.brandName},{field:`products.marketing_status`,value:n.marketingStatus}])||void 0,limit:n.limit,skip:n.skip},r=await t.searchDrugsFDA(e),a=r.results??[];return{success:!0,data:a.map(m),totalResults:r.meta?.results?.total,displayedResults:a.length,searchParams:e,apiUsage:t.getRateLimitInfo()}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}function g(e){return{genericName:e.generic_name,proprietaryName:e.proprietary_name,status:e.status,description:a(e.description),initialPostingDate:e.initial_posting_date,resolvedShortageDate:e.resolved_shortage_date}}async function _(n){e.tools(`searchDrugShortages`,n);try{let e={search:i([{field:`generic_name`,value:n.genericName},{field:`status`,value:n.status}])||void 0,limit:n.limit,skip:n.skip},r=await t.searchDrugShortages(e),a=r.results??[];return{success:!0,data:a.map(g),totalResults:r.meta?.results?.total,displayedResults:a.length,searchParams:e,apiUsage:t.getRateLimitInfo()}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}export{_ as a,d as i,p as n,h as o,l as r,s as t};
2
- //# sourceMappingURL=drug-handlers-Fz_6NLl5.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"drug-handlers-Fz_6NLl5.js","names":["searchTerms: Array<{ field: string; value?: string }>","searchParams: SearchParams"],"sources":["../src/handlers/drug-handlers.ts"],"sourcesContent":["/**\n * Drug Handlers\n * Query handlers for FDA drug-related endpoints\n */\n\nimport type {\n DrugAdverseEvent,\n DrugEnforcement,\n DrugLabel,\n DrugNDC,\n DrugsFDA,\n DrugShortage,\n FDAToolResponse,\n SearchParams,\n} from \"../types/fda.js\"\nimport { fdaAPIClient } from \"../utils/api-client.js\"\nimport { loggers } from \"../utils/logger.js\"\n\n// Helper to build date range query\nfunction buildDateQuery(field: string, dateFrom?: string, dateTo?: string): string | undefined {\n if (!dateFrom && !dateTo) return undefined\n\n // FDA date format is YYYYMMDD\n const from = dateFrom?.replace(/-/g, \"\") ?? \"*\"\n const to = dateTo?.replace(/-/g, \"\") ?? \"*\"\n\n return `${field}:[${from}+TO+${to}]`\n}\n\n// Helper to escape special characters in search terms\nfunction escapeSearchTerm(term: string): string {\n // Escape special characters that have meaning in FDA's search syntax\n return term.replace(/[+\\-&|!(){}[\\]^\"~*?:\\\\]/g, \"\\\\$&\").replace(/\\s+/g, \"+\")\n}\n\n// Helper to build a search query from multiple terms\nfunction buildSearchQuery(terms: Array<{ field: string; value?: string }>): string {\n const validTerms = terms.filter((t) => t.value !== undefined && t.value.trim() !== \"\")\n if (validTerms.length === 0) return \"\"\n\n return validTerms.map((t) => `${t.field}:\"${escapeSearchTerm(t.value!)}\"`).join(\"+AND+\")\n}\n\n// Format truncated text\nfunction truncateText(text: string | undefined, maxLength = 200): string | undefined {\n if (!text) return undefined\n return text.length > maxLength ? text.substring(0, maxLength) + \"...\" : text\n}\n\n// Drug Adverse Events Handler\nexport type DrugAdverseEventsParams = {\n drugName?: string\n reaction?: string\n manufacturer?: string\n serious?: boolean\n dateFrom?: string\n dateTo?: string\n limit?: number\n skip?: number\n}\n\ntype FormattedDrugAdverseEvent = {\n reportId: string | undefined\n receiveDate: string | undefined\n serious: boolean\n drugs: Array<{\n name: string | undefined\n indication: string | undefined\n route: string | undefined\n }>\n reactions: Array<{\n reaction: string | undefined\n outcome: string | undefined\n }>\n patient: {\n age: string | undefined\n sex: string | undefined\n weight: string | undefined\n }\n}\n\nfunction formatDrugAdverseEvent(event: DrugAdverseEvent): FormattedDrugAdverseEvent {\n return {\n reportId: event.safetyreportid,\n receiveDate: event.receivedate,\n serious: event.serious === \"1\",\n drugs:\n event.patient?.drug?.slice(0, 3).map((d) => ({\n name: d.medicinalproduct ?? d.activesubstance?.activesubstancename,\n indication: d.drugindication,\n route: d.drugadministrationroute,\n })) ?? [],\n reactions:\n event.patient?.reaction?.slice(0, 3).map((r) => ({\n reaction: r.reactionmeddrapt,\n outcome: r.reactionoutcome,\n })) ?? [],\n patient: {\n age: event.patient?.patientonsetage\n ? `${event.patient.patientonsetage} ${event.patient.patientonsetageunit ?? \"\"}`\n : undefined,\n sex: event.patient?.patientsex === \"1\" ? \"Male\" : event.patient?.patientsex === \"2\" ? \"Female\" : undefined,\n weight: event.patient?.patientweight ? `${event.patient.patientweight} kg` : undefined,\n },\n }\n}\n\nexport async function handleSearchDrugAdverseEvents(\n params: DrugAdverseEventsParams,\n): Promise<FDAToolResponse<FormattedDrugAdverseEvent[]>> {\n loggers.tools(\"searchDrugAdverseEvents\", params)\n\n try {\n const searchTerms: Array<{ field: string; value?: string }> = [\n { field: \"patient.drug.medicinalproduct\", value: params.drugName },\n { field: \"patient.reaction.reactionmeddrapt\", value: params.reaction },\n { field: \"patient.drug.openfda.manufacturer_name\", value: params.manufacturer },\n ]\n\n if (params.serious !== undefined) {\n searchTerms.push({ field: \"serious\", value: params.serious ? \"1\" : \"2\" })\n }\n\n const searchQuery = buildSearchQuery(searchTerms)\n const dateQuery = buildDateQuery(\"receivedate\", params.dateFrom, params.dateTo)\n const fullQuery = [searchQuery, dateQuery].filter(Boolean).join(\"+AND+\")\n\n const searchParams: SearchParams = {\n search: fullQuery || undefined,\n limit: params.limit,\n skip: params.skip,\n }\n\n const response = await fdaAPIClient.searchDrugAdverseEvents(searchParams)\n const results = response.results ?? []\n\n return {\n success: true,\n data: results.map(formatDrugAdverseEvent),\n totalResults: response.meta?.results?.total,\n displayedResults: results.length,\n searchParams,\n apiUsage: fdaAPIClient.getRateLimitInfo(),\n }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n }\n }\n}\n\n// Drug Labels Handler\nexport type DrugLabelsParams = {\n drugName?: string\n indication?: string\n activeIngredient?: string\n route?: string\n limit?: number\n skip?: number\n}\n\ntype FormattedDrugLabel = {\n brandName: string | undefined\n genericName: string | undefined\n manufacturer: string | undefined\n activeIngredients: string[]\n indications: string | undefined\n warnings: string | undefined\n dosageAndAdministration: string | undefined\n route: string[]\n}\n\nfunction formatDrugLabel(label: DrugLabel): FormattedDrugLabel {\n return {\n brandName: label.openfda?.brand_name?.[0],\n genericName: label.openfda?.generic_name?.[0],\n manufacturer: label.openfda?.manufacturer_name?.[0],\n activeIngredients: label.openfda?.substance_name?.slice(0, 5) ?? [],\n indications: truncateText(label.indications_and_usage?.[0]),\n warnings: truncateText(label.warnings?.[0]),\n dosageAndAdministration: truncateText(label.dosage_and_administration?.[0]),\n route: label.openfda?.route?.slice(0, 3) ?? [],\n }\n}\n\nexport async function handleSearchDrugLabels(params: DrugLabelsParams): Promise<FDAToolResponse<FormattedDrugLabel[]>> {\n loggers.tools(\"searchDrugLabels\", params)\n\n try {\n const searchTerms: Array<{ field: string; value?: string }> = [\n { field: \"openfda.brand_name\", value: params.drugName },\n { field: \"indications_and_usage\", value: params.indication },\n { field: \"openfda.substance_name\", value: params.activeIngredient },\n { field: \"openfda.route\", value: params.route },\n ]\n\n const searchQuery = buildSearchQuery(searchTerms)\n\n const searchParams: SearchParams = {\n search: searchQuery || undefined,\n limit: params.limit,\n skip: params.skip,\n }\n\n const response = await fdaAPIClient.searchDrugLabels(searchParams)\n const results = response.results ?? []\n\n return {\n success: true,\n data: results.map(formatDrugLabel),\n totalResults: response.meta?.results?.total,\n displayedResults: results.length,\n searchParams,\n apiUsage: fdaAPIClient.getRateLimitInfo(),\n }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n }\n }\n}\n\n// Drug NDC Handler\nexport type DrugNDCParams = {\n productNdc?: string\n brandName?: string\n genericName?: string\n labelerName?: string\n dosageForm?: string\n route?: string\n limit?: number\n skip?: number\n}\n\ntype FormattedDrugNDC = {\n productNdc: string | undefined\n brandName: string | undefined\n genericName: string | undefined\n labelerName: string | undefined\n dosageForm: string | undefined\n route: string[]\n activeIngredients: Array<{ name: string | undefined; strength: string | undefined }>\n marketingStartDate: string | undefined\n productType: string | undefined\n}\n\nfunction formatDrugNDC(ndc: DrugNDC): FormattedDrugNDC {\n return {\n productNdc: ndc.product_ndc,\n brandName: ndc.brand_name,\n genericName: ndc.generic_name,\n labelerName: ndc.labeler_name,\n dosageForm: ndc.dosage_form,\n route: ndc.route ?? [],\n activeIngredients:\n ndc.active_ingredients?.slice(0, 3).map((ai) => ({\n name: ai.name,\n strength: ai.strength,\n })) ?? [],\n marketingStartDate: ndc.marketing_start_date,\n productType: ndc.product_type,\n }\n}\n\nexport async function handleSearchDrugNDC(params: DrugNDCParams): Promise<FDAToolResponse<FormattedDrugNDC[]>> {\n loggers.tools(\"searchDrugNDC\", params)\n\n try {\n const searchTerms: Array<{ field: string; value?: string }> = [\n { field: \"product_ndc\", value: params.productNdc },\n { field: \"brand_name\", value: params.brandName },\n { field: \"generic_name\", value: params.genericName },\n { field: \"labeler_name\", value: params.labelerName },\n { field: \"dosage_form\", value: params.dosageForm },\n { field: \"route\", value: params.route },\n ]\n\n const searchQuery = buildSearchQuery(searchTerms)\n\n const searchParams: SearchParams = {\n search: searchQuery || undefined,\n limit: params.limit,\n skip: params.skip,\n }\n\n const response = await fdaAPIClient.searchDrugNDC(searchParams)\n const results = response.results ?? []\n\n return {\n success: true,\n data: results.map(formatDrugNDC),\n totalResults: response.meta?.results?.total,\n displayedResults: results.length,\n searchParams,\n apiUsage: fdaAPIClient.getRateLimitInfo(),\n }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n }\n }\n}\n\n// Drug Enforcement (Recalls) Handler\nexport type DrugEnforcementParams = {\n recallingFirm?: string\n classification?: \"Class I\" | \"Class II\" | \"Class III\"\n status?: \"Ongoing\" | \"Completed\" | \"Terminated\" | \"Pending\"\n state?: string\n dateFrom?: string\n dateTo?: string\n limit?: number\n skip?: number\n}\n\ntype FormattedDrugEnforcement = {\n recallNumber: string | undefined\n recallingFirm: string | undefined\n classification: string | undefined\n status: string | undefined\n productDescription: string | undefined\n reasonForRecall: string | undefined\n recallInitiationDate: string | undefined\n distributionPattern: string | undefined\n city: string | undefined\n state: string | undefined\n}\n\nfunction formatDrugEnforcement(recall: DrugEnforcement): FormattedDrugEnforcement {\n return {\n recallNumber: recall.recall_number,\n recallingFirm: recall.recalling_firm,\n classification: recall.classification,\n status: recall.status,\n productDescription: truncateText(recall.product_description),\n reasonForRecall: truncateText(recall.reason_for_recall),\n recallInitiationDate: recall.recall_initiation_date,\n distributionPattern: truncateText(recall.distribution_pattern),\n city: recall.city,\n state: recall.state,\n }\n}\n\nexport async function handleSearchDrugEnforcement(\n params: DrugEnforcementParams,\n): Promise<FDAToolResponse<FormattedDrugEnforcement[]>> {\n loggers.tools(\"searchDrugEnforcement\", params)\n\n try {\n const searchTerms: Array<{ field: string; value?: string }> = [\n { field: \"recalling_firm\", value: params.recallingFirm },\n { field: \"classification\", value: params.classification },\n { field: \"status\", value: params.status },\n { field: \"state\", value: params.state },\n ]\n\n const searchQuery = buildSearchQuery(searchTerms)\n const dateQuery = buildDateQuery(\"recall_initiation_date\", params.dateFrom, params.dateTo)\n const fullQuery = [searchQuery, dateQuery].filter(Boolean).join(\"+AND+\")\n\n const searchParams: SearchParams = {\n search: fullQuery || undefined,\n limit: params.limit,\n skip: params.skip,\n }\n\n const response = await fdaAPIClient.searchDrugEnforcement(searchParams)\n const results = response.results ?? []\n\n return {\n success: true,\n data: results.map(formatDrugEnforcement),\n totalResults: response.meta?.results?.total,\n displayedResults: results.length,\n searchParams,\n apiUsage: fdaAPIClient.getRateLimitInfo(),\n }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n }\n }\n}\n\n// Drugs@FDA Handler\nexport type DrugsFDAParams = {\n sponsorName?: string\n applicationNumber?: string\n brandName?: string\n marketingStatus?: string\n limit?: number\n skip?: number\n}\n\ntype FormattedDrugsFDA = {\n applicationNumber: string | undefined\n sponsorName: string | undefined\n products: Array<{\n brandName: string | undefined\n dosageForm: string | undefined\n route: string | undefined\n marketingStatus: string | undefined\n activeIngredients: Array<{ name: string | undefined; strength: string | undefined }>\n }>\n latestSubmission:\n | {\n type: string | undefined\n status: string | undefined\n statusDate: string | undefined\n }\n | undefined\n}\n\nfunction formatDrugsFDA(drug: DrugsFDA): FormattedDrugsFDA {\n const latestSubmission = drug.submissions?.[0]\n\n return {\n applicationNumber: drug.application_number,\n sponsorName: drug.sponsor_name,\n products:\n drug.products?.slice(0, 3).map((p) => ({\n brandName: p.brand_name,\n dosageForm: p.dosage_form,\n route: p.route,\n marketingStatus: p.marketing_status,\n activeIngredients:\n p.active_ingredients?.slice(0, 3).map((ai) => ({\n name: ai.name,\n strength: ai.strength,\n })) ?? [],\n })) ?? [],\n latestSubmission: latestSubmission\n ? {\n type: latestSubmission.submission_type,\n status: latestSubmission.submission_status,\n statusDate: latestSubmission.submission_status_date,\n }\n : undefined,\n }\n}\n\nexport async function handleSearchDrugsFDA(params: DrugsFDAParams): Promise<FDAToolResponse<FormattedDrugsFDA[]>> {\n loggers.tools(\"searchDrugsFDA\", params)\n\n try {\n const searchTerms: Array<{ field: string; value?: string }> = [\n { field: \"sponsor_name\", value: params.sponsorName },\n { field: \"application_number\", value: params.applicationNumber },\n { field: \"products.brand_name\", value: params.brandName },\n { field: \"products.marketing_status\", value: params.marketingStatus },\n ]\n\n const searchQuery = buildSearchQuery(searchTerms)\n\n const searchParams: SearchParams = {\n search: searchQuery || undefined,\n limit: params.limit,\n skip: params.skip,\n }\n\n const response = await fdaAPIClient.searchDrugsFDA(searchParams)\n const results = response.results ?? []\n\n return {\n success: true,\n data: results.map(formatDrugsFDA),\n totalResults: response.meta?.results?.total,\n displayedResults: results.length,\n searchParams,\n apiUsage: fdaAPIClient.getRateLimitInfo(),\n }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n }\n }\n}\n\n// Drug Shortages Handler\nexport type DrugShortagesParams = {\n genericName?: string\n status?: \"Current\" | \"Resolved\"\n limit?: number\n skip?: number\n}\n\ntype FormattedDrugShortage = {\n genericName: string | undefined\n proprietaryName: string | undefined\n status: string | undefined\n description: string | undefined\n initialPostingDate: string | undefined\n resolvedShortageDate: string | undefined\n}\n\nfunction formatDrugShortage(shortage: DrugShortage): FormattedDrugShortage {\n return {\n genericName: shortage.generic_name,\n proprietaryName: shortage.proprietary_name,\n status: shortage.status,\n description: truncateText(shortage.description),\n initialPostingDate: shortage.initial_posting_date,\n resolvedShortageDate: shortage.resolved_shortage_date,\n }\n}\n\nexport async function handleSearchDrugShortages(\n params: DrugShortagesParams,\n): Promise<FDAToolResponse<FormattedDrugShortage[]>> {\n loggers.tools(\"searchDrugShortages\", params)\n\n try {\n const searchTerms: Array<{ field: string; value?: string }> = [\n { field: \"generic_name\", value: params.genericName },\n { field: \"status\", value: params.status },\n ]\n\n const searchQuery = buildSearchQuery(searchTerms)\n\n const searchParams: SearchParams = {\n search: searchQuery || undefined,\n limit: params.limit,\n skip: params.skip,\n }\n\n const response = await fdaAPIClient.searchDrugShortages(searchParams)\n const results = response.results ?? []\n\n return {\n success: true,\n data: results.map(formatDrugShortage),\n totalResults: response.meta?.results?.total,\n displayedResults: results.length,\n searchParams,\n apiUsage: fdaAPIClient.getRateLimitInfo(),\n }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n }\n }\n}\n"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{z as e}from"zod";const t={limit:e.number().int().min(1).max(100).optional().describe(`Maximum results to return (1-100, default 10)`),skip:e.number().int().min(0).optional().describe(`Number of results to skip for pagination`)},n={dateFrom:e.string().optional().describe(`Start date (YYYY-MM-DD or YYYYMMDD format)`),dateTo:e.string().optional().describe(`End date (YYYY-MM-DD or YYYYMMDD format)`)},r=e.object({drugName:e.string().optional().describe(`Drug or product name to search`),reaction:e.string().optional().describe(`Adverse reaction to search (e.g., 'headache', 'nausea')`),manufacturer:e.string().optional().describe(`Drug manufacturer name`),serious:e.boolean().optional().describe(`Filter for serious adverse events only`),...n,...t}),i=e.object({drugName:e.string().optional().describe(`Drug brand or generic name`),indication:e.string().optional().describe(`Medical indication or use case`),activeIngredient:e.string().optional().describe(`Active ingredient/substance name`),route:e.string().optional().describe(`Route of administration (e.g., 'oral', 'intravenous')`),...t}),a=e.object({productNdc:e.string().optional().describe(`National Drug Code (NDC)`),brandName:e.string().optional().describe(`Drug brand name`),genericName:e.string().optional().describe(`Drug generic name`),labelerName:e.string().optional().describe(`Drug labeler/manufacturer name`),dosageForm:e.string().optional().describe(`Dosage form (e.g., 'tablet', 'capsule', 'injection')`),route:e.string().optional().describe(`Route of administration`),...t}),o=e.object({recallingFirm:e.string().optional().describe(`Name of the recalling company`),classification:e.enum([`Class I`,`Class II`,`Class III`]).optional().describe(`Recall classification (I=most serious, III=least)`),status:e.enum([`Ongoing`,`Completed`,`Terminated`,`Pending`]).optional().describe(`Recall status`),state:e.string().optional().describe(`US state code (e.g., 'CA', 'NY')`),...n,...t}),s=e.object({sponsorName:e.string().optional().describe(`Drug sponsor/company name`),applicationNumber:e.string().optional().describe(`FDA application number (e.g., 'NDA012345')`),brandName:e.string().optional().describe(`Drug brand name`),marketingStatus:e.string().optional().describe(`Marketing status (e.g., 'Prescription', 'OTC')`),...t}),c=e.object({genericName:e.string().optional().describe(`Generic drug name`),status:e.enum([`Current`,`Resolved`]).optional().describe(`Shortage status`),...t}),l=e.object({deviceName:e.string().optional().describe(`Device name to search`),applicant:e.string().optional().describe(`Applicant/company name`),productCode:e.string().optional().describe(`FDA product code`),clearanceType:e.string().optional().describe(`Clearance type (e.g., 'Traditional', 'Special')`),decisionDateFrom:e.string().optional().describe(`Decision date range start (YYYY-MM-DD)`),decisionDateTo:e.string().optional().describe(`Decision date range end (YYYY-MM-DD)`),...t}),u=e.object({deviceName:e.string().optional().describe(`Device name to search`),deviceClass:e.enum([`1`,`2`,`3`]).optional().describe(`Device class (1=lowest risk, 3=highest)`),medicalSpecialty:e.string().optional().describe(`Medical specialty code`),productCode:e.string().optional().describe(`FDA product code`),regulationNumber:e.string().optional().describe(`CFR regulation number`),...t}),d=e.object({deviceName:e.string().optional().describe(`Device generic name`),brandName:e.string().optional().describe(`Device brand name`),manufacturerName:e.string().optional().describe(`Device manufacturer name`),eventType:e.enum([`Injury`,`Malfunction`,`Death`,`Other`]).optional().describe(`Type of adverse event`),...n,...t}),f=e.object({recallingFirm:e.string().optional().describe(`Name of the recalling company`),productDescription:e.string().optional().describe(`Product description keywords`),classification:e.enum([`Class I`,`Class II`,`Class III`]).optional().describe(`Recall classification (I=most serious)`),status:e.enum([`Ongoing`,`Completed`,`Terminated`,`Pending`]).optional().describe(`Recall status`),...n,...t}),p={searchDrugAdverseEvents:r,searchDrugLabels:i,searchDrugNDC:a,searchDrugEnforcement:o,searchDrugsFDA:s,searchDrugShortages:c,searchDevice510K:l,searchDeviceClassifications:u,searchDeviceAdverseEvents:d,searchDeviceEnforcement:f};export{r as a,a as c,p as d,f as i,c as l,d as n,o,u as r,i as s,l as t,s as u};
2
- //# sourceMappingURL=tools-Bh3wjIRH.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tools-Bh3wjIRH.js","names":[],"sources":["../src/tools/index.ts"],"sourcesContent":["/**\n * MCP Tool Definitions\n * Zod schemas for all FDA MCP tools\n */\n\nimport { z } from \"zod\"\n\n// Common pagination schema\nconst paginationSchema = {\n limit: z.number().int().min(1).max(100).optional().describe(\"Maximum results to return (1-100, default 10)\"),\n skip: z.number().int().min(0).optional().describe(\"Number of results to skip for pagination\"),\n}\n\n// Date range schema\nconst dateRangeSchema = {\n dateFrom: z.string().optional().describe(\"Start date (YYYY-MM-DD or YYYYMMDD format)\"),\n dateTo: z.string().optional().describe(\"End date (YYYY-MM-DD or YYYYMMDD format)\"),\n}\n\n// Drug Tool Schemas\n\nexport const searchDrugAdverseEventsSchema = z.object({\n drugName: z.string().optional().describe(\"Drug or product name to search\"),\n reaction: z.string().optional().describe(\"Adverse reaction to search (e.g., 'headache', 'nausea')\"),\n manufacturer: z.string().optional().describe(\"Drug manufacturer name\"),\n serious: z.boolean().optional().describe(\"Filter for serious adverse events only\"),\n ...dateRangeSchema,\n ...paginationSchema,\n})\n\nexport const searchDrugLabelsSchema = z.object({\n drugName: z.string().optional().describe(\"Drug brand or generic name\"),\n indication: z.string().optional().describe(\"Medical indication or use case\"),\n activeIngredient: z.string().optional().describe(\"Active ingredient/substance name\"),\n route: z.string().optional().describe(\"Route of administration (e.g., 'oral', 'intravenous')\"),\n ...paginationSchema,\n})\n\nexport const searchDrugNDCSchema = z.object({\n productNdc: z.string().optional().describe(\"National Drug Code (NDC)\"),\n brandName: z.string().optional().describe(\"Drug brand name\"),\n genericName: z.string().optional().describe(\"Drug generic name\"),\n labelerName: z.string().optional().describe(\"Drug labeler/manufacturer name\"),\n dosageForm: z.string().optional().describe(\"Dosage form (e.g., 'tablet', 'capsule', 'injection')\"),\n route: z.string().optional().describe(\"Route of administration\"),\n ...paginationSchema,\n})\n\nexport const searchDrugEnforcementSchema = z.object({\n recallingFirm: z.string().optional().describe(\"Name of the recalling company\"),\n classification: z\n .enum([\"Class I\", \"Class II\", \"Class III\"])\n .optional()\n .describe(\"Recall classification (I=most serious, III=least)\"),\n status: z.enum([\"Ongoing\", \"Completed\", \"Terminated\", \"Pending\"]).optional().describe(\"Recall status\"),\n state: z.string().optional().describe(\"US state code (e.g., 'CA', 'NY')\"),\n ...dateRangeSchema,\n ...paginationSchema,\n})\n\nexport const searchDrugsFDASchema = z.object({\n sponsorName: z.string().optional().describe(\"Drug sponsor/company name\"),\n applicationNumber: z.string().optional().describe(\"FDA application number (e.g., 'NDA012345')\"),\n brandName: z.string().optional().describe(\"Drug brand name\"),\n marketingStatus: z.string().optional().describe(\"Marketing status (e.g., 'Prescription', 'OTC')\"),\n ...paginationSchema,\n})\n\nexport const searchDrugShortagesSchema = z.object({\n genericName: z.string().optional().describe(\"Generic drug name\"),\n status: z.enum([\"Current\", \"Resolved\"]).optional().describe(\"Shortage status\"),\n ...paginationSchema,\n})\n\n// Device Tool Schemas\n\nexport const searchDevice510KSchema = z.object({\n deviceName: z.string().optional().describe(\"Device name to search\"),\n applicant: z.string().optional().describe(\"Applicant/company name\"),\n productCode: z.string().optional().describe(\"FDA product code\"),\n clearanceType: z.string().optional().describe(\"Clearance type (e.g., 'Traditional', 'Special')\"),\n decisionDateFrom: z.string().optional().describe(\"Decision date range start (YYYY-MM-DD)\"),\n decisionDateTo: z.string().optional().describe(\"Decision date range end (YYYY-MM-DD)\"),\n ...paginationSchema,\n})\n\nexport const searchDeviceClassificationsSchema = z.object({\n deviceName: z.string().optional().describe(\"Device name to search\"),\n deviceClass: z.enum([\"1\", \"2\", \"3\"]).optional().describe(\"Device class (1=lowest risk, 3=highest)\"),\n medicalSpecialty: z.string().optional().describe(\"Medical specialty code\"),\n productCode: z.string().optional().describe(\"FDA product code\"),\n regulationNumber: z.string().optional().describe(\"CFR regulation number\"),\n ...paginationSchema,\n})\n\nexport const searchDeviceAdverseEventsSchema = z.object({\n deviceName: z.string().optional().describe(\"Device generic name\"),\n brandName: z.string().optional().describe(\"Device brand name\"),\n manufacturerName: z.string().optional().describe(\"Device manufacturer name\"),\n eventType: z.enum([\"Injury\", \"Malfunction\", \"Death\", \"Other\"]).optional().describe(\"Type of adverse event\"),\n ...dateRangeSchema,\n ...paginationSchema,\n})\n\nexport const searchDeviceEnforcementSchema = z.object({\n recallingFirm: z.string().optional().describe(\"Name of the recalling company\"),\n productDescription: z.string().optional().describe(\"Product description keywords\"),\n classification: z\n .enum([\"Class I\", \"Class II\", \"Class III\"])\n .optional()\n .describe(\"Recall classification (I=most serious)\"),\n status: z.enum([\"Ongoing\", \"Completed\", \"Terminated\", \"Pending\"]).optional().describe(\"Recall status\"),\n ...dateRangeSchema,\n ...paginationSchema,\n})\n\n// Export all schemas for use in tool registration\nexport const toolSchemas = {\n searchDrugAdverseEvents: searchDrugAdverseEventsSchema,\n searchDrugLabels: searchDrugLabelsSchema,\n searchDrugNDC: searchDrugNDCSchema,\n searchDrugEnforcement: searchDrugEnforcementSchema,\n searchDrugsFDA: searchDrugsFDASchema,\n searchDrugShortages: searchDrugShortagesSchema,\n searchDevice510K: searchDevice510KSchema,\n searchDeviceClassifications: searchDeviceClassificationsSchema,\n searchDeviceAdverseEvents: searchDeviceAdverseEventsSchema,\n searchDeviceEnforcement: searchDeviceEnforcementSchema,\n}\n\n// Export inferred types\nexport type SearchDrugAdverseEventsParams = z.infer<typeof searchDrugAdverseEventsSchema>\nexport type SearchDrugLabelsParams = z.infer<typeof searchDrugLabelsSchema>\nexport type SearchDrugNDCParams = z.infer<typeof searchDrugNDCSchema>\nexport type SearchDrugEnforcementParams = z.infer<typeof searchDrugEnforcementSchema>\nexport type SearchDrugsFDAParams = z.infer<typeof searchDrugsFDASchema>\nexport type SearchDrugShortagesParams = z.infer<typeof searchDrugShortagesSchema>\nexport type SearchDevice510KParams = z.infer<typeof searchDevice510KSchema>\nexport type SearchDeviceClassificationsParams = z.infer<typeof searchDeviceClassificationsSchema>\nexport type SearchDeviceAdverseEventsParams = z.infer<typeof searchDeviceAdverseEventsSchema>\nexport type SearchDeviceEnforcementParams = z.infer<typeof searchDeviceEnforcementSchema>\n"],"mappings":"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"}