@oneuptime/common 10.2.1 → 10.2.3

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 (77) hide show
  1. package/Models/DatabaseModels/Index.ts +6 -0
  2. package/Models/DatabaseModels/ProjectOidc.ts +705 -0
  3. package/Models/DatabaseModels/UserNotificationRule.ts +49 -0
  4. package/Models/DatabaseModels/UserNotificationSetting.ts +17 -0
  5. package/Models/DatabaseModels/UserOnCallLogTimeline.ts +48 -0
  6. package/Models/DatabaseModels/UserWebhook.ts +290 -0
  7. package/Models/DatabaseModels/WebhookLog.ts +992 -0
  8. package/Server/API/ProjectOIDC.ts +73 -0
  9. package/Server/API/UserWebhookAPI.ts +159 -0
  10. package/Server/Infrastructure/Postgres/SchemaMigrations/1778506655291-AddProjectOIDC.ts +79 -0
  11. package/Server/Infrastructure/Postgres/SchemaMigrations/1778514515756-MigrationName.ts +259 -0
  12. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
  13. package/Server/Services/Index.ts +2 -0
  14. package/Server/Services/OnCallDutyPolicyScheduleService.ts +139 -26
  15. package/Server/Services/ProjectOidcService.ts +10 -0
  16. package/Server/Services/UserNotificationRuleService.ts +213 -1
  17. package/Server/Services/UserNotificationSettingService.ts +95 -0
  18. package/Server/Services/UserWebhookService.ts +208 -0
  19. package/Server/Services/WebhookLogService.ts +15 -0
  20. package/Server/Services/WebhookService.ts +126 -0
  21. package/Types/OnCallDutyPolicy/UserOverrideUtil.ts +155 -0
  22. package/Types/Permission.ts +54 -0
  23. package/Types/Webhook/WebhookMessage.ts +8 -0
  24. package/Types/WebhookStatus.ts +6 -0
  25. package/UI/Components/Calendar/Calendar.css +257 -0
  26. package/UI/Components/Calendar/Calendar.tsx +22 -11
  27. package/build/dist/Models/DatabaseModels/Index.js +6 -0
  28. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  29. package/build/dist/Models/DatabaseModels/ProjectOidc.js +727 -0
  30. package/build/dist/Models/DatabaseModels/ProjectOidc.js.map +1 -0
  31. package/build/dist/Models/DatabaseModels/UserNotificationRule.js +49 -0
  32. package/build/dist/Models/DatabaseModels/UserNotificationRule.js.map +1 -1
  33. package/build/dist/Models/DatabaseModels/UserNotificationSetting.js +19 -0
  34. package/build/dist/Models/DatabaseModels/UserNotificationSetting.js.map +1 -1
  35. package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js +48 -0
  36. package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js.map +1 -1
  37. package/build/dist/Models/DatabaseModels/UserWebhook.js +307 -0
  38. package/build/dist/Models/DatabaseModels/UserWebhook.js.map +1 -0
  39. package/build/dist/Models/DatabaseModels/WebhookLog.js +1021 -0
  40. package/build/dist/Models/DatabaseModels/WebhookLog.js.map +1 -0
  41. package/build/dist/Server/API/ProjectOIDC.js +45 -0
  42. package/build/dist/Server/API/ProjectOIDC.js.map +1 -0
  43. package/build/dist/Server/API/UserWebhookAPI.js +99 -0
  44. package/build/dist/Server/API/UserWebhookAPI.js.map +1 -0
  45. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1778506655291-AddProjectOIDC.js +34 -0
  46. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1778506655291-AddProjectOIDC.js.map +1 -0
  47. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1778514515756-MigrationName.js +94 -0
  48. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1778514515756-MigrationName.js.map +1 -0
  49. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
  50. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  51. package/build/dist/Server/Services/Index.js +2 -0
  52. package/build/dist/Server/Services/Index.js.map +1 -1
  53. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +106 -17
  54. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
  55. package/build/dist/Server/Services/ProjectOidcService.js +9 -0
  56. package/build/dist/Server/Services/ProjectOidcService.js.map +1 -0
  57. package/build/dist/Server/Services/UserNotificationRuleService.js +178 -21
  58. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  59. package/build/dist/Server/Services/UserNotificationSettingService.js +84 -1
  60. package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
  61. package/build/dist/Server/Services/UserWebhookService.js +190 -0
  62. package/build/dist/Server/Services/UserWebhookService.js.map +1 -0
  63. package/build/dist/Server/Services/WebhookLogService.js +13 -0
  64. package/build/dist/Server/Services/WebhookLogService.js.map +1 -0
  65. package/build/dist/Server/Services/WebhookService.js +92 -0
  66. package/build/dist/Server/Services/WebhookService.js.map +1 -0
  67. package/build/dist/Types/OnCallDutyPolicy/UserOverrideUtil.js +86 -0
  68. package/build/dist/Types/OnCallDutyPolicy/UserOverrideUtil.js.map +1 -0
  69. package/build/dist/Types/Permission.js +50 -0
  70. package/build/dist/Types/Permission.js.map +1 -1
  71. package/build/dist/Types/Webhook/WebhookMessage.js +2 -0
  72. package/build/dist/Types/Webhook/WebhookMessage.js.map +1 -0
  73. package/build/dist/Types/WebhookStatus.js +7 -0
  74. package/build/dist/Types/WebhookStatus.js.map +1 -0
  75. package/build/dist/UI/Components/Calendar/Calendar.js +12 -10
  76. package/build/dist/UI/Components/Calendar/Calendar.js.map +1 -1
  77. package/package.json +1 -1
