@oneuptime/common 12.0.18 → 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 (206) 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/EnterpriseLicenseService.ts +60 -0
  20. package/Server/Services/Index.ts +6 -2
  21. package/Server/Services/LlmLogService.ts +25 -9
  22. package/Server/Services/OnCallReadinessService.ts +86 -2
  23. package/Server/Services/ProjectService.ts +67 -0
  24. package/Server/Services/UserMicrosoftTeamsService.ts +208 -0
  25. package/Server/Services/UserNotificationMethodAdminService.ts +167 -5
  26. package/Server/Services/UserNotificationRuleAdminService.ts +40 -6
  27. package/Server/Services/UserNotificationRuleService.ts +589 -11
  28. package/Server/Services/UserNotificationSettingService.ts +138 -0
  29. package/Server/Services/UserService.ts +28 -0
  30. package/Server/Services/UserSlackService.ts +218 -0
  31. package/Server/Services/WorkspaceProjectAuthTokenService.ts +67 -1
  32. package/Server/Services/WorkspaceUserAuthTokenService.ts +73 -0
  33. package/Server/Services/WorkspaceUserNotificationService.ts +190 -0
  34. package/Server/Utils/Marketing/MarketingEventUtil.ts +145 -0
  35. package/Server/Utils/Marketing/MarketingEventWebhook.ts +114 -0
  36. package/Server/Utils/Monitor/MonitorLogUtil.ts +14 -1
  37. package/Server/Utils/Monitor/MonitorPayloadRedaction.ts +321 -0
  38. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +191 -4
  39. package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +22 -14
  40. package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +22 -11
  41. package/Tests/App/Dashboard/OnCallPreventionGuards.test.tsx +37 -1
  42. package/Tests/App/Dashboard/OnCallRulesTable.test.tsx +18 -10
  43. package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +27 -1
  44. package/Tests/Models/DatabaseModels/MonitorSecretKeyColumnAccessControl.test.ts +214 -0
  45. package/Tests/Server/API/OnCallReadinessAPI.test.ts +145 -26
  46. package/Tests/Server/API/UserNotificationMethodAdminAPI.test.ts +2 -2
  47. package/Tests/Server/Services/AIServiceDailyBudget.test.ts +11 -1
  48. package/Tests/Server/Services/AdminRuleEditGuards.test.ts +22 -8
  49. package/Tests/Server/Services/DeliverNotificationForRuleExtraction.test.ts +18 -2
  50. package/Tests/Server/Services/EpisodeRuleSeverityRepair.test.ts +5 -1
  51. package/Tests/Server/Services/LlmLogServiceTokenAggregateParams.test.ts +640 -0
  52. package/Tests/Server/Services/NotificationChannelEventCoverage.test.ts +246 -22
  53. package/Tests/Server/Services/NotificationDeletionImpact.test.ts +136 -8
  54. package/Tests/Server/Services/OnCallNotificationFallback.test.ts +191 -8
  55. package/Tests/Server/Services/OnCallReadinessService.test.ts +343 -18
  56. package/Tests/Server/Services/SeverityRuleBackfill.test.ts +5 -1
  57. package/Tests/Server/Services/UserMicrosoftTeamsService.test.ts +343 -0
  58. package/Tests/Server/Services/UserNotificationMethodAdminService.test.ts +209 -8
  59. package/Tests/Server/Services/UserNotificationRuleAdminGuards.test.ts +22 -6
  60. package/Tests/Server/Services/UserNotificationRuleDefaultCreation.test.ts +12 -6
  61. package/Tests/Server/Services/UserNotificationRuleExecuteItem.test.ts +37 -3
  62. package/Tests/Server/Services/UserNotificationRuleWorkspaceDelivery.test.ts +669 -0
  63. package/Tests/Server/Services/UserNotificationSettingWorkspaceChannels.test.ts +410 -0
  64. package/Tests/Server/Services/UserSlackService.test.ts +407 -0
  65. package/Tests/Server/Services/WorkspaceProjectAuthTokenDisconnectCascade.test.ts +224 -0
  66. package/Tests/Server/Services/WorkspaceUserAuthTokenNotificationMethodCascade.test.ts +189 -0
  67. package/Tests/Server/Services/WorkspaceUserNotificationService.test.ts +496 -0
  68. package/Tests/Server/Types/Database/Permissions/AdminNotificationRuleAccess.test.ts +30 -17
  69. package/Tests/Server/Types/Database/Permissions/CreateOwnershipScoping.test.ts +8 -3
  70. package/Tests/Server/Types/Database/Permissions/OwnerOnlyColumns.test.ts +72 -3
  71. package/Tests/Server/Types/Database/Permissions/UserNotificationRuleScoping.test.ts +22 -18
  72. package/Tests/Server/Types/Database/Permissions/WorkspaceMethodStampedColumnCreate.test.ts +178 -0
  73. package/Tests/Server/Utils/Marketing/MarketingEventUtil.test.ts +259 -0
  74. package/Tests/Server/Utils/Marketing/MarketingEventWebhook.test.ts +257 -0
  75. package/Tests/Server/Utils/Monitor/MonitorLogUtilRedaction.test.ts +300 -0
  76. package/Tests/Server/Utils/Monitor/MonitorPayloadRedaction.test.ts +381 -0
  77. package/Tests/Server/Utils/Runbook/RunbookExecutePermission.test.ts +228 -0
  78. package/Tests/Server/Utils/SessionReplay/SessionReplayErasureTombstone.test.ts +189 -0
  79. package/Tests/Server/Utils/SessionReplay/SessionReplayUsage.test.ts +205 -0
  80. package/Tests/Server/Utils/Telemetry/AppMetrics.test.ts +275 -0
  81. package/Tests/Server/Utils/Telemetry/TelemetryContext.test.ts +279 -0
  82. package/Tests/Server/Utils/Workspace/MicrosoftTeamsDirectMessage.test.ts +454 -0
  83. package/Tests/UI/Utils/NotificationMethodUtil.test.ts +137 -9
  84. package/Tests/UI/Utils/PermissionGate.test.ts +105 -0
  85. package/Types/Marketing/MarketingEvent.ts +97 -0
  86. package/UI/Utils/NotificationMethodUtil.ts +41 -1
  87. package/UI/Utils/PermissionGate.ts +56 -0
  88. package/build/dist/Models/DatabaseModels/EnterpriseLicense.js +24 -0
  89. package/build/dist/Models/DatabaseModels/EnterpriseLicense.js.map +1 -1
  90. package/build/dist/Models/DatabaseModels/Index.js +4 -2
  91. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  92. package/build/dist/Models/DatabaseModels/Monitor.js +39 -9
  93. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  94. package/build/dist/Models/DatabaseModels/UserMicrosoftTeams.js +363 -0
  95. package/build/dist/Models/DatabaseModels/UserMicrosoftTeams.js.map +1 -0
  96. package/build/dist/Models/DatabaseModels/UserNotificationRule.js +145 -8
  97. package/build/dist/Models/DatabaseModels/UserNotificationRule.js.map +1 -1
  98. package/build/dist/Models/DatabaseModels/UserNotificationSetting.js +38 -0
  99. package/build/dist/Models/DatabaseModels/UserNotificationSetting.js.map +1 -1
  100. package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js +96 -0
  101. package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js.map +1 -1
  102. package/build/dist/Models/DatabaseModels/UserSlack.js +361 -0
  103. package/build/dist/Models/DatabaseModels/UserSlack.js.map +1 -0
  104. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
  105. package/build/dist/Server/API/UserMicrosoftTeamsAPI.js +82 -0
  106. package/build/dist/Server/API/UserMicrosoftTeamsAPI.js.map +1 -0
  107. package/build/dist/Server/API/UserSlackAPI.js +81 -0
  108. package/build/dist/Server/API/UserSlackAPI.js.map +1 -0
  109. package/build/dist/Server/EnvironmentConfig.js +10 -70
  110. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  111. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788700000000-RemoveMarketingConversionUploadState.js +26 -0
  112. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788700000000-RemoveMarketingConversionUploadState.js.map +1 -0
  113. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788800000000-DropMarketingConversionAddEnterpriseLicenseEmail.js +37 -0
  114. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788800000000-DropMarketingConversionAddEnterpriseLicenseEmail.js.map +1 -0
  115. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788900000000-RedactStoredMonitorIngestSecrets.js +106 -0
  116. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788900000000-RedactStoredMonitorIngestSecrets.js.map +1 -0
  117. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789000000000-AddUserSlackAndMicrosoftTeams.js +78 -0
  118. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789000000000-AddUserSlackAndMicrosoftTeams.js.map +1 -0
  119. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  120. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  121. package/build/dist/Server/Infrastructure/Queue.js +7 -0
  122. package/build/dist/Server/Infrastructure/Queue.js.map +1 -1
  123. package/build/dist/Server/Services/EnterpriseLicenseService.js +65 -0
  124. package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
  125. package/build/dist/Server/Services/Index.js +6 -2
  126. package/build/dist/Server/Services/Index.js.map +1 -1
  127. package/build/dist/Server/Services/LlmLogService.js +25 -9
  128. package/build/dist/Server/Services/LlmLogService.js.map +1 -1
  129. package/build/dist/Server/Services/OnCallReadinessService.js +74 -2
  130. package/build/dist/Server/Services/OnCallReadinessService.js.map +1 -1
  131. package/build/dist/Server/Services/ProjectService.js +56 -0
  132. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  133. package/build/dist/Server/Services/UserMicrosoftTeamsService.js +183 -0
  134. package/build/dist/Server/Services/UserMicrosoftTeamsService.js.map +1 -0
  135. package/build/dist/Server/Services/UserNotificationMethodAdminService.js +138 -2
  136. package/build/dist/Server/Services/UserNotificationMethodAdminService.js.map +1 -1
  137. package/build/dist/Server/Services/UserNotificationRuleAdminService.js +32 -4
  138. package/build/dist/Server/Services/UserNotificationRuleAdminService.js.map +1 -1
  139. package/build/dist/Server/Services/UserNotificationRuleService.js +499 -67
  140. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  141. package/build/dist/Server/Services/UserNotificationSettingService.js +118 -0
  142. package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
  143. package/build/dist/Server/Services/UserService.js +26 -1
  144. package/build/dist/Server/Services/UserService.js.map +1 -1
  145. package/build/dist/Server/Services/UserSlackService.js +195 -0
  146. package/build/dist/Server/Services/UserSlackService.js.map +1 -0
  147. package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js +64 -1
  148. package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js.map +1 -1
  149. package/build/dist/Server/Services/WorkspaceUserAuthTokenService.js +70 -0
  150. package/build/dist/Server/Services/WorkspaceUserAuthTokenService.js.map +1 -1
  151. package/build/dist/Server/Services/WorkspaceUserNotificationService.js +129 -0
  152. package/build/dist/Server/Services/WorkspaceUserNotificationService.js.map +1 -0
  153. package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js +94 -0
  154. package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js.map +1 -0
  155. package/build/dist/Server/Utils/Marketing/MarketingEventWebhook.js +93 -0
  156. package/build/dist/Server/Utils/Marketing/MarketingEventWebhook.js.map +1 -0
  157. package/build/dist/Server/Utils/Monitor/MonitorLogUtil.js +12 -1
  158. package/build/dist/Server/Utils/Monitor/MonitorLogUtil.js.map +1 -1
  159. package/build/dist/Server/Utils/Monitor/MonitorPayloadRedaction.js +233 -0
  160. package/build/dist/Server/Utils/Monitor/MonitorPayloadRedaction.js.map +1 -0
  161. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +141 -4
  162. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  163. package/build/dist/Types/Marketing/MarketingEvent.js +43 -0
  164. package/build/dist/Types/Marketing/MarketingEvent.js.map +1 -0
  165. package/build/dist/UI/Utils/NotificationMethodUtil.js +33 -1
  166. package/build/dist/UI/Utils/NotificationMethodUtil.js.map +1 -1
  167. package/build/dist/UI/Utils/PermissionGate.js +32 -0
  168. package/build/dist/UI/Utils/PermissionGate.js.map +1 -1
  169. package/package.json +1 -1
  170. package/Models/DatabaseModels/MarketingConversion.ts +0 -410
  171. package/Server/Services/MarketingConversionService.ts +0 -10
  172. package/Server/Utils/Marketing/ConversionUploadProvider.ts +0 -215
  173. package/Server/Utils/Marketing/ConversionUploadProviders.ts +0 -22
  174. package/Server/Utils/Marketing/Providers/GoogleAds.ts +0 -333
  175. package/Server/Utils/Marketing/Providers/LinkedIn.ts +0 -185
  176. package/Server/Utils/Marketing/Providers/Meta.ts +0 -182
  177. package/Server/Utils/Marketing/Providers/MicrosoftAds.ts +0 -223
  178. package/Server/Utils/Marketing/Providers/Reddit.ts +0 -208
  179. package/Tests/Server/Utils/Marketing/AdUploadableConversionTypes.test.ts +0 -315
  180. package/Tests/Server/Utils/Marketing/ConversionUploadProvider.test.ts +0 -300
  181. package/Tests/Server/Utils/Marketing/GoogleAds.test.ts +0 -592
  182. package/Tests/Server/Utils/Marketing/LinkedIn.test.ts +0 -282
  183. package/Tests/Server/Utils/Marketing/Meta.test.ts +0 -304
  184. package/Tests/Server/Utils/Marketing/MicrosoftAds.test.ts +0 -263
  185. package/Tests/Server/Utils/Marketing/Reddit.test.ts +0 -259
  186. package/Types/Marketing/MarketingConversion.ts +0 -53
  187. package/build/dist/Models/DatabaseModels/MarketingConversion.js +0 -445
  188. package/build/dist/Models/DatabaseModels/MarketingConversion.js.map +0 -1
  189. package/build/dist/Server/Services/MarketingConversionService.js +0 -9
  190. package/build/dist/Server/Services/MarketingConversionService.js.map +0 -1
  191. package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js +0 -93
  192. package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js.map +0 -1
  193. package/build/dist/Server/Utils/Marketing/ConversionUploadProviders.js +0 -20
  194. package/build/dist/Server/Utils/Marketing/ConversionUploadProviders.js.map +0 -1
  195. package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js +0 -221
  196. package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js.map +0 -1
  197. package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js +0 -137
  198. package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js.map +0 -1
  199. package/build/dist/Server/Utils/Marketing/Providers/Meta.js +0 -133
  200. package/build/dist/Server/Utils/Marketing/Providers/Meta.js.map +0 -1
  201. package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js +0 -143
  202. package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js.map +0 -1
  203. package/build/dist/Server/Utils/Marketing/Providers/Reddit.js +0 -145
  204. package/build/dist/Server/Utils/Marketing/Providers/Reddit.js.map +0 -1
  205. package/build/dist/Types/Marketing/MarketingConversion.js +0 -52
  206. 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
- });