@oneuptime/common 12.0.18 → 12.0.20

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 (262) hide show
  1. package/Models/DatabaseModels/EnterpriseLicense.ts +23 -0
  2. package/Models/DatabaseModels/Index.ts +4 -2
  3. package/Models/DatabaseModels/Monitor.ts +39 -9
  4. package/Models/DatabaseModels/UserMicrosoftTeams.ts +344 -0
  5. package/Models/DatabaseModels/UserNotificationRule.ts +144 -8
  6. package/Models/DatabaseModels/UserNotificationSetting.ts +34 -0
  7. package/Models/DatabaseModels/UserOnCallLogTimeline.ts +95 -0
  8. package/Models/DatabaseModels/UserSlack.ts +341 -0
  9. package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +9 -0
  10. package/Server/API/EnterpriseLicenseAPI.ts +94 -19
  11. package/Server/API/UserMicrosoftTeamsAPI.ts +127 -0
  12. package/Server/API/UserSlackAPI.ts +125 -0
  13. package/Server/EnvironmentConfig.ts +29 -107
  14. package/Server/Infrastructure/Postgres/SchemaMigrations/1788700000000-RemoveMarketingConversionUploadState.ts +33 -0
  15. package/Server/Infrastructure/Postgres/SchemaMigrations/1788800000000-DropMarketingConversionAddEnterpriseLicenseEmail.ts +51 -0
  16. package/Server/Infrastructure/Postgres/SchemaMigrations/1788900000000-RedactStoredMonitorIngestSecrets.ts +117 -0
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/1789000000000-AddUserSlackAndMicrosoftTeams.ts +197 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
  19. package/Server/Infrastructure/Queue.ts +7 -0
  20. package/Server/Services/EnterpriseLicenseService.ts +60 -0
  21. package/Server/Services/Index.ts +6 -2
  22. package/Server/Services/LlmLogService.ts +25 -9
  23. package/Server/Services/OnCallReadinessService.ts +86 -2
  24. package/Server/Services/ProjectService.ts +171 -0
  25. package/Server/Services/UserMicrosoftTeamsService.ts +208 -0
  26. package/Server/Services/UserNotificationMethodAdminService.ts +167 -5
  27. package/Server/Services/UserNotificationRuleAdminService.ts +40 -6
  28. package/Server/Services/UserNotificationRuleService.ts +589 -11
  29. package/Server/Services/UserNotificationSettingService.ts +138 -0
  30. package/Server/Services/UserService.ts +28 -0
  31. package/Server/Services/UserSlackService.ts +218 -0
  32. package/Server/Services/WorkspaceProjectAuthTokenService.ts +67 -1
  33. package/Server/Services/WorkspaceUserAuthTokenService.ts +73 -0
  34. package/Server/Services/WorkspaceUserNotificationService.ts +190 -0
  35. package/Server/Utils/Marketing/MarketingEventUtil.ts +145 -0
  36. package/Server/Utils/Marketing/MarketingEventWebhook.ts +114 -0
  37. package/Server/Utils/Monitor/MonitorLogUtil.ts +14 -1
  38. package/Server/Utils/Monitor/MonitorPayloadRedaction.ts +321 -0
  39. package/Server/Utils/Response.ts +2 -2
  40. package/Server/Utils/StartServer.ts +2 -2
  41. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +191 -4
  42. package/Server/Views/Partials/AnalyticsConsent.ejs +533 -0
  43. package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +22 -14
  44. package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +22 -11
  45. package/Tests/App/Dashboard/AlertEpisodeViewFields.test.tsx +465 -0
  46. package/Tests/App/Dashboard/DashboardChartWidgetZoom.test.tsx +302 -0
  47. package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +408 -0
  48. package/Tests/App/Dashboard/IncidentEpisodeViewFields.test.tsx +474 -0
  49. package/Tests/App/Dashboard/MetricSeriesInvestigateMenu.test.tsx +368 -0
  50. package/Tests/App/Dashboard/OnCallPreventionGuards.test.tsx +37 -1
  51. package/Tests/App/Dashboard/OnCallRulesTable.test.tsx +18 -10
  52. package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +27 -1
  53. package/Tests/Models/DatabaseModels/MonitorSecretKeyColumnAccessControl.test.ts +214 -0
  54. package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +763 -0
  55. package/Tests/Server/API/OnCallReadinessAPI.test.ts +145 -26
  56. package/Tests/Server/API/UserNotificationMethodAdminAPI.test.ts +2 -2
  57. package/Tests/Server/Services/AIServiceDailyBudget.test.ts +11 -1
  58. package/Tests/Server/Services/AdminRuleEditGuards.test.ts +22 -8
  59. package/Tests/Server/Services/DeliverNotificationForRuleExtraction.test.ts +18 -2
  60. package/Tests/Server/Services/EpisodeRuleSeverityRepair.test.ts +5 -1
  61. package/Tests/Server/Services/LlmLogServiceTokenAggregateParams.test.ts +640 -0
  62. package/Tests/Server/Services/NotificationChannelEventCoverage.test.ts +246 -22
  63. package/Tests/Server/Services/NotificationDeletionImpact.test.ts +136 -8
  64. package/Tests/Server/Services/OnCallNotificationFallback.test.ts +191 -8
  65. package/Tests/Server/Services/OnCallReadinessService.test.ts +343 -18
  66. package/Tests/Server/Services/ProjectServiceChangePlan.test.ts +138 -0
  67. package/Tests/Server/Services/ProjectServiceCreateSubscriptionStarted.test.ts +516 -0
  68. package/Tests/Server/Services/SeverityRuleBackfill.test.ts +5 -1
  69. package/Tests/Server/Services/UserMicrosoftTeamsService.test.ts +343 -0
  70. package/Tests/Server/Services/UserNotificationMethodAdminService.test.ts +209 -8
  71. package/Tests/Server/Services/UserNotificationRuleAdminGuards.test.ts +22 -6
  72. package/Tests/Server/Services/UserNotificationRuleDefaultCreation.test.ts +12 -6
  73. package/Tests/Server/Services/UserNotificationRuleExecuteItem.test.ts +37 -3
  74. package/Tests/Server/Services/UserNotificationRuleWorkspaceDelivery.test.ts +669 -0
  75. package/Tests/Server/Services/UserNotificationSettingWorkspaceChannels.test.ts +410 -0
  76. package/Tests/Server/Services/UserSlackService.test.ts +407 -0
  77. package/Tests/Server/Services/WorkspaceProjectAuthTokenDisconnectCascade.test.ts +224 -0
  78. package/Tests/Server/Services/WorkspaceUserAuthTokenNotificationMethodCascade.test.ts +189 -0
  79. package/Tests/Server/Services/WorkspaceUserNotificationService.test.ts +496 -0
  80. package/Tests/Server/Types/Database/Permissions/AdminNotificationRuleAccess.test.ts +30 -17
  81. package/Tests/Server/Types/Database/Permissions/CreateOwnershipScoping.test.ts +8 -3
  82. package/Tests/Server/Types/Database/Permissions/OwnerOnlyColumns.test.ts +72 -3
  83. package/Tests/Server/Types/Database/Permissions/UserNotificationRuleScoping.test.ts +22 -18
  84. package/Tests/Server/Types/Database/Permissions/WorkspaceMethodStampedColumnCreate.test.ts +178 -0
  85. package/Tests/Server/Utils/Marketing/MarketingEventUtil.test.ts +259 -0
  86. package/Tests/Server/Utils/Marketing/MarketingEventWebhook.test.ts +257 -0
  87. package/Tests/Server/Utils/Monitor/MonitorLogUtilRedaction.test.ts +300 -0
  88. package/Tests/Server/Utils/Monitor/MonitorPayloadRedaction.test.ts +381 -0
  89. package/Tests/Server/Utils/ResponseRenderAnalytics.test.ts +53 -0
  90. package/Tests/Server/Utils/Runbook/RunbookExecutePermission.test.ts +228 -0
  91. package/Tests/Server/Utils/SessionReplay/SessionReplayErasureTombstone.test.ts +189 -0
  92. package/Tests/Server/Utils/SessionReplay/SessionReplayUsage.test.ts +205 -0
  93. package/Tests/Server/Utils/Telemetry/AppMetrics.test.ts +275 -0
  94. package/Tests/Server/Utils/Telemetry/TelemetryContext.test.ts +279 -0
  95. package/Tests/Server/Utils/Workspace/MicrosoftTeamsDirectMessage.test.ts +454 -0
  96. package/Tests/Server/Views/AnalyticsConsentPartial.test.ts +241 -0
  97. package/Tests/UI/Components/Charts/ChartTooltipSorted.test.tsx +129 -0
  98. package/Tests/UI/Components/Charts/TooltipEntries.test.ts +155 -0
  99. package/Tests/UI/Components/Detail/DetailFieldErrors.test.tsx +347 -0
  100. package/Tests/UI/Components/Forms/BasicFormStepValidation.test.tsx +392 -0
  101. package/Tests/UI/Components/Forms/ValidationFormSteps.test.ts +549 -0
  102. package/Tests/UI/Utils/NotificationMethodUtil.test.ts +137 -9
  103. package/Tests/UI/Utils/PermissionGate.test.ts +105 -0
  104. package/Tests/Utils/EnterpriseLicenseSync.test.ts +562 -0
  105. package/Types/Analytics/RevenueEvent.ts +1 -0
  106. package/Types/Marketing/MarketingEvent.ts +140 -0
  107. package/UI/Components/Charts/Area/AreaChart.tsx +8 -1
  108. package/UI/Components/Charts/Bar/BarChart.tsx +8 -1
  109. package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +19 -4
  110. package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +20 -2
  111. package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +19 -4
  112. package/UI/Components/Charts/ChartLibrary/Utils/TooltipEntries.ts +105 -0
  113. package/UI/Components/Charts/Line/LineChart.tsx +8 -1
  114. package/UI/Components/Detail/Detail.tsx +18 -1
  115. package/UI/Utils/NotificationMethodUtil.ts +41 -1
  116. package/UI/Utils/PermissionGate.ts +56 -0
  117. package/Utils/EnterpriseLicense/EnterpriseLicenseSync.ts +244 -0
  118. package/build/dist/Models/DatabaseModels/EnterpriseLicense.js +24 -0
  119. package/build/dist/Models/DatabaseModels/EnterpriseLicense.js.map +1 -1
  120. package/build/dist/Models/DatabaseModels/Index.js +4 -2
  121. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  122. package/build/dist/Models/DatabaseModels/Monitor.js +39 -9
  123. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  124. package/build/dist/Models/DatabaseModels/UserMicrosoftTeams.js +363 -0
  125. package/build/dist/Models/DatabaseModels/UserMicrosoftTeams.js.map +1 -0
  126. package/build/dist/Models/DatabaseModels/UserNotificationRule.js +145 -8
  127. package/build/dist/Models/DatabaseModels/UserNotificationRule.js.map +1 -1
  128. package/build/dist/Models/DatabaseModels/UserNotificationSetting.js +38 -0
  129. package/build/dist/Models/DatabaseModels/UserNotificationSetting.js.map +1 -1
  130. package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js +96 -0
  131. package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js.map +1 -1
  132. package/build/dist/Models/DatabaseModels/UserSlack.js +361 -0
  133. package/build/dist/Models/DatabaseModels/UserSlack.js.map +1 -0
  134. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
  135. package/build/dist/Server/API/EnterpriseLicenseAPI.js +66 -12
  136. package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +1 -1
  137. package/build/dist/Server/API/UserMicrosoftTeamsAPI.js +82 -0
  138. package/build/dist/Server/API/UserMicrosoftTeamsAPI.js.map +1 -0
  139. package/build/dist/Server/API/UserSlackAPI.js +81 -0
  140. package/build/dist/Server/API/UserSlackAPI.js.map +1 -0
  141. package/build/dist/Server/EnvironmentConfig.js +25 -70
  142. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  143. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788700000000-RemoveMarketingConversionUploadState.js +26 -0
  144. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788700000000-RemoveMarketingConversionUploadState.js.map +1 -0
  145. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788800000000-DropMarketingConversionAddEnterpriseLicenseEmail.js +37 -0
  146. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788800000000-DropMarketingConversionAddEnterpriseLicenseEmail.js.map +1 -0
  147. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788900000000-RedactStoredMonitorIngestSecrets.js +106 -0
  148. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788900000000-RedactStoredMonitorIngestSecrets.js.map +1 -0
  149. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789000000000-AddUserSlackAndMicrosoftTeams.js +78 -0
  150. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789000000000-AddUserSlackAndMicrosoftTeams.js.map +1 -0
  151. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  152. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  153. package/build/dist/Server/Infrastructure/Queue.js +7 -0
  154. package/build/dist/Server/Infrastructure/Queue.js.map +1 -1
  155. package/build/dist/Server/Services/EnterpriseLicenseService.js +65 -0
  156. package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
  157. package/build/dist/Server/Services/Index.js +6 -2
  158. package/build/dist/Server/Services/Index.js.map +1 -1
  159. package/build/dist/Server/Services/LlmLogService.js +25 -9
  160. package/build/dist/Server/Services/LlmLogService.js.map +1 -1
  161. package/build/dist/Server/Services/OnCallReadinessService.js +74 -2
  162. package/build/dist/Server/Services/OnCallReadinessService.js.map +1 -1
  163. package/build/dist/Server/Services/ProjectService.js +144 -0
  164. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  165. package/build/dist/Server/Services/UserMicrosoftTeamsService.js +183 -0
  166. package/build/dist/Server/Services/UserMicrosoftTeamsService.js.map +1 -0
  167. package/build/dist/Server/Services/UserNotificationMethodAdminService.js +138 -2
  168. package/build/dist/Server/Services/UserNotificationMethodAdminService.js.map +1 -1
  169. package/build/dist/Server/Services/UserNotificationRuleAdminService.js +32 -4
  170. package/build/dist/Server/Services/UserNotificationRuleAdminService.js.map +1 -1
  171. package/build/dist/Server/Services/UserNotificationRuleService.js +499 -67
  172. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  173. package/build/dist/Server/Services/UserNotificationSettingService.js +118 -0
  174. package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
  175. package/build/dist/Server/Services/UserService.js +26 -1
  176. package/build/dist/Server/Services/UserService.js.map +1 -1
  177. package/build/dist/Server/Services/UserSlackService.js +195 -0
  178. package/build/dist/Server/Services/UserSlackService.js.map +1 -0
  179. package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js +64 -1
  180. package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js.map +1 -1
  181. package/build/dist/Server/Services/WorkspaceUserAuthTokenService.js +70 -0
  182. package/build/dist/Server/Services/WorkspaceUserAuthTokenService.js.map +1 -1
  183. package/build/dist/Server/Services/WorkspaceUserNotificationService.js +129 -0
  184. package/build/dist/Server/Services/WorkspaceUserNotificationService.js.map +1 -0
  185. package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js +94 -0
  186. package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js.map +1 -0
  187. package/build/dist/Server/Utils/Marketing/MarketingEventWebhook.js +93 -0
  188. package/build/dist/Server/Utils/Marketing/MarketingEventWebhook.js.map +1 -0
  189. package/build/dist/Server/Utils/Monitor/MonitorLogUtil.js +12 -1
  190. package/build/dist/Server/Utils/Monitor/MonitorLogUtil.js.map +1 -1
  191. package/build/dist/Server/Utils/Monitor/MonitorPayloadRedaction.js +233 -0
  192. package/build/dist/Server/Utils/Monitor/MonitorPayloadRedaction.js.map +1 -0
  193. package/build/dist/Server/Utils/Response.js +2 -2
  194. package/build/dist/Server/Utils/Response.js.map +1 -1
  195. package/build/dist/Server/Utils/StartServer.js +2 -2
  196. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  197. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +141 -4
  198. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  199. package/build/dist/Types/Analytics/RevenueEvent.js +1 -0
  200. package/build/dist/Types/Analytics/RevenueEvent.js.map +1 -1
  201. package/build/dist/Types/Marketing/MarketingEvent.js +82 -0
  202. package/build/dist/Types/Marketing/MarketingEvent.js.map +1 -0
  203. package/build/dist/UI/Components/Charts/Area/AreaChart.js +9 -1
  204. package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
  205. package/build/dist/UI/Components/Charts/Bar/BarChart.js +9 -1
  206. package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
  207. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +22 -13
  208. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
  209. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +27 -15
  210. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
  211. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +27 -18
  212. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
  213. package/build/dist/UI/Components/Charts/ChartLibrary/Utils/TooltipEntries.js +71 -0
  214. package/build/dist/UI/Components/Charts/ChartLibrary/Utils/TooltipEntries.js.map +1 -0
  215. package/build/dist/UI/Components/Charts/Line/LineChart.js +9 -1
  216. package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
  217. package/build/dist/UI/Components/Detail/Detail.js +17 -1
  218. package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
  219. package/build/dist/UI/Utils/NotificationMethodUtil.js +33 -1
  220. package/build/dist/UI/Utils/NotificationMethodUtil.js.map +1 -1
  221. package/build/dist/UI/Utils/PermissionGate.js +32 -0
  222. package/build/dist/UI/Utils/PermissionGate.js.map +1 -1
  223. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js +174 -0
  224. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js.map +1 -0
  225. package/package.json +1 -1
  226. package/Models/DatabaseModels/MarketingConversion.ts +0 -410
  227. package/Server/Services/MarketingConversionService.ts +0 -10
  228. package/Server/Utils/Marketing/ConversionUploadProvider.ts +0 -215
  229. package/Server/Utils/Marketing/ConversionUploadProviders.ts +0 -22
  230. package/Server/Utils/Marketing/Providers/GoogleAds.ts +0 -333
  231. package/Server/Utils/Marketing/Providers/LinkedIn.ts +0 -185
  232. package/Server/Utils/Marketing/Providers/Meta.ts +0 -182
  233. package/Server/Utils/Marketing/Providers/MicrosoftAds.ts +0 -223
  234. package/Server/Utils/Marketing/Providers/Reddit.ts +0 -208
  235. package/Tests/Server/Utils/Marketing/AdUploadableConversionTypes.test.ts +0 -315
  236. package/Tests/Server/Utils/Marketing/ConversionUploadProvider.test.ts +0 -300
  237. package/Tests/Server/Utils/Marketing/GoogleAds.test.ts +0 -592
  238. package/Tests/Server/Utils/Marketing/LinkedIn.test.ts +0 -282
  239. package/Tests/Server/Utils/Marketing/Meta.test.ts +0 -304
  240. package/Tests/Server/Utils/Marketing/MicrosoftAds.test.ts +0 -263
  241. package/Tests/Server/Utils/Marketing/Reddit.test.ts +0 -259
  242. package/Types/Marketing/MarketingConversion.ts +0 -53
  243. package/build/dist/Models/DatabaseModels/MarketingConversion.js +0 -445
  244. package/build/dist/Models/DatabaseModels/MarketingConversion.js.map +0 -1
  245. package/build/dist/Server/Services/MarketingConversionService.js +0 -9
  246. package/build/dist/Server/Services/MarketingConversionService.js.map +0 -1
  247. package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js +0 -93
  248. package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js.map +0 -1
  249. package/build/dist/Server/Utils/Marketing/ConversionUploadProviders.js +0 -20
  250. package/build/dist/Server/Utils/Marketing/ConversionUploadProviders.js.map +0 -1
  251. package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js +0 -221
  252. package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js.map +0 -1
  253. package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js +0 -137
  254. package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js.map +0 -1
  255. package/build/dist/Server/Utils/Marketing/Providers/Meta.js +0 -133
  256. package/build/dist/Server/Utils/Marketing/Providers/Meta.js.map +0 -1
  257. package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js +0 -143
  258. package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js.map +0 -1
  259. package/build/dist/Server/Utils/Marketing/Providers/Reddit.js +0 -145
  260. package/build/dist/Server/Utils/Marketing/Providers/Reddit.js.map +0 -1
  261. package/build/dist/Types/Marketing/MarketingConversion.js +0 -52
  262. package/build/dist/Types/Marketing/MarketingConversion.js.map +0 -1
