@oneuptime/common 13.0.8 → 14.0.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 (333) hide show
  1. package/Models/AnalyticsModels/AuditLog.ts +23 -15
  2. package/Models/DatabaseModels/GlobalConfig.ts +24 -0
  3. package/Models/DatabaseModels/Monitor.ts +3 -2
  4. package/Models/DatabaseModels/MonitorTemplate.ts +2 -1
  5. package/Scripts/generate-service-worker.js +65 -4
  6. package/Server/API/BaseAPI.ts +26 -5
  7. package/Server/API/GlobalConfigAPI.ts +228 -462
  8. package/Server/API/ProjectOIDC.ts +25 -16
  9. package/Server/API/ProjectSSO.ts +24 -16
  10. package/Server/API/StatusPageAPI.ts +100 -42
  11. package/Server/API/TeamMemberAPI.ts +10 -1
  12. package/Server/Enterprise/EnterpriseEdition.ts +649 -0
  13. package/Server/Enterprise/EnterpriseFeature.ts +48 -0
  14. package/Server/Enterprise/EnterpriseLicenseSnapshot.ts +192 -0
  15. package/Server/Enterprise/EnterpriseServerModule.ts +233 -0
  16. package/Server/EnvironmentConfig.ts +147 -2
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.ts +25 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
  19. package/Server/Middleware/UserAuthorization.ts +38 -16
  20. package/Server/Services/AuditLogService.ts +84 -1079
  21. package/Server/Services/EnterpriseLicenseService.ts +38 -0
  22. package/Server/Services/GlobalConfigService.ts +80 -1
  23. package/Server/Services/MonitorProbeService.ts +116 -20
  24. package/Server/Services/MonitorService.ts +56 -4
  25. package/Server/Services/MonitorStatusTimelineService.ts +284 -0
  26. package/Server/Services/MonitorTemplateService.ts +26 -0
  27. package/Server/Services/ProjectService.ts +284 -0
  28. package/Server/Services/RumSessionPinService.ts +25 -6
  29. package/Server/Services/StatusPagePrivateUserService.ts +7 -3
  30. package/Server/Services/StatusPageService.ts +78 -1
  31. package/Server/Services/TeamMemberService.ts +11 -0
  32. package/Server/Services/TeamService.ts +10 -0
  33. package/Server/Services/UserService.ts +10 -17
  34. package/Server/Types/Database/Permissions/CreatePermission.ts +15 -0
  35. package/Server/Types/Database/Permissions/EditionPermission.ts +208 -18
  36. package/Server/Types/Database/Permissions/TablePermission.ts +10 -3
  37. package/Server/Types/Database/Permissions/UpdatePermission.ts +29 -0
  38. package/Server/Types/Markdown.ts +41 -0
  39. package/Server/Utils/CommunityEditionSsoReport.ts +361 -0
  40. package/Server/Utils/EditionEnforcement.ts +233 -0
  41. package/Server/Utils/FrontendEnvironment.ts +41 -2
  42. package/Server/Utils/InstanceHealth/RedisHealth.ts +12 -277
  43. package/Server/Utils/Monitor/AffectedResourceList.ts +190 -0
  44. package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +10 -1
  45. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +543 -333
  46. package/Server/Utils/Monitor/MonitoringIntervalValidator.ts +116 -0
  47. package/Server/Utils/Workspace/Slack/Slack.ts +423 -10
  48. package/Tests/App/Accounts/LoginPasskey.test.tsx +18 -0
  49. package/Tests/App/Accounts/LoginSsoEdition.test.tsx +616 -0
  50. package/Tests/App/AdminDashboard/AdminAuthenticationSsoEdition.test.tsx +217 -0
  51. package/Tests/App/AdminDashboard/AdminEnterprisePluginPage.test.tsx +357 -0
  52. package/Tests/App/AdminDashboard/EnterpriseLicensesShell.test.tsx +214 -0
  53. package/Tests/App/AdminDashboard/GlobalSSOEnterpriseShells.test.tsx +271 -0
  54. package/Tests/App/AdminDashboard/HealthShells.test.tsx +659 -0
  55. package/Tests/App/Dashboard/AuditLogsAndComplianceShells.test.tsx +572 -0
  56. package/Tests/App/Dashboard/EnterpriseFeatureUpgrade.test.tsx +547 -0
  57. package/Tests/App/Dashboard/EnterprisePluginPage.test.tsx +667 -0
  58. package/Tests/App/Dashboard/IdentityEnterpriseShells.test.tsx +319 -0
  59. package/Tests/App/Dashboard/OnboardingSsoEmptyState.test.tsx +185 -0
  60. package/Tests/App/Dashboard/SecurityEventConnectionDiagnostics.test.tsx +45 -9
  61. package/Tests/App/Dashboard/SecurityEventDetailPanel.test.tsx +399 -0
  62. package/Tests/App/Dashboard/SecurityEventListRow.test.tsx +214 -0
  63. package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +1 -83
  64. package/Tests/App/Dashboard/SecurityEventsNavTabs.test.tsx +248 -0
  65. package/Tests/App/Dashboard/SecurityEventsViewer.test.tsx +1203 -0
  66. package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +11 -91
  67. package/Tests/App/StatusPage/StatusPageSsoEmptyState.test.tsx +319 -0
  68. package/Tests/Helpers/RefreshAwareApiScan.ts +757 -0
  69. package/Tests/Helpers/TenantScopedRequestScan.ts +515 -0
  70. package/Tests/Scripts/GenerateServiceWorker.test.ts +931 -0
  71. package/Tests/Server/API/BaseAPICreateItemDoesNotMutateModel.test.ts +130 -0
  72. package/Tests/Server/API/GlobalConfigLicense.test.ts +742 -497
  73. package/Tests/Server/API/OnCallReadinessAPI.test.ts +35 -909
  74. package/Tests/Server/API/SsoProviderListingsEdition.test.ts +432 -0
  75. package/Tests/Server/API/TeamMemberLeaveScimLockEdition.test.ts +252 -0
  76. package/Tests/Server/Enterprise/EnterpriseEdition.test.ts +824 -0
  77. package/Tests/Server/Enterprise/EnterpriseFeatureActive.test.ts +643 -0
  78. package/Tests/Server/Enterprise/EnterpriseLicenseSnapshot.test.ts +294 -0
  79. package/Tests/Server/Enterprise/EnterpriseModelFeatureMap.test.ts +93 -0
  80. package/Tests/Server/Enterprise/EnterpriseOnlyModulesLiveInEe.test.ts +582 -0
  81. package/Tests/Server/Enterprise/EnterpriseServerModule.test.ts +247 -0
  82. package/Tests/Server/Enterprise/FakeEnterpriseModule.ts +502 -0
  83. package/Tests/Server/Enterprise/TestBillingFlag.ts +70 -0
  84. package/Tests/Server/EnvironmentConfigEnterpriseEdition.test.ts +314 -0
  85. package/Tests/Server/Infrastructure/ContainerBootConfiguration.test.ts +289 -0
  86. package/Tests/Server/Infrastructure/E2EClickHouseFixtureAccess.test.ts +5 -1
  87. package/Tests/Server/Middleware/UserAuthorization.test.ts +37 -2
  88. package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +516 -0
  89. package/Tests/Server/Services/AuditLogService.test.ts +460 -990
  90. package/Tests/Server/Services/CreateAndReadResponsesKeepIds.test.ts +263 -0
  91. package/Tests/Server/Services/EnterpriseLicenseServiceKeyGeneration.test.ts +151 -0
  92. package/Tests/Server/Services/GlobalConfigServiceLicenseColumns.test.ts +357 -0
  93. package/Tests/Server/Services/MonitorDestinationInfoIPv6.test.ts +101 -0
  94. package/Tests/Server/Services/MonitorProbeServiceIntervalScheduling.test.ts +333 -0
  95. package/Tests/Server/Services/MonitorStatusTimelineDailyAggregates.test.ts +303 -0
  96. package/Tests/Server/Services/ProjectServiceAuditLogLicense.test.ts +701 -0
  97. package/Tests/Server/Services/ProjectServiceAuditLogSettingsCache.test.ts +31 -35
  98. package/Tests/Server/Services/ScimPushGroupsTeamLocksEdition.test.ts +431 -0
  99. package/Tests/Server/Services/SsoRequirementReadMasking.test.ts +419 -0
  100. package/Tests/Server/Services/SsoRequirementWriteGuard.test.ts +769 -0
  101. package/Tests/Server/Services/StatusPagePrivateUserInvitationPolicy.test.ts +94 -0
  102. package/Tests/Server/Services/UserAuthenticationService.test.ts +35 -0
  103. package/Tests/Server/Services/UserServiceSeatLimit.test.ts +94 -56
  104. package/Tests/Server/Types/Database/Permissions/EditionPermission.test.ts +1823 -0
  105. package/Tests/Server/Types/Markdown.test.ts +181 -0
  106. package/Tests/Server/Utils/CommunityEditionSsoReport.test.ts +565 -0
  107. package/Tests/Server/Utils/EditionEnforcement.test.ts +303 -0
  108. package/Tests/Server/Utils/FrontendEnvironment.test.ts +367 -0
  109. package/Tests/Server/Utils/InstanceHealth/RedisHealth.test.ts +38 -418
  110. package/Tests/Server/Utils/Monitor/AffectedResourceList.test.ts +518 -0
  111. package/Tests/Server/Utils/Monitor/Criteria/EvaluateOverTime.test.ts +24 -4
  112. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +934 -96
  113. package/Tests/Server/Utils/Monitor/MonitoringIntervalValidator.test.ts +188 -0
  114. package/Tests/Server/Utils/Workspace/Slack/SlackMarkdownSectionSplit.test.ts +1209 -0
  115. package/Tests/Types/API/HostnameFromAuthority.test.ts +20 -10
  116. package/Tests/Types/API/HostnameIPv6.test.ts +149 -0
  117. package/Tests/Types/Database/CanonicalModelInstance.test.ts +190 -0
  118. package/Tests/UI/Components/EditionLabelLapseCopy.ts +104 -0
  119. package/Tests/UI/Components/EditionLabelLicenseManagerWiring.test.tsx +254 -0
  120. package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +84 -178
  121. package/Tests/UI/Components/EditionLabelLicenseStatus.test.tsx +1586 -0
  122. package/Tests/UI/Components/EditionLabelLicenseWritesGuard.test.tsx +157 -0
  123. package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +49 -2
  124. package/Tests/UI/Components/MarkdownConverters.test.ts +684 -0
  125. package/Tests/UI/Components/ModelListEmptyState.test.tsx +289 -0
  126. package/Tests/UI/Components/TelemetryViewer/TelemetryViewerEmptyContent.test.tsx +131 -0
  127. package/Tests/UI/EsbuildEnterpriseAlias.test.ts +1127 -0
  128. package/Tests/Utils/HostAddressUtil.test.ts +138 -0
  129. package/Tests/Utils/Monitor/MonitorDestinationUtil.test.ts +313 -0
  130. package/Tests/Utils/Monitor/MonitoringIntervalUtil.test.ts +304 -0
  131. package/Tests/Utils/StatusPage/UptimeDailyAggregateUtil.test.ts +248 -0
  132. package/Types/API/Hostname.ts +63 -16
  133. package/Types/Database/AccessControl/ColumnAccessControl.ts +19 -7
  134. package/Types/Database/AccessControl/ColumnBillingAccessControl.ts +19 -7
  135. package/Types/Database/AccessControl/OwnerOnlyColumn.ts +15 -6
  136. package/Types/Database/CanonicalModelInstance.ts +102 -0
  137. package/Types/Database/TableColumn.ts +20 -6
  138. package/Types/EnterpriseLicense/EnterpriseLicensePeriods.ts +29 -0
  139. package/Types/IP/IPv6.ts +6 -1
  140. package/Types/Monitor/MonitorStep.ts +6 -1
  141. package/Types/Monitor/ProxmoxAlertTemplates.ts +1 -1
  142. package/Types/StatusPage/UptimeDailyAggregate.ts +110 -0
  143. package/UI/Components/EditionLabel/EditionLabel.tsx +796 -1195
  144. package/UI/Components/EditionLabel/LicenseManager.ts +119 -0
  145. package/UI/Components/Graphs/DayUptimeGraph.tsx +123 -15
  146. package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
  147. package/UI/Components/ModelList/ModelList.tsx +11 -1
  148. package/UI/Components/MonitorGraphs/Uptime.tsx +69 -0
  149. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +28 -12
  150. package/UI/esbuild-enterprise.js +263 -0
  151. package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +7 -2
  152. package/Utils/HostAddressUtil.ts +94 -0
  153. package/Utils/Monitor/MonitorDestinationUtil.ts +157 -0
  154. package/Utils/Monitor/MonitoringIntervalUtil.ts +436 -0
  155. package/Utils/StatusPage/UptimeDailyAggregateUtil.ts +192 -0
  156. package/build/dist/Models/AnalyticsModels/AuditLog.js +23 -15
  157. package/build/dist/Models/AnalyticsModels/AuditLog.js.map +1 -1
  158. package/build/dist/Models/DatabaseModels/GlobalConfig.js +25 -0
  159. package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
  160. package/build/dist/Models/DatabaseModels/Monitor.js +2 -2
  161. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  162. package/build/dist/Models/DatabaseModels/MonitorTemplate.js +2 -1
  163. package/build/dist/Models/DatabaseModels/MonitorTemplate.js.map +1 -1
  164. package/build/dist/Server/API/BaseAPI.js +26 -5
  165. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  166. package/build/dist/Server/API/GlobalConfigAPI.js +148 -344
  167. package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
  168. package/build/dist/Server/API/ProjectOIDC.js +24 -16
  169. package/build/dist/Server/API/ProjectOIDC.js.map +1 -1
  170. package/build/dist/Server/API/ProjectSSO.js +24 -16
  171. package/build/dist/Server/API/ProjectSSO.js.map +1 -1
  172. package/build/dist/Server/API/StatusPageAPI.js +93 -43
  173. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  174. package/build/dist/Server/API/TeamMemberAPI.js +8 -1
  175. package/build/dist/Server/API/TeamMemberAPI.js.map +1 -1
  176. package/build/dist/Server/Enterprise/EnterpriseEdition.js +466 -0
  177. package/build/dist/Server/Enterprise/EnterpriseEdition.js.map +1 -0
  178. package/build/dist/Server/Enterprise/EnterpriseFeature.js +39 -0
  179. package/build/dist/Server/Enterprise/EnterpriseFeature.js.map +1 -0
  180. package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js +70 -0
  181. package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js.map +1 -0
  182. package/build/dist/Server/Enterprise/EnterpriseServerModule.js +84 -0
  183. package/build/dist/Server/Enterprise/EnterpriseServerModule.js.map +1 -0
  184. package/build/dist/Server/EnvironmentConfig.js +84 -2
  185. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  186. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js +18 -0
  187. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js.map +1 -0
  188. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  189. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  190. package/build/dist/Server/Middleware/UserAuthorization.js +30 -11
  191. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  192. package/build/dist/Server/Services/AuditLogService.js +71 -740
  193. package/build/dist/Server/Services/AuditLogService.js.map +1 -1
  194. package/build/dist/Server/Services/EnterpriseLicenseService.js +34 -0
  195. package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
  196. package/build/dist/Server/Services/GlobalConfigService.js +63 -0
  197. package/build/dist/Server/Services/GlobalConfigService.js.map +1 -1
  198. package/build/dist/Server/Services/MonitorProbeService.js +90 -17
  199. package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
  200. package/build/dist/Server/Services/MonitorService.js +45 -4
  201. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  202. package/build/dist/Server/Services/MonitorStatusTimelineService.js +242 -0
  203. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  204. package/build/dist/Server/Services/MonitorTemplateService.js +16 -0
  205. package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
  206. package/build/dist/Server/Services/ProjectService.js +214 -0
  207. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  208. package/build/dist/Server/Services/RumSessionPinService.js +24 -6
  209. package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
  210. package/build/dist/Server/Services/StatusPagePrivateUserService.js +7 -3
  211. package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
  212. package/build/dist/Server/Services/StatusPageService.js +71 -0
  213. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  214. package/build/dist/Server/Services/TeamMemberService.js +10 -0
  215. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  216. package/build/dist/Server/Services/TeamService.js +9 -0
  217. package/build/dist/Server/Services/TeamService.js.map +1 -1
  218. package/build/dist/Server/Services/UserService.js +10 -16
  219. package/build/dist/Server/Services/UserService.js.map +1 -1
  220. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js +10 -0
  221. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js.map +1 -1
  222. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js +154 -14
  223. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js.map +1 -1
  224. package/build/dist/Server/Types/Database/Permissions/TablePermission.js +10 -3
  225. package/build/dist/Server/Types/Database/Permissions/TablePermission.js.map +1 -1
  226. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js +17 -0
  227. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js.map +1 -1
  228. package/build/dist/Server/Types/Markdown.js +31 -0
  229. package/build/dist/Server/Types/Markdown.js.map +1 -1
  230. package/build/dist/Server/Utils/CommunityEditionSsoReport.js +223 -0
  231. package/build/dist/Server/Utils/CommunityEditionSsoReport.js.map +1 -0
  232. package/build/dist/Server/Utils/EditionEnforcement.js +187 -0
  233. package/build/dist/Server/Utils/EditionEnforcement.js.map +1 -0
  234. package/build/dist/Server/Utils/FrontendEnvironment.js +31 -2
  235. package/build/dist/Server/Utils/FrontendEnvironment.js.map +1 -1
  236. package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js +6 -193
  237. package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js.map +1 -1
  238. package/build/dist/Server/Utils/Monitor/AffectedResourceList.js +96 -0
  239. package/build/dist/Server/Utils/Monitor/AffectedResourceList.js.map +1 -0
  240. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +8 -1
  241. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
  242. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +449 -261
  243. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  244. package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js +88 -0
  245. package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js.map +1 -0
  246. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +331 -11
  247. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  248. package/build/dist/Types/API/Hostname.js +59 -11
  249. package/build/dist/Types/API/Hostname.js.map +1 -1
  250. package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js +19 -7
  251. package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js.map +1 -1
  252. package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js +19 -7
  253. package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js.map +1 -1
  254. package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js +13 -6
  255. package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js.map +1 -1
  256. package/build/dist/Types/Database/CanonicalModelInstance.js +88 -0
  257. package/build/dist/Types/Database/CanonicalModelInstance.js.map +1 -0
  258. package/build/dist/Types/Database/TableColumn.js +19 -6
  259. package/build/dist/Types/Database/TableColumn.js.map +1 -1
  260. package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js +28 -0
  261. package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js.map +1 -0
  262. package/build/dist/Types/IP/IPv6.js +6 -1
  263. package/build/dist/Types/IP/IPv6.js.map +1 -1
  264. package/build/dist/Types/Monitor/MonitorStep.js +5 -0
  265. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  266. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +1 -1
  267. package/build/dist/Types/StatusPage/UptimeDailyAggregate.js +32 -0
  268. package/build/dist/Types/StatusPage/UptimeDailyAggregate.js.map +1 -0
  269. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +414 -585
  270. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  271. package/build/dist/UI/Components/EditionLabel/LicenseManager.js +2 -0
  272. package/build/dist/UI/Components/EditionLabel/LicenseManager.js.map +1 -0
  273. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +90 -17
  274. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
  275. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
  276. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
  277. package/build/dist/UI/Components/ModelList/ModelList.js +4 -1
  278. package/build/dist/UI/Components/ModelList/ModelList.js.map +1 -1
  279. package/build/dist/UI/Components/MonitorGraphs/Uptime.js +42 -1
  280. package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
  281. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +2 -2
  282. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  283. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +6 -2
  284. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
  285. package/build/dist/Utils/HostAddressUtil.js +80 -0
  286. package/build/dist/Utils/HostAddressUtil.js.map +1 -0
  287. package/build/dist/Utils/Monitor/MonitorDestinationUtil.js +127 -0
  288. package/build/dist/Utils/Monitor/MonitorDestinationUtil.js.map +1 -0
  289. package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js +374 -0
  290. package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js.map +1 -0
  291. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js +148 -0
  292. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js.map +1 -0
  293. package/jest.config.json +3 -1
  294. package/package.json +1 -1
  295. package/test-setup.sh +103 -34
  296. package/tsconfig.json +13 -0
  297. package/Server/API/EnterpriseLicenseAPI.ts +0 -925
  298. package/Server/API/TeamComplianceAPI.ts +0 -158
  299. package/Server/Middleware/SCIMAuthorization.ts +0 -141
  300. package/Server/Services/TeamComplianceService.ts +0 -733
  301. package/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.ts +0 -186
  302. package/Server/Utils/InstanceHealth/PostgresHealth.ts +0 -286
  303. package/Tests/App/AdminDashboard/EnterpriseLicenseInstanceActivity.test.tsx +0 -451
  304. package/Tests/App/Dashboard/AuditLogsTable.test.tsx +0 -598
  305. package/Tests/App/Dashboard/SecurityEventsExplorer.test.tsx +0 -761
  306. package/Tests/App/Dashboard/SecurityEventsSideMenu.test.tsx +0 -247
  307. package/Tests/App/Dashboard/SecurityEventsTableColumns.test.tsx +0 -382
  308. package/Tests/App/Dashboard/SecurityEventsVolumeChart.test.tsx +0 -321
  309. package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +0 -1851
  310. package/Tests/Server/Middleware/SCIMAuthorization.test.ts +0 -525
  311. package/Tests/Server/Services/TeamComplianceServiceBehaviour.test.ts +0 -1845
  312. package/Tests/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.test.ts +0 -495
  313. package/Tests/Server/Utils/InstanceHealth/PostgresHealth.test.ts +0 -337
  314. package/Tests/Utils/EnterpriseLicenseSeats.test.ts +0 -576
  315. package/Tests/Utils/EnterpriseLicenseSync.test.ts +0 -568
  316. package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +0 -287
  317. package/Utils/EnterpriseLicense/EnterpriseLicenseSync.ts +0 -244
  318. package/build/dist/Server/API/EnterpriseLicenseAPI.js +0 -646
  319. package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +0 -1
  320. package/build/dist/Server/API/TeamComplianceAPI.js +0 -111
  321. package/build/dist/Server/API/TeamComplianceAPI.js.map +0 -1
  322. package/build/dist/Server/Middleware/SCIMAuthorization.js +0 -124
  323. package/build/dist/Server/Middleware/SCIMAuthorization.js.map +0 -1
  324. package/build/dist/Server/Services/TeamComplianceService.js +0 -537
  325. package/build/dist/Server/Services/TeamComplianceService.js.map +0 -1
  326. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js +0 -145
  327. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js.map +0 -1
  328. package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js +0 -194
  329. package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js.map +0 -1
  330. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +0 -168
  331. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +0 -1
  332. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js +0 -174
  333. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js.map +0 -1
