@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,663 @@
|
|
|
1
|
+
import GlobalCache from "./GlobalCache";
|
|
2
|
+
import InMemoryTTLCache from "./InMemoryTTLCache";
|
|
3
|
+
import logger from "../Utils/Logger";
|
|
4
|
+
import { RENDER_CONCURRENCY } from "../../Types/OnCallDutyPolicy/CalendarFeedWindow";
|
|
5
|
+
import { createHash, randomBytes } from "crypto";
|
|
6
|
+
/*
|
|
7
|
+
* Caches for the on-call calendar feeds.
|
|
8
|
+
*
|
|
9
|
+
* Three things are cached, at three lifetimes:
|
|
10
|
+
*
|
|
11
|
+
* 1. Schedule segments. One schedule's resolved shifts over a window, shared
|
|
12
|
+
* by every subscriber of that schedule: N personal feeds, the schedule
|
|
13
|
+
* feed and the project feed all read one LayerUtil expansion instead of
|
|
14
|
+
* each doing their own. Apple Calendar's five-minute polls hit this.
|
|
15
|
+
*
|
|
16
|
+
* 2. Feed bodies. The rendered .ics plus its ETag/Last-Modified for one feed,
|
|
17
|
+
* short-lived (the same 300 s the Cache-Control header promises). A
|
|
18
|
+
* client that comes back within the TTL costs one Redis GET.
|
|
19
|
+
*
|
|
20
|
+
* 3. Last-good bodies. The most recent body that rendered successfully for a
|
|
21
|
+
* feed, kept for a day. Served -- with Warning: 110 -- when a render
|
|
22
|
+
* fails, hits the per-process render cap, or trips an iteration cap, so a
|
|
23
|
+
* transient failure degrades to "slightly stale" rather than to a 503
|
|
24
|
+
* that some clients answer by dropping the calendar.
|
|
25
|
+
*
|
|
26
|
+
* Invalidation is by scope generation, not by key scan. GlobalCache has no
|
|
27
|
+
* SCAN, and a SCAN across a Redis that also backs BullMQ is not something a
|
|
28
|
+
* hook should do. Instead every project, user-in-project and schedule has a
|
|
29
|
+
* generation token in Redis; a cached body's real key mixes in the current
|
|
30
|
+
* generations of every scope the feed depends on, so bumping a generation
|
|
31
|
+
* makes every dependent entry unreachable in one write. Old entries age out on
|
|
32
|
+
* their own TTLs. purgeForUser / purgeForSchedule / purgeForProject are those
|
|
33
|
+
* bumps. Last-good bodies are the deliberate exception: their key embeds the
|
|
34
|
+
* feed's own cache key -- which carries the token hash and the candidate
|
|
35
|
+
* schedule set -- and nothing else, so a rotated token or a changed schedule
|
|
36
|
+
* set can never reach one, while a hook-triggered purge does not throw away
|
|
37
|
+
* the only thing standing between a failed render and a 503.
|
|
38
|
+
*
|
|
39
|
+
* Every GlobalCache call is wrapped: each one throws
|
|
40
|
+
* DatabaseNotConnectedException when Redis is down, and the feeds must keep
|
|
41
|
+
* working through that. Reads and writes fall back to a per-process
|
|
42
|
+
* InMemoryTTLCache; generations are written to both so a purge made while
|
|
43
|
+
* Redis is down still takes effect in this process. The in-memory tier is
|
|
44
|
+
* consulted only when Redis fails -- it is never a first-level cache, so a
|
|
45
|
+
* purge made by another process is not masked by a stale local copy.
|
|
46
|
+
*
|
|
47
|
+
* The render slots are the per-process concurrency cap on cache-miss renders.
|
|
48
|
+
* Not Redis-backed on purpose: the thing being protected is THIS process's
|
|
49
|
+
* event loop and heap, and a cap that vanishes when Redis blips would vanish
|
|
50
|
+
* at exactly the moment every request becomes a miss.
|
|
51
|
+
*/
|
|
52
|
+
export const ON_CALL_CALENDAR_FEED_CACHE_NAMESPACE = "oncall-calendar";
|
|
53
|
+
/*
|
|
54
|
+
* The shared window constant is the default; configure() exists so a test (or
|
|
55
|
+
* an operator-facing knob, should one ever be added) can override it per
|
|
56
|
+
* process without touching the pure-types package.
|
|
57
|
+
*/
|
|
58
|
+
export const DEFAULT_RENDER_CONCURRENCY = RENDER_CONCURRENCY;
|
|
59
|
+
/*
|
|
60
|
+
* Bodies above this are not cached. The compose Redis has no maxmemory and
|
|
61
|
+
* also backs BullMQ; a handful of multi-megabyte feeds is not what it is
|
|
62
|
+
* sized for. Note that this is NOT the same ceiling as MAX_EVENTS: a VEVENT
|
|
63
|
+
* is roughly 0.9 KB, so 2 MiB is crossed at about 2,200 events while
|
|
64
|
+
* MAX_EVENTS allows 5,000. An hourly rotation over a long window is over this
|
|
65
|
+
* cap and still well inside the event cap; such a feed is re-rendered on
|
|
66
|
+
* every poll.
|
|
67
|
+
*/
|
|
68
|
+
export const MAX_CACHED_BODY_BYTES = 2 * 1024 * 1024;
|
|
69
|
+
/*
|
|
70
|
+
* Last-good bodies get their own, larger ceiling. The body cache exists to
|
|
71
|
+
* save work and can afford to skip the heaviest feeds; the last-good tier is
|
|
72
|
+
* the only thing between a failed or capped render and a 503, and refusing it
|
|
73
|
+
* for exactly the feeds most expensive to render -- the ones most likely to
|
|
74
|
+
* trip the render cap -- removed the stale-while-error tier where it matters
|
|
75
|
+
* most. It is written at most once per successful render and read only when
|
|
76
|
+
* something has already gone wrong.
|
|
77
|
+
*/
|
|
78
|
+
export const MAX_CACHED_LAST_GOOD_BYTES = 8 * 1024 * 1024;
|
|
79
|
+
/*
|
|
80
|
+
* A schedule's cached segments carry every user's shifts over the window; an
|
|
81
|
+
* hourly rotation over the widest window is several megabytes. Cached, they
|
|
82
|
+
* save the expansion for every subscriber of that schedule, so the ceiling is
|
|
83
|
+
* generous -- but it is a ceiling: an entry above it is returned to the
|
|
84
|
+
* caller and simply not stored, rather than pushed into a Redis with no
|
|
85
|
+
* maxmemory that also backs BullMQ.
|
|
86
|
+
*/
|
|
87
|
+
export const MAX_CACHED_SEGMENT_BYTES = 8 * 1024 * 1024;
|
|
88
|
+
/* How long a last-good body is kept, in seconds. */
|
|
89
|
+
export const LAST_GOOD_TTL_SECONDS = 24 * 60 * 60;
|
|
90
|
+
/*
|
|
91
|
+
* Generations are read on every feed request and only ever replaced, never
|
|
92
|
+
* incremented, so they need no TTL at all -- but a key with no TTL is a leak
|
|
93
|
+
* once its schedule or user is deleted. 30 days comfortably exceeds every
|
|
94
|
+
* cache TTL that depends on them; an expired generation reads as the default
|
|
95
|
+
* and simply starts a fresh key space.
|
|
96
|
+
*/
|
|
97
|
+
const GENERATION_TTL_SECONDS = 30 * 24 * 60 * 60;
|
|
98
|
+
/* Generation value when none has ever been written for a scope. */
|
|
99
|
+
const DEFAULT_GENERATION = "0";
|
|
100
|
+
const MEMORY_MAX_ENTRIES = 500;
|
|
101
|
+
const MEMORY_GENERATION_MAX_ENTRIES = 5000;
|
|
102
|
+
/*
|
|
103
|
+
* The in-process fallback tiers are bounded by BYTES as well as by entries.
|
|
104
|
+
* They are only written while Redis is failing, but what they hold then are
|
|
105
|
+
* whole calendar bodies and whole schedule expansions -- megabytes each -- so
|
|
106
|
+
* an entry count alone bounds nothing: 500 multi-megabyte strings is most of
|
|
107
|
+
* a container's heap. Entries also outlive their TTL (nothing reads a
|
|
108
|
+
* fallback tier once Redis is healthy again, so nothing triggers the
|
|
109
|
+
* expire-on-read), which is why the store sweeps expired entries when it
|
|
110
|
+
* needs room.
|
|
111
|
+
*/
|
|
112
|
+
export const MEMORY_MAX_BYTES = 32 * 1024 * 1024;
|
|
113
|
+
/*
|
|
114
|
+
* The in-process fallback store: InMemoryTTLCache's coarse-LRU behaviour plus
|
|
115
|
+
* a byte budget and a sweep. Not a change to InMemoryTTLCache itself -- every
|
|
116
|
+
* other user of that class caches small values and does not need the
|
|
117
|
+
* accounting (SessionReplayGateCacheStore keeps its own bounded store for the
|
|
118
|
+
* same reason).
|
|
119
|
+
*/
|
|
120
|
+
class MemoryStringStore {
|
|
121
|
+
constructor(maxEntries, maxBytes) {
|
|
122
|
+
this.maxEntries = maxEntries;
|
|
123
|
+
this.maxBytes = maxBytes;
|
|
124
|
+
this.store = new Map();
|
|
125
|
+
this.bytes = 0;
|
|
126
|
+
}
|
|
127
|
+
set(key, value, ttlMs) {
|
|
128
|
+
this.delete(key);
|
|
129
|
+
const bytes = Buffer.byteLength(value, "utf8");
|
|
130
|
+
/* A single value over the whole budget is not worth evicting for. */
|
|
131
|
+
if (bytes > this.maxBytes) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
/*
|
|
135
|
+
* Sweep on every write. Nothing reads these tiers while Redis is healthy,
|
|
136
|
+
* so expire-on-read never fires for them: without this, an entry written
|
|
137
|
+
* during an outage stays resident long past its TTL, until 500 newer
|
|
138
|
+
* writes push it out. A write only happens while Redis is failing and the
|
|
139
|
+
* store holds at most a few hundred entries, so the scan is free.
|
|
140
|
+
*/
|
|
141
|
+
this.sweepExpired();
|
|
142
|
+
/* Map iteration is insertion order, so the first key is the oldest. */
|
|
143
|
+
while (this.store.size > 0 &&
|
|
144
|
+
(this.store.size + 1 > this.maxEntries ||
|
|
145
|
+
this.bytes + bytes > this.maxBytes)) {
|
|
146
|
+
const oldest = this.store.keys().next().value;
|
|
147
|
+
if (oldest === undefined) {
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
this.delete(oldest);
|
|
151
|
+
}
|
|
152
|
+
this.store.set(key, { value, bytes, expiresAt: Date.now() + ttlMs });
|
|
153
|
+
this.bytes += bytes;
|
|
154
|
+
}
|
|
155
|
+
get(key) {
|
|
156
|
+
const entry = this.store.get(key);
|
|
157
|
+
if (!entry) {
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
if (Date.now() > entry.expiresAt) {
|
|
161
|
+
this.delete(key);
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
return entry.value;
|
|
165
|
+
}
|
|
166
|
+
delete(key) {
|
|
167
|
+
const entry = this.store.get(key);
|
|
168
|
+
if (!entry) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
this.bytes -= entry.bytes;
|
|
172
|
+
this.store.delete(key);
|
|
173
|
+
}
|
|
174
|
+
clear() {
|
|
175
|
+
this.store.clear();
|
|
176
|
+
this.bytes = 0;
|
|
177
|
+
}
|
|
178
|
+
size() {
|
|
179
|
+
return this.store.size;
|
|
180
|
+
}
|
|
181
|
+
byteSize() {
|
|
182
|
+
return this.bytes;
|
|
183
|
+
}
|
|
184
|
+
sweepExpired() {
|
|
185
|
+
const now = Date.now();
|
|
186
|
+
for (const [key, entry] of this.store) {
|
|
187
|
+
if (now > entry.expiresAt) {
|
|
188
|
+
this.delete(key);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
class OnCallCalendarFeedCache {
|
|
194
|
+
// -- Configuration -----------------------------------------------------
|
|
195
|
+
static configure(options) {
|
|
196
|
+
if (options.renderConcurrency !== undefined &&
|
|
197
|
+
Number.isInteger(options.renderConcurrency) &&
|
|
198
|
+
options.renderConcurrency > 0) {
|
|
199
|
+
OnCallCalendarFeedCache.renderConcurrency = options.renderConcurrency;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
static getRenderConcurrency() {
|
|
203
|
+
return OnCallCalendarFeedCache.renderConcurrency;
|
|
204
|
+
}
|
|
205
|
+
/*
|
|
206
|
+
* Drop every in-process fallback entry and release every slot. For tests
|
|
207
|
+
* and for nothing else -- a running server has no reason to do this.
|
|
208
|
+
*/
|
|
209
|
+
static clearInProcessState() {
|
|
210
|
+
OnCallCalendarFeedCache.memorySegments.clear();
|
|
211
|
+
OnCallCalendarFeedCache.memoryBodies.clear();
|
|
212
|
+
OnCallCalendarFeedCache.memoryLastGood.clear();
|
|
213
|
+
OnCallCalendarFeedCache.memoryGenerations.clear();
|
|
214
|
+
OnCallCalendarFeedCache.inFlightRenders.clear();
|
|
215
|
+
OnCallCalendarFeedCache.activeRenderSlots = 0;
|
|
216
|
+
OnCallCalendarFeedCache.renderConcurrency = DEFAULT_RENDER_CONCURRENCY;
|
|
217
|
+
}
|
|
218
|
+
// -- Render slots ------------------------------------------------------
|
|
219
|
+
/*
|
|
220
|
+
* Take a render slot, or refuse. The caller MUST release it in a finally
|
|
221
|
+
* block; a leaked slot is one fewer render this process can do until it
|
|
222
|
+
* restarts.
|
|
223
|
+
*/
|
|
224
|
+
static tryAcquireRenderSlot(options) {
|
|
225
|
+
var _a;
|
|
226
|
+
/*
|
|
227
|
+
* `leaveFreeSlots` keeps a caller out of the last few slots. Session
|
|
228
|
+
* routes (/my-shifts) pass it so they can never take every slot away from
|
|
229
|
+
* the public feed routes, whose callers are calendar clients that answer
|
|
230
|
+
* a 503 with a stale or empty calendar. Clamped so it can never make the
|
|
231
|
+
* budget zero.
|
|
232
|
+
*/
|
|
233
|
+
const requestedReserve = (_a = options === null || options === void 0 ? void 0 : options.leaveFreeSlots) !== null && _a !== void 0 ? _a : 0;
|
|
234
|
+
const reserve = Math.min(Math.max(0, Math.floor(requestedReserve)), OnCallCalendarFeedCache.renderConcurrency - 1);
|
|
235
|
+
const budget = OnCallCalendarFeedCache.renderConcurrency - reserve;
|
|
236
|
+
if (OnCallCalendarFeedCache.activeRenderSlots >= budget) {
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
OnCallCalendarFeedCache.activeRenderSlots++;
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
static releaseRenderSlot() {
|
|
243
|
+
if (OnCallCalendarFeedCache.activeRenderSlots > 0) {
|
|
244
|
+
OnCallCalendarFeedCache.activeRenderSlots--;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
static getActiveRenderSlots() {
|
|
248
|
+
return OnCallCalendarFeedCache.activeRenderSlots;
|
|
249
|
+
}
|
|
250
|
+
/* Bytes held by the three in-process fallback tiers. Tests and diagnostics. */
|
|
251
|
+
static getInProcessBytes() {
|
|
252
|
+
return (OnCallCalendarFeedCache.memorySegments.byteSize() +
|
|
253
|
+
OnCallCalendarFeedCache.memoryBodies.byteSize() +
|
|
254
|
+
OnCallCalendarFeedCache.memoryLastGood.byteSize());
|
|
255
|
+
}
|
|
256
|
+
// -- Schedule-level segment cache --------------------------------------
|
|
257
|
+
/*
|
|
258
|
+
* Read one schedule's resolved segments for `key`, rendering and storing
|
|
259
|
+
* them on a miss. `key` should already carry everything the result depends
|
|
260
|
+
* on (the shiftConfigVersion, the window, the day bucket); the schedule's
|
|
261
|
+
* generation is mixed in here so purgeForSchedule invalidates it.
|
|
262
|
+
*
|
|
263
|
+
* The render function's result must survive JSON.stringify/JSON.parse --
|
|
264
|
+
* Dates should be ISO strings or epoch numbers. The value handed back on a
|
|
265
|
+
* hit is the parsed JSON, so callers must not rely on class instances.
|
|
266
|
+
*
|
|
267
|
+
* A render that throws is not cached and the error propagates; a cache that
|
|
268
|
+
* throws is treated as a miss.
|
|
269
|
+
*/
|
|
270
|
+
static async getOrRenderScheduleSegments(data) {
|
|
271
|
+
const rendered = await OnCallCalendarFeedCache.getOrRenderScheduleSegmentsBatch({
|
|
272
|
+
entries: [{ scheduleId: data.scheduleId, key: data.key }],
|
|
273
|
+
ttlSeconds: data.ttlSeconds,
|
|
274
|
+
renderMissing: async (missing) => {
|
|
275
|
+
const out = new Map();
|
|
276
|
+
if (missing.length > 0) {
|
|
277
|
+
out.set(data.scheduleId, await data.render());
|
|
278
|
+
}
|
|
279
|
+
return out;
|
|
280
|
+
},
|
|
281
|
+
});
|
|
282
|
+
const value = rendered.get(data.scheduleId);
|
|
283
|
+
if (value === undefined) {
|
|
284
|
+
throw new Error("OnCallCalendarFeedCache: the schedule segment render produced no value.");
|
|
285
|
+
}
|
|
286
|
+
return value;
|
|
287
|
+
}
|
|
288
|
+
/*
|
|
289
|
+
* The same thing for MANY schedules at once, which is how a feed render
|
|
290
|
+
* actually reads: a project feed wants every schedule in the project, a
|
|
291
|
+
* personal feed every schedule its subscriber is on.
|
|
292
|
+
*
|
|
293
|
+
* Reading them one at a time meant one materialization per schedule, and
|
|
294
|
+
* each of those is a schedule query, three IN queries, an override query
|
|
295
|
+
* and a users/project lookup -- roughly seven round trips PER SCHEDULE,
|
|
296
|
+
* with the same user and project rows re-read every time, all fanned out
|
|
297
|
+
* concurrently against a fifty-connection pool. `renderMissing` is called
|
|
298
|
+
* ONCE with every schedule that missed, so the batched resolver behind it
|
|
299
|
+
* does that work in a handful of IN queries for the whole feed.
|
|
300
|
+
*
|
|
301
|
+
* Hits, in-flight renders (a schedule another feed is already expanding)
|
|
302
|
+
* and misses are separated first; only the misses reach `renderMissing`,
|
|
303
|
+
* which MUST return an entry for every id it is given. Each result is
|
|
304
|
+
* stored under its own key, so a schedule expanded for one feed is a hit
|
|
305
|
+
* for the next.
|
|
306
|
+
*/
|
|
307
|
+
static async getOrRenderScheduleSegmentsBatch(data) {
|
|
308
|
+
const result = new Map();
|
|
309
|
+
/* One entry per schedule; a repeated id is one read and one render. */
|
|
310
|
+
const entries = [];
|
|
311
|
+
const seen = new Set();
|
|
312
|
+
for (const entry of data.entries) {
|
|
313
|
+
if (seen.has(entry.scheduleId)) {
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
seen.add(entry.scheduleId);
|
|
317
|
+
entries.push(entry);
|
|
318
|
+
}
|
|
319
|
+
if (entries.length === 0) {
|
|
320
|
+
return result;
|
|
321
|
+
}
|
|
322
|
+
const effectiveKeys = new Map();
|
|
323
|
+
await Promise.all(entries.map(async (entry) => {
|
|
324
|
+
const generation = await OnCallCalendarFeedCache.getGeneration(OnCallCalendarFeedCache.scheduleGenerationKey(entry.scheduleId));
|
|
325
|
+
effectiveKeys.set(entry.scheduleId, `seg:${OnCallCalendarFeedCache.digest(`${entry.scheduleId}|${generation}|${entry.key}`)}`);
|
|
326
|
+
}));
|
|
327
|
+
const reads = await Promise.all(entries.map(async (entry) => {
|
|
328
|
+
const cached = await OnCallCalendarFeedCache.readString(effectiveKeys.get(entry.scheduleId), OnCallCalendarFeedCache.memorySegments);
|
|
329
|
+
return {
|
|
330
|
+
entry,
|
|
331
|
+
parsed: cached === null
|
|
332
|
+
? undefined
|
|
333
|
+
: OnCallCalendarFeedCache.parseJson(cached),
|
|
334
|
+
};
|
|
335
|
+
}));
|
|
336
|
+
const missing = [];
|
|
337
|
+
const joining = [];
|
|
338
|
+
/*
|
|
339
|
+
* From here to the in-flight registration below there is NO await: a
|
|
340
|
+
* concurrent caller must not be able to look at the in-flight map between
|
|
341
|
+
* this check and the registration, or two requests that missed the same
|
|
342
|
+
* key in the same instant would both render it.
|
|
343
|
+
*/
|
|
344
|
+
for (const read of reads) {
|
|
345
|
+
if (read.parsed !== undefined) {
|
|
346
|
+
result.set(read.entry.scheduleId, read.parsed);
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
if (OnCallCalendarFeedCache.inFlightRenders.has(effectiveKeys.get(read.entry.scheduleId))) {
|
|
350
|
+
joining.push(read.entry);
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
missing.push(read.entry);
|
|
354
|
+
}
|
|
355
|
+
const registered = [];
|
|
356
|
+
let renderPromise = null;
|
|
357
|
+
if (missing.length > 0) {
|
|
358
|
+
renderPromise = (async () => {
|
|
359
|
+
const rendered = await data.renderMissing(missing);
|
|
360
|
+
await Promise.all(missing.map(async (entry) => {
|
|
361
|
+
const value = rendered.get(entry.scheduleId);
|
|
362
|
+
if (value === undefined) {
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
const serialized = JSON.stringify(value);
|
|
366
|
+
if (!OnCallCalendarFeedCache.isWithinLimit(serialized, MAX_CACHED_SEGMENT_BYTES, "schedule segment")) {
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
await OnCallCalendarFeedCache.writeString(effectiveKeys.get(entry.scheduleId), serialized, data.ttlSeconds, OnCallCalendarFeedCache.memorySegments);
|
|
370
|
+
}));
|
|
371
|
+
return rendered;
|
|
372
|
+
})();
|
|
373
|
+
for (const entry of missing) {
|
|
374
|
+
const effectiveKey = effectiveKeys.get(entry.scheduleId);
|
|
375
|
+
const view = renderPromise.then((rendered) => {
|
|
376
|
+
return rendered.get(entry.scheduleId);
|
|
377
|
+
});
|
|
378
|
+
/*
|
|
379
|
+
* A view nobody joins must not become an unhandled rejection when the
|
|
380
|
+
* batch fails; the failure still reaches everyone who awaits it.
|
|
381
|
+
*/
|
|
382
|
+
view.catch(() => { });
|
|
383
|
+
OnCallCalendarFeedCache.inFlightRenders.set(effectiveKey, view);
|
|
384
|
+
registered.push(effectiveKey);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
try {
|
|
388
|
+
await Promise.all([
|
|
389
|
+
...joining.map(async (entry) => {
|
|
390
|
+
const inFlight = OnCallCalendarFeedCache.inFlightRenders.get(effectiveKeys.get(entry.scheduleId));
|
|
391
|
+
if (!inFlight) {
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
const value = (await inFlight);
|
|
395
|
+
if (value !== undefined) {
|
|
396
|
+
result.set(entry.scheduleId, value);
|
|
397
|
+
}
|
|
398
|
+
}),
|
|
399
|
+
(async () => {
|
|
400
|
+
if (!renderPromise) {
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
const rendered = await renderPromise;
|
|
404
|
+
for (const entry of missing) {
|
|
405
|
+
const value = rendered.get(entry.scheduleId);
|
|
406
|
+
if (value !== undefined) {
|
|
407
|
+
result.set(entry.scheduleId, value);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
})(),
|
|
411
|
+
]);
|
|
412
|
+
}
|
|
413
|
+
finally {
|
|
414
|
+
for (const effectiveKey of registered) {
|
|
415
|
+
OnCallCalendarFeedCache.inFlightRenders.delete(effectiveKey);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
return result;
|
|
419
|
+
}
|
|
420
|
+
// -- Body cache --------------------------------------------------------
|
|
421
|
+
static async getBody(data) {
|
|
422
|
+
const effectiveKey = await OnCallCalendarFeedCache.bodyKey(data.key, data.scope);
|
|
423
|
+
const cached = await OnCallCalendarFeedCache.readString(effectiveKey, OnCallCalendarFeedCache.memoryBodies);
|
|
424
|
+
return OnCallCalendarFeedCache.deserializeBody(cached);
|
|
425
|
+
}
|
|
426
|
+
/*
|
|
427
|
+
* Store a rendered body. Returns false, and stores nothing, when the body
|
|
428
|
+
* is over MAX_CACHED_BODY_BYTES -- the caller still serves it, it just is
|
|
429
|
+
* not kept.
|
|
430
|
+
*/
|
|
431
|
+
static async setBody(data) {
|
|
432
|
+
if (!OnCallCalendarFeedCache.isWithinLimit(data.value.body, MAX_CACHED_BODY_BYTES, "body")) {
|
|
433
|
+
return false;
|
|
434
|
+
}
|
|
435
|
+
const effectiveKey = await OnCallCalendarFeedCache.bodyKey(data.key, data.scope);
|
|
436
|
+
await OnCallCalendarFeedCache.writeString(effectiveKey, OnCallCalendarFeedCache.serializeBody(data.value), data.ttlSeconds, OnCallCalendarFeedCache.memoryBodies);
|
|
437
|
+
return true;
|
|
438
|
+
}
|
|
439
|
+
// -- Last-good (stale-while-error) -------------------------------------
|
|
440
|
+
static async getLastGood(key) {
|
|
441
|
+
const cached = await OnCallCalendarFeedCache.readString(OnCallCalendarFeedCache.lastGoodKey(key), OnCallCalendarFeedCache.memoryLastGood);
|
|
442
|
+
return OnCallCalendarFeedCache.deserializeBody(cached);
|
|
443
|
+
}
|
|
444
|
+
static async setLastGood(key, value) {
|
|
445
|
+
if (!OnCallCalendarFeedCache.isWithinLimit(value.body, MAX_CACHED_LAST_GOOD_BYTES, "last-good body")) {
|
|
446
|
+
return false;
|
|
447
|
+
}
|
|
448
|
+
await OnCallCalendarFeedCache.writeString(OnCallCalendarFeedCache.lastGoodKey(key), OnCallCalendarFeedCache.serializeBody(value), LAST_GOOD_TTL_SECONDS, OnCallCalendarFeedCache.memoryLastGood);
|
|
449
|
+
return true;
|
|
450
|
+
}
|
|
451
|
+
// -- Purges ------------------------------------------------------------
|
|
452
|
+
/*
|
|
453
|
+
* Every body cached for this user's personal feed in this project. Called
|
|
454
|
+
* on token rotation, on disable, and when the user leaves the project.
|
|
455
|
+
*/
|
|
456
|
+
static async purgeForUser(projectId, userId) {
|
|
457
|
+
await OnCallCalendarFeedCache.bumpGeneration(OnCallCalendarFeedCache.userGenerationKey(projectId, userId));
|
|
458
|
+
}
|
|
459
|
+
/*
|
|
460
|
+
* The schedule's segment cache and every body that was rendered from it:
|
|
461
|
+
* personal feeds of its members, its own shared feed, the project feed.
|
|
462
|
+
* Called from the layer / layer-user / override / attachment hooks.
|
|
463
|
+
*/
|
|
464
|
+
static async purgeForSchedule(scheduleId) {
|
|
465
|
+
await OnCallCalendarFeedCache.bumpGeneration(OnCallCalendarFeedCache.scheduleGenerationKey(scheduleId));
|
|
466
|
+
}
|
|
467
|
+
/*
|
|
468
|
+
* Every body in the project. Called when the project feed is rotated and
|
|
469
|
+
* when a member leaving triggers rotation of the shared feeds.
|
|
470
|
+
*/
|
|
471
|
+
static async purgeForProject(projectId) {
|
|
472
|
+
await OnCallCalendarFeedCache.bumpGeneration(OnCallCalendarFeedCache.projectGenerationKey(projectId));
|
|
473
|
+
}
|
|
474
|
+
// -- Keys --------------------------------------------------------------
|
|
475
|
+
/*
|
|
476
|
+
* The real key of a body: the caller's key plus the current generation of
|
|
477
|
+
* every scope the body depends on, digested so the Redis key stays short
|
|
478
|
+
* whatever the schedule count. Generations are fetched concurrently; a
|
|
479
|
+
* project feed over fifty schedules is fifty-two GETs in one round of
|
|
480
|
+
* awaits, not fifty-two round trips in sequence.
|
|
481
|
+
*/
|
|
482
|
+
static async bodyKey(key, scope) {
|
|
483
|
+
const generationKeys = [
|
|
484
|
+
OnCallCalendarFeedCache.projectGenerationKey(scope.projectId),
|
|
485
|
+
];
|
|
486
|
+
if (scope.userId) {
|
|
487
|
+
generationKeys.push(OnCallCalendarFeedCache.userGenerationKey(scope.projectId, scope.userId));
|
|
488
|
+
}
|
|
489
|
+
for (const scheduleId of OnCallCalendarFeedCache.uniqueSorted(scope.scheduleIds || [])) {
|
|
490
|
+
generationKeys.push(OnCallCalendarFeedCache.scheduleGenerationKey(scheduleId));
|
|
491
|
+
}
|
|
492
|
+
const generations = await Promise.all(generationKeys.map((generationKey) => {
|
|
493
|
+
return OnCallCalendarFeedCache.getGeneration(generationKey);
|
|
494
|
+
}));
|
|
495
|
+
return `body:${OnCallCalendarFeedCache.digest(`${key}|${generationKeys
|
|
496
|
+
.map((generationKey, index) => {
|
|
497
|
+
return `${generationKey}=${generations[index]}`;
|
|
498
|
+
})
|
|
499
|
+
.join("|")}`)}`;
|
|
500
|
+
}
|
|
501
|
+
static lastGoodKey(key) {
|
|
502
|
+
return `lastgood:${OnCallCalendarFeedCache.digest(key)}`;
|
|
503
|
+
}
|
|
504
|
+
static projectGenerationKey(projectId) {
|
|
505
|
+
return `gen:project:${projectId}`;
|
|
506
|
+
}
|
|
507
|
+
static userGenerationKey(projectId, userId) {
|
|
508
|
+
return `gen:user:${projectId}:${userId}`;
|
|
509
|
+
}
|
|
510
|
+
static scheduleGenerationKey(scheduleId) {
|
|
511
|
+
return `gen:schedule:${scheduleId}`;
|
|
512
|
+
}
|
|
513
|
+
static digest(value) {
|
|
514
|
+
return createHash("sha256")
|
|
515
|
+
.update(value, "utf8")
|
|
516
|
+
.digest("hex")
|
|
517
|
+
.slice(0, 40);
|
|
518
|
+
}
|
|
519
|
+
static uniqueSorted(values) {
|
|
520
|
+
return Array.from(new Set(values)).sort();
|
|
521
|
+
}
|
|
522
|
+
// -- Generations -------------------------------------------------------
|
|
523
|
+
/*
|
|
524
|
+
* Redis first; the in-memory copy only when Redis fails. Reading memory
|
|
525
|
+
* first would let a stale local generation hide a purge another process
|
|
526
|
+
* made.
|
|
527
|
+
*/
|
|
528
|
+
static async getGeneration(generationKey) {
|
|
529
|
+
try {
|
|
530
|
+
const value = await GlobalCache.getString(ON_CALL_CALENDAR_FEED_CACHE_NAMESPACE, generationKey);
|
|
531
|
+
if (value) {
|
|
532
|
+
return value;
|
|
533
|
+
}
|
|
534
|
+
return DEFAULT_GENERATION;
|
|
535
|
+
}
|
|
536
|
+
catch (err) {
|
|
537
|
+
OnCallCalendarFeedCache.logCacheFailure("read generation", err);
|
|
538
|
+
return (OnCallCalendarFeedCache.memoryGenerations.get(generationKey) ||
|
|
539
|
+
DEFAULT_GENERATION);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
/*
|
|
543
|
+
* A fresh random token, not an increment: GlobalCache has no INCR, and a
|
|
544
|
+
* value nobody can predict cannot collide with a stale one. Written to
|
|
545
|
+
* memory unconditionally so a purge made during a Redis outage is honoured
|
|
546
|
+
* by this process straight away; the Redis write is best effort and logged.
|
|
547
|
+
* Never throws -- hooks call this and must not fail over a cache.
|
|
548
|
+
*/
|
|
549
|
+
static async bumpGeneration(generationKey) {
|
|
550
|
+
const generation = `${Date.now().toString(36)}-${randomBytes(6).toString("hex")}`;
|
|
551
|
+
OnCallCalendarFeedCache.memoryGenerations.set(generationKey, generation, GENERATION_TTL_SECONDS * 1000);
|
|
552
|
+
try {
|
|
553
|
+
await GlobalCache.setString(ON_CALL_CALENDAR_FEED_CACHE_NAMESPACE, generationKey, generation, { expiresInSeconds: GENERATION_TTL_SECONDS });
|
|
554
|
+
}
|
|
555
|
+
catch (err) {
|
|
556
|
+
OnCallCalendarFeedCache.logCacheFailure("write generation", err);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
// -- Storage tiers -----------------------------------------------------
|
|
560
|
+
static async readString(key, memory) {
|
|
561
|
+
var _a;
|
|
562
|
+
try {
|
|
563
|
+
return await GlobalCache.getString(ON_CALL_CALENDAR_FEED_CACHE_NAMESPACE, key);
|
|
564
|
+
}
|
|
565
|
+
catch (err) {
|
|
566
|
+
OnCallCalendarFeedCache.logCacheFailure("read", err);
|
|
567
|
+
return (_a = memory.get(key)) !== null && _a !== void 0 ? _a : null;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
static async writeString(key, value, ttlSeconds, memory) {
|
|
571
|
+
const ttl = Math.max(1, Math.floor(ttlSeconds));
|
|
572
|
+
try {
|
|
573
|
+
await GlobalCache.setString(ON_CALL_CALENDAR_FEED_CACHE_NAMESPACE, key, value, { expiresInSeconds: ttl });
|
|
574
|
+
}
|
|
575
|
+
catch (err) {
|
|
576
|
+
OnCallCalendarFeedCache.logCacheFailure("write", err);
|
|
577
|
+
memory.set(key, value, ttl * 1000);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
// -- Serialisation -----------------------------------------------------
|
|
581
|
+
/*
|
|
582
|
+
* Refusals are logged: a feed that is silently never cached looks exactly
|
|
583
|
+
* like a feed that is cached and busy, and the only symptom is a render on
|
|
584
|
+
* every poll.
|
|
585
|
+
*/
|
|
586
|
+
static isWithinLimit(value, maxBytes, what) {
|
|
587
|
+
const bytes = Buffer.byteLength(value, "utf8");
|
|
588
|
+
if (bytes <= maxBytes) {
|
|
589
|
+
return true;
|
|
590
|
+
}
|
|
591
|
+
logger.debug(`OnCallCalendarFeedCache: not caching a ${what} of ${bytes} bytes (limit ${maxBytes}).`);
|
|
592
|
+
return false;
|
|
593
|
+
}
|
|
594
|
+
static serializeBody(value) {
|
|
595
|
+
const serialized = {
|
|
596
|
+
body: value.body,
|
|
597
|
+
etag: value.etag,
|
|
598
|
+
lastModified: value.lastModified.toISOString(),
|
|
599
|
+
};
|
|
600
|
+
return JSON.stringify(serialized);
|
|
601
|
+
}
|
|
602
|
+
/*
|
|
603
|
+
* A corrupt or foreign entry is a miss, never an error: the worst case is
|
|
604
|
+
* one extra render, which is what a miss costs anyway.
|
|
605
|
+
*/
|
|
606
|
+
static deserializeBody(cached) {
|
|
607
|
+
if (cached === null) {
|
|
608
|
+
return null;
|
|
609
|
+
}
|
|
610
|
+
const parsed = OnCallCalendarFeedCache.parseJson(cached);
|
|
611
|
+
if (!parsed ||
|
|
612
|
+
typeof parsed !== "object" ||
|
|
613
|
+
typeof parsed.body !== "string" ||
|
|
614
|
+
typeof parsed.etag !== "string" ||
|
|
615
|
+
typeof parsed.lastModified !== "string") {
|
|
616
|
+
return null;
|
|
617
|
+
}
|
|
618
|
+
const lastModified = new Date(parsed.lastModified);
|
|
619
|
+
if (Number.isNaN(lastModified.getTime())) {
|
|
620
|
+
return null;
|
|
621
|
+
}
|
|
622
|
+
return {
|
|
623
|
+
body: parsed.body,
|
|
624
|
+
etag: parsed.etag,
|
|
625
|
+
lastModified,
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
static parseJson(value) {
|
|
629
|
+
try {
|
|
630
|
+
return JSON.parse(value);
|
|
631
|
+
}
|
|
632
|
+
catch (_a) {
|
|
633
|
+
return undefined;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
// -- Logging -----------------------------------------------------------
|
|
637
|
+
/*
|
|
638
|
+
* Debug, not warn: when Redis is down every feed request takes this path
|
|
639
|
+
* several times, and Redis being down is already alarmed on by the code
|
|
640
|
+
* that owns the connection. The message never carries a key -- keys are
|
|
641
|
+
* digests of token hashes, which is one hop closer to a token than a log
|
|
642
|
+
* should get.
|
|
643
|
+
*/
|
|
644
|
+
static logCacheFailure(operation, err) {
|
|
645
|
+
logger.debug(`OnCallCalendarFeedCache: ${operation} failed, using in-process fallback`);
|
|
646
|
+
logger.debug(err);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
OnCallCalendarFeedCache.renderConcurrency = DEFAULT_RENDER_CONCURRENCY;
|
|
650
|
+
OnCallCalendarFeedCache.activeRenderSlots = 0;
|
|
651
|
+
OnCallCalendarFeedCache.memorySegments = new MemoryStringStore(MEMORY_MAX_ENTRIES, MEMORY_MAX_BYTES);
|
|
652
|
+
OnCallCalendarFeedCache.memoryBodies = new MemoryStringStore(MEMORY_MAX_ENTRIES, MEMORY_MAX_BYTES);
|
|
653
|
+
OnCallCalendarFeedCache.memoryLastGood = new MemoryStringStore(MEMORY_MAX_ENTRIES, MEMORY_MAX_BYTES);
|
|
654
|
+
OnCallCalendarFeedCache.memoryGenerations = new InMemoryTTLCache(MEMORY_GENERATION_MAX_ENTRIES);
|
|
655
|
+
/*
|
|
656
|
+
* In-flight renders by effective key, so two requests that miss the same
|
|
657
|
+
* segment key in the same instant share one expansion instead of racing to
|
|
658
|
+
* do it twice. Per process; Redis dedupes nothing here, and does not need
|
|
659
|
+
* to -- the point is not to double the CPU spent on one miss.
|
|
660
|
+
*/
|
|
661
|
+
OnCallCalendarFeedCache.inFlightRenders = new Map();
|
|
662
|
+
export default OnCallCalendarFeedCache;
|
|
663
|
+
//# sourceMappingURL=OnCallCalendarFeedCache.js.map
|