@@ -0,0 +1,174 @@
1
+ /*
2
+ * Maps a license-server response (from /enterprise-license/validate or
3
+ * /enterprise-license/report-user-count) onto the GlobalConfig columns a
4
+ * self-hosted installation mirrors locally.
5
+ *
6
+ * Every field is three-state, and the distinction is the whole contract:
7
+ *
8
+ * key absent - the license server did not speak about this field. That is
9
+ * what an oneuptime.com older than this build looks like, so
10
+ * the stored value is left exactly as it is. Collapsing this
11
+ * to null is how a daily report would wipe a perfectly good
12
+ * license expiry and take the installation down.
13
+ * null - the server explicitly says "there is no value". Written as
14
+ * null, so clearing a seat limit on oneuptime.com actually
15
+ * clears it on the customer's installation.
16
+ * a value - validated, then written.
17
+ *
18
+ * Anything that is neither absent, null, nor a usable value is treated as
19
+ * absent and reported as a warning: a malformed response must never be able
20
+ * to corrupt license state that was correct a moment ago.
21
+ */
22
+ export default class EnterpriseLicenseSyncUtil {
23
+ /*
24
+ * The license key is deliberately NOT synced. The installation authenticates
25
+ * with the key it already holds, and a response must never be able to swap
26
+ * it for another one.
27
+ */
28
+ static getGlobalConfigUpdateFromLicenseResponse(data) {
29
+ const payload = data.payload || {};
30
+ const updateData = {};
31
+ const warnings = [];
32
+ /*
33
+ * The seat limit. This is the field customers change on oneuptime.com and
34
+ * then wait for: without it here, buying seats never reaches the
35
+ * installation that is enforcing the old number.
36
+ */
37
+ if (this.isPresent(payload, "userLimit")) {
38
+ const rawUserLimit = payload["userLimit"];
39
+ if (rawUserLimit === null) {
40
+ updateData.enterpriseLicenseUserLimit = null;
41
+ }
42
+ else if (this.isNonNegativeInteger(rawUserLimit)) {
43
+ updateData.enterpriseLicenseUserLimit = rawUserLimit;
44
+ }
45
+ else {
46
+ warnings.push(`Ignored userLimit "${String(rawUserLimit)}" from the license server: it is not a non-negative whole number.`);
47
+ }
48
+ }
49
+ /*
50
+ * The count and its timestamp move together: a count with a stamp from a
51
+ * previous report would read as "confirmed today", which is the exact
52
+ * lie this whole sync exists to stop telling.
53
+ */
54
+ if (this.isPresent(payload, "currentUserCount")) {
55
+ const rawUserCount = payload["currentUserCount"];
56
+ if (this.isNonNegativeInteger(rawUserCount)) {
57
+ updateData.enterpriseLicenseCurrentUserCount = rawUserCount;
58
+ updateData.enterpriseLicenseUserCountUpdatedAt =
59
+ this.parseDate(payload["userCountUpdatedAt"]) || data.reportedAt;
60
+ }
61
+ else if (rawUserCount === null) {
62
+ /*
63
+ * The server has never had a count for this license. Nothing useful to
64
+ * store, and blanking the last known count would be worse than keeping
65
+ * it, so leave both columns alone.
66
+ */
67
+ warnings.push("The license server reported no user count for this license. Keeping the previously stored usage.");
68
+ }
69
+ else {
70
+ warnings.push(`Ignored currentUserCount "${String(rawUserCount)}" from the license server: it is not a non-negative whole number. Keeping the previously stored usage.`);
71
+ }
72
+ }
73
+ /*
74
+ * Expiry drives licenseValid on the installation, so a renewal that never
75
+ * arrives here shows up as a license that expires on its original date
76
+ * however much the customer paid. Null is treated as absent on purpose: a
77
+ * report is not the place to strip an installation of its expiry.
78
+ */
79
+ if (this.isPresent(payload, "expiresAt") && payload["expiresAt"] !== null) {
80
+ const expiresAt = this.parseDate(payload["expiresAt"]);
81
+ if (expiresAt) {
82
+ updateData.enterpriseLicenseExpiresAt = expiresAt;
83
+ }
84
+ else {
85
+ warnings.push(`Ignored expiresAt "${String(payload["expiresAt"])}" from the license server: it is not a date.`);
86
+ }
87
+ }
88
+ if (this.isPresent(payload, "isEvaluationLicense")) {
89
+ const rawIsEvaluation = payload["isEvaluationLicense"];
90
+ if (typeof rawIsEvaluation === "boolean") {
91
+ updateData.enterpriseLicenseIsEvaluation = rawIsEvaluation;
92
+ }
93
+ else {
94
+ warnings.push(`Ignored isEvaluationLicense "${String(rawIsEvaluation)}" from the license server: it is not a boolean.`);
95
+ }
96
+ }
97
+ if (this.isPresent(payload, "companyName")) {
98
+ const companyName = this.parseNonEmptyString(payload["companyName"]);
99
+ /*
100
+ * An empty company name is what the server sends for a license with none
101
+ * set, and overwriting a good name with "" would be a visible regression
102
+ * in the modal. Only a real name is worth writing.
103
+ */
104
+ if (companyName) {
105
+ updateData.enterpriseCompanyName = companyName;
106
+ }
107
+ }
108
+ /*
109
+ * The token is opaque here - it is signed with the license server's secret
110
+ * and this side only checks that it exists. It is never cleared: a license
111
+ * that has expired is legitimately issued no token, and clearing it on the
112
+ * way past would compound an expiry the customer may be about to renew.
113
+ */
114
+ if (this.isPresent(payload, "token")) {
115
+ const token = this.parseNonEmptyString(payload["token"]);
116
+ if (token) {
117
+ updateData.enterpriseLicenseToken = token;
118
+ }
119
+ }
120
+ if (this.isPresent(payload, "instances")) {
121
+ const rawInstances = payload["instances"];
122
+ if (Array.isArray(rawInstances)) {
123
+ updateData.enterpriseLicenseInstances =
124
+ rawInstances;
125
+ }
126
+ else {
127
+ warnings.push("Ignored the instance list from the license server: it is not an array.");
128
+ }
129
+ }
130
+ return {
131
+ updateData: updateData,
132
+ warnings: warnings,
133
+ };
134
+ }
135
+ /*
136
+ * Present means the key is on the object, even when it carries null or
137
+ * undefined. `"x" in payload` rather than a truthiness or undefined check,
138
+ * because "the server said null" and "the server said nothing" have to stay
139
+ * distinguishable all the way down.
140
+ */
141
+ static isPresent(payload, key) {
142
+ if (!Object.prototype.hasOwnProperty.call(payload, key)) {
143
+ return false;
144
+ }
145
+ // An explicit undefined is indistinguishable from silence. Treat it as one.
146
+ return payload[key] !== undefined;
147
+ }
148
+ static isNonNegativeInteger(value) {
149
+ return (typeof value === "number" &&
150
+ Number.isFinite(value) &&
151
+ Number.isInteger(value) &&
152
+ value >= 0);
153
+ }
154
+ static parseNonEmptyString(value) {
155
+ if (typeof value !== "string") {
156
+ return "";
157
+ }
158
+ return value.trim();
159
+ }
160
+ static parseDate(value) {
161
+ if (value instanceof Date) {
162
+ return Number.isNaN(value.getTime()) ? null : value;
163
+ }
164
+ if (typeof value !== "string" || !value.trim()) {
165
+ return null;
166
+ }
167
+ const parsed = new Date(value.trim());
168
+ if (Number.isNaN(parsed.getTime())) {
169
+ return null;
170
+ }
171
+ return parsed;
172
+ }
173
+ }
174
+ //# sourceMappingURL=EnterpriseLicenseSync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EnterpriseLicenseSync.js","sourceRoot":"","sources":["../../../../Utils/EnterpriseLicense/EnterpriseLicenseSync.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oneuptime/common",
3
- "version": "12.0.18",
3
+ "version": "12.0.20",
4
4
  "description": "",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,410 +0,0 @@
