@oneuptime/common 9.3.20 → 9.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/Models/DatabaseModels/IncomingCallLog.ts +521 -0
  2. package/Models/DatabaseModels/IncomingCallLogItem.ts +463 -0
  3. package/Models/DatabaseModels/IncomingCallPolicy.ts +811 -0
  4. package/Models/DatabaseModels/IncomingCallPolicyEscalationRule.ts +597 -0
  5. package/Models/DatabaseModels/Index.ts +18 -0
  6. package/Models/DatabaseModels/ProjectSCIMLog.ts +422 -0
  7. package/Models/DatabaseModels/StatusPageSCIMLog.ts +455 -0
  8. package/Models/DatabaseModels/User.ts +0 -15
  9. package/Models/DatabaseModels/UserIncomingCallNumber.ts +296 -0
  10. package/Server/API/UserIncomingCallNumberAPI.ts +128 -0
  11. package/Server/Infrastructure/Postgres/SchemaMigrations/1768583966447-MigrationName.ts +121 -0
  12. package/Server/Infrastructure/Postgres/SchemaMigrations/1768647802022-RemoveAlertPhoneNumberFromUser.ts +22 -0
  13. package/Server/Infrastructure/Postgres/SchemaMigrations/1768649699509-MigrationName.ts +787 -0
  14. package/Server/Infrastructure/Postgres/SchemaMigrations/1768682071562-MigrationName.ts +29 -0
  15. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
  16. package/Server/Services/IncomingCallLogItemService.ts +10 -0
  17. package/Server/Services/IncomingCallLogService.ts +10 -0
  18. package/Server/Services/IncomingCallPolicyEscalationRuleService.ts +267 -0
  19. package/Server/Services/IncomingCallPolicyService.ts +10 -0
  20. package/Server/Services/Index.ts +7 -0
  21. package/Server/Services/ProjectSCIMLogService.ts +11 -0
  22. package/Server/Services/StatusPageSCIMLogService.ts +11 -0
  23. package/Server/Services/UserCallService.ts +31 -0
  24. package/Server/Services/UserIncomingCallNumberService.ts +258 -0
  25. package/Server/Services/UserSmsService.ts +31 -0
  26. package/Server/Utils/AnalyticsDatabase/Statement.ts +2 -2
  27. package/Server/Utils/StartServer.ts +5 -0
  28. package/Tests/UI/Components/Input.test.tsx +33 -0
  29. package/Types/Call/CallProvider.ts +99 -0
  30. package/Types/Call/CallProviderType.ts +6 -0
  31. package/Types/Date.ts +18 -0
  32. package/Types/Icon/IconProp.ts +1 -0
  33. package/Types/IncomingCall/IncomingCallStatus.ts +13 -0
  34. package/Types/Permission.ts +126 -0
  35. package/Types/Phone.ts +53 -4
  36. package/Types/SCIM/SCIMLogStatus.ts +7 -0
  37. package/UI/Components/Date/StartAndEndDate.tsx +35 -11
  38. package/UI/Components/Diagram/ConceptCards.tsx +74 -0
  39. package/UI/Components/Diagram/HorizontalStepChain.tsx +92 -0
  40. package/UI/Components/Diagram/Index.ts +11 -0
  41. package/UI/Components/Diagram/NumberedSteps.tsx +77 -0
  42. package/UI/Components/Diagram/VerticalFlowSteps.tsx +59 -0
  43. package/UI/Components/Filters/FilterViewer.tsx +7 -0
  44. package/UI/Components/Icon/Icon.tsx +10 -0
  45. package/UI/Components/Input/Input.tsx +7 -0
  46. package/UI/Components/SimpleLogViewer/SimpleLogViewer.tsx +86 -2
  47. package/build/dist/Models/DatabaseModels/IncomingCallLog.js +565 -0
  48. package/build/dist/Models/DatabaseModels/IncomingCallLog.js.map +1 -0
  49. package/build/dist/Models/DatabaseModels/IncomingCallLogItem.js +497 -0
  50. package/build/dist/Models/DatabaseModels/IncomingCallLogItem.js.map +1 -0
  51. package/build/dist/Models/DatabaseModels/IncomingCallPolicy.js +840 -0
  52. package/build/dist/Models/DatabaseModels/IncomingCallPolicy.js.map +1 -0
  53. package/build/dist/Models/DatabaseModels/IncomingCallPolicyEscalationRule.js +619 -0
  54. package/build/dist/Models/DatabaseModels/IncomingCallPolicyEscalationRule.js.map +1 -0
  55. package/build/dist/Models/DatabaseModels/Index.js +16 -0
  56. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  57. package/build/dist/Models/DatabaseModels/ProjectSCIMLog.js +455 -0
  58. package/build/dist/Models/DatabaseModels/ProjectSCIMLog.js.map +1 -0
  59. package/build/dist/Models/DatabaseModels/StatusPageSCIMLog.js +486 -0
  60. package/build/dist/Models/DatabaseModels/StatusPageSCIMLog.js.map +1 -0
  61. package/build/dist/Models/DatabaseModels/User.js +0 -16
  62. package/build/dist/Models/DatabaseModels/User.js.map +1 -1
  63. package/build/dist/Models/DatabaseModels/UserIncomingCallNumber.js +315 -0
  64. package/build/dist/Models/DatabaseModels/UserIncomingCallNumber.js.map +1 -0
  65. package/build/dist/Server/API/UserIncomingCallNumberAPI.js +72 -0
  66. package/build/dist/Server/API/UserIncomingCallNumberAPI.js.map +1 -0
  67. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768583966447-MigrationName.js +48 -0
  68. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768583966447-MigrationName.js.map +1 -0
  69. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768647802022-RemoveAlertPhoneNumberFromUser.js +34 -0
  70. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768647802022-RemoveAlertPhoneNumberFromUser.js.map +1 -0
  71. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768649699509-MigrationName.js +270 -0
  72. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768649699509-MigrationName.js.map +1 -0
  73. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768682071562-MigrationName.js +16 -0
  74. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768682071562-MigrationName.js.map +1 -0
  75. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  76. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  77. package/build/dist/Server/Services/IncomingCallLogItemService.js +9 -0
  78. package/build/dist/Server/Services/IncomingCallLogItemService.js.map +1 -0
  79. package/build/dist/Server/Services/IncomingCallLogService.js +9 -0
  80. package/build/dist/Server/Services/IncomingCallLogService.js.map +1 -0
  81. package/build/dist/Server/Services/IncomingCallPolicyEscalationRuleService.js +197 -0
  82. package/build/dist/Server/Services/IncomingCallPolicyEscalationRuleService.js.map +1 -0
  83. package/build/dist/Server/Services/IncomingCallPolicyService.js +9 -0
  84. package/build/dist/Server/Services/IncomingCallPolicyService.js.map +1 -0
  85. package/build/dist/Server/Services/Index.js +6 -0
  86. package/build/dist/Server/Services/Index.js.map +1 -1
  87. package/build/dist/Server/Services/ProjectSCIMLogService.js +10 -0
  88. package/build/dist/Server/Services/ProjectSCIMLogService.js.map +1 -0
  89. package/build/dist/Server/Services/StatusPageSCIMLogService.js +10 -0
  90. package/build/dist/Server/Services/StatusPageSCIMLogService.js.map +1 -0
  91. package/build/dist/Server/Services/UserCallService.js +21 -0
  92. package/build/dist/Server/Services/UserCallService.js.map +1 -1
  93. package/build/dist/Server/Services/UserIncomingCallNumberService.js +225 -0
  94. package/build/dist/Server/Services/UserIncomingCallNumberService.js.map +1 -0
  95. package/build/dist/Server/Services/UserSmsService.js +21 -0
  96. package/build/dist/Server/Services/UserSmsService.js.map +1 -1
  97. package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js +2 -2
  98. package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js.map +1 -1
  99. package/build/dist/Server/Utils/StartServer.js +5 -0
  100. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  101. package/build/dist/Tests/UI/Components/Input.test.js +10 -0
  102. package/build/dist/Tests/UI/Components/Input.test.js.map +1 -1
  103. package/build/dist/Types/Call/CallProvider.js +2 -0
  104. package/build/dist/Types/Call/CallProvider.js.map +1 -0
  105. package/build/dist/Types/Call/CallProviderType.js +7 -0
  106. package/build/dist/Types/Call/CallProviderType.js.map +1 -0
  107. package/build/dist/Types/Date.js +17 -3
  108. package/build/dist/Types/Date.js.map +1 -1
  109. package/build/dist/Types/Icon/IconProp.js +1 -0
  110. package/build/dist/Types/Icon/IconProp.js.map +1 -1
  111. package/build/dist/Types/IncomingCall/IncomingCallStatus.js +14 -0
  112. package/build/dist/Types/IncomingCall/IncomingCallStatus.js.map +1 -0
  113. package/build/dist/Types/Permission.js +104 -0
  114. package/build/dist/Types/Permission.js.map +1 -1
  115. package/build/dist/Types/Phone.js +47 -3
  116. package/build/dist/Types/Phone.js.map +1 -1
  117. package/build/dist/Types/SCIM/SCIMLogStatus.js +8 -0
  118. package/build/dist/Types/SCIM/SCIMLogStatus.js.map +1 -0
  119. package/build/dist/UI/Components/Date/StartAndEndDate.js +13 -13
  120. package/build/dist/UI/Components/Date/StartAndEndDate.js.map +1 -1
  121. package/build/dist/UI/Components/Diagram/ConceptCards.js +30 -0
  122. package/build/dist/UI/Components/Diagram/ConceptCards.js.map +1 -0
  123. package/build/dist/UI/Components/Diagram/HorizontalStepChain.js +30 -0
  124. package/build/dist/UI/Components/Diagram/HorizontalStepChain.js.map +1 -0
  125. package/build/dist/UI/Components/Diagram/Index.js +5 -0
  126. package/build/dist/UI/Components/Diagram/Index.js.map +1 -0
  127. package/build/dist/UI/Components/Diagram/NumberedSteps.js +18 -0
  128. package/build/dist/UI/Components/Diagram/NumberedSteps.js.map +1 -0
  129. package/build/dist/UI/Components/Diagram/VerticalFlowSteps.js +16 -0
  130. package/build/dist/UI/Components/Diagram/VerticalFlowSteps.js.map +1 -0
  131. package/build/dist/UI/Components/Filters/FilterViewer.js +6 -5
  132. package/build/dist/UI/Components/Filters/FilterViewer.js.map +1 -1
  133. package/build/dist/UI/Components/Icon/Icon.js +4 -0
  134. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  135. package/build/dist/UI/Components/Input/Input.js +4 -1
  136. package/build/dist/UI/Components/Input/Input.js.map +1 -1
  137. package/build/dist/UI/Components/SimpleLogViewer/SimpleLogViewer.js +30 -1
  138. package/build/dist/UI/Components/SimpleLogViewer/SimpleLogViewer.js.map +1 -1
  139. package/package.json +1 -1
