@oneuptime/common 12.0.30 → 12.0.31

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 (489) hide show
  1. package/Models/AnalyticsModels/SecurityEvent.ts +48 -16
  2. package/Models/AnalyticsModels/ThreatIntelIndicator.ts +10 -5
  3. package/Models/DatabaseModels/AlertSeverity.ts +44 -0
  4. package/Models/DatabaseModels/DetectionRule.ts +16 -5
  5. package/Models/DatabaseModels/GoogleSecOpsConnection.ts +14 -5
  6. package/Models/DatabaseModels/IncidentSeverity.ts +44 -0
  7. package/Models/DatabaseModels/Index.ts +2 -0
  8. package/Models/DatabaseModels/NetworkDevice.ts +113 -3
  9. package/Models/DatabaseModels/NetworkDeviceAutoImportRule.ts +88 -0
  10. package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +22 -0
  11. package/Models/DatabaseModels/NetworkDeviceOidTemplate.ts +499 -0
  12. package/Models/DatabaseModels/ThreatIntelFeed.ts +16 -5
  13. package/Server/API/GlobalConfigAPI.ts +362 -183
  14. package/Server/API/TelemetryAPI.ts +42 -4
  15. package/Server/EnvironmentConfig.ts +112 -0
  16. package/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.ts +59 -0
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.ts +25 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
  19. package/Server/Middleware/MultipartFormData.ts +118 -32
  20. package/Server/Services/AlertEpisodeLabelRuleEngineService.ts +9 -1
  21. package/Server/Services/AlertEpisodeOnCallRuleEngineService.ts +9 -1
  22. package/Server/Services/AlertEpisodeOwnerRuleEngineService.ts +9 -1
  23. package/Server/Services/AlertEpisodePrivacyRuleEngineService.ts +9 -1
  24. package/Server/Services/AlertGroupingEngineService.ts +9 -1
  25. package/Server/Services/AlertLabelRuleEngineService.ts +9 -1
  26. package/Server/Services/AlertOnCallRuleEngineService.ts +9 -1
  27. package/Server/Services/AlertOwnerRuleEngineService.ts +9 -1
  28. package/Server/Services/AlertPrivacyRuleEngineService.ts +9 -1
  29. package/Server/Services/AlertReminderRuleService.ts +9 -1
  30. package/Server/Services/AutoRemediationRuleEngineService.ts +9 -1
  31. package/Server/Services/CephClusterLabelRuleEngineService.ts +9 -1
  32. package/Server/Services/CephClusterOwnerRuleEngineService.ts +9 -1
  33. package/Server/Services/CloudResourceLabelRuleEngineService.ts +9 -1
  34. package/Server/Services/CloudResourceOwnerRuleEngineService.ts +9 -1
  35. package/Server/Services/DashboardLabelRuleEngineService.ts +9 -1
  36. package/Server/Services/DashboardOwnerRuleEngineService.ts +9 -1
  37. package/Server/Services/DockerHostLabelRuleEngineService.ts +9 -1
  38. package/Server/Services/DockerHostOwnerRuleEngineService.ts +9 -1
  39. package/Server/Services/DockerSwarmClusterLabelRuleEngineService.ts +9 -1
  40. package/Server/Services/DockerSwarmClusterOwnerRuleEngineService.ts +9 -1
  41. package/Server/Services/HostLabelRuleEngineService.ts +9 -1
  42. package/Server/Services/HostOwnerRuleEngineService.ts +9 -1
  43. package/Server/Services/IncidentEpisodeLabelRuleEngineService.ts +9 -1
  44. package/Server/Services/IncidentEpisodeOnCallRuleEngineService.ts +9 -1
  45. package/Server/Services/IncidentEpisodeOwnerRuleEngineService.ts +9 -1
  46. package/Server/Services/IncidentEpisodePrivacyRuleEngineService.ts +9 -1
  47. package/Server/Services/IncidentGroupingEngineService.ts +9 -1
  48. package/Server/Services/IncidentLabelRuleEngineService.ts +9 -1
  49. package/Server/Services/IncidentOnCallRuleEngineService.ts +9 -1
  50. package/Server/Services/IncidentOwnerRuleEngineService.ts +9 -1
  51. package/Server/Services/IncidentPrivacyRuleEngineService.ts +9 -1
  52. package/Server/Services/IncidentReminderRuleService.ts +9 -1
  53. package/Server/Services/IncidentSlaRuleService.ts +9 -1
  54. package/Server/Services/IncomingCallPolicyLabelRuleEngineService.ts +9 -1
  55. package/Server/Services/IncomingCallPolicyOwnerRuleEngineService.ts +9 -1
  56. package/Server/Services/Index.ts +2 -0
  57. package/Server/Services/IoTFleetLabelRuleEngineService.ts +9 -1
  58. package/Server/Services/IoTFleetOwnerRuleEngineService.ts +9 -1
  59. package/Server/Services/KubernetesClusterLabelRuleEngineService.ts +9 -1
  60. package/Server/Services/KubernetesClusterOwnerRuleEngineService.ts +9 -1
  61. package/Server/Services/KubernetesResourceService.ts +5 -1
  62. package/Server/Services/MonitorLabelRuleEngineService.ts +9 -1
  63. package/Server/Services/MonitorOwnerRuleEngineService.ts +9 -1
  64. package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +35 -0
  65. package/Server/Services/NetworkDeviceAutoImportRuleService.ts +96 -0
  66. package/Server/Services/NetworkDeviceLabelRuleEngineService.ts +9 -1
  67. package/Server/Services/NetworkDeviceOidTemplateService.ts +201 -0
  68. package/Server/Services/NetworkDeviceOwnerRuleEngineService.ts +9 -1
  69. package/Server/Services/NetworkDeviceService.ts +209 -1
  70. package/Server/Services/OnCallDutyPolicyLabelRuleEngineService.ts +9 -1
  71. package/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.ts +9 -1
  72. package/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.ts +9 -1
  73. package/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.ts +9 -1
  74. package/Server/Services/PodmanHostLabelRuleEngineService.ts +9 -1
  75. package/Server/Services/PodmanHostOwnerRuleEngineService.ts +9 -1
  76. package/Server/Services/ProxmoxClusterLabelRuleEngineService.ts +9 -1
  77. package/Server/Services/ProxmoxClusterOwnerRuleEngineService.ts +9 -1
  78. package/Server/Services/RumApplicationLabelRuleEngineService.ts +9 -1
  79. package/Server/Services/RumApplicationOwnerRuleEngineService.ts +9 -1
  80. package/Server/Services/RunbookLabelRuleEngineService.ts +9 -1
  81. package/Server/Services/RunbookOwnerRuleEngineService.ts +9 -1
  82. package/Server/Services/RunbookRuleEngineService.ts +9 -1
  83. package/Server/Services/ScheduledMaintenanceLabelRuleEngineService.ts +9 -1
  84. package/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.ts +9 -1
  85. package/Server/Services/ScheduledMaintenanceReminderRuleService.ts +9 -1
  86. package/Server/Services/ServerlessFunctionLabelRuleEngineService.ts +9 -1
  87. package/Server/Services/ServerlessFunctionOwnerRuleEngineService.ts +9 -1
  88. package/Server/Services/ServiceLabelRuleEngineService.ts +9 -1
  89. package/Server/Services/ServiceOwnerRuleEngineService.ts +9 -1
  90. package/Server/Services/StatusPageLabelRuleEngineService.ts +9 -1
  91. package/Server/Services/StatusPageMonitorRuleEngineService.ts +7 -0
  92. package/Server/Services/StatusPageOwnerRuleEngineService.ts +9 -1
  93. package/Server/Services/TelemetrySourceMapService.ts +266 -23
  94. package/Server/Services/UserService.ts +27 -0
  95. package/Server/Services/WorkflowLabelRuleEngineService.ts +9 -1
  96. package/Server/Services/WorkflowOwnerRuleEngineService.ts +9 -1
  97. package/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.ts +186 -0
  98. package/Server/Utils/Monitor/CapturedMetricAttributeUtil.ts +245 -0
  99. package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +21 -2
  100. package/Server/Utils/Monitor/MonitorMetricUtil.ts +55 -21
  101. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +32 -0
  102. package/Server/Utils/Monitor/NetworkDeviceMetricUtil.ts +15 -2
  103. package/Server/Utils/Monitor/NetworkDeviceWalkUtil.ts +18 -1
  104. package/Server/Utils/Monitor/NetworkInventoryUtil.ts +10 -0
  105. package/Server/Utils/Monitor/SeriesResourceLabels.ts +34 -0
  106. package/Server/Utils/Rules/RuleEngineRuleRead.ts +48 -0
  107. package/Server/Utils/Telemetry/ExceptionSanitizer.ts +14 -1
  108. package/Server/Utils/Telemetry/LogExceptionExtractor.ts +14 -2
  109. package/Server/Utils/Telemetry/SourceMapResolver.ts +16 -5
  110. package/Server/Utils/Telemetry/StackTraceParser.ts +399 -0
  111. package/Tests/App/Dashboard/EventOverlayHook.test.tsx +125 -0
  112. package/Tests/App/Dashboard/HeaderImageAssets.test.tsx +93 -0
  113. package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +3 -3
  114. package/Tests/App/Dashboard/UserElementEmail.test.tsx +12 -4
  115. package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +1 -1
  116. package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +14 -0
  117. package/Tests/Models/DatabaseModels/ModelRegistryInvariants.test.ts +469 -0
  118. package/Tests/Models/SecurityDomainAccessControl.test.ts +429 -0
  119. package/Tests/Server/API/GlobalConfigLicense.test.ts +657 -0
  120. package/Tests/Server/API/SecurityEventAttributesAPI.test.ts +84 -6
  121. package/Tests/Server/API/TelemetryResolveStackTraceAPI.test.ts +805 -0
  122. package/Tests/Server/Infrastructure/Postgres/AddOnCallCalendarFeedsMigration.test.ts +32 -7
  123. package/Tests/Server/Middleware/IdentityRateLimit.test.ts +1144 -0
  124. package/Tests/Server/Middleware/MultipartFormData.test.ts +618 -3
  125. package/Tests/Server/Services/MonitorLabelRuleEngineScale.test.ts +520 -0
  126. package/Tests/Server/Services/NetworkDeviceOidTemplateService.test.ts +332 -0
  127. package/Tests/Server/Services/NetworkDeviceOidTemplateWriteGuards.test.ts +409 -0
  128. package/Tests/Server/Services/RuleEngineRuleFetchLimit.test.ts +239 -0
  129. package/Tests/Server/Services/TelemetrySourceMapService.test.ts +1210 -2
  130. package/Tests/Server/Services/UserServiceSeatLimit.test.ts +182 -0
  131. package/Tests/Server/Types/AnalyticsDatabase/SecurityEventModelPermission.test.ts +255 -0
  132. package/Tests/Server/Types/Database/Permissions/ReadBlockPermission.test.ts +212 -0
  133. package/Tests/Server/Types/Database/Permissions/SecurityRoleAccess.test.ts +413 -0
  134. package/Tests/Server/Utils/CodeRepository.test.ts +689 -0
  135. package/Tests/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.test.ts +495 -0
  136. package/Tests/Server/Utils/ExceptionSanitizer.test.ts +77 -0
  137. package/Tests/Server/Utils/Monitor/CapturedMetricAttributeUtil.test.ts +284 -0
  138. package/Tests/Server/Utils/Monitor/MonitorCustomMetricAttributes.test.ts +503 -0
  139. package/Tests/Server/Utils/Monitor/MonitorTemplatePrototypePollution.test.ts +106 -0
  140. package/Tests/Server/Utils/Monitor/NetworkDeviceWalkLogWritePath.test.ts +33 -4
  141. package/Tests/Server/Utils/Monitor/NetworkDeviceWalkUtil.test.ts +14 -4
  142. package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +44 -0
  143. package/Tests/Server/Utils/OpenAPISpec.test.ts +536 -0
  144. package/Tests/Server/Utils/Rules/RuleEngineRuleRead.test.ts +115 -0
  145. package/Tests/Server/Utils/StackTraceParser.test.ts +610 -0
  146. package/Tests/Server/Utils/Telemetry/LogExceptionExtractor.test.ts +0 -0
  147. package/Tests/Server/Utils/Telemetry/SourceMapLimits.test.ts +656 -0
  148. package/Tests/Server/Utils/Telemetry/SourceMapResolver.test.ts +100 -0
  149. package/Tests/Types/Monitor/SnmpMonitor/SnmpOidListUtil.test.ts +454 -0
  150. package/Tests/Types/SecurityRolePermissions.test.ts +193 -0
  151. package/Tests/UI/Components/Charts/AnnotationLayout.test.ts +773 -0
  152. package/Tests/UI/Components/Charts/ChartAnnotationRail.test.tsx +789 -0
  153. package/Tests/UI/Components/Charts/ChartBucketIdentity.test.ts +254 -0
  154. package/Tests/UI/Components/Charts/TimeAnnotation.test.ts +471 -0
  155. package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +405 -0
  156. package/Tests/UI/Components/ErrorMessageRefreshControl.test.tsx +83 -0
  157. package/Tests/UI/Components/MarkdownConverters.test.ts +686 -0
  158. package/Tests/UI/Components/ModelTable/BaseModelTableDeleteAndEmptyStates.test.tsx +341 -0
  159. package/Tests/UI/Components/OrderedStatesList.test.tsx +5 -5
  160. package/Tests/UI/Components/PendingProjectInvitations.test.tsx +1 -1
  161. package/Tests/UI/Components/TableSortAndMobileColumns.test.tsx +195 -0
  162. package/Tests/UI/Components/XAxis.test.ts +270 -5
  163. package/Tests/UI/Components/XAxisDaylightSaving.test.ts +113 -0
  164. package/Tests/UI/Styles/ChartFocusRing.test.ts +153 -0
  165. package/Tests/UI/Styles/ChartFocusRingCoverage.test.tsx +377 -0
  166. package/Tests/UI/Styles/ThemeStylesheet.ts +162 -0
  167. package/Tests/Utils/EnterpriseLicenseSeats.test.ts +507 -0
  168. package/Tests/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.test.ts +951 -1
  169. package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +238 -0
  170. package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +1056 -0
  171. package/Tests/Utils/NetworkDiscovery/ReverseDnsNameUtil.test.ts +882 -0
  172. package/Types/Date.ts +39 -0
  173. package/Types/Monitor/SnmpMonitor/SnmpOidListUtil.ts +333 -0
  174. package/Types/Permission.ts +96 -0
  175. package/Types/Rum/SessionReplay.ts +21 -0
  176. package/Types/Telemetry/SourceMap.ts +8 -0
  177. package/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.tsx +176 -0
  178. package/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.ts +745 -0
  179. package/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.tsx +576 -0
  180. package/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.tsx +204 -0
  181. package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +491 -544
  182. package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +324 -372
  183. package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +487 -540
  184. package/UI/Components/Charts/ChartLibrary/Types/FormattedReferenceRegion.ts +7 -3
  185. package/UI/Components/Charts/ChartLibrary/Types/FormattedTimeReferenceLine.ts +14 -3
  186. package/UI/Components/Charts/Types/ChartEventKind.ts +13 -0
  187. package/UI/Components/Charts/Types/ReferenceRegionProps.ts +6 -0
  188. package/UI/Components/Charts/Types/TimeReferenceLineProps.ts +20 -3
  189. package/UI/Components/Charts/Utils/TimeAnnotation.ts +69 -35
  190. package/UI/Components/Charts/Utils/XAxis.ts +125 -18
  191. package/UI/Components/EditionLabel/EditionLabel.tsx +280 -26
  192. package/UI/Components/ErrorMessage/ErrorMessage.tsx +21 -10
  193. package/UI/Components/Feed/FeedItem.tsx +4 -5
  194. package/UI/Components/Header/HeaderIconDropdownButton.tsx +1 -2
  195. package/UI/Components/Header/UserProfile/UserProfile.tsx +1 -2
  196. package/UI/Components/Image/Image.tsx +20 -3
  197. package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
  198. package/UI/Components/MemberRoleAssignment/MemberRoleAssignment.tsx +1 -2
  199. package/UI/Components/ModelTable/BaseModelTable.tsx +150 -24
  200. package/UI/Components/Table/TableHeader.tsx +64 -48
  201. package/UI/Components/Table/TableRow.tsx +13 -3
  202. package/UI/Styles/Theme.css +38 -0
  203. package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +271 -0
  204. package/Utils/NetworkDiscovery/AutoImportRuleMatcher.ts +6 -0
  205. package/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.ts +141 -10
  206. package/Utils/NetworkDiscovery/DiscoveredHostUtil.ts +55 -3
  207. package/Utils/NetworkDiscovery/ReverseDnsNameUtil.ts +151 -0
  208. package/Utils/Rules/RuleEngineLimits.ts +32 -0
  209. package/build/dist/Models/AnalyticsModels/SecurityEvent.js +48 -16
  210. package/build/dist/Models/AnalyticsModels/SecurityEvent.js.map +1 -1
  211. package/build/dist/Models/AnalyticsModels/ThreatIntelIndicator.js +10 -5
  212. package/build/dist/Models/AnalyticsModels/ThreatIntelIndicator.js.map +1 -1
  213. package/build/dist/Models/DatabaseModels/AlertSeverity.js +46 -1
  214. package/build/dist/Models/DatabaseModels/AlertSeverity.js.map +1 -1
  215. package/build/dist/Models/DatabaseModels/DetectionRule.js +16 -5
  216. package/build/dist/Models/DatabaseModels/DetectionRule.js.map +1 -1
  217. package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js +14 -5
  218. package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js.map +1 -1
  219. package/build/dist/Models/DatabaseModels/IncidentSeverity.js +46 -1
  220. package/build/dist/Models/DatabaseModels/IncidentSeverity.js.map +1 -1
  221. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  222. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  223. package/build/dist/Models/DatabaseModels/NetworkDevice.js +115 -3
  224. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  225. package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js +88 -0
  226. package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js.map +1 -1
  227. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
  228. package/build/dist/Models/DatabaseModels/NetworkDeviceOidTemplate.js +519 -0
  229. package/build/dist/Models/DatabaseModels/NetworkDeviceOidTemplate.js.map +1 -0
  230. package/build/dist/Models/DatabaseModels/ThreatIntelFeed.js +16 -5
  231. package/build/dist/Models/DatabaseModels/ThreatIntelFeed.js.map +1 -1
  232. package/build/dist/Server/API/GlobalConfigAPI.js +293 -176
  233. package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
  234. package/build/dist/Server/API/TelemetryAPI.js +31 -3
  235. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  236. package/build/dist/Server/EnvironmentConfig.js +83 -0
  237. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  238. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.js +26 -0
  239. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.js.map +1 -0
  240. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.js +14 -0
  241. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.js.map +1 -0
  242. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
  243. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  244. package/build/dist/Server/Middleware/MultipartFormData.js +93 -28
  245. package/build/dist/Server/Middleware/MultipartFormData.js.map +1 -1
  246. package/build/dist/Server/Services/AlertEpisodeLabelRuleEngineService.js +8 -1
  247. package/build/dist/Server/Services/AlertEpisodeLabelRuleEngineService.js.map +1 -1
  248. package/build/dist/Server/Services/AlertEpisodeOnCallRuleEngineService.js +8 -1
  249. package/build/dist/Server/Services/AlertEpisodeOnCallRuleEngineService.js.map +1 -1
  250. package/build/dist/Server/Services/AlertEpisodeOwnerRuleEngineService.js +8 -1
  251. package/build/dist/Server/Services/AlertEpisodeOwnerRuleEngineService.js.map +1 -1
  252. package/build/dist/Server/Services/AlertEpisodePrivacyRuleEngineService.js +8 -1
  253. package/build/dist/Server/Services/AlertEpisodePrivacyRuleEngineService.js.map +1 -1
  254. package/build/dist/Server/Services/AlertGroupingEngineService.js +8 -1
  255. package/build/dist/Server/Services/AlertGroupingEngineService.js.map +1 -1
  256. package/build/dist/Server/Services/AlertLabelRuleEngineService.js +8 -1
  257. package/build/dist/Server/Services/AlertLabelRuleEngineService.js.map +1 -1
  258. package/build/dist/Server/Services/AlertOnCallRuleEngineService.js +8 -1
  259. package/build/dist/Server/Services/AlertOnCallRuleEngineService.js.map +1 -1
  260. package/build/dist/Server/Services/AlertOwnerRuleEngineService.js +8 -1
  261. package/build/dist/Server/Services/AlertOwnerRuleEngineService.js.map +1 -1
  262. package/build/dist/Server/Services/AlertPrivacyRuleEngineService.js +8 -1
  263. package/build/dist/Server/Services/AlertPrivacyRuleEngineService.js.map +1 -1
  264. package/build/dist/Server/Services/AlertReminderRuleService.js +8 -1
  265. package/build/dist/Server/Services/AlertReminderRuleService.js.map +1 -1
  266. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js +8 -1
  267. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js.map +1 -1
  268. package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js +8 -1
  269. package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js.map +1 -1
  270. package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js +8 -1
  271. package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js.map +1 -1
  272. package/build/dist/Server/Services/CloudResourceLabelRuleEngineService.js +8 -1
  273. package/build/dist/Server/Services/CloudResourceLabelRuleEngineService.js.map +1 -1
  274. package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js +8 -1
  275. package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js.map +1 -1
  276. package/build/dist/Server/Services/DashboardLabelRuleEngineService.js +8 -1
  277. package/build/dist/Server/Services/DashboardLabelRuleEngineService.js.map +1 -1
  278. package/build/dist/Server/Services/DashboardOwnerRuleEngineService.js +8 -1
  279. package/build/dist/Server/Services/DashboardOwnerRuleEngineService.js.map +1 -1
  280. package/build/dist/Server/Services/DockerHostLabelRuleEngineService.js +8 -1
  281. package/build/dist/Server/Services/DockerHostLabelRuleEngineService.js.map +1 -1
  282. package/build/dist/Server/Services/DockerHostOwnerRuleEngineService.js +8 -1
  283. package/build/dist/Server/Services/DockerHostOwnerRuleEngineService.js.map +1 -1
  284. package/build/dist/Server/Services/DockerSwarmClusterLabelRuleEngineService.js +8 -1
  285. package/build/dist/Server/Services/DockerSwarmClusterLabelRuleEngineService.js.map +1 -1
  286. package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js +8 -1
  287. package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js.map +1 -1
  288. package/build/dist/Server/Services/HostLabelRuleEngineService.js +8 -1
  289. package/build/dist/Server/Services/HostLabelRuleEngineService.js.map +1 -1
  290. package/build/dist/Server/Services/HostOwnerRuleEngineService.js +8 -1
  291. package/build/dist/Server/Services/HostOwnerRuleEngineService.js.map +1 -1
  292. package/build/dist/Server/Services/IncidentEpisodeLabelRuleEngineService.js +8 -1
  293. package/build/dist/Server/Services/IncidentEpisodeLabelRuleEngineService.js.map +1 -1
  294. package/build/dist/Server/Services/IncidentEpisodeOnCallRuleEngineService.js +8 -1
  295. package/build/dist/Server/Services/IncidentEpisodeOnCallRuleEngineService.js.map +1 -1
  296. package/build/dist/Server/Services/IncidentEpisodeOwnerRuleEngineService.js +8 -1
  297. package/build/dist/Server/Services/IncidentEpisodeOwnerRuleEngineService.js.map +1 -1
  298. package/build/dist/Server/Services/IncidentEpisodePrivacyRuleEngineService.js +8 -1
  299. package/build/dist/Server/Services/IncidentEpisodePrivacyRuleEngineService.js.map +1 -1
  300. package/build/dist/Server/Services/IncidentGroupingEngineService.js +8 -1
  301. package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
  302. package/build/dist/Server/Services/IncidentLabelRuleEngineService.js +8 -1
  303. package/build/dist/Server/Services/IncidentLabelRuleEngineService.js.map +1 -1
  304. package/build/dist/Server/Services/IncidentOnCallRuleEngineService.js +8 -1
  305. package/build/dist/Server/Services/IncidentOnCallRuleEngineService.js.map +1 -1
  306. package/build/dist/Server/Services/IncidentOwnerRuleEngineService.js +8 -1
  307. package/build/dist/Server/Services/IncidentOwnerRuleEngineService.js.map +1 -1
  308. package/build/dist/Server/Services/IncidentPrivacyRuleEngineService.js +8 -1
  309. package/build/dist/Server/Services/IncidentPrivacyRuleEngineService.js.map +1 -1
  310. package/build/dist/Server/Services/IncidentReminderRuleService.js +8 -1
  311. package/build/dist/Server/Services/IncidentReminderRuleService.js.map +1 -1
  312. package/build/dist/Server/Services/IncidentSlaRuleService.js +8 -1
  313. package/build/dist/Server/Services/IncidentSlaRuleService.js.map +1 -1
  314. package/build/dist/Server/Services/IncomingCallPolicyLabelRuleEngineService.js +8 -1
  315. package/build/dist/Server/Services/IncomingCallPolicyLabelRuleEngineService.js.map +1 -1
  316. package/build/dist/Server/Services/IncomingCallPolicyOwnerRuleEngineService.js +8 -1
  317. package/build/dist/Server/Services/IncomingCallPolicyOwnerRuleEngineService.js.map +1 -1
  318. package/build/dist/Server/Services/Index.js +2 -0
  319. package/build/dist/Server/Services/Index.js.map +1 -1
  320. package/build/dist/Server/Services/IoTFleetLabelRuleEngineService.js +8 -1
  321. package/build/dist/Server/Services/IoTFleetLabelRuleEngineService.js.map +1 -1
  322. package/build/dist/Server/Services/IoTFleetOwnerRuleEngineService.js +8 -1
  323. package/build/dist/Server/Services/IoTFleetOwnerRuleEngineService.js.map +1 -1
  324. package/build/dist/Server/Services/KubernetesClusterLabelRuleEngineService.js +8 -1
  325. package/build/dist/Server/Services/KubernetesClusterLabelRuleEngineService.js.map +1 -1
  326. package/build/dist/Server/Services/KubernetesClusterOwnerRuleEngineService.js +8 -1
  327. package/build/dist/Server/Services/KubernetesClusterOwnerRuleEngineService.js.map +1 -1
  328. package/build/dist/Server/Services/KubernetesResourceService.js +5 -1
  329. package/build/dist/Server/Services/KubernetesResourceService.js.map +1 -1
  330. package/build/dist/Server/Services/MonitorLabelRuleEngineService.js +8 -1
  331. package/build/dist/Server/Services/MonitorLabelRuleEngineService.js.map +1 -1
  332. package/build/dist/Server/Services/MonitorOwnerRuleEngineService.js +8 -1
  333. package/build/dist/Server/Services/MonitorOwnerRuleEngineService.js.map +1 -1
  334. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +30 -21
  335. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
  336. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js +64 -0
  337. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js.map +1 -1
  338. package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js +8 -1
  339. package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js.map +1 -1
  340. package/build/dist/Server/Services/NetworkDeviceOidTemplateService.js +180 -0
  341. package/build/dist/Server/Services/NetworkDeviceOidTemplateService.js.map +1 -0
  342. package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js +8 -1
  343. package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js.map +1 -1
  344. package/build/dist/Server/Services/NetworkDeviceService.js +154 -1
  345. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
  346. package/build/dist/Server/Services/OnCallDutyPolicyLabelRuleEngineService.js +8 -1
  347. package/build/dist/Server/Services/OnCallDutyPolicyLabelRuleEngineService.js.map +1 -1
  348. package/build/dist/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.js +8 -1
  349. package/build/dist/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.js.map +1 -1
  350. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.js +8 -1
  351. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.js.map +1 -1
  352. package/build/dist/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.js +8 -1
  353. package/build/dist/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.js.map +1 -1
  354. package/build/dist/Server/Services/PodmanHostLabelRuleEngineService.js +8 -1
  355. package/build/dist/Server/Services/PodmanHostLabelRuleEngineService.js.map +1 -1
  356. package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js +8 -1
  357. package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js.map +1 -1
  358. package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js +8 -1
  359. package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js.map +1 -1
  360. package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js +8 -1
  361. package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js.map +1 -1
  362. package/build/dist/Server/Services/RumApplicationLabelRuleEngineService.js +8 -1
  363. package/build/dist/Server/Services/RumApplicationLabelRuleEngineService.js.map +1 -1
  364. package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js +8 -1
  365. package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js.map +1 -1
  366. package/build/dist/Server/Services/RunbookLabelRuleEngineService.js +8 -1
  367. package/build/dist/Server/Services/RunbookLabelRuleEngineService.js.map +1 -1
  368. package/build/dist/Server/Services/RunbookOwnerRuleEngineService.js +8 -1
  369. package/build/dist/Server/Services/RunbookOwnerRuleEngineService.js.map +1 -1
  370. package/build/dist/Server/Services/RunbookRuleEngineService.js +8 -1
  371. package/build/dist/Server/Services/RunbookRuleEngineService.js.map +1 -1
  372. package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js +8 -1
  373. package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js.map +1 -1
  374. package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js +8 -1
  375. package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js.map +1 -1
  376. package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js +8 -1
  377. package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js.map +1 -1
  378. package/build/dist/Server/Services/ServerlessFunctionLabelRuleEngineService.js +8 -1
  379. package/build/dist/Server/Services/ServerlessFunctionLabelRuleEngineService.js.map +1 -1
  380. package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js +8 -1
  381. package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js.map +1 -1
  382. package/build/dist/Server/Services/ServiceLabelRuleEngineService.js +8 -1
  383. package/build/dist/Server/Services/ServiceLabelRuleEngineService.js.map +1 -1
  384. package/build/dist/Server/Services/ServiceOwnerRuleEngineService.js +8 -1
  385. package/build/dist/Server/Services/ServiceOwnerRuleEngineService.js.map +1 -1
  386. package/build/dist/Server/Services/StatusPageLabelRuleEngineService.js +8 -1
  387. package/build/dist/Server/Services/StatusPageLabelRuleEngineService.js.map +1 -1
  388. package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js +6 -0
  389. package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js.map +1 -1
  390. package/build/dist/Server/Services/StatusPageOwnerRuleEngineService.js +8 -1
  391. package/build/dist/Server/Services/StatusPageOwnerRuleEngineService.js.map +1 -1
  392. package/build/dist/Server/Services/TelemetrySourceMapService.js +213 -19
  393. package/build/dist/Server/Services/TelemetrySourceMapService.js.map +1 -1
  394. package/build/dist/Server/Services/UserService.js +25 -0
  395. package/build/dist/Server/Services/UserService.js.map +1 -1
  396. package/build/dist/Server/Services/WorkflowLabelRuleEngineService.js +8 -1
  397. package/build/dist/Server/Services/WorkflowLabelRuleEngineService.js.map +1 -1
  398. package/build/dist/Server/Services/WorkflowOwnerRuleEngineService.js +8 -1
  399. package/build/dist/Server/Services/WorkflowOwnerRuleEngineService.js.map +1 -1
  400. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js +145 -0
  401. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js.map +1 -0
  402. package/build/dist/Server/Utils/Monitor/CapturedMetricAttributeUtil.js +201 -0
  403. package/build/dist/Server/Utils/Monitor/CapturedMetricAttributeUtil.js.map +1 -0
  404. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +19 -2
  405. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
  406. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +42 -23
  407. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  408. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +29 -0
  409. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  410. package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js +11 -2
  411. package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js.map +1 -1
  412. package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js +16 -1
  413. package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js.map +1 -1
  414. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +10 -0
  415. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
  416. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +33 -0
  417. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
  418. package/build/dist/Server/Utils/Rules/RuleEngineRuleRead.js +37 -0
  419. package/build/dist/Server/Utils/Rules/RuleEngineRuleRead.js.map +1 -0
  420. package/build/dist/Server/Utils/Telemetry/ExceptionSanitizer.js +12 -1
  421. package/build/dist/Server/Utils/Telemetry/ExceptionSanitizer.js.map +1 -1
  422. package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js +14 -2
  423. package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js.map +1 -1
  424. package/build/dist/Server/Utils/Telemetry/SourceMapResolver.js +15 -5
  425. package/build/dist/Server/Utils/Telemetry/SourceMapResolver.js.map +1 -1
  426. package/build/dist/Server/Utils/Telemetry/StackTraceParser.js +307 -0
  427. package/build/dist/Server/Utils/Telemetry/StackTraceParser.js.map +1 -1
  428. package/build/dist/Types/Date.js +27 -0
  429. package/build/dist/Types/Date.js.map +1 -1
  430. package/build/dist/Types/Monitor/SnmpMonitor/SnmpOidListUtil.js +253 -0
  431. package/build/dist/Types/Monitor/SnmpMonitor/SnmpOidListUtil.js.map +1 -0
  432. package/build/dist/Types/Permission.js +86 -0
  433. package/build/dist/Types/Permission.js.map +1 -1
  434. package/build/dist/Types/Rum/SessionReplay.js +19 -0
  435. package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
  436. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.js +83 -0
  437. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.js.map +1 -0
  438. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.js +531 -0
  439. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.js.map +1 -0
  440. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.js +264 -0
  441. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.js.map +1 -0
  442. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.js +122 -0
  443. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.js.map +1 -0
  444. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +213 -233
  445. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
  446. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +139 -152
  447. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
  448. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +212 -232
  449. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
  450. package/build/dist/UI/Components/Charts/Types/ChartEventKind.js +14 -0
  451. package/build/dist/UI/Components/Charts/Types/ChartEventKind.js.map +1 -0
  452. package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js +57 -28
  453. package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js.map +1 -1
  454. package/build/dist/UI/Components/Charts/Utils/XAxis.js +103 -17
  455. package/build/dist/UI/Components/Charts/Utils/XAxis.js.map +1 -1
  456. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +198 -23
  457. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  458. package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js +15 -5
  459. package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js.map +1 -1
  460. package/build/dist/UI/Components/Feed/FeedItem.js +4 -5
  461. package/build/dist/UI/Components/Feed/FeedItem.js.map +1 -1
  462. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js +1 -2
  463. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js.map +1 -1
  464. package/build/dist/UI/Components/Header/UserProfile/UserProfile.js.map +1 -1
  465. package/build/dist/UI/Components/Image/Image.js +6 -1
  466. package/build/dist/UI/Components/Image/Image.js.map +1 -1
  467. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
  468. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
  469. package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js +1 -2
  470. package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js.map +1 -1
  471. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +104 -23
  472. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  473. package/build/dist/UI/Components/Table/TableHeader.js +20 -22
  474. package/build/dist/UI/Components/Table/TableHeader.js.map +1 -1
  475. package/build/dist/UI/Components/Table/TableRow.js +13 -4
  476. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  477. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +153 -0
  478. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +1 -0
  479. package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js.map +1 -1
  480. package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js +127 -7
  481. package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js.map +1 -1
  482. package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js +50 -3
  483. package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js.map +1 -1
  484. package/build/dist/Utils/NetworkDiscovery/ReverseDnsNameUtil.js +132 -0
  485. package/build/dist/Utils/NetworkDiscovery/ReverseDnsNameUtil.js.map +1 -0
  486. package/build/dist/Utils/Rules/RuleEngineLimits.js +31 -0
  487. package/build/dist/Utils/Rules/RuleEngineLimits.js.map +1 -0
  488. package/jest.config.json +1 -0
  489. package/package.json +2 -2