@@ -0,0 +1,208 @@
1
+ import CreateBy from "../Types/Database/CreateBy";
2
+ import DeleteBy from "../Types/Database/DeleteBy";
3
+ import { OnCreate, OnDelete } from "../Types/Database/Hooks";
4
+ import DatabaseService from "./DatabaseService";
5
+ import UserNotificationRuleService from "./UserNotificationRuleService";
6
+ import LIMIT_MAX from "../../Types/Database/LimitMax";
7
+ import BadDataException from "../../Types/Exception/BadDataException";
8
+ import Model from "../../Models/DatabaseModels/UserWebhook";
9
+ import URL from "../../Types/API/URL";
10
+ import logger from "../Utils/Logger";
11
+ import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
12
+
13
+ export class Service extends DatabaseService<Model> {
14
+ public constructor() {
15
+ super(Model);
16
+ }
17
+
18
+ @CaptureSpan()
19
+ protected override async onBeforeCreate(
20
+ createBy: CreateBy<Model>,
21
+ ): Promise<OnCreate<Model>> {
22
+ if (!createBy.data.webhookUrl) {
23
+ throw new BadDataException("Webhook URL is required");
24
+ }
25
+
26
+ if (!createBy.data.name) {
27
+ throw new BadDataException("Webhook name is required");
28
+ }
29
+
30
+ this.validateWebhookUrl(createBy.data.webhookUrl);
31
+
32
+ return {
33
+ createBy,
34
+ carryForward: null,
35
+ };
36
+ }
37
+
38
+ @CaptureSpan()
39
+ protected override async onCreateSuccess(
40
+ _onCreate: OnCreate<Model>,
41
+ createdItem: Model,
42
+ ): Promise<Model> {
43
+ /* Webhooks skip verification, so default on-call rules are seeded at create time. */
44
+ if (createdItem.projectId && createdItem.userId && createdItem.id) {
45
+ try {
46
+ await UserNotificationRuleService.addDefaultNotificationRulesForVerifiedMethod(
47
+ {
48
+ projectId: createdItem.projectId,
49
+ userId: createdItem.userId,
50
+ notificationMethod: {
51
+ userWebhookId: createdItem.id,
52
+ },
53
+ },
54
+ );
55
+ } catch (err) {
56
+ logger.error(err);
57
+ }
58
+ }
59
+
60
+ return createdItem;
61
+ }
62
+
63
+ @CaptureSpan()
64
+ protected override async onBeforeDelete(
65
+ deleteBy: DeleteBy<Model>,
66
+ ): Promise<OnDelete<Model>> {
67
+ const itemsToDelete: Array<Model> = await this.findBy({
68
+ query: deleteBy.query,
69
+ select: {
70
+ _id: true,
71
+ projectId: true,
72
+ },
73
+ skip: 0,
74
+ limit: LIMIT_MAX,
75
+ props: {
76
+ isRoot: true,
77
+ },
78
+ });
79
+
80
+ for (const item of itemsToDelete) {
81
+ await UserNotificationRuleService.deleteBy({
82
+ query: {
83
+ userWebhookId: item.id!,
84
+ projectId: item.projectId!,
85
+ },
86
+ limit: LIMIT_MAX,
87
+ skip: 0,
88
+ props: {
89
+ isRoot: true,
90
+ },
91
+ });
92
+ }
93
+
94
+ return {
95
+ deleteBy,
96
+ carryForward: null,
97
+ };
98
+ }
99
+
100
+ private validateWebhookUrl(rawUrl: string): void {
101
+ let parsed: URL;
102
+ try {
103
+ parsed = URL.fromString(rawUrl);
104
+ } catch {
105
+ throw new BadDataException("Webhook URL is not a valid URL");
106
+ }
107
+
108
+ const protocolValue: string = parsed.protocol.toString().toLowerCase();
109
+ if (protocolValue !== "http://" && protocolValue !== "https://") {
110
+ throw new BadDataException(
111
+ "Webhook URL must use http or https protocol.",
112
+ );
113
+ }
114
+
115
+ const hostname: string = parsed.hostname.hostname.toLowerCase();
116
+
117
+ if (!hostname) {
118
+ throw new BadDataException("Webhook URL must include a host.");
119
+ }
120
+
121
+ if (isBlockedHostnameLiteral(hostname)) {
122
+ throw new BadDataException(
123
+ "Webhook URL points to a private, loopback, or link-local address and is not allowed.",
124
+ );
125
+ }
126
+ }
127
+ }
128
+
129
+ function isBlockedHostnameLiteral(hostname: string): boolean {
130
+ if (
131
+ hostname === "localhost" ||
132
+ hostname.endsWith(".localhost") ||
133
+ hostname === "metadata.google.internal"
134
+ ) {
135
+ return true;
136
+ }
137
+
138
+ // IPv4 literal check
139
+ const ipv4Match: RegExpMatchArray | null = hostname.match(
140
+ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/,
141
+ );
142
+ if (ipv4Match) {
143
+ const octets: Array<number> = [
144
+ Number(ipv4Match[1]),
145
+ Number(ipv4Match[2]),
146
+ Number(ipv4Match[3]),
147
+ Number(ipv4Match[4]),
148
+ ];
149
+
150
+ if (
151
+ octets.some((o: number) => {
152
+ return o < 0 || o > 255;
153
+ })
154
+ ) {
155
+ return true;
156
+ }
157
+
158
+ // 0.0.0.0/8
159
+ if (octets[0] === 0) {
160
+ return true;
161
+ }
162
+ // 127.0.0.0/8 loopback
163
+ if (octets[0] === 127) {
164
+ return true;
165
+ }
166
+ // 10.0.0.0/8
167
+ if (octets[0] === 10) {
168
+ return true;
169
+ }
170
+ // 172.16.0.0/12
171
+ if (octets[0] === 172 && (octets[1]! & 0xf0) === 16) {
172
+ return true;
173
+ }
174
+ // 192.168.0.0/16
175
+ if (octets[0] === 192 && octets[1] === 168) {
176
+ return true;
177
+ }
178
+ // 169.254.0.0/16 link-local (incl. cloud metadata)
179
+ if (octets[0] === 169 && octets[1] === 254) {
180
+ return true;
181
+ }
182
+ // 100.64.0.0/10 carrier-grade NAT
183
+ if (octets[0] === 100 && (octets[1]! & 0xc0) === 64) {
184
+ return true;
185
+ }
186
+ return false;
187
+ }
188
+
189
+ // IPv6 literal — block loopback, link-local, unique-local
190
+ if (hostname.includes(":")) {
191
+ const stripped: string = hostname.replace(/^\[|\]$/g, "");
192
+ if (stripped === "::1" || stripped === "::") {
193
+ return true;
194
+ }
195
+ if (stripped.startsWith("fe80:") || stripped.startsWith("fe80::")) {
196
+ return true;
197
+ }
198
+ if (IPV6_UNIQUE_LOCAL_REGEX.test(stripped)) {
199
+ return true;
200
+ }
201
+ }
202
+
203
+ return false;
204
+ }
205
+
206
+ const IPV6_UNIQUE_LOCAL_REGEX: RegExp = /^f[cd][0-9a-f]{2}:/;
207
+
208
+ export default new Service();
@@ -0,0 +1,15 @@
1
+ import { IsBillingEnabled } from "../EnvironmentConfig";
2
+ import DatabaseService from "./DatabaseService";
3
+ import Model from "../../Models/DatabaseModels/WebhookLog";
4
+
5
+ export class Service extends DatabaseService<Model> {
6
+ public constructor() {
7
+ super(Model);
8
+
9
+ if (IsBillingEnabled) {
10
+ this.hardDeleteItemsOlderThanInDays("createdAt", 3);
11
+ }
12
+ }
13
+ }
14
+
15
+ export default new Service();
@@ -0,0 +1,126 @@
1
+ import { AppApiHostname } from "../EnvironmentConfig";
2
+ import ClusterKeyAuthorization from "../Middleware/ClusterKeyAuthorization";
3
+ import BaseService from "./BaseService";
4
+ import EmptyResponseData from "../../Types/API/EmptyResponse";
5
+ import HTTPResponse from "../../Types/API/HTTPResponse";
6
+ import HTTPErrorResponse from "../../Types/API/HTTPErrorResponse";
7
+ import Protocol from "../../Types/API/Protocol";
8
+ import Route from "../../Types/API/Route";
9
+ import URL from "../../Types/API/URL";
10
+ import { JSONObject } from "../../Types/JSON";
11
+ import ObjectID from "../../Types/ObjectID";
12
+ import WebhookMessage from "../../Types/Webhook/WebhookMessage";
13
+ import API from "../../Utils/API";
14
+ import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
15
+
16
+ export class WebhookService extends BaseService {
17
+ public constructor() {
18
+ super();
19
+ }
20
+
21
+ @CaptureSpan()
22
+ public async sendWebhook(
23
+ message: WebhookMessage,
24
+ options: {
25
+ projectId?: ObjectID | undefined;
26
+ userOnCallLogTimelineId?: ObjectID | undefined;
27
+ incidentId?: ObjectID | undefined;
28
+ alertId?: ObjectID | undefined;
29
+ monitorId?: ObjectID | undefined;
30
+ scheduledMaintenanceId?: ObjectID | undefined;
31
+ statusPageId?: ObjectID | undefined;
32
+ statusPageAnnouncementId?: ObjectID | undefined;
33
+ userId?: ObjectID | undefined;
34
+ onCallPolicyId?: ObjectID | undefined;
35
+ onCallPolicyEscalationRuleId?: ObjectID | undefined;
36
+ onCallDutyPolicyExecutionLogTimelineId?: ObjectID | undefined;
37
+ onCallScheduleId?: ObjectID | undefined;
38
+ teamId?: ObjectID | undefined;
39
+ } = {},
40
+ ): Promise<HTTPResponse<EmptyResponseData> | HTTPErrorResponse> {
41
+ const body: JSONObject = {
42
+ url: message.url,
43
+ eventType: message.eventType,
44
+ payload: message.payload,
45
+ };
46
+
47
+ if (message.secret) {
48
+ body["secret"] = message.secret;
49
+ }
50
+
51
+ if (options.projectId) {
52
+ body["projectId"] = options.projectId.toString();
53
+ }
54
+
55
+ if (options.userOnCallLogTimelineId) {
56
+ body["userOnCallLogTimelineId"] =
57
+ options.userOnCallLogTimelineId.toString();
58
+ }
59
+
60
+ if (options.incidentId) {
61
+ body["incidentId"] = options.incidentId.toString();
62
+ }
63
+
64
+ if (options.alertId) {
65
+ body["alertId"] = options.alertId.toString();
66
+ }
67
+
68
+ if (options.monitorId) {
69
+ body["monitorId"] = options.monitorId.toString();
70
+ }
71
+
72
+ if (options.scheduledMaintenanceId) {
73
+ body["scheduledMaintenanceId"] =
74
+ options.scheduledMaintenanceId.toString();
75
+ }
76
+
77
+ if (options.statusPageId) {
78
+ body["statusPageId"] = options.statusPageId.toString();
79
+ }
80
+
81
+ if (options.statusPageAnnouncementId) {
82
+ body["statusPageAnnouncementId"] =
83
+ options.statusPageAnnouncementId.toString();
84
+ }
85
+
86
+ if (options.userId) {
87
+ body["userId"] = options.userId.toString();
88
+ }
89
+
90
+ if (options.onCallPolicyId) {
91
+ body["onCallPolicyId"] = options.onCallPolicyId.toString();
92
+ }
93
+
94
+ if (options.onCallPolicyEscalationRuleId) {
95
+ body["onCallPolicyEscalationRuleId"] =
96
+ options.onCallPolicyEscalationRuleId.toString();
97
+ }
98
+
99
+ if (options.onCallDutyPolicyExecutionLogTimelineId) {
100
+ body["onCallDutyPolicyExecutionLogTimelineId"] =
101
+ options.onCallDutyPolicyExecutionLogTimelineId.toString();
102
+ }
103
+
104
+ if (options.onCallScheduleId) {
105
+ body["onCallScheduleId"] = options.onCallScheduleId.toString();
106
+ }
107
+
108
+ if (options.teamId) {
109
+ body["teamId"] = options.teamId.toString();
110
+ }
111
+
112
+ return await API.post<EmptyResponseData>({
113
+ url: new URL(
114
+ Protocol.HTTP,
115
+ AppApiHostname,
116
+ new Route("/api/notification/webhook/send"),
117
+ ),
118
+ data: body,
119
+ headers: {
120
+ ...ClusterKeyAuthorization.getClusterKeyHeaders(),
121
+ },
122
+ });
123
+ }
124
+ }
125
+
126
+ export default new WebhookService();
@@ -0,0 +1,155 @@
1
+ import CalendarEvent from "../Calendar/CalendarEvent";
2
+ import OneUptimeDate from "../Date";
3
+
4
+ export interface UserOverrideRecord {
5
+ overrideUserId: string;
6
+ routeAlertsToUserId: string;
7
+ startsAt: Date;
8
+ endsAt: Date;
9
+ // null/undefined means global override (applies to all on-call duty policies)
10
+ onCallDutyPolicyId?: string | null | undefined;
11
+ }
12
+
13
+ export interface OverrideEventMeta {
14
+ isOverride: true;
15
+ originalUserId: string;
16
+ overrideUserId: string;
17
+ overrideStartsAt: Date;
18
+ overrideEndsAt: Date;
19
+ }
20
+
21
+ /*
22
+ * CalendarEvent extends JSONObject so it accepts string-indexed metadata.
23
+ * We attach the override info under a known key so downstream consumers can
24
+ * detect and render the substitution distinctly.
25
+ */
26
+ export const OVERRIDE_META_KEY: string = "_override";
27
+
28
+ export default class UserOverrideUtil {
29
+ /**
30
+ * Returns true when this override should be applied on top of the schedule
31
+ * events. Global overrides always apply; policy-scoped overrides apply to
32
+ * any schedule, since a schedule's calendar shows coverage information for
33
+ * every user who could potentially be paged through it.
34
+ */
35
+ public static isOverrideApplicable(_override: UserOverrideRecord): boolean {
36
+ return true;
37
+ }
38
+
39
+ public static applyOverridesToEvents(data: {
40
+ events: Array<CalendarEvent>;
41
+ overrides: Array<UserOverrideRecord>;
42
+ }): Array<CalendarEvent> {
43
+ const applicable: Array<UserOverrideRecord> = data.overrides.filter(
44
+ UserOverrideUtil.isOverrideApplicable,
45
+ );
46
+
47
+ if (applicable.length === 0) {
48
+ return data.events;
49
+ }
50
+
51
+ let working: Array<CalendarEvent> = data.events;
52
+
53
+ for (const override of applicable) {
54
+ const next: Array<CalendarEvent> = [];
55
+ for (const event of working) {
56
+ next.push(...UserOverrideUtil.splitEventByOverride(event, override));
57
+ }
58
+ working = next;
59
+ }
60
+
61
+ return UserOverrideUtil.reassignEventIds(working);
62
+ }
63
+
64
+ private static splitEventByOverride(
65
+ event: CalendarEvent,
66
+ override: UserOverrideRecord,
67
+ ): Array<CalendarEvent> {
68
+ if (event.title !== override.overrideUserId) {
69
+ return [event];
70
+ }
71
+
72
+ // Override window doesn't overlap event window at all.
73
+ if (
74
+ OneUptimeDate.isAfter(override.startsAt, event.end) ||
75
+ OneUptimeDate.isSame(override.startsAt, event.end) ||
76
+ OneUptimeDate.isBefore(override.endsAt, event.start) ||
77
+ OneUptimeDate.isSame(override.endsAt, event.start)
78
+ ) {
79
+ return [event];
80
+ }
81
+
82
+ const overrideStart: Date = OneUptimeDate.isAfter(
83
+ override.startsAt,
84
+ event.start,
85
+ )
86
+ ? override.startsAt
87
+ : event.start;
88
+
89
+ const overrideEnd: Date = OneUptimeDate.isBefore(override.endsAt, event.end)
90
+ ? override.endsAt
91
+ : event.end;
92
+
93
+ const segments: Array<CalendarEvent> = [];
94
+
95
+ // Segment before the override window — original user remains on call.
96
+ if (OneUptimeDate.isBefore(event.start, overrideStart)) {
97
+ segments.push({
98
+ ...event,
99
+ end: overrideStart,
100
+ });
101
+ }
102
+
103
+ // Override window — substitute user takes over.
104
+ const meta: OverrideEventMeta = {
105
+ isOverride: true,
106
+ originalUserId: override.overrideUserId,
107
+ overrideUserId: override.routeAlertsToUserId,
108
+ overrideStartsAt: override.startsAt,
109
+ overrideEndsAt: override.endsAt,
110
+ };
111
+
112
+ segments.push({
113
+ ...event,
114
+ start: overrideStart,
115
+ end: overrideEnd,
116
+ title: override.routeAlertsToUserId,
117
+ [OVERRIDE_META_KEY]: meta as unknown as never,
118
+ });
119
+
120
+ // Segment after the override window — original user resumes.
121
+ if (OneUptimeDate.isAfter(event.end, overrideEnd)) {
122
+ segments.push({
123
+ ...event,
124
+ start: overrideEnd,
125
+ });
126
+ }
127
+
128
+ return segments;
129
+ }
130
+
131
+ private static reassignEventIds(
132
+ events: Array<CalendarEvent>,
133
+ ): Array<CalendarEvent> {
134
+ let id: number = 1;
135
+ return events.map((event: CalendarEvent) => {
136
+ return { ...event, id: id++ };
137
+ });
138
+ }
139
+
140
+ public static getOverrideMeta(
141
+ event: CalendarEvent,
142
+ ): OverrideEventMeta | null {
143
+ const meta: unknown = (event as unknown as Record<string, unknown>)[
144
+ OVERRIDE_META_KEY
145
+ ];
146
+ if (
147
+ meta &&
148
+ typeof meta === "object" &&
149
+ (meta as { isOverride?: boolean }).isOverride === true
150
+ ) {
151
+ return meta as OverrideEventMeta;
152
+ }
153
+ return null;
154
+ }
155
+ }
@@ -275,6 +275,7 @@ enum Permission {
275
275
  ReadEmailLog = "ReadEmailLog",
276
276
  ReadCallLog = "ReadCallLog",
277
277
  ReadPushLog = "ReadPushLog",
278
+ ReadWebhookLog = "ReadWebhookLog",
278
279
  ReadWorkspaceNotificationLog = "ReadWorkspaceNotificationLog",
279
280
  ReadLlmLog = "ReadLlmLog",
280
281
 
@@ -527,6 +528,11 @@ enum Permission {
527
528
  EditProjectSSO = "EditProjectSSO",
528
529
  ReadProjectSSO = "ReadProjectSSO",
529
530
 
531
+ CreateProjectOIDC = "CreateProjectOIDC",
532
+ DeleteProjectOIDC = "DeleteProjectOIDC",
533
+ EditProjectOIDC = "EditProjectOIDC",
534
+ ReadProjectOIDC = "ReadProjectOIDC",
535
+
530
536
  CreateStatusPageSSO = "CreateStatusPageSSO",
531
537
  DeleteStatusPageSSO = "DeleteStatusPageSSO",
532
538
  EditStatusPageSSO = "EditStatusPageSSO",
@@ -2949,6 +2955,43 @@ export class PermissionHelper {
2949
2955
  group: PermissionGroup.Settings,
2950
2956
  },
2951
2957
 
2958
+ {
2959
+ permission: Permission.CreateProjectOIDC,
2960
+ title: "Create Project OIDC",
2961
+ description: "This permission can create Project OIDC in this project.",
2962
+ isAssignableToTenant: true,
2963
+ isAccessControlPermission: false,
2964
+ isRolePermission: false,
2965
+ group: PermissionGroup.Settings,
2966
+ },
2967
+ {
2968
+ permission: Permission.DeleteProjectOIDC,
2969
+ title: "Delete Project OIDC",
2970
+ description: "This permission can delete Project OIDC in this project.",
2971
+ isAssignableToTenant: true,
2972
+ isAccessControlPermission: false,
2973
+ isRolePermission: false,
2974
+ group: PermissionGroup.Settings,
2975
+ },
2976
+ {
2977
+ permission: Permission.EditProjectOIDC,
2978
+ title: "Edit Project OIDC",
2979
+ description: "This permission can edit Project OIDC in this project.",
2980
+ isAssignableToTenant: true,
2981
+ isAccessControlPermission: false,
2982
+ isRolePermission: false,
2983
+ group: PermissionGroup.Settings,
2984
+ },
2985
+ {
2986
+ permission: Permission.ReadProjectOIDC,
2987
+ title: "Read Project OIDC",
2988
+ description: "This permission can read Project OIDC in this project.",
2989
+ isAssignableToTenant: true,
2990
+ isAccessControlPermission: false,
2991
+ isRolePermission: false,
2992
+ group: PermissionGroup.Settings,
2993
+ },
2994
+
2952
2995
  {
2953
2996
  permission: Permission.CreateStatusPageSSO,
2954
2997
  title: "Create Status Page SSO",
@@ -4718,6 +4761,17 @@ export class PermissionHelper {
4718
4761
  group: PermissionGroup.NotificationLog,
4719
4762
  },
4720
4763
 
4764
+ {
4765
+ permission: Permission.ReadWebhookLog,
4766
+ title: "Read Webhook Log",
4767
+ description:
4768
+ "This permission can read outbound Webhook request Logs of this project.",
4769
+ isAssignableToTenant: true,
4770
+ isAccessControlPermission: false,
4771
+ isRolePermission: false,
4772
+ group: PermissionGroup.NotificationLog,
4773
+ },
4774
+
4721
4775
  {
4722
4776
  permission: Permission.ReadWorkspaceNotificationLog,
4723
4777
  title: "Read Workspace Notification Log",
@@ -0,0 +1,8 @@
1
+ import { JSONObject } from "../JSON";
2
+
3
+ export default interface WebhookMessage {
4
+ url: string;
5
+ eventType: string;
6
+ payload: JSONObject;
7
+ secret?: string | undefined;
8
+ }
@@ -0,0 +1,6 @@
1
+ enum WebhookStatus {
2
+ Success = "Success",
3
+ Error = "Error",
4
+ }
5
+
6
+ export default WebhookStatus;