@@ -0,0 +1,258 @@
1
+ import { IsBillingEnabled } from "../EnvironmentConfig";
2
+ import CreateBy from "../Types/Database/CreateBy";
3
+ import { OnCreate } from "../Types/Database/Hooks";
4
+ import logger from "../Utils/Logger";
5
+ import DatabaseService from "./DatabaseService";
6
+ import ProjectService from "./ProjectService";
7
+ import SmsService from "./SmsService";
8
+ import BadDataException from "../../Types/Exception/BadDataException";
9
+ import ObjectID from "../../Types/ObjectID";
10
+ import Text from "../../Types/Text";
11
+ import Project from "../../Models/DatabaseModels/Project";
12
+ import Model from "../../Models/DatabaseModels/UserIncomingCallNumber";
13
+ import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
14
+
15
+ export class Service extends DatabaseService<Model> {
16
+ public constructor() {
17
+ super(Model);
18
+ }
19
+
20
+ @CaptureSpan()
21
+ protected override async onBeforeCreate(
22
+ createBy: CreateBy<Model>,
23
+ ): Promise<OnCreate<Model>> {
24
+ // Check if user is trying to set isVerified to true
25
+ if (!createBy.props.isRoot && createBy.data.isVerified) {
26
+ throw new BadDataException("isVerified cannot be set to true");
27
+ }
28
+
29
+ // Check if SMS notifications are enabled for this project
30
+ const project: Project | null = await ProjectService.findOneById({
31
+ id: createBy.data.projectId!,
32
+ props: {
33
+ isRoot: true,
34
+ },
35
+ select: {
36
+ enableSmsNotifications: true,
37
+ smsOrCallCurrentBalanceInUSDCents: true,
38
+ },
39
+ });
40
+
41
+ if (!project) {
42
+ throw new BadDataException("Project not found");
43
+ }
44
+
45
+ if (!project.enableSmsNotifications) {
46
+ throw new BadDataException(
47
+ "SMS notifications are disabled for this project. Please enable them in Project Settings > Notification Settings.",
48
+ );
49
+ }
50
+
51
+ if (
52
+ (project.smsOrCallCurrentBalanceInUSDCents as number) <= 100 &&
53
+ IsBillingEnabled
54
+ ) {
55
+ throw new BadDataException(
56
+ "Your SMS balance is low. Please recharge your SMS balance in Project Settings > Notification Settings.",
57
+ );
58
+ }
59
+
60
+ // Check if user already has a verified phone number for this project
61
+ const existingVerifiedNumber: Model | null = await this.findOneBy({
62
+ query: {
63
+ userId: createBy.data.userId!,
64
+ projectId: createBy.data.projectId!,
65
+ isVerified: true,
66
+ },
67
+ select: {
68
+ _id: true,
69
+ },
70
+ props: {
71
+ isRoot: true,
72
+ },
73
+ });
74
+
75
+ if (existingVerifiedNumber) {
76
+ throw new BadDataException(
77
+ "You already have a verified phone number for this project. Please delete the existing one before adding a new one.",
78
+ );
79
+ }
80
+
81
+ return { carryForward: null, createBy };
82
+ }
83
+
84
+ @CaptureSpan()
85
+ protected override async onCreateSuccess(
86
+ _onCreate: OnCreate<Model>,
87
+ createdItem: Model,
88
+ ): Promise<Model> {
89
+ if (!createdItem.isVerified) {
90
+ this.sendVerificationCode(createdItem);
91
+ }
92
+
93
+ return createdItem;
94
+ }
95
+
96
+ @CaptureSpan()
97
+ public async resendVerificationCode(itemId: ObjectID): Promise<void> {
98
+ const item: Model | null = await this.findOneById({
99
+ id: itemId,
100
+ props: {
101
+ isRoot: true,
102
+ },
103
+ select: {
104
+ phone: true,
105
+ verificationCode: true,
106
+ isVerified: true,
107
+ projectId: true,
108
+ userId: true,
109
+ },
110
+ });
111
+
112
+ if (!item) {
113
+ throw new BadDataException(
114
+ "Item with ID " + itemId.toString() + " not found",
115
+ );
116
+ }
117
+
118
+ if (item.isVerified) {
119
+ throw new BadDataException("Phone Number already verified");
120
+ }
121
+
122
+ // Check if SMS notifications are enabled for this project
123
+ const project: Project | null = await ProjectService.findOneById({
124
+ id: item.projectId!,
125
+ props: {
126
+ isRoot: true,
127
+ },
128
+ select: {
129
+ enableSmsNotifications: true,
130
+ smsOrCallCurrentBalanceInUSDCents: true,
131
+ },
132
+ });
133
+
134
+ if (!project) {
135
+ throw new BadDataException("Project not found");
136
+ }
137
+
138
+ if (!project.enableSmsNotifications) {
139
+ throw new BadDataException(
140
+ "SMS notifications are disabled for this project. Please enable them in Project Settings > Notification Settings.",
141
+ );
142
+ }
143
+
144
+ if (
145
+ (project.smsOrCallCurrentBalanceInUSDCents as number) <= 100 &&
146
+ IsBillingEnabled
147
+ ) {
148
+ throw new BadDataException(
149
+ "Your SMS balance is low. Please recharge your SMS balance in Project Settings > Notification Settings.",
150
+ );
151
+ }
152
+
153
+ // Generate new verification code
154
+ item.verificationCode = Text.generateRandomNumber(6);
155
+
156
+ await this.updateOneById({
157
+ id: item.id!,
158
+ props: {
159
+ isRoot: true,
160
+ },
161
+ data: {
162
+ verificationCode: item.verificationCode,
163
+ },
164
+ });
165
+
166
+ this.sendVerificationCode(item);
167
+ }
168
+
169
+ public sendVerificationCode(item: Model): void {
170
+ // Send verification SMS
171
+ SmsService.sendSms(
172
+ {
173
+ to: item.phone!,
174
+ message:
175
+ "This message is from OneUptime. Your verification code for incoming call routing is " +
176
+ item.verificationCode,
177
+ },
178
+ {
179
+ projectId: item.projectId,
180
+ isSensitive: true,
181
+ userId: item.userId!,
182
+ },
183
+ ).catch((err: Error) => {
184
+ logger.error(err);
185
+ });
186
+ }
187
+
188
+ @CaptureSpan()
189
+ public async verifyPhoneNumber(
190
+ itemId: ObjectID,
191
+ userId: ObjectID,
192
+ code: string,
193
+ ): Promise<void> {
194
+ const item: Model | null = await this.findOneById({
195
+ id: itemId,
196
+ props: {
197
+ isRoot: true,
198
+ },
199
+ select: {
200
+ userId: true,
201
+ verificationCode: true,
202
+ isVerified: true,
203
+ projectId: true,
204
+ },
205
+ });
206
+
207
+ if (!item) {
208
+ throw new BadDataException("Item not found");
209
+ }
210
+
211
+ // Check user ID
212
+ if (item.userId?.toString() !== userId.toString()) {
213
+ throw new BadDataException("Invalid user ID");
214
+ }
215
+
216
+ if (item.isVerified) {
217
+ throw new BadDataException("Phone number is already verified");
218
+ }
219
+
220
+ if (item.verificationCode !== code) {
221
+ throw new BadDataException("Invalid verification code");
222
+ }
223
+
224
+ // Check if user already has a verified number for this project
225
+ const existingVerifiedNumber: Model | null = await this.findOneBy({
226
+ query: {
227
+ userId: item.userId!,
228
+ projectId: item.projectId!,
229
+ isVerified: true,
230
+ },
231
+ select: {
232
+ _id: true,
233
+ },
234
+ props: {
235
+ isRoot: true,
236
+ },
237
+ });
238
+
239
+ if (existingVerifiedNumber) {
240
+ throw new BadDataException(
241
+ "You already have a verified phone number for this project. Please delete the existing one before verifying a new one.",
242
+ );
243
+ }
244
+
245
+ // Mark as verified
246
+ await this.updateOneById({
247
+ id: itemId,
248
+ props: {
249
+ isRoot: true,
250
+ },
251
+ data: {
252
+ isVerified: true,
253
+ },
254
+ });
255
+ }
256
+ }
257
+
258
+ export default new Service();
@@ -137,6 +137,37 @@ export class Service extends DatabaseService<Model> {
137
137
  throw new BadDataException("Phone Number already verified");
138
138
  }
