@oneuptime/common 11.3.26 → 11.3.28
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.
- package/Models/DatabaseModels/IncidentEpisodeRoleMember.ts +1 -1
- package/Models/DatabaseModels/IncidentMember.ts +1 -1
- package/Models/DatabaseModels/IncomingCallPolicy.ts +13 -0
- package/Models/DatabaseModels/Index.ts +3 -0
- package/Models/DatabaseModels/MigrationFailure.ts +170 -0
- package/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.ts +51 -2
- package/Models/DatabaseModels/OnCallDutyPolicySchedule.ts +44 -0
- package/Models/DatabaseModels/OnCallDutyPolicyScheduleLayer.ts +6 -0
- package/Models/DatabaseModels/OnCallDutyPolicyScheduleLayerUser.ts +6 -0
- package/Models/DatabaseModels/OnCallDutyPolicyTimeLog.ts +1 -1
- package/Models/DatabaseModels/OnCallDutyPolicyUserOverride.ts +2 -2
- package/Server/API/AlertAPI.ts +1 -1
- package/Server/API/IncidentAPI.ts +2 -2
- package/Server/API/IncidentEpisodeAPI.ts +1 -1
- package/Server/API/LlmProviderAPI.ts +1 -0
- package/Server/API/ScheduledMaintenanceAPI.ts +1 -1
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783470000000-AddIncomingCallPolicyRoutingPhoneNumberUnique.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783510935686-FixNotNullForeignKeysOnDelete.ts +81 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783515836148-MigrationName.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783523076215-AddMigrationFailureTable.ts +35 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
- package/Server/Infrastructure/PostgresDatabase.ts +11 -0
- package/Server/Services/AIService.ts +74 -2
- package/Server/Services/AnalyticsDatabaseService.ts +10 -1
- package/Server/Services/DatabaseService.ts +10 -1
- package/Server/Services/IncidentService.ts +1 -1
- package/Server/Services/IncomingCallPolicyEscalationRuleService.ts +75 -2
- package/Server/Services/IncomingCallPolicyService.ts +42 -1
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/MigrationFailureService.ts +9 -0
- package/Server/Services/MonitorProbeService.ts +33 -7
- package/Server/Services/MonitorService.ts +19 -7
- package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +65 -0
- package/Server/Services/OnCallDutyPolicyEscalationRuleService.ts +185 -41
- package/Server/Services/OnCallDutyPolicyEscalationRuleUserService.ts +23 -15
- package/Server/Services/OnCallDutyPolicyExecutionLogService.ts +39 -0
- package/Server/Services/OnCallDutyPolicyScheduleLayerService.ts +148 -0
- package/Server/Services/OnCallDutyPolicyScheduleLayerUserService.ts +11 -2
- package/Server/Services/OnCallDutyPolicyScheduleService.ts +502 -26
- package/Server/Services/OnCallDutyPolicyTimeLogService.ts +49 -7
- package/Server/Services/OnCallDutyPolicyUserOverrideService.ts +218 -4
- package/Server/Services/ProjectCallSMSConfigService.ts +82 -1
- package/Server/Services/TeamMemberService.ts +6 -0
- package/Server/Services/UserNotificationRuleService.ts +13 -42
- package/Server/Services/UserOnCallLogService.ts +90 -0
- package/Server/Services/UserOnCallLogTimelineService.ts +43 -1
- package/Server/Types/Database/QueryUtil.ts +57 -0
- package/Server/Utils/AI/AlertAIContextBuilder.ts +6 -1
- package/Server/Utils/AI/Chat/ChatAgentRunner.ts +14 -2
- package/Server/Utils/AI/IncidentAIContextBuilder.ts +18 -3
- package/Server/Utils/AI/IncidentEpisodeAIContextBuilder.ts +6 -1
- package/Server/Utils/AI/ScheduledMaintenanceAIContextBuilder.ts +12 -2
- package/Server/Utils/AI/Toolbox/IncidentTools.ts +183 -1
- package/Server/Utils/AI/Toolbox/Index.ts +4 -1
- package/Server/Utils/AI/Toolbox/RecentChangesTools.ts +208 -0
- package/Server/Utils/AI/Toolbox/Serializer.ts +42 -0
- package/Server/Utils/Database/MigrationFailureLog.ts +240 -0
- package/Server/Utils/IncomingCallPhoneNumber.ts +41 -0
- package/Server/Utils/LLM/LLMService.ts +110 -11
- package/Server/Utils/Telemetry/IoTSnapshotScan.ts +12 -9
- package/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.ts +12 -9
- package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +0 -8
- package/Tests/Server/Services/OnCallDutyPolicyScheduleLayerUserReorder.test.ts +233 -0
- package/Tests/Server/Services/OnCallDutyPolicyTimeLogServiceScoping.test.ts +242 -0
- package/Tests/Server/Services/OnCallDutyPolicyUserOverrideEdit.test.ts +198 -0
- package/Tests/Server/Services/UserOnCallLogClaimNotificationRule.test.ts +495 -0
- package/Tests/Server/Types/Database/QueryUtil.test.ts +74 -0
- package/Tests/Server/Utils/AI/LLMServiceToolCalling.test.ts +78 -0
- package/Tests/Server/Utils/AI/ToolResultSerializer.test.ts +68 -0
- package/Tests/Types/DateExhaustiveTimezone.test.ts +700 -0
- package/Tests/Types/DateTimezoneWallClock.test.ts +99 -0
- package/Tests/Types/Events/Recurring.test.ts +22 -9
- package/Tests/Types/OnCallDutyPolicy/LayerUtilAuditFixes.test.ts +291 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilAuditFixesRound2.test.ts +398 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilDSTWeekendGap.test.ts +114 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilDSTWeeklyDayShift.test.ts +76 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilDailyMutation.test.ts +128 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilDailyProbe.test.ts +203 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilDiffFuzz.test.ts +322 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilEdgeCases.test.ts +280 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilExhaustiveCurrentUser.test.ts +863 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilExhaustiveDaily.test.ts +900 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilExhaustiveMultiLayer.test.ts +1104 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilExhaustiveRotation.test.ts +957 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilExhaustiveWeekly.test.ts +1095 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilInvariants.test.ts +232 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilMergeAudit.test.ts +227 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilMonthYearAudit.test.ts +255 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilMultiLayerAudit.test.ts +388 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilMultiLayerEdge.test.ts +300 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilOvernightDSTAudit.test.ts +158 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilRestrictedGapFix.test.ts +253 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilRestrictedGapRepro.test.ts +157 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilRotationFixes.test.ts +414 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilTimezone.test.ts +243 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilWeekendGapRepro.test.ts +112 -0
- package/Tests/Types/OnCallDutyPolicy/OverrideLensAudit.test.ts +117 -0
- package/Tests/Types/OnCallDutyPolicy/RestrictionTimes.test.ts +8 -6
- package/Tests/Types/OnCallDutyPolicy/RestrictionTimesDefaultDayAudit.test.ts +112 -0
- package/Tests/Types/OnCallDutyPolicy/RestrictionTimesExhaustive.test.ts +821 -0
- package/Tests/Types/OnCallDutyPolicy/RestrictionTimesMutationInvariant.test.ts +886 -0
- package/Tests/Types/OnCallDutyPolicy/UserOverrideUtil.test.ts +255 -0
- package/Tests/Types/OnCallDutyPolicy/UserOverrideUtilExhaustive.test.ts +1126 -0
- package/Types/Date.ts +200 -15
- package/Types/OnCallDutyPolicy/Layer.ts +790 -260
- package/Types/OnCallDutyPolicy/RestrictionTimes.ts +39 -13
- package/Types/OnCallDutyPolicy/UserOverrideUtil.ts +21 -5
- package/UI/Components/Events/RecurringFieldElement.tsx +16 -0
- package/UI/Components/ModelFormModal/ModelFormModal.tsx +8 -0
- package/UI/Components/RadioButtons/BasicRadioButtons.tsx +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisodeRoleMember.js +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisodeRoleMember.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentMember.js +1 -1
- package/build/dist/Models/DatabaseModels/IncidentMember.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncomingCallPolicy.js +10 -0
- package/build/dist/Models/DatabaseModels/IncomingCallPolicy.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MigrationFailure.js +196 -0
- package/build/dist/Models/DatabaseModels/MigrationFailure.js.map +1 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js +52 -2
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js +45 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleLayer.js +6 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleLayer.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleLayerUser.js +6 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleLayerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyTimeLog.js +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyTimeLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyUserOverride.js +2 -2
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyUserOverride.js.map +1 -1
- package/build/dist/Server/API/AlertAPI.js +1 -1
- package/build/dist/Server/API/IncidentAPI.js +2 -2
- package/build/dist/Server/API/IncidentEpisodeAPI.js +1 -1
- package/build/dist/Server/API/LlmProviderAPI.js +1 -0
- package/build/dist/Server/API/LlmProviderAPI.js.map +1 -1
- package/build/dist/Server/API/ScheduledMaintenanceAPI.js +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783470000000-AddIncomingCallPolicyRoutingPhoneNumberUnique.js +18 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783470000000-AddIncomingCallPolicyRoutingPhoneNumberUnique.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783510935686-FixNotNullForeignKeysOnDelete.js +38 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783510935686-FixNotNullForeignKeysOnDelete.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783515836148-MigrationName.js +16 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783515836148-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783523076215-AddMigrationFailureTable.js +18 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783523076215-AddMigrationFailureTable.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/PostgresDatabase.js +9 -0
- package/build/dist/Server/Infrastructure/PostgresDatabase.js.map +1 -1
- package/build/dist/Server/Services/AIService.js +53 -2
- package/build/dist/Server/Services/AIService.js.map +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +10 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +10 -1
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +1 -1
- package/build/dist/Server/Services/IncomingCallPolicyEscalationRuleService.js +55 -2
- package/build/dist/Server/Services/IncomingCallPolicyEscalationRuleService.js.map +1 -1
- package/build/dist/Server/Services/IncomingCallPolicyService.js +40 -0
- package/build/dist/Server/Services/IncomingCallPolicyService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +2 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/MigrationFailureService.js +9 -0
- package/build/dist/Server/Services/MigrationFailureService.js.map +1 -0
- package/build/dist/Server/Services/MonitorProbeService.js +33 -7
- package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +12 -5
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +81 -22
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js +134 -31
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js +21 -13
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js +36 -0
- package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerService.js +121 -0
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerUserService.js +11 -2
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerUserService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +409 -36
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyTimeLogService.js +52 -8
- package/build/dist/Server/Services/OnCallDutyPolicyTimeLogService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyUserOverrideService.js +170 -3
- package/build/dist/Server/Services/OnCallDutyPolicyUserOverrideService.js.map +1 -1
- package/build/dist/Server/Services/ProjectCallSMSConfigService.js +72 -0
- package/build/dist/Server/Services/ProjectCallSMSConfigService.js.map +1 -1
- package/build/dist/Server/Services/TeamMemberService.js +6 -0
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationRuleService.js +12 -30
- package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Services/UserOnCallLogService.js +75 -0
- package/build/dist/Server/Services/UserOnCallLogService.js.map +1 -1
- package/build/dist/Server/Services/UserOnCallLogTimelineService.js +31 -1
- package/build/dist/Server/Services/UserOnCallLogTimelineService.js.map +1 -1
- package/build/dist/Server/Types/Database/QueryUtil.js +45 -0
- package/build/dist/Server/Types/Database/QueryUtil.js.map +1 -1
- package/build/dist/Server/Utils/AI/AlertAIContextBuilder.js +6 -1
- package/build/dist/Server/Utils/AI/AlertAIContextBuilder.js.map +1 -1
- package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js +13 -2
- package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/IncidentAIContextBuilder.js +18 -3
- package/build/dist/Server/Utils/AI/IncidentAIContextBuilder.js.map +1 -1
- package/build/dist/Server/Utils/AI/IncidentEpisodeAIContextBuilder.js +6 -1
- package/build/dist/Server/Utils/AI/IncidentEpisodeAIContextBuilder.js.map +1 -1
- package/build/dist/Server/Utils/AI/ScheduledMaintenanceAIContextBuilder.js +12 -2
- package/build/dist/Server/Utils/AI/ScheduledMaintenanceAIContextBuilder.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/IncidentTools.js +152 -1
- package/build/dist/Server/Utils/AI/Toolbox/IncidentTools.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/Index.js +4 -1
- package/build/dist/Server/Utils/AI/Toolbox/Index.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/RecentChangesTools.js +165 -0
- package/build/dist/Server/Utils/AI/Toolbox/RecentChangesTools.js.map +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/Serializer.js +40 -0
- package/build/dist/Server/Utils/AI/Toolbox/Serializer.js.map +1 -1
- package/build/dist/Server/Utils/Database/MigrationFailureLog.js +174 -0
- package/build/dist/Server/Utils/Database/MigrationFailureLog.js.map +1 -0
- package/build/dist/Server/Utils/IncomingCallPhoneNumber.js +30 -0
- package/build/dist/Server/Utils/IncomingCallPhoneNumber.js.map +1 -0
- package/build/dist/Server/Utils/LLM/LLMService.js +81 -5
- package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/IoTSnapshotScan.js +11 -8
- package/build/dist/Server/Utils/Telemetry/IoTSnapshotScan.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.js +11 -8
- package/build/dist/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.js.map +1 -1
- package/build/dist/Types/Date.js +153 -15
- package/build/dist/Types/Date.js.map +1 -1
- package/build/dist/Types/OnCallDutyPolicy/Layer.js +602 -171
- package/build/dist/Types/OnCallDutyPolicy/Layer.js.map +1 -1
- package/build/dist/Types/OnCallDutyPolicy/RestrictionTimes.js +27 -13
- package/build/dist/Types/OnCallDutyPolicy/RestrictionTimes.js.map +1 -1
- package/build/dist/Types/OnCallDutyPolicy/UserOverrideUtil.js +20 -5
- package/build/dist/Types/OnCallDutyPolicy/UserOverrideUtil.js.map +1 -1
- package/build/dist/UI/Components/Events/RecurringFieldElement.js +13 -0
- package/build/dist/UI/Components/Events/RecurringFieldElement.js.map +1 -1
- package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
- package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js +1 -1
- package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import Monitor from "../../../../Models/DatabaseModels/Monitor";
|
|
2
|
+
import MonitorStatusTimeline from "../../../../Models/DatabaseModels/MonitorStatusTimeline";
|
|
3
|
+
import ScheduledMaintenance from "../../../../Models/DatabaseModels/ScheduledMaintenance";
|
|
4
|
+
import TelemetryException from "../../../../Models/DatabaseModels/TelemetryException";
|
|
5
|
+
import { JSONObject } from "../../../../Types/JSON";
|
|
6
|
+
import Permission from "../../../../Types/Permission";
|
|
7
|
+
import SortOrder from "../../../../Types/BaseDatabase/SortOrder";
|
|
8
|
+
import MonitorStatusTimelineService from "../../../Services/MonitorStatusTimelineService";
|
|
9
|
+
import ScheduledMaintenanceService from "../../../Services/ScheduledMaintenanceService";
|
|
10
|
+
import TelemetryExceptionService from "../../../Services/TelemetryExceptionService";
|
|
11
|
+
import QueryHelper from "../../../Types/Database/QueryHelper";
|
|
12
|
+
import logger from "../../Logger";
|
|
13
|
+
import ToolResultSerializer, { SerializedResult } from "./Serializer";
|
|
14
|
+
import {
|
|
15
|
+
ObservabilityTool,
|
|
16
|
+
ToolArgs,
|
|
17
|
+
ToolContext,
|
|
18
|
+
ToolExecutionResult,
|
|
19
|
+
TimeRangeSchemaProperties,
|
|
20
|
+
} from "./ToolTypes";
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
* Gate on Monitor read permissions. This is defense-in-depth only: every
|
|
24
|
+
* source query below runs under the requesting user's props, so a user who
|
|
25
|
+
* cannot see monitors / exceptions / maintenance simply gets no rows from that
|
|
26
|
+
* source — never another user's data. Resolved lazily to avoid the
|
|
27
|
+
* import-time circular-dependency TypeError other tools document.
|
|
28
|
+
*/
|
|
29
|
+
let cachedReadPermissions: Array<Permission> | null = null;
|
|
30
|
+
const resolveReadPermissions: () => Array<Permission> =
|
|
31
|
+
(): Array<Permission> => {
|
|
32
|
+
if (!cachedReadPermissions) {
|
|
33
|
+
cachedReadPermissions = new Monitor().getReadPermissions();
|
|
34
|
+
}
|
|
35
|
+
return cachedReadPermissions;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// One normalized entry in the merged "what changed" feed.
|
|
39
|
+
interface ChangeEvent {
|
|
40
|
+
at: Date;
|
|
41
|
+
change: string;
|
|
42
|
+
detail: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const RecentChangesTool: ObservabilityTool = {
|
|
46
|
+
name: "recent_changes",
|
|
47
|
+
description:
|
|
48
|
+
"Get a single chronological feed of what changed in a time window: newly-seen exceptions, monitor status changes (up/down), and scheduled maintenance overlapping the window. This is the highest-yield way to answer 'what changed right before this started?' during root-cause analysis — call it with the window around when a problem began.",
|
|
49
|
+
inputSchema: {
|
|
50
|
+
type: "object",
|
|
51
|
+
properties: {
|
|
52
|
+
...TimeRangeSchemaProperties,
|
|
53
|
+
limitPerSource: {
|
|
54
|
+
type: "number",
|
|
55
|
+
description:
|
|
56
|
+
"Maximum items to pull from each source (exceptions, monitor changes, maintenance) before merging. Default 15, max 30.",
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
get requiredPermissions(): Array<Permission> {
|
|
61
|
+
return resolveReadPermissions();
|
|
62
|
+
},
|
|
63
|
+
execute: async (
|
|
64
|
+
args: JSONObject,
|
|
65
|
+
ctx: ToolContext,
|
|
66
|
+
): Promise<ToolExecutionResult> => {
|
|
67
|
+
const timeRange: { startTime: Date; endTime: Date } = ToolArgs.getTimeRange(
|
|
68
|
+
args,
|
|
69
|
+
{ defaultHours: 24, maxDays: 30 },
|
|
70
|
+
);
|
|
71
|
+
const startTime: Date = timeRange.startTime;
|
|
72
|
+
const endTime: Date = timeRange.endTime;
|
|
73
|
+
|
|
74
|
+
const limitPerSource: number = ToolArgs.getNumber(args, "limitPerSource", {
|
|
75
|
+
defaultValue: 15,
|
|
76
|
+
min: 1,
|
|
77
|
+
max: 30,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const events: Array<ChangeEvent> = [];
|
|
81
|
+
|
|
82
|
+
// 1) Newly-seen exceptions — their first occurrence falls inside the window.
|
|
83
|
+
try {
|
|
84
|
+
const exceptions: Array<TelemetryException> =
|
|
85
|
+
await TelemetryExceptionService.findBy({
|
|
86
|
+
query: {
|
|
87
|
+
firstSeenAt: QueryHelper.inBetween(startTime, endTime),
|
|
88
|
+
} as never,
|
|
89
|
+
select: {
|
|
90
|
+
message: true,
|
|
91
|
+
exceptionType: true,
|
|
92
|
+
firstSeenAt: true,
|
|
93
|
+
occuranceCount: true,
|
|
94
|
+
},
|
|
95
|
+
sort: { firstSeenAt: SortOrder.Descending },
|
|
96
|
+
limit: limitPerSource,
|
|
97
|
+
skip: 0,
|
|
98
|
+
props: ctx.props,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
for (const exception of exceptions) {
|
|
102
|
+
if (!exception.firstSeenAt) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
events.push({
|
|
106
|
+
at: exception.firstSeenAt,
|
|
107
|
+
change: "new_exception",
|
|
108
|
+
detail: `${exception.exceptionType || "Exception"}: ${exception.message || ""} (x${exception.occuranceCount ?? 0})`,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
} catch (error) {
|
|
112
|
+
logger.debug(`recent_changes: exceptions source skipped: ${error}`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// 2) Monitor status changes (up/down) inside the window.
|
|
116
|
+
try {
|
|
117
|
+
const statusChanges: Array<MonitorStatusTimeline> =
|
|
118
|
+
await MonitorStatusTimelineService.findBy({
|
|
119
|
+
query: {
|
|
120
|
+
createdAt: QueryHelper.inBetween(startTime, endTime),
|
|
121
|
+
},
|
|
122
|
+
select: {
|
|
123
|
+
createdAt: true,
|
|
124
|
+
monitor: { name: true },
|
|
125
|
+
monitorStatus: { name: true },
|
|
126
|
+
},
|
|
127
|
+
sort: { createdAt: SortOrder.Descending },
|
|
128
|
+
limit: limitPerSource,
|
|
129
|
+
skip: 0,
|
|
130
|
+
props: ctx.props,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
for (const statusChange of statusChanges) {
|
|
134
|
+
if (!statusChange.createdAt) {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
events.push({
|
|
138
|
+
at: statusChange.createdAt,
|
|
139
|
+
change: "monitor_status_change",
|
|
140
|
+
detail: `${statusChange.monitor?.name || "Monitor"} → ${statusChange.monitorStatus?.name || "unknown"}`,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
} catch (error) {
|
|
144
|
+
logger.debug(`recent_changes: monitor source skipped: ${error}`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/*
|
|
148
|
+
* 3) Scheduled maintenance overlapping the window (started before it ended,
|
|
149
|
+
* ends after it started).
|
|
150
|
+
*/
|
|
151
|
+
try {
|
|
152
|
+
const maintenanceEvents: Array<ScheduledMaintenance> =
|
|
153
|
+
await ScheduledMaintenanceService.findBy({
|
|
154
|
+
query: {
|
|
155
|
+
startsAt: QueryHelper.lessThanEqualTo(endTime),
|
|
156
|
+
endsAt: QueryHelper.greaterThanEqualTo(startTime),
|
|
157
|
+
},
|
|
158
|
+
select: {
|
|
159
|
+
title: true,
|
|
160
|
+
startsAt: true,
|
|
161
|
+
endsAt: true,
|
|
162
|
+
currentScheduledMaintenanceState: { name: true },
|
|
163
|
+
},
|
|
164
|
+
sort: { startsAt: SortOrder.Descending },
|
|
165
|
+
limit: limitPerSource,
|
|
166
|
+
skip: 0,
|
|
167
|
+
props: ctx.props,
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
for (const maintenance of maintenanceEvents) {
|
|
171
|
+
if (!maintenance.startsAt) {
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
events.push({
|
|
175
|
+
at: maintenance.startsAt,
|
|
176
|
+
change: "scheduled_maintenance",
|
|
177
|
+
detail: `${maintenance.title || "Maintenance"} (${maintenance.currentScheduledMaintenanceState?.name || "scheduled"})`,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
} catch (error) {
|
|
181
|
+
logger.debug(`recent_changes: maintenance source skipped: ${error}`);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Merge into one chronological feed, most recent first.
|
|
185
|
+
events.sort((a: ChangeEvent, b: ChangeEvent) => {
|
|
186
|
+
return b.at.getTime() - a.at.getTime();
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
const rows: Array<JSONObject> = events.map((event: ChangeEvent) => {
|
|
190
|
+
return {
|
|
191
|
+
at: event.at,
|
|
192
|
+
change: event.change,
|
|
193
|
+
detail: event.detail,
|
|
194
|
+
};
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
const serialized: SerializedResult =
|
|
198
|
+
ToolResultSerializer.serializeRows(rows);
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
dataForLlm: serialized.text,
|
|
202
|
+
rowCount: serialized.rowCount,
|
|
203
|
+
citationLabel: `Changes ${startTime.toISOString()} → ${endTime.toISOString()} (${serialized.rowCount} events)`,
|
|
204
|
+
redactionCount: serialized.redactionCount,
|
|
205
|
+
isTruncated: serialized.isTruncated,
|
|
206
|
+
};
|
|
207
|
+
},
|
|
208
|
+
};
|
|
@@ -32,6 +32,37 @@ const REDACTION_RULES: Array<RedactionRule> = [
|
|
|
32
32
|
regex: /Bearer\s+[A-Za-z0-9._~+/-]{16,}=*/gi,
|
|
33
33
|
replacement: "Bearer [redacted-token]",
|
|
34
34
|
},
|
|
35
|
+
{
|
|
36
|
+
/*
|
|
37
|
+
* PEM private key blocks (RSA/EC/OPENSSH/PGP…). Match the whole
|
|
38
|
+
* BEGIN…END block, including newlines, so no key material leaks.
|
|
39
|
+
*/
|
|
40
|
+
name: "private-key",
|
|
41
|
+
regex:
|
|
42
|
+
/-----BEGIN (?:[A-Z0-9]+ )*PRIVATE KEY-----[\s\S]*?-----END (?:[A-Z0-9]+ )*PRIVATE KEY-----/g,
|
|
43
|
+
replacement: "[redacted-private-key]",
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: "aws-access-key-id",
|
|
47
|
+
regex: /\b(?:AKIA|ASIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASCA)[0-9A-Z]{16}\b/g,
|
|
48
|
+
replacement: "[redacted-aws-key]",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: "github-token",
|
|
52
|
+
regex:
|
|
53
|
+
/\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{36,}\b|\bgithub_pat_[A-Za-z0-9_]{22,}\b/g,
|
|
54
|
+
replacement: "[redacted-github-token]",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: "slack-token",
|
|
58
|
+
regex: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g,
|
|
59
|
+
replacement: "[redacted-slack-token]",
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: "google-api-key",
|
|
63
|
+
regex: /\bAIza[0-9A-Za-z_-]{35}\b/g,
|
|
64
|
+
replacement: "[redacted-google-api-key]",
|
|
65
|
+
},
|
|
35
66
|
{
|
|
36
67
|
name: "email",
|
|
37
68
|
regex: /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g,
|
|
@@ -42,6 +73,17 @@ const REDACTION_RULES: Array<RedactionRule> = [
|
|
|
42
73
|
regex: /\b(?:\d{1,3}\.){3}\d{1,3}\b/g,
|
|
43
74
|
replacement: "[redacted-ip]",
|
|
44
75
|
},
|
|
76
|
+
{
|
|
77
|
+
/*
|
|
78
|
+
* Payment card numbers in the classic space/dash-separated grouping
|
|
79
|
+
* (e.g. "4111 1111 1111 1111"). Deliberately NOT matching bare 16-digit
|
|
80
|
+
* runs: an all-numeric 16-char OTel span id would collide with those and
|
|
81
|
+
* break the search_logs → get_trace pivot.
|
|
82
|
+
*/
|
|
83
|
+
name: "credit-card",
|
|
84
|
+
regex: /\b\d{4}[ -]\d{4}[ -]\d{4}[ -]\d{4}\b/g,
|
|
85
|
+
replacement: "[redacted-card]",
|
|
86
|
+
},
|
|
45
87
|
{
|
|
46
88
|
/*
|
|
47
89
|
* Long hex blobs are usually secrets (SHA-256 digests, 40+ char API
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import os from "os";
|
|
2
|
+
import { DataSource, DataSourceOptions } from "typeorm";
|
|
3
|
+
import logger from "../Logger";
|
|
4
|
+
import { AppVersion } from "../../EnvironmentConfig";
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
* Records migrations that FAILED to apply into the "MigrationFailure" table so
|
|
8
|
+
* the admin health page can explain WHY a migration is pending (what error,
|
|
9
|
+
* when it ran) instead of only showing that it is behind. Every write here is
|
|
10
|
+
* best-effort: a diagnostic log must never itself crash a boot / migrate Job or
|
|
11
|
+
* mask the real migration error, so all failures inside this module are
|
|
12
|
+
* swallowed (logged, not thrown).
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
// Which runner a failed migration belongs to. Stored verbatim in the table.
|
|
16
|
+
export enum MigrationFailureType {
|
|
17
|
+
PostgresSchema = "PostgresSchema",
|
|
18
|
+
DataMigration = "DataMigration",
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Keep a single row bounded so a pathological error/stack can't bloat the table.
|
|
22
|
+
const MAX_ERROR_MESSAGE_LENGTH: number = 10000;
|
|
23
|
+
const MAX_ERROR_STACK_LENGTH: number = 20000;
|
|
24
|
+
|
|
25
|
+
/*
|
|
26
|
+
* Best-effort credential scrub for the free-form error text we persist. DB /
|
|
27
|
+
* migration errors seldom carry secrets, but a connection error can echo a
|
|
28
|
+
* `scheme://user:pass@host` DSN and a failing DDL can quote a literal default,
|
|
29
|
+
* so we mask the obvious vectors before the text is stored and later shown.
|
|
30
|
+
*/
|
|
31
|
+
const CONNECTION_STRING_SECRET_PATTERN: RegExp =
|
|
32
|
+
/([a-z][a-z0-9+.-]*:\/\/[^:@\s/]+):[^\s/]+@/gi;
|
|
33
|
+
const KEYWORD_SECRET_PATTERN: RegExp =
|
|
34
|
+
/(password|secret|token|api[_-]?key|apikey|credential|private[_-]?key|auth[_-]?token|access[_-]?key)(\s*[:=]\s*)('(?:[^']|'')*'|"[^"]*"|[^\s,)]+)/gi;
|
|
35
|
+
|
|
36
|
+
export function scrubMigrationErrorText(text: string): string {
|
|
37
|
+
if (!text) {
|
|
38
|
+
return text;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return text
|
|
42
|
+
.replace(
|
|
43
|
+
CONNECTION_STRING_SECRET_PATTERN,
|
|
44
|
+
(_match: string, prefix: string): string => {
|
|
45
|
+
return `${prefix}:***REDACTED***@`;
|
|
46
|
+
},
|
|
47
|
+
)
|
|
48
|
+
.replace(
|
|
49
|
+
KEYWORD_SECRET_PATTERN,
|
|
50
|
+
(_match: string, keyword: string, separator: string): string => {
|
|
51
|
+
return `${keyword}${separator}***REDACTED***`;
|
|
52
|
+
},
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function toErrorMessage(error: unknown): string {
|
|
57
|
+
if (error instanceof Error) {
|
|
58
|
+
return error.message || error.name || "Unknown error";
|
|
59
|
+
}
|
|
60
|
+
return String(error);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function toErrorStack(error: unknown): string | null {
|
|
64
|
+
return error instanceof Error && error.stack ? error.stack : null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
interface MigrationFailureInput {
|
|
68
|
+
migrationName: string;
|
|
69
|
+
migrationType: MigrationFailureType;
|
|
70
|
+
error: unknown;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/*
|
|
74
|
+
* Append one failed-attempt row using the provided (already-connected)
|
|
75
|
+
* DataSource. Raw SQL — not the Service layer — so it also works on a
|
|
76
|
+
* throwaway diagnostic connection and never depends on realtime/event wiring.
|
|
77
|
+
* Returns true if the row was written. If the "MigrationFailure" table does not
|
|
78
|
+
* exist yet (e.g. its own migration is still pending on a first rollout) the
|
|
79
|
+
* INSERT throws and is swallowed — the caller's real error is unaffected.
|
|
80
|
+
*/
|
|
81
|
+
export async function recordMigrationFailure(
|
|
82
|
+
dataSource: DataSource,
|
|
83
|
+
input: MigrationFailureInput,
|
|
84
|
+
): Promise<boolean> {
|
|
85
|
+
try {
|
|
86
|
+
const message: string = scrubMigrationErrorText(
|
|
87
|
+
toErrorMessage(input.error),
|
|
88
|
+
).substring(0, MAX_ERROR_MESSAGE_LENGTH);
|
|
89
|
+
|
|
90
|
+
const rawStack: string | null = toErrorStack(input.error);
|
|
91
|
+
const stack: string | null = rawStack
|
|
92
|
+
? scrubMigrationErrorText(rawStack).substring(0, MAX_ERROR_STACK_LENGTH)
|
|
93
|
+
: null;
|
|
94
|
+
|
|
95
|
+
await dataSource.query(
|
|
96
|
+
`INSERT INTO "MigrationFailure"
|
|
97
|
+
("migrationName", "migrationType", "errorMessage", "errorStack", "attemptedAt", "hostName", "appVersion", "version", "createdAt", "updatedAt")
|
|
98
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, 1, now(), now())`,
|
|
99
|
+
[
|
|
100
|
+
input.migrationName,
|
|
101
|
+
input.migrationType,
|
|
102
|
+
message,
|
|
103
|
+
stack,
|
|
104
|
+
new Date(),
|
|
105
|
+
os.hostname(),
|
|
106
|
+
AppVersion,
|
|
107
|
+
],
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
return true;
|
|
111
|
+
} catch (err) {
|
|
112
|
+
// Diagnostic write must never mask the real failure — log and move on.
|
|
113
|
+
logger.warn(
|
|
114
|
+
`Could not record migration failure for "${input.migrationName}" (${input.migrationType}); continuing.`,
|
|
115
|
+
);
|
|
116
|
+
logger.warn(err);
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Trailing epoch in a migration class name — how TypeORM orders/identifies them.
|
|
122
|
+
function parseMigrationTimestamp(name: string): number {
|
|
123
|
+
const match: RegExpMatchArray | null = name.match(/(\d{10,})$/);
|
|
124
|
+
return match ? Number(match[1]) : 0;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/*
|
|
128
|
+
* The TypeORM schema runner (migrationsRun) applies migrations in ascending
|
|
129
|
+
* timestamp order and halts at the first failure, so the FIRST defined
|
|
130
|
+
* migration not yet in the `migrations` table is exactly the one that failed.
|
|
131
|
+
* We recompute it here from a throwaway connection because the app's own
|
|
132
|
+
* connect() has already failed (its DataSource is not usable) at the point a
|
|
133
|
+
* schema migration throws.
|
|
134
|
+
*/
|
|
135
|
+
export async function recordSchemaMigrationFailureBestEffort(
|
|
136
|
+
dataSourceOptions: DataSourceOptions,
|
|
137
|
+
originalError: unknown,
|
|
138
|
+
): Promise<void> {
|
|
139
|
+
/*
|
|
140
|
+
* Only THIS process's own boot runs schema migrations (migrationsRun=true —
|
|
141
|
+
* the migrate Job and single-pod / dev boots). On runtime pods where a
|
|
142
|
+
* dedicated migrate Job owns migrations (migrationsRun=false), a connect()
|
|
143
|
+
* failure is a connectivity problem, never a failed migration — recording
|
|
144
|
+
* one here would misattribute an outage to a (legitimately) pending
|
|
145
|
+
* migration, so skip.
|
|
146
|
+
*/
|
|
147
|
+
if (
|
|
148
|
+
(dataSourceOptions as { migrationsRun?: boolean }).migrationsRun !== true
|
|
149
|
+
) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
let diagnosticDataSource: DataSource | null = null;
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
diagnosticDataSource = new DataSource({
|
|
157
|
+
...dataSourceOptions,
|
|
158
|
+
// Never re-run migrations or sync schema on the diagnostic connection.
|
|
159
|
+
migrationsRun: false,
|
|
160
|
+
synchronize: false,
|
|
161
|
+
// Keep the probe short so a genuinely-down DB doesn't slow the failing boot.
|
|
162
|
+
extra: {
|
|
163
|
+
...((dataSourceOptions as { extra?: Record<string, unknown> }).extra ||
|
|
164
|
+
{}),
|
|
165
|
+
connectionTimeoutMillis: 5000,
|
|
166
|
+
},
|
|
167
|
+
} as DataSourceOptions);
|
|
168
|
+
|
|
169
|
+
/*
|
|
170
|
+
* If this fails, the original error was a connectivity problem (not a bad
|
|
171
|
+
* migration) — there is nothing meaningful to attribute, so we skip.
|
|
172
|
+
*/
|
|
173
|
+
await diagnosticDataSource.initialize();
|
|
174
|
+
|
|
175
|
+
const definedMigrationClasses: Array<new () => { name: string }> =
|
|
176
|
+
Array.isArray(dataSourceOptions.migrations)
|
|
177
|
+
? (dataSourceOptions.migrations as unknown as Array<
|
|
178
|
+
new () => { name: string }
|
|
179
|
+
>)
|
|
180
|
+
: [];
|
|
181
|
+
|
|
182
|
+
const definedNames: Array<string> = Array.from(
|
|
183
|
+
new Set(
|
|
184
|
+
definedMigrationClasses.map(
|
|
185
|
+
(MigrationClass: new () => { name: string }): string => {
|
|
186
|
+
return new MigrationClass().name;
|
|
187
|
+
},
|
|
188
|
+
),
|
|
189
|
+
),
|
|
190
|
+
).sort((a: string, b: string): number => {
|
|
191
|
+
return parseMigrationTimestamp(a) - parseMigrationTimestamp(b);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
let appliedNames: Set<string> = new Set();
|
|
195
|
+
try {
|
|
196
|
+
const rows: Array<{ name: string }> = await diagnosticDataSource.query(
|
|
197
|
+
"SELECT name FROM migrations",
|
|
198
|
+
);
|
|
199
|
+
appliedNames = new Set(
|
|
200
|
+
rows.map((row: { name: string }): string => {
|
|
201
|
+
return row.name;
|
|
202
|
+
}),
|
|
203
|
+
);
|
|
204
|
+
} catch {
|
|
205
|
+
// migrations table may not exist on a brand-new DB — treat as none applied.
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const firstPending: string | undefined = definedNames.find(
|
|
209
|
+
(name: string): boolean => {
|
|
210
|
+
return !appliedNames.has(name);
|
|
211
|
+
},
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
/*
|
|
215
|
+
* No pending schema migration means the connect() failure was not a pending
|
|
216
|
+
* migration failing (e.g. an entity-metadata error) — don't misattribute it.
|
|
217
|
+
*/
|
|
218
|
+
if (!firstPending) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
await recordMigrationFailure(diagnosticDataSource, {
|
|
223
|
+
migrationName: firstPending,
|
|
224
|
+
migrationType: MigrationFailureType.PostgresSchema,
|
|
225
|
+
error: originalError,
|
|
226
|
+
});
|
|
227
|
+
} catch (err) {
|
|
228
|
+
// Best-effort diagnostics only — swallow everything.
|
|
229
|
+
logger.warn("Could not record Postgres schema migration failure.");
|
|
230
|
+
logger.warn(err);
|
|
231
|
+
} finally {
|
|
232
|
+
try {
|
|
233
|
+
if (diagnosticDataSource && diagnosticDataSource.isInitialized) {
|
|
234
|
+
await diagnosticDataSource.destroy();
|
|
235
|
+
}
|
|
236
|
+
} catch (destroyErr) {
|
|
237
|
+
logger.warn(destroyErr);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { AppApiHostname } from "../EnvironmentConfig";
|
|
2
|
+
import ClusterKeyAuthorization from "../Middleware/ClusterKeyAuthorization";
|
|
3
|
+
import logger from "./Logger";
|
|
4
|
+
import Protocol from "../../Types/API/Protocol";
|
|
5
|
+
import Route from "../../Types/API/Route";
|
|
6
|
+
import URL from "../../Types/API/URL";
|
|
7
|
+
import API from "../../Utils/API";
|
|
8
|
+
import ObjectID from "../../Types/ObjectID";
|
|
9
|
+
|
|
10
|
+
/*
|
|
11
|
+
* Releases a provisioned incoming-call number on the call provider by delegating
|
|
12
|
+
* to the notification app's internal endpoint (the Common layer cannot reach the
|
|
13
|
+
* provider directly). Best-effort: failures are logged but never thrown, so a
|
|
14
|
+
* provider/network issue during cleanup does not block the parent delete.
|
|
15
|
+
*/
|
|
16
|
+
export default async function releaseIncomingCallPhoneNumber(data: {
|
|
17
|
+
projectCallSMSConfigId: ObjectID;
|
|
18
|
+
callProviderPhoneNumberId: string;
|
|
19
|
+
}): Promise<void> {
|
|
20
|
+
try {
|
|
21
|
+
await API.post({
|
|
22
|
+
url: new URL(
|
|
23
|
+
Protocol.HTTP,
|
|
24
|
+
AppApiHostname,
|
|
25
|
+
new Route("/api/notification/phone-number/internal/release"),
|
|
26
|
+
),
|
|
27
|
+
data: {
|
|
28
|
+
projectCallSMSConfigId: data.projectCallSMSConfigId.toString(),
|
|
29
|
+
callProviderPhoneNumberId: data.callProviderPhoneNumberId,
|
|
30
|
+
},
|
|
31
|
+
headers: {
|
|
32
|
+
...ClusterKeyAuthorization.getClusterKeyHeaders(),
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
} catch (err) {
|
|
36
|
+
logger.error(
|
|
37
|
+
"Failed to release incoming-call phone number on the provider during cleanup:",
|
|
38
|
+
);
|
|
39
|
+
logger.error(err);
|
|
40
|
+
}
|
|
41
|
+
}
|