@@ -43,15 +43,21 @@ jest.setTimeout(180_000);
43
43
  */
44
44
 
45
45
  import MultipartFormDataMiddleware, {
46
+ getMultipartFormDataMiddleware,
46
47
  MAX_MULTIPART_FIELDS,
47
48
  MAX_MULTIPART_FIELD_BYTES,
48
49
  MAX_MULTIPART_FILES,
49
50
  MAX_MULTIPART_FILE_BYTES,
50
51
  } from "../../../Server/Middleware/MultipartFormData";
52
+ import {
53
+ SourceMapMaxFilesPerRequest,
54
+ SourceMapMaxFileSizeInBytes,
55
+ } from "../../../Server/EnvironmentConfig";
51
56
  import {
52
57
  ExpressRequest,
53
58
  ExpressResponse,
54
59
  NextFunction,
60
+ RequestHandler,
55
61
  } from "../../../Server/Utils/Express";
56
62
  import Exception from "../../../Types/Exception/Exception";
57
63
  import ExceptionCode from "../../../Types/Exception/ExceptionCode";
@@ -95,11 +101,33 @@ interface Outcome {
95
101
  nextCalls: number;
96
102
  }
97
103
 
104
+ interface RunOptions {
105
+ /*
106
+ * Which handler to drive. Defaults to the shared export, so every call
107
+ * written before getMultipartFormDataMiddleware existed still reads as
108
+ * "the middleware".
109
+ */
110
+ middleware?: RequestHandler;
111
+ /*
112
+ * Override the Content-Type header, for the one case that needs a
113
+ * multipart request busboy cannot parse at all.
114
+ */
115
+ contentType?: string;
116
+ }
117
+
98
118
  /*
99
119
  * Drive the middleware with a real multipart body over a real Readable, so
100
120
  * busboy does the parsing it does in production rather than being faked.
101
121
  */
