@oneuptime/common 9.3.22 → 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 (121) 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/StartServer.ts +5 -0
  27. package/Types/Call/CallProvider.ts +99 -0
  28. package/Types/Call/CallProviderType.ts +6 -0
  29. package/Types/Icon/IconProp.ts +1 -0
  30. package/Types/IncomingCall/IncomingCallStatus.ts +13 -0
  31. package/Types/Permission.ts +126 -0
  32. package/Types/Phone.ts +53 -4
  33. package/Types/SCIM/SCIMLogStatus.ts +7 -0
  34. package/UI/Components/Diagram/ConceptCards.tsx +74 -0
  35. package/UI/Components/Diagram/HorizontalStepChain.tsx +92 -0
  36. package/UI/Components/Diagram/Index.ts +11 -0
  37. package/UI/Components/Diagram/NumberedSteps.tsx +77 -0
  38. package/UI/Components/Diagram/VerticalFlowSteps.tsx +59 -0
  39. package/UI/Components/Icon/Icon.tsx +10 -0
  40. package/UI/Components/SimpleLogViewer/SimpleLogViewer.tsx +86 -2
  41. package/build/dist/Models/DatabaseModels/IncomingCallLog.js +565 -0
  42. package/build/dist/Models/DatabaseModels/IncomingCallLog.js.map +1 -0
  43. package/build/dist/Models/DatabaseModels/IncomingCallLogItem.js +497 -0
  44. package/build/dist/Models/DatabaseModels/IncomingCallLogItem.js.map +1 -0
  45. package/build/dist/Models/DatabaseModels/IncomingCallPolicy.js +840 -0
  46. package/build/dist/Models/DatabaseModels/IncomingCallPolicy.js.map +1 -0
  47. package/build/dist/Models/DatabaseModels/IncomingCallPolicyEscalationRule.js +619 -0
  48. package/build/dist/Models/DatabaseModels/IncomingCallPolicyEscalationRule.js.map +1 -0
  49. package/build/dist/Models/DatabaseModels/Index.js +16 -0
  50. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  51. package/build/dist/Models/DatabaseModels/ProjectSCIMLog.js +455 -0
  52. package/build/dist/Models/DatabaseModels/ProjectSCIMLog.js.map +1 -0
  53. package/build/dist/Models/DatabaseModels/StatusPageSCIMLog.js +486 -0
  54. package/build/dist/Models/DatabaseModels/StatusPageSCIMLog.js.map +1 -0
  55. package/build/dist/Models/DatabaseModels/User.js +0 -16
  56. package/build/dist/Models/DatabaseModels/User.js.map +1 -1
  57. package/build/dist/Models/DatabaseModels/UserIncomingCallNumber.js +315 -0
  58. package/build/dist/Models/DatabaseModels/UserIncomingCallNumber.js.map +1 -0
  59. package/build/dist/Server/API/UserIncomingCallNumberAPI.js +72 -0
  60. package/build/dist/Server/API/UserIncomingCallNumberAPI.js.map +1 -0
  61. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768583966447-MigrationName.js +48 -0
  62. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768583966447-MigrationName.js.map +1 -0
  63. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768647802022-RemoveAlertPhoneNumberFromUser.js +34 -0
  64. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768647802022-RemoveAlertPhoneNumberFromUser.js.map +1 -0
  65. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768649699509-MigrationName.js +270 -0
  66. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768649699509-MigrationName.js.map +1 -0
  67. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768682071562-MigrationName.js +16 -0
  68. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768682071562-MigrationName.js.map +1 -0
  69. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  70. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  71. package/build/dist/Server/Services/IncomingCallLogItemService.js +9 -0
  72. package/build/dist/Server/Services/IncomingCallLogItemService.js.map +1 -0
  73. package/build/dist/Server/Services/IncomingCallLogService.js +9 -0
  74. package/build/dist/Server/Services/IncomingCallLogService.js.map +1 -0
  75. package/build/dist/Server/Services/IncomingCallPolicyEscalationRuleService.js +197 -0
  76. package/build/dist/Server/Services/IncomingCallPolicyEscalationRuleService.js.map +1 -0
  77. package/build/dist/Server/Services/IncomingCallPolicyService.js +9 -0
  78. package/build/dist/Server/Services/IncomingCallPolicyService.js.map +1 -0
  79. package/build/dist/Server/Services/Index.js +6 -0
  80. package/build/dist/Server/Services/Index.js.map +1 -1
  81. package/build/dist/Server/Services/ProjectSCIMLogService.js +10 -0
  82. package/build/dist/Server/Services/ProjectSCIMLogService.js.map +1 -0
  83. package/build/dist/Server/Services/StatusPageSCIMLogService.js +10 -0
  84. package/build/dist/Server/Services/StatusPageSCIMLogService.js.map +1 -0
  85. package/build/dist/Server/Services/UserCallService.js +21 -0
  86. package/build/dist/Server/Services/UserCallService.js.map +1 -1
  87. package/build/dist/Server/Services/UserIncomingCallNumberService.js +225 -0
  88. package/build/dist/Server/Services/UserIncomingCallNumberService.js.map +1 -0
  89. package/build/dist/Server/Services/UserSmsService.js +21 -0
  90. package/build/dist/Server/Services/UserSmsService.js.map +1 -1
  91. package/build/dist/Server/Utils/StartServer.js +5 -0
  92. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  93. package/build/dist/Types/Call/CallProvider.js +2 -0
  94. package/build/dist/Types/Call/CallProvider.js.map +1 -0
  95. package/build/dist/Types/Call/CallProviderType.js +7 -0
  96. package/build/dist/Types/Call/CallProviderType.js.map +1 -0
  97. package/build/dist/Types/Icon/IconProp.js +1 -0
  98. package/build/dist/Types/Icon/IconProp.js.map +1 -1
  99. package/build/dist/Types/IncomingCall/IncomingCallStatus.js +14 -0
  100. package/build/dist/Types/IncomingCall/IncomingCallStatus.js.map +1 -0
  101. package/build/dist/Types/Permission.js +104 -0
  102. package/build/dist/Types/Permission.js.map +1 -1
  103. package/build/dist/Types/Phone.js +47 -3
  104. package/build/dist/Types/Phone.js.map +1 -1
  105. package/build/dist/Types/SCIM/SCIMLogStatus.js +8 -0
  106. package/build/dist/Types/SCIM/SCIMLogStatus.js.map +1 -0
  107. package/build/dist/UI/Components/Diagram/ConceptCards.js +30 -0
  108. package/build/dist/UI/Components/Diagram/ConceptCards.js.map +1 -0
  109. package/build/dist/UI/Components/Diagram/HorizontalStepChain.js +30 -0
  110. package/build/dist/UI/Components/Diagram/HorizontalStepChain.js.map +1 -0
  111. package/build/dist/UI/Components/Diagram/Index.js +5 -0
  112. package/build/dist/UI/Components/Diagram/Index.js.map +1 -0
  113. package/build/dist/UI/Components/Diagram/NumberedSteps.js +18 -0
  114. package/build/dist/UI/Components/Diagram/NumberedSteps.js.map +1 -0
  115. package/build/dist/UI/Components/Diagram/VerticalFlowSteps.js +16 -0
  116. package/build/dist/UI/Components/Diagram/VerticalFlowSteps.js.map +1 -0
  117. package/build/dist/UI/Components/Icon/Icon.js +4 -0
  118. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  119. package/build/dist/UI/Components/SimpleLogViewer/SimpleLogViewer.js +30 -1
  120. package/build/dist/UI/Components/SimpleLogViewer/SimpleLogViewer.js.map +1 -1
  121. 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
 
