@oneuptime/common 12.0.28 → 12.0.30
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/DashboardDomain.ts +43 -0
- package/Models/DatabaseModels/Index.ts +11 -0
- package/Models/DatabaseModels/MonitorTemplate.ts +15 -3
- package/Models/DatabaseModels/OnCallDutyPolicySchedule.ts +43 -0
- package/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.ts +662 -0
- package/Models/DatabaseModels/ProjectOnCallCalendarFeed.ts +584 -0
- package/Models/DatabaseModels/StatusPageDomain.ts +43 -0
- package/Models/DatabaseModels/UserOnCallCalendarFeed.ts +546 -0
- package/Models/DatabaseModels/UserOnCallShiftReminder.ts +231 -0
- package/Models/DatabaseModels/UserOnCallShiftReminderLog.ts +331 -0
- package/Server/API/DashboardDomainAPI.ts +74 -0
- package/Server/API/MicrosoftTeamsAPI.ts +81 -180
- package/Server/API/OnCallCalendarAPI.ts +2194 -0
- package/Server/API/StatusPageDomainAPI.ts +74 -0
- package/Server/EnvironmentConfig.ts +138 -0
- package/Server/Infrastructure/OnCallCalendarFeedCache.ts +1050 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790200000000-AllowNullMonitorNameOnMonitorTemplate.ts +43 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790300000000-AddCertificateReissueRequestedAtToDomains.ts +40 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790400000000-AddOnCallCalendarFeeds.ts +253 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
- package/Server/Middleware/OnCallCalendarFeedRateLimit.ts +487 -0
- package/Server/Middleware/ProjectAuthorization.ts +6 -1
- package/Server/Services/DashboardDomainService.ts +131 -0
- package/Server/Services/Index.ts +12 -0
- package/Server/Services/LogPipelineProcessorService.ts +88 -0
- package/Server/Services/MonitorTemplateService.ts +70 -11
- package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +32 -0
- package/Server/Services/OnCallDutyPolicyScheduleCalendarFeedService.ts +260 -0
- package/Server/Services/OnCallDutyPolicyScheduleLayerService.ts +70 -3
- package/Server/Services/OnCallDutyPolicyScheduleLayerUserService.ts +138 -3
- package/Server/Services/OnCallDutyPolicyScheduleService.ts +1465 -134
- package/Server/Services/OnCallDutyPolicyUserOverrideService.ts +167 -31
- package/Server/Services/ProjectOnCallCalendarFeedService.ts +192 -0
- package/Server/Services/StatusPageDomainService.ts +163 -3
- package/Server/Services/StatusPagePrivateUserSessionService.ts +197 -56
- package/Server/Services/TeamMemberService.ts +489 -1
- package/Server/Services/TeamService.ts +50 -0
- package/Server/Services/UserNotificationSettingService.ts +44 -1
- package/Server/Services/UserOnCallCalendarFeedService.ts +159 -0
- package/Server/Services/UserOnCallShiftReminderLogService.ts +151 -0
- package/Server/Services/UserOnCallShiftReminderService.ts +112 -0
- package/Server/Types/Domain.ts +17 -0
- package/Server/Utils/APIKey/AccessPermission.ts +24 -0
- package/Server/Utils/Greenlock/Greenlock.ts +156 -58
- package/Server/Utils/LogPipelineProcessorValidation.ts +112 -0
- package/Server/Utils/OnCall/CalendarFeedToken.ts +241 -0
- package/Server/Utils/OnCall/OnCallCalendarFeedRenderer.ts +1488 -0
- package/Server/Utils/OnCall/OnCallCalendarFeedUrls.ts +230 -0
- package/Server/Utils/OnCall/OnCallShiftChangeListeners.ts +227 -0
- package/Server/Utils/OnCall/OnCallShiftMaterializer.ts +1127 -0
- package/Server/Utils/OnCall/OnCallShiftReminderListener.ts +174 -0
- package/Server/Utils/OnCall/OnCallShiftReminderRunner.ts +2584 -0
- package/Server/Utils/Response.ts +134 -0
- package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.ts +1094 -45
- package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.ts +153 -17
- package/Server/Utils/StartServer.ts +10 -0
- package/Server/Utils/Telemetry/AppMetrics.ts +51 -0
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.ts +23 -11
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.ts +0 -170
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/Authorization.ts +158 -0
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.ts +23 -11
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +35 -13
- package/Tests/App/Dashboard/MonitorTemplateColumnAndFacet.test.tsx +505 -0
- package/Tests/App/Dashboard/OnCallCalendarFeedLinks.test.tsx +229 -0
- package/Tests/App/Dashboard/OnCallCalendarFeedPlanGate.test.tsx +489 -0
- package/Tests/App/Dashboard/OnCallCalendarFeedSideMenus.test.tsx +149 -0
- package/Tests/App/Dashboard/OnCallCalendarFeedUtil.test.ts +855 -0
- package/Tests/App/Dashboard/OnCallPersonalCalendarFeed.test.tsx +1209 -0
- package/Tests/App/Dashboard/OnCallSharedCalendarFeedCard.test.tsx +1019 -0
- package/Tests/App/Dashboard/OnCallShiftRemindersAndUpcomingShifts.test.tsx +655 -0
- package/Tests/App/Dashboard/UserSettingsSetupChecklistModel.test.ts +73 -0
- package/Tests/App/StatusPage/StatusPageLoginCodeBootstrap.test.ts +106 -0
- package/Tests/App/StatusPage/StatusPageLoginCodeUtil.test.ts +84 -0
- package/Tests/App/StatusPage/StatusPageRedirectSafety.test.ts +119 -0
- package/Tests/Models/MonitorTemplateMonitorNameColumn.test.ts +258 -0
- package/Tests/Models/OnCallCalendarFeedModels.test.ts +642 -0
- package/Tests/Models/OnCallDutyPolicyScheduleCalendarFeed.test.ts +288 -0
- package/Tests/Models/OnCallDutyPolicyScheduleShiftConfigVersion.test.ts +88 -0
- package/Tests/Models/UserOnCallShiftReminderModels.test.ts +368 -0
- package/Tests/Server/API/CustomDomainReissueSslAPI.test.ts +469 -0
- package/Tests/Server/API/Helpers.ts +8 -0
- package/Tests/Server/API/MicrosoftTeamsBotMessagesEndpoint.test.ts +729 -0
- package/Tests/Server/API/MicrosoftTeamsBotTestEndpoint.test.ts +26 -0
- package/Tests/Server/API/MicrosoftTeamsLegacyWebhookRemoval.test.ts +402 -0
- package/Tests/Server/API/OnCallCalendarAPI.test.ts +4461 -0
- package/Tests/Server/EnvironmentConfigOnCallCalendarFeed.test.ts +357 -0
- package/Tests/Server/Infrastructure/OnCallCalendarFeedCache.test.ts +1589 -0
- package/Tests/Server/Infrastructure/Postgres/AddOnCallCalendarFeedsMigration.test.ts +369 -0
- package/Tests/Server/Middleware/OnCallCalendarFeedRateLimit.test.ts +1365 -0
- package/Tests/Server/Middleware/ProjectAuthorizationApiKeyMiddleware.test.ts +4 -0
- package/Tests/Server/Services/AddCertificateReissueRequestedAtToDomainsMigration.test.ts +287 -0
- package/Tests/Server/Services/CustomDomainCertificateReissue.test.ts +477 -0
- package/Tests/Server/Services/FeedRetentionConsistency.test.ts +70 -0
- package/Tests/Server/Services/LogPipelineProcessorSaveValidation.test.ts +249 -0
- package/Tests/Server/Services/MonitorTemplateServiceBulkSync.test.ts +549 -0
- package/Tests/Server/Services/MonitorTemplateServiceNetworkDeviceSync.test.ts +16 -3
- package/Tests/Server/Services/NetworkDeviceAutoImportRuleEngineService.test.ts +57 -0
- package/Tests/Server/Services/OnCallCalendarFeedServices.test.ts +1103 -0
- package/Tests/Server/Services/OnCallDutyPolicyScheduleResolver.test.ts +1037 -0
- package/Tests/Server/Services/OnCallShiftConfigPropagation.test.ts +1270 -0
- package/Tests/Server/Services/SecurityEventLastErrorColumnWidth.test.ts +151 -15
- package/Tests/Server/Services/StatusPagePrivateUserSessionService.test.ts +587 -0
- package/Tests/Server/Services/TeamDeleteMemberCleanup.test.ts +156 -0
- package/Tests/Server/Services/TeamMemberOnCallCleanup.test.ts +755 -0
- package/Tests/Server/Services/UserNotificationSettingShiftReminderDefaults.test.ts +267 -0
- package/Tests/Server/Services/UserOnCallShiftReminderServices.test.ts +583 -0
- package/Tests/Server/Types/Database/Permissions/ApiKeyFileAccess.test.ts +286 -0
- package/Tests/Server/Types/Database/Permissions/MonitorTemplateColumnAccess.test.ts +328 -0
- package/Tests/Server/Types/Database/Permissions/OnCallCalendarFeedPermissions.test.ts +254 -0
- package/Tests/Server/Types/Database/QueryHelperFindWithSameTextAndIsNull.test.ts +83 -0
- package/Tests/Server/Utils/AI/SRE/ConfidenceSignal.test.ts +377 -0
- package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +16 -1
- package/Tests/Server/Utils/Greenlock/CertificateRenewalSchedule.test.ts +250 -0
- package/Tests/Server/Utils/LogPipelineProcessorValidation.test.ts +198 -0
- package/Tests/Server/Utils/OnCall/CalendarFeedToken.test.ts +467 -0
- package/Tests/Server/Utils/OnCall/OnCallCalendarFeedRenderer.test.ts +2142 -0
- package/Tests/Server/Utils/OnCall/OnCallCalendarFeedUrls.test.ts +278 -0
- package/Tests/Server/Utils/OnCall/OnCallResolverTestHarness.ts +440 -0
- package/Tests/Server/Utils/OnCall/OnCallShiftChangeListeners.test.ts +314 -0
- package/Tests/Server/Utils/OnCall/OnCallShiftMaterializer.test.ts +1502 -0
- package/Tests/Server/Utils/OnCall/OnCallShiftReminderListener.test.ts +491 -0
- package/Tests/Server/Utils/OnCall/OnCallShiftReminderRunner.test.ts +3088 -0
- package/Tests/Server/Utils/OnCall/OnCallShiftReminderTestHarness.ts +910 -0
- package/Tests/Server/Utils/ResponseSendCalendarResponse.test.ts +561 -0
- package/Tests/Server/Utils/SecurityEvent/ConnectorErrorMessage.test.ts +48 -9
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsAuth.test.ts +726 -0
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsClient.test.ts +74 -11
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsErrorHandling.test.ts +1107 -0
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPoller.test.ts +20 -3
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPollerFailureTaxonomy.test.ts +51 -11
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPollerHardening.test.ts +1246 -0
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsRequestContract.test.ts +961 -0
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsResponseParsing.test.ts +653 -0
- package/Tests/Server/Utils/StartServerEncryptionSecretWarning.test.ts +64 -0
- package/Tests/Server/Utils/Telemetry/AppMetrics.test.ts +29 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsActionAuthorization.test.ts +880 -0
- package/Tests/Types/API/HTTPResponse.test.ts +175 -0
- package/Tests/Types/API/Route.test.ts +36 -4
- package/Tests/Types/Calendar/ICalendar.test.ts +488 -0
- package/Tests/Types/Database/DatabaseProperty.test.ts +171 -0
- package/Tests/Types/DateLocalShortDateTimeString.test.ts +518 -0
- package/Tests/Types/DateLocalTimeString.test.ts +259 -0
- package/Tests/Types/DateUserPrefers12HourFormat.test.ts +316 -0
- package/Tests/Types/NotificationSetting/NotificationSettingEventType.test.ts +53 -0
- package/Tests/Types/OnCallDutyPolicy/CalendarFeedTestFixtures.ts +310 -0
- package/Tests/Types/OnCallDutyPolicy/CalendarFeedWindow.test.ts +205 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilLayerMetaAndIterationCap.test.ts +458 -0
- package/Tests/Types/OnCallDutyPolicy/MaterializedShift.test.ts +197 -0
- package/Tests/Types/OnCallDutyPolicy/OnCallCalendarFeedUtil.test.ts +1986 -0
- package/Tests/Types/OnCallDutyPolicy/ScheduleShiftUtilGroupKey.test.ts +678 -0
- package/Tests/Types/OnCallDutyPolicy/ShiftSeamUtil.test.ts +417 -0
- package/Tests/UI/Components/LogsHistogram.test.tsx +41 -2
- package/Tests/UI/Components/LogsViewerEmptyStateTimeRange.test.tsx +212 -0
- package/Tests/UI/Components/TelemetryChartClockFormat.test.tsx +359 -0
- package/Tests/UI/Components/TimeRangePickerClockFormat.test.tsx +422 -0
- package/Tests/UI/Components/TimeRangePickerDropdown.test.tsx +146 -8
- package/Tests/UI/MicrosoftTeams/MicrosoftTeamsMessagingEndpointGuidance.test.tsx +520 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +10 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +2 -0
- package/Tests/UI/Utils/Navigation.test.ts +82 -0
- package/Tests/Utils/Array.test.ts +100 -0
- package/Tests/Utils/CertificateReissue.test.ts +225 -0
- package/Tests/Utils/Grok/Grok.test.ts +492 -0
- package/Tests/Utils/Monitor/NetworkDeviceMonitorTemplateUtil.test.ts +181 -13
- package/Types/API/Route.ts +20 -5
- package/Types/Calendar/ICalendar.ts +442 -0
- package/Types/Date.ts +143 -13
- package/Types/Email/EmailTemplateType.ts +2 -0
- package/Types/NotificationSetting/NotificationSettingEventType.ts +4 -0
- package/Types/OnCallDutyPolicy/CalendarFeedWindow.ts +140 -0
- package/Types/OnCallDutyPolicy/Layer.ts +190 -35
- package/Types/OnCallDutyPolicy/MaterializedShift.ts +274 -0
- package/Types/OnCallDutyPolicy/OnCallCalendarFeedUtil.ts +1415 -0
- package/Types/OnCallDutyPolicy/ScheduleShiftUtil.ts +159 -4
- package/Types/OnCallDutyPolicy/ShiftSeamUtil.ts +106 -0
- package/Types/Rum/SessionReplay.ts +62 -1
- package/UI/Components/Date/TimeRangePickerDropdown.tsx +9 -5
- package/UI/Components/LogsViewer/LogsViewer.tsx +12 -7
- package/UI/Components/LogsViewer/components/HistogramTooltip.tsx +18 -17
- package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +21 -28
- package/UI/Components/LogsViewer/components/LogsHistogram.tsx +2 -4
- package/UI/Components/TelemetryViewer/components/TelemetryHistogram.tsx +2 -4
- package/UI/Components/TelemetryViewer/components/TelemetryHistogramTooltip.tsx +17 -16
- package/UI/Utils/Navigation.ts +42 -0
- package/Utils/Array.ts +37 -0
- package/Utils/CertificateReissue.ts +128 -0
- package/Utils/Grok/Grok.ts +461 -0
- package/Utils/Grok/GrokPatterns.ts +118 -0
- package/Utils/Monitor/NetworkDeviceMonitorTemplateUtil.ts +58 -6
- package/build/dist/Models/DatabaseModels/DashboardDomain.js +44 -0
- package/build/dist/Models/DatabaseModels/DashboardDomain.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +11 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MonitorTemplate.js +17 -4
- package/build/dist/Models/DatabaseModels/MonitorTemplate.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js +44 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js +699 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js +620 -0
- package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js.map +1 -0
- package/build/dist/Models/DatabaseModels/StatusPageDomain.js +44 -0
- package/build/dist/Models/DatabaseModels/StatusPageDomain.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js +585 -0
- package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js.map +1 -0
- package/build/dist/Models/DatabaseModels/UserOnCallShiftReminder.js +247 -0
- package/build/dist/Models/DatabaseModels/UserOnCallShiftReminder.js.map +1 -0
- package/build/dist/Models/DatabaseModels/UserOnCallShiftReminderLog.js +355 -0
- package/build/dist/Models/DatabaseModels/UserOnCallShiftReminderLog.js.map +1 -0
- package/build/dist/Server/API/DashboardDomainAPI.js +43 -1
- package/build/dist/Server/API/DashboardDomainAPI.js.map +1 -1
- package/build/dist/Server/API/MicrosoftTeamsAPI.js +74 -118
- package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
- package/build/dist/Server/API/OnCallCalendarAPI.js +1371 -0
- package/build/dist/Server/API/OnCallCalendarAPI.js.map +1 -0
- package/build/dist/Server/API/StatusPageDomainAPI.js +43 -1
- package/build/dist/Server/API/StatusPageDomainAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +102 -0
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/OnCallCalendarFeedCache.js +663 -0
- package/build/dist/Server/Infrastructure/OnCallCalendarFeedCache.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790200000000-AllowNullMonitorNameOnMonitorTemplate.js +34 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790200000000-AllowNullMonitorNameOnMonitorTemplate.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790300000000-AddCertificateReissueRequestedAtToDomains.js +28 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790300000000-AddCertificateReissueRequestedAtToDomains.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790400000000-AddOnCallCalendarFeeds.js +103 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790400000000-AddOnCallCalendarFeeds.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/OnCallCalendarFeedRateLimit.js +342 -0
- package/build/dist/Server/Middleware/OnCallCalendarFeedRateLimit.js.map +1 -0
- package/build/dist/Server/Middleware/ProjectAuthorization.js +6 -1
- package/build/dist/Server/Middleware/ProjectAuthorization.js.map +1 -1
- package/build/dist/Server/Services/DashboardDomainService.js +104 -0
- package/build/dist/Server/Services/DashboardDomainService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +12 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/LogPipelineProcessorService.js +65 -0
- package/build/dist/Server/Services/LogPipelineProcessorService.js.map +1 -1
- package/build/dist/Server/Services/MonitorTemplateService.js +57 -11
- package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +20 -0
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleCalendarFeedService.js +219 -0
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleCalendarFeedService.js.map +1 -0
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerService.js +47 -3
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerUserService.js +112 -3
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerUserService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +955 -9
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyUserOverrideService.js +93 -6
- package/build/dist/Server/Services/OnCallDutyPolicyUserOverrideService.js.map +1 -1
- package/build/dist/Server/Services/ProjectOnCallCalendarFeedService.js +157 -0
- package/build/dist/Server/Services/ProjectOnCallCalendarFeedService.js.map +1 -0
- package/build/dist/Server/Services/StatusPageDomainService.js +132 -3
- package/build/dist/Server/Services/StatusPageDomainService.js.map +1 -1
- package/build/dist/Server/Services/StatusPagePrivateUserSessionService.js +112 -32
- package/build/dist/Server/Services/StatusPagePrivateUserSessionService.js.map +1 -1
- package/build/dist/Server/Services/TeamMemberService.js +396 -1
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/TeamService.js +43 -0
- package/build/dist/Server/Services/TeamService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationSettingService.js +26 -1
- package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
- package/build/dist/Server/Services/UserOnCallCalendarFeedService.js +140 -0
- package/build/dist/Server/Services/UserOnCallCalendarFeedService.js.map +1 -0
- package/build/dist/Server/Services/UserOnCallShiftReminderLogService.js +116 -0
- package/build/dist/Server/Services/UserOnCallShiftReminderLogService.js.map +1 -0
- package/build/dist/Server/Services/UserOnCallShiftReminderService.js +92 -0
- package/build/dist/Server/Services/UserOnCallShiftReminderService.js.map +1 -0
- package/build/dist/Server/Types/Domain.js +16 -0
- package/build/dist/Server/Types/Domain.js.map +1 -1
- package/build/dist/Server/Utils/APIKey/AccessPermission.js +24 -0
- package/build/dist/Server/Utils/APIKey/AccessPermission.js.map +1 -1
- package/build/dist/Server/Utils/Greenlock/Greenlock.js +110 -35
- package/build/dist/Server/Utils/Greenlock/Greenlock.js.map +1 -1
- package/build/dist/Server/Utils/LogPipelineProcessorValidation.js +77 -0
- package/build/dist/Server/Utils/LogPipelineProcessorValidation.js.map +1 -0
- package/build/dist/Server/Utils/OnCall/CalendarFeedToken.js +161 -0
- package/build/dist/Server/Utils/OnCall/CalendarFeedToken.js.map +1 -0
- package/build/dist/Server/Utils/OnCall/OnCallCalendarFeedRenderer.js +983 -0
- package/build/dist/Server/Utils/OnCall/OnCallCalendarFeedRenderer.js.map +1 -0
- package/build/dist/Server/Utils/OnCall/OnCallCalendarFeedUrls.js +155 -0
- package/build/dist/Server/Utils/OnCall/OnCallCalendarFeedUrls.js.map +1 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftChangeListeners.js +145 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftChangeListeners.js.map +1 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftMaterializer.js +752 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftMaterializer.js.map +1 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftReminderListener.js +92 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftReminderListener.js.map +1 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftReminderRunner.js +1786 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftReminderRunner.js.map +1 -0
- package/build/dist/Server/Utils/Response.js +97 -0
- package/build/dist/Server/Utils/Response.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.js +777 -36
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.js +108 -17
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +9 -1
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/AppMetrics.js +41 -0
- package/build/dist/Server/Utils/Telemetry/AppMetrics.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js +17 -6
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.js +0 -159
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Authorization.js +128 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Authorization.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js +17 -6
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +25 -13
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Types/API/Route.js +16 -5
- package/build/dist/Types/API/Route.js.map +1 -1
- package/build/dist/Types/Calendar/ICalendar.js +290 -0
- package/build/dist/Types/Calendar/ICalendar.js.map +1 -0
- package/build/dist/Types/Date.js +115 -13
- package/build/dist/Types/Date.js.map +1 -1
- package/build/dist/Types/Email/EmailTemplateType.js +2 -0
- package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
- package/build/dist/Types/NotificationSetting/NotificationSettingEventType.js +3 -0
- package/build/dist/Types/NotificationSetting/NotificationSettingEventType.js.map +1 -1
- package/build/dist/Types/OnCallDutyPolicy/CalendarFeedWindow.js +97 -0
- package/build/dist/Types/OnCallDutyPolicy/CalendarFeedWindow.js.map +1 -0
- package/build/dist/Types/OnCallDutyPolicy/Layer.js +113 -19
- package/build/dist/Types/OnCallDutyPolicy/Layer.js.map +1 -1
- package/build/dist/Types/OnCallDutyPolicy/MaterializedShift.js +134 -0
- package/build/dist/Types/OnCallDutyPolicy/MaterializedShift.js.map +1 -0
- package/build/dist/Types/OnCallDutyPolicy/OnCallCalendarFeedUtil.js +800 -0
- package/build/dist/Types/OnCallDutyPolicy/OnCallCalendarFeedUtil.js.map +1 -0
- package/build/dist/Types/OnCallDutyPolicy/ScheduleShiftUtil.js +97 -3
- package/build/dist/Types/OnCallDutyPolicy/ScheduleShiftUtil.js.map +1 -1
- package/build/dist/Types/OnCallDutyPolicy/ShiftSeamUtil.js +77 -0
- package/build/dist/Types/OnCallDutyPolicy/ShiftSeamUtil.js.map +1 -0
- package/build/dist/Types/Rum/SessionReplay.js +38 -0
- package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
- package/build/dist/UI/Components/Date/TimeRangePickerDropdown.js +9 -5
- package/build/dist/UI/Components/Date/TimeRangePickerDropdown.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js +12 -7
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/HistogramTooltip.js +15 -14
- package/build/dist/UI/Components/LogsViewer/components/HistogramTooltip.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +17 -22
- package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js +2 -4
- package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js +2 -4
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogramTooltip.js +15 -14
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogramTooltip.js.map +1 -1
- package/build/dist/UI/Utils/Navigation.js +30 -0
- package/build/dist/UI/Utils/Navigation.js.map +1 -1
- package/build/dist/Utils/Array.js +25 -0
- package/build/dist/Utils/Array.js.map +1 -1
- package/build/dist/Utils/CertificateReissue.js +97 -0
- package/build/dist/Utils/CertificateReissue.js.map +1 -0
- package/build/dist/Utils/Grok/Grok.js +324 -0
- package/build/dist/Utils/Grok/Grok.js.map +1 -0
- package/build/dist/Utils/Grok/GrokPatterns.js +112 -0
- package/build/dist/Utils/Grok/GrokPatterns.js.map +1 -0
- package/build/dist/Utils/Monitor/NetworkDeviceMonitorTemplateUtil.js +63 -3
- package/build/dist/Utils/Monitor/NetworkDeviceMonitorTemplateUtil.js.map +1 -1
- package/package.json +1 -1
- package/UI/Utils/JsonWebToken.ts +0 -14
- package/build/dist/UI/Utils/JsonWebToken.js +0 -10
- package/build/dist/UI/Utils/JsonWebToken.js.map +0 -1
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
import ICalendar, {
|
|
2
|
+
ICALENDAR_LINE_BREAK,
|
|
3
|
+
ICALENDAR_MAX_LINE_OCTETS,
|
|
4
|
+
ICalendarCalendar,
|
|
5
|
+
ICalendarDocument,
|
|
6
|
+
ICalendarEvent,
|
|
7
|
+
ICalendarEventStatus,
|
|
8
|
+
ICalendarTransparency,
|
|
9
|
+
} from "../../../Types/Calendar/ICalendar";
|
|
10
|
+
import OneUptimeDate from "../../../Types/Date";
|
|
11
|
+
import BadDataException from "../../../Types/Exception/BadDataException";
|
|
12
|
+
|
|
13
|
+
const at: (iso: string) => Date = (iso: string): Date => {
|
|
14
|
+
return OneUptimeDate.fromString(iso);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const CRLF: string = "\r\n";
|
|
18
|
+
|
|
19
|
+
function physicalLines(body: string): Array<string> {
|
|
20
|
+
const lines: Array<string> = body.split(CRLF);
|
|
21
|
+
if (lines[lines.length - 1] === "") {
|
|
22
|
+
lines.pop();
|
|
23
|
+
}
|
|
24
|
+
return lines;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function octets(text: string): number {
|
|
28
|
+
return Buffer.byteLength(text, "utf8");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// A lone surrogate means a UTF-16 pair (= one 4-octet UTF-8 char) was split.
|
|
32
|
+
const LONE_SURROGATE: RegExp =
|
|
33
|
+
/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:^|[^\uD800-\uDBFF])[\uDC00-\uDFFF]/;
|
|
34
|
+
|
|
35
|
+
function baseCalendar(): ICalendarCalendar {
|
|
36
|
+
return {
|
|
37
|
+
productId: "-//Test//Feed//EN",
|
|
38
|
+
name: "Team",
|
|
39
|
+
description: "Desc",
|
|
40
|
+
timezone: "UTC",
|
|
41
|
+
refreshInterval: "PT1H",
|
|
42
|
+
lastModified: at("2026-08-01T10:00:00Z"),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function baseEvent(): ICalendarEvent {
|
|
47
|
+
return {
|
|
48
|
+
uid: "u1@test",
|
|
49
|
+
dtStamp: at("2026-08-01T10:00:00Z"),
|
|
50
|
+
lastModified: at("2026-08-01T10:00:00Z"),
|
|
51
|
+
sequence: 2,
|
|
52
|
+
start: at("2026-09-01T07:00:00Z"),
|
|
53
|
+
end: at("2026-09-01T15:00:00Z"),
|
|
54
|
+
summary: "On-call · Team",
|
|
55
|
+
description: "Line 1\nLine 2; a, b",
|
|
56
|
+
url: "https://x.test/a",
|
|
57
|
+
status: ICalendarEventStatus.Confirmed,
|
|
58
|
+
transparency: ICalendarTransparency.Transparent,
|
|
59
|
+
categories: ["On-Call"],
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
describe("ICalendar.serialize", () => {
|
|
64
|
+
test("byte-exact snapshot of a small calendar", () => {
|
|
65
|
+
const body: string = ICalendar.serialize({
|
|
66
|
+
calendar: baseCalendar(),
|
|
67
|
+
events: [baseEvent()],
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const expected: string =
|
|
71
|
+
[
|
|
72
|
+
"BEGIN:VCALENDAR",
|
|
73
|
+
"VERSION:2.0",
|
|
74
|
+
"PRODID:-//Test//Feed//EN",
|
|
75
|
+
"CALSCALE:GREGORIAN",
|
|
76
|
+
"NAME:Team",
|
|
77
|
+
"X-WR-CALNAME:Team",
|
|
78
|
+
"X-WR-CALDESC:Desc",
|
|
79
|
+
"X-WR-TIMEZONE:UTC",
|
|
80
|
+
"REFRESH-INTERVAL;VALUE=DURATION:PT1H",
|
|
81
|
+
"X-PUBLISHED-TTL:PT1H",
|
|
82
|
+
"LAST-MODIFIED:20260801T100000Z",
|
|
83
|
+
"BEGIN:VEVENT",
|
|
84
|
+
"UID:u1@test",
|
|
85
|
+
"DTSTAMP:20260801T100000Z",
|
|
86
|
+
"LAST-MODIFIED:20260801T100000Z",
|
|
87
|
+
"SEQUENCE:2",
|
|
88
|
+
"DTSTART:20260901T070000Z",
|
|
89
|
+
"DTEND:20260901T150000Z",
|
|
90
|
+
"SUMMARY:On-call · Team",
|
|
91
|
+
"DESCRIPTION:Line 1\\nLine 2\\; a\\, b",
|
|
92
|
+
"URL:https://x.test/a",
|
|
93
|
+
"STATUS:CONFIRMED",
|
|
94
|
+
"TRANSP:TRANSPARENT",
|
|
95
|
+
"CATEGORIES:On-Call",
|
|
96
|
+
"END:VEVENT",
|
|
97
|
+
"END:VCALENDAR",
|
|
98
|
+
].join(CRLF) + CRLF;
|
|
99
|
+
|
|
100
|
+
expect(body).toBe(expected);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test("every line break is CRLF and the body ends with one", () => {
|
|
104
|
+
const body: string = ICalendar.serialize({
|
|
105
|
+
calendar: baseCalendar(),
|
|
106
|
+
events: [baseEvent()],
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
expect(body.endsWith(CRLF)).toBe(true);
|
|
110
|
+
expect(body.replace(/\r\n/g, "")).not.toContain("\n");
|
|
111
|
+
expect(body.replace(/\r\n/g, "")).not.toContain("\r");
|
|
112
|
+
expect(ICALENDAR_LINE_BREAK).toBe(CRLF);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test("serializing the same document twice gives identical bytes, whatever the key order", () => {
|
|
116
|
+
const first: string = ICalendar.serialize({
|
|
117
|
+
calendar: baseCalendar(),
|
|
118
|
+
events: [baseEvent()],
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
const shuffledEvent: ICalendarEvent = {
|
|
122
|
+
categories: ["On-Call"],
|
|
123
|
+
transparency: ICalendarTransparency.Transparent,
|
|
124
|
+
status: ICalendarEventStatus.Confirmed,
|
|
125
|
+
url: "https://x.test/a",
|
|
126
|
+
description: "Line 1\nLine 2; a, b",
|
|
127
|
+
summary: "On-call · Team",
|
|
128
|
+
end: at("2026-09-01T15:00:00Z"),
|
|
129
|
+
start: at("2026-09-01T07:00:00Z"),
|
|
130
|
+
sequence: 2,
|
|
131
|
+
lastModified: at("2026-08-01T10:00:00Z"),
|
|
132
|
+
dtStamp: at("2026-08-01T10:00:00Z"),
|
|
133
|
+
uid: "u1@test",
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const second: string = ICalendar.serialize({
|
|
137
|
+
calendar: baseCalendar(),
|
|
138
|
+
events: [shuffledEvent],
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
expect(second).toBe(first);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test("never emits METHOD, CLASS, VALARM, RRULE, VTIMEZONE, ORGANIZER or ATTENDEE", () => {
|
|
145
|
+
const body: string = ICalendar.serialize({
|
|
146
|
+
calendar: baseCalendar(),
|
|
147
|
+
events: [baseEvent(), { ...baseEvent(), uid: "u2@test" }],
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
for (const forbidden of [
|
|
151
|
+
"METHOD",
|
|
152
|
+
"CLASS",
|
|
153
|
+
"VALARM",
|
|
154
|
+
"RRULE",
|
|
155
|
+
"VTIMEZONE",
|
|
156
|
+
"ORGANIZER",
|
|
157
|
+
"ATTENDEE",
|
|
158
|
+
"TZID",
|
|
159
|
+
]) {
|
|
160
|
+
expect(body).not.toMatch(new RegExp(`^${forbidden}[:;]`, "m"));
|
|
161
|
+
expect(body).not.toContain(`BEGIN:${forbidden}`);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
test("an empty calendar is just the header", () => {
|
|
166
|
+
const body: string = ICalendar.serialize({
|
|
167
|
+
calendar: baseCalendar(),
|
|
168
|
+
events: [],
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
expect(body).not.toContain("BEGIN:VEVENT");
|
|
172
|
+
expect(physicalLines(body)[0]).toBe("BEGIN:VCALENDAR");
|
|
173
|
+
expect(physicalLines(body)[physicalLines(body).length - 1]).toBe(
|
|
174
|
+
"END:VCALENDAR",
|
|
175
|
+
);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test("optional header properties are omitted when absent or empty; X-WR-CALNAME defaults to NAME", () => {
|
|
179
|
+
const body: string = ICalendar.serialize({
|
|
180
|
+
calendar: {
|
|
181
|
+
productId: "-//Test//Feed//EN",
|
|
182
|
+
name: "Only Name",
|
|
183
|
+
description: "",
|
|
184
|
+
},
|
|
185
|
+
events: [],
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
expect(body).toContain("NAME:Only Name\r\n");
|
|
189
|
+
expect(body).toContain("X-WR-CALNAME:Only Name\r\n");
|
|
190
|
+
expect(body).not.toContain("X-WR-CALDESC");
|
|
191
|
+
expect(body).not.toContain("X-WR-TIMEZONE");
|
|
192
|
+
expect(body).not.toContain("REFRESH-INTERVAL");
|
|
193
|
+
expect(body).not.toContain("X-PUBLISHED-TTL");
|
|
194
|
+
expect(body).not.toContain("LAST-MODIFIED");
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
test("displayName overrides X-WR-CALNAME while NAME keeps the full name", () => {
|
|
198
|
+
const body: string = ICalendar.serialize({
|
|
199
|
+
calendar: {
|
|
200
|
+
productId: "-//Test//Feed//EN",
|
|
201
|
+
name: "A very long schedule name indeed",
|
|
202
|
+
displayName: "A very long schedule…",
|
|
203
|
+
},
|
|
204
|
+
events: [],
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
expect(body).toContain("NAME:A very long schedule name indeed\r\n");
|
|
208
|
+
expect(body).toContain("X-WR-CALNAME:A very long schedule…\r\n");
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test("optional event properties are omitted when absent", () => {
|
|
212
|
+
const lines: Array<string> = ICalendar.serializeEvent({
|
|
213
|
+
uid: "bare@test",
|
|
214
|
+
dtStamp: at("2026-08-01T10:00:00Z"),
|
|
215
|
+
start: at("2026-09-01T07:00:00Z"),
|
|
216
|
+
end: at("2026-09-01T15:00:00Z"),
|
|
217
|
+
summary: "Bare",
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
expect(lines).toEqual([
|
|
221
|
+
"BEGIN:VEVENT",
|
|
222
|
+
"UID:bare@test",
|
|
223
|
+
"DTSTAMP:20260801T100000Z",
|
|
224
|
+
"DTSTART:20260901T070000Z",
|
|
225
|
+
"DTEND:20260901T150000Z",
|
|
226
|
+
"SUMMARY:Bare",
|
|
227
|
+
"END:VEVENT",
|
|
228
|
+
]);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
test("REFRESH-INTERVAL and X-PUBLISHED-TTL carry the same normalised duration", () => {
|
|
232
|
+
const body: string = ICalendar.serialize({
|
|
233
|
+
calendar: { ...baseCalendar(), refreshInterval: " pt15m " },
|
|
234
|
+
events: [],
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
expect(body).toContain("REFRESH-INTERVAL;VALUE=DURATION:PT15M\r\n");
|
|
238
|
+
expect(body).toContain("X-PUBLISHED-TTL:PT15M\r\n");
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
test("an invalid refresh interval throws", () => {
|
|
242
|
+
for (const bad of ["1h", "P", "PT", "PT1X", ""]) {
|
|
243
|
+
expect(() => {
|
|
244
|
+
return ICalendar.serialize({
|
|
245
|
+
calendar: { ...baseCalendar(), refreshInterval: bad },
|
|
246
|
+
events: [],
|
|
247
|
+
});
|
|
248
|
+
}).toThrow(BadDataException);
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
test("an empty UID, an inverted event or a bad SEQUENCE throws", () => {
|
|
253
|
+
expect(() => {
|
|
254
|
+
return ICalendar.serializeEvent({ ...baseEvent(), uid: " " });
|
|
255
|
+
}).toThrow(BadDataException);
|
|
256
|
+
|
|
257
|
+
expect(() => {
|
|
258
|
+
return ICalendar.serializeEvent({
|
|
259
|
+
...baseEvent(),
|
|
260
|
+
end: at("2026-09-01T07:00:00Z"),
|
|
261
|
+
});
|
|
262
|
+
}).toThrow(BadDataException);
|
|
263
|
+
|
|
264
|
+
expect(() => {
|
|
265
|
+
return ICalendar.serializeEvent({ ...baseEvent(), sequence: -1 });
|
|
266
|
+
}).toThrow(BadDataException);
|
|
267
|
+
|
|
268
|
+
expect(() => {
|
|
269
|
+
return ICalendar.serializeEvent({ ...baseEvent(), sequence: 1.5 });
|
|
270
|
+
}).toThrow(BadDataException);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
test("CATEGORIES escapes each entry and joins with commas; URL is not TEXT-escaped", () => {
|
|
274
|
+
const lines: Array<string> = ICalendar.serializeEvent({
|
|
275
|
+
...baseEvent(),
|
|
276
|
+
categories: ["On-Call", "a,b", "c;d"],
|
|
277
|
+
url: "https://x.test/a?b=1,2;3\nrest",
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
expect(lines).toContain("CATEGORIES:On-Call,a\\,b,c\\;d");
|
|
281
|
+
expect(lines).toContain("URL:https://x.test/a?b=1,2;3rest");
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
describe("ICalendar.escapeText", () => {
|
|
286
|
+
test("escapes backslash, semicolon, comma and newline in that order of precedence", () => {
|
|
287
|
+
expect(ICalendar.escapeText("a;b,c\\d\ne")).toBe("a\\;b\\,c\\\\d\\ne");
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
test("drops carriage returns and other control characters but keeps tabs", () => {
|
|
291
|
+
expect(ICalendar.escapeText("x\r\nyz\tw")).toBe("x\\nyz\tw");
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
test("leaves multi-byte characters untouched", () => {
|
|
295
|
+
expect(ICalendar.escapeText("Ærø · 東京 · 😀")).toBe("Ærø · 東京 · 😀");
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
test("escaping is idempotent on already-plain text and round-trips through a client-style unescape", () => {
|
|
299
|
+
const original: string = "Who: A\nSchedule: B (C); D, E\\F";
|
|
300
|
+
const escaped: string = ICalendar.escapeText(original);
|
|
301
|
+
|
|
302
|
+
const unescaped: string = escaped.replace(
|
|
303
|
+
/\\([\\;,nN])/g,
|
|
304
|
+
(_match: string, char: string): string => {
|
|
305
|
+
return char === "n" || char === "N" ? "\n" : char;
|
|
306
|
+
},
|
|
307
|
+
);
|
|
308
|
+
|
|
309
|
+
expect(unescaped).toBe(original);
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
describe("ICalendar.formatUtcDateTime", () => {
|
|
314
|
+
test("formats as YYYYMMDDTHHMMSSZ in UTC, ignoring milliseconds", () => {
|
|
315
|
+
expect(ICalendar.formatUtcDateTime(at("2026-03-08T06:30:05.999Z"))).toBe(
|
|
316
|
+
"20260308T063005Z",
|
|
317
|
+
);
|
|
318
|
+
expect(ICalendar.formatUtcDateTime(at("2026-12-31T23:59:59Z"))).toBe(
|
|
319
|
+
"20261231T235959Z",
|
|
320
|
+
);
|
|
321
|
+
expect(ICalendar.formatUtcDateTime(at("2026-01-01T00:00:00Z"))).toBe(
|
|
322
|
+
"20260101T000000Z",
|
|
323
|
+
);
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
test("zero-pads every component", () => {
|
|
327
|
+
expect(ICalendar.formatUtcDateTime(at("2026-02-03T04:05:06Z"))).toBe(
|
|
328
|
+
"20260203T040506Z",
|
|
329
|
+
);
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
test("throws on an invalid date", () => {
|
|
333
|
+
expect(() => {
|
|
334
|
+
return ICalendar.formatUtcDateTime(new Date("not a date"));
|
|
335
|
+
}).toThrow(BadDataException);
|
|
336
|
+
});
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
describe("ICalendar.foldLine", () => {
|
|
340
|
+
test("a line of at most 75 octets is returned unchanged", () => {
|
|
341
|
+
const line: string = `SUMMARY:${"a".repeat(67)}`;
|
|
342
|
+
expect(octets(line)).toBe(75);
|
|
343
|
+
expect(ICalendar.foldLine(line)).toBe(line);
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
test("a long ASCII line folds into 75-octet pieces with a leading space and unfolds losslessly", () => {
|
|
347
|
+
const line: string = `DESCRIPTION:${"a".repeat(300)}`;
|
|
348
|
+
const folded: string = ICalendar.foldLine(line);
|
|
349
|
+
const pieces: Array<string> = folded.split(CRLF);
|
|
350
|
+
|
|
351
|
+
expect(pieces.length).toBeGreaterThan(1);
|
|
352
|
+
expect(octets(pieces[0]!)).toBe(75);
|
|
353
|
+
|
|
354
|
+
for (let i: number = 1; i < pieces.length; i++) {
|
|
355
|
+
expect(pieces[i]!.startsWith(" ")).toBe(true);
|
|
356
|
+
expect(octets(pieces[i]!)).toBeLessThanOrEqual(75);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Every continuation but the last is packed to the limit.
|
|
360
|
+
for (let i: number = 1; i < pieces.length - 1; i++) {
|
|
361
|
+
expect(octets(pieces[i]!)).toBe(75);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
expect(ICalendar.unfold(folded)).toBe(line);
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
test("never splits a 2-octet character", () => {
|
|
368
|
+
// "SUMMARY:" is 8 octets; 33 x "é" (66) fits, the 34th would make 76.
|
|
369
|
+
const line: string = `SUMMARY:${"é".repeat(120)}`;
|
|
370
|
+
const folded: string = ICalendar.foldLine(line);
|
|
371
|
+
const pieces: Array<string> = folded.split(CRLF);
|
|
372
|
+
|
|
373
|
+
expect(pieces[0]).toBe(`SUMMARY:${"é".repeat(33)}`);
|
|
374
|
+
expect(octets(pieces[0]!)).toBe(74);
|
|
375
|
+
|
|
376
|
+
for (const piece of pieces) {
|
|
377
|
+
expect(octets(piece)).toBeLessThanOrEqual(ICALENDAR_MAX_LINE_OCTETS);
|
|
378
|
+
expect(piece).not.toMatch(LONE_SURROGATE);
|
|
379
|
+
expect(Buffer.from(piece, "utf8").toString("utf8")).toBe(piece);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
expect(ICalendar.unfold(folded)).toBe(line);
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
test("never splits a 3-octet or 4-octet character", () => {
|
|
386
|
+
for (const char of ["東", "😀"]) {
|
|
387
|
+
const line: string = `X:${char.repeat(90)}`;
|
|
388
|
+
const folded: string = ICalendar.foldLine(line);
|
|
389
|
+
|
|
390
|
+
for (const piece of folded.split(CRLF)) {
|
|
391
|
+
expect(octets(piece)).toBeLessThanOrEqual(ICALENDAR_MAX_LINE_OCTETS);
|
|
392
|
+
expect(piece).not.toMatch(LONE_SURROGATE);
|
|
393
|
+
expect(Buffer.from(piece, "utf8").toString("utf8")).toBe(piece);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
expect(ICalendar.unfold(folded)).toBe(line);
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
test("a mixed-width line packs each physical line as full as the boundary allows", () => {
|
|
401
|
+
const line: string = `DESCRIPTION:${"ab😀é東".repeat(40)}`;
|
|
402
|
+
const folded: string = ICalendar.foldLine(line);
|
|
403
|
+
const pieces: Array<string> = folded.split(CRLF);
|
|
404
|
+
|
|
405
|
+
expect(pieces.length).toBeGreaterThan(2);
|
|
406
|
+
|
|
407
|
+
for (let i: number = 0; i < pieces.length; i++) {
|
|
408
|
+
const piece: string = pieces[i]!;
|
|
409
|
+
expect(octets(piece)).toBeLessThanOrEqual(75);
|
|
410
|
+
// Every piece but the last is packed to within one character of the limit.
|
|
411
|
+
if (i < pieces.length - 1) {
|
|
412
|
+
expect(octets(piece)).toBeGreaterThan(70);
|
|
413
|
+
}
|
|
414
|
+
expect(piece).not.toMatch(LONE_SURROGATE);
|
|
415
|
+
if (i > 0) {
|
|
416
|
+
expect(piece.startsWith(" ")).toBe(true);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
expect(ICalendar.unfold(folded)).toBe(line);
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
test("a serialized document has no physical line over 75 octets and unfolds to the logical lines", () => {
|
|
424
|
+
const document: ICalendarDocument = {
|
|
425
|
+
calendar: {
|
|
426
|
+
...baseCalendar(),
|
|
427
|
+
description: "Ærø ".repeat(60),
|
|
428
|
+
},
|
|
429
|
+
events: [
|
|
430
|
+
{
|
|
431
|
+
...baseEvent(),
|
|
432
|
+
summary: "😀".repeat(50),
|
|
433
|
+
description: "東京".repeat(100),
|
|
434
|
+
},
|
|
435
|
+
],
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
const body: string = ICalendar.serialize(document);
|
|
439
|
+
|
|
440
|
+
for (const line of physicalLines(body)) {
|
|
441
|
+
expect(octets(line)).toBeLessThanOrEqual(ICALENDAR_MAX_LINE_OCTETS);
|
|
442
|
+
expect(line).not.toMatch(LONE_SURROGATE);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
const unfolded: string = ICalendar.unfold(body);
|
|
446
|
+
expect(unfolded).toContain(`SUMMARY:${"😀".repeat(50)}\r\n`);
|
|
447
|
+
expect(unfolded).toContain(`DESCRIPTION:${"東京".repeat(100)}\r\n`);
|
|
448
|
+
});
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
describe("ICalendar.getUtf8OctetLength", () => {
|
|
452
|
+
test("counts 1/2/3/4 octet characters", () => {
|
|
453
|
+
expect(ICalendar.getUtf8OctetLength("abc")).toBe(3);
|
|
454
|
+
expect(ICalendar.getUtf8OctetLength("é")).toBe(2);
|
|
455
|
+
expect(ICalendar.getUtf8OctetLength("東")).toBe(3);
|
|
456
|
+
expect(ICalendar.getUtf8OctetLength("😀")).toBe(4);
|
|
457
|
+
expect(ICalendar.getUtf8OctetLength("aé東😀")).toBe(
|
|
458
|
+
Buffer.byteLength("aé東😀", "utf8"),
|
|
459
|
+
);
|
|
460
|
+
});
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
describe("ICalendar.contentLine / textLine", () => {
|
|
464
|
+
test("upper-cases the name and parameter names", () => {
|
|
465
|
+
expect(ICalendar.contentLine("x-thing", "v", { value: "duration" })).toBe(
|
|
466
|
+
"X-THING;VALUE=duration:v",
|
|
467
|
+
);
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
test("quotes parameter values containing reserved characters and strips double quotes", () => {
|
|
471
|
+
expect(ICalendar.contentLine("P", "v", { cn: 'Doe, "John"' })).toBe(
|
|
472
|
+
'P;CN="Doe, John":v',
|
|
473
|
+
);
|
|
474
|
+
expect(ICalendar.contentLine("P", "v", { cn: "a:b" })).toBe('P;CN="a:b":v');
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
test("strips line breaks from any value", () => {
|
|
478
|
+
expect(ICalendar.contentLine("URL", "https://x\r\n.test")).toBe(
|
|
479
|
+
"URL:https://x.test",
|
|
480
|
+
);
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
test("textLine escapes the value", () => {
|
|
484
|
+
expect(ICalendar.textLine("SUMMARY", "a, b; c")).toBe(
|
|
485
|
+
"SUMMARY:a\\, b\\; c",
|
|
486
|
+
);
|
|
487
|
+
});
|
|
488
|
+
});
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import DatabaseProperty from "../../../Types/Database/DatabaseProperty";
|
|
2
|
+
import NotImplementedException from "../../../Types/Exception/NotImplementedException";
|
|
3
|
+
import { JSONArray, JSONObject } from "../../../Types/JSON";
|
|
4
|
+
import { describe, expect, it } from "@jest/globals";
|
|
5
|
+
import { Equal, FindOperator, In, Not } from "typeorm";
|
|
6
|
+
import { ValueTransformer } from "typeorm/decorator/options/ValueTransformer";
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
* DatabaseProperty is the base every value-object column type extends. Its
|
|
10
|
+
* TypeORM ValueTransformer carries three pieces of behavior that are easy to
|
|
11
|
+
* break and expensive to break:
|
|
12
|
+
*
|
|
13
|
+
* - `to(undefined)` must stay `undefined` so an omitted column falls to its
|
|
14
|
+
* SQL DEFAULT instead of being rewritten to an explicit NULL (a not-null
|
|
15
|
+
* constraint violation / HTTP 500 on every create otherwise).
|
|
16
|
+
* - a Raw query object must pass straight through untouched.
|
|
17
|
+
* - a FindOperator (Equal/In/Not/And/...) must keep its structure while its
|
|
18
|
+
* leaf value(s) are converted, so a privacy/scope clause is preserved.
|
|
19
|
+
*
|
|
20
|
+
* DatabasePropertyFindOperator.test.ts checks the concrete subclasses. This
|
|
21
|
+
* suite pins the base-class dispatch itself, using a tiny subclass whose
|
|
22
|
+
* conversion is observable (uppercasing).
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
// A minimal concrete DatabaseProperty whose conversions are observable.
|
|
26
|
+
class UpperCaseProperty extends DatabaseProperty {
|
|
27
|
+
public value: string;
|
|
28
|
+
|
|
29
|
+
public constructor(value: string) {
|
|
30
|
+
super();
|
|
31
|
+
this.value = value;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
protected static override fromDatabase(
|
|
35
|
+
value: string | number | JSONObject | JSONArray,
|
|
36
|
+
): DatabaseProperty | Array<DatabaseProperty> | null {
|
|
37
|
+
return new UpperCaseProperty(String(value));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
protected static override toDatabase(
|
|
41
|
+
value: DatabaseProperty | Array<DatabaseProperty> | any,
|
|
42
|
+
): string | number | JSONObject | JSONArray | null {
|
|
43
|
+
if (value instanceof UpperCaseProperty) {
|
|
44
|
+
return value.value.toUpperCase();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (typeof value === "string") {
|
|
48
|
+
return value.toUpperCase();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
describe("DatabaseProperty", () => {
|
|
56
|
+
describe("getDatabaseTransformer().to", () => {
|
|
57
|
+
it("passes undefined through unchanged so the SQL DEFAULT survives", () => {
|
|
58
|
+
const transformer: ValueTransformer =
|
|
59
|
+
UpperCaseProperty.getDatabaseTransformer();
|
|
60
|
+
|
|
61
|
+
// The whole point: undefined must NOT become null here.
|
|
62
|
+
expect(transformer.to(undefined)).toBeUndefined();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("delegates a plain value to the subclass toDatabase", () => {
|
|
66
|
+
const transformer: ValueTransformer =
|
|
67
|
+
UpperCaseProperty.getDatabaseTransformer();
|
|
68
|
+
|
|
69
|
+
expect(transformer.to(new UpperCaseProperty("hello"))).toBe("HELLO");
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("passes a raw query object straight through without conversion", () => {
|
|
73
|
+
const transformer: ValueTransformer =
|
|
74
|
+
UpperCaseProperty.getDatabaseTransformer();
|
|
75
|
+
|
|
76
|
+
const raw: JSONObject = { _type: "raw", value: "keep me as-is" };
|
|
77
|
+
const result: unknown = transformer.to(raw);
|
|
78
|
+
|
|
79
|
+
// Same object, untouched - toDatabase (which uppercases) never ran.
|
|
80
|
+
expect(result).toBe(raw);
|
|
81
|
+
expect((result as JSONObject)["value"]).toBe("keep me as-is");
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("preserves an Equal FindOperator and converts only its leaf", () => {
|
|
85
|
+
const transformer: ValueTransformer =
|
|
86
|
+
UpperCaseProperty.getDatabaseTransformer();
|
|
87
|
+
|
|
88
|
+
const operator: FindOperator<string> = Equal("abc");
|
|
89
|
+
const result: unknown = transformer.to(operator);
|
|
90
|
+
|
|
91
|
+
// Structure kept (same instance), leaf converted.
|
|
92
|
+
expect(result).toBe(operator);
|
|
93
|
+
expect((result as FindOperator<string>).value).toBe("ABC");
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("preserves a Not FindOperator and converts its leaf", () => {
|
|
97
|
+
const transformer: ValueTransformer =
|
|
98
|
+
UpperCaseProperty.getDatabaseTransformer();
|
|
99
|
+
|
|
100
|
+
const operator: FindOperator<string> = Not("nope");
|
|
101
|
+
const result: unknown = transformer.to(operator);
|
|
102
|
+
|
|
103
|
+
expect(result).toBe(operator);
|
|
104
|
+
expect((result as FindOperator<string>).value).toBe("NOPE");
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("converts every leaf of a multi-value In FindOperator", () => {
|
|
108
|
+
const transformer: ValueTransformer =
|
|
109
|
+
UpperCaseProperty.getDatabaseTransformer();
|
|
110
|
+
|
|
111
|
+
const operator: FindOperator<Array<string>> = In(["a", "b", "c"]);
|
|
112
|
+
const result: unknown = transformer.to(operator);
|
|
113
|
+
|
|
114
|
+
expect(result).toBe(operator);
|
|
115
|
+
expect((result as FindOperator<Array<string>>).value).toEqual([
|
|
116
|
+
"A",
|
|
117
|
+
"B",
|
|
118
|
+
"C",
|
|
119
|
+
]);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("is a fixpoint: transforming its own output again is a no-op", () => {
|
|
123
|
+
const transformer: ValueTransformer =
|
|
124
|
+
UpperCaseProperty.getDatabaseTransformer();
|
|
125
|
+
|
|
126
|
+
const operator: FindOperator<string> = Equal("abc");
|
|
127
|
+
transformer.to(operator);
|
|
128
|
+
// Second pass (BaseAPI.getList shares the query between findBy/countBy).
|
|
129
|
+
transformer.to(operator);
|
|
130
|
+
|
|
131
|
+
expect(operator.value).toBe("ABC");
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
describe("getDatabaseTransformer().from", () => {
|
|
136
|
+
it("delegates to the subclass fromDatabase", () => {
|
|
137
|
+
const transformer: ValueTransformer =
|
|
138
|
+
UpperCaseProperty.getDatabaseTransformer();
|
|
139
|
+
|
|
140
|
+
const result: unknown = transformer.from("stored");
|
|
141
|
+
|
|
142
|
+
expect(result).toBeInstanceOf(UpperCaseProperty);
|
|
143
|
+
expect((result as UpperCaseProperty).value).toBe("stored");
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
describe("base class defaults", () => {
|
|
148
|
+
it("getSchema throws NotImplementedException on the base class", () => {
|
|
149
|
+
expect(() => {
|
|
150
|
+
return DatabaseProperty.getSchema();
|
|
151
|
+
}).toThrow(NotImplementedException);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("still short-circuits undefined even on the un-implemented base", () => {
|
|
155
|
+
const transformer: ValueTransformer =
|
|
156
|
+
DatabaseProperty.getDatabaseTransformer();
|
|
157
|
+
|
|
158
|
+
// Reaches the undefined guard before the un-implemented toDatabase.
|
|
159
|
+
expect(transformer.to(undefined)).toBeUndefined();
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it("throws NotImplementedException when the base must actually convert", () => {
|
|
163
|
+
const transformer: ValueTransformer =
|
|
164
|
+
DatabaseProperty.getDatabaseTransformer();
|
|
165
|
+
|
|
166
|
+
expect(() => {
|
|
167
|
+
return transformer.to("a real value");
|
|
168
|
+
}).toThrow(NotImplementedException);
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
});
|