139
139
 
140
+ // Check if SMS notifications are enabled for this project
141
+ const project: Project | null = await ProjectService.findOneById({
142
+ id: item.projectId!,
143
+ props: {
144
+ isRoot: true,
145
+ },
146
+ select: {
147
+ enableSmsNotifications: true,
148
+ smsOrCallCurrentBalanceInUSDCents: true,
149
+ },
150
+ });
151
+
152
+ if (!project) {
153
+ throw new BadDataException("Project not found");
154
+ }
155
+
156
+ if (!project.enableSmsNotifications) {
157
+ throw new BadDataException(
158
+ "SMS notifications are disabled for this project. Please enable them in Project Settings > Notification Settings.",
159
+ );
160
+ }
161
+
162
+ if (
163
+ (project.smsOrCallCurrentBalanceInUSDCents as number) <= 100 &&
164
+ IsBillingEnabled
165
+ ) {
166
+ throw new BadDataException(
167
+ "Your SMS balance is low. Please recharge your SMS balance in Project Settings > Notification Settings.",
168
+ );
169
+ }
170
+
140
171
  // generate new verification code
141
172
  item.verificationCode = Text.generateRandomNumber(6);
142
173
 
@@ -118,7 +118,7 @@ export class Statement implements BaseQueryParams {
118
118
  finalValue = v.value.values;
119
119
  }
