@oneuptime/common 12.0.17 → 12.0.19

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 (220) 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/UserMicrosoftTeamsAPI.ts +127 -0
  11. package/Server/API/UserSlackAPI.ts +125 -0
  12. package/Server/EnvironmentConfig.ts +12 -107
  13. package/Server/Infrastructure/Postgres/SchemaMigrations/1788700000000-RemoveMarketingConversionUploadState.ts +33 -0
  14. package/Server/Infrastructure/Postgres/SchemaMigrations/1788800000000-DropMarketingConversionAddEnterpriseLicenseEmail.ts +51 -0
  15. package/Server/Infrastructure/Postgres/SchemaMigrations/1788900000000-RedactStoredMonitorIngestSecrets.ts +117 -0
  16. package/Server/Infrastructure/Postgres/SchemaMigrations/1789000000000-AddUserSlackAndMicrosoftTeams.ts +197 -0
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
  18. package/Server/Infrastructure/Queue.ts +7 -0
  19. package/Server/Services/BillingService.ts +8 -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 +67 -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/Workspace/MicrosoftTeams/MicrosoftTeams.ts +191 -4
  40. package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +22 -14
  41. package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +22 -11
  42. package/Tests/App/Dashboard/OnCallPreventionGuards.test.tsx +37 -1
  43. package/Tests/App/Dashboard/OnCallRulesTable.test.tsx +18 -10
  44. package/Tests/App/Dashboard/PayAsYouGoNotices.test.tsx +17 -0
  45. package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +27 -1
  46. package/Tests/Models/DatabaseModels/MonitorSecretKeyColumnAccessControl.test.ts +214 -0
  47. package/Tests/Server/API/OnCallReadinessAPI.test.ts +145 -26
  48. package/Tests/Server/API/UserNotificationMethodAdminAPI.test.ts +2 -2
  49. package/Tests/Server/Services/AIServiceDailyBudget.test.ts +11 -1
  50. package/Tests/Server/Services/AdminRuleEditGuards.test.ts +22 -8
  51. package/Tests/Server/Services/BillingService.test.ts +20 -0
  52. package/Tests/Server/Services/DeliverNotificationForRuleExtraction.test.ts +18 -2
  53. package/Tests/Server/Services/EpisodeRuleSeverityRepair.test.ts +5 -1
  54. package/Tests/Server/Services/LlmLogServiceTokenAggregateParams.test.ts +640 -0
  55. package/Tests/Server/Services/NotificationChannelEventCoverage.test.ts +246 -22
  56. package/Tests/Server/Services/NotificationDeletionImpact.test.ts +136 -8
  57. package/Tests/Server/Services/OnCallNotificationFallback.test.ts +191 -8
  58. package/Tests/Server/Services/OnCallReadinessService.test.ts +343 -18
  59. package/Tests/Server/Services/SeverityRuleBackfill.test.ts +5 -1
  60. package/Tests/Server/Services/UserMicrosoftTeamsService.test.ts +343 -0
  61. package/Tests/Server/Services/UserNotificationMethodAdminService.test.ts +209 -8
  62. package/Tests/Server/Services/UserNotificationRuleAdminGuards.test.ts +22 -6
  63. package/Tests/Server/Services/UserNotificationRuleDefaultCreation.test.ts +12 -6
  64. package/Tests/Server/Services/UserNotificationRuleExecuteItem.test.ts +37 -3
  65. package/Tests/Server/Services/UserNotificationRuleWorkspaceDelivery.test.ts +669 -0
  66. package/Tests/Server/Services/UserNotificationSettingWorkspaceChannels.test.ts +410 -0
  67. package/Tests/Server/Services/UserSlackService.test.ts +407 -0
  68. package/Tests/Server/Services/WorkspaceProjectAuthTokenDisconnectCascade.test.ts +224 -0
  69. package/Tests/Server/Services/WorkspaceUserAuthTokenNotificationMethodCascade.test.ts +189 -0
  70. package/Tests/Server/Services/WorkspaceUserNotificationService.test.ts +496 -0
  71. package/Tests/Server/Types/Database/Permissions/AdminNotificationRuleAccess.test.ts +30 -17
  72. package/Tests/Server/Types/Database/Permissions/CreateOwnershipScoping.test.ts +8 -3
  73. package/Tests/Server/Types/Database/Permissions/OwnerOnlyColumns.test.ts +72 -3
  74. package/Tests/Server/Types/Database/Permissions/UserNotificationRuleScoping.test.ts +22 -18
  75. package/Tests/Server/Types/Database/Permissions/WorkspaceMethodStampedColumnCreate.test.ts +178 -0
  76. package/Tests/Server/Utils/Marketing/MarketingEventUtil.test.ts +259 -0
  77. package/Tests/Server/Utils/Marketing/MarketingEventWebhook.test.ts +257 -0
  78. package/Tests/Server/Utils/Monitor/MonitorLogUtilRedaction.test.ts +300 -0
  79. package/Tests/Server/Utils/Monitor/MonitorPayloadRedaction.test.ts +381 -0
  80. package/Tests/Server/Utils/Runbook/RunbookExecutePermission.test.ts +228 -0
  81. package/Tests/Server/Utils/SessionReplay/SessionReplayErasureTombstone.test.ts +189 -0
  82. package/Tests/Server/Utils/SessionReplay/SessionReplayUsage.test.ts +205 -0
  83. package/Tests/Server/Utils/Telemetry/AppMetrics.test.ts +275 -0
  84. package/Tests/Server/Utils/Telemetry/TelemetryContext.test.ts +279 -0
  85. package/Tests/Server/Utils/Workspace/MicrosoftTeamsDirectMessage.test.ts +454 -0
  86. package/Tests/Types/Kubernetes/KubernetesObjectParsers.test.ts +794 -0
  87. package/Tests/Types/Kubernetes/KubernetesRightSizing.test.ts +53 -0
  88. package/Tests/Types/Measurement/MeasurementAggregationType.test.ts +100 -0
  89. package/Tests/Types/Monitor/MonitorStepConfigHelpers.test.ts +114 -0
  90. package/Tests/Types/Workspace/WorkspaceType.test.ts +53 -0
  91. package/Tests/UI/Utils/NotificationMethodUtil.test.ts +137 -9
  92. package/Tests/UI/Utils/PermissionGate.test.ts +105 -0
  93. package/Tests/Utils/Dashboard/Components/DashboardComponentDefaults.test.ts +257 -0
  94. package/Types/Billing/PayAsYouGoPricing.ts +1 -1
  95. package/Types/Marketing/MarketingEvent.ts +97 -0
  96. package/UI/Utils/NotificationMethodUtil.ts +41 -1
  97. package/UI/Utils/PermissionGate.ts +56 -0
  98. package/build/dist/Models/DatabaseModels/EnterpriseLicense.js +24 -0
  99. package/build/dist/Models/DatabaseModels/EnterpriseLicense.js.map +1 -1
  100. package/build/dist/Models/DatabaseModels/Index.js +4 -2
  101. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  102. package/build/dist/Models/DatabaseModels/Monitor.js +39 -9
  103. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  104. package/build/dist/Models/DatabaseModels/UserMicrosoftTeams.js +363 -0
  105. package/build/dist/Models/DatabaseModels/UserMicrosoftTeams.js.map +1 -0
  106. package/build/dist/Models/DatabaseModels/UserNotificationRule.js +145 -8
  107. package/build/dist/Models/DatabaseModels/UserNotificationRule.js.map +1 -1
  108. package/build/dist/Models/DatabaseModels/UserNotificationSetting.js +38 -0
  109. package/build/dist/Models/DatabaseModels/UserNotificationSetting.js.map +1 -1
  110. package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js +96 -0
  111. package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js.map +1 -1
  112. package/build/dist/Models/DatabaseModels/UserSlack.js +361 -0
  113. package/build/dist/Models/DatabaseModels/UserSlack.js.map +1 -0
  114. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
  115. package/build/dist/Server/API/UserMicrosoftTeamsAPI.js +82 -0
  116. package/build/dist/Server/API/UserMicrosoftTeamsAPI.js.map +1 -0
  117. package/build/dist/Server/API/UserSlackAPI.js +81 -0
  118. package/build/dist/Server/API/UserSlackAPI.js.map +1 -0
  119. package/build/dist/Server/EnvironmentConfig.js +10 -70
  120. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  121. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788700000000-RemoveMarketingConversionUploadState.js +26 -0
  122. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788700000000-RemoveMarketingConversionUploadState.js.map +1 -0
  123. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788800000000-DropMarketingConversionAddEnterpriseLicenseEmail.js +37 -0
  124. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788800000000-DropMarketingConversionAddEnterpriseLicenseEmail.js.map +1 -0
  125. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788900000000-RedactStoredMonitorIngestSecrets.js +106 -0
  126. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788900000000-RedactStoredMonitorIngestSecrets.js.map +1 -0
  127. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789000000000-AddUserSlackAndMicrosoftTeams.js +78 -0
  128. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789000000000-AddUserSlackAndMicrosoftTeams.js.map +1 -0
  129. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  130. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  131. package/build/dist/Server/Infrastructure/Queue.js +7 -0
  132. package/build/dist/Server/Infrastructure/Queue.js.map +1 -1
  133. package/build/dist/Server/Services/BillingService.js +6 -0
  134. package/build/dist/Server/Services/BillingService.js.map +1 -1
  135. package/build/dist/Server/Services/EnterpriseLicenseService.js +65 -0
  136. package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
  137. package/build/dist/Server/Services/Index.js +6 -2
  138. package/build/dist/Server/Services/Index.js.map +1 -1
  139. package/build/dist/Server/Services/LlmLogService.js +25 -9
  140. package/build/dist/Server/Services/LlmLogService.js.map +1 -1
  141. package/build/dist/Server/Services/OnCallReadinessService.js +74 -2
  142. package/build/dist/Server/Services/OnCallReadinessService.js.map +1 -1
  143. package/build/dist/Server/Services/ProjectService.js +56 -0
  144. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  145. package/build/dist/Server/Services/UserMicrosoftTeamsService.js +183 -0
  146. package/build/dist/Server/Services/UserMicrosoftTeamsService.js.map +1 -0
  147. package/build/dist/Server/Services/UserNotificationMethodAdminService.js +138 -2
  148. package/build/dist/Server/Services/UserNotificationMethodAdminService.js.map +1 -1
  149. package/build/dist/Server/Services/UserNotificationRuleAdminService.js +32 -4
  150. package/build/dist/Server/Services/UserNotificationRuleAdminService.js.map +1 -1
  151. package/build/dist/Server/Services/UserNotificationRuleService.js +499 -67
  152. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  153. package/build/dist/Server/Services/UserNotificationSettingService.js +118 -0
  154. package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
  155. package/build/dist/Server/Services/UserService.js +26 -1
  156. package/build/dist/Server/Services/UserService.js.map +1 -1
  157. package/build/dist/Server/Services/UserSlackService.js +195 -0
  158. package/build/dist/Server/Services/UserSlackService.js.map +1 -0
  159. package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js +64 -1
  160. package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js.map +1 -1
  161. package/build/dist/Server/Services/WorkspaceUserAuthTokenService.js +70 -0
  162. package/build/dist/Server/Services/WorkspaceUserAuthTokenService.js.map +1 -1
  163. package/build/dist/Server/Services/WorkspaceUserNotificationService.js +129 -0
  164. package/build/dist/Server/Services/WorkspaceUserNotificationService.js.map +1 -0
  165. package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js +94 -0
  166. package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js.map +1 -0
  167. package/build/dist/Server/Utils/Marketing/MarketingEventWebhook.js +93 -0
  168. package/build/dist/Server/Utils/Marketing/MarketingEventWebhook.js.map +1 -0
  169. package/build/dist/Server/Utils/Monitor/MonitorLogUtil.js +12 -1
  170. package/build/dist/Server/Utils/Monitor/MonitorLogUtil.js.map +1 -1
  171. package/build/dist/Server/Utils/Monitor/MonitorPayloadRedaction.js +233 -0
  172. package/build/dist/Server/Utils/Monitor/MonitorPayloadRedaction.js.map +1 -0
  173. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +141 -4
  174. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  175. package/build/dist/Types/Billing/PayAsYouGoPricing.js +1 -1
  176. package/build/dist/Types/Billing/PayAsYouGoPricing.js.map +1 -1
  177. package/build/dist/Types/Marketing/MarketingEvent.js +43 -0
  178. package/build/dist/Types/Marketing/MarketingEvent.js.map +1 -0
  179. package/build/dist/UI/Utils/NotificationMethodUtil.js +33 -1
  180. package/build/dist/UI/Utils/NotificationMethodUtil.js.map +1 -1
  181. package/build/dist/UI/Utils/PermissionGate.js +32 -0
  182. package/build/dist/UI/Utils/PermissionGate.js.map +1 -1
  183. package/package.json +1 -1
  184. package/Models/DatabaseModels/MarketingConversion.ts +0 -410
  185. package/Server/Services/MarketingConversionService.ts +0 -10
  186. package/Server/Utils/Marketing/ConversionUploadProvider.ts +0 -215
  187. package/Server/Utils/Marketing/ConversionUploadProviders.ts +0 -22
  188. package/Server/Utils/Marketing/Providers/GoogleAds.ts +0 -333
  189. package/Server/Utils/Marketing/Providers/LinkedIn.ts +0 -185
  190. package/Server/Utils/Marketing/Providers/Meta.ts +0 -182
  191. package/Server/Utils/Marketing/Providers/MicrosoftAds.ts +0 -223
  192. package/Server/Utils/Marketing/Providers/Reddit.ts +0 -208
  193. package/Tests/Server/Utils/Marketing/AdUploadableConversionTypes.test.ts +0 -315
  194. package/Tests/Server/Utils/Marketing/ConversionUploadProvider.test.ts +0 -300
  195. package/Tests/Server/Utils/Marketing/GoogleAds.test.ts +0 -592
  196. package/Tests/Server/Utils/Marketing/LinkedIn.test.ts +0 -282
  197. package/Tests/Server/Utils/Marketing/Meta.test.ts +0 -304
  198. package/Tests/Server/Utils/Marketing/MicrosoftAds.test.ts +0 -263
  199. package/Tests/Server/Utils/Marketing/Reddit.test.ts +0 -259
  200. package/Types/Marketing/MarketingConversion.ts +0 -53
  201. package/build/dist/Models/DatabaseModels/MarketingConversion.js +0 -445
  202. package/build/dist/Models/DatabaseModels/MarketingConversion.js.map +0 -1
  203. package/build/dist/Server/Services/MarketingConversionService.js +0 -9
  204. package/build/dist/Server/Services/MarketingConversionService.js.map +0 -1
  205. package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js +0 -93
  206. package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js.map +0 -1
  207. package/build/dist/Server/Utils/Marketing/ConversionUploadProviders.js +0 -20
  208. package/build/dist/Server/Utils/Marketing/ConversionUploadProviders.js.map +0 -1
  209. package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js +0 -221
  210. package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js.map +0 -1
  211. package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js +0 -137
  212. package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js.map +0 -1
  213. package/build/dist/Server/Utils/Marketing/Providers/Meta.js +0 -133
  214. package/build/dist/Server/Utils/Marketing/Providers/Meta.js.map +0 -1
  215. package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js +0 -143
  216. package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js.map +0 -1
  217. package/build/dist/Server/Utils/Marketing/Providers/Reddit.js +0 -145
  218. package/build/dist/Server/Utils/Marketing/Providers/Reddit.js.map +0 -1
  219. package/build/dist/Types/Marketing/MarketingConversion.js +0 -52
  220. package/build/dist/Types/Marketing/MarketingConversion.js.map +0 -1