@@ -0,0 +1,515 @@
1
+ import fs from "fs";
2
+ import ts from "typescript";
3
+ import {
4
+ AllowlistEntry,
5
+ Finding,
6
+ allowlistedFiles,
7
+ fromRelativePath,
8
+ toRelativePath,
9
+ } from "./RefreshAwareApiScan";
10
+
11
+ /*
12
+ * The detector behind the "Dashboard requests name the project they are for"
13
+ * guard.
14
+ *
15
+ * Model CRUD goes through ModelAPI, which calls getCommonHeaders() on every
16
+ * request and so always sends a `tenantid` header. Custom (non-CRUD) routes
17
+ * have no ModelAPI to go through, so pages reach them with a raw
18
+ * `API.post` / `API.get` from Common/UI/Utils/API/API - and BaseAPI.getHeaders()
19
+ * adds only the default and permission-hash headers. It does NOT add
20
+ * `tenantid`. ModelAPI.getCommonHeaders() is the only producer of that header
21
+ * in the entire codebase.
22
+ *
23
+ * Server side, ProjectMiddleware.getProjectId is the only thing that resolves
24
+ * the project, and it looks in exactly these places:
25
+ *
26
+ * req.params.projectId, req.params.tenantid, req.query.tenantid,
27
+ * req.headers.tenantid, req.headers.projectid, req.body.projectId
28
+ *
29
+ * So a raw call from the Dashboard has to make the project explicit in one of
30
+ * three ways: the tenant header, a `projectId` in the body, or a project id in
31
+ * the URL. A call that does none of them arrives with no project at all.
32
+ *
33
+ * What that costs is not theoretical. OneUptime issue #3920 ("Can't test SMTP
34
+ * connection") was `/smtp-config/test` posted without the header: the route
35
+ * had been hardened to require an authenticated member of the config's own
36
+ * project, and with no `tenantid` there was no project to check, so every
37
+ * click on "Send Test Email" came back "Project ID is required". Before that
38
+ * hardening the same omission showed up as "You do not have permissions to
39
+ * read <model>", naming permissions the caller already held. Neither failure
40
+ * is visible in a type check, in a compile, or in any test that does not send
41
+ * the request - which is what this scan is for.
42
+ *
43
+ * The three existing guards (ProjectScopedApiTenantHeader,
44
+ * ProjectScopedCustomRouteTenantHeader, MonitorTemplateSyncTenantHeader) each
45
+ * pin a hardcoded list of files and routes, which is why none of them saw
46
+ * `/smtp-config/test`: it was not on any list. This one sweeps instead, so a
47
+ * new page is covered the day it lands and the only way out is an allowlist
48
+ * entry with a reason.
49
+ *
50
+ * It lives under Common/Tests so both the core suite and ee/ reach it through
51
+ * the "Common/..." specifier, the same way RefreshAwareApiScan does.
52
+ */
53
+
54
+ /* The HTTP verbs the browser client exposes as `API.<verb>({ ... })`. */
55
+ const REQUEST_VERBS: ReadonlySet<string> = new Set<string>([
56
+ "get",
57
+ "post",
58
+ "put",
59
+ "delete",
60
+ "patch",
61
+ ]);
62
+
63
+ /*
64
+ * Module specifiers whose default export is a raw, non-model client: it sends
65
+ * the session cookie but never a tenant header. Matched as a suffix so both
66
+ * "Common/UI/Utils/API/API" and a relative "../../Utils/API/API" resolve.
67
+ *
68
+ * ModelAPI and AnalyticsModelAPI are deliberately absent: those attach the
69
+ * header themselves, so demanding an explicit one from their call sites would
70
+ * be wrong.
71
+ */
72
+ const RAW_CLIENT_SPECIFIERS: ReadonlyArray<string> = [
73
+ "UI/Utils/API/API",
74
+ "Utils/API/API",
75
+ ];
76
+
77
+ /*
78
+ * Every file that opens a request spells one of these, so a module with
79
+ * neither needs no parse.
80
+ */
81
+ const REQUEST_HINT: RegExp = /API\s*\.\s*(?:get|post|put|delete|patch)\b/;
82
+
83
+ /*
84
+ * A `headers` expression that reaches getCommonHeaders(). Both ModelAPI and
85
+ * AnalyticsModelAPI expose it and both produce the tenant header, so the
86
+ * method is what is matched rather than the class.
87
+ */
88
+ const TENANT_HEADER: RegExp = /\bgetCommonHeaders\s*\(/;
89
+
90
+ /* `projectId: value`, or the shorthand `projectId`, in an object literal. */
91
+ const PROJECT_ID_PROPERTY: RegExp = /\bprojectId\b\s*(?::|,|\}|$)/m;
92
+
93
+ /*
94
+ * A project id named in the url itself - a `:projectId` path segment, or a
95
+ * lookup of the current one.
96
+ */
97
+ const PROJECT_ID_IN_URL: RegExp = /\bprojectId\b|getCurrentProjectId\s*\(/;
98
+
99
+ export interface RawApiCall {
100
+ // 1-based, for a clickable file:line in the failure message.
101
+ line: number;
102
+ verb: string;
103
+ // Source text of the call's `url:`, `data:` and `headers:` properties.
104
+ url: string;
105
+ data: string;
106
+ headers: string;
107
+ }
108
+
109
+ /*
110
+ * Identifiers this file declares at any level, mapped to the source text of
111
+ * their declaration - but only when the name is declared exactly once.
112
+ *
113
+ * This is what lets the scan see through the one indirection these pages
114
+ * actually use: LogsViewer.tsx writes `headers: getHeaders()` and declares
115
+ * `function getHeaders() { return ModelAPI.getCommonHeaders(); }` a few lines
116
+ * above. Resolving that is the difference between a true reading and a false
117
+ * accusation.
118
+ *
119
+ * Ambiguity has to read as "cannot tell", never as "take the first one": a
120
+ * name declared twice (two branches of a conditional, a shadowed parameter)
121
+ * would otherwise attribute a call to whichever declaration happened to come
122
+ * first. Such a name is simply absent from the map, and the call is then
123
+ * judged on its own text - which fails closed, into a finding a human reads.
124
+ */
125
+ function collectDeclarations(sourceFile: ts.SourceFile): Map<string, string> {
126
+ const seen: Map<string, number> = new Map<string, number>();
127
+ const text: Map<string, string> = new Map<string, string>();
128
+
129
+ const record: (name: string, node: ts.Node) => void = (
130
+ name: string,
131
+ node: ts.Node,
132
+ ): void => {
133
+ seen.set(name, (seen.get(name) || 0) + 1);
134
+ text.set(name, node.getText(sourceFile));
135
+ };
136
+
137
+ const visit: (node: ts.Node) => void = (node: ts.Node): void => {
138
+ if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {
139
+ record(node.name.text, node);
140
+ }
141
+
142
+ if (ts.isFunctionDeclaration(node) && node.name) {
143
+ record(node.name.text, node);
144
+ }
145
+
146
+ ts.forEachChild(node, visit);
147
+ };
148
+
149
+ ts.forEachChild(sourceFile, visit);
150
+
151
+ for (const [name, count] of seen) {
152
+ if (count !== 1) {
153
+ text.delete(name);
154
+ }
155
+ }
156
+
157
+ return text;
158
+ }
159
+
160
+ /*
161
+ * An expression's own text, plus the text of every identifier in it that this
162
+ * file declares - one level deep.
163
+ *
164
+ * One level is what the indirection in these pages is worth (`getHeaders()`
165
+ * returning `ModelAPI.getCommonHeaders()`), and stopping there keeps the
166
+ * expansion bounded and readable. A deeper chain reads as unresolved, which
167
+ * fails closed into a finding rather than quietly passing.
168
+ */
169
+ function expand(expression: string, declarations: Map<string, string>): string {
170
+ const identifiers: Array<string> =
171
+ expression.match(/[A-Za-z_$][\w$]*/g) || [];
172
+ const parts: Array<string> = [expression];
173
+
174
+ for (const identifier of new Set<string>(identifiers)) {
175
+ const declaration: string | undefined = declarations.get(identifier);
176
+
177
+ if (declaration) {
178
+ parts.push(declaration);
179
+ }
180
+ }
181
+
182
+ return parts.join("\n");
183
+ }
184
+
185
+ /*
186
+ * The local names bound to a raw client in this file, e.g. `API` from
187
+ * `import API from "Common/UI/Utils/API/API"`.
188
+ *
189
+ * Reading the imports rather than matching the literal name `API` is what
190
+ * keeps `ModelAPI.post` and `AnalyticsModelAPI.post` out of the sweep: those
191
+ * resolve to a different module, and demanding an explicit tenant header from
192
+ * them would be wrong - they send one already.
193
+ */
194
+ function rawClientNames(sourceFile: ts.SourceFile): Set<string> {
195
+ const names: Set<string> = new Set<string>();
196
+
197
+ for (const statement of sourceFile.statements) {
198
+ if (!ts.isImportDeclaration(statement)) {
199
+ continue;
200
+ }
201
+
202
+ if (!ts.isStringLiteral(statement.moduleSpecifier)) {
203
+ continue;
204
+ }
205
+
206
+ const specifier: string = statement.moduleSpecifier.text;
207
+
208
+ const isRawClient: boolean = RAW_CLIENT_SPECIFIERS.some(
209
+ (suffix: string): boolean => {
210
+ return specifier.endsWith(suffix);
211
+ },
212
+ );
213
+
214
+ if (!isRawClient || !statement.importClause) {
215
+ continue;
216
+ }
217
+
218
+ // A type-only import carries no client, so it opens no request.
219
+ if (statement.importClause.isTypeOnly) {
220
+ continue;
221
+ }
222
+
223
+ if (statement.importClause.name) {
224
+ names.add(statement.importClause.name.text);
225
+ }
226
+ }
227
+
228
+ return names;
229
+ }
230
+
231
+ /* The source text of one property of an object literal, or "" when unset. */
232
+ function readProperty(
233
+ literal: ts.ObjectLiteralExpression,
234
+ name: string,
235
+ sourceFile: ts.SourceFile,
236
+ ): string {
237
+ for (const property of literal.properties) {
238
+ if (!ts.isPropertyAssignment(property)) {
239
+ continue;
240
+ }
241
+
242
+ if (!ts.isIdentifier(property.name) && !ts.isStringLiteral(property.name)) {
243
+ continue;
244
+ }
245
+
246
+ if (property.name.text === name) {
247
+ return property.initializer.getText(sourceFile);
248
+ }
249
+ }
250
+
251
+ return "";
252
+ }
253
+
254
+ /* One module's syntax tree. JSX only parses under the TSX script kind. */
255
+ function parse(source: string, file: string): ts.SourceFile {
256
+ return ts.createSourceFile(
257
+ file,
258
+ source,
259
+ ts.ScriptTarget.Latest,
260
+ true,
261
+ file.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS,
262
+ );
263
+ }
264
+
265
+ /*
266
+ * Every `API.<verb>(...)` in one browser module, where `API` is a raw client
267
+ * this file imported.
268
+ *
269
+ * A call whose argument is not an object literal - `API.post(buildRequest())`
270
+ * - has no `url`/`data`/`headers` to read, so it is reported with all three
271
+ * empty rather than dropped. Empty reads as "names no project", which turns
272
+ * an unreadable call into a finding a human looks at instead of a hole the
273
+ * sweep walks past. There are none in the Dashboard today; the point is that
274
+ * the first one cannot arrive unnoticed.
275
+ */
276
+ export function findRawApiCalls(
277
+ source: string,
278
+ file: string,
279
+ ): Array<RawApiCall> {
280
+ if (!REQUEST_HINT.test(source)) {
281
+ return [];
282
+ }
283
+
284
+ const sourceFile: ts.SourceFile = parse(source, file);
285
+
286
+ const clients: Set<string> = rawClientNames(sourceFile);
287
+
288
+ if (clients.size === 0) {
289
+ return [];
290
+ }
291
+
292
+ const calls: Array<RawApiCall> = [];
293
+
294
+ const visit: (node: ts.Node) => void = (node: ts.Node): void => {
295
+ ts.forEachChild(node, visit);
296
+
297
+ if (!ts.isCallExpression(node)) {
298
+ return;
299
+ }
300
+
301
+ const callee: ts.LeftHandSideExpression = node.expression;
302
+
303
+ /*
304
+ * `API.post<T>({...})` parses as a call whose expression is the property
305
+ * access; the type argument lives on the call, so nothing extra is needed
306
+ * to match both spellings.
307
+ */
308
+ if (!ts.isPropertyAccessExpression(callee)) {
309
+ return;
310
+ }
311
+
312
+ if (!ts.isIdentifier(callee.expression)) {
313
+ return;
314
+ }
315
+
316
+ if (!clients.has(callee.expression.text)) {
317
+ return;
318
+ }
319
+
320
+ if (!REQUEST_VERBS.has(callee.name.text)) {
321
+ return;
322
+ }
323
+
324
+ const argument: ts.Expression | undefined = node.arguments[0];
325
+
326
+ const literal: ts.ObjectLiteralExpression | null =
327
+ argument && ts.isObjectLiteralExpression(argument) ? argument : null;
328
+
329
+ calls.push({
330
+ line:
331
+ sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile))
332
+ .line + 1,
333
+ verb: callee.name.text,
334
+ url: literal ? readProperty(literal, "url", sourceFile) : "",
335
+ data: literal ? readProperty(literal, "data", sourceFile) : "",
336
+ headers: literal ? readProperty(literal, "headers", sourceFile) : "",
337
+ });
338
+ };
339
+
340
+ ts.forEachChild(sourceFile, visit);
341
+
342
+ return calls.sort((left: RawApiCall, right: RawApiCall): number => {
343
+ return left.line - right.line;
344
+ });
345
+ }
346
+
347
+ /* Whether a call sends `tenantid` - see TENANT_HEADER. */
348
+ export function sendsTenantHeader(
349
+ call: RawApiCall,
350
+ declarations: Map<string, string>,
351
+ ): boolean {
352
+ if (!call.headers) {
353
+ return false;
354
+ }
355
+
356
+ return TENANT_HEADER.test(expand(call.headers, declarations));
357
+ }
358
+
359
+ /*
360
+ * Whether the request body carries `projectId`, which
361
+ * ProjectMiddleware.getProjectId reads as its last fallback. Most of the
362
+ * Dashboard's raw posts scope themselves this way rather than with the
363
+ * header - `projectId: ProjectUtil.getCurrentProjectId()!` - and that is a
364
+ * perfectly good answer to "which project is this for?".
365
+ *
366
+ * Both spellings count: `projectId: x` and the shorthand `projectId`.
367
+ */
368
+ export function sendsProjectIdInBody(
369
+ call: RawApiCall,
370
+ declarations: Map<string, string>,
371
+ ): boolean {
372
+ if (!call.data) {
373
+ return false;
374
+ }
375
+
376
+ const text: string = expand(call.data, declarations);
377
+
378
+ return PROJECT_ID_PROPERTY.test(text);
379
+ }
380
+
381
+ /*
382
+ * Whether the project is named in the URL itself - either as a path segment
383
+ * the route declares as `:projectId`, or by a call to getCurrentProjectId().
384
+ */
385
+ export function urlCarriesProjectId(
386
+ call: RawApiCall,
387
+ declarations: Map<string, string>,
388
+ ): boolean {
389
+ if (!call.url) {
390
+ return false;
391
+ }
392
+
393
+ const text: string = expand(call.url, declarations);
394
+
395
+ return PROJECT_ID_IN_URL.test(text);
396
+ }
397
+
398
+ /* The three ways a request can name its project, in one question. */
399
+ export function makesProjectExplicit(
400
+ call: RawApiCall,
401
+ declarations: Map<string, string>,
402
+ ): boolean {
403
+ return (
404
+ sendsTenantHeader(call, declarations) ||
405
+ sendsProjectIdInBody(call, declarations) ||
406
+ urlCarriesProjectId(call, declarations)
407
+ );
408
+ }
409
+
410
+ /* Every raw call in one module that names no project. */
411
+ export function findImplicitProjectCalls(
412
+ source: string,
413
+ file: string,
414
+ ): Array<Finding> {
415
+ const calls: Array<RawApiCall> = findRawApiCalls(source, file);
416
+
417
+ if (calls.length === 0) {
418
+ return [];
419
+ }
420
+
421
+ const declarations: Map<string, string> = collectDeclarations(
422
+ parse(source, file),
423
+ );
424
+
425
+ return calls
426
+ .filter((call: RawApiCall): boolean => {
427
+ return !makesProjectExplicit(call, declarations);
428
+ })
429
+ .map((call: RawApiCall): Finding => {
430
+ const target: string = call.url.replace(/\s+/g, " ").trim();
431
+
432
+ return {
433
+ line: call.line,
434
+ description: target
435
+ ? `API.${call.verb} to ${target} sends no project`
436
+ : `API.${call.verb} is not written as an object literal, so the scan cannot tell whether it names a project`,
437
+ };
438
+ });
439
+ }
440
+
441
+ /*
442
+ * One line per request that names no project, naming the file, the line and
443
+ * the fix. The strings ARE the failure message: jest prints the received
444
+ * array.
445
+ */
446
+ export function findImplicitProjectOffenders(data: {
447
+ sources: ReadonlyMap<string, string>;
448
+ baseDir: string;
449
+ allowlist: ReadonlyArray<AllowlistEntry>;
450
+ }): Array<string> {
451
+ const allowed: Set<string> = allowlistedFiles(data.allowlist);
452
+ const offenders: Array<string> = [];
453
+
454
+ for (const [file, source] of data.sources) {
455
+ const relative: string = toRelativePath(data.baseDir, file);
456
+
457
+ if (allowed.has(relative)) {
458
+ continue;
459
+ }
460
+
461
+ for (const finding of findImplicitProjectCalls(source, file)) {
462
+ offenders.push(
463
+ `${relative}:${finding.line} ${finding.description}. Add \`headers: ModelAPI.getCommonHeaders(),\` to the call so a \`tenantid\` header is sent (or put \`projectId\` in the body). Without it ProjectMiddleware.getProjectId finds no project, and a project-scoped route answers "Project ID is required".`,
464
+ );
465
+ }
466
+ }
467
+
468
+ return offenders;
469
+ }
470
+
471
+ /*
472
+ * Allowlist entries that no longer earn their place: the file is gone, or
473
+ * every raw call in it now names a project. A suite asserts this is empty, so
474
+ * an allowlist cannot quietly outlive its reasons.
475
+ */
476
+ export function findStaleProjectAllowlistEntries(data: {
477
+ baseDir: string;
478
+ allowlist: ReadonlyArray<AllowlistEntry>;
479
+ allowlistName: string;
480
+ }): Array<string> {
481
+ const stale: Array<string> = [];
482
+
483
+ for (const entry of data.allowlist) {
484
+ const filePath: string = fromRelativePath(data.baseDir, entry.file);
485
+
486
+ if (!fs.existsSync(filePath)) {
487
+ stale.push(
488
+ `${entry.file} no longer exists - remove it from ${data.allowlistName}`,
489
+ );
490
+ continue;
491
+ }
492
+
493
+ if (
494
+ findImplicitProjectCalls(fs.readFileSync(filePath, "utf8"), filePath)
495
+ .length === 0
496
+ ) {
497
+ stale.push(
498
+ `${entry.file} no longer makes a request without a project - remove it from ${data.allowlistName}`,
499
+ );
500
+ }
501
+ }
502
+
503
+ return stale;
504
+ }
505
+
506
+ /*
507
+ * The declarations one module contributes to the scan, exposed so a suite can
508
+ * ask about a single call it names rather than only about the whole sweep.
509
+ */
510
+ export function readDeclarations(
511
+ source: string,
512
+ file: string,
513
+ ): Map<string, string> {
514
+ return collectDeclarations(parse(source, file));
515
+ }