@@ -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({
@@ -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;
@@ -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,
package/Types/Phone.ts CHANGED
@@ -13,7 +13,7 @@ export default class Phone extends DatabaseProperty {
13
13
  public static pickPhoneNumberToSendSMSOrCallFrom(data: {
14
14
  to: Phone | string;
15
15
  primaryPhoneNumberToPickFrom: Phone | string;
16
- seocndaryPhoneNumbersToPickFrom: Phone[] | string[];
16
+ secondaryPhoneNumbersToPickFrom: Phone[] | string[];
17
17
  }): Phone {
18
18
  /*
19
19
  * convert all to string, so that we can compare them
@@ -28,8 +28,8 @@ export default class Phone extends DatabaseProperty {
28
28
  ? data.primaryPhoneNumberToPickFrom
29
29
  : data.primaryPhoneNumberToPickFrom.toString();
30
30
 
31
- const seocndaryPhoneNumbersToPickFrom: string[] =
32
- data.seocndaryPhoneNumbersToPickFrom.map((phone: Phone | string) => {
31
+ const secondaryPhoneNumbersToPickFrom: string[] =
32
+ data.secondaryPhoneNumbersToPickFrom.map((phone: Phone | string) => {
33
33
  return typeof phone === "string" ? phone : phone.toString();
34
34
  });
35
35
 
@@ -51,7 +51,7 @@ export default class Phone extends DatabaseProperty {
51
51
  return new Phone(primaryPhoneNumberToPickFrom);
52
52
  }
53
53
 
54
- for (const secondaryPhoneNumber of seocndaryPhoneNumbersToPickFrom) {
54
+ for (const secondaryPhoneNumber of secondaryPhoneNumbersToPickFrom) {
55
55
  const secondaryPhoneNumberCountryCode: string = normalizePhoneNumber(
56
56
  secondaryPhoneNumber,
57
57
  ).substring(0, 2);
@@ -148,4 +148,53 @@ export default class Phone extends DatabaseProperty {
148
148
  example: { _type: ObjectType.Phone, value: "+1-555-123-4567" },
149
149
  });
150
150
  }
151
+
152
+ // Map of calling code prefixes to ISO country codes
153
+ private static readonly CALLING_CODE_TO_COUNTRY_MAP: Record<string, string> =
154
+ {
155
+ "+1": "US", // US and Canada
156
+ "+44": "GB", // United Kingdom
157
+ "+61": "AU", // Australia
158
+ "+49": "DE", // Germany
159
+ "+33": "FR", // France
160
+ "+91": "IN", // India
161
+ "+81": "JP", // Japan
162
+ "+86": "CN", // China
163
+ "+55": "BR", // Brazil
164
+ "+52": "MX", // Mexico
165
+ };
166
+
167
+ /**
168
+ * Extract ISO country code from a phone number
169
+ * @param phoneNumber - The phone number (e.g., "+15551234567")
170
+ * @returns ISO country code (e.g., "US") or "US" as default
171
+ */
172
+ public static getCountryCodeFromPhoneNumber(phoneNumber: string): string {
173
+ for (const [prefix, countryCode] of Object.entries(
174
+ Phone.CALLING_CODE_TO_COUNTRY_MAP,
175
+ )) {
176
+ if (phoneNumber.startsWith(prefix)) {
177
+ return countryCode;
178
+ }
179
+ }
180
+ return "US"; // Default to US if unknown
181
+ }
182
+
183
+ /**
184
+ * Extract area code from a phone number
185
+ * Currently only supports US/Canada (+1) numbers
186
+ * @param phoneNumber - The phone number (e.g., "+15551234567")
187
+ * @returns Area code (e.g., "555") or empty string for non-US/CA numbers
188
+ */
189
+ public static getAreaCodeFromPhoneNumber(phoneNumber: string): string {
190
+ // For US/Canada numbers (+1), extract the next 3 digits
191
+ if (phoneNumber.startsWith("+1")) {
192
+ const number: string = phoneNumber.substring(2);
193
+ if (number.length >= 3) {
194
+ return number.substring(0, 3);
195
+ }
196
+ }
197
+ // For other countries, area code extraction is more complex
198
+ return "";
199
+ }
151
200
  }
@@ -0,0 +1,7 @@
1
+ enum SCIMLogStatus {
2
+ Success = "Success",
3
+ Error = "Error",
4
+ Warning = "Warning",
5
+ }
6
+
7
+ export default SCIMLogStatus;