@@ -1,300 +0,0 @@
1
- import Attribution from "../../../../Server/Utils/Attribution";
2
- import MarketingConversion from "../../../../Models/DatabaseModels/MarketingConversion";
3
- import ConversionUploadProvider, {
4
- ConversionSkip,
5
- ConversionUploadBatchResult,
6
- } from "../../../../Server/Utils/Marketing/ConversionUploadProvider";
7
- import { MarketingConversionType } from "../../../../Types/Marketing/MarketingConversion";
8
- import { AxiosError } from "axios";
9
- import { afterEach, describe, expect, jest, test } from "@jest/globals";
10
-
11
- class TestProvider extends ConversionUploadProvider {
12
- public override readonly key: string = "test";
13
- public override readonly displayName: string = "Test Provider";
14
-
15
- public override isConfigured(): boolean {
16
- return true;
17
- }
18
-
19
- protected override getProviderSkipReason(
20
- _conversion: MarketingConversion,
21
- ): ConversionSkip | null {
22
- return null;
23
- }
24
-
25
- public override async upload(
26
- _conversions: Array<MarketingConversion>,
27
- ): Promise<ConversionUploadBatchResult> {
28
- return { permanentFailures: new Map<number, string>() };
29
- }
30
-
31
- public readClickId(
32
- conversion: MarketingConversion,
33
- key: string,
34
- ): string | undefined {
35
- return this.getClickId(conversion, key);
36
- }
37
-
38
- public readValueInUSD(conversion: MarketingConversion): number | undefined {
39
- return this.getValueInUSD(conversion);
40
- }
41
-
42
- public readIsLead(conversion: MarketingConversion): boolean {
43
- return this.isLead(conversion);
44
- }
45
-
46
- public readHashedEmail(conversion: MarketingConversion): string | undefined {
47
- return this.getHashedEmail(conversion);
48
- }
49
-
50
- public readByConversionType(
51
- conversion: MarketingConversion,
52
- ): string | undefined {
53
- return this.resolveByConversionType(conversion, {
54
- [MarketingConversionType.SignUp]: "signup-action",
55
- [MarketingConversionType.MeetingBooked]: "meeting-action",
56
- [MarketingConversionType.PaidSubscription]: "paid-action",
57
- });
58
- }
59
-
60
- public readIsOlderThanDays(
61
- conversion: MarketingConversion,
62
- days: number,
63
- ): boolean {
64
- return this.isOlderThanDays(conversion, days);
65
- }
66
- }
67
-
68
- const makeConversion: (
69
- data?: Partial<MarketingConversion>,
70
- ) => MarketingConversion = (
71
- data: Partial<MarketingConversion> = {},
72
- ): MarketingConversion => {
73
- return Object.assign(new MarketingConversion(), data);
74
- };
75
-
76
- describe("ConversionUploadProvider", () => {
77
- const provider: TestProvider = new TestProvider();
78
-
79
- afterEach(() => {
80
- jest.restoreAllMocks();
81
- });
82
-
83
- test("extracts a non-empty string click ID", () => {
84
- const conversion: MarketingConversion = makeConversion({
85
- clickIds: { gclid: "google-click" },
86
- });
87
-
88
- expect(provider.readClickId(conversion, "gclid")).toBe("google-click");
89
- });
90
-
91
- test.each([undefined, null, "", 0, 123, false, { nested: true }])(
92
- "rejects an invalid click ID value: %p",
93
- (value: unknown) => {
94
- const conversion: MarketingConversion = makeConversion({
95
- clickIds: { gclid: value as never },
96
- });
97
-
98
- expect(provider.readClickId(conversion, "gclid")).toBeUndefined();
99
- },
100
- );
101
-
102
- test("returns undefined when click IDs are absent", () => {
103
- const conversion: MarketingConversion = makeConversion();
104
- delete conversion.clickIds;
105
-
106
- expect(provider.readClickId(conversion, "gclid")).toBeUndefined();
107
- });
108
-
109
- test("converts cents to an exact USD decimal", () => {
110
- expect(
111
- provider.readValueInUSD(
112
- makeConversion({ conversionValueInUSDCents: 12345 }),
113
- ),
114
- ).toBe(123.45);
115
- });
116
-
117
- test.each([undefined, null, 0, -1, -100])(
118
- "omits a non-positive or missing conversion value: %p",
119
- (value: number | null | undefined) => {
120
- const conversion: MarketingConversion = makeConversion();
121
- conversion.conversionValueInUSDCents = value as never;
122
-
123
- expect(provider.readValueInUSD(conversion)).toBeUndefined();
124
- },
125
- );
126
-
127
- test("classifies a booked meeting as the sales-led step", () => {
128
- expect(
129
- provider.readIsLead(
130
- makeConversion({
131
- conversionType: MarketingConversionType.MeetingBooked,
132
- }),
133
- ),
134
- ).toBe(true);
135
- expect(
136
- provider.readIsLead(
137
- makeConversion({ conversionType: MarketingConversionType.SignUp }),
138
- ),
139
- ).toBe(false);
140
- expect(
141
- provider.readIsLead(
142
- makeConversion({
143
- conversionType: MarketingConversionType.PaidSubscription,
144
- }),
145
- ),
146
- ).toBe(false);
147
- });
148
-
149
- /*
150
- * A lead's value is suppressed at the base class, not at each call site, so
151
- * a provider cannot forget to do it.
152
- */
153
- test("suppresses the conversion value for a lead", () => {
154
- expect(
155
- provider.readValueInUSD(
156
- makeConversion({
157
- conversionType: MarketingConversionType.MeetingBooked,
158
- conversionValueInUSDCents: 99900,
159
- }),
160
- ),
161
- ).toBeUndefined();
162
- });
163
-
164
- describe("resolveByConversionType", () => {
165
- test.each([
166
- [MarketingConversionType.SignUp, "signup-action"],
167
- [MarketingConversionType.MeetingBooked, "meeting-action"],
168
- [MarketingConversionType.PaidSubscription, "paid-action"],
169
- ])(
170
- "maps %s to its own entry",
171
- (conversionType: MarketingConversionType, expected: string) => {
172
- expect(
173
- provider.readByConversionType(
174
- makeConversion({ conversionType: conversionType }),
175
- ),
176
- ).toBe(expected);
177
- },
178
- );
179
-
180
- /*
181
- * conversionType is a plain varchar. A value the enum does not name must
182
- * resolve to nothing rather than to whichever entry a loose lookup would
183
- * land on — that is the failure mode that used to send a booked meeting as
184
- * a purchase.
185
- */
186
- test.each(["SomethingElse", "", "signup", "MEETINGBOOKED"])(
187
- "resolves nothing for the unrecognised type %p",
188
- (conversionType: string) => {
189
- expect(
190
- provider.readByConversionType(
191
- makeConversion({ conversionType: conversionType }),
192
- ),
193
- ).toBeUndefined();
194
- },
195
- );
196
-
197
- test("resolves nothing when the type is absent", () => {
198
- const conversion: MarketingConversion = makeConversion();
199
- delete conversion.conversionType;
200
-
201
- expect(provider.readByConversionType(conversion)).toBeUndefined();
202
- });
203
- });
204
-
205
- describe("getHashedEmail", () => {
206
- /*
207
- * Deliberately NOT the real digest of the email beside it, so the first
208
- * test can only pass by returning the stored column rather than by
209
- * recomputing and happening to agree.
210
- */
211
- const STORED_DIGEST: string =
212
- "cc1dbbd8a5f5a4e9c0e2e4ba2c1e18c05f5c9e0e3d3b6c7bbd2d47d5a8f0e1f0";
213
-
214
- test("prefers the stored hash over rehashing the address", () => {
215
- expect(
216
- provider.readHashedEmail(
217
- makeConversion({
218
- email: "ada@example.com",
219
- emailHash: STORED_DIGEST,
220
- }),
221
- ),
222
- ).toBe(STORED_DIGEST);
223
- expect(STORED_DIGEST).not.toBe(Attribution.hashEmail("ada@example.com"));
224
- });
225
-
226
- /*
227
- * Rows written before emailHash existed still have to be matchable, or
228
- * enhanced matching would only ever work for conversions recorded after
229
- * this column shipped.
230
- */
231
- test("falls back to hashing the email column", () => {
232
- const hashed: string | undefined = provider.readHashedEmail(
233
- makeConversion({ email: "Ada@Example.com " }),
234
- );
235
-
236
- expect(hashed).toBe(Attribution.hashEmail("ada@example.com"));
237
- });
238
-
239
- test("returns undefined when there is neither", () => {
240
- expect(provider.readHashedEmail(makeConversion())).toBeUndefined();
241
- });
242
- });
243
-
244
- test("checks conversion age against the provider window", () => {
245
- jest
246
- .spyOn(Date, "now")
247
- .mockReturnValue(new Date("2026-07-22T12:00:00.000Z").getTime());
248
-
249
- expect(
250
- provider.readIsOlderThanDays(
251
- makeConversion({
252
- conversionAt: new Date("2026-04-22T11:59:59.999Z"),
253
- }),
254
- 90,
255
- ),
256
- ).toBe(true);
257
- expect(
258
- provider.readIsOlderThanDays(
259
- makeConversion({
260
- conversionAt: new Date("2026-07-21T12:00:00.000Z"),
261
- }),
262
- 90,
263
- ),
264
- ).toBe(false);
265
- });
266
-
267
- test("uses the current time when conversionAt is missing", () => {
268
- jest
269
- .spyOn(Date, "now")
270
- .mockReturnValue(new Date("2026-07-22T12:00:00.000Z").getTime());
271
-
272
- expect(provider.readIsOlderThanDays(makeConversion(), 90)).toBe(false);
273
- });
274
-
275
- test("formats ordinary errors without leaking an object dump", () => {
276
- expect(
277
- ConversionUploadProvider.getErrorMessage(new Error("network down")),
278
- ).toBe("network down");
279
- });
280
-
281
- test("formats Axios errors with status and bounded response data", () => {
282
- const error: AxiosError = new AxiosError("rate limited");
283
- Object.assign(error, {
284
- response: {
285
- status: 429,
286
- data: { error: "retry later" },
287
- },
288
- });
289
-
290
- expect(ConversionUploadProvider.getErrorMessage(error)).toBe(
291
- 'HTTP 429: {"error":"retry later"}',
292
- );
293
- });
294
-
295
- test("falls back to Unknown error for non-error values", () => {
296
- expect(ConversionUploadProvider.getErrorMessage(null)).toBe(
297
- "Unknown error",
298
- );
299
- });
300
- });