1
- import BaseModel from "./DatabaseBaseModel/DatabaseBaseModel";
2
- import Route from "../../Types/API/Route";
3
- import ColumnAccessControl from "../../Types/Database/AccessControl/ColumnAccessControl";
4
- import TableAccessControl from "../../Types/Database/AccessControl/TableAccessControl";
5
- import ColumnLength from "../../Types/Database/ColumnLength";
6
- import ColumnType from "../../Types/Database/ColumnType";
7
- import CrudApiEndpoint from "../../Types/Database/CrudApiEndpoint";
8
- import TableColumn from "../../Types/Database/TableColumn";
9
- import TableColumnType from "../../Types/Database/TableColumnType";
10
- import TableMetadata from "../../Types/Database/TableMetadata";
11
- import IconProp from "../../Types/Icon/IconProp";
12
- import { JSONObject } from "../../Types/JSON";
13
- import ObjectID from "../../Types/ObjectID";
14
- import { Column, Entity, Index } from "typeorm";
15
-
16
- /*
17
- * Internal table (no API access) recording server-confirmed conversions —
18
- * signups, booked meetings and paid subscriptions — together with the
19
- * attribution the converting visitor carried (ad click IDs, UTM parameters,
20
- * first touch) and the status of uploading them to ad platforms. Browser
21
- * analytics never write this table: rows are written by the Cal.com webhook and
22
- * the MarketingConversions worker job, which also reads it.
23
- *
24
- * This table is deliberately not a CRM. Contact, account and deal records live
25
- * in Revenue, and nothing here creates or advances them — a booked meeting is
26
- * a measured conversion, not a qualified opportunity.
27
- */
28
- @TableAccessControl({
29
- create: [],
30
- read: [],
31
- update: [],
32
- delete: [],
33
- })
34
- @CrudApiEndpoint(new Route("/marketing-conversion"))
35
- @TableMetadata({
36
- tableName: "MarketingConversion",
37
- singularName: "Marketing Conversion",
38
- pluralName: "Marketing Conversions",
39
- icon: IconProp.ChartBar,
40
- tableDescription:
41
- "Server-confirmed conversions (signups, meetings booked, paid subscriptions), the campaign attribution each carried, and their upload status to ad platforms for offline conversion tracking.",
42
- })
43
- @Entity({
44
- name: "MarketingConversion",
45
- })
46
- /*
47
- * One conversion of each type per user/project. Postgres treats NULLs as
48
- * distinct, so these indexes only constrain rows that actually carry a user or
49
- * project id — conversion types with neither (a booked meeting from an
50
- * anonymous visitor) are de-duplicated by their deterministic primary key
51
- * instead.
52
- */
53
- @Index("uq_marketing_conversion_type_user", ["conversionType", "userId"], {
54
- unique: true,
55
- })
56
- @Index(
57
- "uq_marketing_conversion_type_project",
58
- ["conversionType", "projectId"],
59
- {
60
- unique: true,
61
- },
62
- )
63
- export default class MarketingConversion extends BaseModel {
64
- @ColumnAccessControl({
65
- create: [],
66
- read: [],
67
- update: [],
68
- })
69
- @TableColumn({
70
- type: TableColumnType.ShortText,
71
- required: true,
72
- title: "Conversion Type",
73
- description: "SignUp, MeetingBooked or PaidSubscription.",
74
- })
75
- @Column({
76
- type: ColumnType.ShortText,
77
- length: ColumnLength.ShortText,
78
- nullable: false,
79
- })
80
- public conversionType?: string = undefined;
81
-
82
- @ColumnAccessControl({
83
- create: [],
84
- read: [],
85
- update: [],
86
- })
87
- @Index("idx_marketing_conversion_user_id")
88
- @TableColumn({
89
- type: TableColumnType.ObjectID,
90
- required: false,
91
- title: "User ID",
92
- description:
93
- "User this conversion belongs to (SignUp conversions). Null when the conversion has no OneUptime user yet, as with a booked meeting.",
94
- })
95
- @Column({
96
- type: ColumnType.ObjectID,
97
- nullable: true,
98
- transformer: ObjectID.getDatabaseTransformer(),
99
- })
100
- public userId?: ObjectID = undefined;
101
-
102
- @ColumnAccessControl({
103
- create: [],
104
- read: [],
105
- update: [],
106
- })
107
- @Index("idx_marketing_conversion_project_id")
108
- @TableColumn({
109
- type: TableColumnType.ObjectID,
110
- required: false,
111
- title: "Project ID",
112
- description:
113
- "Project this conversion belongs to (PaidSubscription conversions).",
114
- })
115
- @Column({
116
- type: ColumnType.ObjectID,
117
- nullable: true,
118
- transformer: ObjectID.getDatabaseTransformer(),
119
- })
120
- public projectId?: ObjectID = undefined;
121
-
122
- @ColumnAccessControl({
123
- create: [],
124
- read: [],
125
- update: [],
126
- })
127
- @TableColumn({
128
- type: TableColumnType.ShortText,
129
- required: false,
130
- title: "Email",
131
- description:
132
- "Email of the converting user. Never sent anywhere in the clear: every ad platform receives the SHA-256 in emailHash instead.",
133
- })
134
- @Column({
135
- type: ColumnType.ShortText,
136
- length: ColumnLength.ShortText,
137
- nullable: true,
138
- })
139
- public email?: string | undefined = undefined;
140
-
141
- @ColumnAccessControl({
142
- create: [],
143
- read: [],
144
- update: [],
145
- })
146
- @TableColumn({
147
- type: TableColumnType.JSON,
148
- required: true,
149
- title: "Click IDs",
150
- description:
151
- "Ad click identifiers (gclid, wbraid, gbraid, fbclid, ...) captured for this conversion.",
152
- })
153
- @Column({
154
- type: ColumnType.JSON,
155
- nullable: false,
156
- })
157
- public clickIds?: JSONObject = undefined;
158
-
159
- @ColumnAccessControl({
160
- create: [],
161
- read: [],
162
- update: [],
163
- })
164
- @TableColumn({
165
- type: TableColumnType.Date,
166
- required: true,
167
- title: "Conversion At",
168
- description: "When the conversion happened.",
169
- })
170
- @Column({
171
- type: ColumnType.Date,
172
- nullable: false,
173
- })
174
- public conversionAt?: Date = undefined;
175
-
176
- @ColumnAccessControl({
177
- create: [],
178
- read: [],
179
- update: [],
180
- })
181
- @TableColumn({
182
- type: TableColumnType.Number,
183
- required: false,
184
- title: "Conversion Value (USD Cents)",
185
- description:
186
- "Conversion value in USD cents (monthly recurring revenue for paid subscriptions). Null when unknown (custom pricing) or not applicable (signups, booked meetings).",
187
- })
188
- @Column({
189
- type: ColumnType.Number,
190
- nullable: true,
191
- })
192
- public conversionValueInUSDCents?: number | undefined = undefined;
193
-
194
- @ColumnAccessControl({
195
- create: [],
196
- read: [],
197
- update: [],
198
- })
199
- @TableColumn({
200
- type: TableColumnType.JSON,
201
- required: false,
202
- title: "Upload State",
203
- description:
204
- "Per-ad-platform upload state, keyed by provider (google, meta, microsoft, linkedin, reddit, ...): { status: Uploaded|Failed|Skipped, attempts, error, uploadedAt }. Absent key or absent status means pending.",
205
- })
206
- @Column({
207
- type: ColumnType.JSON,
208
- nullable: true,
209
- })
210
- public uploadState?: JSONObject = undefined;
211
-
212
- /*
213
- * Last-touch UTM parameters, copied from the User or Project this conversion
214
- * belongs to, or read from Cal booking metadata for a booked meeting.
215
- *
216
- * The ledger carried only clickIds until now, which meant the only thing
217
- * that could answer "how many demos did this campaign produce" was the ad
218
- * platform, and only for clicks it had auto-tagged. Any campaign delivering
219
- * UTMs without a click id — a newsletter, a sponsorship, a conference link —
220
- * was invisible in OneUptime's own data. These columns are what make the
221
- * ledger reportable on its own.
222
- */
223
- @ColumnAccessControl({
224
- create: [],
225
- read: [],
226
- update: [],
227
- })
228
- @Index("idx_marketing_conversion_utm_campaign")
229
- @TableColumn({
230
- type: TableColumnType.LongText,
231
- required: false,
232
- title: "UTM Campaign",
233
- description: "Last-touch utm_campaign for this conversion.",
234
- })
235
- @Column({
236
- type: ColumnType.LongText,
237
- length: ColumnLength.LongText,
238
- nullable: true,
239
- })
240
- public utmCampaign?: string | undefined = undefined;
241
-
242
- @ColumnAccessControl({
243
- create: [],
244
- read: [],
245
- update: [],
246
- })
247
- @Index("idx_marketing_conversion_utm_source")
248
- @TableColumn({
249
- type: TableColumnType.LongText,
250
- required: false,
251
- title: "UTM Source",
252
- description: "Last-touch utm_source for this conversion.",
253
- })
254
- @Column({
255
- type: ColumnType.LongText,
256
- length: ColumnLength.LongText,
257
- nullable: true,
258
- })
259
- public utmSource?: string | undefined = undefined;
260
-
261
- @ColumnAccessControl({
262
- create: [],
263
- read: [],
264
- update: [],
265
- })
266
- @TableColumn({
267
- type: TableColumnType.LongText,
268
- required: false,
269
- title: "UTM Medium",
270
- description: "Last-touch utm_medium for this conversion.",
271
- })
272
- @Column({
273
- type: ColumnType.LongText,
274
- length: ColumnLength.LongText,
275
- nullable: true,
276
- })
277
- public utmMedium?: string | undefined = undefined;
278
-
279
- @ColumnAccessControl({
280
- create: [],
281
- read: [],
282
- update: [],
283
- })
284
- @TableColumn({
285
- type: TableColumnType.LongText,
286
- required: false,
287
- title: "UTM Term",
288
- description: "Last-touch utm_term for this conversion.",
289
- })
290
- @Column({
291
- type: ColumnType.LongText,
292
- length: ColumnLength.LongText,
293
- nullable: true,
294
- })
295
- public utmTerm?: string | undefined = undefined;
296
-
297
- @ColumnAccessControl({
298
- create: [],
299
- read: [],
300
- update: [],
301
- })
302
- @TableColumn({
303
- type: TableColumnType.LongText,
304
- required: false,
305
- title: "UTM Content",
306
- description: "Last-touch utm_content for this conversion.",
307
- })
308
- @Column({
309
- type: ColumnType.LongText,
310
- length: ColumnLength.LongText,
311
- nullable: true,
312
- })
313
- public utmContent?: string | undefined = undefined;
314
-
315
- @ColumnAccessControl({
316
- create: [],
317
- read: [],
318
- update: [],
319
- })
320
- @TableColumn({
321
- type: TableColumnType.LongText,
322
- required: false,
323
- title: "UTM URL",
324
- description:
325
- "Landing URL of the attributed visit. The only attribution a campaign leaves when its link carried a click id and no UTMs at all, as Google Ads auto-tagging does.",
326
- })
327
- @Column({
328
- type: ColumnType.LongText,
329
- length: ColumnLength.LongText,
330
- nullable: true,
331
- })
332
- public utmUrl?: string | undefined = undefined;
333
-
334
- @ColumnAccessControl({
335
- create: [],
336
- read: [],
337
- update: [],
338
- })
339
- @TableColumn({
340
- type: TableColumnType.JSON,
341
- required: false,
342
- title: "First Touch Attribution",
343
- description:
344
- "UTM parameters, click IDs, landing URL and referrer from the visitor's first attributed visit. The utm* columns above hold last-touch values.",
345
- })
346
- @Column({
347
- type: ColumnType.JSON,
348
- nullable: true,
349
- })
350
- public firstTouchAttribution?: JSONObject | undefined = undefined;
351
-
352
- /*
353
- * SHA-256 of the lowercased, trimmed email (Common/Server/Utils/Attribution).
354
- *
355
- * Two jobs, and it is the same value for both. Ad platforms that support
356
- * enhanced matching want exactly this digest, and it is the only key that
357
- * can join a booked meeting to the signup it produced weeks later: a
358
- * MeetingBooked row has no userId, a SignUp row has no booking, and the
359
- * person may well have used a different device for each. Indexed because
360
- * the chain-linking pass looks conversions up by it.
361
- */
362
- @ColumnAccessControl({
363
- create: [],
364
- read: [],
365
- update: [],
366
- })
367
- @Index("idx_marketing_conversion_email_hash")
368
- @TableColumn({
369
- type: TableColumnType.ShortText,
370
- required: false,
371
- title: "Email Hash",
372
- description:
373
- "SHA-256 of the normalized (trimmed, lowercased) email. Used for ad-platform enhanced matching and to join conversions by the same person across the demo/signup boundary.",
374
- })
375
- @Column({
376
- type: ColumnType.ShortText,
377
- length: ColumnLength.ShortText,
378
- nullable: true,
379
- })
380
- public emailHash?: string | undefined = undefined;
381
-
382
- /*
383
- * The earlier conversion by the same person that this one followed.
384
- *
385
- * Set by the MarketingConversions worker, never by a writer: the writers see
386
- * one moment each and cannot know what came before it. A paid subscription
387
- * pointing at a booked meeting is what makes "revenue this demo campaign
388
- * produced" answerable — without it the ledger holds four unrelated rows for
389
- * one customer journey.
390
- */
391
- @ColumnAccessControl({
392
- create: [],
393
- read: [],
394
- update: [],
395
- })
396
- @Index("idx_marketing_conversion_attributed_to")
397
- @TableColumn({
398
- type: TableColumnType.ObjectID,
399
- required: false,
400
- title: "Attributed To Conversion ID",
401
- description:
402
- "The earliest earlier conversion by the same person (matched on emailHash) that this conversion followed. Null when this is the first conversion in the chain.",
403
- })
404
- @Column({
405
- type: ColumnType.ObjectID,
406
- nullable: true,
407
- transformer: ObjectID.getDatabaseTransformer(),
408
- })
409
- public attributedToConversionId?: ObjectID | undefined = undefined;
410
- }
@@ -1,10 +0,0 @@
1
- import DatabaseService from "./DatabaseService";
2
- import MarketingConversion from "../../Models/DatabaseModels/MarketingConversion";
3
-
4
- export class Service extends DatabaseService<MarketingConversion> {
5
- public constructor() {
6
- super(MarketingConversion);
7
- }
8
- }
9
-
10
- export default new Service();