| 'use strict'; |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| function buildDedupMaterial(eventType, title, coalesceKey) { |
| return coalesceKey ? `coalesce:${coalesceKey}` : `${eventType}:${title ?? ''}`; |
| } |
|
|
| const failOpenFallbackDedup = new Map(); |
| const MAX_FAIL_OPEN_FALLBACK_KEYS = 10_000; |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| function classifySetNxResult(result) { |
| if (result === 'OK') return 'new'; |
| if (result === null) return 'duplicate'; |
| if (result === 'disabled') return 'disabled'; |
| return 'error'; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| function normalizeNotificationSeverity(severity) { |
| return String(severity ?? 'high').trim().toLowerCase() || 'high'; |
| } |
|
|
| function isHighPriorityNotificationSeverity(severity) { |
| const normalized = normalizeNotificationSeverity(severity); |
| return normalized === 'critical' || normalized === 'high'; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| function shouldPublishAfterDedupResult(dedupResult, severity) { |
| if (dedupResult === 'new') return true; |
| if (dedupResult === 'duplicate') return false; |
| if (dedupResult === 'error') return isHighPriorityNotificationSeverity(severity); |
| return false; |
| } |
|
|
| function normalizeTelemetryToken(raw) { |
| const value = String(raw ?? 'unknown').trim().toLowerCase(); |
| return (value || 'unknown').replace(/[^a-z0-9_.:-]+/g, '_').slice(0, 80); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| function buildSetNxErrorTelemetryLine({ surface, eventType, severity, action, reason = 'setnx_error' }) { |
| return `[notifications] wm_notification_dedup_setnx_error ` + |
| `count=1 ` + |
| `surface=${normalizeTelemetryToken(surface)} ` + |
| `event_type=${normalizeTelemetryToken(eventType)} ` + |
| `severity=${normalizeTelemetryToken(severity)} ` + |
| `action=${normalizeTelemetryToken(action)} ` + |
| `reason=${normalizeTelemetryToken(reason)}`; |
| } |
|
|
| function normalizeDedupResult(result) { |
| if (result === 'new' || result === 'duplicate' || result === 'error' || result === 'disabled') return result; |
| if (result === true) return 'new'; |
| if (result === false) return 'duplicate'; |
| return classifySetNxResult(result); |
| } |
|
|
| function reserveFailOpenFallback(key, ttlSeconds, nowMs) { |
| if (!key || !Number.isFinite(ttlSeconds) || ttlSeconds <= 0) return false; |
| const existing = failOpenFallbackDedup.get(key); |
| if (existing && existing > nowMs) return true; |
|
|
| failOpenFallbackDedup.set(key, nowMs + ttlSeconds * 1000); |
| for (const [seenKey, expiresAt] of failOpenFallbackDedup) { |
| if (expiresAt <= nowMs || failOpenFallbackDedup.size > MAX_FAIL_OPEN_FALLBACK_KEYS) { |
| failOpenFallbackDedup.delete(seenKey); |
| } |
| if (failOpenFallbackDedup.size <= MAX_FAIL_OPEN_FALLBACK_KEYS) break; |
| } |
| return false; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| function recordDedupOutcome(dedupResult, options) { |
| const result = normalizeDedupResult(dedupResult); |
| const severity = normalizeNotificationSeverity(options?.severity); |
| if (result === 'new') { |
| return { shouldPublish: true, isDuplicate: false, dedupResult: result, action: 'publish', severity }; |
| } |
| if (result === 'duplicate') { |
| return { shouldPublish: false, isDuplicate: true, dedupResult: result, action: 'dedup_hit', severity }; |
| } |
| if (result === 'disabled') { |
| return { shouldPublish: false, isDuplicate: false, dedupResult: result, action: 'disabled', severity }; |
| } |
|
|
| const highPriority = isHighPriorityNotificationSeverity(severity); |
| let shouldPublish = highPriority; |
| let action = highPriority ? 'fail_open' : 'fail_closed'; |
| if (highPriority && reserveFailOpenFallback( |
| options?.fallbackKey, |
| Number(options?.fallbackTtlSeconds), |
| Number(options?.nowMs) || Date.now(), |
| )) { |
| shouldPublish = false; |
| action = 'fallback_suppressed'; |
| } |
| const reason = 'setnx_error'; |
| const line = buildSetNxErrorTelemetryLine({ |
| surface: options?.surface, |
| eventType: options?.eventType, |
| severity, |
| action, |
| reason, |
| }); |
| if (typeof options?.emitTelemetry === 'function') { |
| options.emitTelemetry({ line, action, reason, severity }); |
| } |
| return { shouldPublish, isDuplicate: action === 'fallback_suppressed', dedupResult: result, action, severity }; |
| } |
|
|
| module.exports = { |
| buildDedupMaterial, |
| classifySetNxResult, |
| normalizeNotificationSeverity, |
| shouldPublishAfterDedupResult, |
| buildSetNxErrorTelemetryLine, |
| recordDedupOutcome, |
| }; |
|
|