|
| 1 | +/** |
| 2 | + * Pure builder for the `provisionedPollers` block of the |
| 3 | + * sfcore.analysis.generated.v1 analytics event. Consumed by the sf-core |
| 4 | + * framework runner's getAnalysisEventDetails(). |
| 5 | + * |
| 6 | + * Contract (mirrors sandboxes/mcp analytics builders): |
| 7 | + * - Fixed keys only — never a user-authored string (the poller group NAME |
| 8 | + * is never reported, only its presence count). |
| 9 | + * - Explicit-only + omit-empty: a key appears only when a user set it. |
| 10 | + * - HARD REQUIREMENT: total function — never throws; malformed input |
| 11 | + * degrades to {} so analytics can never break a user command. |
| 12 | + */ |
| 13 | + |
| 14 | +const isObj = (v) => v !== null && typeof v === 'object' && !Array.isArray(v) |
| 15 | + |
| 16 | +const sortedUniqueNumbers = (values) => |
| 17 | + [...new Set(values.filter((n) => typeof n === 'number'))].sort( |
| 18 | + (a, b) => a - b, |
| 19 | + ) |
| 20 | + |
| 21 | +const SOURCES = ['sqs', 'kafka', 'msk'] |
| 22 | +// `group` (PollerGroupName) exists only on kafka/msk; the sqs schema rejects it, |
| 23 | +// so a group on sqs is invalid config and is never reported. |
| 24 | +const SOURCES_WITH_GROUP = new Set(['kafka', 'msk']) |
| 25 | + |
| 26 | +export const buildProvisionedPollersAnalytics = (config) => { |
| 27 | + try { |
| 28 | + const functions = isObj(config?.functions) |
| 29 | + ? Object.values(config.functions) |
| 30 | + : [] |
| 31 | + const perSource = {} |
| 32 | + for (const source of SOURCES) { |
| 33 | + const values = [] |
| 34 | + for (const fn of functions) { |
| 35 | + const events = Array.isArray(fn?.events) ? fn.events : [] |
| 36 | + for (const event of events) { |
| 37 | + if (!isObj(event?.[source])) continue |
| 38 | + const value = event[source].provisionedPollers |
| 39 | + if (value !== undefined) values.push(value) |
| 40 | + } |
| 41 | + } |
| 42 | + const objects = values.filter(isObj) |
| 43 | + const block = {} |
| 44 | + if (objects.length > 0) block.configured = objects.length |
| 45 | + const disabled = values.filter((v) => v === false).length |
| 46 | + if (disabled > 0) block.disabled = disabled |
| 47 | + const min = sortedUniqueNumbers(objects.map((o) => o.min)) |
| 48 | + if (min.length > 0) block.min = min |
| 49 | + const max = sortedUniqueNumbers(objects.map((o) => o.max)) |
| 50 | + if (max.length > 0) block.max = max |
| 51 | + if (SOURCES_WITH_GROUP.has(source)) { |
| 52 | + const groups = objects.filter( |
| 53 | + (o) => typeof o.group === 'string' && o.group.length > 0, |
| 54 | + ).length |
| 55 | + if (groups > 0) block.groups = groups |
| 56 | + } |
| 57 | + if (Object.keys(block).length > 0) perSource[source] = block |
| 58 | + } |
| 59 | + return Object.keys(perSource).length > 0 |
| 60 | + ? { provisionedPollers: perSource } |
| 61 | + : {} |
| 62 | + } catch { |
| 63 | + return {} |
| 64 | + } |
| 65 | +} |
0 commit comments