102
- function run(parts: Array<MultipartPart>): Promise<Outcome> {
122
+ function run(
123
+ parts: Array<MultipartPart>,
124
+ options?: RunOptions,
125
+ ): Promise<Outcome> {
126
+ const middleware: RequestHandler =
127
+ options && options.middleware
128
+ ? options.middleware
129
+ : MultipartFormDataMiddleware;
130
+
103
131
  const body: Buffer = buildMultipartBody(parts);
104
132
 
105
133
  const req: Readable & {
@@ -109,7 +137,10 @@ function run(parts: Array<MultipartPart>): Promise<Outcome> {
109
137
  } = Readable.from([body]) as never;
110
138
 
111
139
  req.headers = {
112
- "content-type": `multipart/form-data; boundary=${BOUNDARY}`,
140
+ "content-type":
141
+ options && options.contentType
142
+ ? options.contentType
143
+ : `multipart/form-data; boundary=${BOUNDARY}`,
113
144
  "content-length": String(body.length),
114
145
  };
115
146
 
@@ -123,7 +154,7 @@ function run(parts: Array<MultipartPart>): Promise<Outcome> {
123
154
  return new Promise<Outcome>((resolve: (value: Outcome) => void): void => {
124
155
  let nextCalls: number = 0;
125
156
 
126
- MultipartFormDataMiddleware(req as unknown as ExpressRequest, res, ((
157
+ middleware(req as unknown as ExpressRequest, res, ((
127
158
  err?: unknown,
128
159
  ): void => {
129
160
  nextCalls++;
@@ -136,6 +167,23 @@ function run(parts: Array<MultipartPart>): Promise<Outcome> {
136
167
  });
137
168
  }
138
169
 
170
+ /*
171
+ * `count` one-byte files. The count limits are what these fixtures probe, so
172
+ * the payload per file is deliberately trivial.
173
+ */
174
+ function tinyFiles(count: number): Array<MultipartPart> {
175
+ return Array.from(
176
+ { length: count },
177
+ (_v: unknown, i: number): MultipartPart => {
178
+ return {
179
+ name: `f${i}`,
180
+ value: Buffer.from("x"),
181
+ filename: `f${i}.bin`,
182
+ };
183
+ },
184
+ );
185
+ }
186
+
139
187
  function files(outcome: Outcome): Array<{ fieldname: string; buffer: Buffer }> {
140
188
  return (outcome.req.files || []) as Array<{
141
189
  fieldname: string;
@@ -155,6 +203,24 @@ describe("MultipartFormData - the limits are set where they were reasoned about"
155
203
  expect(Number.isFinite(MAX_MULTIPART_FILES)).toBe(true);
156
204
  expect(Number.isFinite(MAX_MULTIPART_FIELDS)).toBe(true);
157
205
  });
206
+
207
+ test("the source map env knobs cannot be configured past these two ceilings", () => {
208
+ /*
209
+ * Common/Server/EnvironmentConfig.ts clamps SOURCE_MAP_MAX_FILES_PER_REQUEST
210
+ * to 50 and SOURCE_MAP_MAX_FILE_SIZE_BYTES to 50 MiB, and repeats both as
211
+ * literals rather than importing them - config has no business pulling in
212
+ * multer and express. That copy is the thing this pins: if either constant
213
+ * here moves DOWN, the config default silently becomes unenforceable and
214
+ * multer starts aborting requests the config layer thought it had accepted
215
+ * (a 413 where the operator was promised a 400).
216
+ */
217
+ expect(SourceMapMaxFilesPerRequest).toBeLessThanOrEqual(
218
+ MAX_MULTIPART_FILES,
219
+ );
220
+ expect(SourceMapMaxFileSizeInBytes).toBeLessThanOrEqual(
221
+ MAX_MULTIPART_FILE_BYTES,
222
+ );
223
+ });
158
224
  });
159
225
 
160
226
  describe("MultipartFormData - normal bodies still parse", () => {
@@ -296,3 +362,552 @@ describe("MultipartFormData - breaches answer 413, not 500", () => {
296
362
  expect(outcome.nextCalls).toBe(1);
297
363
  });
298
364
  });
365
+
366
+ /*
367
+ * getMultipartFormDataMiddleware exists so the source map upload route can
368
+ * hold itself to SOURCE_MAP_MAX_FILES_PER_REQUEST files instead of the shared
369
+ * 50. Two properties matter more than the count itself:
370
+ *
371
+ * - it is DOWNWARD only. Every route mounting this parses before its own
372
+ * auth check, so MAX_MULTIPART_FILES is the ceiling an unauthenticated
373
+ * caller is held to across all of them. A knob that could raise it would
374
+ * widen the pre-auth memory surface of routes that never asked for it.
375
+ * - narrowing is per route. It builds a SECOND multer instance rather than
376
+ * reconfiguring the shared one, so a tighter source map route must not
377
+ * make Pyroscope ingest or inbound email tighter by proxy.
378
+ */
379
+ describe("getMultipartFormDataMiddleware - nothing to narrow means the shared instance", () => {
380
+ test("asking for exactly the shared ceiling hands back the default export itself", () => {
381
+ /*
382
+ * Identity, not equivalence: a fresh middleware here would be a second
383
+ * multer with a second memoryStorage for no behavioural difference, and
384
+ * this function is documented as build-once-at-module-scope precisely
385
+ * because instances are not free.
386
+ */
387
+ expect(
388
+ getMultipartFormDataMiddleware({ maxFiles: MAX_MULTIPART_FILES }),
389
+ ).toBe(MultipartFormDataMiddleware);
390
+ });
391
+
392
+ test("one file above the ceiling is clamped back onto the default export", () => {
393
+ expect(
394
+ getMultipartFormDataMiddleware({ maxFiles: MAX_MULTIPART_FILES + 1 }),
395
+ ).toBe(MultipartFormDataMiddleware);
396
+ });
397
+
398
+ test("absurd, unbounded and fractional requests above the ceiling all clamp onto the default export", () => {
399
+ /*
400
+ * The clamp is what turns a misconfigured SOURCE_MAP_MAX_FILES_PER_REQUEST
401
+ * into a no-op instead of a widened pre-auth surface, so every shape an
402
+ * operator could plausibly produce has to land on the shared instance.
403
+ *
404
+ * Written against MAX_MULTIPART_FILES rather than the number it happens
405
+ * to hold, so raising the shared ceiling does not quietly turn these into
406
+ * assertions about a value that is no longer above it.
407
+ */
408
+ for (const attempted of [
409
+ MAX_MULTIPART_FILES + 1,
410
+ MAX_MULTIPART_FILES + 0.5,
411
+ MAX_MULTIPART_FILES * 2,
412
+ 1000,
413
+ Number.MAX_SAFE_INTEGER,
414
+ Number.POSITIVE_INFINITY,
415
+ ]) {
416
+ expect(getMultipartFormDataMiddleware({ maxFiles: attempted })).toBe(
417
+ MultipartFormDataMiddleware,
418
+ );
419
+ }
420
+ });
421
+
422
+ test("no attempted value yields a middleware that accepts more than MAX_MULTIPART_FILES files", async () => {
423
+ /*
424
+ * The identity checks above prove the fast path was taken; this proves
425
+ * the property those checks are a proxy for. If the clamp were ever
426
+ * dropped, an instance built for 1000 files would happily buffer 51 of
427
+ * them before auth - so drive the returned handler with one file more
428
+ * than the shared ceiling and require the 413 either way.
429
+ */
430
+ for (const attempted of [
431
+ MAX_MULTIPART_FILES + 1,
432
+ MAX_MULTIPART_FILES * 2,
433
+ MAX_MULTIPART_FILES * 10,
434
+ Number.MAX_SAFE_INTEGER,
435
+ Number.POSITIVE_INFINITY,
436
+ ]) {
437
+ const middleware: RequestHandler = getMultipartFormDataMiddleware({
438
+ maxFiles: attempted,
439
+ });
440
+
441
+ const outcome: Outcome = await run(tinyFiles(MAX_MULTIPART_FILES + 1), {
442
+ middleware: middleware,
443
+ });
444
+
445
+ expect((outcome.error as Exception).code).toBe(
446
+ ExceptionCode.PayloadTooLargeException,
447
+ );
448
+ expect((outcome.error as Exception).message).toContain(
449
+ "LIMIT_FILE_COUNT",
450
+ );
451
+ }
452
+ });
453
+ });
454
+
455
+ describe("getMultipartFormDataMiddleware - a narrowed instance is narrower, and only for itself", () => {
456
+ const narrow: RequestHandler = getMultipartFormDataMiddleware({
457
+ maxFiles: 2,
458
+ });
459
+
460
+ test("a genuinely narrower request builds its own handler, not the shared one", () => {
461
+ expect(narrow).not.toBe(MultipartFormDataMiddleware);
462
+ });
463
+
464
+ test("exactly its own file limit is accepted", async () => {
465
+ const outcome: Outcome = await run(tinyFiles(2), { middleware: narrow });
466
+
467
+ expect(outcome.error).toBeUndefined();
468
+ expect(files(outcome)).toHaveLength(2);
469
+ });
470
+
471
+ test("one file under its limit is accepted", async () => {
472
+ const outcome: Outcome = await run(tinyFiles(1), { middleware: narrow });
473
+
474
+ expect(outcome.error).toBeUndefined();
475
+ expect(files(outcome)).toHaveLength(1);
476
+ });
477
+
478
+ test("one file over its limit answers 413, not the shared 50-file limit", async () => {
479
+ const outcome: Outcome = await run(tinyFiles(3), { middleware: narrow });
480
+
481
+ expect(outcome.error).toBeInstanceOf(Exception);
482
+ expect((outcome.error as Exception).code).toBe(
483
+ ExceptionCode.PayloadTooLargeException,
484
+ );
485
+ expect((outcome.error as Exception).code).toBe(413);
486
+ expect((outcome.error as Exception).message).toContain("LIMIT_FILE_COUNT");
487
+ });
488
+
489
+ test("the very same three files still pass the default middleware", async () => {
490
+ /*
491
+ * The regression this guards: narrowing one route by mutating the shared
492
+ * multer's limits would look identical in the test above and quietly cut
493
+ * Pyroscope ingest and SendGrid inbound email down to two files each.
494
+ */
495
+ const outcome: Outcome = await run(tinyFiles(3));
496
+
497
+ expect(outcome.error).toBeUndefined();
498
+ expect(files(outcome)).toHaveLength(3);
499
+ });
500
+
501
+ test("the default middleware still accepts a full 50 files after a narrower one exists", async () => {
502
+ const outcome: Outcome = await run(tinyFiles(MAX_MULTIPART_FILES));
503
+
504
+ expect(outcome.error).toBeUndefined();
505
+ expect(files(outcome)).toHaveLength(MAX_MULTIPART_FILES);
506
+ });
507
+
508
+ test("the narrowed instance stays narrow after the default has been used", async () => {
509
+ /*
510
+ * The mirror image of the leak: two multer instances sharing mutable
511
+ * limits would drift in whichever direction ran last, so re-drive the
512
+ * narrow one after the 50-file body above.
513
+ */
514
+ const outcome: Outcome = await run(tinyFiles(3), { middleware: narrow });
515
+
516
+ expect((outcome.error as Exception).message).toContain("LIMIT_FILE_COUNT");
517
+ });
518
+ });
519
+
520
+ describe("getMultipartFormDataMiddleware - the low end clamps up to 1, never to zero", () => {
521
+ test("maxFiles: 0 still accepts a file", async () => {
522
+ /*
523
+ * multer reads `files: 0` as "no files at all", which would turn a
524
+ * misconfigured SOURCE_MAP_MAX_FILES_PER_REQUEST into a route that 413s
525
+ * every upload. Clamping up to 1 keeps the route working, degraded, and
526
+ * the parse still bounded.
527
+ */
528
+ const middleware: RequestHandler = getMultipartFormDataMiddleware({
529
+ maxFiles: 0,
530
+ });
531
+
532
+ const outcome: Outcome = await run(tinyFiles(1), {
533
+ middleware: middleware,
534
+ });
535
+
536
+ expect(outcome.error).toBeUndefined();
537
+ expect(files(outcome)).toHaveLength(1);
538
+ });
539
+
540
+ test("maxFiles: 0 rejects the second file, so it clamped to 1 rather than to the default", async () => {
541
+ const middleware: RequestHandler = getMultipartFormDataMiddleware({
542
+ maxFiles: 0,
543
+ });
544
+
545
+ const outcome: Outcome = await run(tinyFiles(2), {
546
+ middleware: middleware,
547
+ });
548
+
549
+ expect((outcome.error as Exception).code).toBe(
550
+ ExceptionCode.PayloadTooLargeException,
551
+ );
552
+ expect((outcome.error as Exception).message).toContain("LIMIT_FILE_COUNT");
553
+ });
554
+
555
+ test("a negative maxFiles behaves exactly like 1", async () => {
556
+ const middleware: RequestHandler = getMultipartFormDataMiddleware({
557
+ maxFiles: -5,
558
+ });
559
+
560
+ const accepted: Outcome = await run(tinyFiles(1), {
561
+ middleware: middleware,
562
+ });
563
+ const rejected: Outcome = await run(tinyFiles(2), {
564
+ middleware: middleware,
565
+ });
566
+
567
+ expect(accepted.error).toBeUndefined();
568
+ expect(files(accepted)).toHaveLength(1);
569
+ expect((rejected.error as Exception).code).toBe(
570
+ ExceptionCode.PayloadTooLargeException,
571
+ );
572
+ });
573
+
574
+ test("clamped-up values are still their own handler, not the shared one", () => {
575
+ expect(getMultipartFormDataMiddleware({ maxFiles: 0 })).not.toBe(
576
+ MultipartFormDataMiddleware,
577
+ );
578
+ expect(getMultipartFormDataMiddleware({ maxFiles: -5 })).not.toBe(
579
+ MultipartFormDataMiddleware,
580
+ );
581
+ });
582
+ });
583
+
584
+ /*
585
+ * The DOMAIN is clamped, not only the range.
586
+ *
587
+ * busboy's file-count check is `files === filesLimit` - an equality against a
588
+ * counter that only ever holds whole numbers. A fractional or NaN limit
589
+ * therefore never matches anything: it does not narrow the parse, it removes
590
+ * the file bound outright and leaves an unauthenticated caller free to send as
591
+ * many files as it likes. That is the precise widening this function exists to
592
+ * prevent, so Math.floor and the finite check are load-bearing rather than
593
+ * defensive tidiness.
594
+ *
595
+ * Latent as things stand - the only caller passes the value through
596
+ * parsePositiveIntegerFromEnv, which rejects "1.5" and garbage before it gets
597
+ * here. Pinned anyway, because the function is exported and the next caller
598
+ * may not come through the config layer at all.
599
+ */
600
+ describe("getMultipartFormDataMiddleware - a non-integer maxFiles cannot unbound the parse", () => {
601
+ test("a fractional maxFiles narrows to the whole number below it", async () => {
602
+ const middleware: RequestHandler = getMultipartFormDataMiddleware({
603
+ maxFiles: 2.5,
604
+ });
605
+
606
+ const accepted: Outcome = await run(tinyFiles(2), {
607
+ middleware: middleware,
608
+ });
609
+ const rejected: Outcome = await run(tinyFiles(3), {
610
+ middleware: middleware,
611
+ });
612
+
613
+ expect(accepted.error).toBeUndefined();
614
+ expect(files(accepted)).toHaveLength(2);
615
+ /*
616
+ * The half is what matters: handed 2.5 straight to multer, this third
617
+ * file arrives with no error at all.
618
+ */
619
+ expect((rejected.error as Exception).code).toBe(
620
+ ExceptionCode.PayloadTooLargeException,
621
+ );
622
+ expect((rejected.error as Exception).message).toContain("LIMIT_FILE_COUNT");
623
+ });
624
+
625
+ test("a fractional maxFiles above the ceiling is still bounded by the ceiling", async () => {
626
+ const middleware: RequestHandler = getMultipartFormDataMiddleware({
627
+ maxFiles: MAX_MULTIPART_FILES + 0.5,
628
+ });
629
+
630
+ const outcome: Outcome = await run(tinyFiles(MAX_MULTIPART_FILES + 1), {
631
+ middleware: middleware,
632
+ });
633
+
634
+ expect((outcome.error as Exception).code).toBe(
635
+ ExceptionCode.PayloadTooLargeException,
636
+ );
637
+ expect((outcome.error as Exception).message).toContain("LIMIT_FILE_COUNT");
638
+ });
639
+
640
+ test("NaN falls back to the shared ceiling rather than removing the file bound", async () => {
641
+ /*
642
+ * NaN survives every comparison a naive clamp makes - Math.min(NaN, 50)
643
+ * and Math.max(1, NaN) are both NaN - so it would reach multer intact and
644
+ * silently uncap the route. It has to land on the shared instance instead.
645
+ */
646
+ const middleware: RequestHandler = getMultipartFormDataMiddleware({
647
+ maxFiles: Number.NaN,
648
+ });
649
+
650
+ expect(middleware).toBe(MultipartFormDataMiddleware);
651
+
652
+ const outcome: Outcome = await run(tinyFiles(MAX_MULTIPART_FILES + 1), {
653
+ middleware: middleware,
654
+ });
655
+
656
+ expect((outcome.error as Exception).code).toBe(
657
+ ExceptionCode.PayloadTooLargeException,
658
+ );
659
+ expect((outcome.error as Exception).message).toContain("LIMIT_FILE_COUNT");
660
+ });
661
+ });
662
+
663
+ describe("getMultipartFormDataMiddleware - narrowing files changes nothing else", () => {
664
+ const narrow: RequestHandler = getMultipartFormDataMiddleware({
665
+ maxFiles: 2,
666
+ });
667
+
668
+ test("its own file-count limit does not relax the shared size ceiling", async () => {
669
+ const outcome: Outcome = await run(
670
+ [
671
+ {
672
+ name: "big",
673
+ value: Buffer.alloc(MAX_MULTIPART_FILE_BYTES + 1),
674
+ filename: "big.bin",
675
+ },
676
+ ],
677
+ { middleware: narrow },
678
+ );
679
+
680
+ expect((outcome.error as Exception).code).toBe(
681
+ ExceptionCode.PayloadTooLargeException,
682
+ );
683
+ expect((outcome.error as Exception).message).toContain("LIMIT_FILE_SIZE");
684
+ });
685
+
686
+ test("the shared size ceiling is INCLUSIVE, and a narrowed instance lands on the same byte", async () => {
687
+ /*
688
+ * busboy truncates a file the moment its byte count REACHES fileSize,
689
+ * so the middleware hands it MAX_MULTIPART_FILE_BYTES + 1 to make the
690
+ * constant itself an inclusive maximum.
691
+ *
692
+ * Worth pinning rather than glossing: EnvironmentConfig clamps
693
+ * SOURCE_MAP_MAX_FILE_SIZE_BYTES to exactly MAX_MULTIPART_FILE_BYTES and
694
+ * SourceMapIngestService rejects only what is STRICTLY over it, so a map
695
+ * of precisely that many bytes is one the service means to accept -- and
696
+ * before the +1 the parser killed it first, turning the 400 the endpoint
697
+ * documents into a 413 it never saw. Narrowing the file COUNT must not
698
+ * move that boundary either.
699
+ */
700
+ // One allocation, driven through both instances - it is 50 MiB.
701
+ const atLimit: Buffer = Buffer.alloc(MAX_MULTIPART_FILE_BYTES);
702
+
703
+ const atCeiling: Outcome = await run(
704
+ [{ name: "atlimit", value: atLimit, filename: "atlimit.bin" }],
705
+ { middleware: narrow },
706
+ );
707
+
708
+ expect(atCeiling.error).toBeUndefined();
709
+ expect(files(atCeiling)[0]!.buffer.length).toBe(MAX_MULTIPART_FILE_BYTES);
710
+
711
+ // The shared instance is the baseline the narrowed one must match.
712
+ const sharedAtCeiling: Outcome = await run([
713
+ { name: "atlimit", value: atLimit, filename: "atlimit.bin" },
714
+ ]);
715
+
716
+ expect(sharedAtCeiling.error).toBeUndefined();
717
+ expect(files(sharedAtCeiling)[0]!.buffer.length).toBe(
718
+ MAX_MULTIPART_FILE_BYTES,
719
+ );
720
+
721
+ const overCeiling: Outcome = await run(
722
+ [
723
+ {
724
+ name: "overlimit",
725
+ value: Buffer.alloc(MAX_MULTIPART_FILE_BYTES + 1),
726
+ filename: "overlimit.bin",
727
+ },
728
+ ],
729
+ { middleware: narrow },
730
+ );
731
+
732
+ expect((overCeiling.error as Exception).code).toBe(
733
+ ExceptionCode.PayloadTooLargeException,
734
+ );
735
+ expect((overCeiling.error as Exception).message).toContain(
736
+ "LIMIT_FILE_SIZE",
737
+ );
738
+ });
739
+
740
+ test("the shared field-value ceiling still applies", async () => {
741
+ const outcome: Outcome = await run(
742
+ [{ name: "html", value: Buffer.alloc(MAX_MULTIPART_FIELD_BYTES + 1) }],
743
+ { middleware: narrow },
744
+ );
745
+
746
+ expect((outcome.error as Exception).code).toBe(
747
+ ExceptionCode.PayloadTooLargeException,
748
+ );
749
+ expect((outcome.error as Exception).message).toContain("LIMIT_FIELD_VALUE");
750
+ });
751
+
752
+ test("the whole shared field allowance still parses alongside its files", async () => {
753
+ /*
754
+ * `parts` is files + fields, so a narrowed instance has to carry the
755
+ * field allowance over rather than deriving the part budget from its own
756
+ * file count. Leaving parts at 2 - or at anything near it - would make
757
+ * the part count the effective limit, and the source map route would
758
+ * start 413ing bodies whose field count the shared config says are fine.
759
+ */
760
+ const outcome: Outcome = await run(
761
+ [
762
+ ...Array.from(
763
+ { length: MAX_MULTIPART_FIELDS },
764
+ (_v: unknown, i: number): MultipartPart => {
765
+ return { name: `k${i}`, value: Buffer.from("v") };
766
+ },
767
+ ),
768
+ ...tinyFiles(1),
769
+ ],
770
+ { middleware: narrow },
771
+ );
772
+
773
+ expect(outcome.error).toBeUndefined();
774
+ expect(
775
+ Object.keys(outcome.req.body as Record<string, unknown>),
776
+ ).toHaveLength(MAX_MULTIPART_FIELDS);
777
+ expect(files(outcome)).toHaveLength(1);
778
+ });
779
+
780
+ test("its full file count fits alongside one field short of the allowance", async () => {
781
+ const outcome: Outcome = await run(
782
+ [
783
+ ...Array.from(
784
+ { length: MAX_MULTIPART_FIELDS - 1 },
785
+ (_v: unknown, i: number): MultipartPart => {
786
+ return { name: `k${i}`, value: Buffer.from("v") };
787
+ },
788
+ ),
789
+ ...tinyFiles(2),
790
+ ],
791
+ { middleware: narrow },
792
+ );
793
+
794
+ expect(outcome.error).toBeUndefined();
795
+ expect(files(outcome)).toHaveLength(2);
796
+ });
797
+
798
+ test("the maximal body - the full file AND field allowance - is accepted", async () => {
799
+ /*
800
+ * busboy starts its part counter at -1 to account for the opening
801
+ * boundary and then fires partsLimit when the counter REACHES the limit,
802
+ * so a raw `parts: n` admits only n - 1. That used to reject a body
803
+ * carrying the file limit AND the field limit in full with
804
+ * LIMIT_PART_COUNT, though neither of those limits was breached -- the
805
+ * exact thing the comment on `parts` says must not happen. The
806
+ * middleware now converts it, so the maximal body parses.
807
+ *
808
+ * Pinned on BOTH instances so the narrowed one is provably no tighter
809
+ * than the shared one: a narrowing that also stole a part would show up
810
+ * here rather than in production.
811
+ */
812
+ const fields: (count: number) => Array<MultipartPart> = (
813
+ count: number,
814
+ ): Array<MultipartPart> => {
815
+ return Array.from(
816
+ { length: count },
817
+ (_v: unknown, i: number): MultipartPart => {
818
+ return { name: `k${i}`, value: Buffer.from("v") };
819
+ },
820
+ );
821
+ };
822
+
823
+ const narrowed: Outcome = await run(
824
+ [...fields(MAX_MULTIPART_FIELDS), ...tinyFiles(2)],
825
+ { middleware: narrow },
826
+ );
827
+
828
+ expect(narrowed.error).toBeUndefined();
829
+ expect(files(narrowed)).toHaveLength(2);
830
+
831
+ const shared: Outcome = await run([
832
+ ...fields(MAX_MULTIPART_FIELDS),
833
+ ...tinyFiles(MAX_MULTIPART_FILES),
834
+ ]);
835
+
836
+ expect(shared.error).toBeUndefined();
837
+ expect(files(shared)).toHaveLength(MAX_MULTIPART_FILES);
838
+ });
839
+
840
+ test("one file past the maximal body is LIMIT_FILE_COUNT, not LIMIT_PART_COUNT", async () => {
841
+ /*
842
+ * The counts stay the limits that actually speak. Raising `parts` to
843
+ * admit the maximal body must not push the parts limit down onto a body
844
+ * that breaches the file allowance -- the caller needs to be told which
845
+ * allowance they exceeded.
846
+ */
847
+ const outcome: Outcome = await run(
848
+ Array.from(
849
+ { length: MAX_MULTIPART_FIELDS },
850
+ (_v: unknown, i: number): MultipartPart => {
851
+ return { name: `k${i}`, value: Buffer.from("v") };
852
+ },
853
+ ).concat(tinyFiles(MAX_MULTIPART_FILES + 1)),
854
+ );
855
+
856
+ expect((outcome.error as Exception).code).toBe(
857
+ ExceptionCode.PayloadTooLargeException,
858
+ );
859
+ expect((outcome.error as Exception).message).toContain("LIMIT_FILE_COUNT");
860
+ });
861
+
862
+ test("one field too many is still LIMIT_FIELD_COUNT, not LIMIT_PART_COUNT", async () => {
863
+ const outcome: Outcome = await run(
864
+ Array.from(
865
+ { length: MAX_MULTIPART_FIELDS + 1 },
866
+ (_v: unknown, i: number): MultipartPart => {
867
+ return { name: `k${i}`, value: Buffer.from("v") };
868
+ },
869
+ ),
870
+ { middleware: narrow },
871
+ );
872
+
873
+ expect((outcome.error as Exception).code).toBe(
874
+ ExceptionCode.PayloadTooLargeException,
875
+ );
876
+ expect((outcome.error as Exception).message).toContain("LIMIT_FIELD_COUNT");
877
+ });
878
+
879
+ test("next() is called exactly once on a breach here too", async () => {
880
+ const outcome: Outcome = await run(tinyFiles(3), { middleware: narrow });
881
+
882
+ expect(outcome.nextCalls).toBe(1);
883
+ });
884
+
885
+ test("a non-multer error passes straight through instead of becoming a 413", async () => {
886
+ /*
887
+ * A multipart Content-Type with no boundary makes busboy throw during
888
+ * construction, which multer hands to next() as a plain Error. That is a
889
+ * malformed request, not an oversized one, and the error mapping both
890
+ * instances share must not launder it into a PayloadTooLargeException -
891
+ * doing so would report every parser failure as "you sent too much".
892
+ */
893
+ const outcome: Outcome = await run(tinyFiles(1), {
894
+ middleware: narrow,
895
+ contentType: "multipart/form-data",
896
+ });
897
+
898
+ expect(outcome.error).toBeInstanceOf(Error);
899
+ expect(outcome.error).not.toBeInstanceOf(Exception);
900
+ expect((outcome.error as Error).message).toContain("Boundary not found");
901
+ expect(outcome.nextCalls).toBe(1);
902
+ });
903
+
904
+ test("the default middleware treats that same non-multer error identically", async () => {
905
+ const outcome: Outcome = await run(tinyFiles(1), {
906
+ contentType: "multipart/form-data",
907
+ });
908
+
909
+ expect(outcome.error).toBeInstanceOf(Error);
910
+ expect(outcome.error).not.toBeInstanceOf(Exception);
911
+ expect((outcome.error as Error).message).toContain("Boundary not found");
912
+ });
913
+ });