120
120
  } else if (v.value instanceof Date) {
121
- finalValue = OneUptimeDate.toDatabaseDate(v.value);
121
+ finalValue = OneUptimeDate.toClickhouseDateTime(v.value);
122
122
  } else {
123
123
  finalValue = v.value;
124
124
  }
@@ -127,7 +127,7 @@ export class Statement implements BaseQueryParams {
127
127
 
128
128
  if (typeof v !== "string" && v.type === TableColumnType.Date) {
129
129
  finalValue = OneUptimeDate.fromString(finalValue as string);
130
- finalValue = OneUptimeDate.toDatabaseDate(finalValue);
130
+ finalValue = OneUptimeDate.toClickhouseDateTime(finalValue);
131
131
  }
132
132
 
133
133
  return finalValue;
@@ -45,6 +45,11 @@ const app: ExpressApplication = Express.getExpressApp();
45
45
  app.disable("x-powered-by");
46
46
  app.set("port", process.env["PORT"]);
47
47
  app.set("view engine", "ejs");
48
+ /*
49
+ * Enable trust proxy to correctly interpret X-Forwarded-* headers from reverse proxies
50
+ * This is needed for req.protocol, req.ip to be correct when behind nginx/load balancers
51
+ */
52
+ app.set("trust proxy", true);
48
53
  app.use(CookieParser());
49
54
 
50
55
  const jsonBodyParserMiddleware: RequestHandler = ExpressJson({
@@ -207,6 +207,39 @@ describe("Input", () => {
207
207
  );
208
208
  });
209
209
 
210
+ test("sets step attribute to 1 for datetime-local when showSecondsForDateTime is true", () => {
211
+ const dataTestId: string = "testid";
212
+
213
+ render(
214
+ <Input
215
+ type={InputType.DATETIME_LOCAL}
216
+ showSecondsForDateTime={true}
217
+ dataTestId={dataTestId}
218
+ />,
219
+ );
220
+
221
+ expect(screen.getByTestId<HTMLInputElement>(dataTestId)).toHaveAttribute(
222
+ "step",
223
+ "1",
224
+ );
225
+ });
226
+
227
+ test("does not set step attribute for datetime-local when showSecondsForDateTime is false", () => {
228
+ const dataTestId: string = "testid";
229
+
230
+ render(
231
+ <Input
232
+ type={InputType.DATETIME_LOCAL}
233
+ showSecondsForDateTime={false}
234
+ dataTestId={dataTestId}
235
+ />,
236
+ );
237
+
238
+ expect(
239
+ screen.getByTestId<HTMLInputElement>(dataTestId),
240
+ ).not.toHaveAttribute("step");
241
+ });
242
+
210
243
  test("uses YYYY-MM-DD for date type", () => {
211
244
  const date: string = "2023-04-22T00:00:00";
212
245
  const dataTestId: string = "testid";
@@ -0,0 +1,99 @@
1
+ import { JSONObject } from "../JSON";
2
+
3
+ // Phone number from provider search
4
+ export interface AvailablePhoneNumber {
5
+ phoneNumber: string; // "+14155550123"
6
+ friendlyName: string; // "(415) 555-0123"
7
+ locality?: string; // "San Francisco"
8
+ region?: string; // "CA"
9
+ country: string; // "US"
10
+ }
11
+
12
+ // Purchased phone number details
13
+ export interface PurchasedPhoneNumber {
14
+ phoneNumberId: string; // Provider's ID (e.g., Twilio SID)
15
+ phoneNumber: string;
16
+ }
17
+
18
+ // Owned phone number (already purchased in Twilio account)
19
+ export interface OwnedPhoneNumber {
20
+ phoneNumberId: string; // Provider's ID (e.g., Twilio SID)
21
+ phoneNumber: string; // "+14155550123"
22
+ friendlyName: string; // "(415) 555-0123"
23
+ voiceUrl?: string | undefined; // Current webhook URL configured
24
+ }
25
+
26
+ // Search options for available numbers
27
+ export interface SearchNumberOptions {
28
+ countryCode: string;
29
+ areaCode?: string;
30
+ contains?: string;
31
+ limit?: number;
32
+ }
33
+
34
+ // Options for dial operation
35
+ export interface DialOptions {
36
+ toPhoneNumber: string;
37
+ fromPhoneNumber: string;
38
+ timeoutSeconds: number;
39
+ statusCallbackUrl: string;
40
+ }
41
+
42
+ // Parsed incoming call data from webhook
43
+ export interface IncomingCallData {
44
+ callId: string; // Provider's call ID
45
+ callerPhoneNumber: string;
46
+ calledPhoneNumber: string;
47
+ }
48
+
49
+ // Parsed dial status data from webhook
50
+ export interface DialStatusData {
51
+ callId: string;
52
+ dialStatus: "completed" | "busy" | "no-answer" | "failed" | "canceled";
53
+ dialDurationSeconds?: number;
54
+ }
55
+
56
+ // Express Request type for webhook parsing
57
+ export interface WebhookRequest {
58
+ body: JSONObject;
59
+ headers: { [key: string]: string | string[] | undefined };
60
+ originalUrl: string;
61
+ url: string;
62
+ protocol: string;
63
+ get: (name: string) => string | undefined;
64
+ }
65
+
66
+ // Call provider interface - all providers must implement this
67
+ export interface ICallProvider {
68
+ // Phone number management
69
+ searchAvailableNumbers(
70
+ options: SearchNumberOptions,
71
+ ): Promise<AvailablePhoneNumber[]>;
72
+ listOwnedNumbers(): Promise<OwnedPhoneNumber[]>;
73
+ purchaseNumber(
74
+ phoneNumber: string,
75
+ webhookUrl: string,
76
+ ): Promise<PurchasedPhoneNumber>;
77
+ assignExistingNumber(
78
+ phoneNumberId: string,
79
+ webhookUrl: string,
80
+ ): Promise<PurchasedPhoneNumber>;
81
+ releaseNumber(phoneNumberId: string): Promise<void>;
82
+ updateWebhookUrl(phoneNumberId: string, webhookUrl: string): Promise<void>;
83
+
84
+ // Voice response generation (provider-specific markup)
85
+ generateGreetingResponse(message: string): string;
86
+ generateDialResponse(options: DialOptions): string;
87
+ generateHangupResponse(message?: string): string;
88
+ generateEscalationResponse(
89
+ message: string,
90
+ nextDialOptions: DialOptions,
91
+ ): string;
92
+
93
+ // Webhook parsing
94
+ parseIncomingCallWebhook(request: WebhookRequest): IncomingCallData;
95
+ parseDialStatusWebhook(request: WebhookRequest): DialStatusData;
96
+
97
+ // Webhook signature validation
98
+ validateWebhookSignature(request: WebhookRequest, signature: string): boolean;
99
+ }
@@ -0,0 +1,6 @@
1
+ // Available call providers
2
+ enum CallProviderType {
3
+ Twilio = "twilio",
4
+ }
5
+
6
+ export default CallProviderType;
package/Types/Date.ts CHANGED
@@ -970,11 +970,13 @@ export default class OneUptimeDate {
970
970
  public static getDateAsUserFriendlyLocalFormattedString(
971
971
  date: string | Date,
972
972
  onlyShowDate?: boolean,
973
+ showSeconds?: boolean,
973
974
  ): string {
974
975
  return this.getDateAsLocalFormattedString(
975
976
  date,
976
977
  onlyShowDate,
977
978
  this.getUserPrefers12HourFormat(),
979
+ showSeconds,
978
980
  );
979
981
  }
980
982
 
@@ -1363,6 +1365,7 @@ export default class OneUptimeDate {
1363
1365
  date: string | Date,
1364
1366
  onlyShowDate?: boolean,
1365
1367
  use12HourFormat?: boolean,
1368
+ showSeconds?: boolean,
1366
1369
  ): string {
1367
1370
  date = this.fromString(date);
1368
1371
 
@@ -1372,6 +1375,14 @@ export default class OneUptimeDate {
1372
1375
  formatstring = "MMM DD YYYY, hh:mm A";
1373
1376
  }
1374
1377
 
1378
+ if (showSeconds) {
1379
+ if (use12HourFormat) {
1380
+ formatstring = "MMM DD YYYY, hh:mm:ss A";
1381
+ } else {
1382
+ formatstring = "MMM DD YYYY, HH:mm:ss";
1383
+ }
1384
+ }
1385
+
1375
1386
  if (onlyShowDate) {
1376
1387
  formatstring = "MMM DD, YYYY";
1377
1388
  }
@@ -1502,6 +1513,13 @@ export default class OneUptimeDate {
1502
1513
  return moment(date).format("YYYY-MM-DD HH:mm:ss");
1503
1514
  }
1504
1515
 
1516
+ public static resetSecondsAndMilliseconds(date: Date): Date {
1517
+ date = this.fromString(date);
1518
+ date.setSeconds(0);
1519
+ date.setMilliseconds(0);
1520
+ return date;
1521
+ }
1522
+
1505
1523
  public static toClickhouseDateTime(date: Date | string): string {
1506
1524
  const parsedDate: Date = this.fromString(date);
1507
1525
  return moment(parsedDate).utc().format("YYYY-MM-DD HH:mm:ss");
@@ -62,6 +62,7 @@ enum IconProp {
62
62
  Activity = "Activity",
63
63
  Alert = "Alert",
64
64
  Call = "Call",
65
+ IncomingCall = "IncomingCall",
65
66
  List = "List",
66
67
  CheckCircle = "CheckCircle",
67
68
  Search = "Search",
@@ -0,0 +1,13 @@
1
+ enum IncomingCallStatus {
2
+ Initiated = "Initiated",
3
+ Ringing = "Ringing",
4
+ Connected = "Connected",
5
+ Escalated = "Escalated",
6
+ NoAnswer = "NoAnswer",
7
+ Failed = "Failed",
8
+ Completed = "Completed",
9
+ CallerHungUp = "CallerHungUp",
10
+ Busy = "Busy",
11
+ }
12
+
13
+ export default IncomingCallStatus;
@@ -164,6 +164,9 @@ enum Permission {
164
164
  ReadWorkspaceNotificationLog = "ReadWorkspaceNotificationLog",
165
165
  ReadLlmLog = "ReadLlmLog",
166
166
 
167
+ ReadProjectSCIMLog = "ReadProjectSCIMLog",
168
+ ReadStatusPageSCIMLog = "ReadStatusPageSCIMLog",
169
+
167
170
  CreateIncidentOwnerTeam = "CreateIncidentOwnerTeam",
168
171
  DeleteIncidentOwnerTeam = "DeleteIncidentOwnerTeam",
169
172
  EditIncidentOwnerTeam = "EditIncidentOwnerTeam",
@@ -598,6 +601,24 @@ enum Permission {
598
601
  DeleteProjectOnCallDutyPolicyEscalationRuleTeam = "DeleteProjectOnCallDutyPolicyEscalationRuleTeam",
599
602
  ReadProjectOnCallDutyPolicyEscalationRuleTeam = "ReadProjectOnCallDutyPolicyEscalationRuleTeam",
600
603
 
604
+ // Incoming Call Policy Permissions
605
+ CreateProjectIncomingCallPolicy = "CreateProjectIncomingCallPolicy",
606
+ EditProjectIncomingCallPolicy = "EditProjectIncomingCallPolicy",
607
+ DeleteProjectIncomingCallPolicy = "DeleteProjectIncomingCallPolicy",
608
+ ReadProjectIncomingCallPolicy = "ReadProjectIncomingCallPolicy",
609
+
610
+ // Incoming Call Policy Escalation Rule Permissions
611
+ CreateProjectIncomingCallPolicyEscalationRule = "CreateProjectIncomingCallPolicyEscalationRule",
612
+ EditProjectIncomingCallPolicyEscalationRule = "EditProjectIncomingCallPolicyEscalationRule",
613
+ DeleteProjectIncomingCallPolicyEscalationRule = "DeleteProjectIncomingCallPolicyEscalationRule",
614
+ ReadProjectIncomingCallPolicyEscalationRule = "ReadProjectIncomingCallPolicyEscalationRule",
615
+
616
+ // Incoming Call Log Permissions
617
+ ReadProjectIncomingCallLog = "ReadProjectIncomingCallLog",
618
+
619
+ // Incoming Call Log Item Permissions
620
+ ReadProjectIncomingCallLogItem = "ReadProjectIncomingCallLogItem",
621
+
601
622
  // Project SMTP Config (Team Permission)
602
623
  CreateProjectSMTPConfig = "CreateProjectSMTPConfig",
603
624
  EditProjectSMTPConfig = "EditProjectSMTPConfig",
@@ -1373,6 +1394,23 @@ export class PermissionHelper {
1373
1394
  isAccessControlPermission: false,
1374
1395
  },
1375
1396
 
1397
+ {
1398
+ permission: Permission.ReadProjectSCIMLog,
1399
+ title: "Read Project SCIM Log",
1400
+ description:
1401
+ "This permission can read SCIM provisioning logs of the project.",
1402
+ isAssignableToTenant: true,
1403
+ isAccessControlPermission: false,
1404
+ },
1405
+ {
1406
+ permission: Permission.ReadStatusPageSCIMLog,
1407
+ title: "Read Status Page SCIM Log",
1408
+ description:
1409
+ "This permission can read SCIM provisioning logs of status pages in the project.",
1410
+ isAssignableToTenant: true,
1411
+ isAccessControlPermission: false,
1412
+ },
1413
+
1376
1414
  {
1377
1415
  permission: Permission.CreateProjectMonitorStatus,
1378
1416
  title: "Create Monitor Status",
@@ -2475,6 +2513,94 @@ export class PermissionHelper {
2475
2513
  isAccessControlPermission: false,
2476
2514
  },
2477
2515
 
2516
+ // Incoming Call Policy Permissions
2517
+ {
2518
+ permission: Permission.CreateProjectIncomingCallPolicy,
2519
+ title: "Create Incoming Call Policy",
2520
+ description:
2521
+ "This permission can create incoming call policies for this project.",
2522
+ isAssignableToTenant: true,
2523
+ isAccessControlPermission: false,
2524
+ },
2525
+ {
2526
+ permission: Permission.DeleteProjectIncomingCallPolicy,
2527
+ title: "Delete Incoming Call Policy",
2528
+ description:
2529
+ "This permission can delete incoming call policies of this project.",
2530
+ isAssignableToTenant: true,
2531
+ isAccessControlPermission: false,
2532
+ },
2533
+ {
2534
+ permission: Permission.EditProjectIncomingCallPolicy,
2535
+ title: "Edit Incoming Call Policy",
2536
+ description:
2537
+ "This permission can edit incoming call policies of this project.",
2538
+ isAssignableToTenant: true,
2539
+ isAccessControlPermission: false,
2540
+ },
2541
+ {
2542
+ permission: Permission.ReadProjectIncomingCallPolicy,
2543
+ title: "Read Incoming Call Policy",
2544
+ description:
2545
+ "This permission can read incoming call policies of this project.",
2546
+ isAssignableToTenant: true,
2547
+ isAccessControlPermission: false,
2548
+ },
2549
+
2550
+ // Incoming Call Policy Escalation Rule Permissions
2551
+ {
2552
+ permission: Permission.CreateProjectIncomingCallPolicyEscalationRule,
2553
+ title: "Create Incoming Call Policy Escalation Rule",
2554
+ description:
2555
+ "This permission can create incoming call policy escalation rules for this project.",
2556
+ isAssignableToTenant: true,
2557
+ isAccessControlPermission: false,
2558
+ },
2559
+ {
2560
+ permission: Permission.DeleteProjectIncomingCallPolicyEscalationRule,
2561
+ title: "Delete Incoming Call Policy Escalation Rule",
2562
+ description:
2563
+ "This permission can delete incoming call policy escalation rules of this project.",
2564
+ isAssignableToTenant: true,
2565
+ isAccessControlPermission: false,
2566
+ },
2567
+ {
2568
+ permission: Permission.EditProjectIncomingCallPolicyEscalationRule,
2569
+ title: "Edit Incoming Call Policy Escalation Rule",
2570
+ description:
2571
+ "This permission can edit incoming call policy escalation rules of this project.",
2572
+ isAssignableToTenant: true,
2573
+ isAccessControlPermission: false,
2574
+ },
2575
+ {
2576
+ permission: Permission.ReadProjectIncomingCallPolicyEscalationRule,
2577
+ title: "Read Incoming Call Policy Escalation Rule",
2578
+ description:
2579
+ "This permission can read incoming call policy escalation rules of this project.",
2580
+ isAssignableToTenant: true,
2581
+ isAccessControlPermission: false,
2582
+ },
2583
+
2584
+ // Incoming Call Log Permissions
2585
+ {
2586
+ permission: Permission.ReadProjectIncomingCallLog,
2587
+ title: "Read Incoming Call Log",
2588
+ description:
2589
+ "This permission can read incoming call logs of this project.",
2590
+ isAssignableToTenant: true,
2591
+ isAccessControlPermission: false,
2592
+ },
2593
+
2594
+ // Incoming Call Log Item Permissions
2595
+ {
2596
+ permission: Permission.ReadProjectIncomingCallLogItem,
2597
+ title: "Read Incoming Call Log Item",
2598
+ description:
2599
+ "This permission can read incoming call log items of this project.",
2600
+ isAssignableToTenant: true,
2601
+ isAccessControlPermission: false,
2602
+ },
2603
+
2478
2604
  {
2479
2605
  permission:
2480
2606
  Permission.CreateProjectOnCallDutyPolicyEscalationRuleSchedule,