@devicechain/widgets 0.26.0-rc.1 → 0.27.0-rc.1
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/dist/aggregate-feed.d.ts +5 -2
- package/dist/binding-policy.d.ts +1 -0
- package/dist/chunks/{aggregate-feed-7JBQIYJE.js → aggregate-feed-HCF5FYIJ.js} +14 -4
- package/dist/chunks/aggregate-feed-HCF5FYIJ.js.map +7 -0
- package/dist/chunks/{aggregate-widgets-72HMPMBU.js → aggregate-widgets-EVJNAA26.js} +5 -5
- package/dist/chunks/{chunk-NYHNQ5VR.js → chunk-GUCEPNGM.js} +6 -2
- package/dist/chunks/{chunk-NYHNQ5VR.js.map → chunk-GUCEPNGM.js.map} +2 -2
- package/dist/chunks/chunk-QHTO5ZEM.js +35 -0
- package/dist/chunks/chunk-QHTO5ZEM.js.map +7 -0
- package/dist/chunks/{compare-feed-5OLZHFRL.js → compare-feed-MLHG7YFN.js} +8 -8
- package/dist/chunks/{event-markers-feed-B3MVFYUT.js → event-markers-feed-DMRW5GV5.js} +2 -2
- package/dist/chunks/{fleet-feed-D4T3LC25.js → fleet-feed-AKJ7QIMP.js} +5 -5
- package/dist/chunks/{history-widgets-MBR4YRBV.js → history-widgets-DZBMNMEX.js} +2 -2
- package/dist/chunks/{presence-widgets-M5VGG3OO.js → presence-widgets-7OGANOLB.js} +2 -2
- package/dist/host-context.d.ts +2 -0
- package/dist/host-context.js +13 -0
- package/dist/host-context.js.map +7 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +153 -173
- package/dist/index.js.map +4 -4
- package/package.json +11 -7
- package/dist/chunks/aggregate-feed-7JBQIYJE.js.map +0 -7
- /package/dist/chunks/{aggregate-widgets-72HMPMBU.js.map → aggregate-widgets-EVJNAA26.js.map} +0 -0
- /package/dist/chunks/{compare-feed-5OLZHFRL.js.map → compare-feed-MLHG7YFN.js.map} +0 -0
- /package/dist/chunks/{event-markers-feed-B3MVFYUT.js.map → event-markers-feed-DMRW5GV5.js.map} +0 -0
- /package/dist/chunks/{fleet-feed-D4T3LC25.js.map → fleet-feed-AKJ7QIMP.js.map} +0 -0
- /package/dist/chunks/{history-widgets-MBR4YRBV.js.map → history-widgets-DZBMNMEX.js.map} +0 -0
- /package/dist/chunks/{presence-widgets-M5VGG3OO.js.map → presence-widgets-7OGANOLB.js.map} +0 -0
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/dashboard-renderer.tsx", "../src/connected-widget.tsx", "../src/builtin-registry.ts", "../src/widgets/aggregate-lazy.tsx", "../src/builtin-descriptors.ts", "../src/widgets/alarm-lazy.tsx", "../src/widgets/control-lazy.tsx", "../src/widgets/history-lazy.tsx", "../src/widgets/presence-lazy.tsx", "../src/widgets/selection-lazy.tsx", "../src/widgets/gauge.tsx", "../src/widgets/no-reading-lazy.tsx", "../src/widgets/image.tsx", "../src/widgets/label.tsx", "../src/widgets/latest-card.tsx", "../src/widgets/level-lazy.tsx", "../src/widgets/map.tsx", "../src/
|
|
4
|
-
"sourcesContent": ["// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// DashboardRenderer maps a parsed DashboardDefinition onto a real CSS Grid of SQUARE cells: the\n// canvas is `display:grid` with `repeat(columns, 1fr)`, so the board FILLS whatever width its\n// container gives it, and every row is as tall as a column is wide (the cell size is computed in\n// CSS from the grid's own width, `100cqw`, so it needs no measurement and has no first-frame\n// flash). A `grid` widget occupies its footprint (`grid-column`/`grid-row`); a `relative` widget\n// is drawn over its host's area at the host's anchor point, offset in cell pitches, and above\n// every grid widget. Gutters and padding are lengths or spacing tokens scaled by the density;\n// each widget's frame is the canvas default merged with its own (resolveFrame).\n//\n// Adaptive columns and reflow: the board measures its CONTAINER (not the window), and while a\n// cell at the authored column count is at least `minCellSize` it renders as authored and the\n// cells stretch. Narrower than that the column count drops to what fits and the base layout is\n// poured into it in reading order (effectiveLayout), each widget clamped into the span limits\n// its descriptor declares; below STACK_BELOW_WIDTH (a phone) that is a single column. A breakpoint the author defined for the width wins over the automatic\n// reflow. Until the container has a measured width the authored layout is drawn. Container sizing\n// (fill / fixed-width / fixed-height) is a mount knob the host may override via the `sizing`\n// prop. It is view-only; the canvas editor lives in the console. This is the shared viewer the\n// console and the reference /dash app mount.\n\nimport {\n anchorFraction,\n DEFAULT_CANVAS_DENSITY,\n DEFAULT_TIME_RANGE_SECONDS,\n defaultHistoryWindow,\n effectiveLayout,\n historyWindowFor,\n initialTimeRange,\n fetchWidgetHistory,\n layoutShape,\n resolveFrame,\n resolvePlacement,\n resolveWidgetDatasource,\n spanLimitsOfLayout,\n UNKNOWN_WIDGET_TYPE,\n type CanvasBackground,\n type CanvasDensity,\n type CanvasGrid,\n type CanvasSizing,\n type DashboardDefinition,\n type GridLength,\n type GridPlacement,\n type RelativePlacement,\n type WidgetActions,\n type WidgetDataSource,\n type MeasurementSample,\n type SlotBinding,\n type TimeRangeState,\n type WidgetFrameSpec,\n type WidgetInstance,\n} from '@devicechain/dashboards';\nimport {\n densityScale,\n tokenStyle,\n WidgetDensityProvider,\n WidgetFrameStyleProvider,\n WidgetTimeRangeProvider,\n WidgetTokenStyles,\n type WidgetRegistry,\n} from '@devicechain/widget-sdk';\nimport { Fragment, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, type CSSProperties, type ReactNode, type RefObject } from 'react';\n\nimport { measurementSpan } from './binding-policy';\nimport { ConnectedWidget } from './connected-widget';\nimport {\n type WidgetCandidates,\n WidgetCandidatesProvider,\n type WidgetSelect,\n WidgetSelectProvider,\n WidgetSubjectProvider,\n WidgetThemeRootProvider,\n WidgetTimeZoneProvider,\n} from '@devicechain/widget-sdk';\nimport { defaultWidgetRegistry } from './default-registry';\n\nexport interface DashboardRendererProps {\n definition: DashboardDefinition;\n hub: WidgetDataSource;\n // The widget registry that resolves every widget's component, channel, binding policy and\n // history eligibility. Omitted = the built-ins. A host with extension packages passes the\n // SAME registry it parsed `definition` with (parseDashboardDefinition(raw, { catalog:\n // registry.catalog })), so an extension widget is recognized and rendered consistently.\n registry?: WidgetRegistry;\n // The action seam (writes) for acting widgets (alarm ack/clear, command send). Omit\n // for a strictly read-only mount; the same instance as `hub` when the runtime provides\n // both (DashboardHub / SyntheticDataSource implement WidgetActions).\n actions?: WidgetActions;\n // Whether to backfill each widget from bucketedMeasurements (a real backend call).\n // Default true; set false for offline preview, where the data source (e.g.\n // SyntheticDataSource) supplies its own history and the backend must not be hit.\n seedHistory?: boolean;\n // The settled slot manifest (useResolvedBindings). Every widget's `slot` selector is\n // resolved through it HERE, before the widget subscribes, to the bound device or anchor\n // \u2014 or to an explicit `unbound` selector when the slot has no binding. The hub holds no\n // bindings, so a host keeps ONE hub (useDashboardHub) and a change to this map\n // re-subscribes only the widgets whose slot moved. Omitted = no slot is bound.\n bindings?: Record<string, SlotBinding>;\n // Host override for the definition's container sizing (the embed knob \u2014 a host can\n // force a dashboard authored `fill` into a fixed-px box, or vice versa). Omitted \u2192\n // the definition's own `canvas.sizing`.\n sizing?: CanvasSizing;\n // The selection callback (ADR-039 selection amendment): a widget (e.g. an alarm-table\n // originator drill) calls it to re-point a slot; the host accumulates it into the\n // selection overlay that produces `bindings`. Omit for a static dashboard \u2014 widgets\n // then render no drill affordance.\n select?: WidgetSelect;\n // The candidate provider (useSlotCandidates) an entity-selector widget reads to offer a\n // target slot's options. Omit alongside `select` for a static/edit/preview mount \u2014 the\n // selector then renders inert.\n candidates?: WidgetCandidates;\n // The IANA zone widgets print instants in. Omit for the viewer's own zone (every live\n // host); a host replaying a recording pins one so the board agrees with the recording.\n timeZone?: string;\n // The element chart colors are read from, when the host scopes its design tokens to a\n // container rather than the document root. Omit for the document root (every other host).\n themeRoot?: Element;\n // A viewer's density override (the /dash app's `?density=`). Wins over the definition's\n // authored `canvas.density`, which wins over `comfortable`. Density scales every size token\n // (font, spacing) and the floor of the value-font curve, never the curve itself.\n density?: CanvasDensity;\n // The board's time range: the span its time-series widgets draw, and whether the viewer has\n // frozen it. Owned by the host (useBoardTimeRange + TimeRangeBar) so the control can live in the\n // host's own header. Omitted = live over the definition's default span (or one hour), with no\n // control -- a static embed, the replay page, an edit preview.\n timeRange?: TimeRangeState;\n}\n\nexport function DashboardRenderer({\n definition,\n hub,\n registry: registryProp,\n actions,\n seedHistory = true,\n bindings,\n sizing,\n select,\n candidates,\n timeZone,\n themeRoot,\n density,\n timeRange,\n}: DashboardRendererProps) {\n // Each widget with its slot resolved to a concrete selector. Recomputed per render;\n // that is cheap, and every channel keys its subscription on the selector's VALUE, so a\n // widget whose concrete selector did not change keeps its subscription.\n const widgets = useMemo(() => resolveWidgets(definition.widgets, bindings), [definition.widgets, bindings]);\n const registry = registryProp ?? defaultWidgetRegistry();\n // The default is derived, not stored: a host with no control still gets the board's own span.\n const defaultSeconds = definition.timeRange?.defaultSeconds;\n const range = useMemo(\n () => timeRange ?? initialTimeRange(defaultSeconds),\n [timeRange, defaultSeconds],\n );\n const { histories, reseed } = useWidgetHistories(widgets, seedHistory, registry, range);\n // Each fixed window is its own board state: entering, leaving or moving one remounts the widgets,\n // so no live buffer (samples from after the window) and no held snapshot carries across it.\n const windowKey = windowTag(range);\n\n const { grid, background: bg, frame: canvasFrame } = definition.canvas;\n const effectiveSizing = sizing ?? definition.canvas.sizing;\n const effectiveDensity = density ?? definition.canvas.density ?? DEFAULT_CANVAS_DENSITY;\n const scale = densityScale(effectiveDensity);\n // The width is kept only when it changes the layout's shape (breakpoint, columns, single\n // column): within one shape the cells stretch through CSS, so a resize redraws nothing until\n // a column comes or goes.\n const { canvas } = definition;\n const shapeKey = useCallback((width: number) => JSON.stringify(layoutShape(canvas, width, scale)), [canvas, scale]);\n const [boardRef, containerWidth] = useContainerWidth<HTMLDivElement>(shapeKey);\n const layout = useMemo(\n () =>\n effectiveLayout(definition, containerWidth, {\n scale,\n limitsOf: (w) => (w.type === UNKNOWN_WIDGET_TYPE ? undefined : spanLimitsOfLayout(registry.descriptor(w.type)?.layout)),\n }),\n [definition, containerWidth, scale, registry],\n );\n const { breakpoint, columns } = layout;\n const lengths = gridCss(grid, columns);\n\n return (\n <div\n ref={boardRef}\n data-density={effectiveDensity}\n data-columns={columns}\n data-time-paused={range.paused ? '' : undefined}\n style={{ ...sizingStyle(effectiveSizing, bg), ...tokenStyle(scale) }}\n >\n <WidgetTokenStyles />\n <WidgetDensityProvider scale={scale}>\n <WidgetThemeRootProvider root={themeRoot}>\n <WidgetTimeZoneProvider timeZone={timeZone}>\n <WidgetTimeRangeProvider range={range}>\n <WidgetSelectProvider select={select}>\n <WidgetCandidatesProvider candidates={candidates}>\n <div style={{ padding: lengths.padding }}>\n {/* The query container: its width is the grid's, so 100cqw below is the grid width. */}\n <div style={{ containerType: 'inline-size' }}>\n <div\n data-grid=\"\"\n style={{\n display: 'grid',\n gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,\n gridAutoRows: CELL,\n columnGap: lengths.gutterX,\n rowGap: lengths.gutterY,\n width: '100%',\n ...({ '--dc-cell': lengths.cell } as CSSProperties),\n }}\n >\n <PlacedWidgets\n widgets={widgets}\n breakpoint={breakpoint}\n columns={columns}\n grid={layout.grid}\n lengths={lengths}\n render={(widget) => (\n <WidgetFrameStyleProvider frame={resolveFrame(canvasFrame, widgetFrame(widget))}>\n <WidgetSubjectProvider label={widgetSubjectLabel(widget)}>\n <ConnectedWidget\n key={windowKey}\n widget={widget}\n hub={hub}\n registry={registry}\n actions={actions}\n initialSamples={histories[widget.id]?.samples}\n initialSamplesAsOf={histories[widget.id]?.asOf}\n onReconnect={() => reseed(widget.id)}\n />\n </WidgetSubjectProvider>\n </WidgetFrameStyleProvider>\n )}\n />\n </div>\n </div>\n </div>\n </WidgetCandidatesProvider>\n </WidgetSelectProvider>\n </WidgetTimeRangeProvider>\n </WidgetTimeZoneProvider>\n </WidgetThemeRootProvider>\n </WidgetDensityProvider>\n </div>\n );\n}\n\n// The live cell size, as the grid element defines it.\nconst CELL = 'var(--dc-cell)';\n\n// The grid's lengths as CSS: px multiply by the density scale like every size token, and a\n// spacing token reads the board's own variable.\nexport interface GridCss {\n gutterX: string;\n gutterY: string;\n padding: string;\n // The live cell size: the grid's width less its gutters, shared by the columns. Read inside\n // the query container, so `100cqw` is the grid's width.\n cell: string;\n}\n\nexport function gridLengthCss(len: GridLength): string {\n if (typeof len === 'number') return `calc(${len}px * var(--dc-scale, 1))`;\n return len === 'space-0' ? '0px' : `var(--dc-${len})`;\n}\n\nexport function gridCss(grid: CanvasGrid, columns: number): GridCss {\n const g = grid.gutter;\n const gutterX = gridLengthCss(typeof g === 'object' ? g.x : g);\n const gutterY = gridLengthCss(typeof g === 'object' ? g.y : g);\n const p = grid.padding;\n const padding =\n typeof p === 'object'\n ? [p.top, p.right, p.bottom, p.left].map(gridLengthCss).join(' ')\n : gridLengthCss(p);\n return { gutterX, gutterY, padding, cell: `calc((100cqw - ${columns - 1} * ${gutterX}) / ${columns})` };\n}\n\n// The frame override a widget carries (a placeholder carries none: its stored frame is the\n// newer release's to read).\nfunction widgetFrame(widget: WidgetInstance): WidgetFrameSpec | undefined {\n return widget.type === UNKNOWN_WIDGET_TYPE ? undefined : widget.frame;\n}\n\n// gridItemStyle maps a grid placement to a grid-item style. col/row are 0-based cells \u2192\n// CSS's 1-based `col+1 / span cols`. It CLAMPS the placement into the grid's column count: a\n// footprint whose `col`/`cols` overruns `columns` (a hand-authored or imported one; the lint\n// reports it) would otherwise land in implicit `auto` tracks CSS appends past the `1fr`\n// columns \u2014 unequal widths + horizontal overflow instead of a clamped placement. Rows are\n// unbounded (implicit rows are the intended vertical growth), so only columns clamp.\nexport function gridItemStyle(p: GridPlacement, columns: number): CSSProperties {\n const col = Math.min(Math.max(0, p.col), columns - 1);\n const cols = Math.min(Math.max(1, p.cols), columns - col);\n return {\n gridColumn: `${col + 1} / span ${cols}`,\n gridRow: `${p.row + 1} / span ${p.rows}`,\n // Let a grid item shrink below its content's intrinsic size so a wide chart/table\n // fits its track instead of overflowing it.\n minWidth: 0,\n minHeight: 0,\n };\n}\n\n// Relative widgets paint above every grid widget, in `layer` order among themselves.\nconst RELATIVE_Z = 100;\n\n// relativeBoxStyle positions a relative widget inside its host's box (the containing block): the\n// host's anchor point (a percentage of the host), minus this widget's own `self` point (a\n// percentage of itself, via translate), plus the offset in cell pitches.\nexport function relativeBoxStyle(p: RelativePlacement, lengths: Pick<GridCss, 'gutterX' | 'gutterY'>): CSSProperties {\n const a = anchorFraction(p.anchor);\n const s = anchorFraction(p.self ?? p.anchor);\n const span = (n: number, gutter: string) => `calc(${n} * ${CELL} + ${n - 1} * ${gutter})`;\n const pitches = (n: number, gutter: string) => `${n} * (${CELL} + ${gutter})`;\n const fill = 'fill' in p.size;\n return {\n position: 'absolute',\n left: `calc(${a.fx * 100}% + ${pitches(p.offset?.x ?? 0, lengths.gutterX)})`,\n top: `calc(${a.fy * 100}% + ${pitches(p.offset?.y ?? 0, lengths.gutterY)})`,\n width: fill ? '100%' : span((p.size as { cols: number }).cols, lengths.gutterX),\n height: fill ? '100%' : span((p.size as { rows: number }).rows, lengths.gutterY),\n transform: `translate(${-s.fx * 100}%, ${-s.fy * 100}%)`,\n zIndex: RELATIVE_Z + (p.layer ?? 0),\n pointerEvents: 'auto',\n };\n}\n\n// PlacedWidgets draws every widget at a breakpoint: each grid widget as a grid item, and each\n// relative widget inside a layer over its host's grid area (a relative widget hosted on another\n// relative widget is drawn inside that one's box, one level deep, as the parser allows).\nfunction PlacedWidgets({\n widgets,\n breakpoint,\n columns,\n grid,\n lengths,\n render,\n}: {\n widgets: WidgetInstance[];\n breakpoint: string;\n columns: number;\n // Where each grid widget is DRAWN: its authored footprint, or the reflowed one.\n grid: ReadonlyMap<string, GridPlacement>;\n lengths: GridCss;\n render: (widget: WidgetInstance) => ReactNode;\n}) {\n const placed = widgets.map((w) => ({ widget: w, placement: resolvePlacement(w.layout, breakpoint) }));\n const dependents = new Map<string, { widget: WidgetInstance; placement: RelativePlacement }[]>();\n for (const { widget, placement } of placed) {\n if (placement.mode !== 'relative') continue;\n dependents.set(placement.host, [...(dependents.get(placement.host) ?? []), { widget, placement }]);\n }\n const relative = (host: string): ReactNode =>\n (dependents.get(host) ?? []).map(({ widget, placement }) => (\n // data-widget names the box a widget occupies, so a check over the rendered board (the\n // readability gate in apps/board-replay) can find it.\n <div key={widget.id} data-widget={widget.id} data-host={host} style={relativeBoxStyle(placement, lengths)}>\n {render(widget)}\n {relative(widget.id)}\n </div>\n ));\n return (\n <>\n {placed.map(({ widget, placement }) => {\n if (placement.mode !== 'grid') return null;\n const style = gridItemStyle(grid.get(widget.id) ?? placement, columns);\n // Keyed by the widget, so removing or reordering widgets never remounts (and so never\n // re-subscribes) the ones that stay.\n return (\n <Fragment key={widget.id}>\n <div data-widget={widget.id} style={style}>\n {render(widget)}\n </div>\n {dependents.has(widget.id) ? (\n // The host's area again, as a layer for its relative widgets to be positioned in.\n // It takes no pointer events itself, so the host underneath stays usable.\n <div style={{ ...style, position: 'relative', pointerEvents: 'none', zIndex: RELATIVE_Z }}>\n {relative(widget.id)}\n </div>\n ) : null}\n </Fragment>\n );\n })}\n </>\n );\n}\n\n// sizingStyle turns the container-sizing knob into the outer wrapper's box. `fill`\n// takes the mount container's full width+height (the grid fills it); `{width}` caps\n// the width (the fluid grid adjusts within it); `{height}` pins the height (rows\n// scroll). All scroll internally so the board owns its single scroll region. The\n// background (color AND image) paints on this wrapper so it covers the whole container\n// even when the grid's rows are shorter than the sizing box.\nexport function sizingStyle(sizing: CanvasSizing, bg: CanvasBackground | undefined): CSSProperties {\n const base: CSSProperties = {\n overflow: 'auto',\n backgroundColor: bg?.color ?? undefined,\n backgroundImage: bg?.imageUrl ? `url(${bg.imageUrl})` : undefined,\n backgroundSize: 'cover',\n };\n if (sizing === 'fill') return { ...base, width: '100%', height: '100%' };\n if ('width' in sizing) return { ...base, width: sizing.width, maxWidth: '100%', height: '100%' };\n return { ...base, width: '100%', height: sizing.height };\n}\n\n// resolveWidgets maps each widget's datasource through the settled bindings\n// (resolveWidgetDatasource): a slot becomes the device or anchor it is bound to, or an\n// explicit `unbound` selector. A widget with no datasource keeps none \u2014 that is a\n// different fact (tenant-wide on the alarm channel) and must not be manufactured here.\nexport function resolveWidgets(\n widgets: WidgetInstance[],\n bindings: Record<string, SlotBinding> | undefined,\n): WidgetInstance[] {\n return widgets.map((widget) => {\n if (widget.type === UNKNOWN_WIDGET_TYPE || widget.datasource?.kind !== 'slot') return widget;\n return { ...widget, datasource: resolveWidgetDatasource(widget.datasource, bindings) };\n });\n}\n\n// widgetSubjectLabel names the entity a widget shows \u2014 its CONCRETE datasource's device\n// or anchor \u2014 for the frame subtitle. Pass the widget as the renderer resolved it\n// (resolveWidgets), so the subtitle is read from the same selector the widget subscribes\n// with and can never name an entity other than the one being shown. Returns undefined for\n// a datasource-free widget (label/image, a tenant-wide alarm tile), an unbound slot, an\n// unresolved slot, or a reserved selector kind \u2014 the frame then shows no subtitle.\nexport function widgetSubjectLabel(widget: WidgetInstance): string | undefined {\n const ds = widget.datasource;\n if (!ds) return undefined;\n if (ds.kind === 'device') return ds.deviceToken || undefined;\n if (ds.kind === 'anchor') return ds.anchor.targetToken;\n return undefined;\n}\n\n// useContainerWidth tracks an element's content width with a ResizeObserver, measured\n// synchronously before first paint so a narrow container never flashes the authored layout. 0\n// means \"not measured\" (no layout engine, or not yet laid out) and draws the authored layout.\n// A new width is taken only when `keyOf` tells it apart from the one held, so a resize that\n// does not change what is drawn does not re-render; a new `keyOf` re-measures under its rule.\nfunction useContainerWidth<T extends HTMLElement>(keyOf: (width: number) => string): [RefObject<T | null>, number] {\n const ref = useRef<T>(null);\n const [width, setWidth] = useState(0);\n const keyOfRef = useRef(keyOf);\n const measure = useCallback(() => {\n const el = ref.current;\n if (!el) return;\n const next = el.clientWidth;\n setWidth((prev) => (keyOfRef.current(prev) === keyOfRef.current(next) ? prev : next));\n }, []);\n useLayoutEffect(() => {\n keyOfRef.current = keyOf;\n measure();\n }, [keyOf, measure]);\n useLayoutEffect(() => {\n const el = ref.current;\n if (!el || typeof ResizeObserver === 'undefined') return;\n const ro = new ResizeObserver(measure);\n ro.observe(el);\n return () => ro.disconnect();\n }, [measure]);\n return [ref, width];\n}\n\n// A widget's seed, tagged with the concrete selector it was fetched for, and when it was read up to.\ninterface Seed {\n key: string;\n // The fixed window it was read for ('' for a rolling range): see windowTag.\n window: string;\n samples: MeasurementSample[];\n asOf: number;\n}\n\n// A fixed window's identity, '' for a rolling range. A seed belongs to the window it was read for:\n// one read for the live board ends now, and handed to a window yesterday it would draw the last\n// hour under a \"Fixed window\" label (two windows of the same length differ only by this).\nfunction windowTag(range: TimeRangeState): string {\n return range.absolute ? `${range.absolute.fromMs}-${range.absolute.toMs}` : '';\n}\n\n// What a measurement widget is handed: its seed and the instant the seed was read up to.\ninterface WidgetHistory {\n samples: MeasurementSample[];\n asOf: number;\n}\n\n// How long a failed re-read after an interruption waits before it is tried again. Until one lands\n// the widget draws the outage as a gap, so a failure never shows as a quiet stretch of line.\nexport const RESEED_RETRY_MS = 30_000;\n\n// seedKey is the identity of what a measurement widget's history is OF: its concrete\n// selector, by value. Undefined for a widget that takes no seed.\nfunction seedKey(widget: WidgetInstance, registry: WidgetRegistry): string | undefined {\n // Eligibility is registry metadata: only a registered measurement-channel widget takes a\n // seed. A placeholder, an unregistered id and every other channel take none.\n if (widget.type === UNKNOWN_WIDGET_TYPE || registry.descriptor(widget.type)?.channel !== 'measurement') {\n return undefined;\n }\n return JSON.stringify(widget.datasource ?? null);\n}\n\n// useWidgetHistories backfills each measurement widget from bucketedMeasurements and\n// returns an id\u2192seed map. Each seed is keyed by the widget's OWN concrete selector,\n// not by the board's bindings as a whole, so:\n//\n// - a selection that re-points one slot re-fetches only the widgets bound to it;\n// - a seed fetched for a selector the widget no longer has is DROPPED at render,\n// synchronously, so a widget never shows the previous device's history under the new\n// device while the new fetch is pending;\n// - a slow answer for a superseded selector is discarded when it lands.\n//\n// `reseed(id)` reads a widget's history again after its live feed resumed from an interruption.\n// It supersedes any read of that widget still in flight (one asked for before the outage cannot\n// cover it), and the answer is handed over with the instant it was read up to, which is how the\n// widget knows it covers the outage. A failed re-read keeps the seed on screen (the widget then\n// draws the outage as a gap) and is tried again after RESEED_RETRY_MS. While the board is paused\n// the re-read waits: a frozen board shows the moment it froze, and history up to that moment\n// cannot cover an outage after it. Resuming reads it.\n//\n// A widget's samples array is the one stored for its seed, so an unchanged seed keeps\n// its identity across renders and does not churn the stream's merge.\nfunction useWidgetHistories(\n widgets: WidgetInstance[],\n enabled: boolean,\n registry: WidgetRegistry,\n range: TimeRangeState,\n): { histories: Record<string, WidgetHistory | undefined>; reseed: (id: string) => void } {\n const [seeds, setSeeds] = useState<Record<string, Seed>>({});\n // widget id \u2192 the (selector, span, re-read) ask most recently REQUESTED for it. A fetch whose\n // ask is no longer the requested one is stale when it lands.\n const requested = useRef<Record<string, string>>({});\n // widget id \u2192 how many re-reads its live feed has asked for (part of the ask). A read asked for\n // before the latest interruption that lands before the effect below has run is still taken, but\n // it cannot close the gap: it is handed over with the instant it was read up to, which is before\n // the interruption (useMeasurementStream).\n const reseeds = useRef<Record<string, number>>({});\n const [reseedTick, bumpReseeds] = useState(0);\n const mounted = useRef(true);\n useEffect(() => {\n mounted.current = true;\n return () => {\n mounted.current = false;\n };\n }, []);\n\n const reseed = useCallback((id: string) => {\n reseeds.current[id] = (reseeds.current[id] ?? 0) + 1;\n bumpReseeds((n) => n + 1);\n }, []);\n\n // The (id, key, span) triples that want a seed; value-compared so an equal render is a no-op.\n // `span` is the seconds a TIME-RANGED widget draws (null for one that is not, which keeps the\n // fixed default seed): a new span re-fetches, but the seed on screen stays until the new one lands,\n // because it is the same device's history and the stream prunes it to the span anyway.\n const wanted = widgets.flatMap((w) => {\n const key = seedKey(w, registry);\n if (key === undefined) return [];\n const descriptor = w.type === UNKNOWN_WIDGET_TYPE ? undefined : registry.descriptor(w.type);\n const span = descriptor ? (measurementSpan(descriptor, w, range.spanSeconds) ?? null) : null;\n return [[w.id, key, span] as const];\n });\n const tag = windowTag(range);\n const wantedKey = JSON.stringify([tag, wanted]);\n\n useEffect(() => {\n // Preview (enabled=false) must not touch the backend; clear any prior seed so a\n // toggle from live\u2192preview doesn't leave stale real history under synthetic data.\n if (!enabled) {\n requested.current = {};\n setSeeds({});\n return;\n }\n const now = Date.now();\n const byId = new Map(widgets.map((w) => [w.id, w]));\n const next: Record<string, string> = {};\n for (const [id, key, span] of wanted) {\n // What was asked for: the selector, the span and the re-reads. Equal = fetched, or in flight.\n const base = `${key}|${span ?? ''}|${tag}|`;\n const n = reseeds.current[id] ?? 0;\n // A read made while frozen ends at the freeze instant, so it answers no re-read: it is asked\n // as `p`, and resuming reads the outage back.\n const asked = `${base}${range.paused && n ? 'p' : n}`;\n const previous = requested.current[id];\n // Already asked; or only the re-read is new and the board is frozen, so it waits for resume.\n if (previous === asked || (range.paused && previous?.startsWith(base))) {\n next[id] = previous!;\n continue;\n }\n next[id] = asked;\n const widget = byId.get(id);\n // Only a single device has stored history to read (fetchWidgetHistory answers any other\n // selector with nothing, at once). That empty answer is not history across an outage, and\n // taken as one it would wipe what the chart drew before it: such a widget gets no seed.\n if (widget?.datasource?.kind !== 'device') continue;\n // A frozen board reads up to the freeze instant, so a range change while paused re-fetches\n // the same moment at the new span instead of sliding forward.\n const end = range.paused && range.pausedAt !== undefined ? range.pausedAt : now;\n // A widget that is not time-ranged reads its fixed hour back from the window's end under a\n // fixed window (the value AS OF that window), and back from now otherwise.\n const historyWindow =\n span !== null ? historyWindowFor(span, end) : range.absolute ? historyWindowFor(DEFAULT_TIME_RANGE_SECONDS, end) : defaultHistoryWindow();\n const current = () => mounted.current && requested.current[id] === asked;\n void fetchWidgetHistory(widget, historyWindow, { rethrow: n > 0 }).then(\n (samples) => {\n if (!current()) return; // superseded or unmounted\n // `asOf`: what the read covers up to (the fixed hour reads to now, a moment after `now`).\n setSeeds((prev) => ({ ...prev, [id]: { key, window: tag, samples, asOf: end } }));\n },\n () => {\n // Only a re-read rejects. The seed on screen stays, the outage stays a gap, and it is\n // read again later -- unless something newer has been asked for meanwhile, or the board\n // has gone (current() says both).\n setTimeout(() => current() && reseed(id), RESEED_RETRY_MS);\n },\n );\n }\n requested.current = next;\n // `widgets`/`wanted` are read via wantedKey (value identity), not reference.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [wantedKey, enabled, reseedTick, range.paused]);\n\n // Hand each widget its seed ONLY if it was fetched for the selector the widget has now.\n const histories = useMemo(() => {\n const out: Record<string, WidgetHistory | undefined> = {};\n if (!enabled) return out;\n for (const w of widgets) {\n const seed = seeds[w.id];\n out[w.id] = seed && seed.key === seedKey(w, registry) && seed.window === tag ? seed : undefined;\n }\n return out;\n }, [widgets, seeds, enabled, registry, tag]);\n return { histories, reseed };\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// ConnectedWidget is the one place the imperative DashboardHub meets the pure widget\n// contract. It looks the widget up in the host's REGISTRY and dispatches on the registered\n// descriptor's data CHANNEL: a measurement widget subscribes its datasource (windowed per its\n// binding policy); an alarm widget subscribes its scope+filters through the hub's alarm\n// channel; and so on. Either way it resolves the data and renders the registered component\n// with { widget, data }. A dashboard renderer maps over its widgets rendering one\n// ConnectedWidget each.\n//\n// Each widget renders inside its own containment (widget-containment.tsx): a throw shows a\n// local diagnostic with a reset control and the siblings keep rendering. A widget the\n// registry cannot resolve (an unknown or unavailable package, a version it cannot read) is a\n// placeholder with a specific reason: it reads nothing \u2014 no channel, no availability query \u2014\n// and is handed no actions.\n\nimport {\n UNKNOWN_WIDGET_TYPE,\n type MeasurementSample,\n type UnresolvedWidgetReason,\n type WidgetActions,\n type WidgetDataSource,\n type WidgetDescriptor,\n type WidgetInstance,\n} from '@devicechain/dashboards';\nimport {\n newestSampleTime,\n resolveStaleAfterSeconds,\n WidgetCandidatesProvider,\n WidgetDeclaredMetricsProvider,\n WidgetFreshnessProvider,\n WidgetSelectProvider,\n useWidgetScale,\n useWidgetTimeRange,\n type WidgetFreshness,\n type WidgetRegistry,\n} from '@devicechain/widget-sdk';\nimport { isForbiddenError } from '@devicechain/client';\nimport { useCallback, useEffect, useMemo, useState, type ComponentType, type ReactNode } from 'react';\n\nimport { alarmSubscription, commandSubscription, groupsAlarmsByDeviceType, historyMode, measurementSpan, measurementIsMembersOnly, measurementWindow, membersMode, presenceMode, wantsEventMarkers } from './binding-policy';\nimport { useHeld } from './use-held';\nimport { accessStrings } from './access-strings';\nimport { defaultWidgetRegistry } from './default-registry';\nimport {\n css,\n fontVar,\n optString,\n spaceVar,\n viewerLocale,\n useAlarmStream,\n useCommandStream,\n useDatasourceAvailability,\n useLocationStream,\n useMeasurementStream,\n useWidgetCandidates,\n useWidgetSelect,\n WidgetFrame,\n} from '@devicechain/widget-sdk';\nimport { WidgetContainment, useReportRejection } from './widget-containment';\nimport { ChunkLoadingFrame, lazyChunk } from './widgets/lazy-chunk';\nimport type { AggregateFeedProps } from './aggregate-feed';\nimport type { GroupedAlarmProps } from './widgets/alarm-grouped';\nimport type { EventMarkersFeedProps } from './event-markers-feed';\nimport type { FleetFeedProps } from './fleet-feed';\nimport type { HistoryFeedProps } from './history-feed';\nimport type { PresenceFeedProps } from './presence-feed';\nimport { narrowActions, narrowCandidates, narrowSelect } from './widget-host';\n\nexport interface ConnectedWidgetProps {\n widget: WidgetInstance;\n hub: WidgetDataSource;\n // The registry that resolves the widget's component, channel and binding policy. Omitted =\n // the built-in registry. A host composing extension packages passes the SAME registry it\n // parsed the definition with.\n registry?: WidgetRegistry;\n // The action seam (writes). Narrowed per widget to the interactions its descriptor\n // declares; undefined = read-only.\n actions?: WidgetActions;\n // Optional history backfill for this widget (from bucketedMeasurements), seeded\n // under the live tail so a chart isn't blank until the first live sample. Ignored by\n // every channel but measurement (the others reconcile from a query, not a history seed).\n initialSamples?: MeasurementSample[];\n // When `initialSamples` was read up to (epoch ms). A seed read after the live feed resumed from an\n // interruption replaces what the widget held from before it (useMeasurementStream).\n initialSamplesAsOf?: number;\n // Called when the widget's live feed resumes after an interruption: the host reads its history\n // again. Omitted: the outage stays drawn as a gap.\n onReconnect?: () => void;\n}\n\nexport function ConnectedWidget(props: ConnectedWidgetProps) {\n const { widget } = props;\n const registry = props.registry ?? defaultWidgetRegistry();\n // A change to what the widget is configured with retries a widget that threw on the old one.\n const resetKey = JSON.stringify([widget.type, widget.options ?? null, widget.datasource ?? null]);\n return (\n <WidgetContainment title={optString(widget.options, 'title')} resetKey={resetKey}>\n <ConnectedWidgetBody {...props} registry={registry} />\n </WidgetContainment>\n );\n}\n\ntype BodyProps = ConnectedWidgetProps & { registry: WidgetRegistry };\n\n// The component a registration renders. Its props are erased in the registry (one registry\n// holds components of every channel); the channel adapters below supply the matching data.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyWidgetComponent = ComponentType<any>;\n\nfunction ConnectedWidgetBody({ widget, hub, registry, actions, initialSamples, initialSamplesAsOf, onReconnect }: BodyProps) {\n const range = useWidgetTimeRange();\n const unresolved = widget.type === UNKNOWN_WIDGET_TYPE;\n const descriptor = unresolved ? undefined : registry.descriptor(widget.type);\n const implementation = unresolved ? undefined : registry.implementation(widget.type);\n\n // A widget bound to a since-deleted device (its stable token no longer resolves)\n // shows an \"unavailable\" pane rather than a blank one \u2014 checked optimistically, so a\n // valid widget renders from its stream without waiting on this. An unresolved widget asks\n // nothing: it is never given a datasource to check. Nor does a widget whose descriptor\n // binds none (label, image, the selector): a datasource left on its stored JSON is one it\n // never reads, so it must not turn the widget into an \"unavailable\" pane.\n const readsDatasource = descriptor !== undefined && descriptor.datasource.mode !== 'none';\n const availability = useDatasourceAvailability(hub, readsDatasource ? widget.datasource : undefined);\n const supported = useDatasourceSupported(hub, readsDatasource ? widget.datasource : undefined);\n if (!supported) {\n return <WidgetNotForCustomerUsersFrame widget={widget} />;\n }\n if (availability === 'unavailable') {\n return <WidgetUnavailableFrame widget={widget} />;\n }\n\n if (widget.type === UNKNOWN_WIDGET_TYPE) {\n return <UnresolvedWidgetFrame storedType={widget.raw.type} reason={widget.reason} />;\n }\n if (!descriptor || !implementation) {\n // Parsed against a catalog this registry does not hold: say so rather than render nothing.\n return (\n <UnresolvedWidgetFrame\n storedType={widget.type}\n reason={{ code: 'unregistered', message: `\"${widget.type}\" is not registered in this host's widget registry` }}\n />\n );\n }\n\n const body = (\n <DeclaredScope hub={hub} datasource={widget.datasource}>\n <HostScope descriptor={descriptor} actions={actions}>\n {(hostActions) => (\n <ChannelBody\n widget={widget}\n hub={hub}\n descriptor={descriptor}\n Component={implementation.component}\n actions={hostActions}\n initialSamples={initialSamples}\n initialSamplesAsOf={initialSamplesAsOf}\n onReconnect={onReconnect}\n />\n )}\n </HostScope>\n </DeclaredScope>\n );\n return range?.absolute !== undefined && showsCurrentStateOnly(descriptor) ? <CurrentStateBadge>{body}</CurrentStateBadge> : body;\n}\n\n// The widgets that read CURRENT state, with no history to read for a past window: alarms (the\n// active set now), positions (the last fix), and presence (online now). Under a fixed window the\n// rest of the board shows that window, so each of these says, on itself, that it does not --\n// a table of today's active alarms under \"Fixed window: yesterday 02:00-04:00\" would otherwise\n// read as the alarms that were active then.\nfunction showsCurrentStateOnly(descriptor: WidgetDescriptor): boolean {\n return descriptor.channel === 'alarm' || descriptor.channel === 'location' || presenceMode(descriptor);\n}\n\nconst CURRENT_STATE_STRINGS = {\n en: { label: 'Now', title: 'Shows the current state: the fixed time window does not apply to this widget.' },\n es: { label: 'Ahora', title: 'Muestra el estado actual: la ventana de tiempo fija no se aplica a este widget.' },\n};\n\nfunction CurrentStateBadge({ children }: { children: ReactNode }) {\n const words = viewerLocale()?.toLowerCase().startsWith('es') ? CURRENT_STATE_STRINGS.es : CURRENT_STATE_STRINGS.en;\n return (\n <div data-current-state=\"\" style={{ position: 'relative', width: '100%', height: '100%', minWidth: 0, minHeight: 0 }}>\n {children}\n <span\n data-current-state-badge=\"\"\n role=\"note\"\n title={words.title}\n aria-label={words.title}\n style={{\n position: 'absolute',\n // Bottom LEFT: a map keeps its attribution bottom right, and a chart its span badge top right.\n bottom: spaceVar(1),\n left: spaceVar(2),\n padding: `0 ${spaceVar(1)}`,\n fontSize: fontVar('xs'),\n fontWeight: 600,\n whiteSpace: 'nowrap',\n color: css('background'),\n background: css('foreground'),\n borderRadius: 4,\n zIndex: 1,\n }}\n >\n {words.label}\n </span>\n </div>\n );\n}\n\n// useDatasourceSupported asks the source whether the viewer is offered the widget's binding at\n// all (WidgetDataSource.isDatasourceSupported). Optimistic like the availability check: the\n// widget renders from its channel meanwhile, and a source without the method supports every\n// binding. Re-asked when the binding changes (value-compared).\nfunction useDatasourceSupported(hub: WidgetDataSource, datasource: WidgetInstance['datasource']): boolean {\n const key = datasource ? JSON.stringify(datasource) : null;\n const [refused, setRefused] = useState<string | null>(null);\n useEffect(() => {\n if (!datasource || !hub.isDatasourceSupported) return;\n let cancelled = false;\n hub.isDatasourceSupported(datasource).then(\n (ok) => {\n if (!cancelled) setRefused(ok ? null : key);\n },\n () => {\n if (!cancelled) setRefused(null);\n },\n );\n return () => {\n cancelled = true;\n };\n // `datasource` is intentionally read via `key` (value identity), not reference.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [hub, key]);\n // A refusal belongs to the binding it was given for; a changed binding is supported until asked.\n return refused === null || refused !== key;\n}\n\n// DeclaredScope answers, for a single-device widget with nothing to draw, \"does this device's profile\n// declare what you asked for?\". Nothing is read until a widget in the scope asks (an empty state\n// does), so a board whose widgets have data costs no lookup; the answer is the hub's shared one per\n// device type. A binding that is not one device (a group, an unbound slot) has nothing to look up.\nfunction DeclaredScope({ hub, datasource, children }: { hub: WidgetDataSource; datasource: WidgetInstance['datasource']; children: ReactNode }) {\n const token = datasource?.kind === 'device' && datasource.deviceToken ? datasource.deviceToken : undefined;\n const [asked, setAsked] = useState(false);\n const [got, setGot] = useState<{ token: string; names: readonly string[] | null }>();\n const ask = useCallback(() => setAsked(true), []);\n useEffect(() => {\n if (!asked || !token || !hub.declaredMetricsForDevice) return;\n let live = true;\n hub.declaredMetricsForDevice(token).then(\n (names) => live && setGot({ token, names }),\n () => undefined,\n );\n return () => {\n live = false;\n };\n }, [asked, token, hub]);\n const declared = got && got.token === token ? got.names : undefined;\n const value = useMemo(() => ({ declared, ask }), [declared, ask]);\n return <WidgetDeclaredMetricsProvider value={value}>{children}</WidgetDeclaredMetricsProvider>;\n}\n\n// HostScope hands ONE widget only the interactions it declared: a narrowed action seam, and\n// the ambient selection / candidate providers re-provided so an undeclared capability\n// reads as \"not wired\" to a widget that asks.\nfunction HostScope({\n descriptor,\n actions,\n children,\n}: {\n descriptor: WidgetDescriptor;\n actions: WidgetActions | undefined;\n children: (actions: WidgetActions | undefined) => ReactNode;\n}) {\n const report = useReportRejection();\n const select = useWidgetSelect();\n const candidates = useWidgetCandidates();\n const narrowed = useMemo(() => narrowActions(actions, descriptor, report), [actions, descriptor, report]);\n const narrowedSelect = useMemo(() => narrowSelect(select, descriptor), [select, descriptor]);\n const narrowedCandidates = useMemo(\n () => narrowCandidates(candidates, descriptor, report),\n [candidates, descriptor, report],\n );\n return (\n <WidgetSelectProvider select={narrowedSelect}>\n <WidgetCandidatesProvider candidates={narrowedCandidates}>{children(narrowed)}</WidgetCandidatesProvider>\n </WidgetSelectProvider>\n );\n}\n\ninterface ChannelProps {\n widget: WidgetInstance;\n hub: WidgetDataSource;\n descriptor: WidgetDescriptor;\n Component: AnyWidgetComponent;\n actions: WidgetActions | undefined;\n initialSamples?: MeasurementSample[];\n initialSamplesAsOf?: number;\n onReconnect?: () => void;\n}\n\n// The channel is the only thing the runtime branches on \u2014 never the widget id.\nfunction ChannelBody(props: ChannelProps) {\n switch (props.descriptor.channel) {\n case 'alarm':\n return <AlarmConnectedWidget {...props} />;\n case 'control':\n return <ControlConnectedWidget {...props} />;\n case 'location':\n return <LocationConnectedWidget {...props} />;\n case 'aggregate':\n return <AggregateConnectedWidget {...props} />;\n case 'selection':\n case 'none':\n return <StaticConnectedWidget {...props} />;\n case 'measurement':\n return <MeasurementConnectedWidget {...props} />;\n }\n}\n\n// A selection widget (entity-selector) consumes no hub data \u2014 it reads the ambient candidate\n// provider + selection callback; a `none` widget is static. Neither subscribes anything.\nfunction StaticConnectedWidget({ widget, Component, actions }: ChannelProps) {\n return <Component widget={widget} data={null} actions={actions} />;\n}\n\n// The fleet feed is its own chunk (fleet-feed.tsx), like the aggregate feed: a board without a fleet\n// table or a per-device bar chart never downloads it. A chunk that fails to load is thrown to the\n// widget's containment, which shows the failure, and its Reset fetches it again (lazyChunk).\nconst FleetFeed = lazyChunk<typeof import('./fleet-feed')>(() => import('./fleet-feed')).component<never, FleetFeedProps>('default', undefined, ChunkLoadingFrame);\n\n// The presence feed (presence-feed.tsx) loads with the presence widgets, in their chunk: a board\n// without a device status card or an online doughnut never downloads it.\nconst PresenceFeed = lazyChunk<typeof import('./widgets/presence-widgets')>(() => import('./widgets/presence-widgets')).component<never, PresenceFeedProps>('PresenceFeed');\n\n// The history feed (history-feed.tsx) loads with the history table, in its chunk: a board without one\n// never downloads it.\nconst HistoryFeed = lazyChunk<typeof import('./widgets/history-widgets')>(() => import('./widgets/history-widgets')).component<never, HistoryFeedProps>('HistoryFeed');\n\nfunction MeasurementConnectedWidget(props: ChannelProps) {\n // A presence widget reads device-state, not readings: its own feed, whatever it is bound to (the\n // widget itself says so when a card meant for one device is bound to a group).\n if (presenceMode(props.descriptor)) {\n return (\n <PresenceFeed hub={props.hub} widget={props.widget} descriptor={props.descriptor} Component={props.Component} actions={props.actions} ErrorFrame={WidgetErrorFrame} />\n );\n }\n // Read member by member, or as one stream keyed by measurement name: decided by the descriptor\n // and the widget's options, never by the widget id.\n //\n // Keyed by measurement name, a group's devices would overwrite one another and the widget would\n // show whichever spoke last as if it were the answer. So a group reaching a widget that is not\n // reading member by member is refused in words (the fleet chunk says so), whatever brought it\n // here: a host binding, an older definition. The editor offers a group only to the fleet widgets.\n const { widget, hub, descriptor, Component, actions } = props;\n const members = membersMode(descriptor, widget);\n if (members || widget.datasource?.kind === 'anchor') {\n return (\n <FleetFeed hub={hub} widget={widget} descriptor={descriptor} Component={Component} actions={actions} ErrorFrame={WidgetErrorFrame} refuse={!members} />\n );\n }\n // One device's stored history, in buckets (after the group check above, so a group is refused in words).\n if (historyMode(descriptor)) {\n return <HistoryFeed hub={hub} widget={widget} descriptor={descriptor} Component={Component} actions={actions} />;\n }\n return <StreamConnectedWidget {...props} />;\n}\n\nfunction StreamConnectedWidget({ widget, hub, descriptor, Component, actions, initialSamples, initialSamplesAsOf, onReconnect }: ChannelProps) {\n // The board's time range (D-1). A widget that declares `binding.windowSeconds` draws a SPAN: its\n // own pinned one, else the board's. Every measurement widget honors the pause, because a frozen\n // board must freeze its cards and gauges too -- a number that kept moving under a \"Paused\"\n // badge would be the worst possible answer.\n const range = useWidgetTimeRange();\n // The source's own clock (a recorded run is dated by the run), else the wall clock.\n const now = useMemo(() => (hub.now ? () => hub.now!() : Date.now), [hub]);\n const data = useMeasurementStream(hub, widget.datasource, {\n window: measurementWindow(descriptor, widget),\n windowSeconds: measurementSpan(descriptor, widget, range?.spanSeconds),\n pausedAt: range?.paused ? range.pausedAt : undefined,\n now,\n initialSamples,\n initialSamplesAsOf,\n onReconnect,\n });\n\n // Opt-in through the descriptor. The age is of the newest sample among the measurements this\n // widget shows (its pinned one, else its datasource's, else whatever has arrived) -- right for\n // a chart or a table, which time every point or row. A single-value widget narrows it to the\n // sample it actually shows by passing that sample's time to its WidgetFrame (`sampleTime`).\n // The threshold is the widget's own option, and absent means age only.\n const freshness = useMemo<WidgetFreshness | undefined>(() => {\n if (descriptor.freshness !== true) return undefined;\n // A `measurement` that only the widget's members mode reads (a chart's compared measurement) is\n // not what it draws here, one device at a time: it narrows nothing.\n const pinned = measurementIsMembersOnly(descriptor) ? undefined : optString(widget.options, 'measurement');\n const names = pinned ? [pinned] : widget.datasource?.measurements;\n return {\n at: newestSampleTime(data.latest, names),\n staleAfterSeconds: resolveStaleAfterSeconds(widget.options),\n };\n }, [descriptor, widget.options, widget.datasource, data.latest]);\n\n if (data.error) return <WidgetErrorFrame widget={widget} error={data.error} />;\n return (\n <WidgetFreshnessProvider freshness={freshness}>\n {wantsEventMarkers(descriptor, widget) ? (\n <EventMarkersFeed hub={hub} widget={widget} descriptor={descriptor} data={data} Component={Component} actions={actions} />\n ) : (\n <Component widget={widget} data={data} actions={actions} />\n )}\n </WidgetFreshnessProvider>\n );\n}\n\n// The event-marker feed (alarms and commands on a chart) is its own chunk, like the feeds below: a\n// board whose charts have the markers off never downloads it.\nconst EventMarkersFeed = lazyChunk<typeof import('./event-markers-feed')>(() => import('./event-markers-feed')).component<never, EventMarkersFeedProps>('default');\n\n// The aggregate feed is its own chunk (aggregate-feed.tsx): a board without an aggregate widget\n// never downloads it. Nothing renders until it arrives, and a chunk that fails to load is thrown to\n// the widget's containment, which shows the failure, and its Reset fetches it again.\nconst AggregateFeed = lazyChunk<typeof import('./aggregate-feed')>(() => import('./aggregate-feed')).component<never, AggregateFeedProps>('default');\n\nfunction AggregateConnectedWidget({ widget, hub, descriptor, Component, actions }: ChannelProps) {\n // An aggregate names one device's measurements, so a group is refused as above.\n const props = { hub, widget, descriptor, Component, actions, ErrorFrame: WidgetErrorFrame };\n return widget.datasource?.kind === 'anchor' ? <FleetFeed {...props} refuse /> : <AggregateFeed {...props} />;\n}\n\n// An alarm widget grouped by device type is its own part of the alarm chunk (widgets/alarm-grouped.tsx):\n// a board without one never downloads the tab logic, and the eager code carries only this switch.\nconst GroupedAlarm = lazyChunk<typeof import('./widgets/alarm-widgets')>(() => import('./widgets/alarm-widgets')).component<\n never,\n GroupedAlarmProps\n>('GroupedAlarm');\n\nfunction AlarmConnectedWidget(props: ChannelProps) {\n return groupsAlarmsByDeviceType(props.descriptor, props.widget) ? (\n <GroupedAlarm\n hub={props.hub}\n widget={props.widget}\n base={alarmSubscription(props.descriptor, props.widget)}\n useHeld={useHeld}\n Component={props.Component}\n actions={props.actions}\n ErrorFrame={WidgetErrorFrame}\n />\n ) : (\n <PlainAlarmConnectedWidget {...props} />\n );\n}\n\nfunction PlainAlarmConnectedWidget({ widget, hub, descriptor, Component, actions }: ChannelProps) {\n // Frozen while the board is paused: the snapshot on screen at the pause (or the first one to land,\n // when the board opened paused) stays, and the live one is shown again on resume.\n const range = useWidgetTimeRange();\n const live = useAlarmStream(hub, alarmSubscription(descriptor, widget));\n const data = useHeld(live, range?.paused === true, (s) => !s.loading);\n\n // Show the error pane ONLY when there's nothing to display (the initial load failed).\n // Once a snapshot has loaded, a later transient poll/query error keeps the last-good\n // rows on screen \u2014 the channel re-queries every 30s and self-heals, so blanking a\n // populated table on one blip is the exact blink the console page avoids.\n if (data.error && data.alarms.length === 0 && data.total === 0) {\n return <WidgetErrorFrame widget={widget} error={data.error} />;\n }\n return <Component widget={widget} data={data} actions={actions} />;\n}\n\nfunction ControlConnectedWidget({ widget, hub, descriptor, Component, actions }: ChannelProps) {\n const data = useCommandStream(hub, commandSubscription(descriptor, widget));\n\n // Unlike the read-only widgets, a command widget is NEVER replaced by the error pane:\n // its primary control is the send form (a separate authority from reading history), so\n // a history poll error must not tear the form down. The widget surfaces the error\n // inline instead.\n return <Component widget={widget} data={data} actions={actions} />;\n}\n\nfunction LocationConnectedWidget({ widget, hub, Component, actions }: ChannelProps) {\n // The tile source lives in the widget's options, not here \u2014 it is a rendering choice, not\n // part of what the widget asks the platform for.\n const range = useWidgetTimeRange();\n const live = useLocationStream(hub, { datasource: widget.datasource });\n const data = useHeld(live, range?.paused === true, (s) => !s.loading);\n\n // Same rule as the alarm channel: show the error pane ONLY when there is nothing to\n // display. Once a snapshot has loaded, a later transient poll error keeps the last\n // known positions on screen \u2014 the channel re-polls and self-heals, and blanking a\n // populated map on one blip is worse than a marker being a few seconds stale.\n //\n // \uD83D\uDD34 A REFUSAL IS NOT AN ERROR AND MUST NOT REACH THIS BRANCH. The hub delivers it as\n // a snapshot state with `error` null, so the widget renders its own permission copy \u2014\n // if it were surfaced as an error, every ordinary member would see \"Data unavailable\"\n // where the platform is working exactly as designed.\n if (data.error && data.locations.length === 0) {\n return <WidgetErrorFrame widget={widget} error={data.error} />;\n }\n return <Component widget={widget} data={data} actions={actions} />;\n}\n\n// The body of every state pane below: a centered, muted column.\nconst STATE_STYLE = {\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 4,\n width: '100%',\n height: '100%',\n padding: 12,\n boxSizing: 'border-box',\n textAlign: 'center',\n color: 'hsl(var(--muted-foreground))',\n} as const;\n\n// The placeholder for a widget this build cannot resolve. It names the stored type and says\n// WHY (not installed, no version metadata, a settings or SDK generation it cannot read); the\n// stored object is otherwise untouched (the serializer writes it back verbatim).\nfunction UnresolvedWidgetFrame({\n storedType: stored,\n reason,\n}: {\n storedType: unknown;\n reason: UnresolvedWidgetReason | undefined;\n}): ReactNode {\n const storedType = typeof stored === 'string' ? stored : '';\n const heading =\n (reason?.code ?? 'unregistered') === 'unregistered'\n ? 'This widget needs a newer viewer'\n : 'This widget cannot be shown here';\n return (\n <WidgetFrame>\n <div\n style={STATE_STYLE}\n >\n <div style={{ fontSize: 13, fontWeight: 600 }}>{heading}</div>\n {storedType && !reason?.message.includes(storedType) && (\n <div style={{ fontSize: 11, opacity: 0.8 }}>Widget type: {storedType}</div>\n )}\n {reason && <div style={{ fontSize: 11, opacity: 0.8, wordBreak: 'break-word' }}>{reason.message}</div>}\n </div>\n </WidgetFrame>\n );\n}\n\n// The one body of the settled panes below (refused, gone, not offered, source error): a neutral,\n// muted state that says what it is. None of them borrows an alarm glyph or colour, since on a\n// board that means an alarm. `data-empty-state` names the kind for the tests and the screenshots.\nfunction StatePane({\n widget,\n kind,\n glyph,\n title,\n detail,\n}: {\n widget: WidgetInstance;\n kind: string;\n glyph: string;\n title: string;\n detail?: string;\n}): ReactNode {\n return (\n <WidgetFrame title={optString(widget.options, 'title')}>\n <StateBody kind={kind} glyph={glyph} title={title} detail={detail} />\n </WidgetFrame>\n );\n}\n\n// The pane's content, which gives way to the title as the widget shrinks (the glyph first, then the\n// explanation), so a small widget never draws it clipped. Unmeasured, it shows everything.\nfunction StateBody({ kind, glyph, title, detail }: { kind: string; glyph: string; title: string; detail?: string }): ReactNode {\n const { height } = useWidgetScale().size;\n const measured = height > 0;\n return (\n <div role=\"status\" data-empty-state={kind} style={STATE_STYLE}>\n {!measured || height >= 84 ? <div style={{ fontSize: 20, lineHeight: 1 }} aria-hidden=\"true\">{glyph}</div> : null}\n <div style={{ fontSize: 13, fontWeight: 600 }}>{title}</div>\n {detail && (!measured || height >= 64) ? <div style={{ fontSize: 11, opacity: 0.8, wordBreak: 'break-word' }}>{detail}</div> : null}\n </div>\n );\n}\n\n// Shown when the platform refused the widget's read for the viewer.\nfunction WidgetForbiddenFrame({ widget }: { widget: WidgetInstance }): ReactNode {\n return <StatePane widget={widget} kind=\"forbidden\" glyph=\"\u2298\" title={accessStrings().forbidden} />;\n}\n\n// Shown when a widget's bound device no longer exists (a deleted device's stable token). Distinct\n// from the error frame: not a transient failure to retry, but a settled \"this entity is gone\".\nfunction WidgetUnavailableFrame({ widget }: { widget: WidgetInstance }): ReactNode {\n return <StatePane widget={widget} kind=\"gone\" glyph=\"\u2298\" title=\"Device unavailable\" detail=\"The bound device no longer exists.\" />;\n}\n\n// Shown when the platform does not offer the widget's binding to the viewer at all: a member limited\n// to some customers viewing a widget bound to an area or an asset. A settled state, not a failure to\n// retry, and not \"no access\" either, since nothing the member could be granted would change it -- so\n// the dashboard's author knows to bind it otherwise.\nfunction WidgetNotForCustomerUsersFrame({ widget }: { widget: WidgetInstance }): ReactNode {\n return (\n <StatePane\n widget={widget}\n kind=\"unsupported\"\n glyph=\"\u2298\"\n title=\"Not available for customer users\"\n detail=\"This widget is bound to an area or an asset, which customer users cannot view.\"\n />\n );\n}\n\n// A resolution/socket error surfaces as a muted state rather than a blank pane. Shared by the\n// measurement and alarm channels.\n//\n// A REFUSAL is not such an error: a member limited to part of the tenant, viewing a widget bound to a\n// customer or device outside it, is refused by design. It reads as the same plain state the fleet\n// widgets show (\"You do not have access to this data\"), never as \"Data unavailable\" over the\n// server's raw \"forbidden: missing required authority\".\nfunction WidgetErrorFrame({ widget, error }: { widget: WidgetInstance; error: unknown }): ReactNode {\n if (isForbiddenError(error)) return <WidgetForbiddenFrame widget={widget} />;\n return <StatePane widget={widget} kind=\"error\" glyph=\"\u2026\" title=\"Data unavailable\" detail={String(error)} />;\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The built-in widgets as registrations. Each widget module declares its own registration\n// (descriptor + component) through the SAME public `defineWidget` a third-party package uses\n// -- there is no privileged internal path and no id-keyed component table; this module only\n// lists them, in the catalog's order.\n//\n// These are the RUNTIME registrations: their descriptors carry no option `doc`. The package\n// publishes them as `builtinWidgetDefinitionsWithoutDocs`; its `builtinWidgetDefinitions` and\n// `createBuiltinWidgetRegistry` are the documented forms (documented-descriptors.ts).\n\nimport { createWidgetRegistry, type WidgetRegistry } from '@devicechain/widget-sdk';\n\nimport { barChartWidget, fleetCountWidget, fleetTableWidget, pieChartWidget, statCardWidget } from './widgets/aggregate-lazy';\nimport { alarmCountWidget, alarmSeverityWidget, alarmTableWidget } from './widgets/alarm-lazy';\nimport { commandButtonWidget, commandSliderWidget, commandToggleWidget } from './widgets/control-lazy';\nimport { historyTableWidget } from './widgets/history-lazy';\nimport { deviceStatusWidget, onlineDoughnutWidget } from './widgets/presence-lazy';\nimport { entitySelectorWidget } from './widgets/selection-lazy';\nimport { gaugeWidget } from './widgets/gauge';\nimport { imageWidget } from './widgets/image';\nimport { labelWidget } from './widgets/label';\nimport { latestCardWidget } from './widgets/latest-card';\nimport {\n batteryWidget,\n compassWidget,\n levelGaugeWidget,\n linearGaugeWidget,\n progressRingWidget,\n signalBarsWidget,\n statusLightWidget,\n} from './widgets/level-lazy';\nimport { mapWidget } from './widgets/map';\nimport { tableWidget } from './widgets/table-lazy';\nimport { timeSeriesChartWidget } from './widgets/time-series-chart';\n\nexport const builtinWidgetDefinitions = [\n timeSeriesChartWidget,\n latestCardWidget,\n gaugeWidget,\n tableWidget,\n labelWidget,\n imageWidget,\n alarmTableWidget,\n alarmCountWidget,\n alarmSeverityWidget,\n commandButtonWidget,\n entitySelectorWidget,\n mapWidget,\n linearGaugeWidget,\n levelGaugeWidget,\n batteryWidget,\n statusLightWidget,\n signalBarsWidget,\n compassWidget,\n progressRingWidget,\n commandSliderWidget,\n commandToggleWidget,\n statCardWidget,\n barChartWidget,\n pieChartWidget,\n fleetTableWidget,\n fleetCountWidget,\n deviceStatusWidget,\n onlineDoughnutWidget,\n historyTableWidget,\n] as const;\n\n// A fresh, sealed registry holding exactly the built-ins. Every call returns an independent\n// instance; a host composing extensions passes `[...builtinWidgetDefinitions, theirs]` to\n// createWidgetRegistry from @devicechain/widget-sdk instead.\nexport function createBuiltinWidgetRegistry(): WidgetRegistry {\n return createWidgetRegistry(builtinWidgetDefinitions);\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The aggregate and categorical registrations: descriptor eager, component lazy, from a chunk of\n// their own (aggregate-widgets.ts), so a board without a stat card, bar chart or pie chart never\n// downloads them. The bar and pie charts are SVG, so no chart engine type is loaded for them.\n\nimport { defineWidget, type AggregateStreamState } from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { lazyChunk } from './lazy-chunk';\n\nconst chunk = lazyChunk<typeof import('./aggregate-widgets')>(() => import('./aggregate-widgets'));\n\nexport const loadAggregateWidgets = chunk.load;\n\nexport const statCardWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['stat-card'],\n implementation: { kind: 'trusted-react', component: chunk.component<AggregateStreamState>('StatCard') },\n});\n\nexport const barChartWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['bar-chart'],\n implementation: { kind: 'trusted-react', component: chunk.component('BarChart') },\n});\n\nexport const pieChartWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['pie-chart'],\n implementation: { kind: 'trusted-react', component: chunk.component('PieChart') },\n});\n\nexport const fleetCountWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['fleet-count'],\n implementation: { kind: 'trusted-react', component: chunk.component('FleetCount') },\n});\n\nexport const fleetTableWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['fleet-table'],\n implementation: { kind: 'trusted-react', component: chunk.component('FleetTable') },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The portable descriptor of every built-in widget \u2014 pure data, React-free, importing no\n// component. The headless validators read the catalog built from these without ever\n// loading a widget; builtin-registry.ts pairs each descriptor with its component.\n//\n// \uD83D\uDD11 THE SOURCE OF TRUTH. A built-in's channel, option schema, defaults and binding policy are\n// declared here, once, as data. Nothing else in this package keeps an id-keyed table of them:\n// the by-id views the console still reads (WIDGET_CHANNEL, WIDGET_OPTIONS, ...) are derived,\n// read-only projections of these descriptors (registry.ts, options.ts).\n//\n// Every built-in carries version 1.0.0: a per-widget release number, NOT the platform\n// version. It is bumped only on a rendering change worth surfacing to an author, so a\n// platform release does not make every board look \"authored with an older widget\".\n\nimport { SEVERITY_LEVELS } from '@devicechain/widget-sdk';\nimport {\n createWidgetCatalog,\n defineWidgetDescriptor,\n type BuiltinWidgetId,\n type OptionSpec,\n type WidgetChannel,\n type WidgetDescriptor,\n type WidgetOptionSpecs,\n} from '@devicechain/dashboards';\n\n// ---- The doc-free runtime form ----------------------------------------------\n// These descriptors carry no option `doc` (it lives in builtin-option-docs.ts; see there for\n// why). The public `OptionSpec` keeps `doc: string` -- an extension author must write one, and a\n// reader of any descriptor this package publishes gets one -- so the runtime form is typed here:\n// a spec is declared against RuntimeOptionSpec, which FORBIDS a doc (one creeping back is a\n// compile error), and the descriptor is typed as its documented counterpart so it plugs into\n// the registry and defineWidget unchanged. That type claims a doc the value does not hold; it\n// never leaves this package except as `builtinWidgetDefinitionsWithoutDocs`, whose name says so.\ntype Undocumented<S> = S extends { kind: 'list'; item: infer I }\n ? Omit<S, 'doc' | 'item'> & { doc?: never; item: { readonly [K in keyof I]: Undocumented<I[K]> } }\n : Omit<S, 'doc'> & { doc?: never };\ntype RuntimeOptionSpec = Undocumented<OptionSpec>;\n\ntype Documented<S> = S extends { item: infer I }\n ? Omit<S, 'item'> & { readonly doc: string; readonly item: { readonly [K in keyof I]: Documented<I[K]> } }\n : S & { readonly doc: string };\nexport type DocumentedSpecs<S> = { readonly [K in keyof S]: Documented<S[K]> };\ntype AsSpecs<S> = DocumentedSpecs<S> extends infer D extends WidgetOptionSpecs ? D : never;\n\nconst defineRuntimeDescriptor = defineWidgetDescriptor as unknown as <\n const C extends WidgetChannel,\n const S extends Readonly<Record<string, RuntimeOptionSpec>>,\n>(\n descriptor: Omit<WidgetDescriptor<C, AsSpecs<S>>, 'options'> & { options: S },\n) => WidgetDescriptor<C, AsSpecs<S>>;\n\n// ---- Shared option specs ----------------------------------------------------\n// Declared once and referenced by each widget that reads them, so the same key always\n// carries the same type and bounds. They are still listed PER WIDGET below rather than\n// merged in from a base: which widget reads which option is the fact this table exists\n// to record, and a base object would hide it.\n\nconst TITLE = {\n kind: 'string',\n labelId: 'widgetLabelTitle',\n} as const satisfies RuntimeOptionSpec;\n\n// gauge and latest-card fall back to the displayed measurement's name when no title is set.\nconst TITLE_OR_MEASUREMENT = {\n kind: 'string',\n labelId: 'widgetLabelTitle',\n} as const satisfies RuntimeOptionSpec;\n\n// toFixed()'s domain is 0..100 \u2014 outside it throws a RangeError, which would take the\n// whole widget subtree down rather than degrading.\nconst PRECISION = {\n kind: 'number',\n integer: true,\n min: 0,\n max: 100,\n labelId: 'widgetLabelPrecision',\n helpId: 'widgetHintPrecision',\n} as const satisfies RuntimeOptionSpec;\n\n// Where a measurement crosses from one severity to the next. A threshold STARTS a band that\n// runs to the next threshold's value, so \"overheat above 105\" is one entry and \"low fuel below\n// 15\" is two (critical from 0, normal from 15). `level` is a severity NAME that the theme turns\n// into a colour; there is deliberately no colour field, so a board cannot carry a hex value\n// that ignores dark mode or the host's theme. Optional with no default: absent means no bands,\n// exactly as before the option existed, so it needs no optionsVersion bump.\nconst THRESHOLDS = {\n kind: 'list',\n maxItems: 12,\n labelId: 'widgetLabelThresholds',\n helpId: 'widgetHintThresholds',\n item: {\n value: {\n kind: 'number',\n required: true,\n labelId: 'widgetLabelThresholdValue',\n },\n level: {\n kind: 'enum',\n required: true,\n values: SEVERITY_LEVELS,\n labelId: 'widgetLabelThresholdLevel',\n valueLabelIds: {\n normal: 'widgetSeverityNormal',\n warning: 'widgetSeverityWarning',\n minor: 'widgetSeverityMinor',\n major: 'widgetSeverityMajor',\n critical: 'widgetSeverityCritical',\n },\n placeholderId: 'widgetPlaceholderThresholdLevel',\n },\n label: {\n kind: 'string',\n labelId: 'widgetLabelThresholdLabel',\n },\n },\n} as const satisfies RuntimeOptionSpec;\n\nconst FLASH_ON_CHANGE = {\n kind: 'boolean',\n labelId: 'widgetFlashOnChange',\n helpId: 'widgetFlashOnChangeHint',\n} as const satisfies RuntimeOptionSpec;\n\n// Read by MeasurementConnectedWidget for every measurement-channel widget, and declared on\n// each one that binds a datasource. It is NOT declared on label/image, which carry no\n// datasource at all, so there is no stream for it to size.\n//\n// It bounds the RETAINED buffer, not what is drawn: useMeasurementStream keeps `latest`\n// per measurement unconditionally and trims only `samples`. Only the chart draws\n// `samples`, so on a card, gauge or table this is a memory bound with no visible effect \u2014\n// declared because the renderer honors it, documented so nobody expects it to show.\n//\n// The trim is GLOBAL across the widget's measurements, not per measurement: `samples` is\n// one interleaved list, so a chart drawing N series retains roughly window/N of each. An\n// earlier version of this doc said \"per measurement\", and a caller sized a window off it\n// and got half the history it intended.\nconst WINDOW = {\n kind: 'number',\n integer: true,\n min: 1,\n labelId: 'widgetLabelWindow',\n helpId: 'widgetHintWindow',\n} as const satisfies RuntimeOptionSpec;\n\n// Read by the frame, not by the widget: with it set, a widget whose newest sample is older than\n// this many seconds is greyed out under a \"stale\" badge. Unset is the DEFAULT and means age\n// only -- there is no built-in threshold, because any number would paint a sparse fleet stale.\nconst STALE_AFTER_SECONDS = {\n kind: 'number',\n integer: true,\n min: 1,\n labelId: 'widgetLabelStaleAfter',\n helpId: 'widgetHintStaleAfter',\n} as const satisfies RuntimeOptionSpec;\n\nconst UNIT = {\n kind: 'string',\n labelId: 'widgetLabelUnit',\n} as const satisfies RuntimeOptionSpec;\n\n// The two ends of a level widget's scale. REQUIRED, with no default on the descriptor: a tank\n// or a thermometer drawn against a range nobody chose reads a wrong value as a plausible one,\n// so a widget without both ends says so instead of drawing (see level-reading.ts). The\n// greater-than constraint on each descriptor keeps the pair ordered.\nconst SCALE_MIN = {\n kind: 'number',\n required: true,\n labelId: 'widgetLabelMin',\n helpId: 'widgetHintScaleMin',\n} as const satisfies RuntimeOptionSpec;\n\nconst SCALE_MAX = {\n kind: 'number',\n required: true,\n labelId: 'widgetLabelMax',\n helpId: 'widgetHintScaleMax',\n} as const satisfies RuntimeOptionSpec;\n\n// The command a control sends. The three keys are the command-vocabulary triple the console's\n// command picker writes at once (the command button declares the same three), so picking a\n// command in the editor bakes its key, label and parameter schema here too.\nconst CONTROL_COMMAND_NAME = {\n kind: 'string',\n required: true,\n labelId: 'widgetCommandHeading',\n helpId: 'widgetCommandFieldHint',\n control: 'command-vocabulary',\n} as const satisfies RuntimeOptionSpec;\n\nconst CONTROL_COMMAND_LABEL = {\n kind: 'string',\n labelId: 'widgetCommandHeading',\n helpId: 'widgetCommandFieldHint',\n control: 'command-vocabulary',\n} as const satisfies RuntimeOptionSpec;\n\nconst CONTROL_PARAMETER_SCHEMA = {\n kind: 'string',\n format: 'json',\n labelId: 'widgetCommandHeading',\n helpId: 'widgetCommandFieldHint',\n control: 'command-vocabulary',\n} as const satisfies RuntimeOptionSpec;\n\nconst CONTROL_PARAMETER = {\n kind: 'string',\n labelId: 'widgetLabelParameter',\n helpId: 'widgetHintControlParameter',\n} as const satisfies RuntimeOptionSpec;\n\nconst MEASUREMENT = {\n kind: 'string',\n labelId: 'widgetLabelMeasurement',\n helpId: 'widgetHintMeasurement',\n} as const satisfies RuntimeOptionSpec;\n\nconst ALARM_STATE = {\n kind: 'enum',\n values: ['ACTIVE', 'CLEARED'],\n labelId: 'widgetLabelState',\n helpId: 'widgetStateHint',\n valueLabelIds: { ACTIVE: 'widgetAlarmStateActive', CLEARED: 'widgetAlarmStateCleared' },\n placeholderId: 'widgetPlaceholderAny',\n} as const satisfies RuntimeOptionSpec;\n\nconst ALARM_SEVERITY = {\n kind: 'enum',\n values: ['CRITICAL', 'MAJOR', 'MINOR', 'WARNING', 'INDETERMINATE'],\n labelId: 'widgetLabelSeverity',\n helpId: 'widgetSeverityHint',\n valueLabelIds: { CRITICAL: 'widgetAlarmSeverityCritical', MAJOR: 'widgetAlarmSeverityMajor', MINOR: 'widgetAlarmSeverityMinor', WARNING: 'widgetAlarmSeverityWarning', INDETERMINATE: 'widgetAlarmSeverityIndeterminate' },\n placeholderId: 'widgetPlaceholderAny',\n} as const satisfies RuntimeOptionSpec;\n\n// Stored as the STRING 'true'/'false', not a boolean \u2014 alarmSubscription() reads it with\n// optString and maps it through parseAcknowledged, so a real boolean here is read as\n// undefined and the filter silently disappears. Typed as an enum of those two strings so\n// that mistake is an error rather than a no-op.\nconst ALARM_ACKNOWLEDGED = {\n kind: 'enum',\n values: ['true', 'false'],\n labelId: 'widgetLabelAcknowledged',\n helpId: 'widgetAcknowledgedHint',\n valueLabelIds: { true: 'widgetAlarmAckAcknowledged', false: 'widgetAlarmAckUnacknowledged' },\n placeholderId: 'widgetPlaceholderAny',\n} as const satisfies RuntimeOptionSpec;\n\nconst SELECTION_TARGET = {\n kind: 'string',\n labelId: 'widgetLabelTargetSlot',\n helpId: 'widgetTargetSlotHint',\n control: 'slot-target',\n} as const satisfies RuntimeOptionSpec;\n\n\n// Each widget's `layout` is its size contract, in SQUARE cells. A cell is never smaller than the\n// grid's minCellSize (56 px by default; a narrower board reflows instead), so a span is a\n// readable size by construction, and the minimums below are sized at that smallest cell, with\n// 8 px gutters: n cells cover 64n - 8 px, so 2 is 120 px, 3 is 184 px and 4 is 248 px. On a wider\n// screen the cells stretch and every widget only grows.\n//\n// The minimums are the smallest box in which the widget's parts all fit with room to spare:\n// height is usually the binding constraint, since the frame header costs ~34-50 px before the\n// widget's own content. The defaults are what a freshly added widget takes. A maximum is\n// declared only where the content stops filling the box (a single value, a dial, a button, a\n// one-line selector); a chart, table, map or image fills a whole wall, so it has none, and a\n// label's column limit is set past any authored column count.\n\nconst VERSION = '1.0.0';\nconst ALL_SELECTORS = ['device', 'anchor', 'slot'] as const;\n// A telemetry widget that shows readings keyed by measurement name shows ONE device: bound to a group,\n// two devices reporting the same name would overwrite each other in it. Only the fleet widgets (the\n// fleet table, a bar chart with one bar per device) take a group, and the runtime refuses a group\n// that reaches any other one some other way (a host binding, a hand-edited definition).\nconst ONE_DEVICE = ['device', 'slot'] as const;\nconst NO_DATASOURCE = { mode: 'none' } as const;\n\n// The alarm filters are read by both alarm widgets from the same option keys.\nconst ALARM_FILTERS = {\n state: { option: 'state' },\n severity: { option: 'severity' },\n acknowledged: { option: 'acknowledged' },\n} as const;\n\n// The timeseries chart's window, as a SPAN. Unset, the chart follows the board's time range (which\n// a viewer can change from the header); set, it is PINNED to this span whatever the viewer picks,\n// which is what a \"last 5 minutes\" strip on a wall board wants. The bounds are the board range's:\n// a minute to a week.\n// The timeseries chart's event markers: off unless asked, and optional with no default, so a chart\n// saved before they existed needs no optionsVersion bump.\nconst MARK_ALARMS = {\n kind: 'boolean',\n labelId: 'widgetLabelMarkAlarms',\n helpId: 'widgetHintMarkAlarms',\n} as const satisfies RuntimeOptionSpec;\n\n// Which alarms the chart draws. Unset means 'device' (every alarm on the chart's device), which is\n// what a chart saved before this option existed does; a chart added from the palette starts at\n// 'series' (descriptor defaults below), so it draws only the alarms about what it charts.\nconst MARK_ALARMS_SCOPE = {\n kind: 'enum',\n values: ['series', 'device'],\n labelId: 'widgetLabelMarkAlarmsScope',\n helpId: 'widgetHintMarkAlarmsScope',\n valueLabelIds: { series: 'widgetMarkAlarmsScopeSeries', device: 'widgetMarkAlarmsScopeDevice' },\n placeholderId: 'widgetPlaceholderWholeDevice',\n} as const satisfies RuntimeOptionSpec;\n\nconst MARK_COMMANDS = {\n kind: 'boolean',\n labelId: 'widgetLabelMarkCommands',\n helpId: 'widgetHintMarkCommands',\n} as const satisfies RuntimeOptionSpec;\n\n// The timeseries chart's value-axis ends: optional, with no default, so the axis is ECharts' own\n// unless the author frames it. An end is reached, never clipped at: a reading beyond it widens the\n// axis. A 92 \u00B0C engine on an axis from zero is a flat line at the top of an empty tile; framed at\n// 70..130 it sits where its overheat edge can be seen above it.\nconst CHART_AXIS_MIN = {\n kind: 'number',\n labelId: 'widgetLabelMin',\n helpId: 'widgetHintChartAxisMin',\n} as const satisfies RuntimeOptionSpec;\n\nconst CHART_AXIS_MAX = {\n kind: 'number',\n labelId: 'widgetLabelMax',\n helpId: 'widgetHintChartAxisMax',\n} as const satisfies RuntimeOptionSpec;\n\n// The compare mode's line limit: optional, no default stored (the chart's own applies), whole numbers.\n// The ceiling (MAX_SERIES_LIMIT, 12) is the compare model's and is applied when the chart reads the\n// option, not declared here: the editor's own test drives each number option with a value spaced by its\n// position in the schema, which a ceiling this low cannot take.\nconst MAX_SERIES = {\n kind: 'number',\n integer: true,\n min: 1,\n labelId: 'widgetLabelMaxSeries',\n helpId: 'widgetHintMaxSeries',\n} as const satisfies RuntimeOptionSpec;\n\nconst WINDOW_SECONDS = {\n kind: 'number',\n integer: true,\n min: 60,\n max: 604800,\n labelId: 'widgetLabelWindowSeconds',\n helpId: 'widgetHintWindowSeconds',\n} as const satisfies RuntimeOptionSpec;\n\n// The categorical charts' shared options. Both draw the latest reading of each measurement the\n// datasource names: the order is the datasource's own unless a sort is set.\nconst CATEGORY_SORT = {\n kind: 'enum',\n values: ['none', 'ascending', 'descending'],\n labelId: 'widgetLabelSort',\n valueLabelIds: { none: 'widgetSortNone', ascending: 'widgetSortAscending', descending: 'widgetSortDescending' },\n placeholderId: 'widgetPlaceholderDefault',\n} as const satisfies RuntimeOptionSpec;\n\n// A fleet table's per-column and per-column-threshold entries NAME their measurement, because a list\n// item holds scalars only: one flat list per concern keeps each editable as a row, and a column\n// without an entry keeps the datasource's name, the board's formatting and no bands.\n// The measurement column a fleet table's list entry (a format, a band) applies to.\nconst FLEET_MEASUREMENT = {\n kind: 'string',\n required: true,\n labelId: 'widgetLabelMeasurement',\n} as const satisfies RuntimeOptionSpec;\n\nconst FLEET_COLUMNS = {\n kind: 'list',\n maxItems: 24,\n labelId: 'widgetLabelColumns',\n helpId: 'widgetHintColumns',\n item: {\n measurement: FLEET_MEASUREMENT,\n label: { kind: 'string', labelId: 'widgetLabelColumnHeading' },\n unit: { ...UNIT },\n precision: { ...PRECISION },\n },\n} as const satisfies RuntimeOptionSpec;\n\nconst FLEET_THRESHOLDS = {\n ...THRESHOLDS,\n item: {\n measurement: FLEET_MEASUREMENT,\n ...THRESHOLDS.item,\n },\n} as const satisfies RuntimeOptionSpec;\n\nexport const builtinWidgetDescriptors = {\n 'timeseries-chart': defineRuntimeDescriptor({\n id: 'timeseries-chart',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 2,\n display: { title: 'Timeseries chart', category: 'Telemetry', titleId: 'widgetTypeTimeseriesChart', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n // ALL_SELECTORS because of the compare mode (groupBy device): a group bound with the default mode\n // is refused in words at runtime, exactly as for the bar chart.\n datasource: { mode: 'required', selectors: ALL_SELECTORS },\n binding: { windowSeconds: { option: 'windowSeconds' }, members: { option: 'groupBy', equals: 'device' } },\n options: {\n title: TITLE,\n unit: UNIT,\n precision: PRECISION,\n thresholds: THRESHOLDS,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n windowSeconds: WINDOW_SECONDS,\n groupBy: {\n kind: 'enum',\n values: ['measurement', 'device'],\n labelId: 'widgetLabelSeriesBy',\n helpId: 'widgetHintSeriesBy',\n valueLabelIds: { measurement: 'widgetGroupByMeasurement', device: 'widgetGroupByDevice' },\n placeholderId: 'widgetPlaceholderDefault',\n },\n measurement: MEASUREMENT,\n maxSeries: MAX_SERIES,\n markAlarms: MARK_ALARMS,\n markAlarmsScope: MARK_ALARMS_SCOPE,\n markCommands: MARK_COMMANDS,\n min: CHART_AXIS_MIN,\n max: CHART_AXIS_MAX,\n },\n constraints: [{ kind: 'greater-than', key: 'max', than: 'min' }],\n defaults: { title: 'Timeseries chart', markAlarmsScope: 'series' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 6, rows: 4 }, minSpan: { cols: 4, rows: 3 } },\n }),\n\n 'latest-card': defineRuntimeDescriptor({\n id: 'latest-card',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Latest card', category: 'Telemetry', titleId: 'widgetTypeLatestCard', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: {\n kind: 'string',\n labelId: 'widgetLabelMeasurement',\n helpId: 'widgetHintMeasurement',\n },\n unit: UNIT,\n precision: PRECISION,\n thresholds: THRESHOLDS,\n flashOnChange: FLASH_ON_CHANGE,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n defaults: { title: 'Latest card' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 3, rows: 2 }, minSpan: { cols: 3, rows: 2 }, maxSpan: { cols: 6, rows: 4 } },\n }),\n\n gauge: defineRuntimeDescriptor({\n id: 'gauge',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Gauge', category: 'Telemetry', titleId: 'widgetTypeGauge', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: {\n kind: 'string',\n labelId: 'widgetLabelMeasurement',\n helpId: 'widgetHintMeasurement',\n },\n min: {\n kind: 'number',\n labelId: 'widgetLabelMin',\n },\n max: {\n kind: 'number',\n labelId: 'widgetLabelMax',\n },\n unit: UNIT,\n precision: PRECISION,\n thresholds: THRESHOLDS,\n flashOnChange: FLASH_ON_CHANGE,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n constraints: [{ kind: 'greater-than', key: 'max', than: 'min' }],\n defaults: { title: 'Gauge' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 3, rows: 3 }, minSpan: { cols: 3, rows: 3 }, maxSpan: { cols: 6, rows: 6 } },\n }),\n\n table: defineRuntimeDescriptor({\n id: 'table',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Table', category: 'Telemetry', titleId: 'widgetTypeTable', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE,\n precision: PRECISION,\n flashOnChange: FLASH_ON_CHANGE,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n defaults: { title: 'Table' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 6, rows: 3 }, minSpan: { cols: 4, rows: 2 } },\n }),\n\n // label and image are static: the `none` channel, no datasource, no subscription and no\n // history seed.\n label: defineRuntimeDescriptor({\n id: 'label',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Label', category: 'Static', titleId: 'widgetTypeLabel', categoryId: 'widgetCategoryStatic' },\n channel: 'none',\n datasource: NO_DATASOURCE,\n binding: {},\n options: {\n title: TITLE,\n text: {\n kind: 'string',\n required: true,\n labelId: 'widgetLabelText',\n },\n align: {\n kind: 'enum',\n values: ['left', 'center', 'right'],\n labelId: 'widgetLabelAlign',\n valueLabelIds: { left: 'widgetAlignLeft', center: 'widgetAlignCenter', right: 'widgetAlignRight' },\n placeholderId: 'widgetPlaceholderDefault',\n },\n fontSize: {\n kind: 'number',\n min: 1,\n labelId: 'widgetLabelFontSize',\n helpId: 'widgetHintFontSize',\n },\n },\n defaults: { text: 'New label' },\n interactions: {},\n layout: { defaultSpan: { cols: 3, rows: 1 }, minSpan: { cols: 1, rows: 1 }, maxSpan: { cols: 24, rows: 3 } },\n }),\n\n image: defineRuntimeDescriptor({\n id: 'image',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Image', category: 'Static', titleId: 'widgetTypeImage', categoryId: 'widgetCategoryStatic' },\n channel: 'none',\n datasource: NO_DATASOURCE,\n binding: {},\n options: {\n title: TITLE,\n url: {\n kind: 'string',\n required: true,\n labelId: 'widgetLabelImageUrl',\n },\n alt: {\n kind: 'string',\n labelId: 'widgetLabelAltText',\n },\n fit: {\n kind: 'enum',\n values: ['contain', 'cover', 'fill'],\n labelId: 'widgetLabelFit',\n valueLabelIds: { contain: 'widgetFitContain', cover: 'widgetFitCover', fill: 'widgetFitFill' },\n placeholderId: 'widgetPlaceholderDefault',\n },\n },\n defaults: { title: 'Image' },\n interactions: {},\n layout: { defaultSpan: { cols: 3, rows: 2 }, minSpan: { cols: 1, rows: 1 } },\n }),\n\n 'alarm-table': defineRuntimeDescriptor({\n id: 'alarm-table',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Alarm table', category: 'Alarms', titleId: 'widgetTypeAlarmTable', categoryId: 'widgetCategoryAlarms' },\n channel: 'alarm',\n datasource: { mode: 'optional', selectors: ALL_SELECTORS },\n // groupBy 'deviceType' turns the table into one tab per device type (plus All).\n binding: { pageSize: { option: 'maxRows', default: 50, min: 1 }, ...ALARM_FILTERS, groupBy: { option: 'groupBy', equals: 'deviceType' } },\n options: {\n title: TITLE,\n state: ALARM_STATE,\n severity: ALARM_SEVERITY,\n acknowledged: ALARM_ACKNOWLEDGED,\n groupBy: {\n kind: 'enum',\n values: ['none', 'deviceType'],\n labelId: 'widgetLabelAlarmGroupBy',\n helpId: 'widgetHintAlarmGroupBy',\n valueLabelIds: { none: 'widgetAlarmGroupByNone', deviceType: 'widgetAlarmGroupByDeviceType' },\n placeholderId: 'widgetPlaceholderDefault',\n },\n deviceTypes: {\n kind: 'list',\n maxItems: 24,\n ordered: true,\n labelId: 'widgetLabelAlarmDeviceTypes',\n helpId: 'widgetHintAlarmDeviceTypes',\n item: {\n token: { kind: 'string', control: 'device-type', labelId: 'widgetLabelAlarmDeviceTypeToken' },\n },\n },\n maxRows: {\n kind: 'number',\n integer: true,\n min: 1,\n labelId: 'widgetLabelMaxRows',\n helpId: 'widgetMaxRowsAlarmHint',\n },\n precision: PRECISION,\n flashOnChange: FLASH_ON_CHANGE,\n selectionTarget: SELECTION_TARGET,\n },\n defaults: { title: 'Alarm table', state: 'ACTIVE' },\n interactions: { alarmActions: true, selection: true },\n layout: { defaultSpan: { cols: 6, rows: 4 }, minSpan: { cols: 4, rows: 2 } },\n }),\n\n // The count shows the SERVER total and reads a page only to sample the worst loaded\n // severity, so its page size is a constant rather than an authorable option.\n 'alarm-count': defineRuntimeDescriptor({\n id: 'alarm-count',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Alarm count', category: 'Alarms', titleId: 'widgetTypeAlarmCount', categoryId: 'widgetCategoryAlarms' },\n channel: 'alarm',\n datasource: { mode: 'optional', selectors: ALL_SELECTORS },\n binding: { pageSize: { const: 50 }, ...ALARM_FILTERS },\n // No maxRows: alarmSubscription() forces the default page size for a count, because the\n // number it shows is the SERVER total and the page is read only to sample the worst\n // loaded severity. An authored maxRows here would be read by nothing.\n options: {\n title: TITLE,\n state: ALARM_STATE,\n severity: ALARM_SEVERITY,\n acknowledged: ALARM_ACKNOWLEDGED,\n },\n defaults: { title: 'Alarm count', state: 'ACTIVE' },\n interactions: {},\n layout: { defaultSpan: { cols: 3, rows: 2 }, minSpan: { cols: 2, rows: 2 }, maxSpan: { cols: 6, rows: 4 } },\n }),\n\n // Alarms by severity, from ONE grouped count read (device-management's per-severity counts, every\n // originator, exact past any page). Not a mode of alarm-count: a different shape and size, and no\n // severity filter. `deviceType` narrows it to the alarms on one type's devices.\n 'alarm-severity': defineRuntimeDescriptor({\n id: 'alarm-severity',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: {\n title: 'Alarm severity',\n category: 'Alarms',\n titleId: 'widgetTypeAlarmSeverity',\n categoryId: 'widgetCategoryAlarms',\n },\n channel: 'alarm',\n datasource: { mode: 'optional', selectors: ALL_SELECTORS },\n binding: {\n pageSize: { const: 1 },\n state: { option: 'state' },\n acknowledged: { option: 'acknowledged' },\n countBySeverity: { const: true },\n deviceType: { option: 'deviceType' },\n },\n options: {\n title: TITLE,\n state: ALARM_STATE,\n acknowledged: ALARM_ACKNOWLEDGED,\n deviceType: {\n kind: 'string',\n control: 'device-type',\n labelId: 'widgetLabelAlarmSeverityType',\n helpId: 'widgetHintAlarmSeverityType',\n },\n },\n defaults: { title: 'Alarm severity', state: 'ACTIVE' },\n interactions: {},\n layout: { defaultSpan: { cols: 4, rows: 2 }, minSpan: { cols: 3, rows: 2 }, maxSpan: { cols: 12, rows: 4 } },\n }),\n\n 'command-button': defineRuntimeDescriptor({\n id: 'command-button',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Command button', category: 'Control', titleId: 'widgetTypeCommandButton', categoryId: 'widgetCategoryControl' },\n channel: 'control',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { pageSize: { option: 'maxRows', default: 20, min: 1 } },\n options: {\n title: TITLE,\n commandName: {\n kind: 'string',\n required: true,\n labelId: 'widgetCommandHeading',\n helpId: 'widgetCommandFieldHint',\n control: 'command-vocabulary',\n },\n commandLabel: {\n kind: 'string',\n labelId: 'widgetCommandHeading',\n helpId: 'widgetCommandFieldHint',\n control: 'command-vocabulary',\n },\n parameterSchema: {\n kind: 'string',\n format: 'json',\n labelId: 'widgetCommandHeading',\n helpId: 'widgetCommandFieldHint',\n control: 'command-vocabulary',\n },\n maxRows: {\n kind: 'number',\n integer: true,\n min: 1,\n labelId: 'widgetLabelMaxRows',\n helpId: 'widgetMaxRowsCommandHint',\n },\n },\n defaults: { title: 'Command button' },\n interactions: { commandSend: true },\n layout: { defaultSpan: { cols: 3, rows: 3 }, minSpan: { cols: 3, rows: 2 }, maxSpan: { cols: 6, rows: 6 } },\n }),\n\n 'entity-selector': defineRuntimeDescriptor({\n id: 'entity-selector',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Entity selector', category: 'Navigation', titleId: 'widgetTypeEntitySelector', categoryId: 'widgetCategoryNavigation' },\n channel: 'selection',\n datasource: NO_DATASOURCE,\n binding: {},\n options: {\n title: TITLE,\n selectionTarget: { ...SELECTION_TARGET, required: true },\n },\n defaults: { title: 'Entity selector' },\n interactions: { selection: true, candidates: true },\n // A select control is one line high, so its rows are pinned; it widens to fit long names.\n layout: { defaultSpan: { cols: 3, rows: 1 }, minSpan: { cols: 3, rows: 1 }, maxSpan: { cols: 12, rows: 1 }, resize: 'horizontal' },\n }),\n\n map: defineRuntimeDescriptor({\n id: 'map',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Map', category: 'Location', titleId: 'widgetTypeMap', categoryId: 'widgetCategoryLocation' },\n channel: 'location',\n datasource: { mode: 'required', selectors: ALL_SELECTORS },\n binding: {},\n // \uD83D\uDD34 tileUrl is NOT `required`, and that is the decision rather than an oversight.\n // `required` means \"absent leaves the widget with nothing to show\", and a map without\n // a basemap still shows every position it was asked to \u2014 on a plain panel, saying why\n // there is no map behind them. Marking it required would report a correctly-rendering\n // widget as broken on every board that names no provider of its own \u2014 which is most\n // of them, because the usual and recommended answer is to inherit the tenant's\n // basemap rather than to configure tiles per board.\n options: {\n title: TITLE,\n tileUrl: {\n kind: 'string',\n labelId: 'widgetLabelTileUrl',\n helpId: 'widgetTileUrlHint',\n control: 'basemap',\n },\n attribution: {\n kind: 'string',\n labelId: 'widgetLabelAttribution',\n helpId: 'widgetAttributionHint',\n control: 'basemap',\n },\n // Optional and additive: unset, a marker is only a mark. Set, clicking a marker re-points\n // that slot at the device, exactly as a fleet-table row does.\n selectionTarget: SELECTION_TARGET,\n },\n defaults: { title: 'Map' },\n interactions: { selection: true },\n layout: { defaultSpan: { cols: 6, rows: 4 }, minSpan: { cols: 4, rows: 3 } },\n }),\n\n // ---- Levels and indicators ------------------------------------------------\n // DOM/SVG single-value widgets on the measurement channel. A threshold band colours the fill\n // or lamp; `normal` keeps the widget's neutral accent.\n\n 'linear-gauge': defineRuntimeDescriptor({\n id: 'linear-gauge',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Linear gauge', category: 'Telemetry', titleId: 'widgetTypeLinearGauge', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: MEASUREMENT,\n min: SCALE_MIN,\n max: SCALE_MAX,\n style: {\n kind: 'enum',\n values: ['bar', 'thermometer'],\n labelId: 'widgetLabelLinearStyle',\n valueLabelIds: { bar: 'widgetLinearStyleBar', thermometer: 'widgetLinearStyleThermometer' },\n placeholderId: 'widgetPlaceholderDefault',\n },\n orientation: {\n kind: 'enum',\n values: ['horizontal', 'vertical'],\n labelId: 'widgetLabelOrientation',\n valueLabelIds: { horizontal: 'widgetOrientationHorizontal', vertical: 'widgetOrientationVertical' },\n placeholderId: 'widgetPlaceholderDefault',\n },\n unit: UNIT,\n precision: PRECISION,\n thresholds: THRESHOLDS,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n constraints: [{ kind: 'greater-than', key: 'max', than: 'min' }],\n defaults: { title: 'Linear gauge' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 4, rows: 3 }, minSpan: { cols: 3, rows: 3 }, maxSpan: { cols: 8, rows: 8 } },\n }),\n\n 'level-gauge': defineRuntimeDescriptor({\n id: 'level-gauge',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Level gauge', category: 'Telemetry', titleId: 'widgetTypeLevelGauge', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: MEASUREMENT,\n min: SCALE_MIN,\n max: SCALE_MAX,\n readout: {\n kind: 'enum',\n values: ['value', 'percent'],\n labelId: 'widgetLabelReadout',\n valueLabelIds: { value: 'widgetReadoutValue', percent: 'widgetReadoutPercent' },\n placeholderId: 'widgetPlaceholderDefault',\n },\n unit: UNIT,\n precision: PRECISION,\n thresholds: THRESHOLDS,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n constraints: [{ kind: 'greater-than', key: 'max', than: 'min' }],\n defaults: { title: 'Level gauge' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 3, rows: 4 }, minSpan: { cols: 2, rows: 3 }, maxSpan: { cols: 6, rows: 8 } },\n }),\n\n battery: defineRuntimeDescriptor({\n id: 'battery',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Battery', category: 'Telemetry', titleId: 'widgetTypeBattery', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: MEASUREMENT,\n min: {\n kind: 'number',\n labelId: 'widgetLabelMin',\n helpId: 'widgetHintBatteryRange',\n },\n max: {\n kind: 'number',\n labelId: 'widgetLabelMax',\n helpId: 'widgetHintBatteryRange',\n },\n unit: UNIT,\n precision: PRECISION,\n thresholds: THRESHOLDS,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n constraints: [{ kind: 'greater-than', key: 'max', than: 'min' }],\n defaults: { title: 'Battery' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 3, rows: 2 }, minSpan: { cols: 2, rows: 2 }, maxSpan: { cols: 6, rows: 4 } },\n }),\n\n 'status-light': defineRuntimeDescriptor({\n id: 'status-light',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Status light', category: 'Telemetry', titleId: 'widgetTypeStatusLight', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: MEASUREMENT,\n onAt: {\n kind: 'number',\n labelId: 'widgetLabelOnAt',\n helpId: 'widgetHintOnAt',\n },\n unit: UNIT,\n precision: PRECISION,\n thresholds: THRESHOLDS,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n defaults: { title: 'Status light' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 2, rows: 2 }, minSpan: { cols: 2, rows: 2 }, maxSpan: { cols: 4, rows: 4 } },\n }),\n\n 'signal-bars': defineRuntimeDescriptor({\n id: 'signal-bars',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Signal bars', category: 'Telemetry', titleId: 'widgetTypeSignalBars', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: MEASUREMENT,\n unit: UNIT,\n precision: PRECISION,\n // One bar per threshold: the entries ARE the steps, so they are required.\n thresholds: {\n ...THRESHOLDS,\n maxItems: 8,\n required: true,\n helpId: 'widgetHintSignalThresholds',\n },\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n defaults: { title: 'Signal bars' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 2, rows: 2 }, minSpan: { cols: 2, rows: 2 }, maxSpan: { cols: 4, rows: 4 } },\n }),\n\n // ---- Radial family ----------------------------------------------------------\n // A heading on a full turn, and a ring filled between a configured min and max. The compass\n // draws on the registered gauge series; the ring is SVG. Both put their number in DOM text.\n\n compass: defineRuntimeDescriptor({\n id: 'compass',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Compass', category: 'Telemetry', titleId: 'widgetTypeCompass', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: MEASUREMENT,\n precision: {\n ...PRECISION,\n },\n thresholds: {\n ...THRESHOLDS,\n },\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n defaults: { title: 'Compass' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 4, rows: 4 }, minSpan: { cols: 3, rows: 3 }, maxSpan: { cols: 8, rows: 8 } },\n }),\n\n 'progress-ring': defineRuntimeDescriptor({\n id: 'progress-ring',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Progress ring', category: 'Telemetry', titleId: 'widgetTypeProgressRing', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: MEASUREMENT,\n min: SCALE_MIN,\n max: SCALE_MAX,\n readout: {\n kind: 'enum',\n values: ['percent', 'value'],\n labelId: 'widgetLabelReadout',\n valueLabelIds: { percent: 'widgetReadoutPercent', value: 'widgetReadoutValue' },\n placeholderId: 'widgetPlaceholderDefault',\n },\n unit: UNIT,\n precision: PRECISION,\n thresholds: THRESHOLDS,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n constraints: [{ kind: 'greater-than', key: 'max', than: 'min' }],\n defaults: { title: 'Progress ring' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 3, rows: 3 }, minSpan: { cols: 2, rows: 2 }, maxSpan: { cols: 6, rows: 6 } },\n }),\n\n 'command-slider': defineRuntimeDescriptor({\n id: 'command-slider',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Command slider', category: 'Control', titleId: 'widgetTypeCommandSlider', categoryId: 'widgetCategoryControl' },\n channel: 'control',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n // The control reads its last-sent value off this history, so it asks for a long one.\n binding: { pageSize: { const: 50 } },\n options: {\n title: TITLE,\n commandName: CONTROL_COMMAND_NAME,\n commandLabel: CONTROL_COMMAND_LABEL,\n parameterSchema: CONTROL_PARAMETER_SCHEMA,\n parameter: CONTROL_PARAMETER,\n min: {\n kind: 'number',\n labelId: 'widgetLabelMin',\n helpId: 'widgetHintSliderRange',\n },\n max: {\n kind: 'number',\n labelId: 'widgetLabelMax',\n helpId: 'widgetHintSliderRange',\n },\n step: {\n kind: 'number',\n min: 0,\n labelId: 'widgetLabelStep',\n helpId: 'widgetHintSliderStep',\n },\n mode: {\n kind: 'enum',\n values: ['slider', 'stepper'],\n labelId: 'widgetLabelControlMode',\n valueLabelIds: { slider: 'widgetControlModeSlider', stepper: 'widgetControlModeStepper' },\n placeholderId: 'widgetPlaceholderDefault',\n },\n },\n constraints: [{ kind: 'greater-than', key: 'max', than: 'min' }],\n defaults: { title: 'Command slider' },\n interactions: { commandSend: true },\n layout: { defaultSpan: { cols: 4, rows: 2 }, minSpan: { cols: 3, rows: 2 }, maxSpan: { cols: 8, rows: 3 } },\n }),\n\n 'command-toggle': defineRuntimeDescriptor({\n id: 'command-toggle',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Command toggle', category: 'Control', titleId: 'widgetTypeCommandToggle', categoryId: 'widgetCategoryControl' },\n channel: 'control',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { pageSize: { const: 50 } },\n options: {\n title: TITLE,\n commandName: CONTROL_COMMAND_NAME,\n commandLabel: CONTROL_COMMAND_LABEL,\n parameterSchema: CONTROL_PARAMETER_SCHEMA,\n parameter: CONTROL_PARAMETER,\n },\n defaults: { title: 'Command toggle' },\n interactions: { commandSend: true },\n layout: { defaultSpan: { cols: 3, rows: 2 }, minSpan: { cols: 2, rows: 2 }, maxSpan: { cols: 6, rows: 3 } },\n }),\n 'stat-card': defineRuntimeDescriptor({\n id: 'stat-card',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Stat card', category: 'Telemetry', titleId: 'widgetTypeStatCard', categoryId: 'widgetCategoryTelemetry' },\n channel: 'aggregate',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { windowSeconds: { option: 'windowSeconds' } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: MEASUREMENT,\n stat: {\n kind: 'enum',\n values: ['avg', 'min', 'max', 'sum', 'count', 'last'],\n labelId: 'widgetLabelStat',\n helpId: 'widgetHintStat',\n valueLabelIds: {\n avg: 'widgetStatAvg',\n min: 'widgetStatMin',\n max: 'widgetStatMax',\n sum: 'widgetStatSum',\n count: 'widgetStatCount',\n last: 'widgetStatLast',\n },\n placeholderId: 'widgetPlaceholderDefault',\n },\n unit: UNIT,\n precision: PRECISION,\n thresholds: THRESHOLDS,\n sparkline: {\n kind: 'boolean',\n labelId: 'widgetLabelSparkline',\n helpId: 'widgetHintSparkline',\n },\n windowSeconds: WINDOW_SECONDS,\n },\n defaults: { title: 'Stat card' },\n interactions: {},\n layout: { defaultSpan: { cols: 3, rows: 3 }, minSpan: { cols: 3, rows: 2 }, maxSpan: { cols: 6, rows: 4 } },\n }),\n\n 'bar-chart': defineRuntimeDescriptor({\n id: 'bar-chart',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Bar chart', category: 'Telemetry', titleId: 'widgetTypeBarChart', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ALL_SELECTORS },\n // One bar per measurement of a device, or (groupBy device) one bar per member of an anchor.\n binding: { members: { option: 'groupBy', equals: 'device' } },\n options: {\n title: TITLE,\n groupBy: {\n kind: 'enum',\n values: ['measurement', 'device'],\n labelId: 'widgetLabelGroupBy',\n helpId: 'widgetHintGroupBy',\n valueLabelIds: { measurement: 'widgetGroupByMeasurement', device: 'widgetGroupByDevice' },\n placeholderId: 'widgetPlaceholderDefault',\n },\n measurement: MEASUREMENT,\n unit: UNIT,\n precision: PRECISION,\n sort: CATEGORY_SORT,\n },\n defaults: { title: 'Bar chart' },\n interactions: {},\n layout: { defaultSpan: { cols: 6, rows: 4 }, minSpan: { cols: 4, rows: 3 } },\n }),\n\n 'pie-chart': defineRuntimeDescriptor({\n id: 'pie-chart',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Pie chart', category: 'Telemetry', titleId: 'widgetTypePieChart', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: {},\n options: { title: TITLE, unit: UNIT, precision: PRECISION, sort: CATEGORY_SORT },\n defaults: { title: 'Pie chart' },\n interactions: {},\n layout: { defaultSpan: { cols: 4, rows: 4 }, minSpan: { cols: 3, rows: 3 }, maxSpan: { cols: 8, rows: 8 } },\n }),\n\n // A new widget rather than a mode of `table`: that one is one device's measurements as rows, on a\n // channel that keys its values by name; this one is a fleet, a row per member and a column per\n // measurement, and reads its data by device.\n 'fleet-table': defineRuntimeDescriptor({\n id: 'fleet-table',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Fleet table', category: 'Telemetry', titleId: 'widgetTypeFleetTable', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ALL_SELECTORS },\n binding: { windowSeconds: { option: 'windowSeconds' }, members: { const: true } },\n options: {\n title: TITLE,\n columns: FLEET_COLUMNS,\n thresholds: FLEET_THRESHOLDS,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n ageLagSeconds: {\n kind: 'number',\n integer: true,\n min: 1,\n labelId: 'widgetLabelAgeLag',\n helpId: 'widgetHintAgeLag',\n },\n sortBy: {\n kind: 'string',\n labelId: 'widgetLabelSortBy',\n helpId: 'widgetHintSortBy',\n },\n sortDescending: { kind: 'boolean', labelId: 'widgetLabelSortDescending' },\n pageSize: {\n kind: 'number',\n integer: true,\n min: 5,\n max: 100,\n labelId: 'widgetLabelPageSize',\n },\n selectionTarget: SELECTION_TARGET,\n windowSeconds: WINDOW_SECONDS,\n },\n defaults: { title: 'Fleet table' },\n // The frame shows the age of the newest reading in the fleet; each cell shows its own.\n freshness: true,\n interactions: { selection: true },\n layout: { defaultSpan: { cols: 12, rows: 6 }, minSpan: { cols: 6, rows: 3 } },\n }),\n\n // Counts a fleet rather than listing it: how many of its devices are in an abnormal band of one\n // measurement (\"3 of 21\"), or how many devices it has. A new widget rather than a mode of the\n // fleet table, which is a grid; this is the figure above one.\n 'fleet-count': defineRuntimeDescriptor({\n id: 'fleet-count',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Fleet count', category: 'Telemetry', titleId: 'widgetTypeFleetCount', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ALL_SELECTORS },\n binding: { windowSeconds: { option: 'windowSeconds' }, members: { const: true } },\n options: {\n title: TITLE,\n show: {\n kind: 'enum',\n values: ['attention', 'devices'],\n labelId: 'widgetLabelFleetShow',\n helpId: 'widgetHintFleetShow',\n valueLabelIds: { attention: 'widgetFleetShowAttention', devices: 'widgetFleetShowDevices' },\n placeholderId: 'widgetPlaceholderDefault',\n },\n measurement: {\n ...MEASUREMENT,\n },\n thresholds: THRESHOLDS,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n windowSeconds: WINDOW_SECONDS,\n },\n defaults: { title: 'Fleet count' },\n freshness: true,\n interactions: {},\n layout: { defaultSpan: { cols: 3, rows: 3 }, minSpan: { cols: 3, rows: 3 }, maxSpan: { cols: 6, rows: 4 } },\n }),\n\n // One device's connectivity: Online or Offline, and when it was last seen. It reads device-state\n // (`binding.presence`), not the device's readings, and shows one device, so it takes no group.\n 'device-status': defineRuntimeDescriptor({\n id: 'device-status',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Device status', category: 'Telemetry', titleId: 'widgetTypeDeviceStatus', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { presence: { const: true } },\n options: { title: TITLE, staleAfterSeconds: STALE_AFTER_SECONDS },\n defaults: { title: 'Device status' },\n // The frame's age is the status's: when device-state was last read, not the device's last activity.\n freshness: true,\n interactions: {},\n layout: { defaultSpan: { cols: 3, rows: 3 }, minSpan: { cols: 3, rows: 3 }, maxSpan: { cols: 6, rows: 4 } },\n }),\n\n // How many of a group's devices are online: a ring of online, offline and no status yet. A new\n // widget rather than a mode of the pie chart, which is shares of readings; this reads device-state.\n 'online-doughnut': defineRuntimeDescriptor({\n id: 'online-doughnut',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Online doughnut', category: 'Telemetry', titleId: 'widgetTypeOnlineDoughnut', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ALL_SELECTORS },\n binding: { presence: { const: true } },\n options: { title: TITLE, staleAfterSeconds: STALE_AFTER_SECONDS },\n defaults: { title: 'Online doughnut' },\n // The frame's age is the status's: when device-state was last read for the group.\n freshness: true,\n interactions: {},\n layout: { defaultSpan: { cols: 4, rows: 4 }, minSpan: { cols: 3, rows: 3 }, maxSpan: { cols: 8, rows: 8 } },\n }),\n\n // One device's stored history as rows: a row per time bucket over the span, a column per\n // measurement, each cell the bucket's AVERAGE (the table says \"avg per 5m\"). It reads the store's\n // buckets (`binding.history`), never the live feed, so it is time-ranged and takes one device.\n 'history-table': defineRuntimeDescriptor({\n id: 'history-table',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'History table', category: 'Telemetry', titleId: 'widgetTypeHistoryTable', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { windowSeconds: { option: 'windowSeconds' }, history: { const: true } },\n options: {\n title: TITLE,\n columns: FLEET_COLUMNS,\n precision: PRECISION,\n oldestFirst: { kind: 'boolean', labelId: 'widgetLabelOldestFirst' },\n pageSize: {\n kind: 'number',\n integer: true,\n min: 5,\n max: 100,\n labelId: 'widgetLabelRowsPerPage',\n },\n staleAfterSeconds: STALE_AFTER_SECONDS,\n windowSeconds: WINDOW_SECONDS,\n },\n defaults: { title: 'History table' },\n // The frame's age is the table's: when its buckets were last read.\n freshness: true,\n interactions: {},\n layout: { defaultSpan: { cols: 6, rows: 5 }, minSpan: { cols: 4, rows: 3 } },\n }),\n} as const satisfies Record<BuiltinWidgetId, WidgetDescriptor>;\n\n// The catalog the headless validators read. Constructed at module load, so a built-in that\n// fails its own validation fails every consumer of this package on import \u2014 loudly, and not\n// only in a test.\nexport const builtinWidgetCatalog = createWidgetCatalog(Object.values(builtinWidgetDescriptors));\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The alarm registrations: descriptor eager, component lazy, from a chunk of their own\n// (alarm-widgets.ts), so a board without an alarm table or alarm count never downloads them.\n//\n// AlarmTable and AlarmCount are also public exports of this package. That keeps them in this\n// package's own entry graph, and a host bundler drops them from its first download only because\n// package.json declares the modules free of side effects (see dist-shape.test.ts).\n\nimport { defineWidget, type AlarmStreamState } from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { lazyChunk } from './lazy-chunk';\n\nconst chunk = lazyChunk<typeof import('./alarm-widgets'), AlarmStreamState>(() => import('./alarm-widgets'));\n\nexport const loadAlarmWidgets = chunk.load;\n\nexport const alarmTableWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['alarm-table'],\n implementation: { kind: 'trusted-react', component: chunk.component('AlarmTable') },\n});\n\nexport const alarmSeverityWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['alarm-severity'],\n implementation: { kind: 'trusted-react', component: chunk.component('AlarmSeverity') },\n});\n\nexport const alarmCountWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['alarm-count'],\n implementation: { kind: 'trusted-react', component: chunk.component('AlarmCount') },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The command-control registrations: descriptor eager, component lazy, from a chunk of their own\n// (control-widgets.ts) so a board without a command button, slider or toggle never downloads the\n// sending code.\n\nimport { defineWidget, type CommandStreamState } from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { lazyChunk } from './lazy-chunk';\n\nconst chunk = lazyChunk<typeof import('./control-widgets'), CommandStreamState>(() => import('./control-widgets'));\n\nexport const loadControlWidgets = chunk.load;\n\nexport const commandSliderWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['command-slider'],\n implementation: { kind: 'trusted-react', component: chunk.component('CommandSlider') },\n});\n\nexport const commandToggleWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['command-toggle'],\n implementation: { kind: 'trusted-react', component: chunk.component('CommandToggle') },\n});\n\nexport const commandButtonWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['command-button'],\n implementation: { kind: 'trusted-react', component: chunk.component('CommandButton') },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The history table's registration: descriptor eager, component lazy, from a chunk of its own\n// (history-widgets.ts), so a board without one never downloads it.\n\nimport { defineWidget } from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { lazyChunk } from './lazy-chunk';\n\nconst chunk = lazyChunk<typeof import('./history-widgets')>(() => import('./history-widgets'));\n\nexport const loadHistoryWidgets = chunk.load;\n\nexport const historyTableWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['history-table'],\n implementation: { kind: 'trusted-react', component: chunk.component('HistoryTable') },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The presence registrations: descriptor eager, component lazy, from a chunk of their own\n// (presence-widgets.ts), so a board without a device status card or an online doughnut never\n// downloads them.\n\nimport { defineWidget } from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { lazyChunk } from './lazy-chunk';\n\nconst chunk = lazyChunk<typeof import('./presence-widgets')>(() => import('./presence-widgets'));\n\nexport const loadPresenceWidgets = chunk.load;\n\nexport const deviceStatusWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['device-status'],\n implementation: { kind: 'trusted-react', component: chunk.component('DeviceStatus') },\n});\n\nexport const onlineDoughnutWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['online-doughnut'],\n implementation: { kind: 'trusted-react', component: chunk.component('OnlineDoughnut') },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The entity selector's registration: descriptor eager, component lazy, from a chunk of its own,\n// so a board with no selector never downloads it. EntitySelector is also a public export; see\n// alarm-lazy.tsx for what that means for a host's first download.\n\nimport { defineWidget } from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { lazyChunk } from './lazy-chunk';\n\nconst chunk = lazyChunk<typeof import('./entity-selector'), null>(() => import('./entity-selector'));\n\nexport const loadSelectionWidgets = chunk.load;\n\nexport const entitySelectorWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['entity-selector'],\n implementation: { kind: 'trusted-react', component: chunk.component('EntitySelector') },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// gauge \u2014 the current value of one measurement on an ECharts radial gauge.\n\nimport { useMemo } from 'react';\n\nimport {\n defineWidget,\n flashBackgroundStyle,\n formatValue,\n optBoolean,\n optNumber,\n optString,\n optThresholds,\n pickSample,\n primaryMeasurementName,\n useFlashOnChange,\n useWidgetScale,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\nimport { buildGaugeOption, EChart, gaugeReadoutBox, loadChartEngine, useChartTheme } from '@devicechain/widget-sdk/echarts';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { NoReading, useSettledEmpty } from './no-reading-lazy';\nimport { LevelReadout } from '../level-readout';\nimport { readRange } from '../value-scale';\n\nexport function Gauge({ widget, data }: WidgetProps) {\n const name = primaryMeasurementName(widget);\n const sample = pickSample(data.latest, name);\n return (\n <WidgetFrame title={optString(widget.options, 'title') ?? name} sampleTime={sample?.occurredTime ?? null} flush>\n <GaugeBody widget={widget} data={data} />\n </WidgetFrame>\n );\n}\n\n// Rendered INSIDE the frame: the widget scale is the frame's content column, which is only in\n// context below the frame.\nfunction GaugeBody({ widget, data }: WidgetProps) {\n const theme = useChartTheme();\n const { size, scale } = useWidgetScale();\n const name = primaryMeasurementName(widget);\n const sample = pickSample(data.latest, name);\n\n const min = optNumber(widget.options, 'min');\n const max = optNumber(widget.options, 'max');\n const unit = optString(widget.options, 'unit');\n const precision = optNumber(widget.options, 'precision');\n // The stored list is re-parsed only when the options bag changes, so the memo below keys on\n // a stable array rather than a fresh one per render.\n const thresholds = useMemo(() => optThresholds(widget.options, 'thresholds'), [widget.options]);\n\n const option = useMemo(\n () => buildGaugeOption(sample?.value ?? null, theme, { min, max, thresholds, scale, readout: 'none', emptyNeedle: 'none' }, size),\n [sample?.value, theme, min, max, thresholds, scale, size],\n );\n\n // Opt-in directional flash. The value lives on an opaque canvas, so the cue is a\n // translucent tint on the container behind it rather than a recolored number. The identity\n // (device + measurement) suppresses a false flash on an anchor's cross-device interleave.\n const flashDirection = useFlashOnChange(\n sample?.value,\n optBoolean(widget.options, 'flashOnChange'),\n sample && `${sample.deviceToken}:${sample.name}`,\n );\n\n // The number is DOM text laid over the dial where the canvas used to print it, so the\n // readability gate can measure it (it cannot see canvas text). The meter role carries the\n // reading to assistive tech, which the canvas never did.\n const box = gaugeReadoutBox(size);\n const range = readRange(min, max, { min: 0, max: 100 });\n const value = sample?.value ?? undefined;\n const meter =\n range.ok && value !== undefined && Number.isFinite(value)\n ? {\n role: 'meter' as const,\n 'aria-valuemin': range.range.min,\n 'aria-valuemax': range.range.max,\n 'aria-valuenow': Math.min(range.range.max, Math.max(range.range.min, value)),\n 'aria-valuetext': `${formatValue(value, precision)}${unit ? ` ${unit}` : ''}`,\n }\n : {};\n\n // No reading: the dial would be an empty arc; say why instead (after the first moment, while a\n // board is still loading the dial is drawn as it always was).\n const explain = useSettledEmpty(value === undefined);\n if (explain) {\n return <NoReading unbound={widget.datasource?.kind === 'unbound'} measurement={name} waitMs={0} />;\n }\n\n return (\n <div style={{ position: 'relative', width: '100%', height: '100%', ...flashBackgroundStyle(flashDirection) }} {...meter}>\n <EChart option={option} />\n <div\n style={{\n position: 'absolute',\n left: box.centerX - box.width / 2,\n top: box.centerY - box.height / 2,\n width: box.width,\n height: box.height,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n pointerEvents: 'none',\n }}\n >\n <LevelReadout\n text={formatValue(value, precision)}\n unit={value === undefined ? undefined : unit}\n size={{ width: box.width, height: box.height }}\n scale={scale}\n />\n </div>\n </div>\n );\n}\n\n// What preloadWidgets calls: the chart engine loads on demand, as its own chunk, so a host that\n// awaits this for a board holding this widget draws the chart on the board's first frame.\nGauge.preload = loadChartEngine;\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const gaugeWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['gauge'],\n implementation: { kind: 'trusted-react', component: Gauge },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The explained empty state, as the EAGER widgets (the latest-value card, the gauge, the line chart)\n// reach it. The state itself (no-reading.tsx and the SDK's empty-state) loads as a chunk of its own on\n// first use: a board whose widgets all have data never downloads it, and the first-load budget\n// is not spent on words the common case does not show. Until it arrives the widget's box is empty,\n// which is the same as the one frame an empty widget was blank for before there was a state to show.\n\nimport { useEffect, useState } from 'react';\n\nimport { lazyChunk } from './lazy-chunk';\nimport type { NoReadingProps } from '../no-reading';\n\nexport const NoReading = lazyChunk<typeof import('../no-reading')>(() => import('../no-reading')).component<never, NoReadingProps>('NoReading');\n\n// True once `empty` has held for `ms`. A chart is blank for a moment on every board load while its\n// history seed is read, so it explains the absence only after that moment, not in a flash before data.\nexport function useSettledEmpty(empty: boolean, ms = 1500): boolean {\n const [settled, setSettled] = useState(false);\n useEffect(() => {\n if (!empty) {\n setSettled(false);\n return;\n }\n const timer = setTimeout(() => setSettled(true), ms);\n return () => clearTimeout(timer);\n }, [empty, ms]);\n return empty && settled;\n}\n\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// image \u2014 a static image on the canvas (floor plans, logos, SCADA backdrops). No\n// datasource; the Phase-4 SCADA symbol family will layer live SVG on top of this.\n\nimport type { CSSProperties } from 'react';\n\nimport {\n css,\n defineWidget,\n fontVar,\n optString,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\n\nconst FITS = new Set(['contain', 'cover', 'fill']);\n\nexport function Image({ widget }: WidgetProps<null>) {\n const url = optString(widget.options, 'url');\n const alt = optString(widget.options, 'alt') ?? '';\n const fitOption = optString(widget.options, 'fit');\n const objectFit = (fitOption && FITS.has(fitOption) ? fitOption : 'contain') as CSSProperties['objectFit'];\n\n return (\n <WidgetFrame title={optString(widget.options, 'title')} flush>\n {url ? (\n <img src={url} alt={alt} style={{ width: '100%', height: '100%', objectFit, display: 'block' }} />\n ) : (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n height: '100%',\n color: css('muted-foreground'),\n fontSize: fontVar('md'),\n }}\n >\n No image URL\n </div>\n )}\n </WidgetFrame>\n );\n}\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const imageWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['image'],\n implementation: { kind: 'trusted-react', component: Image },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// label \u2014 static text on the canvas (headings, captions, annotations). No\n// datasource. Renders plain text only (no raw HTML) so a tenant-authored\n// definition can't inject markup.\n\nimport type { CSSProperties } from 'react';\n\nimport {\n css,\n defineWidget,\n fontVar,\n spaceVar,\n optNumber,\n optString,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\n\nconst justify: Record<string, CSSProperties['justifyContent']> = {\n left: 'flex-start',\n center: 'center',\n right: 'flex-end',\n};\n\nexport function Label({ widget }: WidgetProps<null>) {\n const text = optString(widget.options, 'text') ?? '';\n const align = optString(widget.options, 'align') ?? 'center';\n // An authored size is a design size in px at the board's normal density: it scales with it,\n // so a wall board's label grows with the rest. Unset takes the large step of the type ramp.\n const authored = optNumber(widget.options, 'fontSize');\n const fontSize = authored !== undefined ? `calc(${authored}px * var(--dc-scale, 1))` : fontVar('lg');\n\n return (\n <WidgetFrame title={optString(widget.options, 'title')} flush>\n <div\n style={{\n display: 'flex',\n alignItems: 'safe center',\n justifyContent: justify[align] ?? 'center',\n height: '100%',\n boxSizing: 'border-box',\n overflow: 'hidden',\n // A label is often one row tall: the frame's uniform inset would leave it a line's\n // height or less, so it keeps a slim vertical inset and the usual side inset.\n padding: `${spaceVar(1)} ${spaceVar(3)}`,\n }}\n >\n <span\n style={{\n fontSize,\n color: css('foreground'),\n textAlign: align as CSSProperties['textAlign'],\n whiteSpace: 'pre-wrap',\n }}\n >\n {text}\n </span>\n </div>\n </WidgetFrame>\n );\n}\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const labelWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['label'],\n implementation: { kind: 'trusted-react', component: Label },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// latest-card \u2014 the current value of one measurement, big and legible.\n\nimport { useMemo } from 'react';\n\nimport {\n bandAt,\n css,\n defineWidget,\n fitValueFont,\n fitValueFontCss,\n FIT_MIN_FONT_PX,\n flashTextStyle,\n fontVar,\n formatTimestamp,\n formatValue,\n levelColor,\n optBoolean,\n optNumber,\n optString,\n optThresholds,\n pickSample,\n primaryMeasurementName,\n spaceVar,\n useSeverityColors,\n useStickyChars,\n useFlashOnChange,\n useWidgetTimeZone,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { NoReading } from './no-reading-lazy';\n\n// The room a timestamp line needs under the value. The frame's content column (what the\n// widget scale reports) is already net of the frame's padding.\nconst TIMESTAMP_ROOM_PX = 18;\n\nexport function LatestCard({ widget, data }: WidgetProps) {\n const severity = useSeverityColors();\n const timeZone = useWidgetTimeZone();\n const name = primaryMeasurementName(widget);\n const sample = pickSample(data.latest, name);\n\n const title = optString(widget.options, 'title') ?? name;\n const unit = optString(widget.options, 'unit');\n const precision = optNumber(widget.options, 'precision');\n const display = formatValue(sample?.value, precision);\n // The value reads in the colour of the band it falls in; below the lowest threshold (or with\n // none, or in a `normal` band) it keeps the foreground: colour only for the abnormal.\n const thresholds = useMemo(() => optThresholds(widget.options, 'thresholds'), [widget.options]);\n const band = bandAt(thresholds, sample?.value);\n const valueColor = levelColor(severity, band?.level) ?? css('foreground');\n\n // Opt-in directional flash: tint the number green/red on a rise/fall, then fade back. The\n // identity (device + measurement) suppresses a false flash when an anchor's single slot\n // interleaves values across member devices, or the shown measurement switches.\n const flashDirection = useFlashOnChange(\n sample?.value,\n optBoolean(widget.options, 'flashOnChange'),\n sample && `${sample.deviceToken}:${sample.name}`,\n );\n\n // Fit the value to the card from both dimensions and the string length (the unit renders at\n // half size, so it counts for half its characters).\n // Sticky: the longest length seen lately, so a value crossing 9.99 -> 10.01 holds its size.\n const chars = useStickyChars(display.length + (sample?.value != null && unit ? Math.ceil(unit.length / 2) + 1 : 0));\n return (\n <WidgetFrame title={title} sampleTime={sample?.occurredTime ?? null}>\n {({ size, scale }) => {\n // No reading: say why, rather than print a bare dash.\n if (sample?.value == null) {\n return <NoReading unbound={widget.datasource?.kind === 'unbound'} measurement={name} />;\n }\n // Measured: the JS curve. Unmeasured (first frame): the SAME curve in cq units, resolved\n // by the browser against the frame's content column, so there is no fallback-size flash.\n const floor = Math.round(FIT_MIN_FONT_PX * scale);\n const measured = size.width > 0 && size.height > 0;\n const valuePx = measured ? fitValueFont(size, chars, { floor }) : undefined;\n const valueFont = valuePx ?? fitValueFontCss(chars, { floor });\n // The timestamp is the first thing to give: it shows only when the measured box has room\n // for it under the value (unmeasured -- first frame, jsdom -- it shows).\n const showTimestamp =\n valuePx === undefined || size.height - Math.ceil(valuePx * 1.1) >= TIMESTAMP_ROOM_PX * scale;\n return (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'safe center',\n height: '100%',\n boxSizing: 'border-box',\n overflow: 'hidden',\n }}\n >\n <div\n data-threshold-level={band?.level}\n title={band?.label}\n style={{\n fontSize: valueFont,\n fontWeight: 600,\n lineHeight: 1.1,\n // One line, and digits of one width: the fit counts characters, so a live value\n // must not wrap or shift sideways as its digits change.\n whiteSpace: 'nowrap',\n fontVariantNumeric: 'tabular-nums',\n color: valueColor,\n ...flashTextStyle(flashDirection),\n }}\n >\n {display}\n {sample?.value != null && unit ? (\n <span\n style={{\n fontSize: valuePx !== undefined ? Math.round(valuePx / 2) : `calc(${valueFont} / 2)`,\n color: css('muted-foreground'),\n marginLeft: spaceVar(1),\n }}\n >\n {unit}\n </span>\n ) : null}\n </div>\n {sample?.occurredTime && showTimestamp ? (\n <div style={{ fontSize: fontVar('xs'), color: css('muted-foreground'), marginTop: spaceVar(1) }}>\n {formatTimestamp(sample.occurredTime, timeZone)}\n </div>\n ) : null}\n </div>\n );\n }}\n </WidgetFrame>\n );\n}\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const latestCardWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['latest-card'],\n implementation: { kind: 'trusted-react', component: LatestCard },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The level, indicator and radial registrations: descriptor eager, component lazy. The descriptors\n// are the catalog (the editor, the validators and WIDGET_TYPES read them without rendering\n// anything), so they stay in the entry; the seven components load on first mount, together,\n// from one chunk (level-widgets.ts), so a board without one of them never downloads it.\n//\n// Until the chunk arrives the widget renders nothing inside its box. A chunk that fails to\n// load is THROWN, so the widget's error boundary shows the failure: an empty tank that looks\n// like a reading is the outcome this must never produce.\n\nimport { defineWidget } from '@devicechain/widget-sdk';\nimport { loadChartEngine } from '@devicechain/widget-sdk/echarts';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { lazyChunk } from './lazy-chunk';\n\nconst chunk = lazyChunk(() => import('./level-widgets'));\n\nexport const loadLevelWidgets = chunk.load;\n\nconst lazyComponent = chunk.component;\n\nexport const linearGaugeWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['linear-gauge'],\n implementation: { kind: 'trusted-react', component: lazyComponent('LinearGauge') },\n});\n\nexport const levelGaugeWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['level-gauge'],\n implementation: { kind: 'trusted-react', component: lazyComponent('LevelGauge') },\n});\n\nexport const batteryWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['battery'],\n implementation: { kind: 'trusted-react', component: lazyComponent('Battery') },\n});\n\nexport const statusLightWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['status-light'],\n implementation: { kind: 'trusted-react', component: lazyComponent('StatusLight') },\n});\n\nexport const signalBarsWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['signal-bars'],\n implementation: { kind: 'trusted-react', component: lazyComponent('SignalBars') },\n});\n\nexport const compassWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['compass'],\n implementation: { kind: 'trusted-react', component: lazyComponent('Compass', loadChartEngine) },\n});\n\nexport const progressRingWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['progress-ring'],\n implementation: { kind: 'trusted-react', component: lazyComponent('ProgressRing') },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// map \u2014 the bound devices' last-known positions, on the location channel.\n//\n// Three rules shape everything here, and each of them is a state some other design\n// would have collapsed into \"the map is empty\":\n//\n// \uD83D\uDD34 REFUSED IS NOT EMPTY. Position is gated on its own `location:read` authority,\n// deliberately absent from the read-only viewer baseline, so an ordinary member with\n// full telemetry access is routinely refused. \"No devices to show\" and \"you are not\n// allowed to see this\" are opposite facts and only one of them is actionable, so the\n// refusal gets its own copy and its own look \u2014 never a blank map.\n//\n// \uD83D\uDD34 NO TILE SOURCE IS NOT A BROKEN MAP. This package hardcodes no tile URL (see\n// rasterStyleFor) and inherits one from the tenant (ADR-079), whose instance-wide\n// default now ships a real provider \u2014 so in practice this branch is rare. It is not\n// dead, though: an operator can empty that default, an air-gapped install can have no\n// route to any provider at all, and a viewer can be looking at a board on either.\n//\n// That case renders a REAL MapLibre map against the BUNDLED public-domain world\n// (loadLandStyle) \u2014 continents and country outlines, compiled into this package.\n//\n// \uD83D\uDD34 Be precise about what survives of the old promise, because an earlier version of\n// this comment was not. It said the widget \"issues no request to any host\" and backed\n// that with \"loads no map library\", and the second half is now FALSE: this path loads\n// the renderer and the geometry, two chunks, from the app's OWN origin. What is still\n// true \u2014 and is the part that ever mattered \u2014 is that it contacts no THIRD-PARTY host,\n// because it has been given none it would be entitled to ask. What it no longer does\n// is show a void that reads as breakage.\n//\n// \uD83D\uDD34 ABSENT IS NOT ZERO. A marker describes only what its device reported; an\n// unreported heading is not due north. See describePosition.\n\nimport { useEffect, useRef, useState, type CSSProperties } from 'react';\nimport { renderableBasemap, resolveBasemap } from '@devicechain/client';\n\nimport { useTenantBasemap } from '../basemap-context';\nimport { useMapRuntime, type MapRuntime } from '../map-runtime-context';\nimport {\n css,\n fontVar,\n defineWidget,\n type LocationStreamState,\n optString,\n useWidgetSelect,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport {\n describePosition,\n loadLandStyle,\n placeable,\n projectToPanel,\n rasterStyleFor,\n type PlaceableLocation,\n} from './map-geometry';\n\n// The MapLibre pieces this widget drives. A TYPE-only import is erased at build time,\n// so naming them here creates no static dependency on the library \u2014 the value only ever\n// arrives through the dynamic import below.\nimport type { Map as MapLibreMap, Marker as MapLibreMarker } from 'maplibre-gl';\n\n// \uD83D\uDD34 THE LIBRARY IS LOADED LAZILY, BY CONSTRUCTION. MapLibre is ~200 KB gzipped, and\n// only a dashboard that actually contains a map widget may pay for it \u2014 a console user\n// who never opens a board with a map must not download a map renderer. The dynamic\n// import is what puts it in its own chunk; a top-level `import 'maplibre-gl'` anywhere\n// in this package would fold it into the main bundle for every viewer, and nothing\n// about the widget's behaviour would change to reveal it.\n//\n// MapLibre's STYLESHEET is no longer imported here at all \u2014 it is the host's, along with\n// the worker URL, for the reason set out below and in map-runtime-context. A host may hand\n// back a loader for it (`MapRuntime.loadStyles`) to keep it on this same lazy chunk, or\n// import it eagerly and pay 83 KB (10.7 KB gzipped) in its main stylesheet. That is the\n// host's call, and both are reasonable; what a LIBRARY cannot do is decide it for them in\n// one bundler's dialect.\n//\n// Loaded once and memoized: several map widgets on one board share the fetch.\nlet mapLibrePromise: Promise<typeof import('maplibre-gl')> | undefined;\n\n// \uD83D\uDD34 THE WORKER HAS TO BE ASKED FOR BY NAME, and getting this wrong produces a map\n// that builds, type-checks, passes every test and then renders nothing. MapLibre\n// otherwise derives the worker's URL at runtime from its own module URL, which is a\n// string no bundler can follow \u2014 nothing emits the file, the browser 404s it, and\n// `new Worker()` does not throw on a 404: the failure arrives later as an async error\n// event, so the map simply sits there having loaded no tiles.\n//\n// \uD83D\uDD34 THE URL COMES FROM THE HOST, and this package no longer computes it. Emitting a\n// worker entry is a bundler-specific act \u2014 Vite spells it `?worker&url`, webpack and\n// Rollup spell it differently \u2014 so a library that writes one dialect works under that\n// bundler and silently renders a blank map under every other. See map-runtime-context\n// for the full argument; the short version is that the specifier is externalized, so\n// no build anywhere reports the breakage.\n//\n// Memoized for the whole module, and FIRST CALLER WINS: several map widgets on one\n// board share the fetch, and `setWorkerUrl` is global state in MapLibre, so a second\n// caller with a different URL could not be honoured even if we tried. In practice\n// there is one provider at the top of the tree and therefore one URL.\nfunction loadMapLibre(runtime: MapRuntime): Promise<typeof import('maplibre-gl')> {\n if (!mapLibrePromise) {\n // The stylesheet rides the SAME dynamic boundary as the renderer, which is why a host\n // may pass a loader rather than importing it at module scope: it is 83 KB raw, 10.7 KB\n // gzipped (maplibre-gl 6.6.0), and a viewer who opens no map should download none of\n // it. Optional \u2014 a host that imports the stylesheet itself is doing the ordinary thing.\n //\n // \uD83D\uDD34 `Promise.resolve().then(...)` IS NOT CEREMONY. `loadStyles()` is host code, and a\n // host CAN throw synchronously \u2014 `loadStyles: () => require('\u2026css')` on a bundler with\n // no CSS loader is the realistic form. Called while building the argument array, that\n // throw escapes loadMapLibre entirely, propagates through the caller's own\n // `Promise.all` argument evaluation, and lands in React's commit phase where the\n // effect's `.catch` cannot see it: React 19 unmounts the tree, so one misconfigured\n // host loader takes down the whole dashboard instead of degrading to the plain panel.\n // Deferring the call puts it inside the promise chain, where the existing catch works.\n mapLibrePromise = Promise.all([\n import('maplibre-gl'),\n Promise.resolve().then(() => runtime.loadStyles?.()),\n ]).then(([mod]) => {\n mod.setWorkerUrl(runtime.workerUrl);\n return mod;\n });\n }\n return mapLibrePromise;\n}\n\n// The zoom a single-device map opens at \u2014 close enough to read a site, wide enough that\n// a lone marker is not floating in featureless tiles. A multi-device map ignores it and\n// fits the fleet's bounds instead.\nconst SINGLE_DEVICE_ZOOM = 14;\n\nexport function MapWidget({ widget, data }: WidgetProps<LocationStreamState>) {\n const title = optString(widget.options, 'title');\n const positions = placeable(data.locations);\n\n // The host's bundler-produced MapLibre runtime. Read unconditionally, with the other\n // hooks, because a hook cannot live behind one of the early returns below.\n const runtime = useMapRuntime();\n\n // A marker click re-points the target slot at that device, so the widgets bound to it follow\n // (the same linked-selection seam a fleet-table row uses). Undefined unless the author named a\n // target slot AND the host wires selection: with either missing a marker is only a mark, and\n // it neither looks nor behaves clickable. Hook order: read before the early returns below.\n const select = useWidgetSelect();\n const selectionTarget = optString(widget.options, 'selectionTarget');\n const pick: PickDevice | undefined =\n select && selectionTarget\n ? (deviceToken) => select({ slot: selectionTarget, binding: { kind: 'device', deviceToken } })\n : undefined;\n\n // Precedence is per-widget override \u2192 tenant \u2192 no basemap (ADR-079 \u00A79). The\n // per-widget options are kept, not replaced: they are how someone tries a provider\n // on one board before committing it tenant-wide.\n //\n // \uD83D\uDD34 resolveBasemap is NOT `override ?? tenant` per field. A widget that names its\n // own tile URL does not inherit the tenant's credit line, because that would credit\n // the tenant's provider for tiles it did not serve. The SDK owns that rule so the\n // fence editor and the /dash app cannot disagree with this widget about it.\n const basemap = renderableBasemap(\n resolveBasemap(\n {\n tileUrl: optString(widget.options, 'tileUrl'),\n attribution: optString(widget.options, 'attribution'),\n },\n useTenantBasemap(),\n ),\n );\n\n // The refusal is checked FIRST and unconditionally: it is a fact about the caller, so\n // it outranks anything about the data, and it must not be reachable only through some\n // \"no positions\" branch that a later edit could reorder past.\n if (data.forbidden) {\n return (\n <WidgetFrame title={title}>\n <MapNotice\n glyph=\"\uD83D\uDD12\"\n heading=\"Location not permitted\"\n detail=\"You do not have permission to view device locations.\"\n />\n </WidgetFrame>\n );\n }\n\n // \uD83D\uDD34 AND THE HOST'S OWN WIRING IS CHECKED SECOND, for the same reason the refusal is\n // checked first: it is a fact about the environment rather than about the data, so it\n // outranks every \"nothing to show\" branch below. Checking it later would hide it behind\n // \"No devices selected\" on exactly the board a developer is using to find it.\n //\n // There is no fallback to take. The only alternative to a host-supplied worker URL is\n // MapLibre's runtime derivation, which is the silent blank map this seam exists to\n // prevent \u2014 so an unwired host is told, in the widget, what it has to install.\n if (!runtime) {\n return (\n <WidgetFrame title={title}>\n <MapNotice\n glyph=\"\uD83E\uDDE9\"\n heading=\"Map runtime not configured\"\n detail=\"This host must install MapRuntimeProvider with its bundler's MapLibre worker URL.\"\n />\n </WidgetFrame>\n );\n }\n\n if (data.loading && positions.length === 0) {\n return (\n <WidgetFrame title={title}>\n <MapNotice heading=\"Loading\u2026\" />\n </WidgetFrame>\n );\n }\n\n if (positions.length === 0) {\n // Two different empty states, because they call for two different actions: bind the\n // widget, or wait for a device to report.\n return (\n <WidgetFrame title={title}>\n <MapNotice\n heading={data.deviceTokens.length === 0 ? 'No devices selected' : 'No positions reported'}\n detail={\n data.deviceTokens.length === 0\n ? 'Bind this widget to a device or anchor and select its location series.'\n : 'None of the selected devices has reported a position yet.'\n }\n />\n </WidgetFrame>\n );\n }\n\n return (\n <WidgetFrame title={title} flush>\n <LiveMap basemap={basemap} positions={positions} runtime={runtime} pick={pick} />\n </WidgetFrame>\n );\n}\n\n// ---- The tile-less panel ----------------------------------------------------\n\n// PlainPanel draws the positions on a themed background with no basemap at all.\n//\n// \uD83D\uDD34 IT HAS EXACTLY ONE JOB LEFT, AND IT IS NOT THE UNCONFIGURED CASE. Since the\n// bundled world basemap landed, an unconfigured widget renders a REAL MapLibre map\n// against public-domain geometry \u2014 so this panel is reached only when the map could\n// not be BUILT at all. Three ways in, not one: the MapLibre chunk fails to load, the\n// bundled-geometry chunk fails to load, or the Map constructor throws (a browser or a\n// context with no usable WebGL). They share a catch because they share an answer.\n//\n// It survives because on that path it is strictly better than an error box. The\n// question a map widget answers is \"where is my fleet, relative to each other\",\n// and this still answers it when the renderer cannot load. That is also why\n// projectToPanel exists at all, and why deleting either would look like tidying up\n// dead code right until someone's dashboard went blank behind a proxy.\nfunction PlainPanel({\n positions,\n note,\n pick,\n}: {\n positions: PlaceableLocation[];\n note: string;\n pick: PickDevice | undefined;\n}) {\n const points = projectToPanel(positions);\n return (\n <div\n data-testid=\"map-plain-panel\"\n style={{\n position: 'relative',\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n background: css('muted'),\n }}\n >\n {positions.map((position, i) => (\n <Marker\n key={position.deviceToken}\n position={position}\n pick={pick}\n style={{\n position: 'absolute',\n left: `${points[i].x * 100}%`,\n top: `${points[i].y * 100}%`,\n transform: 'translate(-50%, -50%)',\n }}\n />\n ))}\n <div\n data-testid=\"map-no-tiles-note\"\n style={{\n position: 'absolute',\n left: 0,\n right: 0,\n bottom: 0,\n padding: '4px 8px',\n fontSize: fontVar('sm'),\n lineHeight: 1.3,\n textAlign: 'center',\n color: css('muted-foreground'),\n background: css('card'),\n opacity: 0.9,\n }}\n >\n {note}\n </div>\n </div>\n );\n}\n\n// ---- The map ----------------------------------------------------------------\n\ntype MapStatus = 'loading' | 'ready' | 'unavailable';\n\n// LiveMap renders MapLibre for BOTH basemap states.\n//\n// The branch is over the STYLE, not over whether there is a map: a configured tile\n// source gets a raster style, and no tile source gets the bundled public-domain\n// world. Everything downstream of that \u2014 the projection, the markers, the fit, the\n// teardown \u2014 is the same code on both paths, which is the point. When the two were\n// different components, \"unconfigured\" was a second rendering path that could drift\n// away from the real one without any test noticing.\n// `runtime` is a required prop rather than a context read, so that LiveMap cannot be\n// constructed without one. The null case is handled once, in MapWidget, and this\n// component never has to reason about it.\nfunction LiveMap({\n basemap,\n positions,\n runtime,\n pick,\n}: {\n basemap: { tileUrl: string; attribution: string | null } | null;\n positions: PlaceableLocation[];\n runtime: MapRuntime;\n pick: PickDevice | undefined;\n}) {\n const containerRef = useRef<HTMLDivElement>(null);\n const mapRef = useRef<MapLibreMap | null>(null);\n const markersRef = useRef<MapLibreMarker[]>([]);\n const [status, setStatus] = useState<MapStatus>('loading');\n // The markers are rebuilt only when positions change, so the click handler they hold reads the\n // CURRENT pick through a ref instead of closing over the one from the render that built them.\n const pickRef = useRef(pick);\n pickRef.current = pick;\n const selectable = pick !== undefined;\n\n const tileUrl = basemap?.tileUrl ?? null;\n const attribution = basemap?.attribution ?? null;\n\n // Init + teardown for this basemap. Re-runs when the source changes, which is the\n // only thing that invalidates the style.\n useEffect(() => {\n let cancelled = false;\n setStatus('loading');\n\n // \uD83D\uDD34 The bundled style is FETCHED, not built inline: its geometry sits behind a\n // dynamic import so a configured viewer never downloads a world map they will\n // not look at. Resolved alongside the renderer so the Map is still constructed\n // once, with its final style \u2014 nothing re-styles after mount.\n Promise.all([\n loadMapLibre(runtime),\n tileUrl ? rasterStyleFor(tileUrl, attribution ?? undefined) : loadLandStyle(),\n ])\n .then(([maplibre, style]) => {\n const el = containerRef.current;\n if (cancelled || !el) return;\n const map = new maplibre.Map({\n container: el,\n style: style as never,\n center: [0, 0],\n zoom: 1,\n });\n mapRef.current = map;\n setStatus('ready');\n })\n .catch(() => {\n // The renderer or the bundled geometry could not be fetched (offline viewer,\n // a CSP that blocks the chunk). Fall back to the plain panel rather than to\n // nothing: the positions are what the operator came for, and the basemap is\n // the part that failed.\n if (!cancelled) setStatus('unavailable');\n });\n\n return () => {\n cancelled = true;\n for (const marker of markersRef.current) marker.remove();\n markersRef.current = [];\n mapRef.current?.remove();\n mapRef.current = null;\n };\n // \uD83D\uDD34 Keyed on runtime.workerUrl, NOT on `runtime`. A host that builds the runtime\n // inline in JSX hands a new object every render; depending on the object would tear the\n // map down and rebuild it each time, which looks like flicker and loses view state. The\n // URL is the only part of it this effect's outcome depends on.\n //\n // `runtime.loadStyles` is used inside and is deliberately not a dependency: loadMapLibre\n // memoizes at module scope, first caller wins, so only the first runtime's loader is\n // ever invoked and a later one could not take effect however this array were written.\n // That is the documented contract, not an oversight \u2014 and no eslint config in this repo\n // lints packages/*, so a disable comment here would suppress nothing and merely look\n // like the question had been settled by a linter.\n }, [tileUrl, attribution, runtime.workerUrl]);\n\n // Sync the markers to the current positions. Rebuilt wholesale rather than diffed:\n // a poll delivers a whole snapshot, the marker count is a dashboard's worth of\n // devices, and a diff here would be state to get wrong for no measurable saving.\n useEffect(() => {\n const map = mapRef.current;\n if (status !== 'ready' || !map) return;\n\n let live = true;\n loadMapLibre(runtime).then((maplibre) => {\n if (!live || mapRef.current !== map) return;\n for (const marker of markersRef.current) marker.remove();\n markersRef.current = positions.map((position) => {\n const el = document.createElement('div');\n el.setAttribute('data-testid', 'map-marker');\n el.setAttribute('data-device', position.deviceToken);\n el.setAttribute('title', describePosition(position));\n el.setAttribute('aria-label', describePosition(position));\n if (selectable) {\n // A 24 px target around the 12 px dot: a fingertip on a phone-width board cannot hit the dot.\n Object.assign(el.style, MARKER_HIT_STYLE);\n el.setAttribute('role', 'button');\n el.setAttribute('tabindex', '0');\n const dot = document.createElement('div');\n Object.assign(dot.style, MARKER_DOT_STYLE, { cursor: 'inherit' });\n el.appendChild(dot);\n const choose = () => pickRef.current?.(position.deviceToken);\n el.addEventListener('click', choose);\n el.addEventListener('keydown', (e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n choose();\n }\n });\n } else {\n Object.assign(el.style, MARKER_DOT_STYLE);\n }\n // \uD83D\uDD34 setLngLat takes [LONGITUDE, LATITUDE] \u2014 x before y, the opposite order\n // from how a coordinate is spoken and written everywhere else on the platform.\n // Swapping them puts a device reporting Atlanta into the Indian Ocean, which\n // renders perfectly.\n return new maplibre.Marker({ element: el })\n .setLngLat([position.longitude, position.latitude])\n .addTo(map);\n });\n\n if (positions.length === 1) {\n map.jumpTo({ center: [positions[0].longitude, positions[0].latitude], zoom: SINGLE_DEVICE_ZOOM });\n } else if (positions.length > 1) {\n const bounds = new maplibre.LngLatBounds();\n for (const p of positions) bounds.extend([p.longitude, p.latitude]);\n map.fitBounds(bounds, { padding: 40, animate: false });\n }\n });\n\n return () => {\n live = false;\n };\n // Positions are compared by VALUE: a poll hands back a fresh array every tick, and\n // rebuilding every marker 4 times a minute for an unchanged fleet would make the\n // markers flicker.\n }, [status, positionsKey(positions), selectable]);\n\n if (status === 'unavailable') {\n return (\n <PlainPanel\n positions={positions}\n note=\"Map renderer unavailable \u2014 positions are shown without a basemap.\"\n pick={pick}\n />\n );\n }\n\n return <div ref={containerRef} data-testid=\"map-canvas\" style={{ width: '100%', height: '100%' }} />;\n}\n\n// positionsKey is the value identity of a marker set: what is drawn, not which array\n// object carries it.\nfunction positionsKey(positions: PlaceableLocation[]): string {\n return positions.map((p) => `${p.deviceToken}:${p.latitude}:${p.longitude}:${p.heading ?? ''}`).join('|');\n}\n\n// ---- Shared bits ------------------------------------------------------------\n\n// What a marker click does: pick that device for the board's linked widgets. Absent = not selectable.\ntype PickDevice = (deviceToken: string) => void;\n\n// The clickable box around a selectable marker's dot (WCAG 2.5.8 asks for 24 px).\nconst MARKER_HIT_STYLE = {\n width: '24px',\n height: '24px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n cursor: 'pointer',\n} as const;\n\nconst MARKER_DOT_STYLE = {\n width: '12px',\n height: '12px',\n borderRadius: '50%',\n background: css('primary'),\n border: `2px solid ${css('card')}`,\n boxShadow: '0 0 0 1px rgba(0,0,0,0.25)',\n cursor: 'default',\n} as const;\n\n// Marker is the tile-less panel's dot. The tiled map builds an equivalent element\n// imperatively (MapLibre owns the DOM its markers live in), which is why the styling is\n// shared as an object rather than as a component.\nfunction Marker({\n position,\n style,\n pick,\n}: {\n position: PlaceableLocation;\n style: CSSProperties;\n pick: PickDevice | undefined;\n}) {\n const label = describePosition(position);\n if (pick) {\n return (\n <button\n type=\"button\"\n data-testid=\"map-marker\"\n data-device={position.deviceToken}\n title={label}\n aria-label={label}\n onClick={() => pick(position.deviceToken)}\n style={{ ...MARKER_HIT_STYLE, padding: 0, border: 0, background: 'transparent', ...style }}\n >\n <span style={{ ...MARKER_DOT_STYLE, cursor: 'inherit', display: 'block' }} />\n </button>\n );\n }\n return (\n <div\n data-testid=\"map-marker\"\n data-device={position.deviceToken}\n title={label}\n aria-label={label}\n style={{ ...MARKER_DOT_STYLE, ...style }}\n />\n );\n}\n\n// MapNotice is the widget's non-map state: permission, loading, empty. One component so\n// the three read as siblings \u2014 a viewer should be able to tell them apart by their words,\n// not by their layout.\nfunction MapNotice({ glyph, heading, detail }: { glyph?: string; heading: string; detail?: string }) {\n return (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'safe center',\n overflow: 'hidden',\n gap: 4,\n width: '100%',\n height: '100%',\n boxSizing: 'border-box',\n textAlign: 'center',\n color: css('muted-foreground'),\n }}\n >\n {glyph ? (\n <div style={{ fontSize: fontVar('xl'), lineHeight: 1 }} aria-hidden=\"true\">\n {glyph}\n </div>\n ) : null}\n <div style={{ fontSize: fontVar('md'), fontWeight: 600 }}>{heading}</div>\n {detail ? <div style={{ fontSize: fontVar('sm'), opacity: 0.8 }}>{detail}</div> : null}\n </div>\n );\n}\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const mapWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['map'],\n implementation: { kind: 'trusted-react', component: MapWidget },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The tenant basemap, threaded to map widgets as ambient environment (ADR-079).\n//\n// \uD83D\uDD34 Why context rather than a new field on WidgetProps. A widget is contractually a\n// pure function of (widget, data): the props carry what the widget SHOWS. A tenant's\n// tile source is not data \u2014 it is environment, like the theme \u2014 and putting it in the\n// props would change the contract for all fifteen widgets to serve one of them.\n//\n// The default is null, deliberately. A host that installs no provider (widgetlab, the\n// synthetic preview, every existing test) behaves exactly as before: the map falls\n// back to its per-widget options, and to a plain panel when it has none. Adding the\n// provider is what turns a tenant's configured basemap on; nothing breaks without it.\n\nimport { createContext, useContext, type ReactNode } from 'react';\nimport type { Basemap } from '@devicechain/client';\n\nconst TenantBasemapContext = createContext<Basemap | null>(null);\n\n/**\n * Supplies the tenant's effective basemap to every map widget beneath it.\n *\n * Both hosts install this ONCE, high in the tree, rather than at each place they\n * render a widget: the console from its TenantProvider, the /dash viewer app from the\n * one place it mounts a DashboardRenderer.\n *\n * \uD83D\uDD34 That placement is the whole safety argument, because a host that forgets this\n * does NOT fail loudly \u2014 its maps simply render as they did before the tenant setting\n * existed, on that surface only. Wrapping individual render sites is the version that\n * silently half-works; there is no render site to forget from the top of the tree.\n */\nexport function TenantBasemapProvider({\n basemap,\n children,\n}: {\n basemap: Basemap | null;\n children: ReactNode;\n}) {\n return <TenantBasemapContext.Provider value={basemap}>{children}</TenantBasemapContext.Provider>;\n}\n\n/**\n * The tenant's effective basemap, or null when no host supplied one.\n *\n * Null means \"no tenant basemap in force\" \u2014 either the host installs no provider, or\n * neither the tenant nor the operator has configured one. Both cases resolve the same\n * way downstream (fall back to the per-widget override, then to a plain panel), so\n * callers do not need to distinguish them.\n */\nexport function useTenantBasemap(): Basemap | null {\n return useContext(TenantBasemapContext);\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The map runtime: the pieces of MapLibre that only the HOST'S BUNDLER can produce.\n//\n// \uD83D\uDD34 WHY THIS EXISTS AT ALL. MapLibre parses tiles and geometry off the main thread, and\n// left to itself it derives the worker's URL at runtime from its own module URL \u2014\n// `new URL('./maplibre-gl-worker.mjs', import.meta.url)`. That is a string no bundler can\n// follow, so nothing emits the file, the browser resolves it to a 404, and `new Worker()`\n// does not throw on one: the failure arrives later as an async error event. The map builds,\n// type-checks, passes every test, and renders nothing.\n//\n// The only thing that can emit that file is the application's own bundler, using its own\n// dialect \u2014 Vite spells it `?worker&url`, webpack and Rollup each spell it differently.\n// So the URL is something a HOST computes and a LIBRARY cannot.\n//\n// \uD83D\uDD34 THIS PACKAGE USED TO WRITE VITE'S DIALECT ITSELF, and that is the defect this seam\n// removes. A published library containing `import('\u2026?worker&url')` works under a consumer's\n// Vite and silently renders a blank map under anything else \u2014 and because the specifier is\n// externalized, no bundler ever tries to resolve it, so NOTHING IN ANY BUILD REPORTS IT.\n// A green pipeline over a broken artifact is strictly worse than a red one.\n//\n// \u26A0\uFE0F HOW THIS DIFFERS FROM TenantBasemapProvider, which sits beside it and looks alike.\n// The basemap provider is OPTIONAL BY DESIGN: a host that installs none behaves exactly as\n// it did before the tenant setting existed, and that is a coherent state. This one is\n// REQUIRED, and a host that omits it gets a loud notice rather than a map. The asymmetry is\n// deliberate and is the whole point: a missing basemap is a configuration a viewer can read\n// off the screen, while a missing worker URL is invisible \u2014 it is the blank map above.\n// Copying the basemap's optional-by-default shape here would relocate that defect into\n// every unwired host instead of removing it.\n\nimport { createContext, useContext, type ReactNode } from 'react';\n\n/**\n * The bundler-produced runtime a map widget needs from its host.\n *\n * `workerUrl` is the emitted, host-resolvable URL of MapLibre's worker entry\n * (`maplibre-gl/dist/maplibre-gl-worker.mjs`). It is handed to MapLibre's `setWorkerUrl`\n * before the first `Map` is constructed.\n *\n * `loadStyles` is OPTIONAL, and imports MapLibre's stylesheet\n * (`maplibre-gl/dist/maplibre-gl.css`). Omit it and import the stylesheet yourself, the way\n * every map library asks you to \u2014 that is the ordinary path and nothing here second-guesses\n * it. Supplying it buys one thing: the CSS rides the renderer's lazy chunk instead of your\n * main stylesheet, which is worth **83 KB raw / 10.7 KB gzipped** to a viewer who never\n * opens a board with a map on it.\n *\n * \uD83D\uDD34 The size is measured against maplibre-gl 6.6.0, the version this package peers on. An\n * earlier draft said 70 KB \"measured, not estimated\" \u2014 measured, but against a stale\n * `node_modules` carrying 6.2.0. Measuring the right thing in the wrong tree reads exactly\n * like measuring, which is why the version is named here.\n *\n * \uD83D\uDD34 It is a FUNCTION rather than a boolean or a URL because the host's bundler owns its\n * CSS pipeline: only the host can say \"load this, lazily, your way\".\n */\nexport type MapRuntime = {\n workerUrl: string;\n loadStyles?: () => Promise<unknown>;\n};\n\nconst MapRuntimeContext = createContext<MapRuntime | null>(null);\n\n/**\n * Supplies the host's MapLibre runtime to every map widget beneath it.\n *\n * Install it ONCE, high in the tree, next to TenantBasemapProvider \u2014 the console from its\n * TenantProvider, the /dash viewer from the one place it mounts a DashboardRenderer.\n *\n * \uD83D\uDD11 ON VITE, DO NOT WRITE ANY OF THIS \u2014 import the ready-made runtime:\n *\n * ```tsx\n * import { viteMapRuntime } from '@devicechain/widgets/vite';\n *\n * <MapRuntimeProvider runtime={viteMapRuntime}>{children}</MapRuntimeProvider>\n * ```\n *\n * On any other bundler you supply the URL yourself, and there is ONE REQUIREMENT that\n * decides whether it works: MapLibre loads the URL as a MODULE worker, so whatever it\n * serves must be a module with no unresolved imports left in it.\n * `maplibre-gl/dist/maplibre-gl-worker.mjs` does not satisfy that on its own \u2014 its first\n * line is `import \u2026 from './maplibre-gl-shared.mjs'`.\n *\n * \uD83D\uDD34 SO DO NOT POINT AT A VERBATIM COPY OF THE WORKER FILE, and in particular do not\n * reach for `new URL('maplibre-gl/dist/maplibre-gl-worker.mjs', import.meta.url)`. That\n * looks exactly right and is wrong: webpack treats the target as an ASSET and copies it,\n * the sibling is never emitted, and the worker dies on its own first line. Measured\n * against webpack 5, from a packed tarball: the worker URL answered 200, both maps drew\n * canvases, all markers appeared, tiles loaded, THE BUILD EXITED 0 AND THE CONSOLE WAS\n * EMPTY \u2014 and the bundled basemap rendered ocean with no land on it.\n *\n * Two recipes that were measured working, in `hack/consumer-proof`:\n *\n * ```js\n * // webpack \u2014 make the worker a second ENTRY, so its imports are bundled into it.\n * entry: { main: './src/index.tsx', 'maplibre-worker': 'maplibre-gl/dist/maplibre-gl-worker.mjs' }\n * // \u2026then: <MapRuntimeProvider runtime={{ workerUrl: '/maplibre-worker.js' }}>\n * ```\n *\n * ```js\n * // any bundler, or none \u2014 copy the worker AND ITS SIBLING, under their own names,\n * // into one served directory: maplibre-gl-worker.mjs + maplibre-gl-shared.mjs\n * // \u2026then: <MapRuntimeProvider runtime={{ workerUrl: '/vendor/maplibre-gl-worker.mjs' }}>\n * ```\n *\n * \uD83D\uDD34 Hold the runtime in a MODULE CONSTANT, as above, rather than building it inline in\n * JSX. An object literal in the element is a new identity on every render, and while the\n * widget deliberately keys its effects on `workerUrl` rather than on the object to survive\n * that, a host that also passes it anywhere keyed on identity would tear down and rebuild\n * the map on every parent render. There is nothing per-render in it to justify the risk.\n *\n * \uD83D\uDD34 `maplibre-gl` is a PEER dependency of this package precisely so that the copy the host\n * takes the worker from is the same copy this package renders with. A worker built from one\n * version driving a main thread from another is the blank map again, by a different route.\n */\nexport function MapRuntimeProvider({\n runtime,\n children,\n}: {\n runtime: MapRuntime;\n children: ReactNode;\n}) {\n return <MapRuntimeContext.Provider value={runtime}>{children}</MapRuntimeContext.Provider>;\n}\n\n/**\n * The host's map runtime, or null when no host supplied one.\n *\n * \uD83D\uDD34 Callers MUST treat null as a refusal to render a map, not as a default to paper over.\n * There is no sensible fallback: the only alternative to a host-supplied URL is MapLibre's\n * own runtime derivation, which is the broken behaviour this seam exists to prevent.\n */\nexport function useMapRuntime(): MapRuntime | null {\n return useContext(MapRuntimeContext);\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The map widget's pure parts: which samples are placeable, where they land on a\n// tile-less panel, and how a fix is described in words.\n//\n// Split out from the component for the usual reason the chart-option builders are \u2014\n// this is the arithmetic that decides whether a marker is in the right place, and it is\n// worth an awful lot more when it can be asserted directly than when it can only be\n// inferred from a rendered `style` string.\n\nimport type { LocationSample } from '@devicechain/dashboards';\n\n// A sample that actually has coordinates. A LocationSample's latitude/longitude are\n// nullable (the projection's columns are), and a sample missing either is not a\n// position \u2014 placing it would put a marker at (0, 0) in the Gulf of Guinea and label it\n// with a real device's name.\nexport interface PlaceableLocation extends LocationSample {\n latitude: number;\n longitude: number;\n}\n\n// placeable keeps the samples that can be drawn.\n//\n// `!= null`, NOT truthiness: latitude 0 is the equator and longitude 0 is Greenwich,\n// and both are real reported positions. A truthy filter would silently drop a device\n// sitting on either line.\nexport function placeable(samples: readonly LocationSample[]): PlaceableLocation[] {\n return samples.filter(\n (s): s is PlaceableLocation => s.latitude != null && s.longitude != null,\n );\n}\n\n// A point on the tile-less panel, as a FRACTION of its width/height, so the component\n// can express it as a percentage and stay resolution-independent.\nexport interface PanelPoint {\n x: number;\n y: number;\n}\n\n// Fraction of the panel kept clear at each edge, so a marker at the extreme of the\n// bounding box sits inside the panel rather than half-clipped by it.\nconst PANEL_PADDING = 0.1;\n\n// projectToPanel lays a set of positions out on a plain (tile-less) panel.\n//\n// An equirectangular fit of the positions' own bounding box: longitude \u2192 x, latitude \u2192\n// y, each stretched across the padded panel. Deliberately NOT a web-mercator\n// projection \u2014 without a basemap there is nothing to align to, so the only job is to\n// show the relative arrangement of a fleet truthfully, and at the extent of a site or a\n// city the difference between the two is invisible. (With a tile source the widget uses\n// MapLibre's real projection instead; this function is never asked to agree with one.)\n//\n// \uD83D\uDD34 THE AXES ARE NOT INTERCHANGEABLE, AND THE Y AXIS IS INVERTED. Longitude is\n// east-west (x); latitude is north-south (y); and screen y grows DOWNWARD while\n// latitude grows northward, so the maximum latitude maps to y = 0. Swap the two and\n// every marker still lands inside the panel, in a plausible-looking scatter \u2014 the\n// output stays well-formed, which is exactly why this is asserted directly rather than\n// eyeballed.\n//\n// A degenerate axis (one device, or several at the same latitude) has no span to\n// stretch across, so it centres on that axis rather than dividing by zero.\nexport function projectToPanel(positions: readonly PlaceableLocation[]): PanelPoint[] {\n if (positions.length === 0) return [];\n\n let minLat = Infinity;\n let maxLat = -Infinity;\n let minLon = Infinity;\n let maxLon = -Infinity;\n for (const p of positions) {\n if (p.latitude < minLat) minLat = p.latitude;\n if (p.latitude > maxLat) maxLat = p.latitude;\n if (p.longitude < minLon) minLon = p.longitude;\n if (p.longitude > maxLon) maxLon = p.longitude;\n }\n\n const lonSpan = maxLon - minLon;\n const latSpan = maxLat - minLat;\n const scale = 1 - 2 * PANEL_PADDING;\n\n return positions.map((p) => ({\n x: PANEL_PADDING + scale * (lonSpan === 0 ? 0.5 : (p.longitude - minLon) / lonSpan),\n // maxLat at the TOP: screen y grows downward, latitude grows northward.\n y: PANEL_PADDING + scale * (latSpan === 0 ? 0.5 : (maxLat - p.latitude) / latSpan),\n }));\n}\n\n// Coordinates are WGS84 decimal degrees platform-wide. Six decimal places is ~0.1 m at\n// the equator \u2014 finer than any consumer receiver \u2014 and fixed notation stops a small\n// value rendering in exponential form. Matches the device-detail position panel, so the\n// same fix reads identically in both places.\nexport function formatDegrees(value: number): string {\n return value.toFixed(6);\n}\n\n// describePosition renders one fix as a marker's hover/screen-reader text.\n//\n// \uD83D\uDD34 IT REPORTS ONLY WHAT THE DEVICE REPORTED. Elevation, accuracy, speed and heading\n// are each optional, and an absent one contributes NO SEGMENT at all \u2014 it is never\n// filled in with a zero. A marker reading \"0\u00B0\" claims the device reported due north; a\n// marker with no heading segment claims nothing, which is the truth. Every test is\n// `!= null`, so a genuine 0 (parked, sea level, due north) is still shown.\n//\n// Units are fixed platform-wide: metres, metres per second, degrees clockwise from true\n// north.\nexport function describePosition(sample: PlaceableLocation): string {\n const parts: string[] = [\n sample.deviceToken,\n `${formatDegrees(sample.latitude)}, ${formatDegrees(sample.longitude)}`,\n ];\n if (sample.elevation != null) parts.push(`${sample.elevation} m`);\n if (sample.accuracy != null) parts.push(`\u00B1${sample.accuracy} m`);\n if (sample.speed != null) parts.push(`${sample.speed} m/s`);\n if (sample.heading != null) parts.push(`${sample.heading}\u00B0`);\n return parts.join(' \u00B7 ');\n}\n\n// rasterStyleFor builds the MapLibre style document for a user-supplied raster tile\n// source.\n//\n// \uD83D\uDD34 THIS PACKAGE HARDCODES NO TILE SOURCE, AND THAT IS A DECISION RATHER THAN AN\n// OMISSION. The library is not the map \u2014 the TILES are, and they carry their own terms,\n// so a widget library is the wrong place to choose a provider on an operator's behalf.\n// The URL arrives as config, and with none set the widget falls back to the BUNDLED\n// world basemap below \u2014 public-domain geometry compiled into this package, which asks\n// no host for anything and so adopts nobody's terms. That is the distinction the rule\n// is actually about: not \"ship no map\", but \"make no request on an operator's behalf\n// to a host they never chose\".\n//\n// The PLATFORM does ship a default (ADR-079): an instance-wide setting a tenant can\n// override, which a board then inherits when its own options name nothing. That is a\n// named, visible, replaceable choice made once by an operator \u2014 a different thing from\n// this module quietly baking a host into every build of the library.\n//\n// `attribution` is passed to the source rather than hidden: a tile source's licence\n// commonly REQUIRES visible credit, so it is a property of the data, not decoration a\n// host may strip.\nexport function rasterStyleFor(tileUrl: string, attribution: string | undefined): unknown {\n return {\n version: 8,\n projection: PROJECTION,\n sources: {\n basemap: {\n type: 'raster',\n tiles: [tileUrl],\n tileSize: 256,\n ...(attribution ? { attribution } : {}),\n },\n },\n layers: [{ id: 'basemap', type: 'raster', source: 'basemap' }],\n };\n}\n\n// ---- The bundled world basemap ----------------------------------------------\n\n// \uD83D\uDD34 THE PROJECTION IS THE CORRECTNESS PROPERTY OF THIS WHOLE FILE, and it is\n// declared explicitly \u2014 on BOTH styles \u2014 rather than left to the default.\n//\n// The fence editor stores the coordinates a click produces, so what a style\n// changes must be what is DRAWN and never where a click LANDS. Mercator is\n// MapLibre's default, so writing it out changes no behaviour today. What it buys\n// is that the two styles now state the same thing in the same words, and a test\n// can compare them: an invariant nobody wrote down is an invariant a later edit\n// breaks without anything going red.\n//\n// This is not hypothetical in MapLibre 6. `projection` is a root style key whose\n// `type` is a ZOOM-INTERPOLATABLE expression, so a style is entitled to hand back\n// a globe past some zoom. A globe re-projects the pointer; every ring an author\n// then drew would be saved somewhere they never pointed at, on a map that looked\n// beautiful throughout.\nconst PROJECTION = { type: 'mercator' } as const;\n\n// The bundled basemap's credit line. Natural Earth requires NO attribution \u2014 its\n// licence says in as many words that crediting the authors is unnecessary \u2014 so\n// this is their own suggested short citation, shown for a reason of ours: a\n// viewer has to be able to tell a schematic bundled world apart from a configured\n// provider, or \"no tiles\" reads as \"broken\" all over again.\nexport const BUNDLED_BASEMAP_ATTRIBUTION = 'Made with Natural Earth';\n\n// The bundled style's palette. Literal colours, not theme tokens: a MapLibre style\n// document is JSON handed to a WebGL renderer, and it does not resolve the CSS\n// custom properties the rest of this package themes with. These sit close to the\n// dark surface the fence editor already drew, so the change reads as \"the void\n// grew continents\" rather than as a new skin.\nconst OCEAN = '#0b1220';\nconst LAND = '#1e293b';\nconst BOUNDARY = '#475569';\n\n// landStyleFrom builds the bundled world style from Natural Earth geometry.\n//\n// Kept separate from the loader, and pure, so the style document can be asserted\n// without pulling 150 KiB of coordinates into a test \u2014 and so the one thing worth\n// asserting about it (that it projects exactly as the tiled style does) is\n// checkable in isolation.\nexport function landStyleFrom(land: unknown, boundaries: unknown): unknown {\n return {\n version: 8,\n projection: PROJECTION,\n sources: {\n land: { type: 'geojson', data: land, attribution: BUNDLED_BASEMAP_ATTRIBUTION },\n boundaries: { type: 'geojson', data: boundaries },\n },\n layers: [\n { id: 'ocean', type: 'background', paint: { 'background-color': OCEAN } },\n { id: 'land', type: 'fill', source: 'land', paint: { 'fill-color': LAND } },\n {\n id: 'boundaries',\n type: 'line',\n source: 'boundaries',\n paint: { 'line-color': BOUNDARY, 'line-width': 0.5 },\n },\n ],\n };\n}\n\n// loadLandStyle fetches the bundled geometry and builds its style.\n//\n// \uD83D\uDD34 THE DYNAMIC IMPORT IS THE WHOLE POINT. natural-earth-data is ~150 KiB (~44\n// KiB over the wire) and it must never enter this package's entry chunk: with a\n// tile source configured \u2014 which, since the platform ships a default provider, is\n// the ordinary case \u2014 nobody should download a world map they will not see. A\n// static `import { NATURAL_EARTH }` at the top of this file would give every\n// viewer the payload and change nothing observable, which is how it would survive\n// review.\n//\n// Memoized on the promise, so several map widgets on one board parse it once.\n//\n// \uD83D\uDD34 That memoizes a REJECTION too: one transient chunk failure leaves every\n// unconfigured map on the page falling back until a reload. Deliberate, and the same\n// bargain loadMapLibre has always made \u2014 a retry-on-failure cache would let N widgets\n// re-request a chunk that is failing for a reason retrying will not fix. Worth knowing\n// that the blast radius grew when this became the DEFAULT unconfigured path rather\n// than a rarity.\nlet landStylePromise: Promise<unknown> | undefined;\n\nexport function loadLandStyle(): Promise<unknown> {\n if (!landStylePromise) {\n landStylePromise = import('./natural-earth-data').then((mod) =>\n landStyleFrom(mod.NATURAL_EARTH.land, mod.NATURAL_EARTH.boundaries),\n );\n }\n return landStylePromise;\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The measurement table's registration: descriptor eager, component lazy, from a chunk of its\n// own, so a board with no table never downloads it. Table is also a public export; see\n// alarm-lazy.tsx for what that means for a host's first download.\n\nimport { defineWidget } from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { lazyChunk } from './lazy-chunk';\n\nconst chunk = lazyChunk<typeof import('./table')>(() => import('./table'));\n\nexport const loadTableWidget = chunk.load;\n\nexport const tableWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['table'],\n implementation: { kind: 'trusted-react', component: chunk.component('Table') },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// timeseries-chart \u2014 a live line chart of the rolling measurement window, one\n// series per measurement name. The window is seeded from bucketedMeasurements\n// history (via useMeasurementStream's initialSamples) and extended by the live tail. An\n// interruption of the live feed that history has not filled yet is drawn as a break in the line.\n\nimport { useMemo } from 'react';\n\nimport { isValidSpanSeconds, spanLabel } from '@devicechain/dashboards';\nimport {\n css,\n defineWidget,\n fontVar,\n formatDateTime,\n formatTimestamp,\n optNumber,\n optString,\n optThresholds,\n pickSample,\n primaryMeasurementName,\n spaceVar,\n useWidgetScale,\n useWidgetTimeRange,\n useWidgetTimeZone,\n viewerLocale,\n WidgetFrame,\n type MeasurementStreamState,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\nimport { buildLineOption, EChart, loadChartEngine, useChartTheme } from '@devicechain/widget-sdk/echarts';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { NoReading, useSettledEmpty } from './no-reading-lazy';\nimport type { EventMarkersView } from '../event-markers-types';\n\n// `markers` is supplied by the event-marker feed (a chart with markAlarms / markCommands on) and by\n// nothing else; without it the chart is drawn exactly as it always was.\ntype TimeSeriesProps = WidgetProps & { markers?: EventMarkersView };\n\nexport function TimeSeriesChart({ widget, data, markers }: TimeSeriesProps) {\n const range = useWidgetTimeRange();\n const pinned = optNumber(widget.options, 'windowSeconds');\n const spanSeconds = isValidSpanSeconds(pinned) ? pinned : range?.spanSeconds;\n // The frame's \"Download CSV\": the samples on screen, nothing re-read. The builder is its own chunk, so\n // the chart carries only this closure.\n const exportRows = () => {\n const device = widget.datasource?.kind === 'device' ? widget.datasource.deviceToken : undefined;\n return import('../export-rows').then((m) =>\n m.samplesExport({\n subject: optString(widget.options, 'title') ?? device ?? 'chart',\n samples: data.samples,\n unit: optString(widget.options, 'unit'),\n precision: optNumber(widget.options, 'precision'),\n seriesIs: 'measurement',\n spanSeconds,\n }),\n );\n };\n return (\n <WidgetFrame title={optString(widget.options, 'title')} flush exportRows={exportRows}>\n <TimeSeriesBody widget={widget} data={data} markers={markers} />\n </WidgetFrame>\n );\n}\n\n// Rendered INSIDE the frame: the widget scale is the frame's content column, which is only in\n// context below the frame.\nfunction TimeSeriesBody({ widget, data, markers }: TimeSeriesProps) {\n const theme = useChartTheme();\n const { size, scale } = useWidgetScale();\n\n const measurements = widget.datasource?.measurements;\n const unit = optString(widget.options, 'unit');\n const precision = optNumber(widget.options, 'precision');\n const thresholds = useMemo(() => optThresholds(widget.options, 'thresholds'), [widget.options]);\n // The value axis's ends, when the author set them (each widens for a reading beyond it).\n const min = optNumber(widget.options, 'min');\n const max = optNumber(widget.options, 'max');\n const option = useMemo(() => {\n const base = buildLineOption(data.samples, theme, { measurements, unit, precision, thresholds, scale, gaps: data.gaps, min, max }, size);\n return markers ? markers.decorate(base, size) : base;\n }, [data.samples, data.gaps, theme, measurements, unit, precision, thresholds, scale, size, markers, min, max]);\n\n // Nothing in the window: say why (after the history read has had its moment), with the last reading\n // known outside it as a hint.\n // A chart of several measurements names none: whether the profile omits the first says nothing\n // about the others, so it is \"no data\", never \"not reported\".\n const name = measurements && measurements.length > 1 ? undefined : primaryMeasurementName(widget);\n const explain = useSettledEmpty(data.samples.length === 0);\n if (explain) {\n return (\n <NoReading\n unbound={widget.datasource?.kind === 'unbound'}\n measurement={name}\n lastSample={pickSample(data.latest, name)}\n unit={unit}\n precision={precision}\n waitMs={0}\n />\n );\n }\n\n const chart = (\n <div style={{ position: 'relative', width: '100%', height: '100%' }}>\n <EChart option={option} />\n <SpanBadge widget={widget} data={data} />\n </div>\n );\n if (!markers) return chart;\n // The list and notes sit UNDER the chart, never over it: the chart gives up their height.\n return (\n <div style={{ display: 'flex', flexDirection: 'column', width: '100%', height: '100%' }}>\n <div style={{ flex: 1, minHeight: 0 }}>{chart}</div>\n {markers.footer}\n </div>\n );\n}\n\n// The words the span badge prints. The widget packages carry no i18n runtime (see level-strings).\nconst SPAN_STRINGS = {\n en: {\n from: (time: string) => `from ${time}`,\n pinned: (span: string) => `Pinned to ${span}: the board's time range does not apply to this chart.`,\n cut: (time: string, span: string) =>\n `Showing from ${time}, not the whole ${span}: older samples were dropped to bound memory.`,\n },\n es: {\n from: (time: string) => `desde ${time}`,\n pinned: (span: string) => `Fijado a ${span}: el intervalo de tiempo del panel no se aplica a este gr\u00E1fico.`,\n cut: (time: string, span: string) =>\n `Se muestra desde ${time}, no todo el intervalo de ${span}: se descartaron las muestras m\u00E1s antiguas para acotar la memoria.`,\n },\n};\n\nconst DAY_MS = 86_400_000;\n\n// SpanBadge says what span the chart draws whenever the board's header would say something else:\n// - a chart PINNED to its own span (`windowSeconds`) ignores the viewer's range pick, so under a\n// \"24h\" header a pinned hour would read as a day of data. It prints its own span (\"1h\").\n// - a window the retention ceiling cut (`truncatedBefore`) covers less than its span. It prints\n// where it starts (\"from 14:03\"), so a short window never passes for the whole range.\n// Nothing shows when the chart draws exactly the board's range, or off a board (no header).\nfunction SpanBadge({ widget, data }: { widget: WidgetProps['widget']; data: MeasurementStreamState }) {\n const range = useWidgetTimeRange();\n const timeZone = useWidgetTimeZone();\n const pinned = optNumber(widget.options, 'windowSeconds');\n const span = isValidSpanSeconds(pinned) ? pinned : range?.spanSeconds;\n const showSpan = range !== undefined && span !== range.spanSeconds;\n const cutAt = data.truncatedBefore;\n if (!showSpan && !cutAt) return null;\n\n const words = viewerLocale()?.toLowerCase().startsWith('es') ? SPAN_STRINGS.es : SPAN_STRINGS.en;\n const label = span === undefined ? '' : spanLabel(span);\n // A start more than a day back prints its date, or \"from 09:14\" would name the wrong day.\n const end = range?.paused && range.pausedAt !== undefined ? range.pausedAt : Date.now();\n const time = cutAt\n ? end - Date.parse(cutAt) > DAY_MS\n ? formatDateTime(cutAt, timeZone)\n : formatTimestamp(cutAt, timeZone)\n : '';\n const text = [showSpan ? label : '', cutAt ? words.from(time) : ''].filter(Boolean).join(' \u00B7 ');\n const title = [showSpan ? words.pinned(label) : '', cutAt ? words.cut(time, label) : ''].filter(Boolean).join(' ');\n return (\n <span\n data-chart-span={showSpan ? label : ''}\n data-chart-truncated={cutAt ? '' : undefined}\n title={title}\n style={{\n position: 'absolute',\n top: spaceVar(1),\n right: spaceVar(2),\n padding: `0 ${spaceVar(1)}`,\n fontSize: fontVar('xs'),\n whiteSpace: 'nowrap',\n color: css('muted-foreground'),\n background: css('muted'),\n borderRadius: 4,\n pointerEvents: 'auto',\n }}\n >\n {text}\n </span>\n );\n}\n\n// What preloadWidgets calls: the chart engine loads on demand, as its own chunk, so a host that\n// awaits this for a board holding this widget draws the chart on the board's first frame.\nTimeSeriesChart.preload = loadChartEngine;\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const timeSeriesChartWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['timeseries-chart'],\n implementation: { kind: 'trusted-react', component: TimeSeriesChart },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { WidgetRegistry } from '@devicechain/widget-sdk';\n\nimport { createBuiltinWidgetRegistry } from './builtin-registry';\n\n// The registry a renderer uses when its host passes none: the built-ins, built once per\n// module instance. A registry is sealed and immutable, so sharing this one default between\n// hosts carries no state \u2014 a host with extension packages passes its own.\nlet builtin: WidgetRegistry | undefined;\n\nexport function defaultWidgetRegistry(): WidgetRegistry {\n builtin ??= createBuiltinWidgetRegistry();\n return builtin;\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// Per-widget failure containment. Every widget implementation renders inside its own error\n// boundary: a component that throws shows a local diagnostic with a reset control while its\n// siblings keep rendering, and a host callback that rejects (an action, a candidate lookup)\n// is surfaced on the widget that made the call instead of vanishing into an unhandled\n// rejection. An error boundary cannot contain an infinite loop or hostile same-page code;\n// trusted package installation remains the operator's responsibility.\n\nimport { Component, createContext, useCallback, useContext, useState, type ReactNode } from 'react';\n\nimport { WidgetFrame } from '@devicechain/widget-sdk';\nimport { describeError, type ReportRejection } from './widget-host';\n\nconst MESSAGE_STYLE = {\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 4,\n width: '100%',\n height: '100%',\n padding: 12,\n boxSizing: 'border-box',\n textAlign: 'center',\n color: 'hsl(var(--muted-foreground))',\n} as const;\n\nconst BUTTON_STYLE = {\n marginTop: 4,\n fontSize: 11,\n padding: '2px 8px',\n cursor: 'pointer',\n} as const;\n\n// The reporter a body uses for async host callbacks. A no-op outside a containment, so a\n// component rendered on its own never needs one.\nconst ReportContext = createContext<ReportRejection>(() => {});\n\nexport function useReportRejection(): ReportRejection {\n return useContext(ReportContext);\n}\n\ninterface BoundaryProps {\n title?: string;\n // Changes when the widget's stored configuration changes, so an edit retries a widget\n // that threw on the old one.\n resetKey: string;\n onReset: () => void;\n children: ReactNode;\n}\n\ninterface BoundaryState {\n error: { message: string } | null;\n resetKey: string;\n}\n\nclass WidgetErrorBoundary extends Component<BoundaryProps, BoundaryState> {\n state: BoundaryState = { error: null, resetKey: this.props.resetKey };\n\n static getDerivedStateFromError(error: unknown): Partial<BoundaryState> {\n return { error: { message: describeError(error) } };\n }\n\n static getDerivedStateFromProps(props: BoundaryProps, state: BoundaryState): Partial<BoundaryState> | null {\n if (props.resetKey === state.resetKey) return null;\n return { error: null, resetKey: props.resetKey };\n }\n\n private reset = (): void => {\n this.props.onReset();\n this.setState({ error: null });\n };\n\n render(): ReactNode {\n const { error } = this.state;\n if (!error) return this.props.children;\n return (\n <WidgetFrame title={this.props.title}>\n <div style={MESSAGE_STYLE} role=\"alert\">\n <div style={{ fontSize: 20, lineHeight: 1 }} aria-hidden=\"true\">\n \u26A0\n </div>\n <div style={{ fontSize: 13, fontWeight: 600 }}>This widget failed to render</div>\n <div style={{ fontSize: 11, opacity: 0.8, wordBreak: 'break-word' }}>{error.message}</div>\n <button type=\"button\" style={BUTTON_STYLE} onClick={this.reset}>\n Reset widget\n </button>\n </div>\n </WidgetFrame>\n );\n }\n}\n\nexport interface WidgetContainmentProps {\n title?: string;\n resetKey: string;\n children: ReactNode;\n}\n\n// WidgetContainment wraps ONE widget. Rejections reported by the host callbacks it hands\n// down appear in a dismissible strip over the widget's bottom edge.\nexport function WidgetContainment({ title, resetKey, children }: WidgetContainmentProps) {\n const [messages, setMessages] = useState<string[]>([]);\n const report = useCallback<ReportRejection>((message) => {\n setMessages((prev) => (prev.includes(message) ? prev : [...prev, message].slice(-3)));\n }, []);\n const clear = useCallback(() => setMessages([]), []);\n return (\n <div style={{ position: 'relative', width: '100%', height: '100%' }}>\n <ReportContext.Provider value={report}>\n <WidgetErrorBoundary title={title} resetKey={resetKey} onReset={clear}>\n {children}\n </WidgetErrorBoundary>\n </ReportContext.Provider>\n {messages.length > 0 && (\n <div\n role=\"status\"\n style={{\n position: 'absolute',\n left: 4,\n right: 4,\n bottom: 4,\n fontSize: 11,\n padding: '2px 6px',\n borderRadius: 4,\n background: 'hsl(var(--destructive, 0 70% 45%))',\n color: 'hsl(var(--destructive-foreground, 0 0% 100%))',\n display: 'flex',\n gap: 6,\n alignItems: 'center',\n }}\n >\n <span style={{ flex: 1, wordBreak: 'break-word' }}>{messages.join(' \u00B7 ')}</span>\n <button type=\"button\" aria-label=\"Dismiss\" onClick={clear} style={{ cursor: 'pointer' }}>\n \u00D7\n </button>\n </div>\n )}\n </div>\n );\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// What the host hands one widget: ONLY the interactions its descriptor declares,\n// intersected with what the host supports. Declaring an interaction is a request, and this\n// narrowing is API hygiene, not a security boundary (trusted React runs with the page's\n// privileges); the server stays the authority on every write.\n\nimport type { WidgetActions, WidgetDescriptor } from '@devicechain/dashboards';\n\nimport { type WidgetCandidates, type WidgetSelect } from '@devicechain/widget-sdk';\n\n// Receives the message of an async host callback that rejected, so it can be shown on the\n// widget that made the call.\nexport type ReportRejection = (message: string) => void;\n\nexport function describeError(error: unknown): string {\n if (error instanceof Error) return error.message || error.name;\n return String(error);\n}\n\n// guardAsync reports a rejection to the widget's local diagnostics and rethrows it, so a\n// widget that handles the failure itself (a refusal it shows inline) still sees it.\nfunction guardAsync<A extends unknown[], R>(\n fn: (...args: A) => Promise<R>,\n report: ReportRejection,\n): (...args: A) => Promise<R> {\n return (...args: A) => {\n let pending: Promise<R>;\n try {\n pending = Promise.resolve(fn(...args));\n } catch (e) {\n report(describeError(e));\n return Promise.reject(e);\n }\n return pending.catch((e: unknown) => {\n report(describeError(e));\n throw e;\n });\n };\n}\n\nconst ALARM_AUTHORITY = 'alarm:write';\nconst COMMAND_AUTHORITY = 'command:write';\n\n// A call to an interaction the widget did not declare rejects, and the rejection is reported\n// on the widget like any other failed host callback: a widget that fires and forgets\n// (`void actions.acknowledgeAlarm(t)`) must still SHOW the refusal, not swallow it.\nfunction undeclared(capability: string, report: ReportRejection): () => Promise<never> {\n return guardAsync(\n () => Promise.reject(new Error(`this widget did not declare the ${capability} interaction`)),\n report,\n );\n}\n\n// narrowActions returns the action seam a widget may use. A widget that declares neither\n// alarm actions nor command send gets none; one that declares a subset gets the declared\n// methods working and the rest refusing loudly (never a silent no-op), and `can` denies the\n// write authorities of capabilities it did not declare.\nexport function narrowActions(\n actions: WidgetActions | undefined,\n descriptor: WidgetDescriptor,\n report: ReportRejection,\n): WidgetActions | undefined {\n if (!actions) return undefined;\n const alarm = descriptor.interactions.alarmActions === true;\n const command = descriptor.interactions.commandSend === true;\n if (!alarm && !command) return undefined;\n const narrowed: WidgetActions = {\n acknowledgeAlarm: alarm\n ? guardAsync((t) => actions.acknowledgeAlarm(t), report)\n : undeclared('alarmActions', report),\n clearAlarm: alarm ? guardAsync((t) => actions.clearAlarm(t), report) : undeclared('alarmActions', report),\n can: (authority) => {\n if (authority === ALARM_AUTHORITY && !alarm) return false;\n if (authority === COMMAND_AUTHORITY && !command) return false;\n return actions.can(authority);\n },\n };\n // Left absent when undeclared or unsupported: a command widget feature-detects it and\n // renders its Send control disabled.\n if (command && typeof actions.sendCommand === 'function') {\n narrowed.sendCommand = guardAsync((d, n, p) => actions.sendCommand!(d, n, p), report);\n }\n return narrowed;\n}\n\n// narrowSelect: the view-selection callback, only for a widget that declared `selection`.\nexport function narrowSelect(select: WidgetSelect | undefined, descriptor: WidgetDescriptor): WidgetSelect | undefined {\n return descriptor.interactions.selection === true ? select : undefined;\n}\n\n// narrowCandidates: the candidate lookup, only for a widget that declared `candidates`; its\n// rejections are reported locally and rethrown.\nexport function narrowCandidates(\n candidates: WidgetCandidates | undefined,\n descriptor: WidgetDescriptor,\n report: ReportRejection,\n): WidgetCandidates | undefined {\n if (!candidates || descriptor.interactions.candidates !== true) return undefined;\n return guardAsync((slot) => candidates(slot), report);\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The viewer's time-range control: the presets, a pause, the \"Paused\" indicator, and a custom\n// from-to window (picked in a lazily loaded panel, or opened from a `?from=&to=` link). One\n// component for every host (the console viewer, the /dash app), so the two cannot disagree about\n// what a frozen board looks like. It is a plain controlled bar -- the host owns the state through\n// useBoardTimeRange and feeds it to the renderer as `timeRange` -- and it carries no copy of its\n// own beyond English defaults: a host passes its translations as `labels`.\n\nimport {\n DEFAULT_TIME_RANGE_SECONDS,\n TIME_RANGE_PRESETS,\n absoluteRange,\n absoluteToParams,\n initialTimeRange,\n isValidSpanSeconds,\n leaveAbsolute,\n pauseRange,\n presetIdOf,\n resumeRange,\n spanLabel,\n withSpan,\n type AbsoluteLinkRejection,\n type AbsoluteRange,\n type AbsoluteRangeProblem,\n type TimeRangeState,\n} from '@devicechain/dashboards';\nimport { useCallback, useEffect, useMemo, useRef, useState, type ComponentType, type CSSProperties } from 'react';\nimport type { AbsolutePickerLabels } from './absolute-range-picker';\n\nexport interface TimeRangeControls {\n setSpan(spanSeconds: number): void;\n pause(): void;\n resume(): void;\n // Show a fixed from-to window (epoch ms). Returns why it was refused, or undefined when taken.\n setAbsolute(fromMs: number, toMs: number): AbsoluteRangeProblem | undefined;\n}\n\n// useBoardTimeRange holds the board's range for a host: the definition's default span, or the\n// deep link's (a preset span, a frozen instant, or an absolute window), and live unless the link\n// says otherwise. `defaultSeconds` is read once, at mount; a host that swaps boards remounts (the\n// console and /dash both do), which is when it should reset.\nexport function useBoardTimeRange(\n defaultSeconds: number | undefined,\n link: { spanSeconds?: number; paused?: boolean; absolute?: AbsoluteRange } = {},\n): [TimeRangeState, TimeRangeControls] {\n const [state, setState] = useState<TimeRangeState>(() => initialTimeRange(defaultSeconds, link));\n // An author who changes the board's default while the viewer is open expects the board to follow;\n // a viewer's own pick is only overridden when the DEFAULT moves, never by re-rendering.\n const lastDefault = useRef(defaultSeconds);\n useEffect(() => {\n if (lastDefault.current === defaultSeconds) return;\n lastDefault.current = defaultSeconds;\n setState((s) => withSpan(s, isValidSpanSeconds(defaultSeconds) ? defaultSeconds : DEFAULT_TIME_RANGE_SECONDS));\n }, [defaultSeconds]);\n const controls = useMemo<TimeRangeControls>(\n () => ({\n // A preset click while a fixed window is showing leaves it: back to live at that span.\n setSpan: (spanSeconds) => setState((s) => withSpan(leaveAbsolute(s), spanSeconds)),\n pause: () => setState((s) => pauseRange(s, Date.now())),\n resume: () => setState((s) => resumeRange(s)),\n setAbsolute: (fromMs, toMs) => {\n const made = absoluteRange(fromMs, toMs);\n if ('problem' in made) return made.problem;\n setState(made.state);\n return undefined;\n },\n }),\n [],\n );\n return [state, controls];\n}\n\nexport interface AbsoluteLabels extends AbsolutePickerLabels {\n // \"Fixed window\" -- what the indicator says in place of \"Paused\".\n fixed: string;\n // The button that leaves a fixed window for the live board.\n backToLive: string;\n copyLink: string;\n linkCopied: string;\n // The picker's chunk could not be fetched.\n loadFailed: string;\n dismiss: string;\n // The note shown when a `?from=&to=` link was ignored. `reason` is the problem; `raw` the values.\n ignored: (reason: string, raw: string) => string;\n incomplete: string;\n // The link carried a date-time with no zone, or one that does not parse.\n unzoned: string;\n}\n\nexport interface TimeRangeLabels {\n range: string;\n pause: string;\n resume: string;\n paused: string;\n // \"Paused at 14:03:22\".\n pausedAt: (time: string) => string;\n // Printed inside the pill: a pause freezes what the board SHOWS, never what it DOES. Commands\n // (and alarm acknowledge / clear) still go out at once, and their status keeps updating, so an\n // operator who acts on a frozen board is told the action is live.\n actionsLive: string;\n // The custom-window strings. Optional so a host written before the absolute range keeps compiling;\n // the English defaults fill any it leaves out.\n absolute?: Partial<AbsoluteLabels>;\n}\n\nexport const DEFAULT_ABSOLUTE_LABELS: AbsoluteLabels = {\n custom: 'Custom range',\n from: 'From',\n to: 'To',\n apply: 'Apply',\n cancel: 'Cancel',\n zone: (zone, offset) => `Times are in ${zone} (${offset}). Shared links use UTC.`,\n problem: {\n unparseable: 'Enter both a start and an end.',\n order: 'The start must be before the end.',\n tooShort: 'The window must be at least one minute.',\n tooLong: 'The window can be at most 31 days.',\n future: 'The end cannot be in the future.',\n tooEarly: 'The start is too far in the past.',\n },\n fixed: 'Fixed window',\n backToLive: 'Back to live',\n copyLink: 'Copy link',\n linkCopied: 'Link copied',\n loadFailed: 'The range picker could not be loaded. Try again.',\n dismiss: 'Dismiss',\n ignored: (reason, raw) => `The link's time window was ignored: ${reason} (${raw}). Showing the live board.`,\n incomplete: 'both from and to are required',\n unzoned: 'times must be ISO 8601 with a zone, such as 2026-10-22T02:00:00Z or +02:00',\n};\n\nexport const DEFAULT_TIME_RANGE_LABELS: TimeRangeLabels = {\n range: 'Time range',\n pause: 'Pause',\n resume: 'Resume',\n paused: 'Paused',\n pausedAt: (time) => `Paused at ${time}`,\n actionsLive: 'commands still send',\n};\n\nconst absoluteLabels = (labels: TimeRangeLabels): AbsoluteLabels => ({ ...DEFAULT_ABSOLUTE_LABELS, ...labels.absolute });\n\n// The note text for a deep link whose `from`/`to` were unusable.\nexport function rejectedLinkNote(rejected: AbsoluteLinkRejection, labels: TimeRangeLabels = DEFAULT_TIME_RANGE_LABELS): string {\n const l = absoluteLabels(labels);\n const raw = `from=${rejected.from || '-'} to=${rejected.to || '-'}`;\n const reason =\n rejected.reason === 'incomplete' ? l.incomplete : rejected.reason === 'unparseable' ? l.unzoned : l.problem[rejected.reason];\n return l.ignored(reason, raw);\n}\n\nconst button = (active: boolean): CSSProperties => ({\n padding: '2px 8px',\n fontSize: 12,\n lineHeight: '18px',\n cursor: 'pointer',\n color: active ? 'hsl(var(--background))' : 'hsl(var(--foreground))',\n background: active ? 'hsl(var(--foreground))' : 'transparent',\n border: '1px solid hsl(var(--border))',\n borderRadius: 4,\n});\n\n// The pill is deliberately loud: filled, bordered and spelled out, because a frozen board that\n// reads as live is the failure this slice exists to prevent. Exported so a kiosk wall (which has\n// no bar) can show it alone.\nexport function PausedIndicator({\n pausedAt,\n labels = DEFAULT_TIME_RANGE_LABELS,\n}: {\n pausedAt: number | undefined;\n labels?: TimeRangeLabels;\n}) {\n const time = pausedAt === undefined ? undefined : new Date(pausedAt).toLocaleTimeString();\n return (\n <span\n role=\"status\"\n data-time-range-paused=\"\"\n title={time ? labels.pausedAt(time) : labels.paused}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: 4,\n padding: '2px 8px',\n fontSize: 12,\n fontWeight: 700,\n letterSpacing: 0.4,\n textTransform: 'uppercase',\n color: 'hsl(var(--background))',\n background: 'hsl(var(--foreground))',\n border: '2px solid hsl(var(--foreground))',\n borderRadius: 4,\n }}\n >\n <span aria-hidden=\"true\">{'\u23F8'}</span>\n {labels.paused}\n {time ? <span style={{ fontWeight: 400, textTransform: 'none' }}>{` ${time}`}</span> : null}\n <span data-time-range-actions-live=\"\" style={{ fontWeight: 400, textTransform: 'none' }}>\n {`\u00B7 ${labels.actionsLive}`}\n </span>\n </span>\n );\n}\n\n// A window as text, each end WITH its zone: \"Oct 22, 2026, 2:00 AM CEST - Oct 22, 2026, 4:00 AM CEST\".\nexport function formatAbsoluteRange(a: AbsoluteRange): string {\n const f = new Intl.DateTimeFormat(undefined, { year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', timeZoneName: 'short' });\n return `${f.format(a.fromMs)} \u2013 ${f.format(a.toMs)}`;\n}\n\n// What stands in for the Paused pill while a fixed window shows. Same loudness, different words:\n// \"Paused\" would be wrong (nothing was paused, a window was chosen), and the live tail is off for\n// the same reason either way. Exported for the kiosk, like PausedIndicator.\nexport function AbsoluteIndicator({\n absolute,\n labels = DEFAULT_TIME_RANGE_LABELS,\n}: {\n absolute: AbsoluteRange;\n labels?: TimeRangeLabels;\n}) {\n const l = absoluteLabels(labels);\n const utc = absoluteToParams(absolute);\n return (\n <span\n role=\"status\"\n data-time-range-absolute=\"\"\n title={`${utc.from} \u2013 ${utc.to} (UTC)`}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n flexWrap: 'wrap',\n gap: 4,\n padding: '2px 8px',\n fontSize: 12,\n fontWeight: 700,\n color: 'hsl(var(--background))',\n background: 'hsl(var(--foreground))',\n border: '2px solid hsl(var(--foreground))',\n borderRadius: 4,\n }}\n >\n <span style={{ letterSpacing: 0.4, textTransform: 'uppercase' }}>{l.fixed}</span>\n <span data-time-range-window=\"\" style={{ fontWeight: 400 }}>\n {formatAbsoluteRange(absolute)}\n </span>\n <span data-time-range-actions-live=\"\" style={{ fontWeight: 400 }}>\n {`\u00B7 ${labels.actionsLive}`}\n </span>\n </span>\n );\n}\n\n// The shareable address of the window: the current page with `from`/`to` in UTC, and the rolling\n// parameters dropped (an absolute window wins over them, so leaving them would only mislead).\nexport function absoluteLinkFor(href: string, a: AbsoluteRange): string {\n const url = new URL(href);\n const { from, to } = absoluteToParams(a);\n url.searchParams.delete('range');\n url.searchParams.delete('paused');\n url.searchParams.set('from', from);\n url.searchParams.set('to', to);\n return url.toString();\n}\n\ntype PickerProps = {\n initial?: AbsoluteRange;\n labels: AbsolutePickerLabels;\n onApply: (fromMs: number, toMs: number) => AbsoluteRangeProblem | undefined;\n onCancel: () => void;\n};\n\nexport function TimeRangeBar({\n state,\n controls,\n labels = DEFAULT_TIME_RANGE_LABELS,\n notice,\n}: {\n state: TimeRangeState;\n controls: TimeRangeControls;\n labels?: TimeRangeLabels;\n // A host's note about its deep link (an ignored `?from=&to=`), shown dismissibly under the bar.\n notice?: string;\n}) {\n const abs = state.absolute;\n const preset = abs ? undefined : presetIdOf(state.spanSeconds);\n const onPause = useCallback(() => (state.paused ? controls.resume() : controls.pause()), [state.paused, controls]);\n const l = absoluteLabels(labels);\n\n // The picker is fetched on the first click, as its own chunk.\n const [Picker, setPicker] = useState<ComponentType<PickerProps> | undefined>();\n const [open, setOpen] = useState(false);\n const [loadFailed, setLoadFailed] = useState(false);\n const [copied, setCopied] = useState(false);\n const [noticeShown, setNoticeShown] = useState(true);\n useEffect(() => setNoticeShown(true), [notice]);\n\n const openPicker = () => {\n if (open) {\n setOpen(false);\n return;\n }\n setLoadFailed(false);\n if (Picker) {\n setOpen(true);\n return;\n }\n import('./absolute-range-picker').then(\n (m) => {\n setPicker(() => m.default);\n setOpen(true);\n },\n () => setLoadFailed(true),\n );\n };\n\n const copyLink = () => {\n if (!abs) return;\n navigator.clipboard?.writeText(absoluteLinkFor(window.location.href, abs)).then(\n () => {\n setCopied(true);\n window.setTimeout(() => setCopied(false), 2000);\n },\n () => undefined,\n );\n };\n\n return (\n <div style={{ position: 'relative', display: 'inline-block', maxWidth: '100%' }}>\n <div\n data-time-range-bar=\"\"\n role=\"group\"\n aria-label={labels.range}\n style={{ display: 'inline-flex', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}\n >\n {/* A board default that is none of the presets (two hours, say) is still the selected span,\n shown under its own label rather than silently looking like another preset. */}\n {!abs && preset === undefined ? (\n <button type=\"button\" aria-pressed=\"true\" data-range={spanLabel(state.spanSeconds)} style={button(true)}>\n {spanLabel(state.spanSeconds)}\n </button>\n ) : null}\n {TIME_RANGE_PRESETS.map((p) => (\n <button\n key={p.id}\n type=\"button\"\n aria-pressed={p.id === preset}\n data-range={p.id}\n onClick={() => controls.setSpan(p.seconds)}\n style={button(p.id === preset)}\n >\n {p.id}\n </button>\n ))}\n <button\n type=\"button\"\n aria-pressed={abs !== undefined}\n aria-expanded={open}\n data-time-range-custom=\"\"\n onClick={openPicker}\n style={button(abs !== undefined)}\n >\n {l.custom}\n </button>\n {abs ? (\n <>\n <button type=\"button\" data-time-range-live=\"\" onClick={() => controls.resume()} style={button(false)}>\n {l.backToLive}\n </button>\n <button type=\"button\" data-time-range-copy=\"\" onClick={copyLink} style={button(false)}>\n {copied ? l.linkCopied : l.copyLink}\n </button>\n <AbsoluteIndicator absolute={abs} labels={labels} />\n </>\n ) : (\n <>\n <button type=\"button\" aria-pressed={state.paused} data-time-range-pause=\"\" onClick={onPause} style={button(state.paused)}>\n {state.paused ? labels.resume : labels.pause}\n </button>\n {state.paused ? <PausedIndicator pausedAt={state.pausedAt} labels={labels} /> : null}\n </>\n )}\n </div>\n {open && Picker ? (\n <div style={{ position: 'absolute', right: 0, top: '100%', marginTop: 6, zIndex: 30 }}>\n <Picker\n initial={abs}\n labels={l}\n onApply={(from, to) => {\n const problem = controls.setAbsolute(from, to);\n if (!problem) setOpen(false);\n return problem;\n }}\n onCancel={() => setOpen(false)}\n />\n </div>\n ) : null}\n {loadFailed ? (\n <div role=\"alert\" data-time-range-load-failed=\"\" style={{ fontSize: 12, color: 'hsl(var(--destructive))' }}>\n {l.loadFailed}\n </div>\n ) : null}\n {notice && noticeShown ? (\n <div\n role=\"status\"\n data-time-range-notice=\"\"\n style={{ display: 'flex', gap: 8, alignItems: 'baseline', marginTop: 4, fontSize: 12, color: 'hsl(var(--muted-foreground))' }}\n >\n <span style={{ minWidth: 0, overflowWrap: 'anywhere' }}>{notice}</span>\n <button type=\"button\" onClick={() => setNoticeShown(false)} style={{ ...button(false), flex: '0 0 auto' }}>\n {l.dismiss}\n </button>\n </div>\n ) : null}\n </div>\n );\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// useBoundDevices: the host-side hook that keeps a board's device selection and the address in\n// step, in both directions, and refuses a deep link it cannot honour.\n//\n// address \u2500\u2500\u25BA selection a `bind.<slot>=<device>` link is read, EVERY named device is checked\n// against the caller's own scope, and only then bound.\n// selection \u2500\u25BA address a pick (a marker click, a table row, a selector) rewrites the\n// `bind.*` parameters, so the address in the bar is always a link that\n// reproduces what is on screen.\n//\n// \uD83D\uDD34 REPLACE, NOT PUSH, and that is the decision rather than a default. A pick refines the view\n// the viewer is already on; it is not a place they went. Pushing an entry per marker click would\n// make Back walk through every device they happened to click, on a wall display or a phone,\n// instead of leaving the board, and would fill history with entries that all show the same\n// board. A copied link still reproduces the state, which is what an address is for. The cost,\n// accepted: Back does not undo a pick. What DOES follow history is an address that changes from\n// outside (the viewer pastes or follows a different link, or a router entry is restored): that\n// is read as a new link and checked like the first one.\n//\n// \uD83D\uDD34 A REFUSED LINK BLOCKS THE BOARD; it does not fall back to the board's default device. The\n// default is a DIFFERENT device from the one the link names, and a viewer who asked for pump 7\n// and is shown pump 3 under pump 7's link is being lied to. `phase: 'refused'` carries the\n// reasons, the host shows them, and `dismiss` is the viewer's explicit choice to open the board\n// without the parts that failed.\n\nimport {\n bindParamsOf,\n bindsToSelection,\n parseBindParams,\n selectionToBinds,\n validateBinds,\n withBindParams,\n type BindCheck,\n type BindParamIssue,\n type DashboardDefinition,\n type DeviceResolver,\n type SelectionTarget,\n type SlotBinding,\n} from '@devicechain/dashboards';\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\n// Where the address lives. A host with a router passes its location and a replace-navigate; a\n// host without one passes window.location and history.replaceState. `search` has no leading `?`\n// requirement: both forms are read.\nexport interface BoundDevicesAddress {\n search: string;\n replaceSearch: (search: string) => void;\n}\n\nexport interface LinkProblems {\n issues: BindParamIssue[];\n missing: BindCheck['missing'];\n failed: BindCheck['failed'];\n}\n\nexport type BoundDevicesPhase = 'ready' | 'checking' | 'refused';\n\nexport interface BoundDevices {\n // The selection overlay to hand to useResolvedBindings. Only validated devices are ever in it.\n selection: Record<string, SlotBinding>;\n select: (target: SelectionTarget) => void;\n // Drops the overlay (a mode switch): the board returns to its own defaults.\n reset: () => void;\n phase: BoundDevicesPhase;\n // Present while `phase` is 'refused'.\n problems: LinkProblems | null;\n // Open the board without the parts of the link that failed.\n dismiss: () => void;\n // Ask again (the check failed rather than the device being absent).\n retry: () => void;\n}\n\nconst NO_PROBLEMS: LinkProblems = { issues: [], missing: [], failed: [] };\n\nfunction hasBindParams(search: string, definition: DashboardDefinition): boolean {\n const { binds, issues } = parseBindParams(search, definition);\n return Object.keys(binds).length > 0 || issues.length > 0;\n}\n\nexport function useBoundDevices({\n definition,\n resolver,\n address,\n enabled = true,\n}: {\n definition: DashboardDefinition;\n resolver: Pick<DeviceResolver, 'deviceExists'>;\n address: BoundDevicesAddress;\n // False while the board is being edited: the overlay is empty then, and an empty overlay must\n // not strip the link out of the address the author will return to.\n enabled?: boolean;\n}): BoundDevices {\n // The check that is read on the first render so a link never paints the board's defaults first.\n // The overlay, with the `bind.*` slice of the address it was last made to agree with. They move\n // together because the write-back below must only run while the address has not moved ahead of\n // the selection: an address that changed from outside is READ, never overwritten by a selection\n // that has not caught up with it yet.\n const [core, setCore] = useState<{ selection: Record<string, SlotBinding>; synced: string }>(() => ({\n selection: {},\n synced: bindParamsOf(address.search),\n }));\n const { selection } = core;\n const [phase, setPhase] = useState<BoundDevicesPhase>(() =>\n hasBindParams(address.search, definition) ? 'checking' : 'ready',\n );\n const [problems, setProblems] = useState<LinkProblems | null>(null);\n const [okBinds, setOkBinds] = useState<Record<string, string>>({});\n\n const definitionRef = useRef(definition);\n definitionRef.current = definition;\n const resolverRef = useRef(resolver);\n resolverRef.current = resolver;\n const replaceRef = useRef(address.replaceSearch);\n replaceRef.current = address.replaceSearch;\n\n // The `bind.*` slice of the address as this hook last wrote or last read it. An address whose\n // slice differs from this changed from OUTSIDE and is a new link.\n const seenRef = useRef<string | null>(null);\n const generation = useRef(0);\n const [attempt, setAttempt] = useState(0);\n\n const search = address.search;\n useEffect(() => {\n if (!enabled) return;\n const slice = bindParamsOf(search);\n // Our own write coming back round: nothing to read.\n if (seenRef.current === slice) return;\n seenRef.current = slice;\n\n const parsed = parseBindParams(search, definitionRef.current);\n if (Object.keys(parsed.binds).length === 0 && parsed.issues.length === 0) {\n generation.current += 1;\n setCore({ selection: {}, synced: slice });\n setProblems(null);\n setPhase('ready');\n return;\n }\n const gen = ++generation.current;\n setPhase('checking');\n void validateBinds(parsed.binds, resolverRef.current).then((check) => {\n if (gen !== generation.current) return;\n setOkBinds(check.ok);\n if (parsed.issues.length === 0 && check.missing.length === 0 && check.failed.length === 0) {\n setCore({ selection: bindsToSelection(check.ok), synced: slice });\n setProblems(null);\n setPhase('ready');\n } else {\n setProblems({ issues: parsed.issues, missing: check.missing, failed: check.failed });\n setCore((c) => ({ ...c, synced: slice }));\n setPhase('refused');\n }\n });\n }, [search, enabled, attempt]);\n\n // selection \u2500\u25BA address\n useEffect(() => {\n if (!enabled || phase !== 'ready') return;\n const current = bindParamsOf(search);\n if (current !== core.synced) return; // the address moved first: the read effect owns this turn\n const next = withBindParams(search, selectionToBinds(core.selection, definition));\n const nextSlice = bindParamsOf(next);\n if (nextSlice === current) return;\n seenRef.current = nextSlice;\n setCore((c) => ({ ...c, synced: nextSlice }));\n replaceRef.current(next);\n }, [core, definition, phase, enabled, search]);\n\n const select = useCallback((t: SelectionTarget) => {\n setCore((c) => ({ ...c, selection: { ...c.selection, [t.slot]: t.binding } }));\n }, []);\n const reset = useCallback(() => setCore((c) => ({ ...c, selection: {} })), []);\n\n const dismiss = useCallback(() => {\n // Keep what DID check out, drop what did not; the write-back effect then cleans the address.\n setCore((c) => ({ ...c, selection: bindsToSelection(okBinds) }));\n setProblems(null);\n setPhase('ready');\n }, [okBinds]);\n const retry = useCallback(() => {\n seenRef.current = null;\n setAttempt((n) => n + 1);\n }, []);\n\n return { selection, select, reset, phase, problems: phase === 'refused' ? (problems ?? NO_PROBLEMS) : null, dismiss, retry };\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// What a host shows INSTEAD of the board when a deep link could not be honoured (see\n// useBoundDevices). One presentational component for every host, so the console and the /dash\n// viewer cannot word a refusal differently or, worse, disagree about whether to show the board.\n// It carries no copy: the host builds the lines from its own translations.\n\nimport type { BindParamIssue } from '@devicechain/dashboards';\nimport { css, fontVar } from '@devicechain/widget-sdk';\n\nexport interface BoundDevicesNoticeProps {\n title: string;\n // One sentence per problem, already worded by the host.\n lines: string[];\n // The explicit way forward: open the board without the parts of the link that failed.\n dismissLabel: string;\n onDismiss: () => void;\n // Offered only when a check failed (so asking again can change the answer).\n retryLabel?: string;\n onRetry?: () => void;\n}\n\nexport function BoundDevicesNotice({ title, lines, dismissLabel, onDismiss, retryLabel, onRetry }: BoundDevicesNoticeProps) {\n const button = {\n minHeight: 44,\n padding: '0 16px',\n borderRadius: 8,\n border: `1px solid ${css('border')}`,\n background: css('card'),\n color: css('foreground'),\n fontSize: fontVar('md'),\n cursor: 'pointer',\n } as const;\n return (\n <div\n role=\"alert\"\n data-testid=\"bound-devices-notice\"\n style={{\n boxSizing: 'border-box',\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'flex-start',\n gap: 12,\n maxWidth: 560,\n margin: '24px auto',\n padding: 16,\n borderRadius: 8,\n border: `1px solid ${css('border')}`,\n background: css('card'),\n color: css('foreground'),\n }}\n >\n <div style={{ fontSize: fontVar('lg'), fontWeight: 600 }}>{title}</div>\n <ul style={{ margin: 0, paddingLeft: 20, display: 'flex', flexDirection: 'column', gap: 4, fontSize: fontVar('md') }}>\n {lines.map((line, i) => (\n <li key={i} style={{ overflowWrap: 'anywhere' }}>\n {line}\n </li>\n ))}\n </ul>\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>\n {retryLabel && onRetry ? (\n <button type=\"button\" style={button} onClick={onRetry} data-testid=\"bound-devices-retry\">\n {retryLabel}\n </button>\n ) : null}\n <button type=\"button\" style={button} onClick={onDismiss} data-testid=\"bound-devices-dismiss\">\n {dismissLabel}\n </button>\n </div>\n </div>\n );\n}\n\n// The lines a refused link reports, in the order a viewer fixes them: what the link got wrong,\n// then which devices are not theirs to see, then which could not be checked. The wording is the\n// host's; this only decides WHICH problems exist and how many sentences they make.\nexport interface BoundDevicesWording {\n unknownSlot: (slot: string) => string;\n notADeviceSlot: (slot: string) => string;\n invalidToken: (slot: string, token: string) => string;\n // The link names the slot twice.\n duplicateSlot: (slot: string) => string;\n // The slot's device follows another slot, so a link cannot choose it.\n derivedSlot: (slot: string) => string;\n // \"doesn't exist, or you don't have access\": one wording, because the server answers one way.\n missing: (slot: string, token: string) => string;\n failed: (slot: string, token: string) => string;\n}\n\n// A slot name or a value that failed the grammar is whatever the link's sender typed, and it is\n// shown inside the product's own UI: clipped, so a link cannot put a paragraph of its own words\n// (\"your session expired, sign in at \u2026\") in front of the viewer. A valid token is at most 128\n// characters of [A-Za-z0-9_-] and is shown whole.\nconst ECHO_MAX = 48;\nconst echo = (s: string) => (s.length > ECHO_MAX ? `${s.slice(0, ECHO_MAX)}\u2026` : s);\n\nexport function describeBoundDevicesProblems(\n problems: { issues: BindParamIssue[]; missing: Array<{ slot: string; token: string }>; failed: Array<{ slot: string; token: string }> },\n w: BoundDevicesWording,\n): string[] {\n const out: string[] = [];\n for (const i of problems.issues) {\n const slot = echo(i.slot);\n if (i.kind === 'unknown-slot') out.push(w.unknownSlot(slot));\n else if (i.kind === 'not-a-device-slot') out.push(w.notADeviceSlot(slot));\n else if (i.kind === 'duplicate-slot') out.push(w.duplicateSlot(slot));\n else if (i.kind === 'derived-slot') out.push(w.derivedSlot(slot));\n else if (i.kind === 'invalid-token') out.push(w.invalidToken(slot, echo(i.token)));\n else {\n // A new kind must be worded, not shown as some other kind's sentence.\n const unhandled: never = i;\n throw new Error(`describeBoundDevicesProblems: unworded link issue ${JSON.stringify(unhandled)}`);\n }\n }\n for (const m of problems.missing) out.push(w.missing(m.slot, m.token));\n for (const f of problems.failed) out.push(w.failed(f.slot, f.token));\n return out;\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The built-in descriptors AS PUBLISHED: the runtime descriptors of builtin-descriptors.ts with each\n// option's authoring `doc` attached from builtin-option-docs.ts.\n//\n// \uD83D\uDD11 WHY TWO. The renderer needs a widget's channel, options, defaults and binding -- not the prose\n// that explains an option to an author. Prose is the heaviest part of a descriptor, and a descriptor\n// is read eagerly, so it rode in the first download of every host (the replay player's initial bundle\n// grew with each widget for exactly this reason). The runtime descriptors therefore carry no `doc`;\n// this module rebuilds the documented form for EVERY public export that always carried it:\n// `builtinWidgetDescriptors`, `builtinWidgetCatalog`, `builtinWidgetDefinitions`,\n// `createBuiltinWidgetRegistry` and `WIDGET_OPTIONS`. These are published API -- an embedder's config\n// panel may read `doc` off any of them -- so none of them may lose it. The doc-free definitions are\n// published separately, and additively, as `builtinWidgetDefinitionsWithoutDocs`: what a render-only\n// host (the shared host-widgets composition) registers.\n//\n// Every value here is a /* @__PURE__ */ call, so a host that imports none of them -- the replay\n// player, the dashboard viewer -- has the whole module, and the doc table behind it, dropped by its\n// bundler. Nothing in this package's own runtime path imports this file; the replay build's size\n// gate (its absence check) is what would show it if that changed.\n\nimport { createWidgetCatalog, type WidgetDescriptor, type WidgetOptionSpecs } from '@devicechain/dashboards';\nimport { createWidgetRegistry, type WidgetRegistry } from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors as runtimeDescriptors } from './builtin-descriptors';\nimport { OPTION_DOCS, OPTION_DOC_OVERRIDES } from './builtin-option-docs';\nimport { builtinWidgetDefinitions as runtimeDefinitions } from './builtin-registry';\n\n// A copy of an option table with every spec's (and list item field's) doc attached. A COPY, never an\n// edit in place: the runtime descriptors are frozen by the runtime catalog, and a documented\n// descriptor sharing their spec objects would freeze/alias them too.\nfunction documentOptions(widgetId: string, specs: WidgetOptionSpecs, prefix: string): WidgetOptionSpecs {\n const out: Record<string, unknown> = {};\n for (const [key, spec] of Object.entries(specs)) {\n const path = `${prefix}${key}`;\n const copy: Record<string, unknown> = { ...spec };\n const doc = OPTION_DOC_OVERRIDES[widgetId]?.[path] ?? OPTION_DOCS[path];\n if (doc !== undefined) copy.doc = doc;\n if ('item' in spec && spec.item) copy.item = documentOptions(widgetId, spec.item as WidgetOptionSpecs, `${path}.`);\n // Arrays and nested plain data (enum values, labels) are shared by reference with the\n // runtime spec; they are read-only data on both sides.\n out[key] = copy;\n }\n return out as WidgetOptionSpecs;\n}\n\nfunction documentDescriptor<D extends WidgetDescriptor>(descriptor: D): D {\n return { ...descriptor, options: documentOptions(descriptor.id, descriptor.options, '') };\n}\n\nfunction documentAll<T extends Record<string, WidgetDescriptor>>(descriptors: T): T {\n return Object.fromEntries(Object.entries(descriptors).map(([id, d]) => [id, documentDescriptor(d)])) as T;\n}\n\nexport const builtinWidgetDescriptors = /* @__PURE__ */ documentAll(runtimeDescriptors);\n\nfunction catalogOf(descriptors: Record<string, WidgetDescriptor>) {\n return createWidgetCatalog(Object.values(descriptors));\n}\n\nexport const builtinWidgetCatalog = /* @__PURE__ */ catalogOf(builtinWidgetDescriptors);\n\n// The registrations, each paired with its documented descriptor (the component is the same one).\nfunction documentDefinitions<T extends readonly { descriptor: WidgetDescriptor }[]>(definitions: T): T {\n const byId: Record<string, WidgetDescriptor> = builtinWidgetDescriptors;\n return definitions.map((d) => ({ ...d, descriptor: byId[d.descriptor.id] })) as unknown as T;\n}\n\nexport const builtinWidgetDefinitions = /* @__PURE__ */ documentDefinitions(runtimeDefinitions);\n\n// A fresh, sealed registry holding exactly the built-ins, documented. Every call returns an\n// independent instance.\nexport function createBuiltinWidgetRegistry(): WidgetRegistry {\n return createWidgetRegistry(builtinWidgetDefinitions);\n}\n\n// Every built-in's option schema keyed by id, documented: the same projection options.ts makes of\n// the runtime descriptors (its type is that one's), by identity with the documented descriptors.\nfunction optionsById<T extends Record<string, WidgetDescriptor>>(descriptors: T): { readonly [K in keyof T]: T[K]['options'] } {\n return Object.freeze(Object.fromEntries(Object.entries(descriptors).map(([id, d]) => [id, d.options]))) as {\n readonly [K in keyof T]: T[K]['options'];\n };\n}\n\nexport const WIDGET_OPTIONS = /* @__PURE__ */ optionsById(builtinWidgetDescriptors);\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The authoring documentation of every built-in widget option -- the `doc` text each option spec\n// carries for the config panel's help and the published \"available widgets\" page.\n//\n// \uD83D\uDD34 WHY THIS IS NOT IN builtin-descriptors.ts. A `doc` is read by nothing that RENDERS a board,\n// only by authoring surfaces, yet it is prose, and prose is the most expensive thing per byte that\n// a descriptor carries: kept inline it shipped in the first download of every host (the replay\n// player's was ~2 KB gzip, growing with each widget). So the runtime descriptors\n// (builtin-descriptors.ts) carry none, and `builtinWidgetDescriptors` / `builtinWidgetCatalog` as\n// PUBLIC exports are rebuilt from them plus this table (documented-descriptors.ts), which a host that\n// never imports those two drops from its bundle.\n//\n// Keys are option PATHS: `thresholds` for an option, `thresholds.value` for a list option's item\n// field. `OPTION_DOCS` is the text an option has on most widgets; `OPTION_DOC_OVERRIDES` is where a\n// widget words one differently. A built-in option with no doc here fails\n// documented-descriptors.test.ts, which is where the \"every option is documented\" rule that\n// validateWidgetDescriptor applies to extensions is enforced for the built-ins.\n\nexport const OPTION_DOCS: Readonly<Record<string, string>> = {\n title: 'Heading shown in the widget frame. Blank hides the frame heading.',\n unit: 'Unit suffix shown beside the value.',\n precision: 'Decimal places to round displayed values to. Unset rounds to at most 3 decimals (4 significant digits under 1).',\n thresholds: 'Severity bands over the value. Each entry starts a band at its value that runs to the next entry; below the first, and in a normal band, the widget keeps its own colour.',\n 'thresholds.value': 'The value at which this band starts.',\n 'thresholds.level': 'The severity of this band. The theme decides the colour; normal has none.',\n 'thresholds.label': 'Text shown on the chart line for this threshold. Defaults to its value.',\n staleAfterSeconds: 'Seconds after which the newest sample is called stale: the value is greyed out and badged. Unset shows the sample age only and never marks the widget stale.',\n windowSeconds: 'Seconds of history the widget covers, back from now. Leave unset to follow the board\u2019s time range; set it to pin this widget to a fixed span that the viewer\u2019s range picker does not change. 60 to 604800.',\n measurement: 'Which measurement to display. Defaults to the first the datasource selects.',\n flashOnChange: 'Briefly tint a value green on a rise and red on a fall when it changes.',\n window: \"Samples retained across ALL of the widget's measurements before the oldest are dropped. Bounds memory; only the chart draws them. Default 300.\",\n min: 'Value at the empty end of the scale. Required: the widget does not guess a range.',\n max: 'Value at the full end of the scale. Required, and above min.',\n text: 'The text to show. Rendered as plain text \u2014 markup is never interpreted.',\n align: 'Horizontal alignment of the text. Default center.',\n fontSize: 'Text size in pixels at the comfortable density; it scales with the board density. Default 16.',\n url: 'Source URL of the image.',\n alt: 'Alternative text describing the image for assistive technology.',\n fit: 'How the image fills its box. Default contain.',\n state: 'Show only alarms in this state. Unset shows every state.',\n severity: 'Show only alarms at this severity. Unset shows every severity.',\n acknowledged: \"Show only acknowledged ('true') or unacknowledged ('false') alarms. Unset shows both.\",\n groupBy: 'deviceType: a tab per device type.',\n deviceType: 'Only alarms on devices of this type (token).',\n deviceTypes: 'Types to tab, in order; unset tabs all.',\n 'deviceTypes.token': 'Type token.',\n maxRows: 'Alarms loaded into the table. Default 50.',\n selectionTarget: 'Name of the slot this widget re-points when the viewer picks an entity.',\n commandName: 'Command key issued to the target device. Without it the control cannot send.',\n commandLabel: 'Name of the control for assistive technology. Defaults to the command key.',\n parameterSchema: \"The command's parameter descriptors, baked in as JSON at author time. Gives the control its range and its refusals.\",\n tileUrl: \"Raster tile URL template, e.g. https://tiles.example.com/{z}/{x}/{y}.png. Leave empty to inherit the tenant's basemap; setting one overrides it for this board only.\",\n attribution: 'Credit line the tile source requires, shown on the map. Set whatever the provider you chose asks for.',\n style: 'A plain bar (default) or a thermometer: a vertical tube with a bulb. A thermometer is always vertical.',\n markAlarms: 'Mark this device\u2019s alarms on the chart, from raise to clear.',\n markAlarmsScope: 'Which alarms to mark: only those about what this chart plots (series, the default for a new chart), or every alarm on the device. An alarm with no known measurement is never marked in series mode; it is listed under the chart as another alarm on the device. A chart saved before this option marks the whole device.',\n markCommands: 'Mark the commands sent to this device on the chart.',\n orientation: 'Direction of a bar: horizontal (default) or vertical. Ignored by a thermometer.',\n readout: 'What the readout shows: the value with its unit (default) or the percent of the scale.',\n onAt: 'For an on/off signal: the lamp is lit at or above this value and dark below it. Unset keeps the lamp lit while a value is present, coloured by its threshold band.',\n parameter: 'Which parameter of the command this control sets. May be left blank when the command has exactly one parameter of the right type.',\n step: 'Distance between values. Defaults to 1 for a whole-number parameter, else a hundredth of the range.',\n mode: 'Slider (default) or stepper: \u2212 / + and Send.',\n stat: 'Which figure to show. Default average.',\n sparkline: 'Draw the measurement\u2019s trend over the span under the figure. Default off.',\n sort: 'Order of the categories. Default: as the data source lists them.',\n columns: 'Heading, unit and precision per measurement column; a column with none shows its name.',\n 'columns.measurement': 'The measurement column this entry applies to.',\n 'columns.label': 'Column heading. Defaults to the measurement name.',\n 'columns.unit': 'Unit suffix shown beside the value.',\n 'columns.precision': 'Decimal places to round displayed values to. Unset rounds to at most 3 decimals (4 significant digits under 1).',\n 'thresholds.measurement': 'The measurement column this entry applies to.',\n ageLagSeconds: \"Show a reading's age under it only when the reading is at least this many seconds older than the newest reading in the table (or stale). Unset shows every reading's age.\",\n sortBy: 'The measurement the table is ordered by. Blank orders by device name.',\n sortDescending: 'Largest first.',\n oldestFirst: 'List the oldest bucket first. Unset lists the newest first.',\n pageSize: 'Devices per page. Default 20.',\n maxSeries: 'Most lines drawn when the chart shows one line per device. Default 5, at most 12. Each line costs one stored-history read, and the chart colours repeat after five; a group larger than this shows the first devices of the group and says how many it left out.',\n show: 'What to count: devices in an abnormal band of the measurement (default), or all devices.',\n};\n\nexport const OPTION_DOC_OVERRIDES: Readonly<Record<string, Readonly<Record<string, string>>>> = {\n 'latest-card': {\n title: 'Heading shown in the widget frame. Defaults to the displayed measurement name.',\n },\n gauge: {\n title: 'Heading shown in the widget frame. Defaults to the displayed measurement name.',\n min: 'Low end of the gauge scale. Default 0.',\n max: 'High end of the gauge scale. Default 100.',\n },\n 'linear-gauge': {\n title: 'Heading shown in the widget frame. Defaults to the displayed measurement name.',\n },\n 'level-gauge': {\n title: 'Heading shown in the widget frame. Defaults to the displayed measurement name.',\n },\n battery: {\n title: 'Heading shown in the widget frame. Defaults to the displayed measurement name.',\n min: 'Value of an empty battery. Default 0 (the scale is percent unless you set min and max).',\n max: 'Value of a full battery. Default 100 (the scale is percent unless you set min and max).',\n },\n 'status-light': {\n title: 'Heading shown in the widget frame. Defaults to the displayed measurement name.',\n },\n 'signal-bars': {\n title: 'Heading shown in the widget frame. Defaults to the displayed measurement name.',\n thresholds: 'The steps of the signal, lowest first: one bar per entry, lit once the value reaches it and coloured by its level. At least two, at most eight.',\n },\n compass: {\n title: 'Heading shown in the widget frame. Defaults to the displayed measurement name.',\n precision: 'Decimal places of the heading. Default 0 (whole degrees). The heading is rounded first, then folded onto 0 to 360, so it never reads 360.',\n thresholds: 'Severity bands over the heading in degrees (0 to 360, after folding). Each entry starts a band at its value that runs to the next entry; below the first, and in a normal band, the needle keeps its own colour.',\n },\n 'progress-ring': {\n title: 'Heading shown in the widget frame. Defaults to the displayed measurement name.',\n readout: 'What the middle of the ring shows: the percent of the scale (default) or the value with its unit.',\n },\n 'stat-card': {\n title: 'Heading shown in the widget frame. Defaults to the displayed measurement name.',\n },\n 'device-status': {\n staleAfterSeconds: 'Marks the card stale once its status has not been read for longer than this many seconds (it is re-read every 15 seconds, so only reads that keep failing make it stale). A device that is merely silent is not stale: whether it is online is the status itself. Unset, the age is shown and nothing is marked stale.',\n },\n 'online-doughnut': {\n staleAfterSeconds: 'Marks the ring stale once the status of its devices has not been read for longer than this many seconds (it is re-read every 15 seconds, so only reads that keep failing make it stale). Unset, the age is shown and nothing is marked stale.',\n },\n 'history-table': {\n columns: 'Which measurements are columns, in order, with a heading, unit and precision each. With none, the columns are the datasource\u2019s measurements (or, when it names none, every measurement the device reported in the range). Every figure is the average of the readings in a time bucket.',\n precision: 'Decimal places to round displayed averages to, for a column that sets none. Unset rounds to at most 3 decimals (4 significant digits under 1). The CSV export is rounded the same way.',\n pageSize: 'Rows per page. Default 10. The CSV export holds every row, not just the page.',\n staleAfterSeconds: 'Marks the table stale once its history has not been read for longer than this many seconds (it is re-read at the end of each time bucket, so only reads that keep failing make it stale). Unset, the age is shown and nothing is marked stale.',\n },\n 'fleet-count': {\n measurement: 'The measurement whose bands flag a device. Defaults to the first the datasource selects.',\n },\n 'command-slider': {\n min: \"Lowest value, used only when the command's parameter declares no minimum.\",\n max: \"Highest value, used only when the command's parameter declares no maximum.\",\n },\n 'timeseries-chart': {\n min: 'Low end of the value axis. Unset, the axis starts where the chart picks. A reading or threshold below it still shows: the axis widens to take it in.',\n max: 'High end of the value axis, above min. Unset, the chart picks. A reading or threshold above it still shows: the axis widens to take it in.',\n groupBy: 'One line per measurement of one device (the default), or one line per device of a group for the measurement set below. Per device, stored history is drawn as the average of each time bucket (the chart says so), and thresholds are reference lines over it.',\n measurement: 'The measurement compared across the group. Defaults to the first the datasource selects. Used only with one line per device.',\n markAlarms: 'Mark this device\u2019s alarms on the chart, from raise to clear. Not drawn with one line per device.',\n markCommands: 'Mark the commands sent to this device on the chart. Not drawn with one line per device.',\n },\n 'bar-chart': {\n groupBy: 'One bar per measurement (the default), or per device of the group for the measurement set below.',\n },\n 'command-button': {\n maxRows: 'Recent commands shown in the history. Default 20.',\n commandName: 'Command key issued to the target device. Without it the widget cannot send.',\n commandLabel: 'Text on the send button. Defaults to the command key.',\n parameterSchema: \"The command's parameter descriptors, baked in as JSON at author time. Drives the typed form.\",\n },\n};\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// preloadWidgets fetches the lazily loaded code of the given widget types, so a host that awaits\n// it before rendering a board draws every widget on the first frame instead of an empty box\n// while a chunk is in flight. A host that never calls it loses nothing: each widget still loads\n// its own chunk on first mount.\n//\n// A type with no lazy code (an eager built-in, an extension, an unknown id) is skipped. A chunk\n// that fails to load does not reject this: a failed load is not remembered, so the widget fetches\n// its chunk again on mount, and if that fails too the error is thrown to its error boundary, which\n// is where the failure belongs.\n\nimport type { WidgetRegistry } from '@devicechain/widget-sdk';\n\nexport async function preloadWidgets(registry: WidgetRegistry, types: Iterable<string>): Promise<void> {\n const loads: Promise<unknown>[] = [];\n for (const type of new Set(types)) {\n const preload = (registry.implementation(type)?.component as { preload?: unknown } | undefined)?.preload;\n if (typeof preload === 'function') loads.push((preload as () => Promise<unknown>)().catch(() => undefined));\n }\n await Promise.all(loads);\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The by-id views of the built-in registrations that older consumers still import.\n//\n// \uD83D\uDD34 READ-ONLY PROJECTIONS, NOT A REGISTRY. A widget's channel and whether it binds a\n// datasource are declared once, on its descriptor (builtin-descriptors.ts), and the\n// renderer resolves everything through a registry instance (createWidgetRegistry) -- never\n// through these. They exist so code that wants to ask \"which channel is this built-in on?\"\n// without building a registry (the console's config panel, fixtures) keeps working. They are\n// frozen, computed from the descriptors at module load, and there is no way to add an\n// entry: an extension widget registers through createWidgetRegistry, not here.\n\nimport type { BuiltinWidgetId, WidgetChannel } from '@devicechain/dashboards';\n\nimport { builtinWidgetDescriptors } from './builtin-descriptors';\n\n// WidgetChannel itself is declared once, in @devicechain/dashboards; re-exported so this\n// module's importers are unchanged.\nexport type { WidgetChannel };\n\ntype Descriptors = typeof builtinWidgetDescriptors;\n\nconst entries = Object.entries(builtinWidgetDescriptors) as Array<[BuiltinWidgetId, Descriptors[BuiltinWidgetId]]>;\n\n// A built-in's data channel, as its descriptor declares it.\nexport const WIDGET_CHANNEL: { readonly [K in BuiltinWidgetId]: Descriptors[K]['channel'] } = Object.freeze(\n Object.fromEntries(entries.map(([id, d]) => [id, d.channel])),\n) as { readonly [K in BuiltinWidgetId]: Descriptors[K]['channel'] };\n\n// Whether a built-in binds a DATASOURCE -- the entity whose data it reads. Derived from the\n// descriptor's datasource mode: `none` binds nothing (label, image, the entity selector).\nexport const WIDGET_BINDS_DATASOURCE: { readonly [K in BuiltinWidgetId]: boolean } = Object.freeze(\n Object.fromEntries(entries.map(([id, d]) => [id, d.datasource.mode !== 'none'])),\n) as { readonly [K in BuiltinWidgetId]: boolean };\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// @devicechain/widgets \u2014 presentational dashboard widgets (ADR-039).\n//\n// Eleven built-ins over the DashboardHub's live data, themed via CSS custom\n// properties (no Tailwind leakage \u2014 embeddable in any React host). Each is a\n// registration declared with the public `defineWidget` from @devicechain/widget-sdk;\n// a renderer resolves a widget through a registry instance.\n\n// The view-only dashboard renderer: lays a parsed definition's widgets on the\n// canvas and binds each to the hub. The shared viewer for the console + external apps.\nexport { DashboardRenderer, resolveWidgets, widgetSubjectLabel, type DashboardRendererProps } from './dashboard-renderer';\nexport {\n AbsoluteIndicator,\n DEFAULT_ABSOLUTE_LABELS,\n DEFAULT_TIME_RANGE_LABELS,\n PausedIndicator,\n TimeRangeBar,\n absoluteLinkFor,\n formatAbsoluteRange,\n rejectedLinkNote,\n useBoardTimeRange,\n type AbsoluteLabels,\n type TimeRangeControls,\n type TimeRangeLabels,\n} from './time-range-bar';\n\n// Deep links that open a board with a device bound: the hook that keeps the address and the\n// selection in step (and checks the named devices against the caller's scope), and the notice a\n// host shows instead of the board when a link cannot be honoured.\nexport {\n useBoundDevices,\n type BoundDevices,\n type BoundDevicesAddress,\n type BoundDevicesPhase,\n type LinkProblems,\n} from './use-bound-devices';\nexport {\n BoundDevicesNotice,\n describeBoundDevicesProblems,\n type BoundDevicesNoticeProps,\n type BoundDevicesWording,\n} from './bound-devices-notice';\n\n// Renderer entry point: binds the hub to a widget by type.\nexport { ConnectedWidget, type ConnectedWidgetProps } from './connected-widget';\n\n// The built-ins as registrations (the same descriptor + component pairing a third-party\n// package supplies), and the factory for a sealed registry holding exactly them.\n//\n// Every one of these carries each option's `doc`. `builtinWidgetDefinitionsWithoutDocs` is the same\n// registrations without it -- for a host that only renders boards and never shows an option's help,\n// which then does not download the prose (a built-in id is the one place the registry excuses a\n// missing doc). Its descriptors are TYPED as documented; their `doc` is absent at runtime.\nexport {\n builtinWidgetCatalog,\n builtinWidgetDescriptors,\n builtinWidgetDefinitions,\n createBuiltinWidgetRegistry,\n WIDGET_OPTIONS,\n} from './documented-descriptors';\nexport { builtinWidgetDefinitions as builtinWidgetDefinitionsWithoutDocs } from './builtin-registry';\nexport { preloadWidgets } from './preload';\n\n// Read-only by-id views of the built-in descriptors (channel, datasource binding), and the\n// widget contract. The registrations above are the source of truth; these are derived.\nexport { WIDGET_CHANNEL, WIDGET_BINDS_DATASOURCE, type WidgetChannel } from './registry';\nexport { pickSample, optBoolean, type WidgetProps, type WidgetComponent } from '@devicechain/widget-sdk';\n\n// The tenant basemap seam. A host installs the provider; map widgets read it.\nexport { TenantBasemapProvider, useTenantBasemap } from './basemap-context';\n\n// The map RUNTIME seam \u2014 the MapLibre pieces only the host's bundler can emit.\n//\n// \uD83D\uDD34 Unlike the basemap provider above, this one is REQUIRED by any host that renders a\n// map widget: without it the widget shows a notice instead of a map. That is deliberate.\n// The alternative to a host-supplied worker URL is MapLibre's own runtime derivation,\n// which no bundler can follow, and which fails as a map that renders nothing at all.\nexport { MapRuntimeProvider, useMapRuntime, type MapRuntime } from './map-runtime-context';\n\n// The typed schema for each widget's options bag: what the renderer reads, at what type,\n// with what legal values. WidgetOptions<T> types code that BUILDS options;\n// validateWidgetOptions reports where a stored bag disagrees with the renderer.\nexport {\n validateWidgetOptions,\n numberOptionSpec,\n clampNumberOption,\n enumOptionValues,\n type WidgetOptions,\n type WidgetOptionSpecs,\n type OptionSpec,\n type StringOptionSpec,\n type NumberOptionSpec,\n type BooleanOptionSpec,\n type EnumOptionSpec,\n type ListItemFieldSpec,\n type ListOptionSpec,\n type OptionIssue,\n type OptionIssueCode,\n} from './options';\n\n// The same schemas applied to a whole board: what a producer of definitions asks\n// before it publishes one, plus the repair for the one issue an author cannot fix in\n// a config panel.\nexport {\n validateDefinitionOptions,\n stripUnknownOptions,\n type DefinitionOptionIssue,\n type DefinitionValidationOptions,\n} from './definition-options';\n\n// Individual widgets (for direct/custom use).\nexport { LatestCard } from './widgets/latest-card';\nexport { Gauge } from './widgets/gauge';\nexport { TimeSeriesChart } from './widgets/time-series-chart';\nexport { Table } from './widgets/table';\nexport { Label } from './widgets/label';\nexport { Image } from './widgets/image';\nexport { AlarmTable } from './widgets/alarm-table';\nexport { AlarmCount } from './widgets/alarm-count';\nexport { AlarmSeverity } from './widgets/alarm-severity';\nexport { CommandButton } from './widgets/command-button';\nexport { EntitySelector } from './widgets/entity-selector';\nexport { MapWidget } from './widgets/map';\n// The map's pure parts: which samples can be placed, where they land on a tile-less\n// panel, and how a fix is described without inventing the fields it does not carry.\n//\n// loadLandStyle is the bundled world basemap \u2014 the style used when no tile source\n// is configured. Exported so the console's fence editor and this package's map\n// widget cannot end up drawing two different worlds; the geometry itself stays\n// behind a dynamic import inside that module, so naming it here costs nothing.\nexport {\n placeable,\n projectToPanel,\n describePosition,\n formatDegrees,\n rasterStyleFor,\n landStyleFrom,\n loadLandStyle,\n BUNDLED_BASEMAP_ATTRIBUTION,\n type PlaceableLocation,\n type PanelPoint,\n} from './widgets/map-geometry';\nexport {\n severityColor,\n severityLabel,\n severityRank,\n highestSeverity,\n} from './widgets/severity';\nexport { commandStatusColor, commandStatusLabel, isTerminalStatus } from './widgets/command-status';\nexport {\n parseParameterSchema,\n defaultValues,\n validateParams,\n buildPayload,\n isScalar,\n} from './widgets/command-params';\n\n// Building blocks for custom widgets. They live in @devicechain/widget-sdk (the one place the\n// ambient host contexts may be defined) and are re-exported so existing imports keep resolving;\n// the chart helpers come from its `/echarts` subpath.\nexport {\n WidgetFrame,\n WidgetSubjectProvider,\n WidgetSelectProvider,\n useWidgetSelect,\n WidgetTimeZoneProvider,\n useWidgetTimeZone,\n WidgetThemeRootProvider,\n useWidgetThemeRoot,\n WidgetCandidatesProvider,\n useWidgetCandidates,\n useFlashOnChange,\n flashTextStyle,\n flashBackgroundStyle,\n FlashValue,\n fitValueFont,\n useMeasurementStream,\n useAlarmStream,\n useCommandStream,\n useLocationStream,\n useDatasourceAvailability,\n useDashboardHub,\n useHubConnectionState,\n HubConnectionBadge,\n useResolvedBindings,\n useSlotCandidates,\n useCandidates,\n css,\n type FlashDirection,\n type WidgetFrameProps,\n type WidgetSelect,\n type WidgetCandidates,\n type MeasurementStreamState,\n type AlarmStreamState,\n type CommandStreamState,\n type LocationStreamState,\n type CandidatesState,\n type DatasourceAvailability,\n type HubConnectionBadgeProps,\n type ThemeVar,\n} from '@devicechain/widget-sdk';\nexport {\n EChart,\n buildLineOption,\n buildGaugeOption,\n resolveChartTheme,\n useChartTheme,\n type EChartOption,\n type LineChartOptions,\n type GaugeChartOptions,\n type ChartTheme,\n} from '@devicechain/widget-sdk/echarts';\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// WIDGET_OPTIONS \u2014 the typed schema for each widget type's `options` bag, as a by-id view.\n//\n// A WidgetInstance's `options` is `Record<string, unknown>` in the stored definition:\n// dashboard-management keeps a definition as opaque JSON, and the definition parser does\n// not look inside `options` at all. Each built-in's descriptor (builtin-descriptors.ts)\n// declares every option the RENDERER actually reads, with its type and legal values; this\n// module projects those schemas by id and wraps the shared engine under the by-type names\n// the console and fixtures use:\n// \u2022 validateWidgetOptions() \u2014 the runtime check, for anything that PRODUCES a definition\n// (a generated dashboard must not ship an options blob the renderer ignores).\n// \u2022 WidgetOptions<T> \u2014 the compile-time shape, for code that builds options.\n//\n// The schema describes the RENDERER, because that is the contract deciding what a viewer\n// actually sees. Where the console's authoring UI offers fewer keys than this \u2014 it does:\n// `align`, `fontSize`, `fit`, `window` and `measurement` are all honored by the renderer\n// and not authorable in the config panel \u2014 the gap is in the panel, not here.\n//\n// The spec VOCABULARY and the engine that checks a bag against a schema live in\n// @devicechain/dashboards (option-schema.ts) \u2014 they know no widget type, so the SDK's\n// registry validates an extension's schema with the very code that validates this one.\n\nimport {\n clampNumberOption,\n enumValues,\n numberSpec,\n validateOptions,\n type NumberOptionSpec,\n type OptionConstraint,\n type OptionIssueCode,\n type BuiltinWidgetId,\n type OptionsOf,\n type WidgetOptionSpecs,\n type WidgetType,\n} from '@devicechain/dashboards';\n\nimport { builtinWidgetCatalog, builtinWidgetDescriptors } from './builtin-descriptors';\n\nexport type {\n BooleanOptionSpec,\n EnumOptionSpec,\n ListItemFieldSpec,\n ListOptionSpec,\n NumberOptionSpec,\n OptionIssueCode,\n OptionSpec,\n StringOptionSpec,\n WidgetOptionSpecs,\n} from '@devicechain/dashboards';\nexport { clampNumberOption };\n\n// ---- The derived by-id view -------------------------------------------------\n\n// Every built-in's option schema, keyed by id. A frozen PROJECTION of the descriptors in\n// builtin-descriptors.ts (each schema is declared there, once, beside the widget's channel and\n// binding policy); it holds no schema of its own, so it cannot drift from what the registry\n// validates. The cross-field rules (gauge's max > min) travel on the descriptor as data.\ntype OptionsById = { readonly [K in BuiltinWidgetId]: (typeof builtinWidgetDescriptors)[K]['options'] };\n\nexport const WIDGET_OPTIONS: OptionsById = Object.freeze(\n Object.fromEntries(Object.entries(builtinWidgetDescriptors).map(([id, d]) => [id, d.options])),\n) as OptionsById;\n\nfunction constraintsFor(widgetType: WidgetType): readonly OptionConstraint[] {\n return builtinWidgetCatalog.get(widgetType)?.constraints ?? [];\n}\n\n// ---- Derived compile-time types ---------------------------------------------\n\n// WidgetOptions<'gauge'> is the typed options bag for a gauge: every declared key at its\n// declared type, required ones mandatory. Code that BUILDS a definition should type its\n// options with this \u2014 a typo is then a compile error rather than a key nothing reads.\n//\n// DISTRIBUTIVE over T, which is the whole reason it is written as a conditional. `keyof` a\n// union of the built-in tables is their INTERSECTION \u2014 only `title` \u2014 and the required-keys\n// computation over that union collapses to never, so the undistributed form silently\n// degenerates for any generic T: it would reject `{ text: 'body' }` as an excess property\n// while accepting `{}` for a widget that requires an option. That is exactly the position a\n// generator writing one widget of each type sits in. Distributing makes\n// WidgetOptions<WidgetType> the union of the per-type bags instead.\nexport type WidgetOptions<T extends WidgetType> = T extends WidgetType ? OptionsOf<(typeof WIDGET_OPTIONS)[T]> : never;\n\n// ---- Runtime validation -----------------------------------------------------\n\n// The by-type issue shape the console reads. `widgetType` keeps its name so existing\n// consumers compile unchanged; the engine's own issue calls the same value `widgetId`.\nexport interface OptionIssue {\n widgetType: WidgetType;\n // The offending option key. For a cross-field rule, the key the fix belongs on.\n key: string;\n code: OptionIssueCode;\n message: string;\n}\n\n// validateWidgetOptions reports every way a widget's stored options bag disagrees with\n// what the renderer reads. An empty result means every key present is one the renderer\n// honors, at a value it accepts, and no required option is missing.\n//\n// It is deliberately a REPORT rather than a throw: the renderer is tolerant by design and\n// must stay that way for a hand-edited definition, so the strictness belongs to whoever\n// produces definitions (fixtures, generators, the config panel) and to the tests that\n// gate them. Callers decide which codes are fatal \u2014 a stored dashboard carrying an\n// 'unknown' leftover is untidy; a generated one carrying 'missing' is broken.\nexport function validateWidgetOptions(\n widgetType: WidgetType,\n options: Record<string, unknown> | undefined,\n): OptionIssue[] {\n const specs: WidgetOptionSpecs = WIDGET_OPTIONS[widgetType];\n return validateOptions(specs, options, { constraints: constraintsFor(widgetType), label: widgetType }).map(\n ({ key, code, message }) => ({ widgetType, key, code, message }),\n );\n}\n\n// numberOptionSpec returns the declared bounds for a numeric option, so an authoring\n// UI can constrain its input from the schema rather than from a second, hand-written\n// copy of the same numbers. See numberSpec for why it exists.\nexport function numberOptionSpec(type: WidgetType, key: string): NumberOptionSpec | undefined {\n return numberSpec(WIDGET_OPTIONS[type], key);\n}\n\n// enumOptionValues returns the legal values of an enum option, so an authoring UI can\n// build its dropdown from the schema instead of a private copy of the same list.\nexport function enumOptionValues(type: WidgetType, key: string): readonly string[] | undefined {\n return enumValues(WIDGET_OPTIONS[type], key);\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The definition-level layer over validateWidgetOptions: \"is every widget on this\n// board configured with options the renderer actually reads?\"\n//\n// WHY IT IS A SEPARATE FUNCTION RATHER THAN A LOOP AT EACH CALL SITE. Every consumer\n// wants the same three things \u2014 walk the widgets, keep the issues, and know WHICH\n// widget each belongs to \u2014 and the third is the one a hand-rolled loop forgets. An\n// issue reported without its widget id tells an author that `commandName` is missing\n// on a board with three command buttons, which is a report they cannot act on.\n//\n// \uD83D\uDD11 THE OPTION SCHEMAS ARE TYPESCRIPT, AND THAT DECIDES WHERE THE GATE CAN LIVE.\n// dashboard-management stores a definition as opaque JSON and checks only that it is\n// a JSON object; it is Go, so it cannot run these schemas, and a Go copy of them\n// would be a THIRD representation of the same table (the reason ADR-076 declined a\n// cross-language widget manifest). So the strictness belongs to whoever PRODUCES a\n// definition, and \uD83D\uDD34 EACH PRODUCER HAS TO WIRE IT FOR ITSELF \u2014 there is no chokepoint\n// downstream that would catch a producer nobody thought about:\n//\n// \u2022 the console, by its publish action (apps/console/src/lib/api/dashboards.ts);\n// \u2022 the sim, by the golden-fixture gate over frontend/testdata/sim-dashboards, which\n// covers every dashboard of every REGISTERED scenario. It was widgetlab-only when\n// this function was written, and the sentence here claimed otherwise \u2014 buildingpulse,\n// the demo board, was gated by nothing. Two reviewers found the same overclaim\n// independently. The gate walks sim.Registry now, so the claim is true by\n// construction rather than by a list someone has to remember to extend.\n//\n// Anything ELSE writing a definition \u2014 raw GraphQL, a future importer \u2014 is unchecked,\n// because dashboard-management deliberately validates nothing. This is not the\n// server-side, ADR-044-style publish gate it superficially resembles, and calling it one\n// would misdescribe exactly which documents are protected.\n\nimport {\n UNKNOWN_WIDGET_TYPE,\n validateOptions,\n type DashboardDefinition,\n type WidgetCatalog,\n type WidgetDescriptor,\n type WidgetInstance,\n} from '@devicechain/dashboards';\n\nimport { builtinWidgetCatalog } from './builtin-descriptors';\nimport type { OptionIssue } from './options';\n\n// A DefinitionOptionIssue is an OptionIssue plus the widget that carries it.\n//\n// It deliberately carries the ID and nothing friendlier. An earlier version also read\n// `options.title` so a consumer could label the issue \u2014 and that one read, purely for\n// presentation, put this file into the option-read scan in options.test.ts, where every\n// other entry is evidence that a RENDERER reads a key. It needed a paragraph explaining\n// why it did not mean what its neighbours meant. A consumer that wants a title already\n// holds the definition and can join on the id; the scan goes back to meaning one thing.\nexport interface DefinitionOptionIssue extends Omit<OptionIssue, 'widgetType'> {\n // The stored widget id: a built-in type, or an extension's namespaced id.\n widgetType: string;\n widgetId: string;\n}\n\n// A definition as this module reads it: only the widget list matters, so the fixture\n// tests and the console's in-flight editor state both satisfy it without either having\n// to be a fully parsed DashboardDefinition.\ntype WidgetCarrier = Pick<DashboardDefinition, 'widgets'>;\n\n// validateDefinitionOptions reports every option issue on the board, in widget order.\n// An empty result means every widget's bag is one the renderer honors in full.\n//\n// A placeholder for a widget type this build does not know reports nothing: it carries\n// no options of its own (its stored object is kept verbatim, options and all), and this\n// build has no schema to judge a newer widget's options against.\n//\n// `options.catalog` is the host's widget catalog (registry.catalog): an extension widget is\n// judged against ITS registered schema. Omitted = the built-ins only, so a board carrying an\n// extension widget must be validated with the catalog it was parsed with.\nexport interface DefinitionValidationOptions {\n catalog?: WidgetCatalog;\n}\n\nexport function validateDefinitionOptions(\n definition: WidgetCarrier,\n options: DefinitionValidationOptions = {},\n): DefinitionOptionIssue[] {\n return definition.widgets.flatMap((widget) => {\n if (widget.type === UNKNOWN_WIDGET_TYPE) return [];\n const type = widget.type;\n const descriptor = descriptorFor(type, options.catalog);\n return validateOptions(descriptor.options, widget.options, {\n constraints: descriptor.constraints,\n label: type,\n }).map(({ key, code, message }) => ({ widgetType: type, key, code, message, widgetId: widget.id }));\n });\n}\n\n// The schema a recognized widget is judged against comes from the built-in CATALOG \u2014 the\n// same descriptors a registry holds \u2014 rather than from a by-type table, so this gate is the\n// live consumer of the registry's data. Every built-in type is in the catalog by\n// construction (builtin-registry.test.ts), so a miss is a defect to surface, not a widget\n// to skip.\n//\n// A catalog the host supplies is consulted first (an extension lives only there); a built-in\n// the supplied catalog omits falls back to the built-in descriptor, since its schema is the\n// same everywhere. An id neither holds is a defect \u2014 the board was parsed against a catalog\n// other than the one it is validated with \u2014 so it throws rather than skipping the widget.\nfunction descriptorFor(type: string, catalog: WidgetCatalog | undefined): WidgetDescriptor {\n const descriptor = catalog?.get(type) ?? builtinWidgetCatalog.get(type);\n if (!descriptor) {\n throw new Error(`no widget descriptor for \"${type}\"; validate with the catalog the definition was parsed with`);\n }\n return descriptor;\n}\n\n// stripUnknownOptions removes every option key no widget of that type reads, leaving\n// everything else untouched.\n//\n// \uD83D\uDD34 IT EXISTS BECAUSE 'unknown' IS THE ONE ISSUE CODE AN AUTHOR CANNOT FIX IN THE UI.\n// This is the canonical statement of that reasoning; the call sites point here.\n// Every other code sits on a DECLARED key, so the config panel renders a control for it\n// and the author edits or clears it. An unknown key is by definition one the panel has\n// no control for \u2014 and the panel preserves the bag it did not write (it spreads\n// `widget.options` on every edit), so the key survives every subsequent change. Without\n// this, a publish gate that treats 'unknown' as fatal is a dead end: a dashboard that\n// acquired a leftover key \u2014 from a version predating an option rename, or from a\n// producer other than the console \u2014 could never be published again through the UI.\n//\n// Returns the SAME object when there is nothing to strip, so a caller can detect a\n// no-op with `next === before`.\n//\n// \uD83D\uDD34 THE OBVIOUS REASON TO WANT THIS IS NOT THE REAL ONE, and the first version of this\n// comment gave the wrong one: it claimed a fresh-but-equal object would read as an\n// unsaved edit. It would not \u2014 the console's isDirty compares SERIALIZATIONS\n// (dashboards/src/definition.ts), so an equal-but-new object is not dirty. What the\n// identity actually buys is smaller and still worth having: the caller can tell \"there\n// was nothing to remove\" from \"I removed something\" without diffing, and it avoids a\n// state write that would re-render the editor for no change.\nexport function stripUnknownOptions<T extends WidgetCarrier>(definition: T, options: DefinitionValidationOptions = {}): T {\n let changed = false;\n const widgets = definition.widgets.map((widget) => {\n const stripped = stripUnknownWidgetOptions(widget, options.catalog);\n if (stripped !== widget) changed = true;\n return stripped;\n });\n return changed ? { ...definition, widgets } : definition;\n}\n\nfunction stripUnknownWidgetOptions(widget: WidgetInstance, catalog: WidgetCatalog | undefined): WidgetInstance {\n // A placeholder for an unknown widget type carries no options (they stay in its raw\n // object, which is never rewritten), so it returns here unchanged.\n const bag = widget.options;\n if (!bag) return widget;\n const specs = descriptorFor(widget.type, catalog).options;\n // hasOwnProperty.call, not `in` \u2014 see validateWidgetOptions: every specs table\n // inherits Object.prototype, so `in` would report '__proto__' and 'constructor' as\n // declared and leave exactly the keys a JSON.parse'd definition can smuggle in.\n const keys = Object.keys(bag);\n const kept = keys.filter((key) => Object.prototype.hasOwnProperty.call(specs, key));\n if (kept.length === keys.length) return widget;\n const options: Record<string, unknown> = {};\n for (const key of kept) options[key] = bag[key];\n return { ...widget, options };\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsBA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,uBAAAA;AAAA,OAgBK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,SAAS,UAAU,eAAAC,cAAa,aAAAC,YAAW,iBAAiB,WAAAC,UAAS,UAAAC,SAAQ,YAAAC,iBAAoE;;;AC7CjJ;AAAA,EACE;AAAA,OAOK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAAC;AAAA,EACA,sBAAAC;AAAA,OAGK;AACP,SAAS,wBAAwB;AACjC,SAAS,eAAAC,cAAa,aAAAC,YAAW,WAAAC,UAAS,YAAAC,iBAAoD;;;AC3B9F,SAAS,4BAAiD;;;ACL1D,SAAS,oBAA+C;;;ACSxD,SAAS,uBAAuB;AAChC;AAAA,EACE;AAAA,EACA;AAAA,OAMK;AAqBP,IAAM,0BAA0B;AAahC,IAAM,QAAQ;AAAA,EACZ,MAAM;AAAA,EACN,SAAS;AACX;AAGA,IAAM,uBAAuB;AAAA,EAC3B,MAAM;AAAA,EACN,SAAS;AACX;AAIA,IAAM,YAAY;AAAA,EAChB,MAAM;AAAA,EACN,SAAS;AAAA,EACT,KAAK;AAAA,EACL,KAAK;AAAA,EACL,SAAS;AAAA,EACT,QAAQ;AACV;AAQA,IAAM,aAAa;AAAA,EACjB,MAAM;AAAA,EACN,UAAU;AAAA,EACV,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,MAAM;AAAA,IACJ,OAAO;AAAA,MACL,MAAM;AAAA,MACN,UAAU;AAAA,MACV,SAAS;AAAA,IACX;AAAA,IACA,OAAO;AAAA,MACL,MAAM;AAAA,MACN,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,eAAe;AAAA,QACb,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,OAAO;AAAA,QACP,OAAO;AAAA,QACP,UAAU;AAAA,MACZ;AAAA,MACA,eAAe;AAAA,IACjB;AAAA,IACA,OAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,EACF;AACF;AAEA,IAAM,kBAAkB;AAAA,EACtB,MAAM;AAAA,EACN,SAAS;AAAA,EACT,QAAQ;AACV;AAeA,IAAM,SAAS;AAAA,EACb,MAAM;AAAA,EACN,SAAS;AAAA,EACT,KAAK;AAAA,EACL,SAAS;AAAA,EACT,QAAQ;AACV;AAKA,IAAM,sBAAsB;AAAA,EAC1B,MAAM;AAAA,EACN,SAAS;AAAA,EACT,KAAK;AAAA,EACL,SAAS;AAAA,EACT,QAAQ;AACV;AAEA,IAAM,OAAO;AAAA,EACX,MAAM;AAAA,EACN,SAAS;AACX;AAMA,IAAM,YAAY;AAAA,EAChB,MAAM;AAAA,EACN,UAAU;AAAA,EACV,SAAS;AAAA,EACT,QAAQ;AACV;AAEA,IAAM,YAAY;AAAA,EAChB,MAAM;AAAA,EACN,UAAU;AAAA,EACV,SAAS;AAAA,EACT,QAAQ;AACV;AAKA,IAAM,uBAAuB;AAAA,EAC3B,MAAM;AAAA,EACN,UAAU;AAAA,EACV,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,SAAS;AACX;AAEA,IAAM,wBAAwB;AAAA,EAC5B,MAAM;AAAA,EACN,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,SAAS;AACX;AAEA,IAAM,2BAA2B;AAAA,EAC/B,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,SAAS;AACX;AAEA,IAAM,oBAAoB;AAAA,EACxB,MAAM;AAAA,EACN,SAAS;AAAA,EACT,QAAQ;AACV;AAEA,IAAM,cAAc;AAAA,EAClB,MAAM;AAAA,EACN,SAAS;AAAA,EACT,QAAQ;AACV;AAEA,IAAM,cAAc;AAAA,EAClB,MAAM;AAAA,EACN,QAAQ,CAAC,UAAU,SAAS;AAAA,EAC5B,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,eAAe,EAAE,QAAQ,0BAA0B,SAAS,0BAA0B;AAAA,EACtF,eAAe;AACjB;AAEA,IAAM,iBAAiB;AAAA,EACrB,MAAM;AAAA,EACN,QAAQ,CAAC,YAAY,SAAS,SAAS,WAAW,eAAe;AAAA,EACjE,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,eAAe,EAAE,UAAU,+BAA+B,OAAO,4BAA4B,OAAO,4BAA4B,SAAS,8BAA8B,eAAe,mCAAmC;AAAA,EACzN,eAAe;AACjB;AAMA,IAAM,qBAAqB;AAAA,EACzB,MAAM;AAAA,EACN,QAAQ,CAAC,QAAQ,OAAO;AAAA,EACxB,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,eAAe,EAAE,MAAM,8BAA8B,OAAO,+BAA+B;AAAA,EAC3F,eAAe;AACjB;AAEA,IAAM,mBAAmB;AAAA,EACvB,MAAM;AAAA,EACN,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,SAAS;AACX;AAgBA,IAAM,UAAU;AAChB,IAAM,gBAAgB,CAAC,UAAU,UAAU,MAAM;AAKjD,IAAM,aAAa,CAAC,UAAU,MAAM;AACpC,IAAM,gBAAgB,EAAE,MAAM,OAAO;AAGrC,IAAM,gBAAgB;AAAA,EACpB,OAAO,EAAE,QAAQ,QAAQ;AAAA,EACzB,UAAU,EAAE,QAAQ,WAAW;AAAA,EAC/B,cAAc,EAAE,QAAQ,eAAe;AACzC;AAQA,IAAM,cAAc;AAAA,EAClB,MAAM;AAAA,EACN,SAAS;AAAA,EACT,QAAQ;AACV;AAKA,IAAM,oBAAoB;AAAA,EACxB,MAAM;AAAA,EACN,QAAQ,CAAC,UAAU,QAAQ;AAAA,EAC3B,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,eAAe,EAAE,QAAQ,+BAA+B,QAAQ,8BAA8B;AAAA,EAC9F,eAAe;AACjB;AAEA,IAAM,gBAAgB;AAAA,EACpB,MAAM;AAAA,EACN,SAAS;AAAA,EACT,QAAQ;AACV;AAMA,IAAM,iBAAiB;AAAA,EACrB,MAAM;AAAA,EACN,SAAS;AAAA,EACT,QAAQ;AACV;AAEA,IAAM,iBAAiB;AAAA,EACrB,MAAM;AAAA,EACN,SAAS;AAAA,EACT,QAAQ;AACV;AAMA,IAAM,aAAa;AAAA,EACjB,MAAM;AAAA,EACN,SAAS;AAAA,EACT,KAAK;AAAA,EACL,SAAS;AAAA,EACT,QAAQ;AACV;AAEA,IAAM,iBAAiB;AAAA,EACrB,MAAM;AAAA,EACN,SAAS;AAAA,EACT,KAAK;AAAA,EACL,KAAK;AAAA,EACL,SAAS;AAAA,EACT,QAAQ;AACV;AAIA,IAAM,gBAAgB;AAAA,EACpB,MAAM;AAAA,EACN,QAAQ,CAAC,QAAQ,aAAa,YAAY;AAAA,EAC1C,SAAS;AAAA,EACT,eAAe,EAAE,MAAM,kBAAkB,WAAW,uBAAuB,YAAY,uBAAuB;AAAA,EAC9G,eAAe;AACjB;AAMA,IAAM,oBAAoB;AAAA,EACxB,MAAM;AAAA,EACN,UAAU;AAAA,EACV,SAAS;AACX;AAEA,IAAM,gBAAgB;AAAA,EACpB,MAAM;AAAA,EACN,UAAU;AAAA,EACV,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,OAAO,EAAE,MAAM,UAAU,SAAS,2BAA2B;AAAA,IAC7D,MAAM,EAAE,GAAG,KAAK;AAAA,IAChB,WAAW,EAAE,GAAG,UAAU;AAAA,EAC5B;AACF;AAEA,IAAM,mBAAmB;AAAA,EACvB,GAAG;AAAA,EACH,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,GAAG,WAAW;AAAA,EAChB;AACF;AAEO,IAAM,2BAA2B;AAAA,EACtC,oBAAoB,wBAAwB;AAAA,IAC1C,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS,EAAE,OAAO,oBAAoB,UAAU,aAAa,SAAS,6BAA6B,YAAY,0BAA0B;AAAA,IACzI,SAAS;AAAA;AAAA;AAAA,IAGT,YAAY,EAAE,MAAM,YAAY,WAAW,cAAc;AAAA,IACzD,SAAS,EAAE,eAAe,EAAE,QAAQ,gBAAgB,GAAG,SAAS,EAAE,QAAQ,WAAW,QAAQ,SAAS,EAAE;AAAA,IACxG,SAAS;AAAA,MACP,OAAO;AAAA,MACP,MAAM;AAAA,MACN,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,mBAAmB;AAAA,MACnB,eAAe;AAAA,MACf,SAAS;AAAA,QACP,MAAM;AAAA,QACN,QAAQ,CAAC,eAAe,QAAQ;AAAA,QAChC,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,eAAe,EAAE,aAAa,4BAA4B,QAAQ,sBAAsB;AAAA,QACxF,eAAe;AAAA,MACjB;AAAA,MACA,aAAa;AAAA,MACb,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,iBAAiB;AAAA,MACjB,cAAc;AAAA,MACd,KAAK;AAAA,MACL,KAAK;AAAA,IACP;AAAA,IACA,aAAa,CAAC,EAAE,MAAM,gBAAgB,KAAK,OAAO,MAAM,MAAM,CAAC;AAAA,IAC/D,UAAU,EAAE,OAAO,oBAAoB,iBAAiB,SAAS;AAAA,IACjE,cAAc,CAAC;AAAA,IACf,WAAW;AAAA,IACX,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE;AAAA,EAC7E,CAAC;AAAA,EAED,eAAe,wBAAwB;AAAA,IACrC,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS,EAAE,OAAO,eAAe,UAAU,aAAa,SAAS,wBAAwB,YAAY,0BAA0B;AAAA,IAC/H,SAAS;AAAA,IACT,YAAY,EAAE,MAAM,YAAY,WAAW,WAAW;AAAA,IACtD,SAAS,EAAE,QAAQ,EAAE,QAAQ,UAAU,KAAK,EAAE,EAAE;AAAA,IAChD,SAAS;AAAA,MACP,OAAO;AAAA,MACP,aAAa;AAAA,QACX,MAAM;AAAA,QACN,SAAS;AAAA,QACT,QAAQ;AAAA,MACV;AAAA,MACA,MAAM;AAAA,MACN,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,mBAAmB;AAAA,MACnB,QAAQ;AAAA,IACV;AAAA,IACA,UAAU,EAAE,OAAO,cAAc;AAAA,IACjC,cAAc,CAAC;AAAA,IACf,WAAW;AAAA,IACX,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE;AAAA,EAC5G,CAAC;AAAA,EAED,OAAO,wBAAwB;AAAA,IAC7B,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS,EAAE,OAAO,SAAS,UAAU,aAAa,SAAS,mBAAmB,YAAY,0BAA0B;AAAA,IACpH,SAAS;AAAA,IACT,YAAY,EAAE,MAAM,YAAY,WAAW,WAAW;AAAA,IACtD,SAAS,EAAE,QAAQ,EAAE,QAAQ,UAAU,KAAK,EAAE,EAAE;AAAA,IAChD,SAAS;AAAA,MACP,OAAO;AAAA,MACP,aAAa;AAAA,QACX,MAAM;AAAA,QACN,SAAS;AAAA,QACT,QAAQ;AAAA,MACV;AAAA,MACA,KAAK;AAAA,QACH,MAAM;AAAA,QACN,SAAS;AAAA,MACX;AAAA,MACA,KAAK;AAAA,QACH,MAAM;AAAA,QACN,SAAS;AAAA,MACX;AAAA,MACA,MAAM;AAAA,MACN,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,mBAAmB;AAAA,MACnB,QAAQ;AAAA,IACV;AAAA,IACA,aAAa,CAAC,EAAE,MAAM,gBAAgB,KAAK,OAAO,MAAM,MAAM,CAAC;AAAA,IAC/D,UAAU,EAAE,OAAO,QAAQ;AAAA,IAC3B,cAAc,CAAC;AAAA,IACf,WAAW;AAAA,IACX,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE;AAAA,EAC5G,CAAC;AAAA,EAED,OAAO,wBAAwB;AAAA,IAC7B,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS,EAAE,OAAO,SAAS,UAAU,aAAa,SAAS,mBAAmB,YAAY,0BAA0B;AAAA,IACpH,SAAS;AAAA,IACT,YAAY,EAAE,MAAM,YAAY,WAAW,WAAW;AAAA,IACtD,SAAS,EAAE,QAAQ,EAAE,QAAQ,UAAU,KAAK,EAAE,EAAE;AAAA,IAChD,SAAS;AAAA,MACP,OAAO;AAAA,MACP,WAAW;AAAA,MACX,eAAe;AAAA,MACf,mBAAmB;AAAA,MACnB,QAAQ;AAAA,IACV;AAAA,IACA,UAAU,EAAE,OAAO,QAAQ;AAAA,IAC3B,cAAc,CAAC;AAAA,IACf,WAAW;AAAA,IACX,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE;AAAA,EAC7E,CAAC;AAAA;AAAA;AAAA,EAID,OAAO,wBAAwB;AAAA,IAC7B,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS,EAAE,OAAO,SAAS,UAAU,UAAU,SAAS,mBAAmB,YAAY,uBAAuB;AAAA,IAC9G,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,SAAS,CAAC;AAAA,IACV,SAAS;AAAA,MACP,OAAO;AAAA,MACP,MAAM;AAAA,QACJ,MAAM;AAAA,QACN,UAAU;AAAA,QACV,SAAS;AAAA,MACX;AAAA,MACA,OAAO;AAAA,QACL,MAAM;AAAA,QACN,QAAQ,CAAC,QAAQ,UAAU,OAAO;AAAA,QAClC,SAAS;AAAA,QACT,eAAe,EAAE,MAAM,mBAAmB,QAAQ,qBAAqB,OAAO,mBAAmB;AAAA,QACjG,eAAe;AAAA,MACjB;AAAA,MACA,UAAU;AAAA,QACR,MAAM;AAAA,QACN,KAAK;AAAA,QACL,SAAS;AAAA,QACT,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,IACA,UAAU,EAAE,MAAM,YAAY;AAAA,IAC9B,cAAc,CAAC;AAAA,IACf,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,IAAI,MAAM,EAAE,EAAE;AAAA,EAC7G,CAAC;AAAA,EAED,OAAO,wBAAwB;AAAA,IAC7B,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS,EAAE,OAAO,SAAS,UAAU,UAAU,SAAS,mBAAmB,YAAY,uBAAuB;AAAA,IAC9G,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,SAAS,CAAC;AAAA,IACV,SAAS;AAAA,MACP,OAAO;AAAA,MACP,KAAK;AAAA,QACH,MAAM;AAAA,QACN,UAAU;AAAA,QACV,SAAS;AAAA,MACX;AAAA,MACA,KAAK;AAAA,QACH,MAAM;AAAA,QACN,SAAS;AAAA,MACX;AAAA,MACA,KAAK;AAAA,QACH,MAAM;AAAA,QACN,QAAQ,CAAC,WAAW,SAAS,MAAM;AAAA,QACnC,SAAS;AAAA,QACT,eAAe,EAAE,SAAS,oBAAoB,OAAO,kBAAkB,MAAM,gBAAgB;AAAA,QAC7F,eAAe;AAAA,MACjB;AAAA,IACF;AAAA,IACA,UAAU,EAAE,OAAO,QAAQ;AAAA,IAC3B,cAAc,CAAC;AAAA,IACf,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE;AAAA,EAC7E,CAAC;AAAA,EAED,eAAe,wBAAwB;AAAA,IACrC,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS,EAAE,OAAO,eAAe,UAAU,UAAU,SAAS,wBAAwB,YAAY,uBAAuB;AAAA,IACzH,SAAS;AAAA,IACT,YAAY,EAAE,MAAM,YAAY,WAAW,cAAc;AAAA;AAAA,IAEzD,SAAS,EAAE,UAAU,EAAE,QAAQ,WAAW,SAAS,IAAI,KAAK,EAAE,GAAG,GAAG,eAAe,SAAS,EAAE,QAAQ,WAAW,QAAQ,aAAa,EAAE;AAAA,IACxI,SAAS;AAAA,MACP,OAAO;AAAA,MACP,OAAO;AAAA,MACP,UAAU;AAAA,MACV,cAAc;AAAA,MACd,SAAS;AAAA,QACP,MAAM;AAAA,QACN,QAAQ,CAAC,QAAQ,YAAY;AAAA,QAC7B,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,eAAe,EAAE,MAAM,0BAA0B,YAAY,+BAA+B;AAAA,QAC5F,eAAe;AAAA,MACjB;AAAA,MACA,aAAa;AAAA,QACX,MAAM;AAAA,QACN,UAAU;AAAA,QACV,SAAS;AAAA,QACT,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,MAAM;AAAA,UACJ,OAAO,EAAE,MAAM,UAAU,SAAS,eAAe,SAAS,kCAAkC;AAAA,QAC9F;AAAA,MACF;AAAA,MACA,SAAS;AAAA,QACP,MAAM;AAAA,QACN,SAAS;AAAA,QACT,KAAK;AAAA,QACL,SAAS;AAAA,QACT,QAAQ;AAAA,MACV;AAAA,MACA,WAAW;AAAA,MACX,eAAe;AAAA,MACf,iBAAiB;AAAA,IACnB;AAAA,IACA,UAAU,EAAE,OAAO,eAAe,OAAO,SAAS;AAAA,IAClD,cAAc,EAAE,cAAc,MAAM,WAAW,KAAK;AAAA,IACpD,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE;AAAA,EAC7E,CAAC;AAAA;AAAA;AAAA,EAID,eAAe,wBAAwB;AAAA,IACrC,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS,EAAE,OAAO,eAAe,UAAU,UAAU,SAAS,wBAAwB,YAAY,uBAAuB;AAAA,IACzH,SAAS;AAAA,IACT,YAAY,EAAE,MAAM,YAAY,WAAW,cAAc;AAAA,IACzD,SAAS,EAAE,UAAU,EAAE,OAAO,GAAG,GAAG,GAAG,cAAc;AAAA;AAAA;AAAA;AAAA,IAIrD,SAAS;AAAA,MACP,OAAO;AAAA,MACP,OAAO;AAAA,MACP,UAAU;AAAA,MACV,cAAc;AAAA,IAChB;AAAA,IACA,UAAU,EAAE,OAAO,eAAe,OAAO,SAAS;AAAA,IAClD,cAAc,CAAC;AAAA,IACf,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE;AAAA,EAC5G,CAAC;AAAA;AAAA;AAAA;AAAA,EAKD,kBAAkB,wBAAwB;AAAA,IACxC,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS;AAAA,MACP,OAAO;AAAA,MACP,UAAU;AAAA,MACV,SAAS;AAAA,MACT,YAAY;AAAA,IACd;AAAA,IACA,SAAS;AAAA,IACT,YAAY,EAAE,MAAM,YAAY,WAAW,cAAc;AAAA,IACzD,SAAS;AAAA,MACP,UAAU,EAAE,OAAO,EAAE;AAAA,MACrB,OAAO,EAAE,QAAQ,QAAQ;AAAA,MACzB,cAAc,EAAE,QAAQ,eAAe;AAAA,MACvC,iBAAiB,EAAE,OAAO,KAAK;AAAA,MAC/B,YAAY,EAAE,QAAQ,aAAa;AAAA,IACrC;AAAA,IACA,SAAS;AAAA,MACP,OAAO;AAAA,MACP,OAAO;AAAA,MACP,cAAc;AAAA,MACd,YAAY;AAAA,QACV,MAAM;AAAA,QACN,SAAS;AAAA,QACT,SAAS;AAAA,QACT,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,IACA,UAAU,EAAE,OAAO,kBAAkB,OAAO,SAAS;AAAA,IACrD,cAAc,CAAC;AAAA,IACf,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,IAAI,MAAM,EAAE,EAAE;AAAA,EAC7G,CAAC;AAAA,EAED,kBAAkB,wBAAwB;AAAA,IACxC,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS,EAAE,OAAO,kBAAkB,UAAU,WAAW,SAAS,2BAA2B,YAAY,wBAAwB;AAAA,IACjI,SAAS;AAAA,IACT,YAAY,EAAE,MAAM,YAAY,WAAW,WAAW;AAAA,IACtD,SAAS,EAAE,UAAU,EAAE,QAAQ,WAAW,SAAS,IAAI,KAAK,EAAE,EAAE;AAAA,IAChE,SAAS;AAAA,MACP,OAAO;AAAA,MACP,aAAa;AAAA,QACX,MAAM;AAAA,QACN,UAAU;AAAA,QACV,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,SAAS;AAAA,MACX;AAAA,MACA,cAAc;AAAA,QACZ,MAAM;AAAA,QACN,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,SAAS;AAAA,MACX;AAAA,MACA,iBAAiB;AAAA,QACf,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,SAAS;AAAA,MACX;AAAA,MACA,SAAS;AAAA,QACP,MAAM;AAAA,QACN,SAAS;AAAA,QACT,KAAK;AAAA,QACL,SAAS;AAAA,QACT,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,IACA,UAAU,EAAE,OAAO,iBAAiB;AAAA,IACpC,cAAc,EAAE,aAAa,KAAK;AAAA,IAClC,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE;AAAA,EAC5G,CAAC;AAAA,EAED,mBAAmB,wBAAwB;AAAA,IACzC,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS,EAAE,OAAO,mBAAmB,UAAU,cAAc,SAAS,4BAA4B,YAAY,2BAA2B;AAAA,IACzI,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,SAAS,CAAC;AAAA,IACV,SAAS;AAAA,MACP,OAAO;AAAA,MACP,iBAAiB,EAAE,GAAG,kBAAkB,UAAU,KAAK;AAAA,IACzD;AAAA,IACA,UAAU,EAAE,OAAO,kBAAkB;AAAA,IACrC,cAAc,EAAE,WAAW,MAAM,YAAY,KAAK;AAAA;AAAA,IAElD,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,IAAI,MAAM,EAAE,GAAG,QAAQ,aAAa;AAAA,EACnI,CAAC;AAAA,EAED,KAAK,wBAAwB;AAAA,IAC3B,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS,EAAE,OAAO,OAAO,UAAU,YAAY,SAAS,iBAAiB,YAAY,yBAAyB;AAAA,IAC9G,SAAS;AAAA,IACT,YAAY,EAAE,MAAM,YAAY,WAAW,cAAc;AAAA,IACzD,SAAS,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQV,SAAS;AAAA,MACP,OAAO;AAAA,MACP,SAAS;AAAA,QACP,MAAM;AAAA,QACN,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,SAAS;AAAA,MACX;AAAA,MACA,aAAa;AAAA,QACX,MAAM;AAAA,QACN,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,SAAS;AAAA,MACX;AAAA;AAAA;AAAA,MAGA,iBAAiB;AAAA,IACnB;AAAA,IACA,UAAU,EAAE,OAAO,MAAM;AAAA,IACzB,cAAc,EAAE,WAAW,KAAK;AAAA,IAChC,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE;AAAA,EAC7E,CAAC;AAAA;AAAA;AAAA;AAAA,EAMD,gBAAgB,wBAAwB;AAAA,IACtC,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS,EAAE,OAAO,gBAAgB,UAAU,aAAa,SAAS,yBAAyB,YAAY,0BAA0B;AAAA,IACjI,SAAS;AAAA,IACT,YAAY,EAAE,MAAM,YAAY,WAAW,WAAW;AAAA,IACtD,SAAS,EAAE,QAAQ,EAAE,QAAQ,UAAU,KAAK,EAAE,EAAE;AAAA,IAChD,SAAS;AAAA,MACP,OAAO;AAAA,MACP,aAAa;AAAA,MACb,KAAK;AAAA,MACL,KAAK;AAAA,MACL,OAAO;AAAA,QACL,MAAM;AAAA,QACN,QAAQ,CAAC,OAAO,aAAa;AAAA,QAC7B,SAAS;AAAA,QACT,eAAe,EAAE,KAAK,wBAAwB,aAAa,+BAA+B;AAAA,QAC1F,eAAe;AAAA,MACjB;AAAA,MACA,aAAa;AAAA,QACX,MAAM;AAAA,QACN,QAAQ,CAAC,cAAc,UAAU;AAAA,QACjC,SAAS;AAAA,QACT,eAAe,EAAE,YAAY,+BAA+B,UAAU,4BAA4B;AAAA,QAClG,eAAe;AAAA,MACjB;AAAA,MACA,MAAM;AAAA,MACN,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,mBAAmB;AAAA,MACnB,QAAQ;AAAA,IACV;AAAA,IACA,aAAa,CAAC,EAAE,MAAM,gBAAgB,KAAK,OAAO,MAAM,MAAM,CAAC;AAAA,IAC/D,UAAU,EAAE,OAAO,eAAe;AAAA,IAClC,cAAc,CAAC;AAAA,IACf,WAAW;AAAA,IACX,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE;AAAA,EAC5G,CAAC;AAAA,EAED,eAAe,wBAAwB;AAAA,IACrC,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS,EAAE,OAAO,eAAe,UAAU,aAAa,SAAS,wBAAwB,YAAY,0BAA0B;AAAA,IAC/H,SAAS;AAAA,IACT,YAAY,EAAE,MAAM,YAAY,WAAW,WAAW;AAAA,IACtD,SAAS,EAAE,QAAQ,EAAE,QAAQ,UAAU,KAAK,EAAE,EAAE;AAAA,IAChD,SAAS;AAAA,MACP,OAAO;AAAA,MACP,aAAa;AAAA,MACb,KAAK;AAAA,MACL,KAAK;AAAA,MACL,SAAS;AAAA,QACP,MAAM;AAAA,QACN,QAAQ,CAAC,SAAS,SAAS;AAAA,QAC3B,SAAS;AAAA,QACT,eAAe,EAAE,OAAO,sBAAsB,SAAS,uBAAuB;AAAA,QAC9E,eAAe;AAAA,MACjB;AAAA,MACA,MAAM;AAAA,MACN,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,mBAAmB;AAAA,MACnB,QAAQ;AAAA,IACV;AAAA,IACA,aAAa,CAAC,EAAE,MAAM,gBAAgB,KAAK,OAAO,MAAM,MAAM,CAAC;AAAA,IAC/D,UAAU,EAAE,OAAO,cAAc;AAAA,IACjC,cAAc,CAAC;AAAA,IACf,WAAW;AAAA,IACX,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE;AAAA,EAC5G,CAAC;AAAA,EAED,SAAS,wBAAwB;AAAA,IAC/B,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS,EAAE,OAAO,WAAW,UAAU,aAAa,SAAS,qBAAqB,YAAY,0BAA0B;AAAA,IACxH,SAAS;AAAA,IACT,YAAY,EAAE,MAAM,YAAY,WAAW,WAAW;AAAA,IACtD,SAAS,EAAE,QAAQ,EAAE,QAAQ,UAAU,KAAK,EAAE,EAAE;AAAA,IAChD,SAAS;AAAA,MACP,OAAO;AAAA,MACP,aAAa;AAAA,MACb,KAAK;AAAA,QACH,MAAM;AAAA,QACN,SAAS;AAAA,QACT,QAAQ;AAAA,MACV;AAAA,MACA,KAAK;AAAA,QACH,MAAM;AAAA,QACN,SAAS;AAAA,QACT,QAAQ;AAAA,MACV;AAAA,MACA,MAAM;AAAA,MACN,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,mBAAmB;AAAA,MACnB,QAAQ;AAAA,IACV;AAAA,IACA,aAAa,CAAC,EAAE,MAAM,gBAAgB,KAAK,OAAO,MAAM,MAAM,CAAC;AAAA,IAC/D,UAAU,EAAE,OAAO,UAAU;AAAA,IAC7B,cAAc,CAAC;AAAA,IACf,WAAW;AAAA,IACX,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE;AAAA,EAC5G,CAAC;AAAA,EAED,gBAAgB,wBAAwB;AAAA,IACtC,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS,EAAE,OAAO,gBAAgB,UAAU,aAAa,SAAS,yBAAyB,YAAY,0BAA0B;AAAA,IACjI,SAAS;AAAA,IACT,YAAY,EAAE,MAAM,YAAY,WAAW,WAAW;AAAA,IACtD,SAAS,EAAE,QAAQ,EAAE,QAAQ,UAAU,KAAK,EAAE,EAAE;AAAA,IAChD,SAAS;AAAA,MACP,OAAO;AAAA,MACP,aAAa;AAAA,MACb,MAAM;AAAA,QACJ,MAAM;AAAA,QACN,SAAS;AAAA,QACT,QAAQ;AAAA,MACV;AAAA,MACA,MAAM;AAAA,MACN,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,mBAAmB;AAAA,MACnB,QAAQ;AAAA,IACV;AAAA,IACA,UAAU,EAAE,OAAO,eAAe;AAAA,IAClC,cAAc,CAAC;AAAA,IACf,WAAW;AAAA,IACX,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE;AAAA,EAC5G,CAAC;AAAA,EAED,eAAe,wBAAwB;AAAA,IACrC,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS,EAAE,OAAO,eAAe,UAAU,aAAa,SAAS,wBAAwB,YAAY,0BAA0B;AAAA,IAC/H,SAAS;AAAA,IACT,YAAY,EAAE,MAAM,YAAY,WAAW,WAAW;AAAA,IACtD,SAAS,EAAE,QAAQ,EAAE,QAAQ,UAAU,KAAK,EAAE,EAAE;AAAA,IAChD,SAAS;AAAA,MACP,OAAO;AAAA,MACP,aAAa;AAAA,MACb,MAAM;AAAA,MACN,WAAW;AAAA;AAAA,MAEX,YAAY;AAAA,QACV,GAAG;AAAA,QACH,UAAU;AAAA,QACV,UAAU;AAAA,QACV,QAAQ;AAAA,MACV;AAAA,MACA,mBAAmB;AAAA,MACnB,QAAQ;AAAA,IACV;AAAA,IACA,UAAU,EAAE,OAAO,cAAc;AAAA,IACjC,cAAc,CAAC;AAAA,IACf,WAAW;AAAA,IACX,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE;AAAA,EAC5G,CAAC;AAAA;AAAA;AAAA;AAAA,EAMD,SAAS,wBAAwB;AAAA,IAC/B,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS,EAAE,OAAO,WAAW,UAAU,aAAa,SAAS,qBAAqB,YAAY,0BAA0B;AAAA,IACxH,SAAS;AAAA,IACT,YAAY,EAAE,MAAM,YAAY,WAAW,WAAW;AAAA,IACtD,SAAS,EAAE,QAAQ,EAAE,QAAQ,UAAU,KAAK,EAAE,EAAE;AAAA,IAChD,SAAS;AAAA,MACP,OAAO;AAAA,MACP,aAAa;AAAA,MACb,WAAW;AAAA,QACT,GAAG;AAAA,MACL;AAAA,MACA,YAAY;AAAA,QACV,GAAG;AAAA,MACL;AAAA,MACA,mBAAmB;AAAA,MACnB,QAAQ;AAAA,IACV;AAAA,IACA,UAAU,EAAE,OAAO,UAAU;AAAA,IAC7B,cAAc,CAAC;AAAA,IACf,WAAW;AAAA,IACX,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE;AAAA,EAC5G,CAAC;AAAA,EAED,iBAAiB,wBAAwB;AAAA,IACvC,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS,EAAE,OAAO,iBAAiB,UAAU,aAAa,SAAS,0BAA0B,YAAY,0BAA0B;AAAA,IACnI,SAAS;AAAA,IACT,YAAY,EAAE,MAAM,YAAY,WAAW,WAAW;AAAA,IACtD,SAAS,EAAE,QAAQ,EAAE,QAAQ,UAAU,KAAK,EAAE,EAAE;AAAA,IAChD,SAAS;AAAA,MACP,OAAO;AAAA,MACP,aAAa;AAAA,MACb,KAAK;AAAA,MACL,KAAK;AAAA,MACL,SAAS;AAAA,QACP,MAAM;AAAA,QACN,QAAQ,CAAC,WAAW,OAAO;AAAA,QAC3B,SAAS;AAAA,QACT,eAAe,EAAE,SAAS,wBAAwB,OAAO,qBAAqB;AAAA,QAC9E,eAAe;AAAA,MACjB;AAAA,MACA,MAAM;AAAA,MACN,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,mBAAmB;AAAA,MACnB,QAAQ;AAAA,IACV;AAAA,IACA,aAAa,CAAC,EAAE,MAAM,gBAAgB,KAAK,OAAO,MAAM,MAAM,CAAC;AAAA,IAC/D,UAAU,EAAE,OAAO,gBAAgB;AAAA,IACnC,cAAc,CAAC;AAAA,IACf,WAAW;AAAA,IACX,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE;AAAA,EAC5G,CAAC;AAAA,EAED,kBAAkB,wBAAwB;AAAA,IACxC,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS,EAAE,OAAO,kBAAkB,UAAU,WAAW,SAAS,2BAA2B,YAAY,wBAAwB;AAAA,IACjI,SAAS;AAAA,IACT,YAAY,EAAE,MAAM,YAAY,WAAW,WAAW;AAAA;AAAA,IAEtD,SAAS,EAAE,UAAU,EAAE,OAAO,GAAG,EAAE;AAAA,IACnC,SAAS;AAAA,MACP,OAAO;AAAA,MACP,aAAa;AAAA,MACb,cAAc;AAAA,MACd,iBAAiB;AAAA,MACjB,WAAW;AAAA,MACX,KAAK;AAAA,QACH,MAAM;AAAA,QACN,SAAS;AAAA,QACT,QAAQ;AAAA,MACV;AAAA,MACA,KAAK;AAAA,QACH,MAAM;AAAA,QACN,SAAS;AAAA,QACT,QAAQ;AAAA,MACV;AAAA,MACA,MAAM;AAAA,QACJ,MAAM;AAAA,QACN,KAAK;AAAA,QACL,SAAS;AAAA,QACT,QAAQ;AAAA,MACV;AAAA,MACA,MAAM;AAAA,QACJ,MAAM;AAAA,QACN,QAAQ,CAAC,UAAU,SAAS;AAAA,QAC5B,SAAS;AAAA,QACT,eAAe,EAAE,QAAQ,2BAA2B,SAAS,2BAA2B;AAAA,QACxF,eAAe;AAAA,MACjB;AAAA,IACF;AAAA,IACA,aAAa,CAAC,EAAE,MAAM,gBAAgB,KAAK,OAAO,MAAM,MAAM,CAAC;AAAA,IAC/D,UAAU,EAAE,OAAO,iBAAiB;AAAA,IACpC,cAAc,EAAE,aAAa,KAAK;AAAA,IAClC,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE;AAAA,EAC5G,CAAC;AAAA,EAED,kBAAkB,wBAAwB;AAAA,IACxC,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS,EAAE,OAAO,kBAAkB,UAAU,WAAW,SAAS,2BAA2B,YAAY,wBAAwB;AAAA,IACjI,SAAS;AAAA,IACT,YAAY,EAAE,MAAM,YAAY,WAAW,WAAW;AAAA,IACtD,SAAS,EAAE,UAAU,EAAE,OAAO,GAAG,EAAE;AAAA,IACnC,SAAS;AAAA,MACP,OAAO;AAAA,MACP,aAAa;AAAA,MACb,cAAc;AAAA,MACd,iBAAiB;AAAA,MACjB,WAAW;AAAA,IACb;AAAA,IACA,UAAU,EAAE,OAAO,iBAAiB;AAAA,IACpC,cAAc,EAAE,aAAa,KAAK;AAAA,IAClC,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE;AAAA,EAC5G,CAAC;AAAA,EACD,aAAa,wBAAwB;AAAA,IACnC,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS,EAAE,OAAO,aAAa,UAAU,aAAa,SAAS,sBAAsB,YAAY,0BAA0B;AAAA,IAC3H,SAAS;AAAA,IACT,YAAY,EAAE,MAAM,YAAY,WAAW,WAAW;AAAA,IACtD,SAAS,EAAE,eAAe,EAAE,QAAQ,gBAAgB,EAAE;AAAA,IACtD,SAAS;AAAA,MACP,OAAO;AAAA,MACP,aAAa;AAAA,MACb,MAAM;AAAA,QACJ,MAAM;AAAA,QACN,QAAQ,CAAC,OAAO,OAAO,OAAO,OAAO,SAAS,MAAM;AAAA,QACpD,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,eAAe;AAAA,UACb,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AAAA,UACL,OAAO;AAAA,UACP,MAAM;AAAA,QACR;AAAA,QACA,eAAe;AAAA,MACjB;AAAA,MACA,MAAM;AAAA,MACN,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,WAAW;AAAA,QACT,MAAM;AAAA,QACN,SAAS;AAAA,QACT,QAAQ;AAAA,MACV;AAAA,MACA,eAAe;AAAA,IACjB;AAAA,IACA,UAAU,EAAE,OAAO,YAAY;AAAA,IAC/B,cAAc,CAAC;AAAA,IACf,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE;AAAA,EAC5G,CAAC;AAAA,EAED,aAAa,wBAAwB;AAAA,IACnC,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS,EAAE,OAAO,aAAa,UAAU,aAAa,SAAS,sBAAsB,YAAY,0BAA0B;AAAA,IAC3H,SAAS;AAAA,IACT,YAAY,EAAE,MAAM,YAAY,WAAW,cAAc;AAAA;AAAA,IAEzD,SAAS,EAAE,SAAS,EAAE,QAAQ,WAAW,QAAQ,SAAS,EAAE;AAAA,IAC5D,SAAS;AAAA,MACP,OAAO;AAAA,MACP,SAAS;AAAA,QACP,MAAM;AAAA,QACN,QAAQ,CAAC,eAAe,QAAQ;AAAA,QAChC,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,eAAe,EAAE,aAAa,4BAA4B,QAAQ,sBAAsB;AAAA,QACxF,eAAe;AAAA,MACjB;AAAA,MACA,aAAa;AAAA,MACb,MAAM;AAAA,MACN,WAAW;AAAA,MACX,MAAM;AAAA,IACR;AAAA,IACA,UAAU,EAAE,OAAO,YAAY;AAAA,IAC/B,cAAc,CAAC;AAAA,IACf,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE;AAAA,EAC7E,CAAC;AAAA,EAED,aAAa,wBAAwB;AAAA,IACnC,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS,EAAE,OAAO,aAAa,UAAU,aAAa,SAAS,sBAAsB,YAAY,0BAA0B;AAAA,IAC3H,SAAS;AAAA,IACT,YAAY,EAAE,MAAM,YAAY,WAAW,WAAW;AAAA,IACtD,SAAS,CAAC;AAAA,IACV,SAAS,EAAE,OAAO,OAAO,MAAM,MAAM,WAAW,WAAW,MAAM,cAAc;AAAA,IAC/E,UAAU,EAAE,OAAO,YAAY;AAAA,IAC/B,cAAc,CAAC;AAAA,IACf,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE;AAAA,EAC5G,CAAC;AAAA;AAAA;AAAA;AAAA,EAKD,eAAe,wBAAwB;AAAA,IACrC,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS,EAAE,OAAO,eAAe,UAAU,aAAa,SAAS,wBAAwB,YAAY,0BAA0B;AAAA,IAC/H,SAAS;AAAA,IACT,YAAY,EAAE,MAAM,YAAY,WAAW,cAAc;AAAA,IACzD,SAAS,EAAE,eAAe,EAAE,QAAQ,gBAAgB,GAAG,SAAS,EAAE,OAAO,KAAK,EAAE;AAAA,IAChF,SAAS;AAAA,MACP,OAAO;AAAA,MACP,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,mBAAmB;AAAA,MACnB,eAAe;AAAA,QACb,MAAM;AAAA,QACN,SAAS;AAAA,QACT,KAAK;AAAA,QACL,SAAS;AAAA,QACT,QAAQ;AAAA,MACV;AAAA,MACA,QAAQ;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,QACT,QAAQ;AAAA,MACV;AAAA,MACA,gBAAgB,EAAE,MAAM,WAAW,SAAS,4BAA4B;AAAA,MACxE,UAAU;AAAA,QACR,MAAM;AAAA,QACN,SAAS;AAAA,QACT,KAAK;AAAA,QACL,KAAK;AAAA,QACL,SAAS;AAAA,MACX;AAAA,MACA,iBAAiB;AAAA,MACjB,eAAe;AAAA,IACjB;AAAA,IACA,UAAU,EAAE,OAAO,cAAc;AAAA;AAAA,IAEjC,WAAW;AAAA,IACX,cAAc,EAAE,WAAW,KAAK;AAAA,IAChC,QAAQ,EAAE,aAAa,EAAE,MAAM,IAAI,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE;AAAA,EAC9E,CAAC;AAAA;AAAA;AAAA;AAAA,EAKD,eAAe,wBAAwB;AAAA,IACrC,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS,EAAE,OAAO,eAAe,UAAU,aAAa,SAAS,wBAAwB,YAAY,0BAA0B;AAAA,IAC/H,SAAS;AAAA,IACT,YAAY,EAAE,MAAM,YAAY,WAAW,cAAc;AAAA,IACzD,SAAS,EAAE,eAAe,EAAE,QAAQ,gBAAgB,GAAG,SAAS,EAAE,OAAO,KAAK,EAAE;AAAA,IAChF,SAAS;AAAA,MACP,OAAO;AAAA,MACP,MAAM;AAAA,QACJ,MAAM;AAAA,QACN,QAAQ,CAAC,aAAa,SAAS;AAAA,QAC/B,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,eAAe,EAAE,WAAW,4BAA4B,SAAS,yBAAyB;AAAA,QAC1F,eAAe;AAAA,MACjB;AAAA,MACA,aAAa;AAAA,QACX,GAAG;AAAA,MACL;AAAA,MACA,YAAY;AAAA,MACZ,mBAAmB;AAAA,MACnB,eAAe;AAAA,IACjB;AAAA,IACA,UAAU,EAAE,OAAO,cAAc;AAAA,IACjC,WAAW;AAAA,IACX,cAAc,CAAC;AAAA,IACf,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE;AAAA,EAC5G,CAAC;AAAA;AAAA;AAAA,EAID,iBAAiB,wBAAwB;AAAA,IACvC,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS,EAAE,OAAO,iBAAiB,UAAU,aAAa,SAAS,0BAA0B,YAAY,0BAA0B;AAAA,IACnI,SAAS;AAAA,IACT,YAAY,EAAE,MAAM,YAAY,WAAW,WAAW;AAAA,IACtD,SAAS,EAAE,UAAU,EAAE,OAAO,KAAK,EAAE;AAAA,IACrC,SAAS,EAAE,OAAO,OAAO,mBAAmB,oBAAoB;AAAA,IAChE,UAAU,EAAE,OAAO,gBAAgB;AAAA;AAAA,IAEnC,WAAW;AAAA,IACX,cAAc,CAAC;AAAA,IACf,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE;AAAA,EAC5G,CAAC;AAAA;AAAA;AAAA,EAID,mBAAmB,wBAAwB;AAAA,IACzC,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS,EAAE,OAAO,mBAAmB,UAAU,aAAa,SAAS,4BAA4B,YAAY,0BAA0B;AAAA,IACvI,SAAS;AAAA,IACT,YAAY,EAAE,MAAM,YAAY,WAAW,cAAc;AAAA,IACzD,SAAS,EAAE,UAAU,EAAE,OAAO,KAAK,EAAE;AAAA,IACrC,SAAS,EAAE,OAAO,OAAO,mBAAmB,oBAAoB;AAAA,IAChE,UAAU,EAAE,OAAO,kBAAkB;AAAA;AAAA,IAErC,WAAW;AAAA,IACX,cAAc,CAAC;AAAA,IACf,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE;AAAA,EAC5G,CAAC;AAAA;AAAA;AAAA;AAAA,EAKD,iBAAiB,wBAAwB;AAAA,IACvC,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAS,EAAE,OAAO,iBAAiB,UAAU,aAAa,SAAS,0BAA0B,YAAY,0BAA0B;AAAA,IACnI,SAAS;AAAA,IACT,YAAY,EAAE,MAAM,YAAY,WAAW,WAAW;AAAA,IACtD,SAAS,EAAE,eAAe,EAAE,QAAQ,gBAAgB,GAAG,SAAS,EAAE,OAAO,KAAK,EAAE;AAAA,IAChF,SAAS;AAAA,MACP,OAAO;AAAA,MACP,SAAS;AAAA,MACT,WAAW;AAAA,MACX,aAAa,EAAE,MAAM,WAAW,SAAS,yBAAyB;AAAA,MAClE,UAAU;AAAA,QACR,MAAM;AAAA,QACN,SAAS;AAAA,QACT,KAAK;AAAA,QACL,KAAK;AAAA,QACL,SAAS;AAAA,MACX;AAAA,MACA,mBAAmB;AAAA,MACnB,eAAe;AAAA,IACjB;AAAA,IACA,UAAU,EAAE,OAAO,gBAAgB;AAAA;AAAA,IAEnC,WAAW;AAAA,IACX,cAAc,CAAC;AAAA,IACf,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE;AAAA,EAC7E,CAAC;AACH;AAKO,IAAM,uBAAuB,oBAAoB,OAAO,OAAO,wBAAwB,CAAC;;;ADn0C/F,IAAM,QAAQ,UAAgD,MAAM,OAAO,wCAAqB,CAAC;AAE1F,IAAM,uBAAuB,MAAM;AAEnC,IAAM,iBAAiB,aAAa;AAAA,EACzC,YAAY,yBAAyB,WAAW;AAAA,EAChD,gBAAgB,EAAE,MAAM,iBAAiB,WAAW,MAAM,UAAgC,UAAU,EAAE;AACxG,CAAC;AAEM,IAAM,iBAAiB,aAAa;AAAA,EACzC,YAAY,yBAAyB,WAAW;AAAA,EAChD,gBAAgB,EAAE,MAAM,iBAAiB,WAAW,MAAM,UAAU,UAAU,EAAE;AAClF,CAAC;AAEM,IAAM,iBAAiB,aAAa;AAAA,EACzC,YAAY,yBAAyB,WAAW;AAAA,EAChD,gBAAgB,EAAE,MAAM,iBAAiB,WAAW,MAAM,UAAU,UAAU,EAAE;AAClF,CAAC;AAEM,IAAM,mBAAmB,aAAa;AAAA,EAC3C,YAAY,yBAAyB,aAAa;AAAA,EAClD,gBAAgB,EAAE,MAAM,iBAAiB,WAAW,MAAM,UAAU,YAAY,EAAE;AACpF,CAAC;AAEM,IAAM,mBAAmB,aAAa;AAAA,EAC3C,YAAY,yBAAyB,aAAa;AAAA,EAClD,gBAAgB,EAAE,MAAM,iBAAiB,WAAW,MAAM,UAAU,YAAY,EAAE;AACpF,CAAC;;;AE7BD,SAAS,gBAAAC,qBAA2C;AAKpD,IAAMC,SAAQ,UAA8D,MAAM,OAAO,oCAAiB,CAAC;AAEpG,IAAM,mBAAmBA,OAAM;AAE/B,IAAM,mBAAmBC,cAAa;AAAA,EAC3C,YAAY,yBAAyB,aAAa;AAAA,EAClD,gBAAgB,EAAE,MAAM,iBAAiB,WAAWD,OAAM,UAAU,YAAY,EAAE;AACpF,CAAC;AAEM,IAAM,sBAAsBC,cAAa;AAAA,EAC9C,YAAY,yBAAyB,gBAAgB;AAAA,EACrD,gBAAgB,EAAE,MAAM,iBAAiB,WAAWD,OAAM,UAAU,eAAe,EAAE;AACvF,CAAC;AAEM,IAAM,mBAAmBC,cAAa;AAAA,EAC3C,YAAY,yBAAyB,aAAa;AAAA,EAClD,gBAAgB,EAAE,MAAM,iBAAiB,WAAWD,OAAM,UAAU,YAAY,EAAE;AACpF,CAAC;;;ACzBD,SAAS,gBAAAE,qBAA6C;AAKtD,IAAMC,SAAQ,UAAkE,MAAM,OAAO,sCAAmB,CAAC;AAE1G,IAAM,qBAAqBA,OAAM;AAEjC,IAAM,sBAAsBC,cAAa;AAAA,EAC9C,YAAY,yBAAyB,gBAAgB;AAAA,EACrD,gBAAgB,EAAE,MAAM,iBAAiB,WAAWD,OAAM,UAAU,eAAe,EAAE;AACvF,CAAC;AAEM,IAAM,sBAAsBC,cAAa;AAAA,EAC9C,YAAY,yBAAyB,gBAAgB;AAAA,EACrD,gBAAgB,EAAE,MAAM,iBAAiB,WAAWD,OAAM,UAAU,eAAe,EAAE;AACvF,CAAC;AAEM,IAAM,sBAAsBC,cAAa;AAAA,EAC9C,YAAY,yBAAyB,gBAAgB;AAAA,EACrD,gBAAgB,EAAE,MAAM,iBAAiB,WAAWD,OAAM,UAAU,eAAe,EAAE;AACvF,CAAC;;;ACvBD,SAAS,gBAAAE,qBAAoB;AAK7B,IAAMC,SAAQ,UAA8C,MAAM,OAAO,sCAAmB,CAAC;AAEtF,IAAM,qBAAqBA,OAAM;AAEjC,IAAM,qBAAqBC,cAAa;AAAA,EAC7C,YAAY,yBAAyB,eAAe;AAAA,EACpD,gBAAgB,EAAE,MAAM,iBAAiB,WAAWD,OAAM,UAAU,cAAc,EAAE;AACtF,CAAC;;;ACXD,SAAS,gBAAAE,qBAAoB;AAK7B,IAAMC,SAAQ,UAA+C,MAAM,OAAO,uCAAoB,CAAC;AAExF,IAAM,sBAAsBA,OAAM;AAElC,IAAM,qBAAqBC,cAAa;AAAA,EAC7C,YAAY,yBAAyB,eAAe;AAAA,EACpD,gBAAgB,EAAE,MAAM,iBAAiB,WAAWD,OAAM,UAAU,cAAc,EAAE;AACtF,CAAC;AAEM,IAAM,uBAAuBC,cAAa;AAAA,EAC/C,YAAY,yBAAyB,iBAAiB;AAAA,EACtD,gBAAgB,EAAE,MAAM,iBAAiB,WAAWD,OAAM,UAAU,gBAAgB,EAAE;AACxF,CAAC;;;ACjBD,SAAS,gBAAAE,qBAAoB;AAK7B,IAAMC,SAAQ,UAAoD,MAAM,OAAO,sCAAmB,CAAC;AAE5F,IAAM,uBAAuBA,OAAM;AAEnC,IAAM,uBAAuBC,cAAa;AAAA,EAC/C,YAAY,yBAAyB,iBAAiB;AAAA,EACtD,gBAAgB,EAAE,MAAM,iBAAiB,WAAWD,OAAM,UAAU,gBAAgB,EAAE;AACxF,CAAC;;;ACdD,SAAS,eAAe;AAExB;AAAA,EACE,gBAAAE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,SAAS,kBAAkB,QAAQ,iBAAiB,iBAAiB,qBAAqB;;;ACb1F,SAAS,WAAW,gBAAgB;AAK7B,IAAM,YAAY,UAA0C,MAAM,OAAO,iCAAe,CAAC,EAAE,UAAiC,WAAW;AAIvI,SAAS,gBAAgB,OAAgB,KAAK,MAAe;AAClE,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAC5C,YAAU,MAAM;AACd,QAAI,CAAC,OAAO;AACV,iBAAW,KAAK;AAChB;AAAA,IACF;AACA,UAAM,QAAQ,WAAW,MAAM,WAAW,IAAI,GAAG,EAAE;AACnD,WAAO,MAAM,aAAa,KAAK;AAAA,EACjC,GAAG,CAAC,OAAO,EAAE,CAAC;AACd,SAAO,SAAS;AAClB;;;ADKM,cA4DF,YA5DE;AALC,SAAS,MAAM,EAAE,QAAQ,KAAK,GAAgB;AACnD,QAAM,OAAO,uBAAuB,MAAM;AAC1C,QAAM,SAAS,WAAW,KAAK,QAAQ,IAAI;AAC3C,SACE,oBAAC,eAAY,OAAO,UAAU,OAAO,SAAS,OAAO,KAAK,MAAM,YAAY,QAAQ,gBAAgB,MAAM,OAAK,MAC7G,8BAAC,aAAU,QAAgB,MAAY,GACzC;AAEJ;AAIA,SAAS,UAAU,EAAE,QAAQ,KAAK,GAAgB;AAChD,QAAM,QAAQ,cAAc;AAC5B,QAAM,EAAE,MAAM,MAAM,IAAI,eAAe;AACvC,QAAM,OAAO,uBAAuB,MAAM;AAC1C,QAAM,SAAS,WAAW,KAAK,QAAQ,IAAI;AAE3C,QAAM,MAAM,UAAU,OAAO,SAAS,KAAK;AAC3C,QAAM,MAAM,UAAU,OAAO,SAAS,KAAK;AAC3C,QAAM,OAAO,UAAU,OAAO,SAAS,MAAM;AAC7C,QAAM,YAAY,UAAU,OAAO,SAAS,WAAW;AAGvD,QAAM,aAAa,QAAQ,MAAM,cAAc,OAAO,SAAS,YAAY,GAAG,CAAC,OAAO,OAAO,CAAC;AAE9F,QAAM,SAAS;AAAA,IACb,MAAM,iBAAiB,QAAQ,SAAS,MAAM,OAAO,EAAE,KAAK,KAAK,YAAY,OAAO,SAAS,QAAQ,aAAa,OAAO,GAAG,IAAI;AAAA,IAChI,CAAC,QAAQ,OAAO,OAAO,KAAK,KAAK,YAAY,OAAO,IAAI;AAAA,EAC1D;AAKA,QAAM,iBAAiB;AAAA,IACrB,QAAQ;AAAA,IACR,WAAW,OAAO,SAAS,eAAe;AAAA,IAC1C,UAAU,GAAG,OAAO,WAAW,IAAI,OAAO,IAAI;AAAA,EAChD;AAKA,QAAM,MAAM,gBAAgB,IAAI;AAChC,QAAM,QAAQ,UAAU,KAAK,KAAK,EAAE,KAAK,GAAG,KAAK,IAAI,CAAC;AACtD,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,QACJ,MAAM,MAAM,UAAU,UAAa,OAAO,SAAS,KAAK,IACpD;AAAA,IACE,MAAM;AAAA,IACN,iBAAiB,MAAM,MAAM;AAAA,IAC7B,iBAAiB,MAAM,MAAM;AAAA,IAC7B,iBAAiB,KAAK,IAAI,MAAM,MAAM,KAAK,KAAK,IAAI,MAAM,MAAM,KAAK,KAAK,CAAC;AAAA,IAC3E,kBAAkB,GAAG,YAAY,OAAO,SAAS,CAAC,GAAG,OAAO,IAAI,IAAI,KAAK,EAAE;AAAA,EAC7E,IACA,CAAC;AAIP,QAAM,UAAU,gBAAgB,UAAU,MAAS;AACnD,MAAI,SAAS;AACX,WAAO,oBAAC,aAAU,SAAS,OAAO,YAAY,SAAS,WAAW,aAAa,MAAM,QAAQ,GAAG;AAAA,EAClG;AAEA,SACE,qBAAC,SAAI,OAAO,EAAE,UAAU,YAAY,OAAO,QAAQ,QAAQ,QAAQ,GAAG,qBAAqB,cAAc,EAAE,GAAI,GAAG,OAChH;AAAA,wBAAC,UAAO,QAAgB;AAAA,IACxB;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,UACL,UAAU;AAAA,UACV,MAAM,IAAI,UAAU,IAAI,QAAQ;AAAA,UAChC,KAAK,IAAI,UAAU,IAAI,SAAS;AAAA,UAChC,OAAO,IAAI;AAAA,UACX,QAAQ,IAAI;AAAA,UACZ,SAAS;AAAA,UACT,YAAY;AAAA,UACZ,gBAAgB;AAAA,UAChB,eAAe;AAAA,QACjB;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC,MAAM,YAAY,OAAO,SAAS;AAAA,YAClC,MAAM,UAAU,SAAY,SAAY;AAAA,YACxC,MAAM,EAAE,OAAO,IAAI,OAAO,QAAQ,IAAI,OAAO;AAAA,YAC7C;AAAA;AAAA,QACF;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;AAIA,MAAM,UAAU;AAIT,IAAM,cAAcC,cAAa;AAAA,EACtC,YAAY,yBAAyB,OAAO;AAAA,EAC5C,gBAAgB,EAAE,MAAM,iBAAiB,WAAW,MAAM;AAC5D,CAAC;;;AEzHD;AAAA,EACE;AAAA,EACA,gBAAAC;AAAA,EACA;AAAA,EACA,aAAAC;AAAA,EACA,eAAAC;AAAA,OAEK;AAeC,gBAAAC,YAAA;AAXR,IAAM,OAAO,oBAAI,IAAI,CAAC,WAAW,SAAS,MAAM,CAAC;AAE1C,SAAS,MAAM,EAAE,OAAO,GAAsB;AACnD,QAAM,MAAMC,WAAU,OAAO,SAAS,KAAK;AAC3C,QAAM,MAAMA,WAAU,OAAO,SAAS,KAAK,KAAK;AAChD,QAAM,YAAYA,WAAU,OAAO,SAAS,KAAK;AACjD,QAAM,YAAa,aAAa,KAAK,IAAI,SAAS,IAAI,YAAY;AAElE,SACE,gBAAAD,KAACE,cAAA,EAAY,OAAOD,WAAU,OAAO,SAAS,OAAO,GAAG,OAAK,MAC1D,gBACC,gBAAAD,KAAC,SAAI,KAAK,KAAK,KAAU,OAAO,EAAE,OAAO,QAAQ,QAAQ,QAAQ,WAAW,SAAS,QAAQ,GAAG,IAEhG,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,QACL,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,gBAAgB;AAAA,QAChB,QAAQ;AAAA,QACR,OAAO,IAAI,kBAAkB;AAAA,QAC7B,UAAU,QAAQ,IAAI;AAAA,MACxB;AAAA,MACD;AAAA;AAAA,EAED,GAEJ;AAEJ;AAIO,IAAM,cAAcG,cAAa;AAAA,EACtC,YAAY,yBAAyB,OAAO;AAAA,EAC5C,gBAAgB,EAAE,MAAM,iBAAiB,WAAW,MAAM;AAC5D,CAAC;;;AC7CD;AAAA,EACE,OAAAC;AAAA,EACA,gBAAAC;AAAA,EACA,WAAAC;AAAA,EACA;AAAA,EACA,aAAAC;AAAA,EACA,aAAAC;AAAA,EACA,eAAAC;AAAA,OAEK;AAiCC,gBAAAC,YAAA;AA7BR,IAAM,UAA2D;AAAA,EAC/D,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,OAAO;AACT;AAEO,SAAS,MAAM,EAAE,OAAO,GAAsB;AACnD,QAAM,OAAOC,WAAU,OAAO,SAAS,MAAM,KAAK;AAClD,QAAM,QAAQA,WAAU,OAAO,SAAS,OAAO,KAAK;AAGpD,QAAM,WAAWC,WAAU,OAAO,SAAS,UAAU;AACrD,QAAM,WAAW,aAAa,SAAY,QAAQ,QAAQ,6BAA6BC,SAAQ,IAAI;AAEnG,SACE,gBAAAH,KAACI,cAAA,EAAY,OAAOH,WAAU,OAAO,SAAS,OAAO,GAAG,OAAK,MAC3D,0BAAAD;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,QACL,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,gBAAgB,QAAQ,KAAK,KAAK;AAAA,QAClC,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,UAAU;AAAA;AAAA;AAAA,QAGV,SAAS,GAAG,SAAS,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC;AAAA,MACxC;AAAA,MAEA,0BAAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO;AAAA,YACL;AAAA,YACA,OAAOK,KAAI,YAAY;AAAA,YACvB,WAAW;AAAA,YACX,YAAY;AAAA,UACd;AAAA,UAEC;AAAA;AAAA,MACH;AAAA;AAAA,EACF,GACF;AAEJ;AAIO,IAAM,cAAcC,cAAa;AAAA,EACtC,YAAY,yBAAyB,OAAO;AAAA,EAC5C,gBAAgB,EAAE,MAAM,iBAAiB,WAAW,MAAM;AAC5D,CAAC;;;AClED,SAAS,WAAAC,gBAAe;AAExB;AAAA,EACE;AAAA,EACA,OAAAC;AAAA,EACA,gBAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAAC;AAAA,EACA;AAAA,EACA,eAAAC;AAAA,EACA;AAAA,EACA,cAAAC;AAAA,EACA,aAAAC;AAAA,EACA,aAAAC;AAAA,EACA,iBAAAC;AAAA,EACA,cAAAC;AAAA,EACA,0BAAAC;AAAA,EACA,YAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA,oBAAAC;AAAA,EACA;AAAA,EACA,eAAAC;AAAA,OAEK;AA2CU,gBAAAC,MAuBL,QAAAC,aAvBK;AApCjB,IAAM,oBAAoB;AAEnB,SAAS,WAAW,EAAE,QAAQ,KAAK,GAAgB;AACxD,QAAM,WAAW,kBAAkB;AACnC,QAAM,WAAW,kBAAkB;AACnC,QAAM,OAAOC,wBAAuB,MAAM;AAC1C,QAAM,SAASC,YAAW,KAAK,QAAQ,IAAI;AAE3C,QAAM,QAAQC,WAAU,OAAO,SAAS,OAAO,KAAK;AACpD,QAAM,OAAOA,WAAU,OAAO,SAAS,MAAM;AAC7C,QAAM,YAAYC,WAAU,OAAO,SAAS,WAAW;AACvD,QAAM,UAAUC,aAAY,QAAQ,OAAO,SAAS;AAGpD,QAAM,aAAaC,SAAQ,MAAMC,eAAc,OAAO,SAAS,YAAY,GAAG,CAAC,OAAO,OAAO,CAAC;AAC9F,QAAM,OAAO,OAAO,YAAY,QAAQ,KAAK;AAC7C,QAAM,aAAa,WAAW,UAAU,MAAM,KAAK,KAAKC,KAAI,YAAY;AAKxE,QAAM,iBAAiBC;AAAA,IACrB,QAAQ;AAAA,IACRC,YAAW,OAAO,SAAS,eAAe;AAAA,IAC1C,UAAU,GAAG,OAAO,WAAW,IAAI,OAAO,IAAI;AAAA,EAChD;AAKA,QAAM,QAAQ,eAAe,QAAQ,UAAU,QAAQ,SAAS,QAAQ,OAAO,KAAK,KAAK,KAAK,SAAS,CAAC,IAAI,IAAI,EAAE;AAClH,SACE,gBAAAX,KAACY,cAAA,EAAY,OAAc,YAAY,QAAQ,gBAAgB,MAC5D,WAAC,EAAE,MAAM,MAAM,MAAM;AAEpB,QAAI,QAAQ,SAAS,MAAM;AACzB,aAAO,gBAAAZ,KAAC,aAAU,SAAS,OAAO,YAAY,SAAS,WAAW,aAAa,MAAM;AAAA,IACvF;AAGA,UAAM,QAAQ,KAAK,MAAM,kBAAkB,KAAK;AAChD,UAAM,WAAW,KAAK,QAAQ,KAAK,KAAK,SAAS;AACjD,UAAM,UAAU,WAAW,aAAa,MAAM,OAAO,EAAE,MAAM,CAAC,IAAI;AAClE,UAAM,YAAY,WAAW,gBAAgB,OAAO,EAAE,MAAM,CAAC;AAG7D,UAAM,gBACJ,YAAY,UAAa,KAAK,SAAS,KAAK,KAAK,UAAU,GAAG,KAAK,oBAAoB;AACzF,WACE,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,UACL,SAAS;AAAA,UACT,eAAe;AAAA,UACf,gBAAgB;AAAA,UAChB,QAAQ;AAAA,UACR,WAAW;AAAA,UACX,UAAU;AAAA,QACZ;AAAA,QAEA;AAAA,0BAAAA;AAAA,YAAC;AAAA;AAAA,cACC,wBAAsB,MAAM;AAAA,cAC5B,OAAO,MAAM;AAAA,cACb,OAAO;AAAA,gBACL,UAAU;AAAA,gBACV,YAAY;AAAA,gBACZ,YAAY;AAAA;AAAA;AAAA,gBAGZ,YAAY;AAAA,gBACZ,oBAAoB;AAAA,gBACpB,OAAO;AAAA,gBACP,GAAG,eAAe,cAAc;AAAA,cAClC;AAAA,cAEC;AAAA;AAAA,gBACA,QAAQ,SAAS,QAAQ,OACxB,gBAAAD;AAAA,kBAAC;AAAA;AAAA,oBACC,OAAO;AAAA,sBACL,UAAU,YAAY,SAAY,KAAK,MAAM,UAAU,CAAC,IAAI,QAAQ,SAAS;AAAA,sBAC7E,OAAOS,KAAI,kBAAkB;AAAA,sBAC7B,YAAYI,UAAS,CAAC;AAAA,oBACxB;AAAA,oBAEC;AAAA;AAAA,gBACH,IACE;AAAA;AAAA;AAAA,UACN;AAAA,UACC,QAAQ,gBAAgB,gBACvB,gBAAAb,KAAC,SAAI,OAAO,EAAE,UAAUc,SAAQ,IAAI,GAAG,OAAOL,KAAI,kBAAkB,GAAG,WAAWI,UAAS,CAAC,EAAE,GAC3F,0BAAgB,OAAO,cAAc,QAAQ,GAChD,IACE;AAAA;AAAA;AAAA,IACN;AAAA,EAEJ,GACF;AAEJ;AAIO,IAAM,mBAAmBE,eAAa;AAAA,EAC3C,YAAY,yBAAyB,aAAa;AAAA,EAClD,gBAAgB,EAAE,MAAM,iBAAiB,WAAW,WAAW;AACjE,CAAC;;;ACnID,SAAS,gBAAAC,sBAAoB;AAC7B,SAAS,mBAAAC,wBAAuB;AAKhC,IAAMC,SAAQ,UAAU,MAAM,OAAO,oCAAiB,CAAC;AAEhD,IAAM,mBAAmBA,OAAM;AAEtC,IAAM,gBAAgBA,OAAM;AAErB,IAAM,oBAAoBC,eAAa;AAAA,EAC5C,YAAY,yBAAyB,cAAc;AAAA,EACnD,gBAAgB,EAAE,MAAM,iBAAiB,WAAW,cAAc,aAAa,EAAE;AACnF,CAAC;AAEM,IAAM,mBAAmBA,eAAa;AAAA,EAC3C,YAAY,yBAAyB,aAAa;AAAA,EAClD,gBAAgB,EAAE,MAAM,iBAAiB,WAAW,cAAc,YAAY,EAAE;AAClF,CAAC;AAEM,IAAM,gBAAgBA,eAAa;AAAA,EACxC,YAAY,yBAAyB,SAAS;AAAA,EAC9C,gBAAgB,EAAE,MAAM,iBAAiB,WAAW,cAAc,SAAS,EAAE;AAC/E,CAAC;AAEM,IAAM,oBAAoBA,eAAa;AAAA,EAC5C,YAAY,yBAAyB,cAAc;AAAA,EACnD,gBAAgB,EAAE,MAAM,iBAAiB,WAAW,cAAc,aAAa,EAAE;AACnF,CAAC;AAEM,IAAM,mBAAmBA,eAAa;AAAA,EAC3C,YAAY,yBAAyB,aAAa;AAAA,EAClD,gBAAgB,EAAE,MAAM,iBAAiB,WAAW,cAAc,YAAY,EAAE;AAClF,CAAC;AAEM,IAAM,gBAAgBA,eAAa;AAAA,EACxC,YAAY,yBAAyB,SAAS;AAAA,EAC9C,gBAAgB,EAAE,MAAM,iBAAiB,WAAW,cAAc,WAAWC,gBAAe,EAAE;AAChG,CAAC;AAEM,IAAM,qBAAqBD,eAAa;AAAA,EAC7C,YAAY,yBAAyB,eAAe;AAAA,EACpD,gBAAgB,EAAE,MAAM,iBAAiB,WAAW,cAAc,cAAc,EAAE;AACpF,CAAC;;;ACvBD,SAAS,aAAAE,YAAW,QAAQ,YAAAC,iBAAoC;AAChE,SAAS,mBAAmB,sBAAsB;;;ACpBlD,SAAS,eAAe,kBAAkC;AAwBjD,gBAAAC,YAAA;AArBT,IAAM,uBAAuB,cAA8B,IAAI;AAcxD,SAAS,sBAAsB;AAAA,EACpC;AAAA,EACA;AACF,GAGG;AACD,SAAO,gBAAAA,KAAC,qBAAqB,UAArB,EAA8B,OAAO,SAAU,UAAS;AAClE;AAUO,SAAS,mBAAmC;AACjD,SAAO,WAAW,oBAAoB;AACxC;;;ACrBA,SAAS,iBAAAC,gBAAe,cAAAC,mBAAkC;AA0FjD,gBAAAC,YAAA;AA7DT,IAAM,oBAAoBF,eAAiC,IAAI;AAsDxD,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AACF,GAGG;AACD,SAAO,gBAAAE,KAAC,kBAAkB,UAAlB,EAA2B,OAAO,SAAU,UAAS;AAC/D;AASO,SAAS,gBAAmC;AACjD,SAAOD,YAAW,iBAAiB;AACrC;;;AF9FA;AAAA,EACE,OAAAE;AAAA,EACA,WAAAC;AAAA,EACA,gBAAAC;AAAA,EAEA,aAAAC;AAAA,EACA;AAAA,EACA,eAAAC;AAAA,OAEK;;;AGrBA,SAAS,UAAU,SAAyD;AACjF,SAAO,QAAQ;AAAA,IACb,CAAC,MAA8B,EAAE,YAAY,QAAQ,EAAE,aAAa;AAAA,EACtE;AACF;AAWA,IAAM,gBAAgB;AAoBf,SAAS,eAAe,WAAuD;AACpF,MAAI,UAAU,WAAW,EAAG,QAAO,CAAC;AAEpC,MAAI,SAAS;AACb,MAAI,SAAS;AACb,MAAI,SAAS;AACb,MAAI,SAAS;AACb,aAAW,KAAK,WAAW;AACzB,QAAI,EAAE,WAAW,OAAQ,UAAS,EAAE;AACpC,QAAI,EAAE,WAAW,OAAQ,UAAS,EAAE;AACpC,QAAI,EAAE,YAAY,OAAQ,UAAS,EAAE;AACrC,QAAI,EAAE,YAAY,OAAQ,UAAS,EAAE;AAAA,EACvC;AAEA,QAAM,UAAU,SAAS;AACzB,QAAM,UAAU,SAAS;AACzB,QAAM,QAAQ,IAAI,IAAI;AAEtB,SAAO,UAAU,IAAI,CAAC,OAAO;AAAA,IAC3B,GAAG,gBAAgB,SAAS,YAAY,IAAI,OAAO,EAAE,YAAY,UAAU;AAAA;AAAA,IAE3E,GAAG,gBAAgB,SAAS,YAAY,IAAI,OAAO,SAAS,EAAE,YAAY;AAAA,EAC5E,EAAE;AACJ;AAMO,SAAS,cAAc,OAAuB;AACnD,SAAO,MAAM,QAAQ,CAAC;AACxB;AAYO,SAAS,iBAAiB,QAAmC;AAClE,QAAM,QAAkB;AAAA,IACtB,OAAO;AAAA,IACP,GAAG,cAAc,OAAO,QAAQ,CAAC,KAAK,cAAc,OAAO,SAAS,CAAC;AAAA,EACvE;AACA,MAAI,OAAO,aAAa,KAAM,OAAM,KAAK,GAAG,OAAO,SAAS,IAAI;AAChE,MAAI,OAAO,YAAY,KAAM,OAAM,KAAK,OAAI,OAAO,QAAQ,IAAI;AAC/D,MAAI,OAAO,SAAS,KAAM,OAAM,KAAK,GAAG,OAAO,KAAK,MAAM;AAC1D,MAAI,OAAO,WAAW,KAAM,OAAM,KAAK,GAAG,OAAO,OAAO,MAAG;AAC3D,SAAO,MAAM,KAAK,QAAK;AACzB;AAsBO,SAAS,eAAe,SAAiB,aAA0C;AACxF,SAAO;AAAA,IACL,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,SAAS;AAAA,MACP,SAAS;AAAA,QACP,MAAM;AAAA,QACN,OAAO,CAAC,OAAO;AAAA,QACf,UAAU;AAAA,QACV,GAAI,cAAc,EAAE,YAAY,IAAI,CAAC;AAAA,MACvC;AAAA,IACF;AAAA,IACA,QAAQ,CAAC,EAAE,IAAI,WAAW,MAAM,UAAU,QAAQ,UAAU,CAAC;AAAA,EAC/D;AACF;AAmBA,IAAM,aAAa,EAAE,MAAM,WAAW;AAO/B,IAAM,8BAA8B;AAO3C,IAAM,QAAQ;AACd,IAAM,OAAO;AACb,IAAM,WAAW;AAQV,SAAS,cAAc,MAAe,YAA8B;AACzE,SAAO;AAAA,IACL,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,SAAS;AAAA,MACP,MAAM,EAAE,MAAM,WAAW,MAAM,MAAM,aAAa,4BAA4B;AAAA,MAC9E,YAAY,EAAE,MAAM,WAAW,MAAM,WAAW;AAAA,IAClD;AAAA,IACA,QAAQ;AAAA,MACN,EAAE,IAAI,SAAS,MAAM,cAAc,OAAO,EAAE,oBAAoB,MAAM,EAAE;AAAA,MACxE,EAAE,IAAI,QAAQ,MAAM,QAAQ,QAAQ,QAAQ,OAAO,EAAE,cAAc,KAAK,EAAE;AAAA,MAC1E;AAAA,QACE,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,OAAO,EAAE,cAAc,UAAU,cAAc,IAAI;AAAA,MACrD;AAAA,IACF;AAAA,EACF;AACF;AAoBA,IAAI;AAEG,SAAS,gBAAkC;AAChD,MAAI,CAAC,kBAAkB;AACrB,uBAAmB,OAAO,yCAAsB,EAAE;AAAA,MAAK,CAAC,QACtD,cAAc,IAAI,cAAc,MAAM,IAAI,cAAc,UAAU;AAAA,IACpE;AAAA,EACF;AACA,SAAO;AACT;;;AHpEQ,gBAAAC,MAwFJ,QAAAC,aAxFI;AA9FR,IAAI;AAoBJ,SAAS,aAAa,SAA4D;AAChF,MAAI,CAAC,iBAAiB;AAcpB,sBAAkB,QAAQ,IAAI;AAAA,MAC5B,OAAO,aAAa;AAAA,MACpB,QAAQ,QAAQ,EAAE,KAAK,MAAM,QAAQ,aAAa,CAAC;AAAA,IACrD,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,MAAM;AACjB,UAAI,aAAa,QAAQ,SAAS;AAClC,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAKA,IAAM,qBAAqB;AAEpB,SAAS,UAAU,EAAE,QAAQ,KAAK,GAAqC;AAC5E,QAAM,QAAQC,WAAU,OAAO,SAAS,OAAO;AAC/C,QAAM,YAAY,UAAU,KAAK,SAAS;AAI1C,QAAM,UAAU,cAAc;AAM9B,QAAM,SAAS,gBAAgB;AAC/B,QAAM,kBAAkBA,WAAU,OAAO,SAAS,iBAAiB;AACnE,QAAM,OACJ,UAAU,kBACN,CAAC,gBAAgB,OAAO,EAAE,MAAM,iBAAiB,SAAS,EAAE,MAAM,UAAU,YAAY,EAAE,CAAC,IAC3F;AAUN,QAAM,UAAU;AAAA,IACd;AAAA,MACE;AAAA,QACE,SAASA,WAAU,OAAO,SAAS,SAAS;AAAA,QAC5C,aAAaA,WAAU,OAAO,SAAS,aAAa;AAAA,MACtD;AAAA,MACA,iBAAiB;AAAA,IACnB;AAAA,EACF;AAKA,MAAI,KAAK,WAAW;AAClB,WACE,gBAAAF,KAACG,cAAA,EAAY,OACX,0BAAAH;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,SAAQ;AAAA,QACR,QAAO;AAAA;AAAA,IACT,GACF;AAAA,EAEJ;AAUA,MAAI,CAAC,SAAS;AACZ,WACE,gBAAAA,KAACG,cAAA,EAAY,OACX,0BAAAH;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,SAAQ;AAAA,QACR,QAAO;AAAA;AAAA,IACT,GACF;AAAA,EAEJ;AAEA,MAAI,KAAK,WAAW,UAAU,WAAW,GAAG;AAC1C,WACE,gBAAAA,KAACG,cAAA,EAAY,OACX,0BAAAH,KAAC,aAAU,SAAQ,iBAAW,GAChC;AAAA,EAEJ;AAEA,MAAI,UAAU,WAAW,GAAG;AAG1B,WACE,gBAAAA,KAACG,cAAA,EAAY,OACX,0BAAAH;AAAA,MAAC;AAAA;AAAA,QACC,SAAS,KAAK,aAAa,WAAW,IAAI,wBAAwB;AAAA,QAClE,QACE,KAAK,aAAa,WAAW,IACzB,2EACA;AAAA;AAAA,IAER,GACF;AAAA,EAEJ;AAEA,SACE,gBAAAA,KAACG,cAAA,EAAY,OAAc,OAAK,MAC9B,0BAAAH,KAAC,WAAQ,SAAkB,WAAsB,SAAkB,MAAY,GACjF;AAEJ;AAkBA,SAAS,WAAW;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,SAAS,eAAe,SAAS;AACvC,SACE,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACC,eAAY;AAAA,MACZ,OAAO;AAAA,QACL,UAAU;AAAA,QACV,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,YAAYG,KAAI,OAAO;AAAA,MACzB;AAAA,MAEC;AAAA,kBAAU,IAAI,CAAC,UAAU,MACxB,gBAAAJ;AAAA,UAAC;AAAA;AAAA,YAEC;AAAA,YACA;AAAA,YACA,OAAO;AAAA,cACL,UAAU;AAAA,cACV,MAAM,GAAG,OAAO,CAAC,EAAE,IAAI,GAAG;AAAA,cAC1B,KAAK,GAAG,OAAO,CAAC,EAAE,IAAI,GAAG;AAAA,cACzB,WAAW;AAAA,YACb;AAAA;AAAA,UARK,SAAS;AAAA,QAShB,CACD;AAAA,QACD,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,eAAY;AAAA,YACZ,OAAO;AAAA,cACL,UAAU;AAAA,cACV,MAAM;AAAA,cACN,OAAO;AAAA,cACP,QAAQ;AAAA,cACR,SAAS;AAAA,cACT,UAAUK,SAAQ,IAAI;AAAA,cACtB,YAAY;AAAA,cACZ,WAAW;AAAA,cACX,OAAOD,KAAI,kBAAkB;AAAA,cAC7B,YAAYA,KAAI,MAAM;AAAA,cACtB,SAAS;AAAA,YACX;AAAA,YAEC;AAAA;AAAA,QACH;AAAA;AAAA;AAAA,EACF;AAEJ;AAiBA,SAAS,QAAQ;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,eAAe,OAAuB,IAAI;AAChD,QAAM,SAAS,OAA2B,IAAI;AAC9C,QAAM,aAAa,OAAyB,CAAC,CAAC;AAC9C,QAAM,CAAC,QAAQ,SAAS,IAAIE,UAAoB,SAAS;AAGzD,QAAM,UAAU,OAAO,IAAI;AAC3B,UAAQ,UAAU;AAClB,QAAM,aAAa,SAAS;AAE5B,QAAM,UAAU,SAAS,WAAW;AACpC,QAAM,cAAc,SAAS,eAAe;AAI5C,EAAAC,WAAU,MAAM;AACd,QAAI,YAAY;AAChB,cAAU,SAAS;AAMnB,YAAQ,IAAI;AAAA,MACV,aAAa,OAAO;AAAA,MACpB,UAAU,eAAe,SAAS,eAAe,MAAS,IAAI,cAAc;AAAA,IAC9E,CAAC,EACE,KAAK,CAAC,CAAC,UAAU,KAAK,MAAM;AAC3B,YAAM,KAAK,aAAa;AACxB,UAAI,aAAa,CAAC,GAAI;AACtB,YAAM,MAAM,IAAI,SAAS,IAAI;AAAA,QAC3B,WAAW;AAAA,QACX;AAAA,QACA,QAAQ,CAAC,GAAG,CAAC;AAAA,QACb,MAAM;AAAA,MACR,CAAC;AACD,aAAO,UAAU;AACjB,gBAAU,OAAO;AAAA,IACnB,CAAC,EACA,MAAM,MAAM;AAKX,UAAI,CAAC,UAAW,WAAU,aAAa;AAAA,IACzC,CAAC;AAEH,WAAO,MAAM;AACX,kBAAY;AACZ,iBAAW,UAAU,WAAW,QAAS,QAAO,OAAO;AACvD,iBAAW,UAAU,CAAC;AACtB,aAAO,SAAS,OAAO;AACvB,aAAO,UAAU;AAAA,IACnB;AAAA,EAYF,GAAG,CAAC,SAAS,aAAa,QAAQ,SAAS,CAAC;AAK5C,EAAAA,WAAU,MAAM;AACd,UAAM,MAAM,OAAO;AACnB,QAAI,WAAW,WAAW,CAAC,IAAK;AAEhC,QAAI,OAAO;AACX,iBAAa,OAAO,EAAE,KAAK,CAAC,aAAa;AACvC,UAAI,CAAC,QAAQ,OAAO,YAAY,IAAK;AACrC,iBAAW,UAAU,WAAW,QAAS,QAAO,OAAO;AACvD,iBAAW,UAAU,UAAU,IAAI,CAAC,aAAa;AAC/C,cAAM,KAAK,SAAS,cAAc,KAAK;AACvC,WAAG,aAAa,eAAe,YAAY;AAC3C,WAAG,aAAa,eAAe,SAAS,WAAW;AACnD,WAAG,aAAa,SAAS,iBAAiB,QAAQ,CAAC;AACnD,WAAG,aAAa,cAAc,iBAAiB,QAAQ,CAAC;AACxD,YAAI,YAAY;AAEd,iBAAO,OAAO,GAAG,OAAO,gBAAgB;AACxC,aAAG,aAAa,QAAQ,QAAQ;AAChC,aAAG,aAAa,YAAY,GAAG;AAC/B,gBAAM,MAAM,SAAS,cAAc,KAAK;AACxC,iBAAO,OAAO,IAAI,OAAO,kBAAkB,EAAE,QAAQ,UAAU,CAAC;AAChE,aAAG,YAAY,GAAG;AAClB,gBAAM,SAAS,MAAM,QAAQ,UAAU,SAAS,WAAW;AAC3D,aAAG,iBAAiB,SAAS,MAAM;AACnC,aAAG,iBAAiB,WAAW,CAAC,MAAM;AACpC,gBAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,KAAK;AACtC,gBAAE,eAAe;AACjB,qBAAO;AAAA,YACT;AAAA,UACF,CAAC;AAAA,QACH,OAAO;AACL,iBAAO,OAAO,GAAG,OAAO,gBAAgB;AAAA,QAC1C;AAKA,eAAO,IAAI,SAAS,OAAO,EAAE,SAAS,GAAG,CAAC,EACvC,UAAU,CAAC,SAAS,WAAW,SAAS,QAAQ,CAAC,EACjD,MAAM,GAAG;AAAA,MACd,CAAC;AAED,UAAI,UAAU,WAAW,GAAG;AAC1B,YAAI,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,WAAW,UAAU,CAAC,EAAE,QAAQ,GAAG,MAAM,mBAAmB,CAAC;AAAA,MAClG,WAAW,UAAU,SAAS,GAAG;AAC/B,cAAM,SAAS,IAAI,SAAS,aAAa;AACzC,mBAAW,KAAK,UAAW,QAAO,OAAO,CAAC,EAAE,WAAW,EAAE,QAAQ,CAAC;AAClE,YAAI,UAAU,QAAQ,EAAE,SAAS,IAAI,SAAS,MAAM,CAAC;AAAA,MACvD;AAAA,IACF,CAAC;AAED,WAAO,MAAM;AACX,aAAO;AAAA,IACT;AAAA,EAIF,GAAG,CAAC,QAAQ,aAAa,SAAS,GAAG,UAAU,CAAC;AAEhD,MAAI,WAAW,eAAe;AAC5B,WACE,gBAAAP;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,MAAK;AAAA,QACL;AAAA;AAAA,IACF;AAAA,EAEJ;AAEA,SAAO,gBAAAA,KAAC,SAAI,KAAK,cAAc,eAAY,cAAa,OAAO,EAAE,OAAO,QAAQ,QAAQ,OAAO,GAAG;AACpG;AAIA,SAAS,aAAa,WAAwC;AAC5D,SAAO,UAAU,IAAI,CAAC,MAAM,GAAG,EAAE,WAAW,IAAI,EAAE,QAAQ,IAAI,EAAE,SAAS,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,KAAK,GAAG;AAC1G;AAQA,IAAM,mBAAmB;AAAA,EACvB,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,QAAQ;AACV;AAEA,IAAM,mBAAmB;AAAA,EACvB,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,YAAYI,KAAI,SAAS;AAAA,EACzB,QAAQ,aAAaA,KAAI,MAAM,CAAC;AAAA,EAChC,WAAW;AAAA,EACX,QAAQ;AACV;AAKA,SAAS,OAAO;AAAA,EACd;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,QAAQ,iBAAiB,QAAQ;AACvC,MAAI,MAAM;AACR,WACE,gBAAAJ;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,eAAY;AAAA,QACZ,eAAa,SAAS;AAAA,QACtB,OAAO;AAAA,QACP,cAAY;AAAA,QACZ,SAAS,MAAM,KAAK,SAAS,WAAW;AAAA,QACxC,OAAO,EAAE,GAAG,kBAAkB,SAAS,GAAG,QAAQ,GAAG,YAAY,eAAe,GAAG,MAAM;AAAA,QAEzF,0BAAAA,KAAC,UAAK,OAAO,EAAE,GAAG,kBAAkB,QAAQ,WAAW,SAAS,QAAQ,GAAG;AAAA;AAAA,IAC7E;AAAA,EAEJ;AACA,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,eAAY;AAAA,MACZ,eAAa,SAAS;AAAA,MACtB,OAAO;AAAA,MACP,cAAY;AAAA,MACZ,OAAO,EAAE,GAAG,kBAAkB,GAAG,MAAM;AAAA;AAAA,EACzC;AAEJ;AAKA,SAAS,UAAU,EAAE,OAAO,SAAS,OAAO,GAAyD;AACnG,SACE,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,QACL,SAAS;AAAA,QACT,eAAe;AAAA,QACf,YAAY;AAAA,QACZ,gBAAgB;AAAA,QAChB,UAAU;AAAA,QACV,KAAK;AAAA,QACL,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,WAAW;AAAA,QACX,OAAOG,KAAI,kBAAkB;AAAA,MAC/B;AAAA,MAEC;AAAA,gBACC,gBAAAJ,KAAC,SAAI,OAAO,EAAE,UAAUK,SAAQ,IAAI,GAAG,YAAY,EAAE,GAAG,eAAY,QACjE,iBACH,IACE;AAAA,QACJ,gBAAAL,KAAC,SAAI,OAAO,EAAE,UAAUK,SAAQ,IAAI,GAAG,YAAY,IAAI,GAAI,mBAAQ;AAAA,QAClE,SAAS,gBAAAL,KAAC,SAAI,OAAO,EAAE,UAAUK,SAAQ,IAAI,GAAG,SAAS,IAAI,GAAI,kBAAO,IAAS;AAAA;AAAA;AAAA,EACpF;AAEJ;AAIO,IAAM,YAAYG,eAAa;AAAA,EACpC,YAAY,yBAAyB,KAAK;AAAA,EAC1C,gBAAgB,EAAE,MAAM,iBAAiB,WAAW,UAAU;AAChE,CAAC;;;AI9jBD,SAAS,gBAAAC,sBAAoB;AAK7B,IAAMC,SAAQ,UAAoC,MAAM,OAAO,4BAAS,CAAC;AAElE,IAAM,kBAAkBA,OAAM;AAE9B,IAAM,cAAcC,eAAa;AAAA,EACtC,YAAY,yBAAyB,OAAO;AAAA,EAC5C,gBAAgB,EAAE,MAAM,iBAAiB,WAAWD,OAAM,UAAU,OAAO,EAAE;AAC/E,CAAC;;;ACXD,SAAS,WAAAE,gBAAe;AAExB,SAAS,oBAAoB,iBAAiB;AAC9C;AAAA,EACE,OAAAC;AAAA,EACA,gBAAAC;AAAA,EACA,WAAAC;AAAA,EACA;AAAA,EACA,mBAAAC;AAAA,EACA,aAAAC;AAAA,EACA,aAAAC;AAAA,EACA,iBAAAC;AAAA,EACA,cAAAC;AAAA,EACA,0BAAAC;AAAA,EACA,YAAAC;AAAA,EACA,kBAAAC;AAAA,EACA;AAAA,EACA,qBAAAC;AAAA,EACA;AAAA,EACA,eAAAC;AAAA,OAGK;AACP,SAAS,iBAAiB,UAAAC,SAAQ,mBAAAC,kBAAiB,iBAAAC,sBAAqB;AA+BlE,gBAAAC,MA2CF,QAAAC,aA3CE;AArBC,SAAS,gBAAgB,EAAE,QAAQ,MAAM,QAAQ,GAAoB;AAC1E,QAAM,QAAQ,mBAAmB;AACjC,QAAM,SAASC,WAAU,OAAO,SAAS,eAAe;AACxD,QAAM,cAAc,mBAAmB,MAAM,IAAI,SAAS,OAAO;AAGjE,QAAM,aAAa,MAAM;AACvB,UAAM,SAAS,OAAO,YAAY,SAAS,WAAW,OAAO,WAAW,cAAc;AACtF,WAAO,OAAO,kCAAgB,EAAE;AAAA,MAAK,CAAC,MACpC,EAAE,cAAc;AAAA,QACd,SAASC,WAAU,OAAO,SAAS,OAAO,KAAK,UAAU;AAAA,QACzD,SAAS,KAAK;AAAA,QACd,MAAMA,WAAU,OAAO,SAAS,MAAM;AAAA,QACtC,WAAWD,WAAU,OAAO,SAAS,WAAW;AAAA,QAChD,UAAU;AAAA,QACV;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACA,SACE,gBAAAF,KAACI,cAAA,EAAY,OAAOD,WAAU,OAAO,SAAS,OAAO,GAAG,OAAK,MAAC,YAC5D,0BAAAH,KAAC,kBAAe,QAAgB,MAAY,SAAkB,GAChE;AAEJ;AAIA,SAAS,eAAe,EAAE,QAAQ,MAAM,QAAQ,GAAoB;AAClE,QAAM,QAAQK,eAAc;AAC5B,QAAM,EAAE,MAAM,MAAM,IAAIC,gBAAe;AAEvC,QAAM,eAAe,OAAO,YAAY;AACxC,QAAM,OAAOH,WAAU,OAAO,SAAS,MAAM;AAC7C,QAAM,YAAYD,WAAU,OAAO,SAAS,WAAW;AACvD,QAAM,aAAaK,SAAQ,MAAMC,eAAc,OAAO,SAAS,YAAY,GAAG,CAAC,OAAO,OAAO,CAAC;AAE9F,QAAM,MAAMN,WAAU,OAAO,SAAS,KAAK;AAC3C,QAAM,MAAMA,WAAU,OAAO,SAAS,KAAK;AAC3C,QAAM,SAASK,SAAQ,MAAM;AAC3B,UAAM,OAAO,gBAAgB,KAAK,SAAS,OAAO,EAAE,cAAc,MAAM,WAAW,YAAY,OAAO,MAAM,KAAK,MAAM,KAAK,IAAI,GAAG,IAAI;AACvI,WAAO,UAAU,QAAQ,SAAS,MAAM,IAAI,IAAI;AAAA,EAClD,GAAG,CAAC,KAAK,SAAS,KAAK,MAAM,OAAO,cAAc,MAAM,WAAW,YAAY,OAAO,MAAM,SAAS,KAAK,GAAG,CAAC;AAM9G,QAAM,OAAO,gBAAgB,aAAa,SAAS,IAAI,SAAYE,wBAAuB,MAAM;AAChG,QAAM,UAAU,gBAAgB,KAAK,QAAQ,WAAW,CAAC;AACzD,MAAI,SAAS;AACX,WACE,gBAAAT;AAAA,MAAC;AAAA;AAAA,QACC,SAAS,OAAO,YAAY,SAAS;AAAA,QACrC,aAAa;AAAA,QACb,YAAYU,YAAW,KAAK,QAAQ,IAAI;AAAA,QACxC;AAAA,QACA;AAAA,QACA,QAAQ;AAAA;AAAA,IACV;AAAA,EAEJ;AAEA,QAAM,QACJ,gBAAAT,MAAC,SAAI,OAAO,EAAE,UAAU,YAAY,OAAO,QAAQ,QAAQ,OAAO,GAChE;AAAA,oBAAAD,KAACW,SAAA,EAAO,QAAgB;AAAA,IACxB,gBAAAX,KAAC,aAAU,QAAgB,MAAY;AAAA,KACzC;AAEF,MAAI,CAAC,QAAS,QAAO;AAErB,SACE,gBAAAC,MAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,eAAe,UAAU,OAAO,QAAQ,QAAQ,OAAO,GACpF;AAAA,oBAAAD,KAAC,SAAI,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,GAAI,iBAAM;AAAA,IAC7C,QAAQ;AAAA,KACX;AAEJ;AAGA,IAAM,eAAe;AAAA,EACnB,IAAI;AAAA,IACF,MAAM,CAAC,SAAiB,QAAQ,IAAI;AAAA,IACpC,QAAQ,CAAC,SAAiB,aAAa,IAAI;AAAA,IAC3C,KAAK,CAAC,MAAc,SAClB,gBAAgB,IAAI,mBAAmB,IAAI;AAAA,EAC/C;AAAA,EACA,IAAI;AAAA,IACF,MAAM,CAAC,SAAiB,SAAS,IAAI;AAAA,IACrC,QAAQ,CAAC,SAAiB,YAAY,IAAI;AAAA,IAC1C,KAAK,CAAC,MAAc,SAClB,oBAAoB,IAAI,6BAA6B,IAAI;AAAA,EAC7D;AACF;AAEA,IAAM,SAAS;AAQf,SAAS,UAAU,EAAE,QAAQ,KAAK,GAAoE;AACpG,QAAM,QAAQ,mBAAmB;AACjC,QAAM,WAAWY,mBAAkB;AACnC,QAAM,SAASV,WAAU,OAAO,SAAS,eAAe;AACxD,QAAM,OAAO,mBAAmB,MAAM,IAAI,SAAS,OAAO;AAC1D,QAAM,WAAW,UAAU,UAAa,SAAS,MAAM;AACvD,QAAM,QAAQ,KAAK;AACnB,MAAI,CAAC,YAAY,CAAC,MAAO,QAAO;AAEhC,QAAM,QAAQ,aAAa,GAAG,YAAY,EAAE,WAAW,IAAI,IAAI,aAAa,KAAK,aAAa;AAC9F,QAAM,QAAQ,SAAS,SAAY,KAAK,UAAU,IAAI;AAEtD,QAAM,MAAM,OAAO,UAAU,MAAM,aAAa,SAAY,MAAM,WAAW,KAAK,IAAI;AACtF,QAAM,OAAO,QACT,MAAM,KAAK,MAAM,KAAK,IAAI,SACxB,eAAe,OAAO,QAAQ,IAC9BW,iBAAgB,OAAO,QAAQ,IACjC;AACJ,QAAM,OAAO,CAAC,WAAW,QAAQ,IAAI,QAAQ,MAAM,KAAK,IAAI,IAAI,EAAE,EAAE,OAAO,OAAO,EAAE,KAAK,QAAK;AAC9F,QAAM,QAAQ,CAAC,WAAW,MAAM,OAAO,KAAK,IAAI,IAAI,QAAQ,MAAM,IAAI,MAAM,KAAK,IAAI,EAAE,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AACjH,SACE,gBAAAb;AAAA,IAAC;AAAA;AAAA,MACC,mBAAiB,WAAW,QAAQ;AAAA,MACpC,wBAAsB,QAAQ,KAAK;AAAA,MACnC;AAAA,MACA,OAAO;AAAA,QACL,UAAU;AAAA,QACV,KAAKc,UAAS,CAAC;AAAA,QACf,OAAOA,UAAS,CAAC;AAAA,QACjB,SAAS,KAAKA,UAAS,CAAC,CAAC;AAAA,QACzB,UAAUC,SAAQ,IAAI;AAAA,QACtB,YAAY;AAAA,QACZ,OAAOC,KAAI,kBAAkB;AAAA,QAC7B,YAAYA,KAAI,OAAO;AAAA,QACvB,cAAc;AAAA,QACd,eAAe;AAAA,MACjB;AAAA,MAEC;AAAA;AAAA,EACH;AAEJ;AAIA,gBAAgB,UAAUC;AAInB,IAAM,wBAAwBC,eAAa;AAAA,EAChD,YAAY,yBAAyB,kBAAkB;AAAA,EACvD,gBAAgB,EAAE,MAAM,iBAAiB,WAAW,gBAAgB;AACtE,CAAC;;;AnB/JM,IAAM,2BAA2B;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAKO,SAAS,8BAA8C;AAC5D,SAAO,qBAAqB,wBAAwB;AACtD;;;AoBhEA,IAAI;AAEG,SAAS,wBAAwC;AACtD,wBAAY,4BAA4B;AACxC,SAAO;AACT;;;ArB8BA;AAAA,EACE,OAAAC;AAAA,EACA,WAAAC;AAAA,EACA,aAAAC;AAAA,EACA,YAAAC;AAAA,EACA,gBAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,mBAAAC;AAAA,EACA,eAAAC;AAAA,OACK;;;AsBjDP,SAAS,WAAW,iBAAAC,gBAAe,aAAa,cAAAC,aAAY,YAAAC,iBAAgC;AAE5F,SAAS,eAAAC,oBAAmB;;;ACIrB,SAAS,cAAc,OAAwB;AACpD,MAAI,iBAAiB,MAAO,QAAO,MAAM,WAAW,MAAM;AAC1D,SAAO,OAAO,KAAK;AACrB;AAIA,SAAS,WACP,IACA,QAC4B;AAC5B,SAAO,IAAI,SAAY;AACrB,QAAI;AACJ,QAAI;AACF,gBAAU,QAAQ,QAAQ,GAAG,GAAG,IAAI,CAAC;AAAA,IACvC,SAAS,GAAG;AACV,aAAO,cAAc,CAAC,CAAC;AACvB,aAAO,QAAQ,OAAO,CAAC;AAAA,IACzB;AACA,WAAO,QAAQ,MAAM,CAAC,MAAe;AACnC,aAAO,cAAc,CAAC,CAAC;AACvB,YAAM;AAAA,IACR,CAAC;AAAA,EACH;AACF;AAEA,IAAM,kBAAkB;AACxB,IAAM,oBAAoB;AAK1B,SAAS,WAAW,YAAoB,QAA+C;AACrF,SAAO;AAAA,IACL,MAAM,QAAQ,OAAO,IAAI,MAAM,mCAAmC,UAAU,cAAc,CAAC;AAAA,IAC3F;AAAA,EACF;AACF;AAMO,SAAS,cACd,SACA,YACA,QAC2B;AAC3B,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,QAAQ,WAAW,aAAa,iBAAiB;AACvD,QAAM,UAAU,WAAW,aAAa,gBAAgB;AACxD,MAAI,CAAC,SAAS,CAAC,QAAS,QAAO;AAC/B,QAAM,WAA0B;AAAA,IAC9B,kBAAkB,QACd,WAAW,CAAC,MAAM,QAAQ,iBAAiB,CAAC,GAAG,MAAM,IACrD,WAAW,gBAAgB,MAAM;AAAA,IACrC,YAAY,QAAQ,WAAW,CAAC,MAAM,QAAQ,WAAW,CAAC,GAAG,MAAM,IAAI,WAAW,gBAAgB,MAAM;AAAA,IACxG,KAAK,CAAC,cAAc;AAClB,UAAI,cAAc,mBAAmB,CAAC,MAAO,QAAO;AACpD,UAAI,cAAc,qBAAqB,CAAC,QAAS,QAAO;AACxD,aAAO,QAAQ,IAAI,SAAS;AAAA,IAC9B;AAAA,EACF;AAGA,MAAI,WAAW,OAAO,QAAQ,gBAAgB,YAAY;AACxD,aAAS,cAAc,WAAW,CAAC,GAAG,GAAG,MAAM,QAAQ,YAAa,GAAG,GAAG,CAAC,GAAG,MAAM;AAAA,EACtF;AACA,SAAO;AACT;AAGO,SAAS,aAAa,QAAkC,YAAwD;AACrH,SAAO,WAAW,aAAa,cAAc,OAAO,SAAS;AAC/D;AAIO,SAAS,iBACd,YACA,YACA,QAC8B;AAC9B,MAAI,CAAC,cAAc,WAAW,aAAa,eAAe,KAAM,QAAO;AACvE,SAAO,WAAW,CAAC,SAAS,WAAW,IAAI,GAAG,MAAM;AACtD;;;ADrBQ,SACE,OAAAC,MADF,QAAAC,aAAA;AAjER,IAAM,gBAAgB;AAAA,EACpB,SAAS;AAAA,EACT,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,KAAK;AAAA,EACL,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,WAAW;AAAA,EACX,WAAW;AAAA,EACX,OAAO;AACT;AAEA,IAAM,eAAe;AAAA,EACnB,WAAW;AAAA,EACX,UAAU;AAAA,EACV,SAAS;AAAA,EACT,QAAQ;AACV;AAIA,IAAM,gBAAgBC,eAA+B,MAAM;AAAC,CAAC;AAEtD,SAAS,qBAAsC;AACpD,SAAOC,YAAW,aAAa;AACjC;AAgBA,IAAM,sBAAN,cAAkC,UAAwC;AAAA,EAA1E;AAAA;AACE,iBAAuB,EAAE,OAAO,MAAM,UAAU,KAAK,MAAM,SAAS;AAWpE,SAAQ,QAAQ,MAAY;AAC1B,WAAK,MAAM,QAAQ;AACnB,WAAK,SAAS,EAAE,OAAO,KAAK,CAAC;AAAA,IAC/B;AAAA;AAAA,EAZA,OAAO,yBAAyB,OAAwC;AACtE,WAAO,EAAE,OAAO,EAAE,SAAS,cAAc,KAAK,EAAE,EAAE;AAAA,EACpD;AAAA,EAEA,OAAO,yBAAyB,OAAsB,OAAqD;AACzG,QAAI,MAAM,aAAa,MAAM,SAAU,QAAO;AAC9C,WAAO,EAAE,OAAO,MAAM,UAAU,MAAM,SAAS;AAAA,EACjD;AAAA,EAOA,SAAoB;AAClB,UAAM,EAAE,MAAM,IAAI,KAAK;AACvB,QAAI,CAAC,MAAO,QAAO,KAAK,MAAM;AAC9B,WACE,gBAAAH,KAACI,cAAA,EAAY,OAAO,KAAK,MAAM,OAC7B,0BAAAH,MAAC,SAAI,OAAO,eAAe,MAAK,SAC9B;AAAA,sBAAAD,KAAC,SAAI,OAAO,EAAE,UAAU,IAAI,YAAY,EAAE,GAAG,eAAY,QAAO,oBAEhE;AAAA,MACA,gBAAAA,KAAC,SAAI,OAAO,EAAE,UAAU,IAAI,YAAY,IAAI,GAAG,0CAA4B;AAAA,MAC3E,gBAAAA,KAAC,SAAI,OAAO,EAAE,UAAU,IAAI,SAAS,KAAK,WAAW,aAAa,GAAI,gBAAM,SAAQ;AAAA,MACpF,gBAAAA,KAAC,YAAO,MAAK,UAAS,OAAO,cAAc,SAAS,KAAK,OAAO,0BAEhE;AAAA,OACF,GACF;AAAA,EAEJ;AACF;AAUO,SAAS,kBAAkB,EAAE,OAAO,UAAU,SAAS,GAA2B;AACvF,QAAM,CAAC,UAAU,WAAW,IAAIK,UAAmB,CAAC,CAAC;AACrD,QAAM,SAAS,YAA6B,CAAC,YAAY;AACvD,gBAAY,CAAC,SAAU,KAAK,SAAS,OAAO,IAAI,OAAO,CAAC,GAAG,MAAM,OAAO,EAAE,MAAM,EAAE,CAAE;AAAA,EACtF,GAAG,CAAC,CAAC;AACL,QAAM,QAAQ,YAAY,MAAM,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC;AACnD,SACE,gBAAAJ,MAAC,SAAI,OAAO,EAAE,UAAU,YAAY,OAAO,QAAQ,QAAQ,OAAO,GAChE;AAAA,oBAAAD,KAAC,cAAc,UAAd,EAAuB,OAAO,QAC7B,0BAAAA,KAAC,uBAAoB,OAAc,UAAoB,SAAS,OAC7D,UACH,GACF;AAAA,IACC,SAAS,SAAS,KACjB,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,OAAO;AAAA,UACL,UAAU;AAAA,UACV,MAAM;AAAA,UACN,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,SAAS;AAAA,UACT,cAAc;AAAA,UACd,YAAY;AAAA,UACZ,OAAO;AAAA,UACP,SAAS;AAAA,UACT,KAAK;AAAA,UACL,YAAY;AAAA,QACd;AAAA,QAEA;AAAA,0BAAAD,KAAC,UAAK,OAAO,EAAE,MAAM,GAAG,WAAW,aAAa,GAAI,mBAAS,KAAK,QAAK,GAAE;AAAA,UACzE,gBAAAA,KAAC,YAAO,MAAK,UAAS,cAAW,WAAU,SAAS,OAAO,OAAO,EAAE,QAAQ,UAAU,GAAG,kBAEzF;AAAA;AAAA;AAAA,IACF;AAAA,KAEJ;AAEJ;;;AtB3CM,gBAAAM,OAqFF,QAAAC,aArFE;AAPC,SAAS,gBAAgB,OAA6B;AAC3D,QAAM,EAAE,OAAO,IAAI;AACnB,QAAM,WAAW,MAAM,YAAY,sBAAsB;AAEzD,QAAM,WAAW,KAAK,UAAU,CAAC,OAAO,MAAM,OAAO,WAAW,MAAM,OAAO,cAAc,IAAI,CAAC;AAChG,SACE,gBAAAD,MAAC,qBAAkB,OAAOE,WAAU,OAAO,SAAS,OAAO,GAAG,UAC5D,0BAAAF,MAAC,uBAAqB,GAAG,OAAO,UAAoB,GACtD;AAEJ;AASA,SAAS,oBAAoB,EAAE,QAAQ,KAAK,UAAU,SAAS,gBAAgB,oBAAoB,YAAY,GAAc;AAC3H,QAAM,QAAQG,oBAAmB;AACjC,QAAM,aAAa,OAAO,SAAS;AACnC,QAAM,aAAa,aAAa,SAAY,SAAS,WAAW,OAAO,IAAI;AAC3E,QAAM,iBAAiB,aAAa,SAAY,SAAS,eAAe,OAAO,IAAI;AAQnF,QAAM,kBAAkB,eAAe,UAAa,WAAW,WAAW,SAAS;AACnF,QAAM,eAAe,0BAA0B,KAAK,kBAAkB,OAAO,aAAa,MAAS;AACnG,QAAM,YAAY,uBAAuB,KAAK,kBAAkB,OAAO,aAAa,MAAS;AAC7F,MAAI,CAAC,WAAW;AACd,WAAO,gBAAAH,MAAC,kCAA+B,QAAgB;AAAA,EACzD;AACA,MAAI,iBAAiB,eAAe;AAClC,WAAO,gBAAAA,MAAC,0BAAuB,QAAgB;AAAA,EACjD;AAEA,MAAI,OAAO,SAAS,qBAAqB;AACvC,WAAO,gBAAAA,MAAC,yBAAsB,YAAY,OAAO,IAAI,MAAM,QAAQ,OAAO,QAAQ;AAAA,EACpF;AACA,MAAI,CAAC,cAAc,CAAC,gBAAgB;AAElC,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,YAAY,OAAO;AAAA,QACnB,QAAQ,EAAE,MAAM,gBAAgB,SAAS,IAAI,OAAO,IAAI,qDAAqD;AAAA;AAAA,IAC/G;AAAA,EAEJ;AAEA,QAAM,OACJ,gBAAAA,MAAC,iBAAc,KAAU,YAAY,OAAO,YAC5C,0BAAAA,MAAC,aAAU,YAAwB,SAChC,WAAC,gBACA,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,eAAe;AAAA,MAC1B,SAAS;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA;AAAA,EACF,GAEJ,GACA;AAEF,SAAO,OAAO,aAAa,UAAa,sBAAsB,UAAU,IAAI,gBAAAA,MAAC,qBAAmB,gBAAK,IAAuB;AAC9H;AAOA,SAAS,sBAAsB,YAAuC;AACpE,SAAO,WAAW,YAAY,WAAW,WAAW,YAAY,cAAc,aAAa,UAAU;AACvG;AAEA,IAAM,wBAAwB;AAAA,EAC5B,IAAI,EAAE,OAAO,OAAO,OAAO,gFAAgF;AAAA,EAC3G,IAAI,EAAE,OAAO,SAAS,OAAO,kFAAkF;AACjH;AAEA,SAAS,kBAAkB,EAAE,SAAS,GAA4B;AAChE,QAAM,QAAQI,cAAa,GAAG,YAAY,EAAE,WAAW,IAAI,IAAI,sBAAsB,KAAK,sBAAsB;AAChH,SACE,gBAAAH,MAAC,SAAI,sBAAmB,IAAG,OAAO,EAAE,UAAU,YAAY,OAAO,QAAQ,QAAQ,QAAQ,UAAU,GAAG,WAAW,EAAE,GAChH;AAAA;AAAA,IACD,gBAAAD;AAAA,MAAC;AAAA;AAAA,QACC,4BAAyB;AAAA,QACzB,MAAK;AAAA,QACL,OAAO,MAAM;AAAA,QACb,cAAY,MAAM;AAAA,QAClB,OAAO;AAAA,UACL,UAAU;AAAA;AAAA,UAEV,QAAQK,UAAS,CAAC;AAAA,UAClB,MAAMA,UAAS,CAAC;AAAA,UAChB,SAAS,KAAKA,UAAS,CAAC,CAAC;AAAA,UACzB,UAAUC,SAAQ,IAAI;AAAA,UACtB,YAAY;AAAA,UACZ,YAAY;AAAA,UACZ,OAAOC,KAAI,YAAY;AAAA,UACvB,YAAYA,KAAI,YAAY;AAAA,UAC5B,cAAc;AAAA,UACd,QAAQ;AAAA,QACV;AAAA,QAEC,gBAAM;AAAA;AAAA,IACT;AAAA,KACF;AAEJ;AAMA,SAAS,uBAAuB,KAAuB,YAAmD;AACxG,QAAM,MAAM,aAAa,KAAK,UAAU,UAAU,IAAI;AACtD,QAAM,CAAC,SAAS,UAAU,IAAIC,UAAwB,IAAI;AAC1D,EAAAC,WAAU,MAAM;AACd,QAAI,CAAC,cAAc,CAAC,IAAI,sBAAuB;AAC/C,QAAI,YAAY;AAChB,QAAI,sBAAsB,UAAU,EAAE;AAAA,MACpC,CAAC,OAAO;AACN,YAAI,CAAC,UAAW,YAAW,KAAK,OAAO,GAAG;AAAA,MAC5C;AAAA,MACA,MAAM;AACJ,YAAI,CAAC,UAAW,YAAW,IAAI;AAAA,MACjC;AAAA,IACF;AACA,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EAGF,GAAG,CAAC,KAAK,GAAG,CAAC;AAEb,SAAO,YAAY,QAAQ,YAAY;AACzC;AAMA,SAAS,cAAc,EAAE,KAAK,YAAY,SAAS,GAA6F;AAC9I,QAAM,QAAQ,YAAY,SAAS,YAAY,WAAW,cAAc,WAAW,cAAc;AACjG,QAAM,CAAC,OAAO,QAAQ,IAAID,UAAS,KAAK;AACxC,QAAM,CAAC,KAAK,MAAM,IAAIA,UAA6D;AACnF,QAAM,MAAME,aAAY,MAAM,SAAS,IAAI,GAAG,CAAC,CAAC;AAChD,EAAAD,WAAU,MAAM;AACd,QAAI,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,yBAA0B;AACvD,QAAI,OAAO;AACX,QAAI,yBAAyB,KAAK,EAAE;AAAA,MAClC,CAAC,UAAU,QAAQ,OAAO,EAAE,OAAO,MAAM,CAAC;AAAA,MAC1C,MAAM;AAAA,IACR;AACA,WAAO,MAAM;AACX,aAAO;AAAA,IACT;AAAA,EACF,GAAG,CAAC,OAAO,OAAO,GAAG,CAAC;AACtB,QAAM,WAAW,OAAO,IAAI,UAAU,QAAQ,IAAI,QAAQ;AAC1D,QAAM,QAAQE,SAAQ,OAAO,EAAE,UAAU,IAAI,IAAI,CAAC,UAAU,GAAG,CAAC;AAChE,SAAO,gBAAAX,MAAC,iCAA8B,OAAe,UAAS;AAChE;AAKA,SAAS,UAAU;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,SAAS,mBAAmB;AAClC,QAAM,SAASY,iBAAgB;AAC/B,QAAM,aAAa,oBAAoB;AACvC,QAAM,WAAWD,SAAQ,MAAM,cAAc,SAAS,YAAY,MAAM,GAAG,CAAC,SAAS,YAAY,MAAM,CAAC;AACxG,QAAM,iBAAiBA,SAAQ,MAAM,aAAa,QAAQ,UAAU,GAAG,CAAC,QAAQ,UAAU,CAAC;AAC3F,QAAM,qBAAqBA;AAAA,IACzB,MAAM,iBAAiB,YAAY,YAAY,MAAM;AAAA,IACrD,CAAC,YAAY,YAAY,MAAM;AAAA,EACjC;AACA,SACE,gBAAAX,MAAC,wBAAqB,QAAQ,gBAC5B,0BAAAA,MAAC,4BAAyB,YAAY,oBAAqB,mBAAS,QAAQ,GAAE,GAChF;AAEJ;AAcA,SAAS,YAAY,OAAqB;AACxC,UAAQ,MAAM,WAAW,SAAS;AAAA,IAChC,KAAK;AACH,aAAO,gBAAAA,MAAC,wBAAsB,GAAG,OAAO;AAAA,IAC1C,KAAK;AACH,aAAO,gBAAAA,MAAC,0BAAwB,GAAG,OAAO;AAAA,IAC5C,KAAK;AACH,aAAO,gBAAAA,MAAC,2BAAyB,GAAG,OAAO;AAAA,IAC7C,KAAK;AACH,aAAO,gBAAAA,MAAC,4BAA0B,GAAG,OAAO;AAAA,IAC9C,KAAK;AAAA,IACL,KAAK;AACH,aAAO,gBAAAA,MAAC,yBAAuB,GAAG,OAAO;AAAA,IAC3C,KAAK;AACH,aAAO,gBAAAA,MAAC,8BAA4B,GAAG,OAAO;AAAA,EAClD;AACF;AAIA,SAAS,sBAAsB,EAAE,QAAQ,WAAAa,YAAW,QAAQ,GAAiB;AAC3E,SAAO,gBAAAb,MAACa,YAAA,EAAU,QAAgB,MAAM,MAAM,SAAkB;AAClE;AAKA,IAAM,YAAY,UAAyC,MAAM,OAAO,iCAAc,CAAC,EAAE,UAAiC,WAAW,QAAW,iBAAiB;AAIjK,IAAM,eAAe,UAAuD,MAAM,OAAO,uCAA4B,CAAC,EAAE,UAAoC,cAAc;AAI1K,IAAM,cAAc,UAAsD,MAAM,OAAO,sCAA2B,CAAC,EAAE,UAAmC,aAAa;AAErK,SAAS,2BAA2B,OAAqB;AAGvD,MAAI,aAAa,MAAM,UAAU,GAAG;AAClC,WACE,gBAAAb,MAAC,gBAAa,KAAK,MAAM,KAAK,QAAQ,MAAM,QAAQ,YAAY,MAAM,YAAY,WAAW,MAAM,WAAW,SAAS,MAAM,SAAS,YAAY,kBAAkB;AAAA,EAExK;AAQA,QAAM,EAAE,QAAQ,KAAK,YAAY,WAAAa,YAAW,QAAQ,IAAI;AACxD,QAAM,UAAU,YAAY,YAAY,MAAM;AAC9C,MAAI,WAAW,OAAO,YAAY,SAAS,UAAU;AACnD,WACE,gBAAAb,MAAC,aAAU,KAAU,QAAgB,YAAwB,WAAWa,YAAW,SAAkB,YAAY,kBAAkB,QAAQ,CAAC,SAAS;AAAA,EAEzJ;AAEA,MAAI,YAAY,UAAU,GAAG;AAC3B,WAAO,gBAAAb,MAAC,eAAY,KAAU,QAAgB,YAAwB,WAAWa,YAAW,SAAkB;AAAA,EAChH;AACA,SAAO,gBAAAb,MAAC,yBAAuB,GAAG,OAAO;AAC3C;AAEA,SAAS,sBAAsB,EAAE,QAAQ,KAAK,YAAY,WAAAa,YAAW,SAAS,gBAAgB,oBAAoB,YAAY,GAAiB;AAK7I,QAAM,QAAQV,oBAAmB;AAEjC,QAAM,MAAMQ,SAAQ,MAAO,IAAI,MAAM,MAAM,IAAI,IAAK,IAAI,KAAK,KAAM,CAAC,GAAG,CAAC;AACxE,QAAM,OAAO,qBAAqB,KAAK,OAAO,YAAY;AAAA,IACxD,QAAQ,kBAAkB,YAAY,MAAM;AAAA,IAC5C,eAAe,gBAAgB,YAAY,QAAQ,OAAO,WAAW;AAAA,IACrE,UAAU,OAAO,SAAS,MAAM,WAAW;AAAA,IAC3C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAOD,QAAM,YAAYA,SAAqC,MAAM;AAC3D,QAAI,WAAW,cAAc,KAAM,QAAO;AAG1C,UAAM,SAAS,yBAAyB,UAAU,IAAI,SAAYT,WAAU,OAAO,SAAS,aAAa;AACzG,UAAM,QAAQ,SAAS,CAAC,MAAM,IAAI,OAAO,YAAY;AACrD,WAAO;AAAA,MACL,IAAI,iBAAiB,KAAK,QAAQ,KAAK;AAAA,MACvC,mBAAmB,yBAAyB,OAAO,OAAO;AAAA,IAC5D;AAAA,EACF,GAAG,CAAC,YAAY,OAAO,SAAS,OAAO,YAAY,KAAK,MAAM,CAAC;AAE/D,MAAI,KAAK,MAAO,QAAO,gBAAAF,MAAC,oBAAiB,QAAgB,OAAO,KAAK,OAAO;AAC5E,SACE,gBAAAA,MAAC,2BAAwB,WACtB,4BAAkB,YAAY,MAAM,IACnC,gBAAAA,MAAC,oBAAiB,KAAU,QAAgB,YAAwB,MAAY,WAAWa,YAAW,SAAkB,IAExH,gBAAAb,MAACa,YAAA,EAAU,QAAgB,MAAY,SAAkB,GAE7D;AAEJ;AAIA,IAAM,mBAAmB,UAAiD,MAAM,OAAO,yCAAsB,CAAC,EAAE,UAAwC,SAAS;AAKjK,IAAM,gBAAgB,UAA6C,MAAM,OAAO,qCAAkB,CAAC,EAAE,UAAqC,SAAS;AAEnJ,SAAS,yBAAyB,EAAE,QAAQ,KAAK,YAAY,WAAAA,YAAW,QAAQ,GAAiB;AAE/F,QAAM,QAAQ,EAAE,KAAK,QAAQ,YAAY,WAAAA,YAAW,SAAS,YAAY,iBAAiB;AAC1F,SAAO,OAAO,YAAY,SAAS,WAAW,gBAAAb,MAAC,aAAW,GAAG,OAAO,QAAM,MAAC,IAAK,gBAAAA,MAAC,iBAAe,GAAG,OAAO;AAC5G;AAIA,IAAM,eAAe,UAAoD,MAAM,OAAO,oCAAyB,CAAC,EAAE,UAGhH,cAAc;AAEhB,SAAS,qBAAqB,OAAqB;AACjD,SAAO,yBAAyB,MAAM,YAAY,MAAM,MAAM,IAC5D,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,KAAK,MAAM;AAAA,MACX,QAAQ,MAAM;AAAA,MACd,MAAM,kBAAkB,MAAM,YAAY,MAAM,MAAM;AAAA,MACtD;AAAA,MACA,WAAW,MAAM;AAAA,MACjB,SAAS,MAAM;AAAA,MACf,YAAY;AAAA;AAAA,EACd,IAEA,gBAAAA,MAAC,6BAA2B,GAAG,OAAO;AAE1C;AAEA,SAAS,0BAA0B,EAAE,QAAQ,KAAK,YAAY,WAAAa,YAAW,QAAQ,GAAiB;AAGhG,QAAM,QAAQV,oBAAmB;AACjC,QAAM,OAAO,eAAe,KAAK,kBAAkB,YAAY,MAAM,CAAC;AACtE,QAAM,OAAO,QAAQ,MAAM,OAAO,WAAW,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO;AAMpE,MAAI,KAAK,SAAS,KAAK,OAAO,WAAW,KAAK,KAAK,UAAU,GAAG;AAC9D,WAAO,gBAAAH,MAAC,oBAAiB,QAAgB,OAAO,KAAK,OAAO;AAAA,EAC9D;AACA,SAAO,gBAAAA,MAACa,YAAA,EAAU,QAAgB,MAAY,SAAkB;AAClE;AAEA,SAAS,uBAAuB,EAAE,QAAQ,KAAK,YAAY,WAAAA,YAAW,QAAQ,GAAiB;AAC7F,QAAM,OAAO,iBAAiB,KAAK,oBAAoB,YAAY,MAAM,CAAC;AAM1E,SAAO,gBAAAb,MAACa,YAAA,EAAU,QAAgB,MAAY,SAAkB;AAClE;AAEA,SAAS,wBAAwB,EAAE,QAAQ,KAAK,WAAAA,YAAW,QAAQ,GAAiB;AAGlF,QAAM,QAAQV,oBAAmB;AACjC,QAAM,OAAO,kBAAkB,KAAK,EAAE,YAAY,OAAO,WAAW,CAAC;AACrE,QAAM,OAAO,QAAQ,MAAM,OAAO,WAAW,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO;AAWpE,MAAI,KAAK,SAAS,KAAK,UAAU,WAAW,GAAG;AAC7C,WAAO,gBAAAH,MAAC,oBAAiB,QAAgB,OAAO,KAAK,OAAO;AAAA,EAC9D;AACA,SAAO,gBAAAA,MAACa,YAAA,EAAU,QAAgB,MAAY,SAAkB;AAClE;AAGA,IAAM,cAAc;AAAA,EAClB,SAAS;AAAA,EACT,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,KAAK;AAAA,EACL,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,WAAW;AAAA,EACX,WAAW;AAAA,EACX,OAAO;AACT;AAKA,SAAS,sBAAsB;AAAA,EAC7B,YAAY;AAAA,EACZ;AACF,GAGc;AACZ,QAAM,aAAa,OAAO,WAAW,WAAW,SAAS;AACzD,QAAM,WACH,QAAQ,QAAQ,oBAAoB,iBACjC,qCACA;AACN,SACE,gBAAAb,MAACc,cAAA,EACC,0BAAAb;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,MAEP;AAAA,wBAAAD,MAAC,SAAI,OAAO,EAAE,UAAU,IAAI,YAAY,IAAI,GAAI,mBAAQ;AAAA,QACvD,cAAc,CAAC,QAAQ,QAAQ,SAAS,UAAU,KACjD,gBAAAC,MAAC,SAAI,OAAO,EAAE,UAAU,IAAI,SAAS,IAAI,GAAG;AAAA;AAAA,UAAc;AAAA,WAAW;AAAA,QAEtE,UAAU,gBAAAD,MAAC,SAAI,OAAO,EAAE,UAAU,IAAI,SAAS,KAAK,WAAW,aAAa,GAAI,iBAAO,SAAQ;AAAA;AAAA;AAAA,EAClG,GACF;AAEJ;AAKA,SAAS,UAAU;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMc;AACZ,SACE,gBAAAA,MAACc,cAAA,EAAY,OAAOZ,WAAU,OAAO,SAAS,OAAO,GACnD,0BAAAF,MAAC,aAAU,MAAY,OAAc,OAAc,QAAgB,GACrE;AAEJ;AAIA,SAAS,UAAU,EAAE,MAAM,OAAO,OAAO,OAAO,GAA+E;AAC7H,QAAM,EAAE,OAAO,IAAIe,gBAAe,EAAE;AACpC,QAAM,WAAW,SAAS;AAC1B,SACE,gBAAAd,MAAC,SAAI,MAAK,UAAS,oBAAkB,MAAM,OAAO,aAC/C;AAAA,KAAC,YAAY,UAAU,KAAK,gBAAAD,MAAC,SAAI,OAAO,EAAE,UAAU,IAAI,YAAY,EAAE,GAAG,eAAY,QAAQ,iBAAM,IAAS;AAAA,IAC7G,gBAAAA,MAAC,SAAI,OAAO,EAAE,UAAU,IAAI,YAAY,IAAI,GAAI,iBAAM;AAAA,IACrD,WAAW,CAAC,YAAY,UAAU,MAAM,gBAAAA,MAAC,SAAI,OAAO,EAAE,UAAU,IAAI,SAAS,KAAK,WAAW,aAAa,GAAI,kBAAO,IAAS;AAAA,KACjI;AAEJ;AAGA,SAAS,qBAAqB,EAAE,OAAO,GAA0C;AAC/E,SAAO,gBAAAA,MAAC,aAAU,QAAgB,MAAK,aAAY,OAAM,UAAI,OAAO,cAAc,EAAE,WAAW;AACjG;AAIA,SAAS,uBAAuB,EAAE,OAAO,GAA0C;AACjF,SAAO,gBAAAA,MAAC,aAAU,QAAgB,MAAK,QAAO,OAAM,UAAI,OAAM,sBAAqB,QAAO,sCAAqC;AACjI;AAMA,SAAS,+BAA+B,EAAE,OAAO,GAA0C;AACzF,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,MAAK;AAAA,MACL,OAAM;AAAA,MACN,OAAM;AAAA,MACN,QAAO;AAAA;AAAA,EACT;AAEJ;AASA,SAAS,iBAAiB,EAAE,QAAQ,MAAM,GAA0D;AAClG,MAAI,iBAAiB,KAAK,EAAG,QAAO,gBAAAA,MAAC,wBAAqB,QAAgB;AAC1E,SAAO,gBAAAA,MAAC,aAAU,QAAgB,MAAK,SAAQ,OAAM,UAAI,OAAM,oBAAmB,QAAQ,OAAO,KAAK,GAAG;AAC3G;;;AD9iBA;AAAA,EAEE,4BAAAgB;AAAA,EAEA,wBAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AA4GH,SAoLA,YAAAC,WA7KE,OAAAC,OAPF,QAAAC,aAAA;AArDG,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA2B;AAIzB,QAAM,UAAUC,SAAQ,MAAM,eAAe,WAAW,SAAS,QAAQ,GAAG,CAAC,WAAW,SAAS,QAAQ,CAAC;AAC1G,QAAM,WAAW,gBAAgB,sBAAsB;AAEvD,QAAM,iBAAiB,WAAW,WAAW;AAC7C,QAAM,QAAQA;AAAA,IACZ,MAAM,aAAa,iBAAiB,cAAc;AAAA,IAClD,CAAC,WAAW,cAAc;AAAA,EAC5B;AACA,QAAM,EAAE,WAAW,OAAO,IAAI,mBAAmB,SAAS,aAAa,UAAU,KAAK;AAGtF,QAAM,YAAY,UAAU,KAAK;AAEjC,QAAM,EAAE,MAAM,YAAY,IAAI,OAAO,YAAY,IAAI,WAAW;AAChE,QAAM,kBAAkB,UAAU,WAAW,OAAO;AACpD,QAAM,mBAAmB,WAAW,WAAW,OAAO,WAAW;AACjE,QAAM,QAAQ,aAAa,gBAAgB;AAI3C,QAAM,EAAE,OAAO,IAAI;AACnB,QAAM,WAAWC,aAAY,CAAC,UAAkB,KAAK,UAAU,YAAY,QAAQ,OAAO,KAAK,CAAC,GAAG,CAAC,QAAQ,KAAK,CAAC;AAClH,QAAM,CAAC,UAAU,cAAc,IAAI,kBAAkC,QAAQ;AAC7E,QAAM,SAASD;AAAA,IACb,MACE,gBAAgB,YAAY,gBAAgB;AAAA,MAC1C;AAAA,MACA,UAAU,CAAC,MAAO,EAAE,SAASE,uBAAsB,SAAY,mBAAmB,SAAS,WAAW,EAAE,IAAI,GAAG,MAAM;AAAA,IACvH,CAAC;AAAA,IACH,CAAC,YAAY,gBAAgB,OAAO,QAAQ;AAAA,EAC9C;AACA,QAAM,EAAE,YAAY,QAAQ,IAAI;AAChC,QAAM,UAAU,QAAQ,MAAM,OAAO;AAErC,SACE,gBAAAH;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,gBAAc;AAAA,MACd,gBAAc;AAAA,MACd,oBAAkB,MAAM,SAAS,KAAK;AAAA,MACtC,OAAO,EAAE,GAAG,YAAY,iBAAiB,EAAE,GAAG,GAAG,WAAW,KAAK,EAAE;AAAA,MAEnE;AAAA,wBAAAD,MAAC,qBAAkB;AAAA,QACnB,gBAAAA,MAAC,yBAAsB,OACvB,0BAAAA,MAAC,2BAAwB,MAAM,WAC/B,0BAAAA,MAAC,0BAAuB,UACxB,0BAAAA,MAAC,2BAAwB,OACzB,0BAAAA,MAACK,uBAAA,EAAqB,QACpB,0BAAAL,MAACM,2BAAA,EAAyB,YAC1B,0BAAAN,MAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,QAAQ,GAErC,0BAAAA,MAAC,SAAI,OAAO,EAAE,eAAe,cAAc,GACzC,0BAAAA;AAAA,UAAC;AAAA;AAAA,YACC,aAAU;AAAA,YACV,OAAO;AAAA,cACL,SAAS;AAAA,cACT,qBAAqB,UAAU,OAAO;AAAA,cACtC,cAAc;AAAA,cACd,WAAW,QAAQ;AAAA,cACnB,QAAQ,QAAQ;AAAA,cAChB,OAAO;AAAA,cACP,GAAI,EAAE,aAAa,QAAQ,KAAK;AAAA,YAClC;AAAA,YAEA,0BAAAA;AAAA,cAAC;AAAA;AAAA,gBACC;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA,MAAM,OAAO;AAAA,gBACb;AAAA,gBACA,QAAQ,CAAC,WACP,gBAAAA,MAAC,4BAAyB,OAAO,aAAa,aAAa,YAAY,MAAM,CAAC,GAC5E,0BAAAA,MAAC,yBAAsB,OAAO,mBAAmB,MAAM,GACrD,0BAAAA;AAAA,kBAAC;AAAA;AAAA,oBAEC;AAAA,oBACA;AAAA,oBACA;AAAA,oBACA;AAAA,oBACA,gBAAgB,UAAU,OAAO,EAAE,GAAG;AAAA,oBACtC,oBAAoB,UAAU,OAAO,EAAE,GAAG;AAAA,oBAC1C,aAAa,MAAM,OAAO,OAAO,EAAE;AAAA;AAAA,kBAP9B;AAAA,gBAQP,GACF,GACF;AAAA;AAAA,YAEJ;AAAA;AAAA,QACF,GACF,GACF,GACA,GACF,GACA,GACA,GACA,GACA;AAAA;AAAA;AAAA,EACF;AAEJ;AAGA,IAAM,OAAO;AAaN,SAAS,cAAc,KAAyB;AACrD,MAAI,OAAO,QAAQ,SAAU,QAAO,QAAQ,GAAG;AAC/C,SAAO,QAAQ,YAAY,QAAQ,YAAY,GAAG;AACpD;AAEO,SAAS,QAAQ,MAAkB,SAA0B;AAClE,QAAM,IAAI,KAAK;AACf,QAAM,UAAU,cAAc,OAAO,MAAM,WAAW,EAAE,IAAI,CAAC;AAC7D,QAAM,UAAU,cAAc,OAAO,MAAM,WAAW,EAAE,IAAI,CAAC;AAC7D,QAAM,IAAI,KAAK;AACf,QAAM,UACJ,OAAO,MAAM,WACT,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,aAAa,EAAE,KAAK,GAAG,IAC9D,cAAc,CAAC;AACrB,SAAO,EAAE,SAAS,SAAS,SAAS,MAAM,kBAAkB,UAAU,CAAC,MAAM,OAAO,OAAO,OAAO,IAAI;AACxG;AAIA,SAAS,YAAY,QAAqD;AACxE,SAAO,OAAO,SAASI,uBAAsB,SAAY,OAAO;AAClE;AAQO,SAAS,cAAc,GAAkB,SAAgC;AAC9E,QAAM,MAAM,KAAK,IAAI,KAAK,IAAI,GAAG,EAAE,GAAG,GAAG,UAAU,CAAC;AACpD,QAAM,OAAO,KAAK,IAAI,KAAK,IAAI,GAAG,EAAE,IAAI,GAAG,UAAU,GAAG;AACxD,SAAO;AAAA,IACL,YAAY,GAAG,MAAM,CAAC,WAAW,IAAI;AAAA,IACrC,SAAS,GAAG,EAAE,MAAM,CAAC,WAAW,EAAE,IAAI;AAAA;AAAA;AAAA,IAGtC,UAAU;AAAA,IACV,WAAW;AAAA,EACb;AACF;AAGA,IAAM,aAAa;AAKZ,SAAS,iBAAiB,GAAsB,SAA8D;AACnH,QAAM,IAAI,eAAe,EAAE,MAAM;AACjC,QAAM,IAAI,eAAe,EAAE,QAAQ,EAAE,MAAM;AAC3C,QAAM,OAAO,CAAC,GAAW,WAAmB,QAAQ,CAAC,MAAM,IAAI,MAAM,IAAI,CAAC,MAAM,MAAM;AACtF,QAAM,UAAU,CAAC,GAAW,WAAmB,GAAG,CAAC,OAAO,IAAI,MAAM,MAAM;AAC1E,QAAM,OAAO,UAAU,EAAE;AACzB,SAAO;AAAA,IACL,UAAU;AAAA,IACV,MAAM,QAAQ,EAAE,KAAK,GAAG,OAAO,QAAQ,EAAE,QAAQ,KAAK,GAAG,QAAQ,OAAO,CAAC;AAAA,IACzE,KAAK,QAAQ,EAAE,KAAK,GAAG,OAAO,QAAQ,EAAE,QAAQ,KAAK,GAAG,QAAQ,OAAO,CAAC;AAAA,IACxE,OAAO,OAAO,SAAS,KAAM,EAAE,KAA0B,MAAM,QAAQ,OAAO;AAAA,IAC9E,QAAQ,OAAO,SAAS,KAAM,EAAE,KAA0B,MAAM,QAAQ,OAAO;AAAA,IAC/E,WAAW,aAAa,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC,EAAE,KAAK,GAAG;AAAA,IACpD,QAAQ,cAAc,EAAE,SAAS;AAAA,IACjC,eAAe;AAAA,EACjB;AACF;AAKA,SAAS,cAAc;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAQG;AACD,QAAM,SAAS,QAAQ,IAAI,CAAC,OAAO,EAAE,QAAQ,GAAG,WAAW,iBAAiB,EAAE,QAAQ,UAAU,EAAE,EAAE;AACpG,QAAM,aAAa,oBAAI,IAAwE;AAC/F,aAAW,EAAE,QAAQ,UAAU,KAAK,QAAQ;AAC1C,QAAI,UAAU,SAAS,WAAY;AACnC,eAAW,IAAI,UAAU,MAAM,CAAC,GAAI,WAAW,IAAI,UAAU,IAAI,KAAK,CAAC,GAAI,EAAE,QAAQ,UAAU,CAAC,CAAC;AAAA,EACnG;AACA,QAAM,WAAW,CAAC,UACf,WAAW,IAAI,IAAI,KAAK,CAAC,GAAG,IAAI,CAAC,EAAE,QAAQ,UAAU;AAAA;AAAA;AAAA,IAGpD,gBAAAH,MAAC,SAAoB,eAAa,OAAO,IAAI,aAAW,MAAM,OAAO,iBAAiB,WAAW,OAAO,GACrG;AAAA,aAAO,MAAM;AAAA,MACb,SAAS,OAAO,EAAE;AAAA,SAFX,OAAO,EAGjB;AAAA,GACD;AACH,SACE,gBAAAD,MAAAD,WAAA,EACG,iBAAO,IAAI,CAAC,EAAE,QAAQ,UAAU,MAAM;AACrC,QAAI,UAAU,SAAS,OAAQ,QAAO;AACtC,UAAM,QAAQ,cAAc,KAAK,IAAI,OAAO,EAAE,KAAK,WAAW,OAAO;AAGrE,WACE,gBAAAE,MAAC,YACC;AAAA,sBAAAD,MAAC,SAAI,eAAa,OAAO,IAAI,OAC1B,iBAAO,MAAM,GAChB;AAAA,MACC,WAAW,IAAI,OAAO,EAAE;AAAA;AAAA;AAAA,QAGvB,gBAAAA,MAAC,SAAI,OAAO,EAAE,GAAG,OAAO,UAAU,YAAY,eAAe,QAAQ,QAAQ,WAAW,GACrF,mBAAS,OAAO,EAAE,GACrB;AAAA,UACE;AAAA,SAVS,OAAO,EAWtB;AAAA,EAEJ,CAAC,GACH;AAEJ;AAQO,SAAS,YAAY,QAAsB,IAAiD;AACjG,QAAM,OAAsB;AAAA,IAC1B,UAAU;AAAA,IACV,iBAAiB,IAAI,SAAS;AAAA,IAC9B,iBAAiB,IAAI,WAAW,OAAO,GAAG,QAAQ,MAAM;AAAA,IACxD,gBAAgB;AAAA,EAClB;AACA,MAAI,WAAW,OAAQ,QAAO,EAAE,GAAG,MAAM,OAAO,QAAQ,QAAQ,OAAO;AACvE,MAAI,WAAW,OAAQ,QAAO,EAAE,GAAG,MAAM,OAAO,OAAO,OAAO,UAAU,QAAQ,QAAQ,OAAO;AAC/F,SAAO,EAAE,GAAG,MAAM,OAAO,QAAQ,QAAQ,OAAO,OAAO;AACzD;AAMO,SAAS,eACd,SACA,UACkB;AAClB,SAAO,QAAQ,IAAI,CAAC,WAAW;AAC7B,QAAI,OAAO,SAASI,wBAAuB,OAAO,YAAY,SAAS,OAAQ,QAAO;AACtF,WAAO,EAAE,GAAG,QAAQ,YAAY,wBAAwB,OAAO,YAAY,QAAQ,EAAE;AAAA,EACvF,CAAC;AACH;AAQO,SAAS,mBAAmB,QAA4C;AAC7E,QAAM,KAAK,OAAO;AAClB,MAAI,CAAC,GAAI,QAAO;AAChB,MAAI,GAAG,SAAS,SAAU,QAAO,GAAG,eAAe;AACnD,MAAI,GAAG,SAAS,SAAU,QAAO,GAAG,OAAO;AAC3C,SAAO;AACT;AAOA,SAAS,kBAAyC,OAAiE;AACjH,QAAM,MAAMG,QAAU,IAAI;AAC1B,QAAM,CAAC,OAAO,QAAQ,IAAIC,UAAS,CAAC;AACpC,QAAM,WAAWD,QAAO,KAAK;AAC7B,QAAM,UAAUJ,aAAY,MAAM;AAChC,UAAM,KAAK,IAAI;AACf,QAAI,CAAC,GAAI;AACT,UAAM,OAAO,GAAG;AAChB,aAAS,CAAC,SAAU,SAAS,QAAQ,IAAI,MAAM,SAAS,QAAQ,IAAI,IAAI,OAAO,IAAK;AAAA,EACtF,GAAG,CAAC,CAAC;AACL,kBAAgB,MAAM;AACpB,aAAS,UAAU;AACnB,YAAQ;AAAA,EACV,GAAG,CAAC,OAAO,OAAO,CAAC;AACnB,kBAAgB,MAAM;AACpB,UAAM,KAAK,IAAI;AACf,QAAI,CAAC,MAAM,OAAO,mBAAmB,YAAa;AAClD,UAAM,KAAK,IAAI,eAAe,OAAO;AACrC,OAAG,QAAQ,EAAE;AACb,WAAO,MAAM,GAAG,WAAW;AAAA,EAC7B,GAAG,CAAC,OAAO,CAAC;AACZ,SAAO,CAAC,KAAK,KAAK;AACpB;AAcA,SAAS,UAAU,OAA+B;AAChD,SAAO,MAAM,WAAW,GAAG,MAAM,SAAS,MAAM,IAAI,MAAM,SAAS,IAAI,KAAK;AAC9E;AAUO,IAAM,kBAAkB;AAI/B,SAAS,QAAQ,QAAwB,UAA8C;AAGrF,MAAI,OAAO,SAASC,wBAAuB,SAAS,WAAW,OAAO,IAAI,GAAG,YAAY,eAAe;AACtG,WAAO;AAAA,EACT;AACA,SAAO,KAAK,UAAU,OAAO,cAAc,IAAI;AACjD;AAsBA,SAAS,mBACP,SACA,SACA,UACA,OACwF;AACxF,QAAM,CAAC,OAAO,QAAQ,IAAII,UAA+B,CAAC,CAAC;AAG3D,QAAM,YAAYD,QAA+B,CAAC,CAAC;AAKnD,QAAM,UAAUA,QAA+B,CAAC,CAAC;AACjD,QAAM,CAAC,YAAY,WAAW,IAAIC,UAAS,CAAC;AAC5C,QAAM,UAAUD,QAAO,IAAI;AAC3B,EAAAE,WAAU,MAAM;AACd,YAAQ,UAAU;AAClB,WAAO,MAAM;AACX,cAAQ,UAAU;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,SAASN,aAAY,CAAC,OAAe;AACzC,YAAQ,QAAQ,EAAE,KAAK,QAAQ,QAAQ,EAAE,KAAK,KAAK;AACnD,gBAAY,CAAC,MAAM,IAAI,CAAC;AAAA,EAC1B,GAAG,CAAC,CAAC;AAML,QAAM,SAAS,QAAQ,QAAQ,CAAC,MAAM;AACpC,UAAM,MAAM,QAAQ,GAAG,QAAQ;AAC/B,QAAI,QAAQ,OAAW,QAAO,CAAC;AAC/B,UAAM,aAAa,EAAE,SAASC,uBAAsB,SAAY,SAAS,WAAW,EAAE,IAAI;AAC1F,UAAM,OAAO,aAAc,gBAAgB,YAAY,GAAG,MAAM,WAAW,KAAK,OAAQ;AACxF,WAAO,CAAC,CAAC,EAAE,IAAI,KAAK,IAAI,CAAU;AAAA,EACpC,CAAC;AACD,QAAM,MAAM,UAAU,KAAK;AAC3B,QAAM,YAAY,KAAK,UAAU,CAAC,KAAK,MAAM,CAAC;AAE9C,EAAAK,WAAU,MAAM;AAGd,QAAI,CAAC,SAAS;AACZ,gBAAU,UAAU,CAAC;AACrB,eAAS,CAAC,CAAC;AACX;AAAA,IACF;AACA,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,OAAO,IAAI,IAAI,QAAQ,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAClD,UAAM,OAA+B,CAAC;AACtC,eAAW,CAAC,IAAI,KAAK,IAAI,KAAK,QAAQ;AAEpC,YAAM,OAAO,GAAG,GAAG,IAAI,QAAQ,EAAE,IAAI,GAAG;AACxC,YAAM,IAAI,QAAQ,QAAQ,EAAE,KAAK;AAGjC,YAAM,QAAQ,GAAG,IAAI,GAAG,MAAM,UAAU,IAAI,MAAM,CAAC;AACnD,YAAM,WAAW,UAAU,QAAQ,EAAE;AAErC,UAAI,aAAa,SAAU,MAAM,UAAU,UAAU,WAAW,IAAI,GAAI;AACtE,aAAK,EAAE,IAAI;AACX;AAAA,MACF;AACA,WAAK,EAAE,IAAI;AACX,YAAM,SAAS,KAAK,IAAI,EAAE;AAI1B,UAAI,QAAQ,YAAY,SAAS,SAAU;AAG3C,YAAM,MAAM,MAAM,UAAU,MAAM,aAAa,SAAY,MAAM,WAAW;AAG5E,YAAM,gBACJ,SAAS,OAAO,iBAAiB,MAAM,GAAG,IAAI,MAAM,WAAW,iBAAiB,4BAA4B,GAAG,IAAI,qBAAqB;AAC1I,YAAM,UAAU,MAAM,QAAQ,WAAW,UAAU,QAAQ,EAAE,MAAM;AACnE,WAAK,mBAAmB,QAAQ,eAAe,EAAE,SAAS,IAAI,EAAE,CAAC,EAAE;AAAA,QACjE,CAAC,YAAY;AACX,cAAI,CAAC,QAAQ,EAAG;AAEhB,mBAAS,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,EAAE,GAAG,EAAE,KAAK,QAAQ,KAAK,SAAS,MAAM,IAAI,EAAE,EAAE;AAAA,QAClF;AAAA,QACA,MAAM;AAIJ,qBAAW,MAAM,QAAQ,KAAK,OAAO,EAAE,GAAG,eAAe;AAAA,QAC3D;AAAA,MACF;AAAA,IACF;AACA,cAAU,UAAU;AAAA,EAGtB,GAAG,CAAC,WAAW,SAAS,YAAY,MAAM,MAAM,CAAC;AAGjD,QAAM,YAAYP,SAAQ,MAAM;AAC9B,UAAM,MAAiD,CAAC;AACxD,QAAI,CAAC,QAAS,QAAO;AACrB,eAAW,KAAK,SAAS;AACvB,YAAM,OAAO,MAAM,EAAE,EAAE;AACvB,UAAI,EAAE,EAAE,IAAI,QAAQ,KAAK,QAAQ,QAAQ,GAAG,QAAQ,KAAK,KAAK,WAAW,MAAM,OAAO;AAAA,IACxF;AACA,WAAO;AAAA,EACT,GAAG,CAAC,SAAS,OAAO,SAAS,UAAU,GAAG,CAAC;AAC3C,SAAO,EAAE,WAAW,OAAO;AAC7B;;;AyB5mBA;AAAA,EACE,8BAAAQ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,oBAAAC;AAAA,EACA,sBAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAAC;AAAA,EACA;AAAA,OAKK;AACP,SAAS,eAAAC,cAAa,aAAAC,YAAW,WAAAC,UAAS,UAAAC,SAAQ,YAAAC,iBAAwD;AAoJtG,SA6LM,YAAAC,WA1KJ,OAAAC,OAnBF,QAAAC,aAAA;AArIG,SAAS,kBACd,gBACA,OAA6E,CAAC,GACzC;AACrC,QAAM,CAAC,OAAO,QAAQ,IAAIH,UAAyB,MAAMP,kBAAiB,gBAAgB,IAAI,CAAC;AAG/F,QAAM,cAAcM,QAAO,cAAc;AACzC,EAAAF,WAAU,MAAM;AACd,QAAI,YAAY,YAAY,eAAgB;AAC5C,gBAAY,UAAU;AACtB,aAAS,CAAC,MAAM,SAAS,GAAGH,oBAAmB,cAAc,IAAI,iBAAiBF,2BAA0B,CAAC;AAAA,EAC/G,GAAG,CAAC,cAAc,CAAC;AACnB,QAAM,WAAWM;AAAA,IACf,OAAO;AAAA;AAAA,MAEL,SAAS,CAAC,gBAAgB,SAAS,CAAC,MAAM,SAAS,cAAc,CAAC,GAAG,WAAW,CAAC;AAAA,MACjF,OAAO,MAAM,SAAS,CAAC,MAAM,WAAW,GAAG,KAAK,IAAI,CAAC,CAAC;AAAA,MACtD,QAAQ,MAAM,SAAS,CAAC,MAAM,YAAY,CAAC,CAAC;AAAA,MAC5C,aAAa,CAAC,QAAQ,SAAS;AAC7B,cAAM,OAAO,cAAc,QAAQ,IAAI;AACvC,YAAI,aAAa,KAAM,QAAO,KAAK;AACnC,iBAAS,KAAK,KAAK;AACnB,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,CAAC;AAAA,EACH;AACA,SAAO,CAAC,OAAO,QAAQ;AACzB;AAmCO,IAAM,0BAA0C;AAAA,EACrD,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,MAAM,CAAC,MAAM,WAAW,gBAAgB,IAAI,KAAK,MAAM;AAAA,EACvD,SAAS;AAAA,IACP,aAAa;AAAA,IACb,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ;AAAA,EACA,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,SAAS,CAAC,QAAQ,QAAQ,uCAAuC,MAAM,KAAK,GAAG;AAAA,EAC/E,YAAY;AAAA,EACZ,SAAS;AACX;AAEO,IAAM,4BAA6C;AAAA,EACxD,OAAO;AAAA,EACP,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,UAAU,CAAC,SAAS,aAAa,IAAI;AAAA,EACrC,aAAa;AACf;AAEA,IAAM,iBAAiB,CAAC,YAA6C,EAAE,GAAG,yBAAyB,GAAG,OAAO,SAAS;AAG/G,SAAS,iBAAiB,UAAiC,SAA0B,2BAAmC;AAC7H,QAAM,IAAI,eAAe,MAAM;AAC/B,QAAM,MAAM,QAAQ,SAAS,QAAQ,GAAG,OAAO,SAAS,MAAM,GAAG;AACjE,QAAM,SACJ,SAAS,WAAW,eAAe,EAAE,aAAa,SAAS,WAAW,gBAAgB,EAAE,UAAU,EAAE,QAAQ,SAAS,MAAM;AAC7H,SAAO,EAAE,QAAQ,QAAQ,GAAG;AAC9B;AAEA,IAAM,SAAS,CAAC,YAAoC;AAAA,EAClD,SAAS;AAAA,EACT,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,OAAO,SAAS,2BAA2B;AAAA,EAC3C,YAAY,SAAS,2BAA2B;AAAA,EAChD,QAAQ;AAAA,EACR,cAAc;AAChB;AAKO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA,SAAS;AACX,GAGG;AACD,QAAM,OAAO,aAAa,SAAY,SAAY,IAAI,KAAK,QAAQ,EAAE,mBAAmB;AACxF,SACE,gBAAAK;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,0BAAuB;AAAA,MACvB,OAAO,OAAO,OAAO,SAAS,IAAI,IAAI,OAAO;AAAA,MAC7C,OAAO;AAAA,QACL,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,KAAK;AAAA,QACL,SAAS;AAAA,QACT,UAAU;AAAA,QACV,YAAY;AAAA,QACZ,eAAe;AAAA,QACf,eAAe;AAAA,QACf,OAAO;AAAA,QACP,YAAY;AAAA,QACZ,QAAQ;AAAA,QACR,cAAc;AAAA,MAChB;AAAA,MAEA;AAAA,wBAAAD,MAAC,UAAK,eAAY,QAAQ,oBAAI;AAAA,QAC7B,OAAO;AAAA,QACP,OAAO,gBAAAA,MAAC,UAAK,OAAO,EAAE,YAAY,KAAK,eAAe,OAAO,GAAI,cAAI,IAAI,IAAG,IAAU;AAAA,QACvF,gBAAAA,MAAC,UAAK,gCAA6B,IAAG,OAAO,EAAE,YAAY,KAAK,eAAe,OAAO,GACnF,kBAAK,OAAO,WAAW,IAC1B;AAAA;AAAA;AAAA,EACF;AAEJ;AAGO,SAAS,oBAAoB,GAA0B;AAC5D,QAAM,IAAI,IAAI,KAAK,eAAe,QAAW,EAAE,MAAM,WAAW,OAAO,SAAS,KAAK,WAAW,MAAM,WAAW,QAAQ,WAAW,cAAc,QAAQ,CAAC;AAC3J,SAAO,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,WAAM,EAAE,OAAO,EAAE,IAAI,CAAC;AACpD;AAKO,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA,SAAS;AACX,GAGG;AACD,QAAM,IAAI,eAAe,MAAM;AAC/B,QAAM,MAAM,iBAAiB,QAAQ;AACrC,SACE,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,4BAAyB;AAAA,MACzB,OAAO,GAAG,IAAI,IAAI,WAAM,IAAI,EAAE;AAAA,MAC9B,OAAO;AAAA,QACL,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,UAAU;AAAA,QACV,KAAK;AAAA,QACL,SAAS;AAAA,QACT,UAAU;AAAA,QACV,YAAY;AAAA,QACZ,OAAO;AAAA,QACP,YAAY;AAAA,QACZ,QAAQ;AAAA,QACR,cAAc;AAAA,MAChB;AAAA,MAEA;AAAA,wBAAAD,MAAC,UAAK,OAAO,EAAE,eAAe,KAAK,eAAe,YAAY,GAAI,YAAE,OAAM;AAAA,QAC1E,gBAAAA,MAAC,UAAK,0BAAuB,IAAG,OAAO,EAAE,YAAY,IAAI,GACtD,8BAAoB,QAAQ,GAC/B;AAAA,QACA,gBAAAA,MAAC,UAAK,gCAA6B,IAAG,OAAO,EAAE,YAAY,IAAI,GAC5D,kBAAK,OAAO,WAAW,IAC1B;AAAA;AAAA;AAAA,EACF;AAEJ;AAIO,SAAS,gBAAgB,MAAc,GAA0B;AACtE,QAAM,MAAM,IAAI,IAAI,IAAI;AACxB,QAAM,EAAE,MAAM,GAAG,IAAI,iBAAiB,CAAC;AACvC,MAAI,aAAa,OAAO,OAAO;AAC/B,MAAI,aAAa,OAAO,QAAQ;AAChC,MAAI,aAAa,IAAI,QAAQ,IAAI;AACjC,MAAI,aAAa,IAAI,MAAM,EAAE;AAC7B,SAAO,IAAI,SAAS;AACtB;AASO,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA,SAAS;AAAA,EACT;AACF,GAMG;AACD,QAAM,MAAM,MAAM;AAClB,QAAM,SAAS,MAAM,SAAY,WAAW,MAAM,WAAW;AAC7D,QAAM,UAAUN,aAAY,MAAO,MAAM,SAAS,SAAS,OAAO,IAAI,SAAS,MAAM,GAAI,CAAC,MAAM,QAAQ,QAAQ,CAAC;AACjH,QAAM,IAAI,eAAe,MAAM;AAG/B,QAAM,CAAC,QAAQ,SAAS,IAAII,UAAiD;AAC7E,QAAM,CAAC,MAAM,OAAO,IAAIA,UAAS,KAAK;AACtC,QAAM,CAAC,YAAY,aAAa,IAAIA,UAAS,KAAK;AAClD,QAAM,CAAC,QAAQ,SAAS,IAAIA,UAAS,KAAK;AAC1C,QAAM,CAAC,aAAa,cAAc,IAAIA,UAAS,IAAI;AACnD,EAAAH,WAAU,MAAM,eAAe,IAAI,GAAG,CAAC,MAAM,CAAC;AAE9C,QAAM,aAAa,MAAM;AACvB,QAAI,MAAM;AACR,cAAQ,KAAK;AACb;AAAA,IACF;AACA,kBAAc,KAAK;AACnB,QAAI,QAAQ;AACV,cAAQ,IAAI;AACZ;AAAA,IACF;AACA,WAAO,4CAAyB,EAAE;AAAA,MAChC,CAAC,MAAM;AACL,kBAAU,MAAM,EAAE,OAAO;AACzB,gBAAQ,IAAI;AAAA,MACd;AAAA,MACA,MAAM,cAAc,IAAI;AAAA,IAC1B;AAAA,EACF;AAEA,QAAM,WAAW,MAAM;AACrB,QAAI,CAAC,IAAK;AACV,cAAU,WAAW,UAAU,gBAAgB,OAAO,SAAS,MAAM,GAAG,CAAC,EAAE;AAAA,MACzE,MAAM;AACJ,kBAAU,IAAI;AACd,eAAO,WAAW,MAAM,UAAU,KAAK,GAAG,GAAI;AAAA,MAChD;AAAA,MACA,MAAM;AAAA,IACR;AAAA,EACF;AAEA,SACE,gBAAAM,MAAC,SAAI,OAAO,EAAE,UAAU,YAAY,SAAS,gBAAgB,UAAU,OAAO,GAC5E;AAAA,oBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,uBAAoB;AAAA,QACpB,MAAK;AAAA,QACL,cAAY,OAAO;AAAA,QACnB,OAAO,EAAE,SAAS,eAAe,YAAY,UAAU,KAAK,GAAG,UAAU,OAAO;AAAA,QAI/E;AAAA,WAAC,OAAO,WAAW,SAClB,gBAAAD,MAAC,YAAO,MAAK,UAAS,gBAAa,QAAO,cAAYP,WAAU,MAAM,WAAW,GAAG,OAAO,OAAO,IAAI,GACnG,UAAAA,WAAU,MAAM,WAAW,GAC9B,IACE;AAAA,UACH,mBAAmB,IAAI,CAAC,MACvB,gBAAAO;AAAA,YAAC;AAAA;AAAA,cAEC,MAAK;AAAA,cACL,gBAAc,EAAE,OAAO;AAAA,cACvB,cAAY,EAAE;AAAA,cACd,SAAS,MAAM,SAAS,QAAQ,EAAE,OAAO;AAAA,cACzC,OAAO,OAAO,EAAE,OAAO,MAAM;AAAA,cAE5B,YAAE;AAAA;AAAA,YAPE,EAAE;AAAA,UAQT,CACD;AAAA,UACD,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,gBAAc,QAAQ;AAAA,cACtB,iBAAe;AAAA,cACf,0BAAuB;AAAA,cACvB,SAAS;AAAA,cACT,OAAO,OAAO,QAAQ,MAAS;AAAA,cAE9B,YAAE;AAAA;AAAA,UACL;AAAA,UACC,MACC,gBAAAC,MAAAF,WAAA,EACE;AAAA,4BAAAC,MAAC,YAAO,MAAK,UAAS,wBAAqB,IAAG,SAAS,MAAM,SAAS,OAAO,GAAG,OAAO,OAAO,KAAK,GAChG,YAAE,YACL;AAAA,YACA,gBAAAA,MAAC,YAAO,MAAK,UAAS,wBAAqB,IAAG,SAAS,UAAU,OAAO,OAAO,KAAK,GACjF,mBAAS,EAAE,aAAa,EAAE,UAC7B;AAAA,YACA,gBAAAA,MAAC,qBAAkB,UAAU,KAAK,QAAgB;AAAA,aACpD,IAEA,gBAAAC,MAAAF,WAAA,EACE;AAAA,4BAAAC,MAAC,YAAO,MAAK,UAAS,gBAAc,MAAM,QAAQ,yBAAsB,IAAG,SAAS,SAAS,OAAO,OAAO,MAAM,MAAM,GACpH,gBAAM,SAAS,OAAO,SAAS,OAAO,OACzC;AAAA,YACC,MAAM,SAAS,gBAAAA,MAAC,mBAAgB,UAAU,MAAM,UAAU,QAAgB,IAAK;AAAA,aAClF;AAAA;AAAA;AAAA,IAEJ;AAAA,IACC,QAAQ,SACP,gBAAAA,MAAC,SAAI,OAAO,EAAE,UAAU,YAAY,OAAO,GAAG,KAAK,QAAQ,WAAW,GAAG,QAAQ,GAAG,GAClF,0BAAAA;AAAA,MAAC;AAAA;AAAA,QACC,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,SAAS,CAAC,MAAM,OAAO;AACrB,gBAAM,UAAU,SAAS,YAAY,MAAM,EAAE;AAC7C,cAAI,CAAC,QAAS,SAAQ,KAAK;AAC3B,iBAAO;AAAA,QACT;AAAA,QACA,UAAU,MAAM,QAAQ,KAAK;AAAA;AAAA,IAC/B,GACF,IACE;AAAA,IACH,aACC,gBAAAA,MAAC,SAAI,MAAK,SAAQ,+BAA4B,IAAG,OAAO,EAAE,UAAU,IAAI,OAAO,0BAA0B,GACtG,YAAE,YACL,IACE;AAAA,IACH,UAAU,cACT,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,0BAAuB;AAAA,QACvB,OAAO,EAAE,SAAS,QAAQ,KAAK,GAAG,YAAY,YAAY,WAAW,GAAG,UAAU,IAAI,OAAO,+BAA+B;AAAA,QAE5H;AAAA,0BAAAD,MAAC,UAAK,OAAO,EAAE,UAAU,GAAG,cAAc,WAAW,GAAI,kBAAO;AAAA,UAChE,gBAAAA,MAAC,YAAO,MAAK,UAAS,SAAS,MAAM,eAAe,KAAK,GAAG,OAAO,EAAE,GAAG,OAAO,KAAK,GAAG,MAAM,WAAW,GACrG,YAAE,SACL;AAAA;AAAA;AAAA,IACF,IACE;AAAA,KACN;AAEJ;;;ACrYA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAOK;AACP,SAAS,eAAAE,cAAa,aAAAC,YAAW,UAAAC,SAAQ,YAAAC,iBAAgB;AAiCzD,IAAM,cAA4B,EAAE,QAAQ,CAAC,GAAG,SAAS,CAAC,GAAG,QAAQ,CAAC,EAAE;AAExE,SAAS,cAAc,QAAgB,YAA0C;AAC/E,QAAM,EAAE,OAAO,OAAO,IAAI,gBAAgB,QAAQ,UAAU;AAC5D,SAAO,OAAO,KAAK,KAAK,EAAE,SAAS,KAAK,OAAO,SAAS;AAC1D;AAEO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AACZ,GAOiB;AAMf,QAAM,CAAC,MAAM,OAAO,IAAIA,UAAqE,OAAO;AAAA,IAClG,WAAW,CAAC;AAAA,IACZ,QAAQ,aAAa,QAAQ,MAAM;AAAA,EACrC,EAAE;AACF,QAAM,EAAE,UAAU,IAAI;AACtB,QAAM,CAAC,OAAO,QAAQ,IAAIA;AAAA,IAA4B,MACpD,cAAc,QAAQ,QAAQ,UAAU,IAAI,aAAa;AAAA,EAC3D;AACA,QAAM,CAAC,UAAU,WAAW,IAAIA,UAA8B,IAAI;AAClE,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAiC,CAAC,CAAC;AAEjE,QAAM,gBAAgBD,QAAO,UAAU;AACvC,gBAAc,UAAU;AACxB,QAAM,cAAcA,QAAO,QAAQ;AACnC,cAAY,UAAU;AACtB,QAAM,aAAaA,QAAO,QAAQ,aAAa;AAC/C,aAAW,UAAU,QAAQ;AAI7B,QAAM,UAAUA,QAAsB,IAAI;AAC1C,QAAM,aAAaA,QAAO,CAAC;AAC3B,QAAM,CAAC,SAAS,UAAU,IAAIC,UAAS,CAAC;AAExC,QAAM,SAAS,QAAQ;AACvB,EAAAF,WAAU,MAAM;AACd,QAAI,CAAC,QAAS;AACd,UAAM,QAAQ,aAAa,MAAM;AAEjC,QAAI,QAAQ,YAAY,MAAO;AAC/B,YAAQ,UAAU;AAElB,UAAM,SAAS,gBAAgB,QAAQ,cAAc,OAAO;AAC5D,QAAI,OAAO,KAAK,OAAO,KAAK,EAAE,WAAW,KAAK,OAAO,OAAO,WAAW,GAAG;AACxE,iBAAW,WAAW;AACtB,cAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,MAAM,CAAC;AACxC,kBAAY,IAAI;AAChB,eAAS,OAAO;AAChB;AAAA,IACF;AACA,UAAM,MAAM,EAAE,WAAW;AACzB,aAAS,UAAU;AACnB,SAAK,cAAc,OAAO,OAAO,YAAY,OAAO,EAAE,KAAK,CAAC,UAAU;AACpE,UAAI,QAAQ,WAAW,QAAS;AAChC,iBAAW,MAAM,EAAE;AACnB,UAAI,OAAO,OAAO,WAAW,KAAK,MAAM,QAAQ,WAAW,KAAK,MAAM,OAAO,WAAW,GAAG;AACzF,gBAAQ,EAAE,WAAW,iBAAiB,MAAM,EAAE,GAAG,QAAQ,MAAM,CAAC;AAChE,oBAAY,IAAI;AAChB,iBAAS,OAAO;AAAA,MAClB,OAAO;AACL,oBAAY,EAAE,QAAQ,OAAO,QAAQ,SAAS,MAAM,SAAS,QAAQ,MAAM,OAAO,CAAC;AACnF,gBAAQ,CAAC,OAAO,EAAE,GAAG,GAAG,QAAQ,MAAM,EAAE;AACxC,iBAAS,SAAS;AAAA,MACpB;AAAA,IACF,CAAC;AAAA,EACH,GAAG,CAAC,QAAQ,SAAS,OAAO,CAAC;AAG7B,EAAAA,WAAU,MAAM;AACd,QAAI,CAAC,WAAW,UAAU,QAAS;AACnC,UAAM,UAAU,aAAa,MAAM;AACnC,QAAI,YAAY,KAAK,OAAQ;AAC7B,UAAM,OAAO,eAAe,QAAQ,iBAAiB,KAAK,WAAW,UAAU,CAAC;AAChF,UAAM,YAAY,aAAa,IAAI;AACnC,QAAI,cAAc,QAAS;AAC3B,YAAQ,UAAU;AAClB,YAAQ,CAAC,OAAO,EAAE,GAAG,GAAG,QAAQ,UAAU,EAAE;AAC5C,eAAW,QAAQ,IAAI;AAAA,EACzB,GAAG,CAAC,MAAM,YAAY,OAAO,SAAS,MAAM,CAAC;AAE7C,QAAM,SAASD,aAAY,CAAC,MAAuB;AACjD,YAAQ,CAAC,OAAO,EAAE,GAAG,GAAG,WAAW,EAAE,GAAG,EAAE,WAAW,CAAC,EAAE,IAAI,GAAG,EAAE,QAAQ,EAAE,EAAE;AAAA,EAC/E,GAAG,CAAC,CAAC;AACL,QAAM,QAAQA,aAAY,MAAM,QAAQ,CAAC,OAAO,EAAE,GAAG,GAAG,WAAW,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;AAE7E,QAAM,UAAUA,aAAY,MAAM;AAEhC,YAAQ,CAAC,OAAO,EAAE,GAAG,GAAG,WAAW,iBAAiB,OAAO,EAAE,EAAE;AAC/D,gBAAY,IAAI;AAChB,aAAS,OAAO;AAAA,EAClB,GAAG,CAAC,OAAO,CAAC;AACZ,QAAM,QAAQA,aAAY,MAAM;AAC9B,YAAQ,UAAU;AAClB,eAAW,CAAC,MAAM,IAAI,CAAC;AAAA,EACzB,GAAG,CAAC,CAAC;AAEL,SAAO,EAAE,WAAW,QAAQ,OAAO,OAAO,UAAU,UAAU,YAAa,YAAY,cAAe,MAAM,SAAS,MAAM;AAC7H;;;ACjLA,SAAS,OAAAI,MAAK,WAAAC,gBAAe;AA4CvB,gBAAAC,OAQA,QAAAC,aARA;AA9BC,SAAS,mBAAmB,EAAE,OAAO,OAAO,cAAc,WAAW,YAAY,QAAQ,GAA4B;AAC1H,QAAMC,UAAS;AAAA,IACb,WAAW;AAAA,IACX,SAAS;AAAA,IACT,cAAc;AAAA,IACd,QAAQ,aAAaJ,KAAI,QAAQ,CAAC;AAAA,IAClC,YAAYA,KAAI,MAAM;AAAA,IACtB,OAAOA,KAAI,YAAY;AAAA,IACvB,UAAUC,SAAQ,IAAI;AAAA,IACtB,QAAQ;AAAA,EACV;AACA,SACE,gBAAAE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,eAAY;AAAA,MACZ,OAAO;AAAA,QACL,WAAW;AAAA,QACX,SAAS;AAAA,QACT,eAAe;AAAA,QACf,YAAY;AAAA,QACZ,KAAK;AAAA,QACL,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,cAAc;AAAA,QACd,QAAQ,aAAaH,KAAI,QAAQ,CAAC;AAAA,QAClC,YAAYA,KAAI,MAAM;AAAA,QACtB,OAAOA,KAAI,YAAY;AAAA,MACzB;AAAA,MAEA;AAAA,wBAAAE,MAAC,SAAI,OAAO,EAAE,UAAUD,SAAQ,IAAI,GAAG,YAAY,IAAI,GAAI,iBAAM;AAAA,QACjE,gBAAAC,MAAC,QAAG,OAAO,EAAE,QAAQ,GAAG,aAAa,IAAI,SAAS,QAAQ,eAAe,UAAU,KAAK,GAAG,UAAUD,SAAQ,IAAI,EAAE,GAChH,gBAAM,IAAI,CAAC,MAAM,MAChB,gBAAAC,MAAC,QAAW,OAAO,EAAE,cAAc,WAAW,GAC3C,kBADM,CAET,CACD,GACH;AAAA,QACA,gBAAAC,MAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,UAAU,QAAQ,KAAK,EAAE,GACrD;AAAA,wBAAc,UACb,gBAAAD,MAAC,YAAO,MAAK,UAAS,OAAOE,SAAQ,SAAS,SAAS,eAAY,uBAChE,sBACH,IACE;AAAA,UACJ,gBAAAF,MAAC,YAAO,MAAK,UAAS,OAAOE,SAAQ,SAAS,WAAW,eAAY,yBAClE,wBACH;AAAA,WACF;AAAA;AAAA;AAAA,EACF;AAEJ;AAsBA,IAAM,WAAW;AACjB,IAAM,OAAO,CAAC,MAAe,EAAE,SAAS,WAAW,GAAG,EAAE,MAAM,GAAG,QAAQ,CAAC,WAAM;AAEzE,SAAS,6BACd,UACA,GACU;AACV,QAAM,MAAgB,CAAC;AACvB,aAAW,KAAK,SAAS,QAAQ;AAC/B,UAAM,OAAO,KAAK,EAAE,IAAI;AACxB,QAAI,EAAE,SAAS,eAAgB,KAAI,KAAK,EAAE,YAAY,IAAI,CAAC;AAAA,aAClD,EAAE,SAAS,oBAAqB,KAAI,KAAK,EAAE,eAAe,IAAI,CAAC;AAAA,aAC/D,EAAE,SAAS,iBAAkB,KAAI,KAAK,EAAE,cAAc,IAAI,CAAC;AAAA,aAC3D,EAAE,SAAS,eAAgB,KAAI,KAAK,EAAE,YAAY,IAAI,CAAC;AAAA,aACvD,EAAE,SAAS,gBAAiB,KAAI,KAAK,EAAE,aAAa,MAAM,KAAK,EAAE,KAAK,CAAC,CAAC;AAAA,SAC5E;AAEH,YAAM,YAAmB;AACzB,YAAM,IAAI,MAAM,qDAAqD,KAAK,UAAU,SAAS,CAAC,EAAE;AAAA,IAClG;AAAA,EACF;AACA,aAAW,KAAK,SAAS,QAAS,KAAI,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC;AACrE,aAAW,KAAK,SAAS,OAAQ,KAAI,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC;AACnE,SAAO;AACT;;;ACjGA,SAAS,uBAAAC,4BAA0E;AACnF,SAAS,wBAAAC,6BAAiD;;;ACHnD,IAAM,cAAgD;AAAA,EAC3D,OAAO;AAAA,EACP,MAAM;AAAA,EACN,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,mBAAmB;AAAA,EACnB,eAAe;AAAA,EACf,aAAa;AAAA,EACb,eAAe;AAAA,EACf,QAAQ;AAAA,EACR,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,OAAO;AAAA,EACP,UAAU;AAAA,EACV,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,OAAO;AAAA,EACP,UAAU;AAAA,EACV,cAAc;AAAA,EACd,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,qBAAqB;AAAA,EACrB,SAAS;AAAA,EACT,iBAAiB;AAAA,EACjB,aAAa;AAAA,EACb,cAAc;AAAA,EACd,iBAAiB;AAAA,EACjB,SAAS;AAAA,EACT,aAAa;AAAA,EACb,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,cAAc;AAAA,EACd,aAAa;AAAA,EACb,SAAS;AAAA,EACT,MAAM;AAAA,EACN,WAAW;AAAA,EACX,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,WAAW;AAAA,EACX,MAAM;AAAA,EACN,SAAS;AAAA,EACT,uBAAuB;AAAA,EACvB,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,qBAAqB;AAAA,EACrB,0BAA0B;AAAA,EAC1B,eAAe;AAAA,EACf,QAAQ;AAAA,EACR,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,UAAU;AAAA,EACV,WAAW;AAAA,EACX,MAAM;AACR;AAEO,IAAM,uBAAmF;AAAA,EAC9F,eAAe;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,OAAO;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,IACL,KAAK;AAAA,EACP;AAAA,EACA,gBAAgB;AAAA,IACd,OAAO;AAAA,EACT;AAAA,EACA,eAAe;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,OAAO;AAAA,IACP,KAAK;AAAA,IACL,KAAK;AAAA,EACP;AAAA,EACA,gBAAgB;AAAA,IACd,OAAO;AAAA,EACT;AAAA,EACA,eAAe;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,EACd;AAAA,EACA,SAAS;AAAA,IACP,OAAO;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,EACd;AAAA,EACA,iBAAiB;AAAA,IACf,OAAO;AAAA,IACP,SAAS;AAAA,EACX;AAAA,EACA,aAAa;AAAA,IACX,OAAO;AAAA,EACT;AAAA,EACA,iBAAiB;AAAA,IACf,mBAAmB;AAAA,EACrB;AAAA,EACA,mBAAmB;AAAA,IACjB,mBAAmB;AAAA,EACrB;AAAA,EACA,iBAAiB;AAAA,IACf,SAAS;AAAA,IACT,WAAW;AAAA,IACX,UAAU;AAAA,IACV,mBAAmB;AAAA,EACrB;AAAA,EACA,eAAe;AAAA,IACb,aAAa;AAAA,EACf;AAAA,EACA,kBAAkB;AAAA,IAChB,KAAK;AAAA,IACL,KAAK;AAAA,EACP;AAAA,EACA,oBAAoB;AAAA,IAClB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,SAAS;AAAA,IACT,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,aAAa;AAAA,IACX,SAAS;AAAA,EACX;AAAA,EACA,kBAAkB;AAAA,IAChB,SAAS;AAAA,IACT,aAAa;AAAA,IACb,cAAc;AAAA,IACd,iBAAiB;AAAA,EACnB;AACF;;;AD9HA,SAAS,gBAAgB,UAAkB,OAA0B,QAAmC;AACtG,QAAM,MAA+B,CAAC;AACtC,aAAW,CAAC,KAAK,IAAI,KAAK,OAAO,QAAQ,KAAK,GAAG;AAC/C,UAAM,OAAO,GAAG,MAAM,GAAG,GAAG;AAC5B,UAAM,OAAgC,EAAE,GAAG,KAAK;AAChD,UAAM,MAAM,qBAAqB,QAAQ,IAAI,IAAI,KAAK,YAAY,IAAI;AACtE,QAAI,QAAQ,OAAW,MAAK,MAAM;AAClC,QAAI,UAAU,QAAQ,KAAK,KAAM,MAAK,OAAO,gBAAgB,UAAU,KAAK,MAA2B,GAAG,IAAI,GAAG;AAGjH,QAAI,GAAG,IAAI;AAAA,EACb;AACA,SAAO;AACT;AAEA,SAAS,mBAA+C,YAAkB;AACxE,SAAO,EAAE,GAAG,YAAY,SAAS,gBAAgB,WAAW,IAAI,WAAW,SAAS,EAAE,EAAE;AAC1F;AAEA,SAAS,YAAwD,aAAmB;AAClF,SAAO,OAAO,YAAY,OAAO,QAAQ,WAAW,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,mBAAmB,CAAC,CAAC,CAAC,CAAC;AACrG;AAEO,IAAMC,4BAA2C,4BAAY,wBAAkB;AAEtF,SAAS,UAAU,aAA+C;AAChE,SAAOC,qBAAoB,OAAO,OAAO,WAAW,CAAC;AACvD;AAEO,IAAMC,wBAAuC,0BAAUF,yBAAwB;AAGtF,SAAS,oBAA2E,aAAmB;AACrG,QAAM,OAAyCA;AAC/C,SAAO,YAAY,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,YAAY,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE;AAC7E;AAEO,IAAMG,4BAA2C,oCAAoB,wBAAkB;AAIvF,SAASC,+BAA8C;AAC5D,SAAOC,sBAAqBF,yBAAwB;AACtD;AAIA,SAAS,YAAwD,aAA8D;AAC7H,SAAO,OAAO,OAAO,OAAO,YAAY,OAAO,QAAQ,WAAW,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;AAGxG;AAEO,IAAM,iBAAiC,4BAAYH,yBAAwB;;;AEtElF,eAAsB,eAAe,UAA0B,OAAwC;AACrG,QAAM,QAA4B,CAAC;AACnC,aAAW,QAAQ,IAAI,IAAI,KAAK,GAAG;AACjC,UAAM,UAAW,SAAS,eAAe,IAAI,GAAG,WAAiD;AACjG,QAAI,OAAO,YAAY,WAAY,OAAM,KAAM,QAAmC,EAAE,MAAM,MAAM,MAAS,CAAC;AAAA,EAC5G;AACA,QAAM,QAAQ,IAAI,KAAK;AACzB;;;ACCA,IAAM,UAAU,OAAO,QAAQ,wBAAwB;AAGhD,IAAM,iBAAiF,OAAO;AAAA,EACnG,OAAO,YAAY,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC9D;AAIO,IAAM,0BAAwE,OAAO;AAAA,EAC1F,OAAO,YAAY,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,SAAS,MAAM,CAAC,CAAC;AACjF;;;ACkCA,SAAS,cAAAM,aAAY,cAAAC,mBAA0D;;;AC5C/E;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAQK;AAyBA,IAAMC,kBAA8B,OAAO;AAAA,EAChD,OAAO,YAAY,OAAO,QAAQ,wBAAwB,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC/F;AAEA,SAAS,eAAe,YAAqD;AAC3E,SAAO,qBAAqB,IAAI,UAAU,GAAG,eAAe,CAAC;AAC/D;AAsCO,SAAS,sBACd,YACA,SACe;AACf,QAAM,QAA2BA,gBAAe,UAAU;AAC1D,SAAO,gBAAgB,OAAO,SAAS,EAAE,aAAa,eAAe,UAAU,GAAG,OAAO,WAAW,CAAC,EAAE;AAAA,IACrG,CAAC,EAAE,KAAK,MAAM,QAAQ,OAAO,EAAE,YAAY,KAAK,MAAM,QAAQ;AAAA,EAChE;AACF;AAKO,SAAS,iBAAiB,MAAkB,KAA2C;AAC5F,SAAO,WAAWA,gBAAe,IAAI,GAAG,GAAG;AAC7C;AAIO,SAAS,iBAAiB,MAAkB,KAA4C;AAC7F,SAAO,WAAWA,gBAAe,IAAI,GAAG,GAAG;AAC7C;;;AC7FA;AAAA,EACE,uBAAAC;AAAA,EACA,mBAAAC;AAAA,OAKK;AAsCA,SAAS,0BACd,YACA,UAAuC,CAAC,GACf;AACzB,SAAO,WAAW,QAAQ,QAAQ,CAAC,WAAW;AAC5C,QAAI,OAAO,SAASC,qBAAqB,QAAO,CAAC;AACjD,UAAM,OAAO,OAAO;AACpB,UAAM,aAAa,cAAc,MAAM,QAAQ,OAAO;AACtD,WAAOC,iBAAgB,WAAW,SAAS,OAAO,SAAS;AAAA,MACzD,aAAa,WAAW;AAAA,MACxB,OAAO;AAAA,IACT,CAAC,EAAE,IAAI,CAAC,EAAE,KAAK,MAAM,QAAQ,OAAO,EAAE,YAAY,MAAM,KAAK,MAAM,SAAS,UAAU,OAAO,GAAG,EAAE;AAAA,EACpG,CAAC;AACH;AAYA,SAAS,cAAc,MAAc,SAAsD;AACzF,QAAM,aAAa,SAAS,IAAI,IAAI,KAAK,qBAAqB,IAAI,IAAI;AACtE,MAAI,CAAC,YAAY;AACf,UAAM,IAAI,MAAM,6BAA6B,IAAI,6DAA6D;AAAA,EAChH;AACA,SAAO;AACT;AAyBO,SAAS,oBAA6C,YAAe,UAAuC,CAAC,GAAM;AACxH,MAAI,UAAU;AACd,QAAM,UAAU,WAAW,QAAQ,IAAI,CAAC,WAAW;AACjD,UAAM,WAAW,0BAA0B,QAAQ,QAAQ,OAAO;AAClE,QAAI,aAAa,OAAQ,WAAU;AACnC,WAAO;AAAA,EACT,CAAC;AACD,SAAO,UAAU,EAAE,GAAG,YAAY,QAAQ,IAAI;AAChD;AAEA,SAAS,0BAA0B,QAAwB,SAAoD;AAG7G,QAAM,MAAM,OAAO;AACnB,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,QAAQ,cAAc,OAAO,MAAM,OAAO,EAAE;AAIlD,QAAM,OAAO,OAAO,KAAK,GAAG;AAC5B,QAAM,OAAO,KAAK,OAAO,CAAC,QAAQ,OAAO,UAAU,eAAe,KAAK,OAAO,GAAG,CAAC;AAClF,MAAI,KAAK,WAAW,KAAK,OAAQ,QAAO;AACxC,QAAM,UAAmC,CAAC;AAC1C,aAAW,OAAO,KAAM,SAAQ,GAAG,IAAI,IAAI,GAAG;AAC9C,SAAO,EAAE,GAAG,QAAQ,QAAQ;AAC9B;;;AFGA;AAAA,EACE,eAAAC;AAAA,EACA,yBAAAC;AAAA,EACA,wBAAAC;AAAA,EACA,mBAAAC;AAAA,EACA,0BAAAC;AAAA,EACA,qBAAAC;AAAA,EACA,2BAAAC;AAAA,EACA;AAAA,EACA,4BAAAC;AAAA,EACA,uBAAAC;AAAA,EACA,oBAAAC;AAAA,EACA,kBAAAC;AAAA,EACA,wBAAAC;AAAA,EACA;AAAA,EACA,gBAAAC;AAAA,EACA,wBAAAC;AAAA,EACA,kBAAAC;AAAA,EACA,oBAAAC;AAAA,EACA,qBAAAC;AAAA,EACA,6BAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAAC;AAAA,OAaK;AACP;AAAA,EACE,UAAAC;AAAA,EACA,mBAAAC;AAAA,EACA,oBAAAC;AAAA,EACA;AAAA,EACA,iBAAAC;AAAA,OAKK;",
|
|
6
|
-
"names": ["UNKNOWN_WIDGET_TYPE", "useCallback", "useEffect", "useMemo", "useRef", "useState", "useWidgetScale", "useWidgetTimeRange", "useCallback", "useEffect", "useMemo", "useState", "defineWidget", "chunk", "defineWidget", "defineWidget", "chunk", "defineWidget", "defineWidget", "chunk", "defineWidget", "defineWidget", "chunk", "defineWidget", "defineWidget", "chunk", "defineWidget", "defineWidget", "defineWidget", "defineWidget", "optString", "WidgetFrame", "jsx", "optString", "WidgetFrame", "defineWidget", "css", "defineWidget", "fontVar", "optNumber", "optString", "WidgetFrame", "jsx", "optString", "optNumber", "fontVar", "WidgetFrame", "css", "defineWidget", "useMemo", "css", "defineWidget", "fontVar", "formatValue", "optBoolean", "optNumber", "optString", "optThresholds", "pickSample", "primaryMeasurementName", "spaceVar", "useFlashOnChange", "WidgetFrame", "jsx", "jsxs", "primaryMeasurementName", "pickSample", "optString", "optNumber", "formatValue", "useMemo", "optThresholds", "css", "useFlashOnChange", "optBoolean", "WidgetFrame", "spaceVar", "fontVar", "defineWidget", "defineWidget", "loadChartEngine", "chunk", "defineWidget", "loadChartEngine", "useEffect", "useState", "
|
|
3
|
+
"sources": ["../src/dashboard-renderer.tsx", "../src/connected-widget.tsx", "../src/builtin-registry.ts", "../src/widgets/aggregate-lazy.tsx", "../src/builtin-descriptors.ts", "../src/widgets/alarm-lazy.tsx", "../src/widgets/control-lazy.tsx", "../src/widgets/history-lazy.tsx", "../src/widgets/presence-lazy.tsx", "../src/widgets/selection-lazy.tsx", "../src/widgets/gauge.tsx", "../src/widgets/no-reading-lazy.tsx", "../src/widgets/image.tsx", "../src/widgets/label.tsx", "../src/widgets/latest-card.tsx", "../src/widgets/level-lazy.tsx", "../src/widgets/map.tsx", "../src/widgets/map-geometry.ts", "../src/widgets/table-lazy.tsx", "../src/widgets/time-series-chart.tsx", "../src/default-registry.ts", "../src/widget-containment.tsx", "../src/widget-host.ts", "../src/time-range-bar.tsx", "../src/use-bound-devices.ts", "../src/bound-devices-notice.tsx", "../src/documented-descriptors.ts", "../src/builtin-option-docs.ts", "../src/preload.ts", "../src/registry.ts", "../src/index.ts", "../src/options.ts", "../src/definition-options.ts"],
|
|
4
|
+
"sourcesContent": ["// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// DashboardRenderer maps a parsed DashboardDefinition onto a real CSS Grid of SQUARE cells: the\n// canvas is `display:grid` with `repeat(columns, 1fr)`, so the board FILLS whatever width its\n// container gives it, and every row is as tall as a column is wide (the cell size is computed in\n// CSS from the grid's own width, `100cqw`, so it needs no measurement and has no first-frame\n// flash). A `grid` widget occupies its footprint (`grid-column`/`grid-row`); a `relative` widget\n// is drawn over its host's area at the host's anchor point, offset in cell pitches, and above\n// every grid widget. Gutters and padding are lengths or spacing tokens scaled by the density;\n// each widget's frame is the canvas default merged with its own (resolveFrame).\n//\n// Adaptive columns and reflow: the board measures its CONTAINER (not the window), and while a\n// cell at the authored column count is at least `minCellSize` it renders as authored and the\n// cells stretch. Narrower than that the column count drops to what fits and the base layout is\n// poured into it in reading order (effectiveLayout), each widget clamped into the span limits\n// its descriptor declares; below STACK_BELOW_WIDTH (a phone) that is a single column. A breakpoint the author defined for the width wins over the automatic\n// reflow. Until the container has a measured width the authored layout is drawn. Container sizing\n// (fill / fixed-width / fixed-height) is a mount knob the host may override via the `sizing`\n// prop. It is view-only; the canvas editor lives in the console. This is the shared viewer the\n// console and the reference /dash app mount.\n\nimport {\n anchorFraction,\n DEFAULT_CANVAS_DENSITY,\n DEFAULT_TIME_RANGE_SECONDS,\n defaultHistoryWindow,\n effectiveLayout,\n historyWindowFor,\n initialTimeRange,\n fetchWidgetHistory,\n layoutShape,\n resolveFrame,\n resolvePlacement,\n resolveWidgetDatasource,\n spanLimitsOfLayout,\n UNKNOWN_WIDGET_TYPE,\n type CanvasBackground,\n type CanvasDensity,\n type CanvasGrid,\n type CanvasSizing,\n type DashboardDefinition,\n type GridLength,\n type GridPlacement,\n type RelativePlacement,\n type WidgetActions,\n type WidgetDataSource,\n type MeasurementSample,\n type SlotBinding,\n type TimeRangeState,\n type WidgetFrameSpec,\n type WidgetInstance,\n} from '@devicechain/dashboards';\nimport {\n densityScale,\n tokenStyle,\n WidgetDensityProvider,\n WidgetFrameStyleProvider,\n WidgetTimeRangeProvider,\n WidgetTokenStyles,\n type WidgetRegistry,\n} from '@devicechain/widget-sdk';\nimport { Fragment, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, type CSSProperties, type ReactNode, type RefObject } from 'react';\n\nimport { measurementSpan, takesHistorySeed } from './binding-policy';\nimport { ConnectedWidget } from './connected-widget';\nimport {\n type WidgetCandidates,\n WidgetCandidatesProvider,\n type WidgetSelect,\n WidgetSelectProvider,\n WidgetSubjectProvider,\n WidgetThemeRootProvider,\n WidgetTimeZoneProvider,\n} from '@devicechain/widget-sdk';\nimport { defaultWidgetRegistry } from './default-registry';\n\nexport interface DashboardRendererProps {\n definition: DashboardDefinition;\n hub: WidgetDataSource;\n // The widget registry that resolves every widget's component, channel, binding policy and\n // history eligibility. Omitted = the built-ins. A host with extension packages passes the\n // SAME registry it parsed `definition` with (parseDashboardDefinition(raw, { catalog:\n // registry.catalog })), so an extension widget is recognized and rendered consistently.\n registry?: WidgetRegistry;\n // The action seam (writes) for acting widgets (alarm ack/clear, command send). Omit\n // for a strictly read-only mount; the same instance as `hub` when the runtime provides\n // both (DashboardHub / SyntheticDataSource implement WidgetActions).\n actions?: WidgetActions;\n // Whether to backfill each widget from bucketedMeasurements (a real backend call).\n // Default true; set false for offline preview, where the data source (e.g.\n // SyntheticDataSource) supplies its own history and the backend must not be hit.\n seedHistory?: boolean;\n // The settled slot manifest (useResolvedBindings). Every widget's `slot` selector is\n // resolved through it HERE, before the widget subscribes, to the bound device or anchor\n // \u2014 or to an explicit `unbound` selector when the slot has no binding. The hub holds no\n // bindings, so a host keeps ONE hub (useDashboardHub) and a change to this map\n // re-subscribes only the widgets whose slot moved. Omitted = no slot is bound.\n bindings?: Record<string, SlotBinding>;\n // Host override for the definition's container sizing (the embed knob \u2014 a host can\n // force a dashboard authored `fill` into a fixed-px box, or vice versa). Omitted \u2192\n // the definition's own `canvas.sizing`.\n sizing?: CanvasSizing;\n // The selection callback (ADR-039 selection amendment): a widget (e.g. an alarm-table\n // originator drill) calls it to re-point a slot; the host accumulates it into the\n // selection overlay that produces `bindings`. Omit for a static dashboard \u2014 widgets\n // then render no drill affordance.\n select?: WidgetSelect;\n // The candidate provider (useSlotCandidates) an entity-selector widget reads to offer a\n // target slot's options. Omit alongside `select` for a static/edit/preview mount \u2014 the\n // selector then renders inert.\n candidates?: WidgetCandidates;\n // The IANA zone widgets print instants in. Omit for the viewer's own zone (every live\n // host); a host replaying a recording pins one so the board agrees with the recording.\n timeZone?: string;\n // The element chart colors are read from, when the host scopes its design tokens to a\n // container rather than the document root. Omit for the document root (every other host).\n themeRoot?: Element;\n // A viewer's density override (the /dash app's `?density=`). Wins over the definition's\n // authored `canvas.density`, which wins over `comfortable`. Density scales every size token\n // (font, spacing) and the floor of the value-font curve, never the curve itself.\n density?: CanvasDensity;\n // The board's time range: the span its time-series widgets draw, and whether the viewer has\n // frozen it. Owned by the host (useBoardTimeRange + TimeRangeBar) so the control can live in the\n // host's own header. Omitted = live over the definition's default span (or one hour), with no\n // control -- a static embed, the replay page, an edit preview.\n timeRange?: TimeRangeState;\n}\n\nexport function DashboardRenderer({\n definition,\n hub,\n registry: registryProp,\n actions,\n seedHistory = true,\n bindings,\n sizing,\n select,\n candidates,\n timeZone,\n themeRoot,\n density,\n timeRange,\n}: DashboardRendererProps) {\n // Each widget with its slot resolved to a concrete selector. Recomputed per render;\n // that is cheap, and every channel keys its subscription on the selector's VALUE, so a\n // widget whose concrete selector did not change keeps its subscription.\n const widgets = useMemo(() => resolveWidgets(definition.widgets, bindings), [definition.widgets, bindings]);\n const registry = registryProp ?? defaultWidgetRegistry();\n // The default is derived, not stored: a host with no control still gets the board's own span.\n const defaultSeconds = definition.timeRange?.defaultSeconds;\n const range = useMemo(\n () => timeRange ?? initialTimeRange(defaultSeconds),\n [timeRange, defaultSeconds],\n );\n const { histories, reseed } = useWidgetHistories(widgets, seedHistory, registry, range);\n // Each fixed window is its own board state: entering, leaving or moving one remounts the widgets,\n // so no live buffer (samples from after the window) and no held snapshot carries across it.\n const windowKey = windowTag(range);\n\n const { grid, background: bg, frame: canvasFrame } = definition.canvas;\n const effectiveSizing = sizing ?? definition.canvas.sizing;\n const effectiveDensity = density ?? definition.canvas.density ?? DEFAULT_CANVAS_DENSITY;\n const scale = densityScale(effectiveDensity);\n // The width is kept only when it changes the layout's shape (breakpoint, columns, single\n // column): within one shape the cells stretch through CSS, so a resize redraws nothing until\n // a column comes or goes.\n const { canvas } = definition;\n const shapeKey = useCallback((width: number) => JSON.stringify(layoutShape(canvas, width, scale)), [canvas, scale]);\n const [boardRef, containerWidth] = useContainerWidth<HTMLDivElement>(shapeKey);\n const layout = useMemo(\n () =>\n effectiveLayout(definition, containerWidth, {\n scale,\n limitsOf: (w) => (w.type === UNKNOWN_WIDGET_TYPE ? undefined : spanLimitsOfLayout(registry.descriptor(w.type)?.layout)),\n }),\n [definition, containerWidth, scale, registry],\n );\n const { breakpoint, columns } = layout;\n const lengths = gridCss(grid, columns);\n\n return (\n <div\n ref={boardRef}\n data-density={effectiveDensity}\n data-columns={columns}\n data-time-paused={range.paused ? '' : undefined}\n style={{ ...sizingStyle(effectiveSizing, bg), ...tokenStyle(scale) }}\n >\n <WidgetTokenStyles />\n <WidgetDensityProvider scale={scale}>\n <WidgetThemeRootProvider root={themeRoot}>\n <WidgetTimeZoneProvider timeZone={timeZone}>\n <WidgetTimeRangeProvider range={range}>\n <WidgetSelectProvider select={select}>\n <WidgetCandidatesProvider candidates={candidates}>\n <div style={{ padding: lengths.padding }}>\n {/* The query container: its width is the grid's, so 100cqw below is the grid width. */}\n <div style={{ containerType: 'inline-size' }}>\n <div\n data-grid=\"\"\n style={{\n display: 'grid',\n gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,\n gridAutoRows: CELL,\n columnGap: lengths.gutterX,\n rowGap: lengths.gutterY,\n width: '100%',\n ...({ '--dc-cell': lengths.cell } as CSSProperties),\n }}\n >\n <PlacedWidgets\n widgets={widgets}\n breakpoint={breakpoint}\n columns={columns}\n grid={layout.grid}\n lengths={lengths}\n render={(widget) => (\n <WidgetFrameStyleProvider frame={resolveFrame(canvasFrame, widgetFrame(widget))}>\n <WidgetSubjectProvider label={widgetSubjectLabel(widget)}>\n <ConnectedWidget\n key={windowKey}\n widget={widget}\n hub={hub}\n registry={registry}\n actions={actions}\n initialSamples={histories[widget.id]?.samples}\n initialSamplesAsOf={histories[widget.id]?.asOf}\n onReconnect={() => reseed(widget.id)}\n />\n </WidgetSubjectProvider>\n </WidgetFrameStyleProvider>\n )}\n />\n </div>\n </div>\n </div>\n </WidgetCandidatesProvider>\n </WidgetSelectProvider>\n </WidgetTimeRangeProvider>\n </WidgetTimeZoneProvider>\n </WidgetThemeRootProvider>\n </WidgetDensityProvider>\n </div>\n );\n}\n\n// The live cell size, as the grid element defines it.\nconst CELL = 'var(--dc-cell)';\n\n// The grid's lengths as CSS: px multiply by the density scale like every size token, and a\n// spacing token reads the board's own variable.\nexport interface GridCss {\n gutterX: string;\n gutterY: string;\n padding: string;\n // The live cell size: the grid's width less its gutters, shared by the columns. Read inside\n // the query container, so `100cqw` is the grid's width.\n cell: string;\n}\n\nexport function gridLengthCss(len: GridLength): string {\n if (typeof len === 'number') return `calc(${len}px * var(--dc-scale, 1))`;\n return len === 'space-0' ? '0px' : `var(--dc-${len})`;\n}\n\nexport function gridCss(grid: CanvasGrid, columns: number): GridCss {\n const g = grid.gutter;\n const gutterX = gridLengthCss(typeof g === 'object' ? g.x : g);\n const gutterY = gridLengthCss(typeof g === 'object' ? g.y : g);\n const p = grid.padding;\n const padding =\n typeof p === 'object'\n ? [p.top, p.right, p.bottom, p.left].map(gridLengthCss).join(' ')\n : gridLengthCss(p);\n return { gutterX, gutterY, padding, cell: `calc((100cqw - ${columns - 1} * ${gutterX}) / ${columns})` };\n}\n\n// The frame override a widget carries (a placeholder carries none: its stored frame is the\n// newer release's to read).\nfunction widgetFrame(widget: WidgetInstance): WidgetFrameSpec | undefined {\n return widget.type === UNKNOWN_WIDGET_TYPE ? undefined : widget.frame;\n}\n\n// gridItemStyle maps a grid placement to a grid-item style. col/row are 0-based cells \u2192\n// CSS's 1-based `col+1 / span cols`. It CLAMPS the placement into the grid's column count: a\n// footprint whose `col`/`cols` overruns `columns` (a hand-authored or imported one; the lint\n// reports it) would otherwise land in implicit `auto` tracks CSS appends past the `1fr`\n// columns \u2014 unequal widths + horizontal overflow instead of a clamped placement. Rows are\n// unbounded (implicit rows are the intended vertical growth), so only columns clamp.\nexport function gridItemStyle(p: GridPlacement, columns: number): CSSProperties {\n const col = Math.min(Math.max(0, p.col), columns - 1);\n const cols = Math.min(Math.max(1, p.cols), columns - col);\n return {\n gridColumn: `${col + 1} / span ${cols}`,\n gridRow: `${p.row + 1} / span ${p.rows}`,\n // Let a grid item shrink below its content's intrinsic size so a wide chart/table\n // fits its track instead of overflowing it.\n minWidth: 0,\n minHeight: 0,\n };\n}\n\n// Relative widgets paint above every grid widget, in `layer` order among themselves.\nconst RELATIVE_Z = 100;\n\n// relativeBoxStyle positions a relative widget inside its host's box (the containing block): the\n// host's anchor point (a percentage of the host), minus this widget's own `self` point (a\n// percentage of itself, via translate), plus the offset in cell pitches.\nexport function relativeBoxStyle(p: RelativePlacement, lengths: Pick<GridCss, 'gutterX' | 'gutterY'>): CSSProperties {\n const a = anchorFraction(p.anchor);\n const s = anchorFraction(p.self ?? p.anchor);\n const span = (n: number, gutter: string) => `calc(${n} * ${CELL} + ${n - 1} * ${gutter})`;\n const pitches = (n: number, gutter: string) => `${n} * (${CELL} + ${gutter})`;\n const fill = 'fill' in p.size;\n return {\n position: 'absolute',\n left: `calc(${a.fx * 100}% + ${pitches(p.offset?.x ?? 0, lengths.gutterX)})`,\n top: `calc(${a.fy * 100}% + ${pitches(p.offset?.y ?? 0, lengths.gutterY)})`,\n width: fill ? '100%' : span((p.size as { cols: number }).cols, lengths.gutterX),\n height: fill ? '100%' : span((p.size as { rows: number }).rows, lengths.gutterY),\n transform: `translate(${-s.fx * 100}%, ${-s.fy * 100}%)`,\n zIndex: RELATIVE_Z + (p.layer ?? 0),\n pointerEvents: 'auto',\n };\n}\n\n// PlacedWidgets draws every widget at a breakpoint: each grid widget as a grid item, and each\n// relative widget inside a layer over its host's grid area (a relative widget hosted on another\n// relative widget is drawn inside that one's box, one level deep, as the parser allows).\nfunction PlacedWidgets({\n widgets,\n breakpoint,\n columns,\n grid,\n lengths,\n render,\n}: {\n widgets: WidgetInstance[];\n breakpoint: string;\n columns: number;\n // Where each grid widget is DRAWN: its authored footprint, or the reflowed one.\n grid: ReadonlyMap<string, GridPlacement>;\n lengths: GridCss;\n render: (widget: WidgetInstance) => ReactNode;\n}) {\n const placed = widgets.map((w) => ({ widget: w, placement: resolvePlacement(w.layout, breakpoint) }));\n const dependents = new Map<string, { widget: WidgetInstance; placement: RelativePlacement }[]>();\n for (const { widget, placement } of placed) {\n if (placement.mode !== 'relative') continue;\n dependents.set(placement.host, [...(dependents.get(placement.host) ?? []), { widget, placement }]);\n }\n const relative = (host: string): ReactNode =>\n (dependents.get(host) ?? []).map(({ widget, placement }) => (\n // data-widget names the box a widget occupies, so a check over the rendered board (the\n // readability gate in apps/board-replay) can find it.\n <div key={widget.id} data-widget={widget.id} data-host={host} style={relativeBoxStyle(placement, lengths)}>\n {render(widget)}\n {relative(widget.id)}\n </div>\n ));\n return (\n <>\n {placed.map(({ widget, placement }) => {\n if (placement.mode !== 'grid') return null;\n const style = gridItemStyle(grid.get(widget.id) ?? placement, columns);\n // Keyed by the widget, so removing or reordering widgets never remounts (and so never\n // re-subscribes) the ones that stay.\n return (\n <Fragment key={widget.id}>\n <div data-widget={widget.id} style={style}>\n {render(widget)}\n </div>\n {dependents.has(widget.id) ? (\n // The host's area again, as a layer for its relative widgets to be positioned in.\n // It takes no pointer events itself, so the host underneath stays usable.\n <div style={{ ...style, position: 'relative', pointerEvents: 'none', zIndex: RELATIVE_Z }}>\n {relative(widget.id)}\n </div>\n ) : null}\n </Fragment>\n );\n })}\n </>\n );\n}\n\n// sizingStyle turns the container-sizing knob into the outer wrapper's box. `fill`\n// takes the mount container's full width+height (the grid fills it); `{width}` caps\n// the width (the fluid grid adjusts within it); `{height}` pins the height (rows\n// scroll). All scroll internally so the board owns its single scroll region. The\n// background (color AND image) paints on this wrapper so it covers the whole container\n// even when the grid's rows are shorter than the sizing box.\nexport function sizingStyle(sizing: CanvasSizing, bg: CanvasBackground | undefined): CSSProperties {\n const base: CSSProperties = {\n overflow: 'auto',\n backgroundColor: bg?.color ?? undefined,\n backgroundImage: bg?.imageUrl ? `url(${bg.imageUrl})` : undefined,\n backgroundSize: 'cover',\n };\n if (sizing === 'fill') return { ...base, width: '100%', height: '100%' };\n if ('width' in sizing) return { ...base, width: sizing.width, maxWidth: '100%', height: '100%' };\n return { ...base, width: '100%', height: sizing.height };\n}\n\n// resolveWidgets maps each widget's datasource through the settled bindings\n// (resolveWidgetDatasource): a slot becomes the device or anchor it is bound to, or an\n// explicit `unbound` selector. A widget with no datasource keeps none \u2014 that is a\n// different fact (tenant-wide on the alarm channel) and must not be manufactured here.\nexport function resolveWidgets(\n widgets: WidgetInstance[],\n bindings: Record<string, SlotBinding> | undefined,\n): WidgetInstance[] {\n return widgets.map((widget) => {\n if (widget.type === UNKNOWN_WIDGET_TYPE || widget.datasource?.kind !== 'slot') return widget;\n return { ...widget, datasource: resolveWidgetDatasource(widget.datasource, bindings) };\n });\n}\n\n// widgetSubjectLabel names the entity a widget shows \u2014 its CONCRETE datasource's device\n// or anchor \u2014 for the frame subtitle. Pass the widget as the renderer resolved it\n// (resolveWidgets), so the subtitle is read from the same selector the widget subscribes\n// with and can never name an entity other than the one being shown. Returns undefined for\n// a datasource-free widget (label/image, a tenant-wide alarm tile), an unbound slot, an\n// unresolved slot, or a reserved selector kind \u2014 the frame then shows no subtitle.\nexport function widgetSubjectLabel(widget: WidgetInstance): string | undefined {\n const ds = widget.datasource;\n if (!ds) return undefined;\n if (ds.kind === 'device') return ds.deviceToken || undefined;\n if (ds.kind === 'anchor') return ds.anchor.targetToken;\n return undefined;\n}\n\n// useContainerWidth tracks an element's content width with a ResizeObserver, measured\n// synchronously before first paint so a narrow container never flashes the authored layout. 0\n// means \"not measured\" (no layout engine, or not yet laid out) and draws the authored layout.\n// A new width is taken only when `keyOf` tells it apart from the one held, so a resize that\n// does not change what is drawn does not re-render; a new `keyOf` re-measures under its rule.\nfunction useContainerWidth<T extends HTMLElement>(keyOf: (width: number) => string): [RefObject<T | null>, number] {\n const ref = useRef<T>(null);\n const [width, setWidth] = useState(0);\n const keyOfRef = useRef(keyOf);\n const measure = useCallback(() => {\n const el = ref.current;\n if (!el) return;\n const next = el.clientWidth;\n setWidth((prev) => (keyOfRef.current(prev) === keyOfRef.current(next) ? prev : next));\n }, []);\n useLayoutEffect(() => {\n keyOfRef.current = keyOf;\n measure();\n }, [keyOf, measure]);\n useLayoutEffect(() => {\n const el = ref.current;\n if (!el || typeof ResizeObserver === 'undefined') return;\n const ro = new ResizeObserver(measure);\n ro.observe(el);\n return () => ro.disconnect();\n }, [measure]);\n return [ref, width];\n}\n\n// A widget's seed, tagged with the concrete selector it was fetched for, and when it was read up to.\ninterface Seed {\n key: string;\n // The fixed window it was read for ('' for a rolling range): see windowTag.\n window: string;\n samples: MeasurementSample[];\n asOf: number;\n}\n\n// A fixed window's identity, '' for a rolling range. A seed belongs to the window it was read for:\n// one read for the live board ends now, and handed to a window yesterday it would draw the last\n// hour under a \"Fixed window\" label (two windows of the same length differ only by this).\nfunction windowTag(range: TimeRangeState): string {\n return range.absolute ? `${range.absolute.fromMs}-${range.absolute.toMs}` : '';\n}\n\n// What a measurement widget is handed: its seed and the instant the seed was read up to.\ninterface WidgetHistory {\n samples: MeasurementSample[];\n asOf: number;\n}\n\n// How long a failed re-read after an interruption waits before it is tried again. Until one lands\n// the widget draws the outage as a gap, so a failure never shows as a quiet stretch of line.\nexport const RESEED_RETRY_MS = 30_000;\n\n// seedKey is the identity of what a measurement widget's history is OF: its concrete\n// selector, by value. Undefined for a widget that takes no seed.\nfunction seedKey(widget: WidgetInstance, registry: WidgetRegistry): string | undefined {\n // Eligibility is registry metadata (takesHistorySeed). A placeholder, an unregistered id and every\n // other channel take none.\n const descriptor = widget.type === UNKNOWN_WIDGET_TYPE ? undefined : registry.descriptor(widget.type);\n if (!descriptor || !takesHistorySeed(descriptor, widget)) {\n return undefined;\n }\n return JSON.stringify(widget.datasource ?? null);\n}\n\n// useWidgetHistories backfills each measurement widget from bucketedMeasurements and\n// returns an id\u2192seed map. Each seed is keyed by the widget's OWN concrete selector,\n// not by the board's bindings as a whole, so:\n//\n// - a selection that re-points one slot re-fetches only the widgets bound to it;\n// - a seed fetched for a selector the widget no longer has is DROPPED at render,\n// synchronously, so a widget never shows the previous device's history under the new\n// device while the new fetch is pending;\n// - a slow answer for a superseded selector is discarded when it lands.\n//\n// `reseed(id)` reads a widget's history again after its live feed resumed from an interruption.\n// It supersedes any read of that widget still in flight (one asked for before the outage cannot\n// cover it), and the answer is handed over with the instant it was read up to, which is how the\n// widget knows it covers the outage. A failed re-read keeps the seed on screen (the widget then\n// draws the outage as a gap) and is tried again after RESEED_RETRY_MS. While the board is paused\n// the re-read waits: a frozen board shows the moment it froze, and history up to that moment\n// cannot cover an outage after it. Resuming reads it.\n//\n// A widget's samples array is the one stored for its seed, so an unchanged seed keeps\n// its identity across renders and does not churn the stream's merge.\nfunction useWidgetHistories(\n widgets: WidgetInstance[],\n enabled: boolean,\n registry: WidgetRegistry,\n range: TimeRangeState,\n): { histories: Record<string, WidgetHistory | undefined>; reseed: (id: string) => void } {\n const [seeds, setSeeds] = useState<Record<string, Seed>>({});\n // widget id \u2192 the (selector, span, re-read) ask most recently REQUESTED for it. A fetch whose\n // ask is no longer the requested one is stale when it lands.\n const requested = useRef<Record<string, string>>({});\n // widget id \u2192 how many re-reads its live feed has asked for (part of the ask). A read asked for\n // before the latest interruption that lands before the effect below has run is still taken, but\n // it cannot close the gap: it is handed over with the instant it was read up to, which is before\n // the interruption (useMeasurementStream).\n const reseeds = useRef<Record<string, number>>({});\n const [reseedTick, bumpReseeds] = useState(0);\n const mounted = useRef(true);\n useEffect(() => {\n mounted.current = true;\n return () => {\n mounted.current = false;\n };\n }, []);\n\n const reseed = useCallback((id: string) => {\n reseeds.current[id] = (reseeds.current[id] ?? 0) + 1;\n bumpReseeds((n) => n + 1);\n }, []);\n\n // The (id, key, span) triples that want a seed; value-compared so an equal render is a no-op.\n // `span` is the seconds a TIME-RANGED widget draws (null for one that is not, which keeps the\n // fixed default seed): a new span re-fetches, but the seed on screen stays until the new one lands,\n // because it is the same device's history and the stream prunes it to the span anyway.\n const wanted = widgets.flatMap((w) => {\n const key = seedKey(w, registry);\n if (key === undefined) return [];\n const descriptor = w.type === UNKNOWN_WIDGET_TYPE ? undefined : registry.descriptor(w.type);\n const span = descriptor ? (measurementSpan(descriptor, w, range.spanSeconds) ?? null) : null;\n return [[w.id, key, span] as const];\n });\n const tag = windowTag(range);\n const wantedKey = JSON.stringify([tag, wanted]);\n\n useEffect(() => {\n // Preview (enabled=false) must not touch the backend; clear any prior seed so a\n // toggle from live\u2192preview doesn't leave stale real history under synthetic data.\n if (!enabled) {\n requested.current = {};\n setSeeds({});\n return;\n }\n const now = Date.now();\n const byId = new Map(widgets.map((w) => [w.id, w]));\n const next: Record<string, string> = {};\n for (const [id, key, span] of wanted) {\n // What was asked for: the selector, the span and the re-reads. Equal = fetched, or in flight.\n const base = `${key}|${span ?? ''}|${tag}|`;\n const n = reseeds.current[id] ?? 0;\n // A read made while frozen ends at the freeze instant, so it answers no re-read: it is asked\n // as `p`, and resuming reads the outage back.\n const asked = `${base}${range.paused && n ? 'p' : n}`;\n const previous = requested.current[id];\n // Already asked; or only the re-read is new and the board is frozen, so it waits for resume.\n if (previous === asked || (range.paused && previous?.startsWith(base))) {\n next[id] = previous!;\n continue;\n }\n next[id] = asked;\n const widget = byId.get(id);\n // Only a single device has stored history to read (fetchWidgetHistory answers any other\n // selector with nothing, at once). That empty answer is not history across an outage, and\n // taken as one it would wipe what the chart drew before it: such a widget gets no seed.\n if (widget?.datasource?.kind !== 'device') continue;\n // A frozen board reads up to the freeze instant, so a range change while paused re-fetches\n // the same moment at the new span instead of sliding forward.\n const end = range.paused && range.pausedAt !== undefined ? range.pausedAt : now;\n // A widget that is not time-ranged reads its fixed hour back from the window's end under a\n // fixed window (the value AS OF that window), and back from now otherwise.\n const historyWindow =\n span !== null ? historyWindowFor(span, end) : range.absolute ? historyWindowFor(DEFAULT_TIME_RANGE_SECONDS, end) : defaultHistoryWindow();\n const current = () => mounted.current && requested.current[id] === asked;\n void fetchWidgetHistory(widget, historyWindow, { rethrow: n > 0 }).then(\n (samples) => {\n if (!current()) return; // superseded or unmounted\n // `asOf`: what the read covers up to (the fixed hour reads to now, a moment after `now`).\n setSeeds((prev) => ({ ...prev, [id]: { key, window: tag, samples, asOf: end } }));\n },\n () => {\n // Only a re-read rejects. The seed on screen stays, the outage stays a gap, and it is\n // read again later -- unless something newer has been asked for meanwhile, or the board\n // has gone (current() says both).\n setTimeout(() => current() && reseed(id), RESEED_RETRY_MS);\n },\n );\n }\n requested.current = next;\n // `widgets`/`wanted` are read via wantedKey (value identity), not reference.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [wantedKey, enabled, reseedTick, range.paused]);\n\n // Hand each widget its seed ONLY if it was fetched for the selector the widget has now.\n const histories = useMemo(() => {\n const out: Record<string, WidgetHistory | undefined> = {};\n if (!enabled) return out;\n for (const w of widgets) {\n const seed = seeds[w.id];\n out[w.id] = seed && seed.key === seedKey(w, registry) && seed.window === tag ? seed : undefined;\n }\n return out;\n }, [widgets, seeds, enabled, registry, tag]);\n return { histories, reseed };\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// ConnectedWidget is the one place the imperative DashboardHub meets the pure widget\n// contract. It looks the widget up in the host's REGISTRY and dispatches on the registered\n// descriptor's data CHANNEL: a measurement widget subscribes its datasource (windowed per its\n// binding policy); an alarm widget subscribes its scope+filters through the hub's alarm\n// channel; and so on. Either way it resolves the data and renders the registered component\n// with { widget, data }. A dashboard renderer maps over its widgets rendering one\n// ConnectedWidget each.\n//\n// Each widget renders inside its own containment (widget-containment.tsx): a throw shows a\n// local diagnostic with a reset control and the siblings keep rendering. A widget the\n// registry cannot resolve (an unknown or unavailable package, a version it cannot read) is a\n// placeholder with a specific reason: it reads nothing \u2014 no channel, no availability query \u2014\n// and is handed no actions.\n\nimport {\n UNKNOWN_WIDGET_TYPE,\n type MeasurementSample,\n type UnresolvedWidgetReason,\n type WidgetActions,\n type WidgetDataSource,\n type WidgetDescriptor,\n type WidgetInstance,\n} from '@devicechain/dashboards';\nimport {\n newestSampleTime,\n resolveStaleAfterSeconds,\n WidgetCandidatesProvider,\n WidgetDeclaredMetricsProvider,\n WidgetFreshnessProvider,\n WidgetSelectProvider,\n useWidgetScale,\n useWidgetTimeRange,\n type WidgetFreshness,\n type WidgetRegistry,\n} from '@devicechain/widget-sdk';\nimport { isForbiddenError } from '@devicechain/client';\nimport { useCallback, useEffect, useMemo, useState, type ComponentType, type ReactNode } from 'react';\n\nimport { alarmSubscription, commandSubscription, groupsAlarmsByDeviceType, historyMode, measurementSpan, measurementIsMembersOnly, measurementWindow, membersMode, presenceMode, wantsEventMarkers } from './binding-policy';\nimport { useHeld } from './use-held';\nimport { accessStrings } from './access-strings';\nimport { defaultWidgetRegistry } from './default-registry';\nimport {\n css,\n fontVar,\n optString,\n spaceVar,\n viewerLocale,\n useAlarmStream,\n useCommandStream,\n useDatasourceAvailability,\n useLocationStream,\n useMeasurementStream,\n useWidgetCandidates,\n useWidgetSelect,\n WidgetFrame,\n} from '@devicechain/widget-sdk';\nimport { WidgetContainment, useReportRejection } from './widget-containment';\nimport { ChunkLoadingFrame, lazyChunk } from './widgets/lazy-chunk';\nimport type { AggregateFeedProps } from './aggregate-feed';\nimport type { GroupedAlarmProps } from './widgets/alarm-grouped';\nimport type { EventMarkersFeedProps } from './event-markers-feed';\nimport type { FleetFeedProps } from './fleet-feed';\nimport type { HistoryFeedProps } from './history-feed';\nimport type { PresenceFeedProps } from './presence-feed';\nimport { narrowActions, narrowCandidates, narrowSelect } from './widget-host';\n\nexport interface ConnectedWidgetProps {\n widget: WidgetInstance;\n hub: WidgetDataSource;\n // The registry that resolves the widget's component, channel and binding policy. Omitted =\n // the built-in registry. A host composing extension packages passes the SAME registry it\n // parsed the definition with.\n registry?: WidgetRegistry;\n // The action seam (writes). Narrowed per widget to the interactions its descriptor\n // declares; undefined = read-only.\n actions?: WidgetActions;\n // Optional history backfill for this widget (from bucketedMeasurements), seeded\n // under the live tail so a chart isn't blank until the first live sample. Ignored by\n // every channel but measurement (the others reconcile from a query, not a history seed).\n initialSamples?: MeasurementSample[];\n // When `initialSamples` was read up to (epoch ms). A seed read after the live feed resumed from an\n // interruption replaces what the widget held from before it (useMeasurementStream).\n initialSamplesAsOf?: number;\n // Called when the widget's live feed resumes after an interruption: the host reads its history\n // again. Omitted: the outage stays drawn as a gap.\n onReconnect?: () => void;\n}\n\nexport function ConnectedWidget(props: ConnectedWidgetProps) {\n const { widget } = props;\n const registry = props.registry ?? defaultWidgetRegistry();\n // A change to what the widget is configured with retries a widget that threw on the old one.\n const resetKey = JSON.stringify([widget.type, widget.options ?? null, widget.datasource ?? null]);\n return (\n <WidgetContainment title={optString(widget.options, 'title')} resetKey={resetKey}>\n <ConnectedWidgetBody {...props} registry={registry} />\n </WidgetContainment>\n );\n}\n\ntype BodyProps = ConnectedWidgetProps & { registry: WidgetRegistry };\n\n// The component a registration renders. Its props are erased in the registry (one registry\n// holds components of every channel); the channel adapters below supply the matching data.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyWidgetComponent = ComponentType<any>;\n\nfunction ConnectedWidgetBody({ widget, hub, registry, actions, initialSamples, initialSamplesAsOf, onReconnect }: BodyProps) {\n const range = useWidgetTimeRange();\n const unresolved = widget.type === UNKNOWN_WIDGET_TYPE;\n const descriptor = unresolved ? undefined : registry.descriptor(widget.type);\n const implementation = unresolved ? undefined : registry.implementation(widget.type);\n\n // A widget bound to a since-deleted device (its stable token no longer resolves)\n // shows an \"unavailable\" pane rather than a blank one \u2014 checked optimistically, so a\n // valid widget renders from its stream without waiting on this. An unresolved widget asks\n // nothing: it is never given a datasource to check. Nor does a widget whose descriptor\n // binds none (label, image, the selector): a datasource left on its stored JSON is one it\n // never reads, so it must not turn the widget into an \"unavailable\" pane.\n const readsDatasource = descriptor !== undefined && descriptor.datasource.mode !== 'none';\n const availability = useDatasourceAvailability(hub, readsDatasource ? widget.datasource : undefined);\n const supported = useDatasourceSupported(hub, readsDatasource ? widget.datasource : undefined);\n if (!supported) {\n return <WidgetNotForCustomerUsersFrame widget={widget} />;\n }\n if (availability === 'unavailable') {\n return <WidgetUnavailableFrame widget={widget} />;\n }\n\n if (widget.type === UNKNOWN_WIDGET_TYPE) {\n return <UnresolvedWidgetFrame storedType={widget.raw.type} reason={widget.reason} />;\n }\n if (!descriptor || !implementation) {\n // Parsed against a catalog this registry does not hold: say so rather than render nothing.\n return (\n <UnresolvedWidgetFrame\n storedType={widget.type}\n reason={{ code: 'unregistered', message: `\"${widget.type}\" is not registered in this host's widget registry` }}\n />\n );\n }\n\n const body = (\n <DeclaredScope hub={hub} datasource={widget.datasource}>\n <HostScope descriptor={descriptor} actions={actions}>\n {(hostActions) => (\n <ChannelBody\n widget={widget}\n hub={hub}\n descriptor={descriptor}\n Component={implementation.component}\n actions={hostActions}\n initialSamples={initialSamples}\n initialSamplesAsOf={initialSamplesAsOf}\n onReconnect={onReconnect}\n />\n )}\n </HostScope>\n </DeclaredScope>\n );\n return range?.absolute !== undefined && showsCurrentStateOnly(descriptor) ? <CurrentStateBadge>{body}</CurrentStateBadge> : body;\n}\n\n// The widgets that read CURRENT state, with no history to read for a past window: alarms (the\n// active set now), positions (the last fix), and presence (online now). Under a fixed window the\n// rest of the board shows that window, so each of these says, on itself, that it does not --\n// a table of today's active alarms under \"Fixed window: yesterday 02:00-04:00\" would otherwise\n// read as the alarms that were active then.\nfunction showsCurrentStateOnly(descriptor: WidgetDescriptor): boolean {\n return descriptor.channel === 'alarm' || descriptor.channel === 'location' || presenceMode(descriptor);\n}\n\nconst CURRENT_STATE_STRINGS = {\n en: { label: 'Now', title: 'Shows the current state: the fixed time window does not apply to this widget.' },\n es: { label: 'Ahora', title: 'Muestra el estado actual: la ventana de tiempo fija no se aplica a este widget.' },\n};\n\nfunction CurrentStateBadge({ children }: { children: ReactNode }) {\n const words = viewerLocale()?.toLowerCase().startsWith('es') ? CURRENT_STATE_STRINGS.es : CURRENT_STATE_STRINGS.en;\n return (\n <div data-current-state=\"\" style={{ position: 'relative', width: '100%', height: '100%', minWidth: 0, minHeight: 0 }}>\n {children}\n <span\n data-current-state-badge=\"\"\n role=\"note\"\n title={words.title}\n aria-label={words.title}\n style={{\n position: 'absolute',\n // Bottom LEFT: a map keeps its attribution bottom right, and a chart its span badge top right.\n bottom: spaceVar(1),\n left: spaceVar(2),\n padding: `0 ${spaceVar(1)}`,\n fontSize: fontVar('xs'),\n fontWeight: 600,\n whiteSpace: 'nowrap',\n color: css('background'),\n background: css('foreground'),\n borderRadius: 4,\n zIndex: 1,\n }}\n >\n {words.label}\n </span>\n </div>\n );\n}\n\n// useDatasourceSupported asks the source whether the viewer is offered the widget's binding at\n// all (WidgetDataSource.isDatasourceSupported). Optimistic like the availability check: the\n// widget renders from its channel meanwhile, and a source without the method supports every\n// binding. Re-asked when the binding changes (value-compared).\nfunction useDatasourceSupported(hub: WidgetDataSource, datasource: WidgetInstance['datasource']): boolean {\n const key = datasource ? JSON.stringify(datasource) : null;\n const [refused, setRefused] = useState<string | null>(null);\n useEffect(() => {\n if (!datasource || !hub.isDatasourceSupported) return;\n let cancelled = false;\n hub.isDatasourceSupported(datasource).then(\n (ok) => {\n if (!cancelled) setRefused(ok ? null : key);\n },\n () => {\n if (!cancelled) setRefused(null);\n },\n );\n return () => {\n cancelled = true;\n };\n // `datasource` is intentionally read via `key` (value identity), not reference.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [hub, key]);\n // A refusal belongs to the binding it was given for; a changed binding is supported until asked.\n return refused === null || refused !== key;\n}\n\n// DeclaredScope answers, for a single-device widget with nothing to draw, \"does this device's profile\n// declare what you asked for?\". Nothing is read until a widget in the scope asks (an empty state\n// does), so a board whose widgets have data costs no lookup; the answer is the hub's shared one per\n// device type. A binding that is not one device (a group, an unbound slot) has nothing to look up.\nfunction DeclaredScope({ hub, datasource, children }: { hub: WidgetDataSource; datasource: WidgetInstance['datasource']; children: ReactNode }) {\n const token = datasource?.kind === 'device' && datasource.deviceToken ? datasource.deviceToken : undefined;\n const [asked, setAsked] = useState(false);\n const [got, setGot] = useState<{ token: string; names: readonly string[] | null }>();\n const ask = useCallback(() => setAsked(true), []);\n useEffect(() => {\n if (!asked || !token || !hub.declaredMetricsForDevice) return;\n let live = true;\n hub.declaredMetricsForDevice(token).then(\n (names) => live && setGot({ token, names }),\n () => undefined,\n );\n return () => {\n live = false;\n };\n }, [asked, token, hub]);\n const declared = got && got.token === token ? got.names : undefined;\n const value = useMemo(() => ({ declared, ask }), [declared, ask]);\n return <WidgetDeclaredMetricsProvider value={value}>{children}</WidgetDeclaredMetricsProvider>;\n}\n\n// HostScope hands ONE widget only the interactions it declared: a narrowed action seam, and\n// the ambient selection / candidate providers re-provided so an undeclared capability\n// reads as \"not wired\" to a widget that asks.\nfunction HostScope({\n descriptor,\n actions,\n children,\n}: {\n descriptor: WidgetDescriptor;\n actions: WidgetActions | undefined;\n children: (actions: WidgetActions | undefined) => ReactNode;\n}) {\n const report = useReportRejection();\n const select = useWidgetSelect();\n const candidates = useWidgetCandidates();\n const narrowed = useMemo(() => narrowActions(actions, descriptor, report), [actions, descriptor, report]);\n const narrowedSelect = useMemo(() => narrowSelect(select, descriptor), [select, descriptor]);\n const narrowedCandidates = useMemo(\n () => narrowCandidates(candidates, descriptor, report),\n [candidates, descriptor, report],\n );\n return (\n <WidgetSelectProvider select={narrowedSelect}>\n <WidgetCandidatesProvider candidates={narrowedCandidates}>{children(narrowed)}</WidgetCandidatesProvider>\n </WidgetSelectProvider>\n );\n}\n\ninterface ChannelProps {\n widget: WidgetInstance;\n hub: WidgetDataSource;\n descriptor: WidgetDescriptor;\n Component: AnyWidgetComponent;\n actions: WidgetActions | undefined;\n initialSamples?: MeasurementSample[];\n initialSamplesAsOf?: number;\n onReconnect?: () => void;\n}\n\n// The channel is the only thing the runtime branches on \u2014 never the widget id.\nfunction ChannelBody(props: ChannelProps) {\n switch (props.descriptor.channel) {\n case 'alarm':\n return <AlarmConnectedWidget {...props} />;\n case 'control':\n return <ControlConnectedWidget {...props} />;\n case 'location':\n return <LocationConnectedWidget {...props} />;\n case 'aggregate':\n return <AggregateConnectedWidget {...props} />;\n case 'selection':\n case 'none':\n return <StaticConnectedWidget {...props} />;\n case 'measurement':\n return <MeasurementConnectedWidget {...props} />;\n }\n}\n\n// A selection widget (entity-selector) consumes no hub data \u2014 it reads the ambient candidate\n// provider + selection callback; a `none` widget is static. Neither subscribes anything.\nfunction StaticConnectedWidget({ widget, Component, actions }: ChannelProps) {\n return <Component widget={widget} data={null} actions={actions} />;\n}\n\n// The fleet feed is its own chunk (fleet-feed.tsx), like the aggregate feed: a board without a fleet\n// table or a per-device bar chart never downloads it. A chunk that fails to load is thrown to the\n// widget's containment, which shows the failure, and its Reset fetches it again (lazyChunk).\nconst FleetFeed = lazyChunk<typeof import('./fleet-feed')>(() => import('./fleet-feed')).component<never, FleetFeedProps>('default', undefined, ChunkLoadingFrame);\n\n// The presence feed (presence-feed.tsx) loads with the presence widgets, in their chunk: a board\n// without a device status card or an online doughnut never downloads it.\nconst PresenceFeed = lazyChunk<typeof import('./widgets/presence-widgets')>(() => import('./widgets/presence-widgets')).component<never, PresenceFeedProps>('PresenceFeed');\n\n// The history feed (history-feed.tsx) loads with the history table, in its chunk: a board without one\n// never downloads it.\nconst HistoryFeed = lazyChunk<typeof import('./widgets/history-widgets')>(() => import('./widgets/history-widgets')).component<never, HistoryFeedProps>('HistoryFeed');\n\nfunction MeasurementConnectedWidget(props: ChannelProps) {\n // A presence widget reads device-state, not readings: its own feed, whatever it is bound to (the\n // widget itself says so when a card meant for one device is bound to a group).\n if (presenceMode(props.descriptor)) {\n return (\n <PresenceFeed hub={props.hub} widget={props.widget} descriptor={props.descriptor} Component={props.Component} actions={props.actions} ErrorFrame={WidgetErrorFrame} />\n );\n }\n // Read member by member, or as one stream keyed by measurement name: decided by the descriptor\n // and the widget's options, never by the widget id.\n //\n // Keyed by measurement name, a group's devices would overwrite one another and the widget would\n // show whichever spoke last as if it were the answer. So a group reaching a widget that is not\n // reading member by member is refused in words (the fleet chunk says so), whatever brought it\n // here: a host binding, an older definition. The editor offers a group only to the fleet widgets.\n const { widget, hub, descriptor, Component, actions } = props;\n const members = membersMode(descriptor, widget);\n if (members || widget.datasource?.kind === 'anchor') {\n return (\n <FleetFeed hub={hub} widget={widget} descriptor={descriptor} Component={Component} actions={actions} ErrorFrame={WidgetErrorFrame} refuse={!members} />\n );\n }\n // One device's stored history, in buckets (after the group check above, so a group is refused in words).\n if (historyMode(descriptor)) {\n return <HistoryFeed hub={hub} widget={widget} descriptor={descriptor} Component={Component} actions={actions} />;\n }\n return <StreamConnectedWidget {...props} />;\n}\n\nfunction StreamConnectedWidget({ widget, hub, descriptor, Component, actions, initialSamples, initialSamplesAsOf, onReconnect }: ChannelProps) {\n // The board's time range (D-1). A widget that declares `binding.windowSeconds` draws a SPAN: its\n // own pinned one, else the board's. Every measurement widget honors the pause, because a frozen\n // board must freeze its cards and gauges too -- a number that kept moving under a \"Paused\"\n // badge would be the worst possible answer.\n const range = useWidgetTimeRange();\n // The source's own clock (a recorded run is dated by the run), else the wall clock.\n const now = useMemo(() => (hub.now ? () => hub.now!() : Date.now), [hub]);\n const data = useMeasurementStream(hub, widget.datasource, {\n window: measurementWindow(descriptor, widget),\n windowSeconds: measurementSpan(descriptor, widget, range?.spanSeconds),\n pausedAt: range?.paused ? range.pausedAt : undefined,\n now,\n initialSamples,\n initialSamplesAsOf,\n onReconnect,\n });\n\n // Opt-in through the descriptor. The age is of the newest sample among the measurements this\n // widget shows (its pinned one, else its datasource's, else whatever has arrived) -- right for\n // a chart or a table, which time every point or row. A single-value widget narrows it to the\n // sample it actually shows by passing that sample's time to its WidgetFrame (`sampleTime`).\n // The threshold is the widget's own option, and absent means age only.\n const freshness = useMemo<WidgetFreshness | undefined>(() => {\n if (descriptor.freshness !== true) return undefined;\n // A `measurement` that only the widget's members mode reads (a chart's compared measurement) is\n // not what it draws here, one device at a time: it narrows nothing.\n const pinned = measurementIsMembersOnly(descriptor) ? undefined : optString(widget.options, 'measurement');\n const names = pinned ? [pinned] : widget.datasource?.measurements;\n return {\n at: newestSampleTime(data.latest, names),\n staleAfterSeconds: resolveStaleAfterSeconds(widget.options),\n };\n }, [descriptor, widget.options, widget.datasource, data.latest]);\n\n if (data.error) return <WidgetErrorFrame widget={widget} error={data.error} />;\n return (\n <WidgetFreshnessProvider freshness={freshness}>\n {wantsEventMarkers(descriptor, widget) ? (\n <EventMarkersFeed hub={hub} widget={widget} descriptor={descriptor} data={data} Component={Component} actions={actions} />\n ) : (\n <Component widget={widget} data={data} actions={actions} />\n )}\n </WidgetFreshnessProvider>\n );\n}\n\n// The event-marker feed (alarms and commands on a chart) is its own chunk, like the feeds below: a\n// board whose charts have the markers off never downloads it.\nconst EventMarkersFeed = lazyChunk<typeof import('./event-markers-feed')>(() => import('./event-markers-feed')).component<never, EventMarkersFeedProps>('default');\n\n// The aggregate feed is its own chunk (aggregate-feed.tsx): a board without an aggregate widget\n// never downloads it. Nothing renders until it arrives, and a chunk that fails to load is thrown to\n// the widget's containment, which shows the failure, and its Reset fetches it again.\nconst AggregateFeed = lazyChunk<typeof import('./aggregate-feed')>(() => import('./aggregate-feed')).component<never, AggregateFeedProps>('default');\n\nfunction AggregateConnectedWidget(channel: ChannelProps) {\n // An aggregate names one device's measurements, so a group is refused as above.\n const props = { ...channel, ErrorFrame: WidgetErrorFrame };\n return channel.widget.datasource?.kind === 'anchor' ? <FleetFeed {...props} refuse /> : <AggregateFeed {...props} />;\n}\n\n// An alarm widget grouped by device type is its own part of the alarm chunk (widgets/alarm-grouped.tsx):\n// a board without one never downloads the tab logic, and the eager code carries only this switch.\nconst GroupedAlarm = lazyChunk<typeof import('./widgets/alarm-widgets')>(() => import('./widgets/alarm-widgets')).component<\n never,\n GroupedAlarmProps\n>('GroupedAlarm');\n\nfunction AlarmConnectedWidget(props: ChannelProps) {\n return groupsAlarmsByDeviceType(props.descriptor, props.widget) ? (\n <GroupedAlarm\n hub={props.hub}\n widget={props.widget}\n base={alarmSubscription(props.descriptor, props.widget)}\n useHeld={useHeld}\n Component={props.Component}\n actions={props.actions}\n ErrorFrame={WidgetErrorFrame}\n />\n ) : (\n <PlainAlarmConnectedWidget {...props} />\n );\n}\n\nfunction PlainAlarmConnectedWidget({ widget, hub, descriptor, Component, actions }: ChannelProps) {\n // Frozen while the board is paused: the snapshot on screen at the pause (or the first one to land,\n // when the board opened paused) stays, and the live one is shown again on resume.\n const range = useWidgetTimeRange();\n const live = useAlarmStream(hub, alarmSubscription(descriptor, widget));\n const data = useHeld(live, range?.paused === true, (s) => !s.loading);\n\n // Show the error pane ONLY when there's nothing to display (the initial load failed).\n // Once a snapshot has loaded, a later transient poll/query error keeps the last-good\n // rows on screen \u2014 the channel re-queries every 30s and self-heals, so blanking a\n // populated table on one blip is the exact blink the console page avoids.\n if (data.error && data.alarms.length === 0 && data.total === 0) {\n return <WidgetErrorFrame widget={widget} error={data.error} />;\n }\n return <Component widget={widget} data={data} actions={actions} />;\n}\n\nfunction ControlConnectedWidget({ widget, hub, descriptor, Component, actions }: ChannelProps) {\n const data = useCommandStream(hub, commandSubscription(descriptor, widget));\n\n // Unlike the read-only widgets, a command widget is NEVER replaced by the error pane:\n // its primary control is the send form (a separate authority from reading history), so\n // a history poll error must not tear the form down. The widget surfaces the error\n // inline instead.\n return <Component widget={widget} data={data} actions={actions} />;\n}\n\nfunction LocationConnectedWidget({ widget, hub, Component, actions }: ChannelProps) {\n // The tile source lives in the widget's options, not here \u2014 it is a rendering choice, not\n // part of what the widget asks the platform for.\n const range = useWidgetTimeRange();\n const live = useLocationStream(hub, { datasource: widget.datasource });\n const data = useHeld(live, range?.paused === true, (s) => !s.loading);\n\n // Same rule as the alarm channel: show the error pane ONLY when there is nothing to\n // display. Once a snapshot has loaded, a later transient poll error keeps the last\n // known positions on screen \u2014 the channel re-polls and self-heals, and blanking a\n // populated map on one blip is worse than a marker being a few seconds stale.\n //\n // \uD83D\uDD34 A REFUSAL IS NOT AN ERROR AND MUST NOT REACH THIS BRANCH. The hub delivers it as\n // a snapshot state with `error` null, so the widget renders its own permission copy \u2014\n // if it were surfaced as an error, every ordinary member would see \"Data unavailable\"\n // where the platform is working exactly as designed.\n if (data.error && data.locations.length === 0) {\n return <WidgetErrorFrame widget={widget} error={data.error} />;\n }\n return <Component widget={widget} data={data} actions={actions} />;\n}\n\n// The body of every state pane below: a centered, muted column.\nconst STATE_STYLE = {\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 4,\n width: '100%',\n height: '100%',\n padding: 12,\n boxSizing: 'border-box',\n textAlign: 'center',\n color: 'hsl(var(--muted-foreground))',\n} as const;\n\n// The placeholder for a widget this build cannot resolve. It names the stored type and says\n// WHY (not installed, no version metadata, a settings or SDK generation it cannot read); the\n// stored object is otherwise untouched (the serializer writes it back verbatim).\nfunction UnresolvedWidgetFrame({\n storedType: stored,\n reason,\n}: {\n storedType: unknown;\n reason: UnresolvedWidgetReason | undefined;\n}): ReactNode {\n const storedType = typeof stored === 'string' ? stored : '';\n const heading =\n (reason?.code ?? 'unregistered') === 'unregistered'\n ? 'This widget needs a newer viewer'\n : 'This widget cannot be shown here';\n return (\n <WidgetFrame>\n <div\n style={STATE_STYLE}\n >\n <div style={{ fontSize: 13, fontWeight: 600 }}>{heading}</div>\n {storedType && !reason?.message.includes(storedType) && (\n <div style={{ fontSize: 11, opacity: 0.8 }}>Widget type: {storedType}</div>\n )}\n {reason && <div style={{ fontSize: 11, opacity: 0.8, wordBreak: 'break-word' }}>{reason.message}</div>}\n </div>\n </WidgetFrame>\n );\n}\n\n// The one body of the settled panes below (refused, gone, not offered, source error): a neutral,\n// muted state that says what it is. None of them borrows an alarm glyph or colour, since on a\n// board that means an alarm. `data-empty-state` names the kind for the tests and the screenshots.\nfunction StatePane({\n widget,\n kind,\n glyph,\n title,\n detail,\n}: {\n widget: WidgetInstance;\n kind: string;\n glyph: string;\n title: string;\n detail?: string;\n}): ReactNode {\n return (\n <WidgetFrame title={optString(widget.options, 'title')}>\n <StateBody kind={kind} glyph={glyph} title={title} detail={detail} />\n </WidgetFrame>\n );\n}\n\n// The pane's content, which gives way to the title as the widget shrinks (the glyph first, then the\n// explanation), so a small widget never draws it clipped. Unmeasured, it shows everything.\nfunction StateBody({ kind, glyph, title, detail }: { kind: string; glyph: string; title: string; detail?: string }): ReactNode {\n const { height } = useWidgetScale().size;\n const measured = height > 0;\n return (\n <div role=\"status\" data-empty-state={kind} style={STATE_STYLE}>\n {!measured || height >= 84 ? <div style={{ fontSize: 20, lineHeight: 1 }} aria-hidden=\"true\">{glyph}</div> : null}\n <div style={{ fontSize: 13, fontWeight: 600 }}>{title}</div>\n {detail && (!measured || height >= 64) ? <div style={{ fontSize: 11, opacity: 0.8, wordBreak: 'break-word' }}>{detail}</div> : null}\n </div>\n );\n}\n\n// Shown when the platform refused the widget's read for the viewer.\nfunction WidgetForbiddenFrame({ widget }: { widget: WidgetInstance }): ReactNode {\n return <StatePane widget={widget} kind=\"forbidden\" glyph=\"\u2298\" title={accessStrings().forbidden} />;\n}\n\n// Shown when a widget's bound device no longer exists (a deleted device's stable token). Distinct\n// from the error frame: not a transient failure to retry, but a settled \"this entity is gone\".\nfunction WidgetUnavailableFrame({ widget }: { widget: WidgetInstance }): ReactNode {\n return <StatePane widget={widget} kind=\"gone\" glyph=\"\u2298\" title=\"Device unavailable\" detail=\"The bound device no longer exists.\" />;\n}\n\n// Shown when the platform does not offer the widget's binding to the viewer at all: a member limited\n// to some customers viewing a widget bound to something the platform still declines to resolve for\n// them (a group, say; areas and assets resolve through anchorDevices). A settled state, not a failure to\n// retry, and not \"no access\" either, since nothing the member could be granted would change it -- so\n// the dashboard's author knows to bind it otherwise.\nfunction WidgetNotForCustomerUsersFrame({ widget }: { widget: WidgetInstance }): ReactNode {\n return (\n <StatePane\n widget={widget}\n kind=\"unsupported\"\n glyph=\"\u2298\"\n title=\"Not available for customer users\"\n detail=\"This widget is bound to something customer users cannot view.\"\n />\n );\n}\n\n// A resolution/socket error surfaces as a muted state rather than a blank pane. Shared by the\n// measurement and alarm channels.\n//\n// A REFUSAL is not such an error: a member limited to part of the tenant, viewing a widget bound to a\n// customer or device outside it, is refused by design. It reads as the same plain state the fleet\n// widgets show (\"You do not have access to this data\"), never as \"Data unavailable\" over the\n// server's raw \"forbidden: missing required authority\".\nfunction WidgetErrorFrame({ widget, error }: { widget: WidgetInstance; error: unknown }): ReactNode {\n if (isForbiddenError(error)) return <WidgetForbiddenFrame widget={widget} />;\n return <StatePane widget={widget} kind=\"error\" glyph=\"\u2026\" title=\"Data unavailable\" detail={String(error)} />;\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The built-in widgets as registrations. Each widget module declares its own registration\n// (descriptor + component) through the SAME public `defineWidget` a third-party package uses\n// -- there is no privileged internal path and no id-keyed component table; this module only\n// lists them, in the catalog's order.\n//\n// These are the RUNTIME registrations: their descriptors carry no option `doc`. The package\n// publishes them as `builtinWidgetDefinitionsWithoutDocs`; its `builtinWidgetDefinitions` and\n// `createBuiltinWidgetRegistry` are the documented forms (documented-descriptors.ts).\n\nimport { createWidgetRegistry, type WidgetRegistry } from '@devicechain/widget-sdk';\n\nimport { barChartWidget, fleetCountWidget, fleetTableWidget, pieChartWidget, statCardWidget } from './widgets/aggregate-lazy';\nimport { alarmCountWidget, alarmSeverityWidget, alarmTableWidget } from './widgets/alarm-lazy';\nimport { commandButtonWidget, commandSliderWidget, commandToggleWidget } from './widgets/control-lazy';\nimport { historyTableWidget } from './widgets/history-lazy';\nimport { deviceStatusWidget, onlineDoughnutWidget } from './widgets/presence-lazy';\nimport { entitySelectorWidget } from './widgets/selection-lazy';\nimport { gaugeWidget } from './widgets/gauge';\nimport { imageWidget } from './widgets/image';\nimport { labelWidget } from './widgets/label';\nimport { latestCardWidget } from './widgets/latest-card';\nimport {\n batteryWidget,\n compassWidget,\n levelGaugeWidget,\n linearGaugeWidget,\n progressRingWidget,\n signalBarsWidget,\n statusLightWidget,\n} from './widgets/level-lazy';\nimport { mapWidget } from './widgets/map';\nimport { tableWidget } from './widgets/table-lazy';\nimport { timeSeriesChartWidget } from './widgets/time-series-chart';\n\nexport const builtinWidgetDefinitions = [\n timeSeriesChartWidget,\n latestCardWidget,\n gaugeWidget,\n tableWidget,\n labelWidget,\n imageWidget,\n alarmTableWidget,\n alarmCountWidget,\n alarmSeverityWidget,\n commandButtonWidget,\n entitySelectorWidget,\n mapWidget,\n linearGaugeWidget,\n levelGaugeWidget,\n batteryWidget,\n statusLightWidget,\n signalBarsWidget,\n compassWidget,\n progressRingWidget,\n commandSliderWidget,\n commandToggleWidget,\n statCardWidget,\n barChartWidget,\n pieChartWidget,\n fleetTableWidget,\n fleetCountWidget,\n deviceStatusWidget,\n onlineDoughnutWidget,\n historyTableWidget,\n] as const;\n\n// A fresh, sealed registry holding exactly the built-ins. Every call returns an independent\n// instance; a host composing extensions passes `[...builtinWidgetDefinitions, theirs]` to\n// createWidgetRegistry from @devicechain/widget-sdk instead.\nexport function createBuiltinWidgetRegistry(): WidgetRegistry {\n return createWidgetRegistry(builtinWidgetDefinitions);\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The aggregate and categorical registrations: descriptor eager, component lazy, from a chunk of\n// their own (aggregate-widgets.ts), so a board without a stat card, bar chart or pie chart never\n// downloads them. The bar and pie charts are SVG, so no chart engine type is loaded for them.\n\nimport { defineWidget, type AggregateStreamState } from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { lazyChunk } from './lazy-chunk';\n\nconst chunk = lazyChunk<typeof import('./aggregate-widgets')>(() => import('./aggregate-widgets'));\n\nexport const loadAggregateWidgets = chunk.load;\n\nexport const statCardWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['stat-card'],\n implementation: { kind: 'trusted-react', component: chunk.component<AggregateStreamState>('StatCard') },\n});\n\nexport const barChartWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['bar-chart'],\n implementation: { kind: 'trusted-react', component: chunk.component('BarChart') },\n});\n\nexport const pieChartWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['pie-chart'],\n implementation: { kind: 'trusted-react', component: chunk.component('PieChart') },\n});\n\nexport const fleetCountWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['fleet-count'],\n implementation: { kind: 'trusted-react', component: chunk.component('FleetCount') },\n});\n\nexport const fleetTableWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['fleet-table'],\n implementation: { kind: 'trusted-react', component: chunk.component('FleetTable') },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The portable descriptor of every built-in widget \u2014 pure data, React-free, importing no\n// component. The headless validators read the catalog built from these without ever\n// loading a widget; builtin-registry.ts pairs each descriptor with its component.\n//\n// \uD83D\uDD11 THE SOURCE OF TRUTH. A built-in's channel, option schema, defaults and binding policy are\n// declared here, once, as data. Nothing else in this package keeps an id-keyed table of them:\n// the by-id views the console still reads (WIDGET_CHANNEL, WIDGET_OPTIONS, ...) are derived,\n// read-only projections of these descriptors (registry.ts, options.ts).\n//\n// Every built-in carries version 1.0.0: a per-widget release number, NOT the platform\n// version. It is bumped only on a rendering change worth surfacing to an author, so a\n// platform release does not make every board look \"authored with an older widget\".\n\nimport { SEVERITY_LEVELS } from '@devicechain/widget-sdk';\nimport {\n createWidgetCatalog,\n defineWidgetDescriptor,\n type BuiltinWidgetId,\n type OptionSpec,\n type WidgetChannel,\n type WidgetDescriptor,\n type WidgetOptionSpecs,\n} from '@devicechain/dashboards';\n\n// ---- The doc-free runtime form ----------------------------------------------\n// These descriptors carry no option `doc` (it lives in builtin-option-docs.ts; see there for\n// why). The public `OptionSpec` keeps `doc: string` -- an extension author must write one, and a\n// reader of any descriptor this package publishes gets one -- so the runtime form is typed here:\n// a spec is declared against RuntimeOptionSpec, which FORBIDS a doc (one creeping back is a\n// compile error), and the descriptor is typed as its documented counterpart so it plugs into\n// the registry and defineWidget unchanged. That type claims a doc the value does not hold; it\n// never leaves this package except as `builtinWidgetDefinitionsWithoutDocs`, whose name says so.\ntype Undocumented<S> = S extends { kind: 'list'; item: infer I }\n ? Omit<S, 'doc' | 'item'> & { doc?: never; item: { readonly [K in keyof I]: Undocumented<I[K]> } }\n : Omit<S, 'doc'> & { doc?: never };\ntype RuntimeOptionSpec = Undocumented<OptionSpec>;\n\ntype Documented<S> = S extends { item: infer I }\n ? Omit<S, 'item'> & { readonly doc: string; readonly item: { readonly [K in keyof I]: Documented<I[K]> } }\n : S & { readonly doc: string };\nexport type DocumentedSpecs<S> = { readonly [K in keyof S]: Documented<S[K]> };\ntype AsSpecs<S> = DocumentedSpecs<S> extends infer D extends WidgetOptionSpecs ? D : never;\n\nconst defineRuntimeDescriptor = defineWidgetDescriptor as unknown as <\n const C extends WidgetChannel,\n const S extends Readonly<Record<string, RuntimeOptionSpec>>,\n>(\n descriptor: Omit<WidgetDescriptor<C, AsSpecs<S>>, 'options'> & { options: S },\n) => WidgetDescriptor<C, AsSpecs<S>>;\n\n// ---- Shared option specs ----------------------------------------------------\n// Declared once and referenced by each widget that reads them, so the same key always\n// carries the same type and bounds. They are still listed PER WIDGET below rather than\n// merged in from a base: which widget reads which option is the fact this table exists\n// to record, and a base object would hide it.\n\nconst TITLE = {\n kind: 'string',\n labelId: 'widgetLabelTitle',\n} as const satisfies RuntimeOptionSpec;\n\n// gauge and latest-card fall back to the displayed measurement's name when no title is set.\nconst TITLE_OR_MEASUREMENT = {\n kind: 'string',\n labelId: 'widgetLabelTitle',\n} as const satisfies RuntimeOptionSpec;\n\n// toFixed()'s domain is 0..100 \u2014 outside it throws a RangeError, which would take the\n// whole widget subtree down rather than degrading.\nconst PRECISION = {\n kind: 'number',\n integer: true,\n min: 0,\n max: 100,\n labelId: 'widgetLabelPrecision',\n helpId: 'widgetHintPrecision',\n} as const satisfies RuntimeOptionSpec;\n\n// Where a measurement crosses from one severity to the next. A threshold STARTS a band that\n// runs to the next threshold's value, so \"overheat above 105\" is one entry and \"low fuel below\n// 15\" is two (critical from 0, normal from 15). `level` is a severity NAME that the theme turns\n// into a colour; there is deliberately no colour field, so a board cannot carry a hex value\n// that ignores dark mode or the host's theme. Optional with no default: absent means no bands,\n// exactly as before the option existed, so it needs no optionsVersion bump.\nconst THRESHOLDS = {\n kind: 'list',\n maxItems: 12,\n labelId: 'widgetLabelThresholds',\n helpId: 'widgetHintThresholds',\n item: {\n value: {\n kind: 'number',\n required: true,\n labelId: 'widgetLabelThresholdValue',\n },\n level: {\n kind: 'enum',\n required: true,\n values: SEVERITY_LEVELS,\n labelId: 'widgetLabelThresholdLevel',\n valueLabelIds: {\n normal: 'widgetSeverityNormal',\n warning: 'widgetSeverityWarning',\n minor: 'widgetSeverityMinor',\n major: 'widgetSeverityMajor',\n critical: 'widgetSeverityCritical',\n },\n placeholderId: 'widgetPlaceholderThresholdLevel',\n },\n label: {\n kind: 'string',\n labelId: 'widgetLabelThresholdLabel',\n },\n },\n} as const satisfies RuntimeOptionSpec;\n\nconst FLASH_ON_CHANGE = {\n kind: 'boolean',\n labelId: 'widgetFlashOnChange',\n helpId: 'widgetFlashOnChangeHint',\n} as const satisfies RuntimeOptionSpec;\n\n// Read by MeasurementConnectedWidget for every measurement-channel widget, and declared on\n// each one that binds a datasource. It is NOT declared on label/image, which carry no\n// datasource at all, so there is no stream for it to size.\n//\n// It bounds the RETAINED buffer, not what is drawn: useMeasurementStream keeps `latest`\n// per measurement unconditionally and trims only `samples`. Only the chart draws\n// `samples`, so on a card, gauge or table this is a memory bound with no visible effect \u2014\n// declared because the renderer honors it, documented so nobody expects it to show.\n//\n// The trim is GLOBAL across the widget's measurements, not per measurement: `samples` is\n// one interleaved list, so a chart drawing N series retains roughly window/N of each. An\n// earlier version of this doc said \"per measurement\", and a caller sized a window off it\n// and got half the history it intended.\nconst WINDOW = {\n kind: 'number',\n integer: true,\n min: 1,\n labelId: 'widgetLabelWindow',\n helpId: 'widgetHintWindow',\n} as const satisfies RuntimeOptionSpec;\n\n// Read by the frame, not by the widget: with it set, a widget whose newest sample is older than\n// this many seconds is greyed out under a \"stale\" badge. Unset is the DEFAULT and means age\n// only -- there is no built-in threshold, because any number would paint a sparse fleet stale.\nconst STALE_AFTER_SECONDS = {\n kind: 'number',\n integer: true,\n min: 1,\n labelId: 'widgetLabelStaleAfter',\n helpId: 'widgetHintStaleAfter',\n} as const satisfies RuntimeOptionSpec;\n\nconst UNIT = {\n kind: 'string',\n labelId: 'widgetLabelUnit',\n} as const satisfies RuntimeOptionSpec;\n\n// The two ends of a level widget's scale. REQUIRED, with no default on the descriptor: a tank\n// or a thermometer drawn against a range nobody chose reads a wrong value as a plausible one,\n// so a widget without both ends says so instead of drawing (see level-reading.ts). The\n// greater-than constraint on each descriptor keeps the pair ordered.\nconst SCALE_MIN = {\n kind: 'number',\n required: true,\n labelId: 'widgetLabelMin',\n helpId: 'widgetHintScaleMin',\n} as const satisfies RuntimeOptionSpec;\n\nconst SCALE_MAX = {\n kind: 'number',\n required: true,\n labelId: 'widgetLabelMax',\n helpId: 'widgetHintScaleMax',\n} as const satisfies RuntimeOptionSpec;\n\n// The command a control sends. The three keys are the command-vocabulary triple the console's\n// command picker writes at once (the command button declares the same three), so picking a\n// command in the editor bakes its key, label and parameter schema here too.\nconst CONTROL_COMMAND_NAME = {\n kind: 'string',\n required: true,\n labelId: 'widgetCommandHeading',\n helpId: 'widgetCommandFieldHint',\n control: 'command-vocabulary',\n} as const satisfies RuntimeOptionSpec;\n\nconst CONTROL_COMMAND_LABEL = {\n kind: 'string',\n labelId: 'widgetCommandHeading',\n helpId: 'widgetCommandFieldHint',\n control: 'command-vocabulary',\n} as const satisfies RuntimeOptionSpec;\n\nconst CONTROL_PARAMETER_SCHEMA = {\n kind: 'string',\n format: 'json',\n labelId: 'widgetCommandHeading',\n helpId: 'widgetCommandFieldHint',\n control: 'command-vocabulary',\n} as const satisfies RuntimeOptionSpec;\n\nconst CONTROL_PARAMETER = {\n kind: 'string',\n labelId: 'widgetLabelParameter',\n helpId: 'widgetHintControlParameter',\n} as const satisfies RuntimeOptionSpec;\n\nconst MEASUREMENT = {\n kind: 'string',\n labelId: 'widgetLabelMeasurement',\n helpId: 'widgetHintMeasurement',\n} as const satisfies RuntimeOptionSpec;\n\nconst ALARM_STATE = {\n kind: 'enum',\n values: ['ACTIVE', 'CLEARED'],\n labelId: 'widgetLabelState',\n helpId: 'widgetStateHint',\n valueLabelIds: { ACTIVE: 'widgetAlarmStateActive', CLEARED: 'widgetAlarmStateCleared' },\n placeholderId: 'widgetPlaceholderAny',\n} as const satisfies RuntimeOptionSpec;\n\nconst ALARM_SEVERITY = {\n kind: 'enum',\n values: ['CRITICAL', 'MAJOR', 'MINOR', 'WARNING', 'INDETERMINATE'],\n labelId: 'widgetLabelSeverity',\n helpId: 'widgetSeverityHint',\n valueLabelIds: { CRITICAL: 'widgetAlarmSeverityCritical', MAJOR: 'widgetAlarmSeverityMajor', MINOR: 'widgetAlarmSeverityMinor', WARNING: 'widgetAlarmSeverityWarning', INDETERMINATE: 'widgetAlarmSeverityIndeterminate' },\n placeholderId: 'widgetPlaceholderAny',\n} as const satisfies RuntimeOptionSpec;\n\n// Stored as the STRING 'true'/'false', not a boolean \u2014 alarmSubscription() reads it with\n// optString and maps it through parseAcknowledged, so a real boolean here is read as\n// undefined and the filter silently disappears. Typed as an enum of those two strings so\n// that mistake is an error rather than a no-op.\nconst ALARM_ACKNOWLEDGED = {\n kind: 'enum',\n values: ['true', 'false'],\n labelId: 'widgetLabelAcknowledged',\n helpId: 'widgetAcknowledgedHint',\n valueLabelIds: { true: 'widgetAlarmAckAcknowledged', false: 'widgetAlarmAckUnacknowledged' },\n placeholderId: 'widgetPlaceholderAny',\n} as const satisfies RuntimeOptionSpec;\n\nconst SELECTION_TARGET = {\n kind: 'string',\n labelId: 'widgetLabelTargetSlot',\n helpId: 'widgetTargetSlotHint',\n control: 'slot-target',\n} as const satisfies RuntimeOptionSpec;\n\n\n// Each widget's `layout` is its size contract, in SQUARE cells. A cell is never smaller than the\n// grid's minCellSize (56 px by default; a narrower board reflows instead), so a span is a\n// readable size by construction, and the minimums below are sized at that smallest cell, with\n// 8 px gutters: n cells cover 64n - 8 px, so 2 is 120 px, 3 is 184 px and 4 is 248 px. On a wider\n// screen the cells stretch and every widget only grows.\n//\n// The minimums are the smallest box in which the widget's parts all fit with room to spare:\n// height is usually the binding constraint, since the frame header costs ~34-50 px before the\n// widget's own content. The defaults are what a freshly added widget takes. A maximum is\n// declared only where the content stops filling the box (a single value, a dial, a button, a\n// one-line selector); a chart, table, map or image fills a whole wall, so it has none, and a\n// label's column limit is set past any authored column count.\n\nconst VERSION = '1.0.0';\nconst ALL_SELECTORS = ['device', 'anchor', 'slot'] as const;\n// A telemetry widget that shows readings keyed by measurement name shows ONE device: bound to a group,\n// two devices reporting the same name would overwrite each other in it. Only the fleet widgets (the\n// fleet table, a bar chart with one bar per device) take a group, and the runtime refuses a group\n// that reaches any other one some other way (a host binding, a hand-edited definition).\nconst ONE_DEVICE = ['device', 'slot'] as const;\nconst NO_DATASOURCE = { mode: 'none' } as const;\n\n// The alarm filters are read by both alarm widgets from the same option keys.\nconst ALARM_FILTERS = {\n state: { option: 'state' },\n severity: { option: 'severity' },\n acknowledged: { option: 'acknowledged' },\n} as const;\n\n// The timeseries chart's window, as a SPAN. Unset, the chart follows the board's time range (which\n// a viewer can change from the header); set, it is PINNED to this span whatever the viewer picks,\n// which is what a \"last 5 minutes\" strip on a wall board wants. The bounds are the board range's:\n// a minute to a week.\n// The timeseries chart's event markers: off unless asked, and optional with no default, so a chart\n// saved before they existed needs no optionsVersion bump.\nconst MARK_ALARMS = {\n kind: 'boolean',\n labelId: 'widgetLabelMarkAlarms',\n helpId: 'widgetHintMarkAlarms',\n} as const satisfies RuntimeOptionSpec;\n\n// Which alarms the chart draws. Unset means 'device' (every alarm on the chart's device), which is\n// what a chart saved before this option existed does; a chart added from the palette starts at\n// 'series' (descriptor defaults below), so it draws only the alarms about what it charts.\nconst MARK_ALARMS_SCOPE = {\n kind: 'enum',\n values: ['series', 'device'],\n labelId: 'widgetLabelMarkAlarmsScope',\n helpId: 'widgetHintMarkAlarmsScope',\n valueLabelIds: { series: 'widgetMarkAlarmsScopeSeries', device: 'widgetMarkAlarmsScopeDevice' },\n placeholderId: 'widgetPlaceholderWholeDevice',\n} as const satisfies RuntimeOptionSpec;\n\nconst MARK_COMMANDS = {\n kind: 'boolean',\n labelId: 'widgetLabelMarkCommands',\n helpId: 'widgetHintMarkCommands',\n} as const satisfies RuntimeOptionSpec;\n\n// The timeseries chart's value-axis ends: optional, with no default, so the axis is ECharts' own\n// unless the author frames it. An end is reached, never clipped at: a reading beyond it widens the\n// axis. A 92 \u00B0C engine on an axis from zero is a flat line at the top of an empty tile; framed at\n// 70..130 it sits where its overheat edge can be seen above it.\nconst CHART_AXIS_MIN = {\n kind: 'number',\n labelId: 'widgetLabelMin',\n helpId: 'widgetHintChartAxisMin',\n} as const satisfies RuntimeOptionSpec;\n\nconst CHART_AXIS_MAX = {\n kind: 'number',\n labelId: 'widgetLabelMax',\n helpId: 'widgetHintChartAxisMax',\n} as const satisfies RuntimeOptionSpec;\n\n// The compare mode's line limit: optional, no default stored (the chart's own applies), whole numbers.\n// The ceiling (MAX_SERIES_LIMIT, 12) is the compare model's and is applied when the chart reads the\n// option, not declared here: the editor's own test drives each number option with a value spaced by its\n// position in the schema, which a ceiling this low cannot take.\nconst MAX_SERIES = {\n kind: 'number',\n integer: true,\n min: 1,\n labelId: 'widgetLabelMaxSeries',\n helpId: 'widgetHintMaxSeries',\n} as const satisfies RuntimeOptionSpec;\n\nconst WINDOW_SECONDS = {\n kind: 'number',\n integer: true,\n min: 60,\n max: 604800,\n labelId: 'widgetLabelWindowSeconds',\n helpId: 'widgetHintWindowSeconds',\n} as const satisfies RuntimeOptionSpec;\n\n// The categorical charts' shared options. Both draw the latest reading of each measurement the\n// datasource names: the order is the datasource's own unless a sort is set.\nconst CATEGORY_SORT = {\n kind: 'enum',\n values: ['none', 'ascending', 'descending'],\n labelId: 'widgetLabelSort',\n valueLabelIds: { none: 'widgetSortNone', ascending: 'widgetSortAscending', descending: 'widgetSortDescending' },\n placeholderId: 'widgetPlaceholderDefault',\n} as const satisfies RuntimeOptionSpec;\n\n// A fleet table's per-column and per-column-threshold entries NAME their measurement, because a list\n// item holds scalars only: one flat list per concern keeps each editable as a row, and a column\n// without an entry keeps the datasource's name, the board's formatting and no bands.\n// The measurement column a fleet table's list entry (a format, a band) applies to.\nconst FLEET_MEASUREMENT = {\n kind: 'string',\n required: true,\n labelId: 'widgetLabelMeasurement',\n} as const satisfies RuntimeOptionSpec;\n\nconst FLEET_COLUMNS = {\n kind: 'list',\n maxItems: 24,\n labelId: 'widgetLabelColumns',\n helpId: 'widgetHintColumns',\n item: {\n measurement: FLEET_MEASUREMENT,\n label: { kind: 'string', labelId: 'widgetLabelColumnHeading' },\n unit: { ...UNIT },\n precision: { ...PRECISION },\n },\n} as const satisfies RuntimeOptionSpec;\n\nconst FLEET_THRESHOLDS = {\n ...THRESHOLDS,\n item: {\n measurement: FLEET_MEASUREMENT,\n ...THRESHOLDS.item,\n },\n} as const satisfies RuntimeOptionSpec;\n\nexport const builtinWidgetDescriptors = {\n 'timeseries-chart': defineRuntimeDescriptor({\n id: 'timeseries-chart',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 2,\n display: { title: 'Timeseries chart', category: 'Telemetry', titleId: 'widgetTypeTimeseriesChart', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n // ALL_SELECTORS because of the compare mode (groupBy device): a group bound with the default mode\n // is refused in words at runtime, exactly as for the bar chart.\n datasource: { mode: 'required', selectors: ALL_SELECTORS },\n binding: { windowSeconds: { option: 'windowSeconds' }, members: { option: 'groupBy', equals: 'device' } },\n options: {\n title: TITLE,\n unit: UNIT,\n precision: PRECISION,\n thresholds: THRESHOLDS,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n windowSeconds: WINDOW_SECONDS,\n groupBy: {\n kind: 'enum',\n values: ['measurement', 'device'],\n labelId: 'widgetLabelSeriesBy',\n helpId: 'widgetHintSeriesBy',\n valueLabelIds: { measurement: 'widgetGroupByMeasurement', device: 'widgetGroupByDevice' },\n placeholderId: 'widgetPlaceholderDefault',\n },\n measurement: MEASUREMENT,\n maxSeries: MAX_SERIES,\n markAlarms: MARK_ALARMS,\n markAlarmsScope: MARK_ALARMS_SCOPE,\n markCommands: MARK_COMMANDS,\n min: CHART_AXIS_MIN,\n max: CHART_AXIS_MAX,\n },\n constraints: [{ kind: 'greater-than', key: 'max', than: 'min' }],\n defaults: { title: 'Timeseries chart', markAlarmsScope: 'series' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 6, rows: 4 }, minSpan: { cols: 4, rows: 3 } },\n }),\n\n 'latest-card': defineRuntimeDescriptor({\n id: 'latest-card',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Latest card', category: 'Telemetry', titleId: 'widgetTypeLatestCard', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: {\n kind: 'string',\n labelId: 'widgetLabelMeasurement',\n helpId: 'widgetHintMeasurement',\n },\n unit: UNIT,\n precision: PRECISION,\n thresholds: THRESHOLDS,\n flashOnChange: FLASH_ON_CHANGE,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n defaults: { title: 'Latest card' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 3, rows: 2 }, minSpan: { cols: 3, rows: 2 }, maxSpan: { cols: 6, rows: 4 } },\n }),\n\n gauge: defineRuntimeDescriptor({\n id: 'gauge',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Gauge', category: 'Telemetry', titleId: 'widgetTypeGauge', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: {\n kind: 'string',\n labelId: 'widgetLabelMeasurement',\n helpId: 'widgetHintMeasurement',\n },\n min: {\n kind: 'number',\n labelId: 'widgetLabelMin',\n },\n max: {\n kind: 'number',\n labelId: 'widgetLabelMax',\n },\n unit: UNIT,\n precision: PRECISION,\n thresholds: THRESHOLDS,\n flashOnChange: FLASH_ON_CHANGE,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n constraints: [{ kind: 'greater-than', key: 'max', than: 'min' }],\n defaults: { title: 'Gauge' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 3, rows: 3 }, minSpan: { cols: 3, rows: 3 }, maxSpan: { cols: 6, rows: 6 } },\n }),\n\n table: defineRuntimeDescriptor({\n id: 'table',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Table', category: 'Telemetry', titleId: 'widgetTypeTable', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE,\n precision: PRECISION,\n flashOnChange: FLASH_ON_CHANGE,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n defaults: { title: 'Table' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 6, rows: 3 }, minSpan: { cols: 4, rows: 2 } },\n }),\n\n // label and image are static: the `none` channel, no datasource, no subscription and no\n // history seed.\n label: defineRuntimeDescriptor({\n id: 'label',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Label', category: 'Static', titleId: 'widgetTypeLabel', categoryId: 'widgetCategoryStatic' },\n channel: 'none',\n datasource: NO_DATASOURCE,\n binding: {},\n options: {\n title: TITLE,\n text: {\n kind: 'string',\n required: true,\n labelId: 'widgetLabelText',\n },\n align: {\n kind: 'enum',\n values: ['left', 'center', 'right'],\n labelId: 'widgetLabelAlign',\n valueLabelIds: { left: 'widgetAlignLeft', center: 'widgetAlignCenter', right: 'widgetAlignRight' },\n placeholderId: 'widgetPlaceholderDefault',\n },\n fontSize: {\n kind: 'number',\n min: 1,\n labelId: 'widgetLabelFontSize',\n helpId: 'widgetHintFontSize',\n },\n },\n defaults: { text: 'New label' },\n interactions: {},\n layout: { defaultSpan: { cols: 3, rows: 1 }, minSpan: { cols: 1, rows: 1 }, maxSpan: { cols: 24, rows: 3 } },\n }),\n\n image: defineRuntimeDescriptor({\n id: 'image',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Image', category: 'Static', titleId: 'widgetTypeImage', categoryId: 'widgetCategoryStatic' },\n channel: 'none',\n datasource: NO_DATASOURCE,\n binding: {},\n options: {\n title: TITLE,\n url: {\n kind: 'string',\n required: true,\n labelId: 'widgetLabelImageUrl',\n },\n alt: {\n kind: 'string',\n labelId: 'widgetLabelAltText',\n },\n fit: {\n kind: 'enum',\n values: ['contain', 'cover', 'fill'],\n labelId: 'widgetLabelFit',\n valueLabelIds: { contain: 'widgetFitContain', cover: 'widgetFitCover', fill: 'widgetFitFill' },\n placeholderId: 'widgetPlaceholderDefault',\n },\n },\n defaults: { title: 'Image' },\n interactions: {},\n layout: { defaultSpan: { cols: 3, rows: 2 }, minSpan: { cols: 1, rows: 1 } },\n }),\n\n 'alarm-table': defineRuntimeDescriptor({\n id: 'alarm-table',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Alarm table', category: 'Alarms', titleId: 'widgetTypeAlarmTable', categoryId: 'widgetCategoryAlarms' },\n channel: 'alarm',\n datasource: { mode: 'optional', selectors: ALL_SELECTORS },\n // groupBy 'deviceType' turns the table into one tab per device type (plus All).\n binding: { pageSize: { option: 'maxRows', default: 50, min: 1 }, ...ALARM_FILTERS, groupBy: { option: 'groupBy', equals: 'deviceType' } },\n options: {\n title: TITLE,\n state: ALARM_STATE,\n severity: ALARM_SEVERITY,\n acknowledged: ALARM_ACKNOWLEDGED,\n groupBy: {\n kind: 'enum',\n values: ['none', 'deviceType'],\n labelId: 'widgetLabelAlarmGroupBy',\n helpId: 'widgetHintAlarmGroupBy',\n valueLabelIds: { none: 'widgetAlarmGroupByNone', deviceType: 'widgetAlarmGroupByDeviceType' },\n placeholderId: 'widgetPlaceholderDefault',\n },\n deviceTypes: {\n kind: 'list',\n maxItems: 24,\n ordered: true,\n labelId: 'widgetLabelAlarmDeviceTypes',\n helpId: 'widgetHintAlarmDeviceTypes',\n item: {\n token: { kind: 'string', control: 'device-type', labelId: 'widgetLabelAlarmDeviceTypeToken' },\n },\n },\n maxRows: {\n kind: 'number',\n integer: true,\n min: 1,\n labelId: 'widgetLabelMaxRows',\n helpId: 'widgetMaxRowsAlarmHint',\n },\n precision: PRECISION,\n flashOnChange: FLASH_ON_CHANGE,\n selectionTarget: SELECTION_TARGET,\n },\n defaults: { title: 'Alarm table', state: 'ACTIVE' },\n interactions: { alarmActions: true, selection: true },\n layout: { defaultSpan: { cols: 6, rows: 4 }, minSpan: { cols: 4, rows: 2 } },\n }),\n\n // The count shows the SERVER total and reads a page only to sample the worst loaded\n // severity, so its page size is a constant rather than an authorable option.\n 'alarm-count': defineRuntimeDescriptor({\n id: 'alarm-count',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Alarm count', category: 'Alarms', titleId: 'widgetTypeAlarmCount', categoryId: 'widgetCategoryAlarms' },\n channel: 'alarm',\n datasource: { mode: 'optional', selectors: ALL_SELECTORS },\n binding: { pageSize: { const: 50 }, ...ALARM_FILTERS },\n // No maxRows: alarmSubscription() forces the default page size for a count, because the\n // number it shows is the SERVER total and the page is read only to sample the worst\n // loaded severity. An authored maxRows here would be read by nothing.\n options: {\n title: TITLE,\n state: ALARM_STATE,\n severity: ALARM_SEVERITY,\n acknowledged: ALARM_ACKNOWLEDGED,\n },\n defaults: { title: 'Alarm count', state: 'ACTIVE' },\n interactions: {},\n layout: { defaultSpan: { cols: 3, rows: 2 }, minSpan: { cols: 2, rows: 2 }, maxSpan: { cols: 6, rows: 4 } },\n }),\n\n // Alarms by severity, from ONE grouped count read (device-management's per-severity counts, every\n // originator, exact past any page). Not a mode of alarm-count: a different shape and size, and no\n // severity filter. `deviceType` narrows it to the alarms on one type's devices.\n 'alarm-severity': defineRuntimeDescriptor({\n id: 'alarm-severity',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: {\n title: 'Alarm severity',\n category: 'Alarms',\n titleId: 'widgetTypeAlarmSeverity',\n categoryId: 'widgetCategoryAlarms',\n },\n channel: 'alarm',\n datasource: { mode: 'optional', selectors: ALL_SELECTORS },\n binding: {\n pageSize: { const: 1 },\n state: { option: 'state' },\n acknowledged: { option: 'acknowledged' },\n countBySeverity: { const: true },\n deviceType: { option: 'deviceType' },\n },\n options: {\n title: TITLE,\n state: ALARM_STATE,\n acknowledged: ALARM_ACKNOWLEDGED,\n deviceType: {\n kind: 'string',\n control: 'device-type',\n labelId: 'widgetLabelAlarmSeverityType',\n helpId: 'widgetHintAlarmSeverityType',\n },\n },\n defaults: { title: 'Alarm severity', state: 'ACTIVE' },\n interactions: {},\n layout: { defaultSpan: { cols: 4, rows: 2 }, minSpan: { cols: 3, rows: 2 }, maxSpan: { cols: 12, rows: 4 } },\n }),\n\n 'command-button': defineRuntimeDescriptor({\n id: 'command-button',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Command button', category: 'Control', titleId: 'widgetTypeCommandButton', categoryId: 'widgetCategoryControl' },\n channel: 'control',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { pageSize: { option: 'maxRows', default: 20, min: 1 } },\n options: {\n title: TITLE,\n commandName: {\n kind: 'string',\n required: true,\n labelId: 'widgetCommandHeading',\n helpId: 'widgetCommandFieldHint',\n control: 'command-vocabulary',\n },\n commandLabel: {\n kind: 'string',\n labelId: 'widgetCommandHeading',\n helpId: 'widgetCommandFieldHint',\n control: 'command-vocabulary',\n },\n parameterSchema: {\n kind: 'string',\n format: 'json',\n labelId: 'widgetCommandHeading',\n helpId: 'widgetCommandFieldHint',\n control: 'command-vocabulary',\n },\n maxRows: {\n kind: 'number',\n integer: true,\n min: 1,\n labelId: 'widgetLabelMaxRows',\n helpId: 'widgetMaxRowsCommandHint',\n },\n },\n defaults: { title: 'Command button' },\n interactions: { commandSend: true },\n layout: { defaultSpan: { cols: 3, rows: 3 }, minSpan: { cols: 3, rows: 2 }, maxSpan: { cols: 6, rows: 6 } },\n }),\n\n 'entity-selector': defineRuntimeDescriptor({\n id: 'entity-selector',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Entity selector', category: 'Navigation', titleId: 'widgetTypeEntitySelector', categoryId: 'widgetCategoryNavigation' },\n channel: 'selection',\n datasource: NO_DATASOURCE,\n binding: {},\n options: {\n title: TITLE,\n selectionTarget: { ...SELECTION_TARGET, required: true },\n },\n defaults: { title: 'Entity selector' },\n interactions: { selection: true, candidates: true },\n // A select control is one line high, so its rows are pinned; it widens to fit long names.\n layout: { defaultSpan: { cols: 3, rows: 1 }, minSpan: { cols: 3, rows: 1 }, maxSpan: { cols: 12, rows: 1 }, resize: 'horizontal' },\n }),\n\n map: defineRuntimeDescriptor({\n id: 'map',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Map', category: 'Location', titleId: 'widgetTypeMap', categoryId: 'widgetCategoryLocation' },\n channel: 'location',\n datasource: { mode: 'required', selectors: ALL_SELECTORS },\n binding: {},\n // \uD83D\uDD34 tileUrl is NOT `required`, and that is the decision rather than an oversight.\n // `required` means \"absent leaves the widget with nothing to show\", and a map without\n // a basemap still shows every position it was asked to \u2014 on a plain panel, saying why\n // there is no map behind them. Marking it required would report a correctly-rendering\n // widget as broken on every board that names no provider of its own \u2014 which is most\n // of them, because the usual and recommended answer is to inherit the tenant's\n // basemap rather than to configure tiles per board.\n options: {\n title: TITLE,\n tileUrl: {\n kind: 'string',\n labelId: 'widgetLabelTileUrl',\n helpId: 'widgetTileUrlHint',\n control: 'basemap',\n },\n attribution: {\n kind: 'string',\n labelId: 'widgetLabelAttribution',\n helpId: 'widgetAttributionHint',\n control: 'basemap',\n },\n // Optional and additive: unset, a marker is only a mark. Set, clicking a marker re-points\n // that slot at the device, exactly as a fleet-table row does.\n selectionTarget: SELECTION_TARGET,\n },\n defaults: { title: 'Map' },\n interactions: { selection: true },\n layout: { defaultSpan: { cols: 6, rows: 4 }, minSpan: { cols: 4, rows: 3 } },\n }),\n\n // ---- Levels and indicators ------------------------------------------------\n // DOM/SVG single-value widgets on the measurement channel. A threshold band colours the fill\n // or lamp; `normal` keeps the widget's neutral accent.\n\n 'linear-gauge': defineRuntimeDescriptor({\n id: 'linear-gauge',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Linear gauge', category: 'Telemetry', titleId: 'widgetTypeLinearGauge', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: MEASUREMENT,\n min: SCALE_MIN,\n max: SCALE_MAX,\n style: {\n kind: 'enum',\n values: ['bar', 'thermometer'],\n labelId: 'widgetLabelLinearStyle',\n valueLabelIds: { bar: 'widgetLinearStyleBar', thermometer: 'widgetLinearStyleThermometer' },\n placeholderId: 'widgetPlaceholderDefault',\n },\n orientation: {\n kind: 'enum',\n values: ['horizontal', 'vertical'],\n labelId: 'widgetLabelOrientation',\n valueLabelIds: { horizontal: 'widgetOrientationHorizontal', vertical: 'widgetOrientationVertical' },\n placeholderId: 'widgetPlaceholderDefault',\n },\n unit: UNIT,\n precision: PRECISION,\n thresholds: THRESHOLDS,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n constraints: [{ kind: 'greater-than', key: 'max', than: 'min' }],\n defaults: { title: 'Linear gauge' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 4, rows: 3 }, minSpan: { cols: 3, rows: 3 }, maxSpan: { cols: 8, rows: 8 } },\n }),\n\n 'level-gauge': defineRuntimeDescriptor({\n id: 'level-gauge',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Level gauge', category: 'Telemetry', titleId: 'widgetTypeLevelGauge', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: MEASUREMENT,\n min: SCALE_MIN,\n max: SCALE_MAX,\n readout: {\n kind: 'enum',\n values: ['value', 'percent'],\n labelId: 'widgetLabelReadout',\n valueLabelIds: { value: 'widgetReadoutValue', percent: 'widgetReadoutPercent' },\n placeholderId: 'widgetPlaceholderDefault',\n },\n unit: UNIT,\n precision: PRECISION,\n thresholds: THRESHOLDS,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n constraints: [{ kind: 'greater-than', key: 'max', than: 'min' }],\n defaults: { title: 'Level gauge' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 3, rows: 4 }, minSpan: { cols: 2, rows: 3 }, maxSpan: { cols: 6, rows: 8 } },\n }),\n\n battery: defineRuntimeDescriptor({\n id: 'battery',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Battery', category: 'Telemetry', titleId: 'widgetTypeBattery', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: MEASUREMENT,\n min: {\n kind: 'number',\n labelId: 'widgetLabelMin',\n helpId: 'widgetHintBatteryRange',\n },\n max: {\n kind: 'number',\n labelId: 'widgetLabelMax',\n helpId: 'widgetHintBatteryRange',\n },\n unit: UNIT,\n precision: PRECISION,\n thresholds: THRESHOLDS,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n constraints: [{ kind: 'greater-than', key: 'max', than: 'min' }],\n defaults: { title: 'Battery' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 3, rows: 2 }, minSpan: { cols: 2, rows: 2 }, maxSpan: { cols: 6, rows: 4 } },\n }),\n\n 'status-light': defineRuntimeDescriptor({\n id: 'status-light',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Status light', category: 'Telemetry', titleId: 'widgetTypeStatusLight', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: MEASUREMENT,\n onAt: {\n kind: 'number',\n labelId: 'widgetLabelOnAt',\n helpId: 'widgetHintOnAt',\n },\n unit: UNIT,\n precision: PRECISION,\n thresholds: THRESHOLDS,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n defaults: { title: 'Status light' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 2, rows: 2 }, minSpan: { cols: 2, rows: 2 }, maxSpan: { cols: 4, rows: 4 } },\n }),\n\n 'signal-bars': defineRuntimeDescriptor({\n id: 'signal-bars',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Signal bars', category: 'Telemetry', titleId: 'widgetTypeSignalBars', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: MEASUREMENT,\n unit: UNIT,\n precision: PRECISION,\n // One bar per threshold: the entries ARE the steps, so they are required.\n thresholds: {\n ...THRESHOLDS,\n maxItems: 8,\n required: true,\n helpId: 'widgetHintSignalThresholds',\n },\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n defaults: { title: 'Signal bars' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 2, rows: 2 }, minSpan: { cols: 2, rows: 2 }, maxSpan: { cols: 4, rows: 4 } },\n }),\n\n // ---- Radial family ----------------------------------------------------------\n // A heading on a full turn, and a ring filled between a configured min and max. The compass\n // draws on the registered gauge series; the ring is SVG. Both put their number in DOM text.\n\n compass: defineRuntimeDescriptor({\n id: 'compass',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Compass', category: 'Telemetry', titleId: 'widgetTypeCompass', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: MEASUREMENT,\n precision: {\n ...PRECISION,\n },\n thresholds: {\n ...THRESHOLDS,\n },\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n defaults: { title: 'Compass' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 4, rows: 4 }, minSpan: { cols: 3, rows: 3 }, maxSpan: { cols: 8, rows: 8 } },\n }),\n\n 'progress-ring': defineRuntimeDescriptor({\n id: 'progress-ring',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Progress ring', category: 'Telemetry', titleId: 'widgetTypeProgressRing', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: MEASUREMENT,\n min: SCALE_MIN,\n max: SCALE_MAX,\n readout: {\n kind: 'enum',\n values: ['percent', 'value'],\n labelId: 'widgetLabelReadout',\n valueLabelIds: { percent: 'widgetReadoutPercent', value: 'widgetReadoutValue' },\n placeholderId: 'widgetPlaceholderDefault',\n },\n unit: UNIT,\n precision: PRECISION,\n thresholds: THRESHOLDS,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n constraints: [{ kind: 'greater-than', key: 'max', than: 'min' }],\n defaults: { title: 'Progress ring' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 3, rows: 3 }, minSpan: { cols: 2, rows: 2 }, maxSpan: { cols: 6, rows: 6 } },\n }),\n\n 'command-slider': defineRuntimeDescriptor({\n id: 'command-slider',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Command slider', category: 'Control', titleId: 'widgetTypeCommandSlider', categoryId: 'widgetCategoryControl' },\n channel: 'control',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n // The control reads its last-sent value off this history, so it asks for a long one.\n binding: { pageSize: { const: 50 } },\n options: {\n title: TITLE,\n commandName: CONTROL_COMMAND_NAME,\n commandLabel: CONTROL_COMMAND_LABEL,\n parameterSchema: CONTROL_PARAMETER_SCHEMA,\n parameter: CONTROL_PARAMETER,\n min: {\n kind: 'number',\n labelId: 'widgetLabelMin',\n helpId: 'widgetHintSliderRange',\n },\n max: {\n kind: 'number',\n labelId: 'widgetLabelMax',\n helpId: 'widgetHintSliderRange',\n },\n step: {\n kind: 'number',\n min: 0,\n labelId: 'widgetLabelStep',\n helpId: 'widgetHintSliderStep',\n },\n mode: {\n kind: 'enum',\n values: ['slider', 'stepper'],\n labelId: 'widgetLabelControlMode',\n valueLabelIds: { slider: 'widgetControlModeSlider', stepper: 'widgetControlModeStepper' },\n placeholderId: 'widgetPlaceholderDefault',\n },\n },\n constraints: [{ kind: 'greater-than', key: 'max', than: 'min' }],\n defaults: { title: 'Command slider' },\n interactions: { commandSend: true },\n layout: { defaultSpan: { cols: 4, rows: 2 }, minSpan: { cols: 3, rows: 2 }, maxSpan: { cols: 8, rows: 3 } },\n }),\n\n 'command-toggle': defineRuntimeDescriptor({\n id: 'command-toggle',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Command toggle', category: 'Control', titleId: 'widgetTypeCommandToggle', categoryId: 'widgetCategoryControl' },\n channel: 'control',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { pageSize: { const: 50 } },\n options: {\n title: TITLE,\n commandName: CONTROL_COMMAND_NAME,\n commandLabel: CONTROL_COMMAND_LABEL,\n parameterSchema: CONTROL_PARAMETER_SCHEMA,\n parameter: CONTROL_PARAMETER,\n },\n defaults: { title: 'Command toggle' },\n interactions: { commandSend: true },\n layout: { defaultSpan: { cols: 3, rows: 2 }, minSpan: { cols: 2, rows: 2 }, maxSpan: { cols: 6, rows: 3 } },\n }),\n 'stat-card': defineRuntimeDescriptor({\n id: 'stat-card',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Stat card', category: 'Telemetry', titleId: 'widgetTypeStatCard', categoryId: 'widgetCategoryTelemetry' },\n channel: 'aggregate',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { windowSeconds: { option: 'windowSeconds' } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: MEASUREMENT,\n stat: {\n kind: 'enum',\n values: ['avg', 'min', 'max', 'sum', 'count', 'last'],\n labelId: 'widgetLabelStat',\n helpId: 'widgetHintStat',\n valueLabelIds: {\n avg: 'widgetStatAvg',\n min: 'widgetStatMin',\n max: 'widgetStatMax',\n sum: 'widgetStatSum',\n count: 'widgetStatCount',\n last: 'widgetStatLast',\n },\n placeholderId: 'widgetPlaceholderDefault',\n },\n unit: UNIT,\n precision: PRECISION,\n thresholds: THRESHOLDS,\n sparkline: {\n kind: 'boolean',\n labelId: 'widgetLabelSparkline',\n helpId: 'widgetHintSparkline',\n },\n windowSeconds: WINDOW_SECONDS,\n },\n defaults: { title: 'Stat card' },\n interactions: {},\n layout: { defaultSpan: { cols: 3, rows: 3 }, minSpan: { cols: 3, rows: 2 }, maxSpan: { cols: 6, rows: 4 } },\n }),\n\n 'bar-chart': defineRuntimeDescriptor({\n id: 'bar-chart',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Bar chart', category: 'Telemetry', titleId: 'widgetTypeBarChart', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ALL_SELECTORS },\n // One bar per measurement of a device, or (groupBy device) one bar per member of an anchor.\n binding: { members: { option: 'groupBy', equals: 'device' } },\n options: {\n title: TITLE,\n groupBy: {\n kind: 'enum',\n values: ['measurement', 'device'],\n labelId: 'widgetLabelGroupBy',\n helpId: 'widgetHintGroupBy',\n valueLabelIds: { measurement: 'widgetGroupByMeasurement', device: 'widgetGroupByDevice' },\n placeholderId: 'widgetPlaceholderDefault',\n },\n measurement: MEASUREMENT,\n unit: UNIT,\n precision: PRECISION,\n sort: CATEGORY_SORT,\n },\n defaults: { title: 'Bar chart' },\n interactions: {},\n layout: { defaultSpan: { cols: 6, rows: 4 }, minSpan: { cols: 4, rows: 3 } },\n }),\n\n 'pie-chart': defineRuntimeDescriptor({\n id: 'pie-chart',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Pie chart', category: 'Telemetry', titleId: 'widgetTypePieChart', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: {},\n options: { title: TITLE, unit: UNIT, precision: PRECISION, sort: CATEGORY_SORT },\n defaults: { title: 'Pie chart' },\n interactions: {},\n layout: { defaultSpan: { cols: 4, rows: 4 }, minSpan: { cols: 3, rows: 3 }, maxSpan: { cols: 8, rows: 8 } },\n }),\n\n // A new widget rather than a mode of `table`: that one is one device's measurements as rows, on a\n // channel that keys its values by name; this one is a fleet, a row per member and a column per\n // measurement, and reads its data by device.\n 'fleet-table': defineRuntimeDescriptor({\n id: 'fleet-table',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Fleet table', category: 'Telemetry', titleId: 'widgetTypeFleetTable', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ALL_SELECTORS },\n binding: { windowSeconds: { option: 'windowSeconds' }, members: { const: true } },\n options: {\n title: TITLE,\n columns: FLEET_COLUMNS,\n thresholds: FLEET_THRESHOLDS,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n ageLagSeconds: {\n kind: 'number',\n integer: true,\n min: 1,\n labelId: 'widgetLabelAgeLag',\n helpId: 'widgetHintAgeLag',\n },\n sortBy: {\n kind: 'string',\n labelId: 'widgetLabelSortBy',\n helpId: 'widgetHintSortBy',\n },\n sortDescending: { kind: 'boolean', labelId: 'widgetLabelSortDescending' },\n pageSize: {\n kind: 'number',\n integer: true,\n min: 5,\n max: 100,\n labelId: 'widgetLabelPageSize',\n },\n selectionTarget: SELECTION_TARGET,\n windowSeconds: WINDOW_SECONDS,\n },\n defaults: { title: 'Fleet table' },\n // The frame shows the age of the newest reading in the fleet; each cell shows its own.\n freshness: true,\n interactions: { selection: true },\n layout: { defaultSpan: { cols: 12, rows: 6 }, minSpan: { cols: 6, rows: 3 } },\n }),\n\n // Counts a fleet rather than listing it: how many of its devices are in an abnormal band of one\n // measurement (\"3 of 21\"), or how many devices it has. A new widget rather than a mode of the\n // fleet table, which is a grid; this is the figure above one.\n 'fleet-count': defineRuntimeDescriptor({\n id: 'fleet-count',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Fleet count', category: 'Telemetry', titleId: 'widgetTypeFleetCount', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ALL_SELECTORS },\n binding: { windowSeconds: { option: 'windowSeconds' }, members: { const: true } },\n options: {\n title: TITLE,\n show: {\n kind: 'enum',\n values: ['attention', 'devices'],\n labelId: 'widgetLabelFleetShow',\n helpId: 'widgetHintFleetShow',\n valueLabelIds: { attention: 'widgetFleetShowAttention', devices: 'widgetFleetShowDevices' },\n placeholderId: 'widgetPlaceholderDefault',\n },\n measurement: {\n ...MEASUREMENT,\n },\n thresholds: THRESHOLDS,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n windowSeconds: WINDOW_SECONDS,\n },\n defaults: { title: 'Fleet count' },\n freshness: true,\n interactions: {},\n layout: { defaultSpan: { cols: 3, rows: 3 }, minSpan: { cols: 3, rows: 3 }, maxSpan: { cols: 6, rows: 4 } },\n }),\n\n // One device's connectivity: Online or Offline, and when it was last seen. It reads device-state\n // (`binding.presence`), not the device's readings, and shows one device, so it takes no group.\n 'device-status': defineRuntimeDescriptor({\n id: 'device-status',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Device status', category: 'Telemetry', titleId: 'widgetTypeDeviceStatus', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { presence: { const: true } },\n options: { title: TITLE, staleAfterSeconds: STALE_AFTER_SECONDS },\n defaults: { title: 'Device status' },\n // The frame's age is the status's: when device-state was last read, not the device's last activity.\n freshness: true,\n interactions: {},\n layout: { defaultSpan: { cols: 3, rows: 3 }, minSpan: { cols: 3, rows: 3 }, maxSpan: { cols: 6, rows: 4 } },\n }),\n\n // How many of a group's devices are online: a ring of online, offline and no status yet. A new\n // widget rather than a mode of the pie chart, which is shares of readings; this reads device-state.\n 'online-doughnut': defineRuntimeDescriptor({\n id: 'online-doughnut',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Online doughnut', category: 'Telemetry', titleId: 'widgetTypeOnlineDoughnut', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ALL_SELECTORS },\n binding: { presence: { const: true } },\n options: { title: TITLE, staleAfterSeconds: STALE_AFTER_SECONDS },\n defaults: { title: 'Online doughnut' },\n // The frame's age is the status's: when device-state was last read for the group.\n freshness: true,\n interactions: {},\n layout: { defaultSpan: { cols: 4, rows: 4 }, minSpan: { cols: 3, rows: 3 }, maxSpan: { cols: 8, rows: 8 } },\n }),\n\n // One device's stored history as rows: a row per time bucket over the span, a column per\n // measurement, each cell the bucket's AVERAGE (the table says \"avg per 5m\"). It reads the store's\n // buckets (`binding.history`), never the live feed, so it is time-ranged and takes one device.\n 'history-table': defineRuntimeDescriptor({\n id: 'history-table',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'History table', category: 'Telemetry', titleId: 'widgetTypeHistoryTable', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { windowSeconds: { option: 'windowSeconds' }, history: { const: true } },\n options: {\n title: TITLE,\n columns: FLEET_COLUMNS,\n precision: PRECISION,\n oldestFirst: { kind: 'boolean', labelId: 'widgetLabelOldestFirst' },\n pageSize: {\n kind: 'number',\n integer: true,\n min: 5,\n max: 100,\n labelId: 'widgetLabelRowsPerPage',\n },\n staleAfterSeconds: STALE_AFTER_SECONDS,\n windowSeconds: WINDOW_SECONDS,\n },\n defaults: { title: 'History table' },\n // The frame's age is the table's: when its buckets were last read.\n freshness: true,\n interactions: {},\n layout: { defaultSpan: { cols: 6, rows: 5 }, minSpan: { cols: 4, rows: 3 } },\n }),\n} as const satisfies Record<BuiltinWidgetId, WidgetDescriptor>;\n\n// The catalog the headless validators read. Constructed at module load, so a built-in that\n// fails its own validation fails every consumer of this package on import \u2014 loudly, and not\n// only in a test.\nexport const builtinWidgetCatalog = createWidgetCatalog(Object.values(builtinWidgetDescriptors));\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The alarm registrations: descriptor eager, component lazy, from a chunk of their own\n// (alarm-widgets.ts), so a board without an alarm table or alarm count never downloads them.\n//\n// AlarmTable and AlarmCount are also public exports of this package. That keeps them in this\n// package's own entry graph, and a host bundler drops them from its first download only because\n// package.json declares the modules free of side effects (see dist-shape.test.ts).\n\nimport { defineWidget, type AlarmStreamState } from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { lazyChunk } from './lazy-chunk';\n\nconst chunk = lazyChunk<typeof import('./alarm-widgets'), AlarmStreamState>(() => import('./alarm-widgets'));\n\nexport const loadAlarmWidgets = chunk.load;\n\nexport const alarmTableWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['alarm-table'],\n implementation: { kind: 'trusted-react', component: chunk.component('AlarmTable') },\n});\n\nexport const alarmSeverityWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['alarm-severity'],\n implementation: { kind: 'trusted-react', component: chunk.component('AlarmSeverity') },\n});\n\nexport const alarmCountWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['alarm-count'],\n implementation: { kind: 'trusted-react', component: chunk.component('AlarmCount') },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The command-control registrations: descriptor eager, component lazy, from a chunk of their own\n// (control-widgets.ts) so a board without a command button, slider or toggle never downloads the\n// sending code.\n\nimport { defineWidget, type CommandStreamState } from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { lazyChunk } from './lazy-chunk';\n\nconst chunk = lazyChunk<typeof import('./control-widgets'), CommandStreamState>(() => import('./control-widgets'));\n\nexport const loadControlWidgets = chunk.load;\n\nexport const commandSliderWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['command-slider'],\n implementation: { kind: 'trusted-react', component: chunk.component('CommandSlider') },\n});\n\nexport const commandToggleWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['command-toggle'],\n implementation: { kind: 'trusted-react', component: chunk.component('CommandToggle') },\n});\n\nexport const commandButtonWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['command-button'],\n implementation: { kind: 'trusted-react', component: chunk.component('CommandButton') },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The history table's registration: descriptor eager, component lazy, from a chunk of its own\n// (history-widgets.ts), so a board without one never downloads it.\n\nimport { defineWidget } from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { lazyChunk } from './lazy-chunk';\n\nconst chunk = lazyChunk<typeof import('./history-widgets')>(() => import('./history-widgets'));\n\nexport const loadHistoryWidgets = chunk.load;\n\nexport const historyTableWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['history-table'],\n implementation: { kind: 'trusted-react', component: chunk.component('HistoryTable') },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The presence registrations: descriptor eager, component lazy, from a chunk of their own\n// (presence-widgets.ts), so a board without a device status card or an online doughnut never\n// downloads them.\n\nimport { defineWidget } from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { lazyChunk } from './lazy-chunk';\n\nconst chunk = lazyChunk<typeof import('./presence-widgets')>(() => import('./presence-widgets'));\n\nexport const loadPresenceWidgets = chunk.load;\n\nexport const deviceStatusWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['device-status'],\n implementation: { kind: 'trusted-react', component: chunk.component('DeviceStatus') },\n});\n\nexport const onlineDoughnutWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['online-doughnut'],\n implementation: { kind: 'trusted-react', component: chunk.component('OnlineDoughnut') },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The entity selector's registration: descriptor eager, component lazy, from a chunk of its own,\n// so a board with no selector never downloads it. EntitySelector is also a public export; see\n// alarm-lazy.tsx for what that means for a host's first download.\n\nimport { defineWidget } from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { lazyChunk } from './lazy-chunk';\n\nconst chunk = lazyChunk<typeof import('./entity-selector'), null>(() => import('./entity-selector'));\n\nexport const loadSelectionWidgets = chunk.load;\n\nexport const entitySelectorWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['entity-selector'],\n implementation: { kind: 'trusted-react', component: chunk.component('EntitySelector') },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// gauge \u2014 the current value of one measurement on an ECharts radial gauge.\n\nimport { useMemo } from 'react';\n\nimport {\n defineWidget,\n flashBackgroundStyle,\n formatValue,\n optBoolean,\n optNumber,\n optString,\n optThresholds,\n pickSample,\n primaryMeasurementName,\n useFlashOnChange,\n useWidgetScale,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\nimport { buildGaugeOption, EChart, gaugeReadoutBox, loadChartEngine, useChartTheme } from '@devicechain/widget-sdk/echarts';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { NoReading, useSettledEmpty } from './no-reading-lazy';\nimport { LevelReadout } from '../level-readout';\nimport { readRange } from '../value-scale';\n\nexport function Gauge({ widget, data }: WidgetProps) {\n const name = primaryMeasurementName(widget);\n const sample = pickSample(data.latest, name);\n return (\n <WidgetFrame title={optString(widget.options, 'title') ?? name} sampleTime={sample?.occurredTime ?? null} flush>\n <GaugeBody widget={widget} data={data} />\n </WidgetFrame>\n );\n}\n\n// Rendered INSIDE the frame: the widget scale is the frame's content column, which is only in\n// context below the frame.\nfunction GaugeBody({ widget, data }: WidgetProps) {\n const theme = useChartTheme();\n const { size, scale } = useWidgetScale();\n const name = primaryMeasurementName(widget);\n const sample = pickSample(data.latest, name);\n\n const min = optNumber(widget.options, 'min');\n const max = optNumber(widget.options, 'max');\n const unit = optString(widget.options, 'unit');\n const precision = optNumber(widget.options, 'precision');\n // The stored list is re-parsed only when the options bag changes, so the memo below keys on\n // a stable array rather than a fresh one per render.\n const thresholds = useMemo(() => optThresholds(widget.options, 'thresholds'), [widget.options]);\n\n const option = useMemo(\n () => buildGaugeOption(sample?.value ?? null, theme, { min, max, thresholds, scale, readout: 'none', emptyNeedle: 'none' }, size),\n [sample?.value, theme, min, max, thresholds, scale, size],\n );\n\n // Opt-in directional flash. The value lives on an opaque canvas, so the cue is a\n // translucent tint on the container behind it rather than a recolored number. The identity\n // (device + measurement) suppresses a false flash on an anchor's cross-device interleave.\n const flashDirection = useFlashOnChange(\n sample?.value,\n optBoolean(widget.options, 'flashOnChange'),\n sample && `${sample.deviceToken}:${sample.name}`,\n );\n\n // The number is DOM text laid over the dial where the canvas used to print it, so the\n // readability gate can measure it (it cannot see canvas text). The meter role carries the\n // reading to assistive tech, which the canvas never did.\n const box = gaugeReadoutBox(size);\n const range = readRange(min, max, { min: 0, max: 100 });\n const value = sample?.value ?? undefined;\n const meter =\n range.ok && value !== undefined && Number.isFinite(value)\n ? {\n role: 'meter' as const,\n 'aria-valuemin': range.range.min,\n 'aria-valuemax': range.range.max,\n 'aria-valuenow': Math.min(range.range.max, Math.max(range.range.min, value)),\n 'aria-valuetext': `${formatValue(value, precision)}${unit ? ` ${unit}` : ''}`,\n }\n : {};\n\n // No reading: the dial would be an empty arc; say why instead (after the first moment, while a\n // board is still loading the dial is drawn as it always was).\n const explain = useSettledEmpty(value === undefined);\n if (explain) {\n return <NoReading unbound={widget.datasource?.kind === 'unbound'} measurement={name} waitMs={0} />;\n }\n\n return (\n <div style={{ position: 'relative', width: '100%', height: '100%', ...flashBackgroundStyle(flashDirection) }} {...meter}>\n <EChart option={option} />\n <div\n style={{\n position: 'absolute',\n left: box.centerX - box.width / 2,\n top: box.centerY - box.height / 2,\n width: box.width,\n height: box.height,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n pointerEvents: 'none',\n }}\n >\n <LevelReadout\n text={formatValue(value, precision)}\n unit={value === undefined ? undefined : unit}\n size={{ width: box.width, height: box.height }}\n scale={scale}\n />\n </div>\n </div>\n );\n}\n\n// What preloadWidgets calls: the chart engine loads on demand, as its own chunk, so a host that\n// awaits this for a board holding this widget draws the chart on the board's first frame.\nGauge.preload = loadChartEngine;\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const gaugeWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['gauge'],\n implementation: { kind: 'trusted-react', component: Gauge },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The explained empty state, as the EAGER widgets (the latest-value card, the gauge, the line chart)\n// reach it. The state itself (no-reading.tsx and the SDK's empty-state) loads as a chunk of its own on\n// first use: a board whose widgets all have data never downloads it, and the first-load budget\n// is not spent on words the common case does not show. Until it arrives the widget's box is empty,\n// which is the same as the one frame an empty widget was blank for before there was a state to show.\n\nimport { useEffect, useState } from 'react';\n\nimport { lazyChunk } from './lazy-chunk';\nimport type { NoReadingProps } from '../no-reading';\n\nexport const NoReading = lazyChunk<typeof import('../no-reading')>(() => import('../no-reading')).component<never, NoReadingProps>('NoReading');\n\n// True once `empty` has held for `ms`. A chart is blank for a moment on every board load while its\n// history seed is read, so it explains the absence only after that moment, not in a flash before data.\nexport function useSettledEmpty(empty: boolean, ms = 1500): boolean {\n const [settled, setSettled] = useState(false);\n useEffect(() => {\n if (!empty) {\n setSettled(false);\n return;\n }\n const timer = setTimeout(() => setSettled(true), ms);\n return () => clearTimeout(timer);\n }, [empty, ms]);\n return empty && settled;\n}\n\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// image \u2014 a static image on the canvas (floor plans, logos, SCADA backdrops). No\n// datasource; the Phase-4 SCADA symbol family will layer live SVG on top of this.\n\nimport type { CSSProperties } from 'react';\n\nimport {\n css,\n defineWidget,\n fontVar,\n optString,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\n\nconst FITS = new Set(['contain', 'cover', 'fill']);\n\nexport function Image({ widget }: WidgetProps<null>) {\n const url = optString(widget.options, 'url');\n const alt = optString(widget.options, 'alt') ?? '';\n const fitOption = optString(widget.options, 'fit');\n const objectFit = (fitOption && FITS.has(fitOption) ? fitOption : 'contain') as CSSProperties['objectFit'];\n\n return (\n <WidgetFrame title={optString(widget.options, 'title')} flush>\n {url ? (\n <img src={url} alt={alt} style={{ width: '100%', height: '100%', objectFit, display: 'block' }} />\n ) : (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n height: '100%',\n color: css('muted-foreground'),\n fontSize: fontVar('md'),\n }}\n >\n No image URL\n </div>\n )}\n </WidgetFrame>\n );\n}\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const imageWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['image'],\n implementation: { kind: 'trusted-react', component: Image },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// label \u2014 static text on the canvas (headings, captions, annotations). No\n// datasource. Renders plain text only (no raw HTML) so a tenant-authored\n// definition can't inject markup.\n\nimport type { CSSProperties } from 'react';\n\nimport {\n css,\n defineWidget,\n fontVar,\n spaceVar,\n optNumber,\n optString,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\n\nconst justify: Record<string, CSSProperties['justifyContent']> = {\n left: 'flex-start',\n center: 'center',\n right: 'flex-end',\n};\n\nexport function Label({ widget }: WidgetProps<null>) {\n const text = optString(widget.options, 'text') ?? '';\n const align = optString(widget.options, 'align') ?? 'center';\n // An authored size is a design size in px at the board's normal density: it scales with it,\n // so a wall board's label grows with the rest. Unset takes the large step of the type ramp.\n const authored = optNumber(widget.options, 'fontSize');\n const fontSize = authored !== undefined ? `calc(${authored}px * var(--dc-scale, 1))` : fontVar('lg');\n\n return (\n <WidgetFrame title={optString(widget.options, 'title')} flush>\n <div\n style={{\n display: 'flex',\n alignItems: 'safe center',\n justifyContent: justify[align] ?? 'center',\n height: '100%',\n boxSizing: 'border-box',\n overflow: 'hidden',\n // A label is often one row tall: the frame's uniform inset would leave it a line's\n // height or less, so it keeps a slim vertical inset and the usual side inset.\n padding: `${spaceVar(1)} ${spaceVar(3)}`,\n }}\n >\n <span\n style={{\n fontSize,\n color: css('foreground'),\n textAlign: align as CSSProperties['textAlign'],\n whiteSpace: 'pre-wrap',\n }}\n >\n {text}\n </span>\n </div>\n </WidgetFrame>\n );\n}\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const labelWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['label'],\n implementation: { kind: 'trusted-react', component: Label },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// latest-card \u2014 the current value of one measurement, big and legible.\n\nimport { useMemo } from 'react';\n\nimport {\n bandAt,\n css,\n defineWidget,\n fitValueFont,\n fitValueFontCss,\n FIT_MIN_FONT_PX,\n flashTextStyle,\n fontVar,\n formatTimestamp,\n formatValue,\n levelColor,\n optBoolean,\n optNumber,\n optString,\n optThresholds,\n pickSample,\n primaryMeasurementName,\n spaceVar,\n useSeverityColors,\n useStickyChars,\n useFlashOnChange,\n useWidgetTimeZone,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { NoReading } from './no-reading-lazy';\n\n// The room a timestamp line needs under the value. The frame's content column (what the\n// widget scale reports) is already net of the frame's padding.\nconst TIMESTAMP_ROOM_PX = 18;\n\nexport function LatestCard({ widget, data }: WidgetProps) {\n const severity = useSeverityColors();\n const timeZone = useWidgetTimeZone();\n const name = primaryMeasurementName(widget);\n const sample = pickSample(data.latest, name);\n\n const title = optString(widget.options, 'title') ?? name;\n const unit = optString(widget.options, 'unit');\n const precision = optNumber(widget.options, 'precision');\n const display = formatValue(sample?.value, precision);\n // The value reads in the colour of the band it falls in; below the lowest threshold (or with\n // none, or in a `normal` band) it keeps the foreground: colour only for the abnormal.\n const thresholds = useMemo(() => optThresholds(widget.options, 'thresholds'), [widget.options]);\n const band = bandAt(thresholds, sample?.value);\n const valueColor = levelColor(severity, band?.level) ?? css('foreground');\n\n // Opt-in directional flash: tint the number green/red on a rise/fall, then fade back. The\n // identity (device + measurement) suppresses a false flash when an anchor's single slot\n // interleaves values across member devices, or the shown measurement switches.\n const flashDirection = useFlashOnChange(\n sample?.value,\n optBoolean(widget.options, 'flashOnChange'),\n sample && `${sample.deviceToken}:${sample.name}`,\n );\n\n // Fit the value to the card from both dimensions and the string length (the unit renders at\n // half size, so it counts for half its characters).\n // Sticky: the longest length seen lately, so a value crossing 9.99 -> 10.01 holds its size.\n const chars = useStickyChars(display.length + (sample?.value != null && unit ? Math.ceil(unit.length / 2) + 1 : 0));\n return (\n <WidgetFrame title={title} sampleTime={sample?.occurredTime ?? null}>\n {({ size, scale }) => {\n // No reading: say why, rather than print a bare dash.\n if (sample?.value == null) {\n return <NoReading unbound={widget.datasource?.kind === 'unbound'} measurement={name} />;\n }\n // Measured: the JS curve. Unmeasured (first frame): the SAME curve in cq units, resolved\n // by the browser against the frame's content column, so there is no fallback-size flash.\n const floor = Math.round(FIT_MIN_FONT_PX * scale);\n const measured = size.width > 0 && size.height > 0;\n const valuePx = measured ? fitValueFont(size, chars, { floor }) : undefined;\n const valueFont = valuePx ?? fitValueFontCss(chars, { floor });\n // The timestamp is the first thing to give: it shows only when the measured box has room\n // for it under the value (unmeasured -- first frame, jsdom -- it shows).\n const showTimestamp =\n valuePx === undefined || size.height - Math.ceil(valuePx * 1.1) >= TIMESTAMP_ROOM_PX * scale;\n return (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'safe center',\n height: '100%',\n boxSizing: 'border-box',\n overflow: 'hidden',\n }}\n >\n <div\n data-threshold-level={band?.level}\n title={band?.label}\n style={{\n fontSize: valueFont,\n fontWeight: 600,\n lineHeight: 1.1,\n // One line, and digits of one width: the fit counts characters, so a live value\n // must not wrap or shift sideways as its digits change.\n whiteSpace: 'nowrap',\n fontVariantNumeric: 'tabular-nums',\n color: valueColor,\n ...flashTextStyle(flashDirection),\n }}\n >\n {display}\n {sample?.value != null && unit ? (\n <span\n style={{\n fontSize: valuePx !== undefined ? Math.round(valuePx / 2) : `calc(${valueFont} / 2)`,\n color: css('muted-foreground'),\n marginLeft: spaceVar(1),\n }}\n >\n {unit}\n </span>\n ) : null}\n </div>\n {sample?.occurredTime && showTimestamp ? (\n <div style={{ fontSize: fontVar('xs'), color: css('muted-foreground'), marginTop: spaceVar(1) }}>\n {formatTimestamp(sample.occurredTime, timeZone)}\n </div>\n ) : null}\n </div>\n );\n }}\n </WidgetFrame>\n );\n}\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const latestCardWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['latest-card'],\n implementation: { kind: 'trusted-react', component: LatestCard },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The level, indicator and radial registrations: descriptor eager, component lazy. The descriptors\n// are the catalog (the editor, the validators and WIDGET_TYPES read them without rendering\n// anything), so they stay in the entry; the seven components load on first mount, together,\n// from one chunk (level-widgets.ts), so a board without one of them never downloads it.\n//\n// Until the chunk arrives the widget renders nothing inside its box. A chunk that fails to\n// load is THROWN, so the widget's error boundary shows the failure: an empty tank that looks\n// like a reading is the outcome this must never produce.\n\nimport { defineWidget } from '@devicechain/widget-sdk';\nimport { loadChartEngine } from '@devicechain/widget-sdk/echarts';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { lazyChunk } from './lazy-chunk';\n\nconst chunk = lazyChunk(() => import('./level-widgets'));\n\nexport const loadLevelWidgets = chunk.load;\n\nconst lazyComponent = chunk.component;\n\nexport const linearGaugeWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['linear-gauge'],\n implementation: { kind: 'trusted-react', component: lazyComponent('LinearGauge') },\n});\n\nexport const levelGaugeWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['level-gauge'],\n implementation: { kind: 'trusted-react', component: lazyComponent('LevelGauge') },\n});\n\nexport const batteryWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['battery'],\n implementation: { kind: 'trusted-react', component: lazyComponent('Battery') },\n});\n\nexport const statusLightWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['status-light'],\n implementation: { kind: 'trusted-react', component: lazyComponent('StatusLight') },\n});\n\nexport const signalBarsWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['signal-bars'],\n implementation: { kind: 'trusted-react', component: lazyComponent('SignalBars') },\n});\n\nexport const compassWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['compass'],\n implementation: { kind: 'trusted-react', component: lazyComponent('Compass', loadChartEngine) },\n});\n\nexport const progressRingWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['progress-ring'],\n implementation: { kind: 'trusted-react', component: lazyComponent('ProgressRing') },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// map \u2014 the bound devices' last-known positions, on the location channel.\n//\n// Three rules shape everything here, and each of them is a state some other design\n// would have collapsed into \"the map is empty\":\n//\n// \uD83D\uDD34 REFUSED IS NOT EMPTY. Position is gated on its own `location:read` authority,\n// deliberately absent from the read-only viewer baseline, so an ordinary member with\n// full telemetry access is routinely refused. \"No devices to show\" and \"you are not\n// allowed to see this\" are opposite facts and only one of them is actionable, so the\n// refusal gets its own copy and its own look \u2014 never a blank map.\n//\n// \uD83D\uDD34 NO TILE SOURCE IS NOT A BROKEN MAP. This package hardcodes no tile URL (see\n// rasterStyleFor) and inherits one from the tenant (ADR-079), whose instance-wide\n// default now ships a real provider \u2014 so in practice this branch is rare. It is not\n// dead, though: an operator can empty that default, an air-gapped install can have no\n// route to any provider at all, and a viewer can be looking at a board on either.\n//\n// That case renders a REAL MapLibre map against the BUNDLED public-domain world\n// (loadLandStyle) \u2014 continents and country outlines, compiled into this package.\n//\n// \uD83D\uDD34 Be precise about what survives of the old promise, because an earlier version of\n// this comment was not. It said the widget \"issues no request to any host\" and backed\n// that with \"loads no map library\", and the second half is now FALSE: this path loads\n// the renderer and the geometry, two chunks, from the app's OWN origin. What is still\n// true \u2014 and is the part that ever mattered \u2014 is that it contacts no THIRD-PARTY host,\n// because it has been given none it would be entitled to ask. What it no longer does\n// is show a void that reads as breakage.\n//\n// \uD83D\uDD34 ABSENT IS NOT ZERO. A marker describes only what its device reported; an\n// unreported heading is not due north. See describePosition.\n\nimport { useEffect, useRef, useState, type CSSProperties } from 'react';\nimport { renderableBasemap, resolveBasemap } from '@devicechain/client';\n\nimport { useTenantBasemap } from '../basemap-context';\nimport { useMapRuntime, type MapRuntime } from '../map-runtime-context';\nimport {\n css,\n fontVar,\n defineWidget,\n type LocationStreamState,\n optString,\n useWidgetSelect,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport {\n describePosition,\n loadLandStyle,\n placeable,\n projectToPanel,\n rasterStyleFor,\n type PlaceableLocation,\n} from './map-geometry';\n\n// The MapLibre pieces this widget drives. A TYPE-only import is erased at build time,\n// so naming them here creates no static dependency on the library \u2014 the value only ever\n// arrives through the dynamic import below.\nimport type { Map as MapLibreMap, Marker as MapLibreMarker } from 'maplibre-gl';\n\n// \uD83D\uDD34 THE LIBRARY IS LOADED LAZILY, BY CONSTRUCTION. MapLibre is ~200 KB gzipped, and\n// only a dashboard that actually contains a map widget may pay for it \u2014 a console user\n// who never opens a board with a map must not download a map renderer. The dynamic\n// import is what puts it in its own chunk; a top-level `import 'maplibre-gl'` anywhere\n// in this package would fold it into the main bundle for every viewer, and nothing\n// about the widget's behaviour would change to reveal it.\n//\n// MapLibre's STYLESHEET is no longer imported here at all \u2014 it is the host's, along with\n// the worker URL, for the reason set out below and in map-runtime-context. A host may hand\n// back a loader for it (`MapRuntime.loadStyles`) to keep it on this same lazy chunk, or\n// import it eagerly and pay 83 KB (10.7 KB gzipped) in its main stylesheet. That is the\n// host's call, and both are reasonable; what a LIBRARY cannot do is decide it for them in\n// one bundler's dialect.\n//\n// Loaded once and memoized: several map widgets on one board share the fetch.\nlet mapLibrePromise: Promise<typeof import('maplibre-gl')> | undefined;\n\n// \uD83D\uDD34 THE WORKER HAS TO BE ASKED FOR BY NAME, and getting this wrong produces a map\n// that builds, type-checks, passes every test and then renders nothing. MapLibre\n// otherwise derives the worker's URL at runtime from its own module URL, which is a\n// string no bundler can follow \u2014 nothing emits the file, the browser 404s it, and\n// `new Worker()` does not throw on a 404: the failure arrives later as an async error\n// event, so the map simply sits there having loaded no tiles.\n//\n// \uD83D\uDD34 THE URL COMES FROM THE HOST, and this package no longer computes it. Emitting a\n// worker entry is a bundler-specific act \u2014 Vite spells it `?worker&url`, webpack and\n// Rollup spell it differently \u2014 so a library that writes one dialect works under that\n// bundler and silently renders a blank map under every other. See map-runtime-context\n// for the full argument; the short version is that the specifier is externalized, so\n// no build anywhere reports the breakage.\n//\n// Memoized for the whole module, and FIRST CALLER WINS: several map widgets on one\n// board share the fetch, and `setWorkerUrl` is global state in MapLibre, so a second\n// caller with a different URL could not be honoured even if we tried. In practice\n// there is one provider at the top of the tree and therefore one URL.\nfunction loadMapLibre(runtime: MapRuntime): Promise<typeof import('maplibre-gl')> {\n if (!mapLibrePromise) {\n // The stylesheet rides the SAME dynamic boundary as the renderer, which is why a host\n // may pass a loader rather than importing it at module scope: it is 83 KB raw, 10.7 KB\n // gzipped (maplibre-gl 6.6.0), and a viewer who opens no map should download none of\n // it. Optional \u2014 a host that imports the stylesheet itself is doing the ordinary thing.\n //\n // \uD83D\uDD34 `Promise.resolve().then(...)` IS NOT CEREMONY. `loadStyles()` is host code, and a\n // host CAN throw synchronously \u2014 `loadStyles: () => require('\u2026css')` on a bundler with\n // no CSS loader is the realistic form. Called while building the argument array, that\n // throw escapes loadMapLibre entirely, propagates through the caller's own\n // `Promise.all` argument evaluation, and lands in React's commit phase where the\n // effect's `.catch` cannot see it: React 19 unmounts the tree, so one misconfigured\n // host loader takes down the whole dashboard instead of degrading to the plain panel.\n // Deferring the call puts it inside the promise chain, where the existing catch works.\n mapLibrePromise = Promise.all([\n import('maplibre-gl'),\n Promise.resolve().then(() => runtime.loadStyles?.()),\n ]).then(([mod]) => {\n mod.setWorkerUrl(runtime.workerUrl);\n return mod;\n });\n }\n return mapLibrePromise;\n}\n\n// The zoom a single-device map opens at \u2014 close enough to read a site, wide enough that\n// a lone marker is not floating in featureless tiles. A multi-device map ignores it and\n// fits the fleet's bounds instead.\nconst SINGLE_DEVICE_ZOOM = 14;\n\nexport function MapWidget({ widget, data }: WidgetProps<LocationStreamState>) {\n const title = optString(widget.options, 'title');\n const positions = placeable(data.locations);\n\n // The host's bundler-produced MapLibre runtime. Read unconditionally, with the other\n // hooks, because a hook cannot live behind one of the early returns below.\n const runtime = useMapRuntime();\n\n // A marker click re-points the target slot at that device, so the widgets bound to it follow\n // (the same linked-selection seam a fleet-table row uses). Undefined unless the author named a\n // target slot AND the host wires selection: with either missing a marker is only a mark, and\n // it neither looks nor behaves clickable. Hook order: read before the early returns below.\n const select = useWidgetSelect();\n const selectionTarget = optString(widget.options, 'selectionTarget');\n const pick: PickDevice | undefined =\n select && selectionTarget\n ? (deviceToken) => select({ slot: selectionTarget, binding: { kind: 'device', deviceToken } })\n : undefined;\n\n // Precedence is per-widget override \u2192 tenant \u2192 no basemap (ADR-079 \u00A79). The\n // per-widget options are kept, not replaced: they are how someone tries a provider\n // on one board before committing it tenant-wide.\n //\n // \uD83D\uDD34 resolveBasemap is NOT `override ?? tenant` per field. A widget that names its\n // own tile URL does not inherit the tenant's credit line, because that would credit\n // the tenant's provider for tiles it did not serve. The SDK owns that rule so the\n // fence editor and the /dash app cannot disagree with this widget about it.\n const basemap = renderableBasemap(\n resolveBasemap(\n {\n tileUrl: optString(widget.options, 'tileUrl'),\n attribution: optString(widget.options, 'attribution'),\n },\n useTenantBasemap(),\n ),\n );\n\n // The refusal is checked FIRST and unconditionally: it is a fact about the caller, so\n // it outranks anything about the data, and it must not be reachable only through some\n // \"no positions\" branch that a later edit could reorder past.\n if (data.forbidden) {\n return (\n <WidgetFrame title={title}>\n <MapNotice\n glyph=\"\uD83D\uDD12\"\n heading=\"Location not permitted\"\n detail=\"You do not have permission to view device locations.\"\n />\n </WidgetFrame>\n );\n }\n\n // \uD83D\uDD34 AND THE HOST'S OWN WIRING IS CHECKED SECOND, for the same reason the refusal is\n // checked first: it is a fact about the environment rather than about the data, so it\n // outranks every \"nothing to show\" branch below. Checking it later would hide it behind\n // \"No devices selected\" on exactly the board a developer is using to find it.\n //\n // There is no fallback to take. The only alternative to a host-supplied worker URL is\n // MapLibre's runtime derivation, which is the silent blank map this seam exists to\n // prevent \u2014 so an unwired host is told, in the widget, what it has to install.\n if (!runtime) {\n return (\n <WidgetFrame title={title}>\n <MapNotice\n glyph=\"\uD83E\uDDE9\"\n heading=\"Map runtime not configured\"\n detail=\"This host must install MapRuntimeProvider with its bundler's MapLibre worker URL.\"\n />\n </WidgetFrame>\n );\n }\n\n if (data.loading && positions.length === 0) {\n return (\n <WidgetFrame title={title}>\n <MapNotice heading=\"Loading\u2026\" />\n </WidgetFrame>\n );\n }\n\n if (positions.length === 0) {\n // Two different empty states, because they call for two different actions: bind the\n // widget, or wait for a device to report.\n return (\n <WidgetFrame title={title}>\n <MapNotice\n heading={data.deviceTokens.length === 0 ? 'No devices selected' : 'No positions reported'}\n detail={\n data.deviceTokens.length === 0\n ? 'Bind this widget to a device or anchor and select its location series.'\n : 'None of the selected devices has reported a position yet.'\n }\n />\n </WidgetFrame>\n );\n }\n\n return (\n <WidgetFrame title={title} flush>\n <LiveMap basemap={basemap} positions={positions} runtime={runtime} pick={pick} />\n </WidgetFrame>\n );\n}\n\n// ---- The tile-less panel ----------------------------------------------------\n\n// PlainPanel draws the positions on a themed background with no basemap at all.\n//\n// \uD83D\uDD34 IT HAS EXACTLY ONE JOB LEFT, AND IT IS NOT THE UNCONFIGURED CASE. Since the\n// bundled world basemap landed, an unconfigured widget renders a REAL MapLibre map\n// against public-domain geometry \u2014 so this panel is reached only when the map could\n// not be BUILT at all. Three ways in, not one: the MapLibre chunk fails to load, the\n// bundled-geometry chunk fails to load, or the Map constructor throws (a browser or a\n// context with no usable WebGL). They share a catch because they share an answer.\n//\n// It survives because on that path it is strictly better than an error box. The\n// question a map widget answers is \"where is my fleet, relative to each other\",\n// and this still answers it when the renderer cannot load. That is also why\n// projectToPanel exists at all, and why deleting either would look like tidying up\n// dead code right until someone's dashboard went blank behind a proxy.\nfunction PlainPanel({\n positions,\n note,\n pick,\n}: {\n positions: PlaceableLocation[];\n note: string;\n pick: PickDevice | undefined;\n}) {\n const points = projectToPanel(positions);\n return (\n <div\n data-testid=\"map-plain-panel\"\n style={{\n position: 'relative',\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n background: css('muted'),\n }}\n >\n {positions.map((position, i) => (\n <Marker\n key={position.deviceToken}\n position={position}\n pick={pick}\n style={{\n position: 'absolute',\n left: `${points[i].x * 100}%`,\n top: `${points[i].y * 100}%`,\n transform: 'translate(-50%, -50%)',\n }}\n />\n ))}\n <div\n data-testid=\"map-no-tiles-note\"\n style={{\n position: 'absolute',\n left: 0,\n right: 0,\n bottom: 0,\n padding: '4px 8px',\n fontSize: fontVar('sm'),\n lineHeight: 1.3,\n textAlign: 'center',\n color: css('muted-foreground'),\n background: css('card'),\n opacity: 0.9,\n }}\n >\n {note}\n </div>\n </div>\n );\n}\n\n// ---- The map ----------------------------------------------------------------\n\ntype MapStatus = 'loading' | 'ready' | 'unavailable';\n\n// LiveMap renders MapLibre for BOTH basemap states.\n//\n// The branch is over the STYLE, not over whether there is a map: a configured tile\n// source gets a raster style, and no tile source gets the bundled public-domain\n// world. Everything downstream of that \u2014 the projection, the markers, the fit, the\n// teardown \u2014 is the same code on both paths, which is the point. When the two were\n// different components, \"unconfigured\" was a second rendering path that could drift\n// away from the real one without any test noticing.\n// `runtime` is a required prop rather than a context read, so that LiveMap cannot be\n// constructed without one. The null case is handled once, in MapWidget, and this\n// component never has to reason about it.\nfunction LiveMap({\n basemap,\n positions,\n runtime,\n pick,\n}: {\n basemap: { tileUrl: string; attribution: string | null } | null;\n positions: PlaceableLocation[];\n runtime: MapRuntime;\n pick: PickDevice | undefined;\n}) {\n const containerRef = useRef<HTMLDivElement>(null);\n const mapRef = useRef<MapLibreMap | null>(null);\n const markersRef = useRef<MapLibreMarker[]>([]);\n const [status, setStatus] = useState<MapStatus>('loading');\n // The markers are rebuilt only when positions change, so the click handler they hold reads the\n // CURRENT pick through a ref instead of closing over the one from the render that built them.\n const pickRef = useRef(pick);\n pickRef.current = pick;\n const selectable = pick !== undefined;\n\n const tileUrl = basemap?.tileUrl ?? null;\n const attribution = basemap?.attribution ?? null;\n\n // Init + teardown for this basemap. Re-runs when the source changes, which is the\n // only thing that invalidates the style.\n useEffect(() => {\n let cancelled = false;\n setStatus('loading');\n\n // \uD83D\uDD34 The bundled style is FETCHED, not built inline: its geometry sits behind a\n // dynamic import so a configured viewer never downloads a world map they will\n // not look at. Resolved alongside the renderer so the Map is still constructed\n // once, with its final style \u2014 nothing re-styles after mount.\n Promise.all([\n loadMapLibre(runtime),\n tileUrl ? rasterStyleFor(tileUrl, attribution ?? undefined) : loadLandStyle(),\n ])\n .then(([maplibre, style]) => {\n const el = containerRef.current;\n if (cancelled || !el) return;\n const map = new maplibre.Map({\n container: el,\n style: style as never,\n center: [0, 0],\n zoom: 1,\n });\n mapRef.current = map;\n setStatus('ready');\n })\n .catch(() => {\n // The renderer or the bundled geometry could not be fetched (offline viewer,\n // a CSP that blocks the chunk). Fall back to the plain panel rather than to\n // nothing: the positions are what the operator came for, and the basemap is\n // the part that failed.\n if (!cancelled) setStatus('unavailable');\n });\n\n return () => {\n cancelled = true;\n for (const marker of markersRef.current) marker.remove();\n markersRef.current = [];\n mapRef.current?.remove();\n mapRef.current = null;\n };\n // \uD83D\uDD34 Keyed on runtime.workerUrl, NOT on `runtime`. A host that builds the runtime\n // inline in JSX hands a new object every render; depending on the object would tear the\n // map down and rebuild it each time, which looks like flicker and loses view state. The\n // URL is the only part of it this effect's outcome depends on.\n //\n // `runtime.loadStyles` is used inside and is deliberately not a dependency: loadMapLibre\n // memoizes at module scope, first caller wins, so only the first runtime's loader is\n // ever invoked and a later one could not take effect however this array were written.\n // That is the documented contract, not an oversight \u2014 and no eslint config in this repo\n // lints packages/*, so a disable comment here would suppress nothing and merely look\n // like the question had been settled by a linter.\n }, [tileUrl, attribution, runtime.workerUrl]);\n\n // Sync the markers to the current positions. Rebuilt wholesale rather than diffed:\n // a poll delivers a whole snapshot, the marker count is a dashboard's worth of\n // devices, and a diff here would be state to get wrong for no measurable saving.\n useEffect(() => {\n const map = mapRef.current;\n if (status !== 'ready' || !map) return;\n\n let live = true;\n loadMapLibre(runtime).then((maplibre) => {\n if (!live || mapRef.current !== map) return;\n for (const marker of markersRef.current) marker.remove();\n markersRef.current = positions.map((position) => {\n const el = document.createElement('div');\n el.setAttribute('data-testid', 'map-marker');\n el.setAttribute('data-device', position.deviceToken);\n el.setAttribute('title', describePosition(position));\n el.setAttribute('aria-label', describePosition(position));\n if (selectable) {\n // A 24 px target around the 12 px dot: a fingertip on a phone-width board cannot hit the dot.\n Object.assign(el.style, MARKER_HIT_STYLE);\n el.setAttribute('role', 'button');\n el.setAttribute('tabindex', '0');\n const dot = document.createElement('div');\n Object.assign(dot.style, MARKER_DOT_STYLE, { cursor: 'inherit' });\n el.appendChild(dot);\n const choose = () => pickRef.current?.(position.deviceToken);\n el.addEventListener('click', choose);\n el.addEventListener('keydown', (e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n choose();\n }\n });\n } else {\n Object.assign(el.style, MARKER_DOT_STYLE);\n }\n // \uD83D\uDD34 setLngLat takes [LONGITUDE, LATITUDE] \u2014 x before y, the opposite order\n // from how a coordinate is spoken and written everywhere else on the platform.\n // Swapping them puts a device reporting Atlanta into the Indian Ocean, which\n // renders perfectly.\n return new maplibre.Marker({ element: el })\n .setLngLat([position.longitude, position.latitude])\n .addTo(map);\n });\n\n if (positions.length === 1) {\n map.jumpTo({ center: [positions[0].longitude, positions[0].latitude], zoom: SINGLE_DEVICE_ZOOM });\n } else if (positions.length > 1) {\n const bounds = new maplibre.LngLatBounds();\n for (const p of positions) bounds.extend([p.longitude, p.latitude]);\n map.fitBounds(bounds, { padding: 40, animate: false });\n }\n });\n\n return () => {\n live = false;\n };\n // Positions are compared by VALUE: a poll hands back a fresh array every tick, and\n // rebuilding every marker 4 times a minute for an unchanged fleet would make the\n // markers flicker.\n }, [status, positionsKey(positions), selectable]);\n\n if (status === 'unavailable') {\n return (\n <PlainPanel\n positions={positions}\n note=\"Map renderer unavailable \u2014 positions are shown without a basemap.\"\n pick={pick}\n />\n );\n }\n\n return <div ref={containerRef} data-testid=\"map-canvas\" style={{ width: '100%', height: '100%' }} />;\n}\n\n// positionsKey is the value identity of a marker set: what is drawn, not which array\n// object carries it.\nfunction positionsKey(positions: PlaceableLocation[]): string {\n return positions.map((p) => `${p.deviceToken}:${p.latitude}:${p.longitude}:${p.heading ?? ''}`).join('|');\n}\n\n// ---- Shared bits ------------------------------------------------------------\n\n// What a marker click does: pick that device for the board's linked widgets. Absent = not selectable.\ntype PickDevice = (deviceToken: string) => void;\n\n// The clickable box around a selectable marker's dot (WCAG 2.5.8 asks for 24 px).\nconst MARKER_HIT_STYLE = {\n width: '24px',\n height: '24px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n cursor: 'pointer',\n} as const;\n\nconst MARKER_DOT_STYLE = {\n width: '12px',\n height: '12px',\n borderRadius: '50%',\n background: css('primary'),\n border: `2px solid ${css('card')}`,\n boxShadow: '0 0 0 1px rgba(0,0,0,0.25)',\n cursor: 'default',\n} as const;\n\n// Marker is the tile-less panel's dot. The tiled map builds an equivalent element\n// imperatively (MapLibre owns the DOM its markers live in), which is why the styling is\n// shared as an object rather than as a component.\nfunction Marker({\n position,\n style,\n pick,\n}: {\n position: PlaceableLocation;\n style: CSSProperties;\n pick: PickDevice | undefined;\n}) {\n const label = describePosition(position);\n if (pick) {\n return (\n <button\n type=\"button\"\n data-testid=\"map-marker\"\n data-device={position.deviceToken}\n title={label}\n aria-label={label}\n onClick={() => pick(position.deviceToken)}\n style={{ ...MARKER_HIT_STYLE, padding: 0, border: 0, background: 'transparent', ...style }}\n >\n <span style={{ ...MARKER_DOT_STYLE, cursor: 'inherit', display: 'block' }} />\n </button>\n );\n }\n return (\n <div\n data-testid=\"map-marker\"\n data-device={position.deviceToken}\n title={label}\n aria-label={label}\n style={{ ...MARKER_DOT_STYLE, ...style }}\n />\n );\n}\n\n// MapNotice is the widget's non-map state: permission, loading, empty. One component so\n// the three read as siblings \u2014 a viewer should be able to tell them apart by their words,\n// not by their layout.\nfunction MapNotice({ glyph, heading, detail }: { glyph?: string; heading: string; detail?: string }) {\n return (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'safe center',\n overflow: 'hidden',\n gap: 4,\n width: '100%',\n height: '100%',\n boxSizing: 'border-box',\n textAlign: 'center',\n color: css('muted-foreground'),\n }}\n >\n {glyph ? (\n <div style={{ fontSize: fontVar('xl'), lineHeight: 1 }} aria-hidden=\"true\">\n {glyph}\n </div>\n ) : null}\n <div style={{ fontSize: fontVar('md'), fontWeight: 600 }}>{heading}</div>\n {detail ? <div style={{ fontSize: fontVar('sm'), opacity: 0.8 }}>{detail}</div> : null}\n </div>\n );\n}\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const mapWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['map'],\n implementation: { kind: 'trusted-react', component: MapWidget },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The map widget's pure parts: which samples are placeable, where they land on a\n// tile-less panel, and how a fix is described in words.\n//\n// Split out from the component for the usual reason the chart-option builders are \u2014\n// this is the arithmetic that decides whether a marker is in the right place, and it is\n// worth an awful lot more when it can be asserted directly than when it can only be\n// inferred from a rendered `style` string.\n\nimport type { LocationSample } from '@devicechain/dashboards';\n\n// A sample that actually has coordinates. A LocationSample's latitude/longitude are\n// nullable (the projection's columns are), and a sample missing either is not a\n// position \u2014 placing it would put a marker at (0, 0) in the Gulf of Guinea and label it\n// with a real device's name.\nexport interface PlaceableLocation extends LocationSample {\n latitude: number;\n longitude: number;\n}\n\n// placeable keeps the samples that can be drawn.\n//\n// `!= null`, NOT truthiness: latitude 0 is the equator and longitude 0 is Greenwich,\n// and both are real reported positions. A truthy filter would silently drop a device\n// sitting on either line.\nexport function placeable(samples: readonly LocationSample[]): PlaceableLocation[] {\n return samples.filter(\n (s): s is PlaceableLocation => s.latitude != null && s.longitude != null,\n );\n}\n\n// A point on the tile-less panel, as a FRACTION of its width/height, so the component\n// can express it as a percentage and stay resolution-independent.\nexport interface PanelPoint {\n x: number;\n y: number;\n}\n\n// Fraction of the panel kept clear at each edge, so a marker at the extreme of the\n// bounding box sits inside the panel rather than half-clipped by it.\nconst PANEL_PADDING = 0.1;\n\n// projectToPanel lays a set of positions out on a plain (tile-less) panel.\n//\n// An equirectangular fit of the positions' own bounding box: longitude \u2192 x, latitude \u2192\n// y, each stretched across the padded panel. Deliberately NOT a web-mercator\n// projection \u2014 without a basemap there is nothing to align to, so the only job is to\n// show the relative arrangement of a fleet truthfully, and at the extent of a site or a\n// city the difference between the two is invisible. (With a tile source the widget uses\n// MapLibre's real projection instead; this function is never asked to agree with one.)\n//\n// \uD83D\uDD34 THE AXES ARE NOT INTERCHANGEABLE, AND THE Y AXIS IS INVERTED. Longitude is\n// east-west (x); latitude is north-south (y); and screen y grows DOWNWARD while\n// latitude grows northward, so the maximum latitude maps to y = 0. Swap the two and\n// every marker still lands inside the panel, in a plausible-looking scatter \u2014 the\n// output stays well-formed, which is exactly why this is asserted directly rather than\n// eyeballed.\n//\n// A degenerate axis (one device, or several at the same latitude) has no span to\n// stretch across, so it centres on that axis rather than dividing by zero.\nexport function projectToPanel(positions: readonly PlaceableLocation[]): PanelPoint[] {\n if (positions.length === 0) return [];\n\n let minLat = Infinity;\n let maxLat = -Infinity;\n let minLon = Infinity;\n let maxLon = -Infinity;\n for (const p of positions) {\n if (p.latitude < minLat) minLat = p.latitude;\n if (p.latitude > maxLat) maxLat = p.latitude;\n if (p.longitude < minLon) minLon = p.longitude;\n if (p.longitude > maxLon) maxLon = p.longitude;\n }\n\n const lonSpan = maxLon - minLon;\n const latSpan = maxLat - minLat;\n const scale = 1 - 2 * PANEL_PADDING;\n\n return positions.map((p) => ({\n x: PANEL_PADDING + scale * (lonSpan === 0 ? 0.5 : (p.longitude - minLon) / lonSpan),\n // maxLat at the TOP: screen y grows downward, latitude grows northward.\n y: PANEL_PADDING + scale * (latSpan === 0 ? 0.5 : (maxLat - p.latitude) / latSpan),\n }));\n}\n\n// Coordinates are WGS84 decimal degrees platform-wide. Six decimal places is ~0.1 m at\n// the equator \u2014 finer than any consumer receiver \u2014 and fixed notation stops a small\n// value rendering in exponential form. Matches the device-detail position panel, so the\n// same fix reads identically in both places.\nexport function formatDegrees(value: number): string {\n return value.toFixed(6);\n}\n\n// describePosition renders one fix as a marker's hover/screen-reader text.\n//\n// \uD83D\uDD34 IT REPORTS ONLY WHAT THE DEVICE REPORTED. Elevation, accuracy, speed and heading\n// are each optional, and an absent one contributes NO SEGMENT at all \u2014 it is never\n// filled in with a zero. A marker reading \"0\u00B0\" claims the device reported due north; a\n// marker with no heading segment claims nothing, which is the truth. Every test is\n// `!= null`, so a genuine 0 (parked, sea level, due north) is still shown.\n//\n// Units are fixed platform-wide: metres, metres per second, degrees clockwise from true\n// north.\nexport function describePosition(sample: PlaceableLocation): string {\n const parts: string[] = [\n sample.deviceToken,\n `${formatDegrees(sample.latitude)}, ${formatDegrees(sample.longitude)}`,\n ];\n if (sample.elevation != null) parts.push(`${sample.elevation} m`);\n if (sample.accuracy != null) parts.push(`\u00B1${sample.accuracy} m`);\n if (sample.speed != null) parts.push(`${sample.speed} m/s`);\n if (sample.heading != null) parts.push(`${sample.heading}\u00B0`);\n return parts.join(' \u00B7 ');\n}\n\n// rasterStyleFor builds the MapLibre style document for a user-supplied raster tile\n// source.\n//\n// \uD83D\uDD34 THIS PACKAGE HARDCODES NO TILE SOURCE, AND THAT IS A DECISION RATHER THAN AN\n// OMISSION. The library is not the map \u2014 the TILES are, and they carry their own terms,\n// so a widget library is the wrong place to choose a provider on an operator's behalf.\n// The URL arrives as config, and with none set the widget falls back to the BUNDLED\n// world basemap below \u2014 public-domain geometry compiled into this package, which asks\n// no host for anything and so adopts nobody's terms. That is the distinction the rule\n// is actually about: not \"ship no map\", but \"make no request on an operator's behalf\n// to a host they never chose\".\n//\n// The PLATFORM does ship a default (ADR-079): an instance-wide setting a tenant can\n// override, which a board then inherits when its own options name nothing. That is a\n// named, visible, replaceable choice made once by an operator \u2014 a different thing from\n// this module quietly baking a host into every build of the library.\n//\n// `attribution` is passed to the source rather than hidden: a tile source's licence\n// commonly REQUIRES visible credit, so it is a property of the data, not decoration a\n// host may strip.\nexport function rasterStyleFor(tileUrl: string, attribution: string | undefined): unknown {\n return {\n version: 8,\n projection: PROJECTION,\n sources: {\n basemap: {\n type: 'raster',\n tiles: [tileUrl],\n tileSize: 256,\n ...(attribution ? { attribution } : {}),\n },\n },\n layers: [{ id: 'basemap', type: 'raster', source: 'basemap' }],\n };\n}\n\n// ---- The bundled world basemap ----------------------------------------------\n\n// \uD83D\uDD34 THE PROJECTION IS THE CORRECTNESS PROPERTY OF THIS WHOLE FILE, and it is\n// declared explicitly \u2014 on BOTH styles \u2014 rather than left to the default.\n//\n// The fence editor stores the coordinates a click produces, so what a style\n// changes must be what is DRAWN and never where a click LANDS. Mercator is\n// MapLibre's default, so writing it out changes no behaviour today. What it buys\n// is that the two styles now state the same thing in the same words, and a test\n// can compare them: an invariant nobody wrote down is an invariant a later edit\n// breaks without anything going red.\n//\n// This is not hypothetical in MapLibre 6. `projection` is a root style key whose\n// `type` is a ZOOM-INTERPOLATABLE expression, so a style is entitled to hand back\n// a globe past some zoom. A globe re-projects the pointer; every ring an author\n// then drew would be saved somewhere they never pointed at, on a map that looked\n// beautiful throughout.\nconst PROJECTION = { type: 'mercator' } as const;\n\n// The bundled basemap's credit line. Natural Earth requires NO attribution \u2014 its\n// licence says in as many words that crediting the authors is unnecessary \u2014 so\n// this is their own suggested short citation, shown for a reason of ours: a\n// viewer has to be able to tell a schematic bundled world apart from a configured\n// provider, or \"no tiles\" reads as \"broken\" all over again.\nexport const BUNDLED_BASEMAP_ATTRIBUTION = 'Made with Natural Earth';\n\n// The bundled style's palette. Literal colours, not theme tokens: a MapLibre style\n// document is JSON handed to a WebGL renderer, and it does not resolve the CSS\n// custom properties the rest of this package themes with. These sit close to the\n// dark surface the fence editor already drew, so the change reads as \"the void\n// grew continents\" rather than as a new skin.\nconst OCEAN = '#0b1220';\nconst LAND = '#1e293b';\nconst BOUNDARY = '#475569';\n\n// landStyleFrom builds the bundled world style from Natural Earth geometry.\n//\n// Kept separate from the loader, and pure, so the style document can be asserted\n// without pulling 150 KiB of coordinates into a test \u2014 and so the one thing worth\n// asserting about it (that it projects exactly as the tiled style does) is\n// checkable in isolation.\nexport function landStyleFrom(land: unknown, boundaries: unknown): unknown {\n return {\n version: 8,\n projection: PROJECTION,\n sources: {\n land: { type: 'geojson', data: land, attribution: BUNDLED_BASEMAP_ATTRIBUTION },\n boundaries: { type: 'geojson', data: boundaries },\n },\n layers: [\n { id: 'ocean', type: 'background', paint: { 'background-color': OCEAN } },\n { id: 'land', type: 'fill', source: 'land', paint: { 'fill-color': LAND } },\n {\n id: 'boundaries',\n type: 'line',\n source: 'boundaries',\n paint: { 'line-color': BOUNDARY, 'line-width': 0.5 },\n },\n ],\n };\n}\n\n// loadLandStyle fetches the bundled geometry and builds its style.\n//\n// \uD83D\uDD34 THE DYNAMIC IMPORT IS THE WHOLE POINT. natural-earth-data is ~150 KiB (~44\n// KiB over the wire) and it must never enter this package's entry chunk: with a\n// tile source configured \u2014 which, since the platform ships a default provider, is\n// the ordinary case \u2014 nobody should download a world map they will not see. A\n// static `import { NATURAL_EARTH }` at the top of this file would give every\n// viewer the payload and change nothing observable, which is how it would survive\n// review.\n//\n// Memoized on the promise, so several map widgets on one board parse it once.\n//\n// \uD83D\uDD34 That memoizes a REJECTION too: one transient chunk failure leaves every\n// unconfigured map on the page falling back until a reload. Deliberate, and the same\n// bargain loadMapLibre has always made \u2014 a retry-on-failure cache would let N widgets\n// re-request a chunk that is failing for a reason retrying will not fix. Worth knowing\n// that the blast radius grew when this became the DEFAULT unconfigured path rather\n// than a rarity.\nlet landStylePromise: Promise<unknown> | undefined;\n\nexport function loadLandStyle(): Promise<unknown> {\n if (!landStylePromise) {\n landStylePromise = import('./natural-earth-data').then((mod) =>\n landStyleFrom(mod.NATURAL_EARTH.land, mod.NATURAL_EARTH.boundaries),\n );\n }\n return landStylePromise;\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The measurement table's registration: descriptor eager, component lazy, from a chunk of its\n// own, so a board with no table never downloads it. Table is also a public export; see\n// alarm-lazy.tsx for what that means for a host's first download.\n\nimport { defineWidget } from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { lazyChunk } from './lazy-chunk';\n\nconst chunk = lazyChunk<typeof import('./table')>(() => import('./table'));\n\nexport const loadTableWidget = chunk.load;\n\nexport const tableWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['table'],\n implementation: { kind: 'trusted-react', component: chunk.component('Table') },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// timeseries-chart \u2014 a live line chart of the rolling measurement window, one\n// series per measurement name. The window is seeded from bucketedMeasurements\n// history (via useMeasurementStream's initialSamples) and extended by the live tail. An\n// interruption of the live feed that history has not filled yet is drawn as a break in the line.\n\nimport { useMemo } from 'react';\n\nimport { isValidSpanSeconds, spanLabel } from '@devicechain/dashboards';\nimport {\n css,\n defineWidget,\n fontVar,\n formatDateTime,\n formatTimestamp,\n optNumber,\n optString,\n optThresholds,\n pickSample,\n primaryMeasurementName,\n spaceVar,\n useWidgetScale,\n useWidgetTimeRange,\n useWidgetTimeZone,\n viewerLocale,\n WidgetFrame,\n type MeasurementStreamState,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\nimport { buildLineOption, EChart, loadChartEngine, useChartTheme } from '@devicechain/widget-sdk/echarts';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { NoReading, useSettledEmpty } from './no-reading-lazy';\nimport type { EventMarkersView } from '../event-markers-types';\n\n// `markers` is supplied by the event-marker feed (a chart with markAlarms / markCommands on) and by\n// nothing else; without it the chart is drawn exactly as it always was.\ntype TimeSeriesProps = WidgetProps & { markers?: EventMarkersView };\n\nexport function TimeSeriesChart({ widget, data, markers }: TimeSeriesProps) {\n const range = useWidgetTimeRange();\n const pinned = optNumber(widget.options, 'windowSeconds');\n const spanSeconds = isValidSpanSeconds(pinned) ? pinned : range?.spanSeconds;\n // The frame's \"Download CSV\": the samples on screen, nothing re-read. The builder is its own chunk, so\n // the chart carries only this closure.\n const exportRows = () => {\n const device = widget.datasource?.kind === 'device' ? widget.datasource.deviceToken : undefined;\n return import('../export-rows').then((m) =>\n m.samplesExport({\n subject: optString(widget.options, 'title') ?? device ?? 'chart',\n samples: data.samples,\n unit: optString(widget.options, 'unit'),\n precision: optNumber(widget.options, 'precision'),\n seriesIs: 'measurement',\n spanSeconds,\n }),\n );\n };\n return (\n <WidgetFrame title={optString(widget.options, 'title')} flush exportRows={exportRows}>\n <TimeSeriesBody widget={widget} data={data} markers={markers} />\n </WidgetFrame>\n );\n}\n\n// Rendered INSIDE the frame: the widget scale is the frame's content column, which is only in\n// context below the frame.\nfunction TimeSeriesBody({ widget, data, markers }: TimeSeriesProps) {\n const theme = useChartTheme();\n const { size, scale } = useWidgetScale();\n\n const measurements = widget.datasource?.measurements;\n const unit = optString(widget.options, 'unit');\n const precision = optNumber(widget.options, 'precision');\n const thresholds = useMemo(() => optThresholds(widget.options, 'thresholds'), [widget.options]);\n // The value axis's ends, when the author set them (each widens for a reading beyond it).\n const min = optNumber(widget.options, 'min');\n const max = optNumber(widget.options, 'max');\n const option = useMemo(() => {\n const base = buildLineOption(data.samples, theme, { measurements, unit, precision, thresholds, scale, gaps: data.gaps, min, max }, size);\n return markers ? markers.decorate(base, size) : base;\n }, [data.samples, data.gaps, theme, measurements, unit, precision, thresholds, scale, size, markers, min, max]);\n\n // Nothing in the window: say why (after the history read has had its moment), with the last reading\n // known outside it as a hint.\n // A chart of several measurements names none: whether the profile omits the first says nothing\n // about the others, so it is \"no data\", never \"not reported\".\n const name = measurements && measurements.length > 1 ? undefined : primaryMeasurementName(widget);\n const explain = useSettledEmpty(data.samples.length === 0);\n if (explain) {\n return (\n <NoReading\n unbound={widget.datasource?.kind === 'unbound'}\n measurement={name}\n lastSample={pickSample(data.latest, name)}\n unit={unit}\n precision={precision}\n waitMs={0}\n />\n );\n }\n\n const chart = (\n <div style={{ position: 'relative', width: '100%', height: '100%' }}>\n <EChart option={option} />\n <SpanBadge widget={widget} data={data} />\n </div>\n );\n if (!markers) return chart;\n // The list and notes sit UNDER the chart, never over it: the chart gives up their height.\n return (\n <div style={{ display: 'flex', flexDirection: 'column', width: '100%', height: '100%' }}>\n <div style={{ flex: 1, minHeight: 0 }}>{chart}</div>\n {markers.footer}\n </div>\n );\n}\n\n// The words the span badge prints. The widget packages carry no i18n runtime (see level-strings).\nconst SPAN_STRINGS = {\n en: {\n from: (time: string) => `from ${time}`,\n pinned: (span: string) => `Pinned to ${span}: the board's time range does not apply to this chart.`,\n cut: (time: string, span: string) =>\n `Showing from ${time}, not the whole ${span}: older samples were dropped to bound memory.`,\n },\n es: {\n from: (time: string) => `desde ${time}`,\n pinned: (span: string) => `Fijado a ${span}: el intervalo de tiempo del panel no se aplica a este gr\u00E1fico.`,\n cut: (time: string, span: string) =>\n `Se muestra desde ${time}, no todo el intervalo de ${span}: se descartaron las muestras m\u00E1s antiguas para acotar la memoria.`,\n },\n};\n\nconst DAY_MS = 86_400_000;\n\n// SpanBadge says what span the chart draws whenever the board's header would say something else:\n// - a chart PINNED to its own span (`windowSeconds`) ignores the viewer's range pick, so under a\n// \"24h\" header a pinned hour would read as a day of data. It prints its own span (\"1h\").\n// - a window the retention ceiling cut (`truncatedBefore`) covers less than its span. It prints\n// where it starts (\"from 14:03\"), so a short window never passes for the whole range.\n// Nothing shows when the chart draws exactly the board's range, or off a board (no header).\nfunction SpanBadge({ widget, data }: { widget: WidgetProps['widget']; data: MeasurementStreamState }) {\n const range = useWidgetTimeRange();\n const timeZone = useWidgetTimeZone();\n const pinned = optNumber(widget.options, 'windowSeconds');\n const span = isValidSpanSeconds(pinned) ? pinned : range?.spanSeconds;\n const showSpan = range !== undefined && span !== range.spanSeconds;\n const cutAt = data.truncatedBefore;\n if (!showSpan && !cutAt) return null;\n\n const words = viewerLocale()?.toLowerCase().startsWith('es') ? SPAN_STRINGS.es : SPAN_STRINGS.en;\n const label = span === undefined ? '' : spanLabel(span);\n // A start more than a day back prints its date, or \"from 09:14\" would name the wrong day.\n const end = range?.paused && range.pausedAt !== undefined ? range.pausedAt : Date.now();\n const time = cutAt\n ? end - Date.parse(cutAt) > DAY_MS\n ? formatDateTime(cutAt, timeZone)\n : formatTimestamp(cutAt, timeZone)\n : '';\n const text = [showSpan ? label : '', cutAt ? words.from(time) : ''].filter(Boolean).join(' \u00B7 ');\n const title = [showSpan ? words.pinned(label) : '', cutAt ? words.cut(time, label) : ''].filter(Boolean).join(' ');\n return (\n <span\n data-chart-span={showSpan ? label : ''}\n data-chart-truncated={cutAt ? '' : undefined}\n title={title}\n style={{\n position: 'absolute',\n top: spaceVar(1),\n right: spaceVar(2),\n padding: `0 ${spaceVar(1)}`,\n fontSize: fontVar('xs'),\n whiteSpace: 'nowrap',\n color: css('muted-foreground'),\n background: css('muted'),\n borderRadius: 4,\n pointerEvents: 'auto',\n }}\n >\n {text}\n </span>\n );\n}\n\n// What preloadWidgets calls: the chart engine loads on demand, as its own chunk, so a host that\n// awaits this for a board holding this widget draws the chart on the board's first frame.\nTimeSeriesChart.preload = loadChartEngine;\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const timeSeriesChartWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['timeseries-chart'],\n implementation: { kind: 'trusted-react', component: TimeSeriesChart },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { WidgetRegistry } from '@devicechain/widget-sdk';\n\nimport { createBuiltinWidgetRegistry } from './builtin-registry';\n\n// The registry a renderer uses when its host passes none: the built-ins, built once per\n// module instance. A registry is sealed and immutable, so sharing this one default between\n// hosts carries no state \u2014 a host with extension packages passes its own.\nlet builtin: WidgetRegistry | undefined;\n\nexport function defaultWidgetRegistry(): WidgetRegistry {\n builtin ??= createBuiltinWidgetRegistry();\n return builtin;\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// Per-widget failure containment. Every widget implementation renders inside its own error\n// boundary: a component that throws shows a local diagnostic with a reset control while its\n// siblings keep rendering, and a host callback that rejects (an action, a candidate lookup)\n// is surfaced on the widget that made the call instead of vanishing into an unhandled\n// rejection. An error boundary cannot contain an infinite loop or hostile same-page code;\n// trusted package installation remains the operator's responsibility.\n\nimport { Component, createContext, useCallback, useContext, useState, type ReactNode } from 'react';\n\nimport { WidgetFrame } from '@devicechain/widget-sdk';\nimport { describeError, type ReportRejection } from './widget-host';\n\nconst MESSAGE_STYLE = {\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 4,\n width: '100%',\n height: '100%',\n padding: 12,\n boxSizing: 'border-box',\n textAlign: 'center',\n color: 'hsl(var(--muted-foreground))',\n} as const;\n\nconst BUTTON_STYLE = {\n marginTop: 4,\n fontSize: 11,\n padding: '2px 8px',\n cursor: 'pointer',\n} as const;\n\n// The reporter a body uses for async host callbacks. A no-op outside a containment, so a\n// component rendered on its own never needs one.\nconst ReportContext = createContext<ReportRejection>(() => {});\n\nexport function useReportRejection(): ReportRejection {\n return useContext(ReportContext);\n}\n\ninterface BoundaryProps {\n title?: string;\n // Changes when the widget's stored configuration changes, so an edit retries a widget\n // that threw on the old one.\n resetKey: string;\n onReset: () => void;\n children: ReactNode;\n}\n\ninterface BoundaryState {\n error: { message: string } | null;\n resetKey: string;\n}\n\nclass WidgetErrorBoundary extends Component<BoundaryProps, BoundaryState> {\n state: BoundaryState = { error: null, resetKey: this.props.resetKey };\n\n static getDerivedStateFromError(error: unknown): Partial<BoundaryState> {\n return { error: { message: describeError(error) } };\n }\n\n static getDerivedStateFromProps(props: BoundaryProps, state: BoundaryState): Partial<BoundaryState> | null {\n if (props.resetKey === state.resetKey) return null;\n return { error: null, resetKey: props.resetKey };\n }\n\n private reset = (): void => {\n this.props.onReset();\n this.setState({ error: null });\n };\n\n render(): ReactNode {\n const { error } = this.state;\n if (!error) return this.props.children;\n return (\n <WidgetFrame title={this.props.title}>\n <div style={MESSAGE_STYLE} role=\"alert\">\n <div style={{ fontSize: 20, lineHeight: 1 }} aria-hidden=\"true\">\n \u26A0\n </div>\n <div style={{ fontSize: 13, fontWeight: 600 }}>This widget failed to render</div>\n <div style={{ fontSize: 11, opacity: 0.8, wordBreak: 'break-word' }}>{error.message}</div>\n <button type=\"button\" style={BUTTON_STYLE} onClick={this.reset}>\n Reset widget\n </button>\n </div>\n </WidgetFrame>\n );\n }\n}\n\nexport interface WidgetContainmentProps {\n title?: string;\n resetKey: string;\n children: ReactNode;\n}\n\n// WidgetContainment wraps ONE widget. Rejections reported by the host callbacks it hands\n// down appear in a dismissible strip over the widget's bottom edge.\nexport function WidgetContainment({ title, resetKey, children }: WidgetContainmentProps) {\n const [messages, setMessages] = useState<string[]>([]);\n const report = useCallback<ReportRejection>((message) => {\n setMessages((prev) => (prev.includes(message) ? prev : [...prev, message].slice(-3)));\n }, []);\n const clear = useCallback(() => setMessages([]), []);\n return (\n <div style={{ position: 'relative', width: '100%', height: '100%' }}>\n <ReportContext.Provider value={report}>\n <WidgetErrorBoundary title={title} resetKey={resetKey} onReset={clear}>\n {children}\n </WidgetErrorBoundary>\n </ReportContext.Provider>\n {messages.length > 0 && (\n <div\n role=\"status\"\n style={{\n position: 'absolute',\n left: 4,\n right: 4,\n bottom: 4,\n fontSize: 11,\n padding: '2px 6px',\n borderRadius: 4,\n background: 'hsl(var(--destructive, 0 70% 45%))',\n color: 'hsl(var(--destructive-foreground, 0 0% 100%))',\n display: 'flex',\n gap: 6,\n alignItems: 'center',\n }}\n >\n <span style={{ flex: 1, wordBreak: 'break-word' }}>{messages.join(' \u00B7 ')}</span>\n <button type=\"button\" aria-label=\"Dismiss\" onClick={clear} style={{ cursor: 'pointer' }}>\n \u00D7\n </button>\n </div>\n )}\n </div>\n );\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// What the host hands one widget: ONLY the interactions its descriptor declares,\n// intersected with what the host supports. Declaring an interaction is a request, and this\n// narrowing is API hygiene, not a security boundary (trusted React runs with the page's\n// privileges); the server stays the authority on every write.\n\nimport type { WidgetActions, WidgetDescriptor } from '@devicechain/dashboards';\n\nimport { type WidgetCandidates, type WidgetSelect } from '@devicechain/widget-sdk';\n\n// Receives the message of an async host callback that rejected, so it can be shown on the\n// widget that made the call.\nexport type ReportRejection = (message: string) => void;\n\nexport function describeError(error: unknown): string {\n if (error instanceof Error) return error.message || error.name;\n return String(error);\n}\n\n// guardAsync reports a rejection to the widget's local diagnostics and rethrows it, so a\n// widget that handles the failure itself (a refusal it shows inline) still sees it.\nfunction guardAsync<A extends unknown[], R>(\n fn: (...args: A) => Promise<R>,\n report: ReportRejection,\n): (...args: A) => Promise<R> {\n return (...args: A) => {\n let pending: Promise<R>;\n try {\n pending = Promise.resolve(fn(...args));\n } catch (e) {\n report(describeError(e));\n return Promise.reject(e);\n }\n return pending.catch((e: unknown) => {\n report(describeError(e));\n throw e;\n });\n };\n}\n\nconst ALARM_AUTHORITY = 'alarm:write';\nconst COMMAND_AUTHORITY = 'command:write';\n\n// A call to an interaction the widget did not declare rejects, and the rejection is reported\n// on the widget like any other failed host callback: a widget that fires and forgets\n// (`void actions.acknowledgeAlarm(t)`) must still SHOW the refusal, not swallow it.\nfunction undeclared(capability: string, report: ReportRejection): () => Promise<never> {\n return guardAsync(\n () => Promise.reject(new Error(`this widget did not declare the ${capability} interaction`)),\n report,\n );\n}\n\n// narrowActions returns the action seam a widget may use. A widget that declares neither\n// alarm actions nor command send gets none; one that declares a subset gets the declared\n// methods working and the rest refusing loudly (never a silent no-op), and `can` denies the\n// write authorities of capabilities it did not declare.\nexport function narrowActions(\n actions: WidgetActions | undefined,\n descriptor: WidgetDescriptor,\n report: ReportRejection,\n): WidgetActions | undefined {\n if (!actions) return undefined;\n const alarm = descriptor.interactions.alarmActions === true;\n const command = descriptor.interactions.commandSend === true;\n if (!alarm && !command) return undefined;\n const narrowed: WidgetActions = {\n acknowledgeAlarm: alarm\n ? guardAsync((t) => actions.acknowledgeAlarm(t), report)\n : undeclared('alarmActions', report),\n clearAlarm: alarm ? guardAsync((t) => actions.clearAlarm(t), report) : undeclared('alarmActions', report),\n can: (authority) => {\n if (authority === ALARM_AUTHORITY && !alarm) return false;\n if (authority === COMMAND_AUTHORITY && !command) return false;\n return actions.can(authority);\n },\n };\n // Left absent when undeclared or unsupported: a command widget feature-detects it and\n // renders its Send control disabled.\n if (command && typeof actions.sendCommand === 'function') {\n narrowed.sendCommand = guardAsync((d, n, p) => actions.sendCommand!(d, n, p), report);\n }\n return narrowed;\n}\n\n// narrowSelect: the view-selection callback, only for a widget that declared `selection`.\nexport function narrowSelect(select: WidgetSelect | undefined, descriptor: WidgetDescriptor): WidgetSelect | undefined {\n return descriptor.interactions.selection === true ? select : undefined;\n}\n\n// narrowCandidates: the candidate lookup, only for a widget that declared `candidates`; its\n// rejections are reported locally and rethrown.\nexport function narrowCandidates(\n candidates: WidgetCandidates | undefined,\n descriptor: WidgetDescriptor,\n report: ReportRejection,\n): WidgetCandidates | undefined {\n if (!candidates || descriptor.interactions.candidates !== true) return undefined;\n return guardAsync((slot) => candidates(slot), report);\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The viewer's time-range control: the presets, a pause, the \"Paused\" indicator, and a custom\n// from-to window (picked in a lazily loaded panel, or opened from a `?from=&to=` link). One\n// component for every host (the console viewer, the /dash app), so the two cannot disagree about\n// what a frozen board looks like. It is a plain controlled bar -- the host owns the state through\n// useBoardTimeRange and feeds it to the renderer as `timeRange` -- and it carries no copy of its\n// own beyond English defaults: a host passes its translations as `labels`.\n\nimport {\n DEFAULT_TIME_RANGE_SECONDS,\n TIME_RANGE_PRESETS,\n absoluteRange,\n absoluteToParams,\n initialTimeRange,\n isValidSpanSeconds,\n leaveAbsolute,\n pauseRange,\n presetIdOf,\n resumeRange,\n spanLabel,\n withSpan,\n type AbsoluteLinkRejection,\n type AbsoluteRange,\n type AbsoluteRangeProblem,\n type TimeRangeState,\n} from '@devicechain/dashboards';\nimport { useCallback, useEffect, useMemo, useRef, useState, type ComponentType, type CSSProperties } from 'react';\nimport type { AbsolutePickerLabels } from './absolute-range-picker';\n\nexport interface TimeRangeControls {\n setSpan(spanSeconds: number): void;\n pause(): void;\n resume(): void;\n // Show a fixed from-to window (epoch ms). Returns why it was refused, or undefined when taken.\n setAbsolute(fromMs: number, toMs: number): AbsoluteRangeProblem | undefined;\n}\n\n// useBoardTimeRange holds the board's range for a host: the definition's default span, or the\n// deep link's (a preset span, a frozen instant, or an absolute window), and live unless the link\n// says otherwise. `defaultSeconds` is read once, at mount; a host that swaps boards remounts (the\n// console and /dash both do), which is when it should reset.\nexport function useBoardTimeRange(\n defaultSeconds: number | undefined,\n link: { spanSeconds?: number; paused?: boolean; absolute?: AbsoluteRange } = {},\n): [TimeRangeState, TimeRangeControls] {\n const [state, setState] = useState<TimeRangeState>(() => initialTimeRange(defaultSeconds, link));\n // An author who changes the board's default while the viewer is open expects the board to follow;\n // a viewer's own pick is only overridden when the DEFAULT moves, never by re-rendering.\n const lastDefault = useRef(defaultSeconds);\n useEffect(() => {\n if (lastDefault.current === defaultSeconds) return;\n lastDefault.current = defaultSeconds;\n setState((s) => withSpan(s, isValidSpanSeconds(defaultSeconds) ? defaultSeconds : DEFAULT_TIME_RANGE_SECONDS));\n }, [defaultSeconds]);\n const controls = useMemo<TimeRangeControls>(\n () => ({\n // A preset click while a fixed window is showing leaves it: back to live at that span.\n setSpan: (spanSeconds) => setState((s) => withSpan(leaveAbsolute(s), spanSeconds)),\n pause: () => setState((s) => pauseRange(s, Date.now())),\n resume: () => setState((s) => resumeRange(s)),\n setAbsolute: (fromMs, toMs) => {\n const made = absoluteRange(fromMs, toMs);\n if ('problem' in made) return made.problem;\n setState(made.state);\n return undefined;\n },\n }),\n [],\n );\n return [state, controls];\n}\n\nexport interface AbsoluteLabels extends AbsolutePickerLabels {\n // \"Fixed window\" -- what the indicator says in place of \"Paused\".\n fixed: string;\n // The button that leaves a fixed window for the live board.\n backToLive: string;\n copyLink: string;\n linkCopied: string;\n // The picker's chunk could not be fetched.\n loadFailed: string;\n dismiss: string;\n // The note shown when a `?from=&to=` link was ignored. `reason` is the problem; `raw` the values.\n ignored: (reason: string, raw: string) => string;\n incomplete: string;\n // The link carried a date-time with no zone, or one that does not parse.\n unzoned: string;\n}\n\nexport interface TimeRangeLabels {\n range: string;\n pause: string;\n resume: string;\n paused: string;\n // \"Paused at 14:03:22\".\n pausedAt: (time: string) => string;\n // Printed inside the pill: a pause freezes what the board SHOWS, never what it DOES. Commands\n // (and alarm acknowledge / clear) still go out at once, and their status keeps updating, so an\n // operator who acts on a frozen board is told the action is live.\n actionsLive: string;\n // The custom-window strings. Optional so a host written before the absolute range keeps compiling;\n // the English defaults fill any it leaves out.\n absolute?: Partial<AbsoluteLabels>;\n}\n\nexport const DEFAULT_ABSOLUTE_LABELS: AbsoluteLabels = {\n custom: 'Custom range',\n from: 'From',\n to: 'To',\n apply: 'Apply',\n cancel: 'Cancel',\n zone: (zone, offset) => `Times are in ${zone} (${offset}). Shared links use UTC.`,\n problem: {\n unparseable: 'Enter both a start and an end.',\n order: 'The start must be before the end.',\n tooShort: 'The window must be at least one minute.',\n tooLong: 'The window can be at most 31 days.',\n future: 'The end cannot be in the future.',\n tooEarly: 'The start is too far in the past.',\n },\n fixed: 'Fixed window',\n backToLive: 'Back to live',\n copyLink: 'Copy link',\n linkCopied: 'Link copied',\n loadFailed: 'The range picker could not be loaded. Try again.',\n dismiss: 'Dismiss',\n ignored: (reason, raw) => `The link's time window was ignored: ${reason} (${raw}). Showing the live board.`,\n incomplete: 'both from and to are required',\n unzoned: 'times must be ISO 8601 with a zone, such as 2026-10-22T02:00:00Z or +02:00',\n};\n\nexport const DEFAULT_TIME_RANGE_LABELS: TimeRangeLabels = {\n range: 'Time range',\n pause: 'Pause',\n resume: 'Resume',\n paused: 'Paused',\n pausedAt: (time) => `Paused at ${time}`,\n actionsLive: 'commands still send',\n};\n\nconst absoluteLabels = (labels: TimeRangeLabels): AbsoluteLabels => ({ ...DEFAULT_ABSOLUTE_LABELS, ...labels.absolute });\n\n// The note text for a deep link whose `from`/`to` were unusable.\nexport function rejectedLinkNote(rejected: AbsoluteLinkRejection, labels: TimeRangeLabels = DEFAULT_TIME_RANGE_LABELS): string {\n const l = absoluteLabels(labels);\n const raw = `from=${rejected.from || '-'} to=${rejected.to || '-'}`;\n const reason =\n rejected.reason === 'incomplete' ? l.incomplete : rejected.reason === 'unparseable' ? l.unzoned : l.problem[rejected.reason];\n return l.ignored(reason, raw);\n}\n\nconst button = (active: boolean): CSSProperties => ({\n padding: '2px 8px',\n fontSize: 12,\n lineHeight: '18px',\n cursor: 'pointer',\n color: active ? 'hsl(var(--background))' : 'hsl(var(--foreground))',\n background: active ? 'hsl(var(--foreground))' : 'transparent',\n border: '1px solid hsl(var(--border))',\n borderRadius: 4,\n});\n\n// The pill is deliberately loud: filled, bordered and spelled out, because a frozen board that\n// reads as live is the failure this slice exists to prevent. Exported so a kiosk wall (which has\n// no bar) can show it alone.\nexport function PausedIndicator({\n pausedAt,\n labels = DEFAULT_TIME_RANGE_LABELS,\n}: {\n pausedAt: number | undefined;\n labels?: TimeRangeLabels;\n}) {\n const time = pausedAt === undefined ? undefined : new Date(pausedAt).toLocaleTimeString();\n return (\n <span\n role=\"status\"\n data-time-range-paused=\"\"\n title={time ? labels.pausedAt(time) : labels.paused}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: 4,\n padding: '2px 8px',\n fontSize: 12,\n fontWeight: 700,\n letterSpacing: 0.4,\n textTransform: 'uppercase',\n color: 'hsl(var(--background))',\n background: 'hsl(var(--foreground))',\n border: '2px solid hsl(var(--foreground))',\n borderRadius: 4,\n }}\n >\n <span aria-hidden=\"true\">{'\u23F8'}</span>\n {labels.paused}\n {time ? <span style={{ fontWeight: 400, textTransform: 'none' }}>{` ${time}`}</span> : null}\n <span data-time-range-actions-live=\"\" style={{ fontWeight: 400, textTransform: 'none' }}>\n {`\u00B7 ${labels.actionsLive}`}\n </span>\n </span>\n );\n}\n\n// A window as text, each end WITH its zone: \"Oct 22, 2026, 2:00 AM CEST - Oct 22, 2026, 4:00 AM CEST\".\nexport function formatAbsoluteRange(a: AbsoluteRange): string {\n const f = new Intl.DateTimeFormat(undefined, { year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', timeZoneName: 'short' });\n return `${f.format(a.fromMs)} \u2013 ${f.format(a.toMs)}`;\n}\n\n// What stands in for the Paused pill while a fixed window shows. Same loudness, different words:\n// \"Paused\" would be wrong (nothing was paused, a window was chosen), and the live tail is off for\n// the same reason either way. Exported for the kiosk, like PausedIndicator.\nexport function AbsoluteIndicator({\n absolute,\n labels = DEFAULT_TIME_RANGE_LABELS,\n}: {\n absolute: AbsoluteRange;\n labels?: TimeRangeLabels;\n}) {\n const l = absoluteLabels(labels);\n const utc = absoluteToParams(absolute);\n return (\n <span\n role=\"status\"\n data-time-range-absolute=\"\"\n title={`${utc.from} \u2013 ${utc.to} (UTC)`}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n flexWrap: 'wrap',\n gap: 4,\n padding: '2px 8px',\n fontSize: 12,\n fontWeight: 700,\n color: 'hsl(var(--background))',\n background: 'hsl(var(--foreground))',\n border: '2px solid hsl(var(--foreground))',\n borderRadius: 4,\n }}\n >\n <span style={{ letterSpacing: 0.4, textTransform: 'uppercase' }}>{l.fixed}</span>\n <span data-time-range-window=\"\" style={{ fontWeight: 400 }}>\n {formatAbsoluteRange(absolute)}\n </span>\n <span data-time-range-actions-live=\"\" style={{ fontWeight: 400 }}>\n {`\u00B7 ${labels.actionsLive}`}\n </span>\n </span>\n );\n}\n\n// The shareable address of the window: the current page with `from`/`to` in UTC, and the rolling\n// parameters dropped (an absolute window wins over them, so leaving them would only mislead).\nexport function absoluteLinkFor(href: string, a: AbsoluteRange): string {\n const url = new URL(href);\n const { from, to } = absoluteToParams(a);\n url.searchParams.delete('range');\n url.searchParams.delete('paused');\n url.searchParams.set('from', from);\n url.searchParams.set('to', to);\n return url.toString();\n}\n\ntype PickerProps = {\n initial?: AbsoluteRange;\n labels: AbsolutePickerLabels;\n onApply: (fromMs: number, toMs: number) => AbsoluteRangeProblem | undefined;\n onCancel: () => void;\n};\n\nexport function TimeRangeBar({\n state,\n controls,\n labels = DEFAULT_TIME_RANGE_LABELS,\n notice,\n}: {\n state: TimeRangeState;\n controls: TimeRangeControls;\n labels?: TimeRangeLabels;\n // A host's note about its deep link (an ignored `?from=&to=`), shown dismissibly under the bar.\n notice?: string;\n}) {\n const abs = state.absolute;\n const preset = abs ? undefined : presetIdOf(state.spanSeconds);\n const onPause = useCallback(() => (state.paused ? controls.resume() : controls.pause()), [state.paused, controls]);\n const l = absoluteLabels(labels);\n\n // The picker is fetched on the first click, as its own chunk.\n const [Picker, setPicker] = useState<ComponentType<PickerProps> | undefined>();\n const [open, setOpen] = useState(false);\n const [loadFailed, setLoadFailed] = useState(false);\n const [copied, setCopied] = useState(false);\n const [noticeShown, setNoticeShown] = useState(true);\n useEffect(() => setNoticeShown(true), [notice]);\n\n const openPicker = () => {\n if (open) {\n setOpen(false);\n return;\n }\n setLoadFailed(false);\n if (Picker) {\n setOpen(true);\n return;\n }\n import('./absolute-range-picker').then(\n (m) => {\n setPicker(() => m.default);\n setOpen(true);\n },\n () => setLoadFailed(true),\n );\n };\n\n const copyLink = () => {\n if (!abs) return;\n navigator.clipboard?.writeText(absoluteLinkFor(window.location.href, abs)).then(\n () => {\n setCopied(true);\n window.setTimeout(() => setCopied(false), 2000);\n },\n () => undefined,\n );\n };\n\n return (\n <div style={{ position: 'relative', display: 'inline-block', maxWidth: '100%' }}>\n <div\n data-time-range-bar=\"\"\n role=\"group\"\n aria-label={labels.range}\n style={{ display: 'inline-flex', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}\n >\n {/* A board default that is none of the presets (two hours, say) is still the selected span,\n shown under its own label rather than silently looking like another preset. */}\n {!abs && preset === undefined ? (\n <button type=\"button\" aria-pressed=\"true\" data-range={spanLabel(state.spanSeconds)} style={button(true)}>\n {spanLabel(state.spanSeconds)}\n </button>\n ) : null}\n {TIME_RANGE_PRESETS.map((p) => (\n <button\n key={p.id}\n type=\"button\"\n aria-pressed={p.id === preset}\n data-range={p.id}\n onClick={() => controls.setSpan(p.seconds)}\n style={button(p.id === preset)}\n >\n {p.id}\n </button>\n ))}\n <button\n type=\"button\"\n aria-pressed={abs !== undefined}\n aria-expanded={open}\n data-time-range-custom=\"\"\n onClick={openPicker}\n style={button(abs !== undefined)}\n >\n {l.custom}\n </button>\n {abs ? (\n <>\n <button type=\"button\" data-time-range-live=\"\" onClick={() => controls.resume()} style={button(false)}>\n {l.backToLive}\n </button>\n <button type=\"button\" data-time-range-copy=\"\" onClick={copyLink} style={button(false)}>\n {copied ? l.linkCopied : l.copyLink}\n </button>\n <AbsoluteIndicator absolute={abs} labels={labels} />\n </>\n ) : (\n <>\n <button type=\"button\" aria-pressed={state.paused} data-time-range-pause=\"\" onClick={onPause} style={button(state.paused)}>\n {state.paused ? labels.resume : labels.pause}\n </button>\n {state.paused ? <PausedIndicator pausedAt={state.pausedAt} labels={labels} /> : null}\n </>\n )}\n </div>\n {open && Picker ? (\n <div style={{ position: 'absolute', right: 0, top: '100%', marginTop: 6, zIndex: 30 }}>\n <Picker\n initial={abs}\n labels={l}\n onApply={(from, to) => {\n const problem = controls.setAbsolute(from, to);\n if (!problem) setOpen(false);\n return problem;\n }}\n onCancel={() => setOpen(false)}\n />\n </div>\n ) : null}\n {loadFailed ? (\n <div role=\"alert\" data-time-range-load-failed=\"\" style={{ fontSize: 12, color: 'hsl(var(--destructive))' }}>\n {l.loadFailed}\n </div>\n ) : null}\n {notice && noticeShown ? (\n <div\n role=\"status\"\n data-time-range-notice=\"\"\n style={{ display: 'flex', gap: 8, alignItems: 'baseline', marginTop: 4, fontSize: 12, color: 'hsl(var(--muted-foreground))' }}\n >\n <span style={{ minWidth: 0, overflowWrap: 'anywhere' }}>{notice}</span>\n <button type=\"button\" onClick={() => setNoticeShown(false)} style={{ ...button(false), flex: '0 0 auto' }}>\n {l.dismiss}\n </button>\n </div>\n ) : null}\n </div>\n );\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// useBoundDevices: the host-side hook that keeps a board's device selection and the address in\n// step, in both directions, and refuses a deep link it cannot honour.\n//\n// address \u2500\u2500\u25BA selection a `bind.<slot>=<device>` link is read, EVERY named device is checked\n// against the caller's own scope, and only then bound.\n// selection \u2500\u25BA address a pick (a marker click, a table row, a selector) rewrites the\n// `bind.*` parameters, so the address in the bar is always a link that\n// reproduces what is on screen.\n//\n// \uD83D\uDD34 REPLACE, NOT PUSH, and that is the decision rather than a default. A pick refines the view\n// the viewer is already on; it is not a place they went. Pushing an entry per marker click would\n// make Back walk through every device they happened to click, on a wall display or a phone,\n// instead of leaving the board, and would fill history with entries that all show the same\n// board. A copied link still reproduces the state, which is what an address is for. The cost,\n// accepted: Back does not undo a pick. What DOES follow history is an address that changes from\n// outside (the viewer pastes or follows a different link, or a router entry is restored): that\n// is read as a new link and checked like the first one.\n//\n// \uD83D\uDD34 A REFUSED LINK BLOCKS THE BOARD; it does not fall back to the board's default device. The\n// default is a DIFFERENT device from the one the link names, and a viewer who asked for pump 7\n// and is shown pump 3 under pump 7's link is being lied to. `phase: 'refused'` carries the\n// reasons, the host shows them, and `dismiss` is the viewer's explicit choice to open the board\n// without the parts that failed.\n\nimport {\n bindParamsOf,\n bindsToSelection,\n parseBindParams,\n selectionToBinds,\n validateBinds,\n withBindParams,\n type BindCheck,\n type BindParamIssue,\n type DashboardDefinition,\n type DeviceResolver,\n type SelectionTarget,\n type SlotBinding,\n} from '@devicechain/dashboards';\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\n// Where the address lives. A host with a router passes its location and a replace-navigate; a\n// host without one passes window.location and history.replaceState. `search` has no leading `?`\n// requirement: both forms are read.\nexport interface BoundDevicesAddress {\n search: string;\n replaceSearch: (search: string) => void;\n}\n\nexport interface LinkProblems {\n issues: BindParamIssue[];\n missing: BindCheck['missing'];\n failed: BindCheck['failed'];\n}\n\nexport type BoundDevicesPhase = 'ready' | 'checking' | 'refused';\n\nexport interface BoundDevices {\n // The selection overlay to hand to useResolvedBindings. Only validated devices are ever in it.\n selection: Record<string, SlotBinding>;\n select: (target: SelectionTarget) => void;\n // Drops the overlay (a mode switch): the board returns to its own defaults.\n reset: () => void;\n phase: BoundDevicesPhase;\n // Present while `phase` is 'refused'.\n problems: LinkProblems | null;\n // Open the board without the parts of the link that failed.\n dismiss: () => void;\n // Ask again (the check failed rather than the device being absent).\n retry: () => void;\n}\n\nconst NO_PROBLEMS: LinkProblems = { issues: [], missing: [], failed: [] };\n\nfunction hasBindParams(search: string, definition: DashboardDefinition): boolean {\n const { binds, issues } = parseBindParams(search, definition);\n return Object.keys(binds).length > 0 || issues.length > 0;\n}\n\nexport function useBoundDevices({\n definition,\n resolver,\n address,\n enabled = true,\n}: {\n definition: DashboardDefinition;\n resolver: Pick<DeviceResolver, 'deviceExists'>;\n address: BoundDevicesAddress;\n // False while the board is being edited: the overlay is empty then, and an empty overlay must\n // not strip the link out of the address the author will return to.\n enabled?: boolean;\n}): BoundDevices {\n // The check that is read on the first render so a link never paints the board's defaults first.\n // The overlay, with the `bind.*` slice of the address it was last made to agree with. They move\n // together because the write-back below must only run while the address has not moved ahead of\n // the selection: an address that changed from outside is READ, never overwritten by a selection\n // that has not caught up with it yet.\n const [core, setCore] = useState<{ selection: Record<string, SlotBinding>; synced: string }>(() => ({\n selection: {},\n synced: bindParamsOf(address.search),\n }));\n const { selection } = core;\n const [phase, setPhase] = useState<BoundDevicesPhase>(() =>\n hasBindParams(address.search, definition) ? 'checking' : 'ready',\n );\n const [problems, setProblems] = useState<LinkProblems | null>(null);\n const [okBinds, setOkBinds] = useState<Record<string, string>>({});\n\n const definitionRef = useRef(definition);\n definitionRef.current = definition;\n const resolverRef = useRef(resolver);\n resolverRef.current = resolver;\n const replaceRef = useRef(address.replaceSearch);\n replaceRef.current = address.replaceSearch;\n\n // The `bind.*` slice of the address as this hook last wrote or last read it. An address whose\n // slice differs from this changed from OUTSIDE and is a new link.\n const seenRef = useRef<string | null>(null);\n const generation = useRef(0);\n const [attempt, setAttempt] = useState(0);\n\n const search = address.search;\n useEffect(() => {\n if (!enabled) return;\n const slice = bindParamsOf(search);\n // Our own write coming back round: nothing to read.\n if (seenRef.current === slice) return;\n seenRef.current = slice;\n\n const parsed = parseBindParams(search, definitionRef.current);\n if (Object.keys(parsed.binds).length === 0 && parsed.issues.length === 0) {\n generation.current += 1;\n setCore({ selection: {}, synced: slice });\n setProblems(null);\n setPhase('ready');\n return;\n }\n const gen = ++generation.current;\n setPhase('checking');\n void validateBinds(parsed.binds, resolverRef.current).then((check) => {\n if (gen !== generation.current) return;\n setOkBinds(check.ok);\n if (parsed.issues.length === 0 && check.missing.length === 0 && check.failed.length === 0) {\n setCore({ selection: bindsToSelection(check.ok), synced: slice });\n setProblems(null);\n setPhase('ready');\n } else {\n setProblems({ issues: parsed.issues, missing: check.missing, failed: check.failed });\n setCore((c) => ({ ...c, synced: slice }));\n setPhase('refused');\n }\n });\n }, [search, enabled, attempt]);\n\n // selection \u2500\u25BA address\n useEffect(() => {\n if (!enabled || phase !== 'ready') return;\n const current = bindParamsOf(search);\n if (current !== core.synced) return; // the address moved first: the read effect owns this turn\n const next = withBindParams(search, selectionToBinds(core.selection, definition));\n const nextSlice = bindParamsOf(next);\n if (nextSlice === current) return;\n seenRef.current = nextSlice;\n setCore((c) => ({ ...c, synced: nextSlice }));\n replaceRef.current(next);\n }, [core, definition, phase, enabled, search]);\n\n const select = useCallback((t: SelectionTarget) => {\n setCore((c) => ({ ...c, selection: { ...c.selection, [t.slot]: t.binding } }));\n }, []);\n const reset = useCallback(() => setCore((c) => ({ ...c, selection: {} })), []);\n\n const dismiss = useCallback(() => {\n // Keep what DID check out, drop what did not; the write-back effect then cleans the address.\n setCore((c) => ({ ...c, selection: bindsToSelection(okBinds) }));\n setProblems(null);\n setPhase('ready');\n }, [okBinds]);\n const retry = useCallback(() => {\n seenRef.current = null;\n setAttempt((n) => n + 1);\n }, []);\n\n return { selection, select, reset, phase, problems: phase === 'refused' ? (problems ?? NO_PROBLEMS) : null, dismiss, retry };\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// What a host shows INSTEAD of the board when a deep link could not be honoured (see\n// useBoundDevices). One presentational component for every host, so the console and the /dash\n// viewer cannot word a refusal differently or, worse, disagree about whether to show the board.\n// It carries no copy: the host builds the lines from its own translations.\n\nimport type { BindParamIssue } from '@devicechain/dashboards';\nimport { css, fontVar } from '@devicechain/widget-sdk';\n\nexport interface BoundDevicesNoticeProps {\n title: string;\n // One sentence per problem, already worded by the host.\n lines: string[];\n // The explicit way forward: open the board without the parts of the link that failed.\n dismissLabel: string;\n onDismiss: () => void;\n // Offered only when a check failed (so asking again can change the answer).\n retryLabel?: string;\n onRetry?: () => void;\n}\n\nexport function BoundDevicesNotice({ title, lines, dismissLabel, onDismiss, retryLabel, onRetry }: BoundDevicesNoticeProps) {\n const button = {\n minHeight: 44,\n padding: '0 16px',\n borderRadius: 8,\n border: `1px solid ${css('border')}`,\n background: css('card'),\n color: css('foreground'),\n fontSize: fontVar('md'),\n cursor: 'pointer',\n } as const;\n return (\n <div\n role=\"alert\"\n data-testid=\"bound-devices-notice\"\n style={{\n boxSizing: 'border-box',\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'flex-start',\n gap: 12,\n maxWidth: 560,\n margin: '24px auto',\n padding: 16,\n borderRadius: 8,\n border: `1px solid ${css('border')}`,\n background: css('card'),\n color: css('foreground'),\n }}\n >\n <div style={{ fontSize: fontVar('lg'), fontWeight: 600 }}>{title}</div>\n <ul style={{ margin: 0, paddingLeft: 20, display: 'flex', flexDirection: 'column', gap: 4, fontSize: fontVar('md') }}>\n {lines.map((line, i) => (\n <li key={i} style={{ overflowWrap: 'anywhere' }}>\n {line}\n </li>\n ))}\n </ul>\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>\n {retryLabel && onRetry ? (\n <button type=\"button\" style={button} onClick={onRetry} data-testid=\"bound-devices-retry\">\n {retryLabel}\n </button>\n ) : null}\n <button type=\"button\" style={button} onClick={onDismiss} data-testid=\"bound-devices-dismiss\">\n {dismissLabel}\n </button>\n </div>\n </div>\n );\n}\n\n// The lines a refused link reports, in the order a viewer fixes them: what the link got wrong,\n// then which devices are not theirs to see, then which could not be checked. The wording is the\n// host's; this only decides WHICH problems exist and how many sentences they make.\nexport interface BoundDevicesWording {\n unknownSlot: (slot: string) => string;\n notADeviceSlot: (slot: string) => string;\n invalidToken: (slot: string, token: string) => string;\n // The link names the slot twice.\n duplicateSlot: (slot: string) => string;\n // The slot's device follows another slot, so a link cannot choose it.\n derivedSlot: (slot: string) => string;\n // \"doesn't exist, or you don't have access\": one wording, because the server answers one way.\n missing: (slot: string, token: string) => string;\n failed: (slot: string, token: string) => string;\n}\n\n// A slot name or a value that failed the grammar is whatever the link's sender typed, and it is\n// shown inside the product's own UI: clipped, so a link cannot put a paragraph of its own words\n// (\"your session expired, sign in at \u2026\") in front of the viewer. A valid token is at most 128\n// characters of [A-Za-z0-9_-] and is shown whole.\nconst ECHO_MAX = 48;\nconst echo = (s: string) => (s.length > ECHO_MAX ? `${s.slice(0, ECHO_MAX)}\u2026` : s);\n\nexport function describeBoundDevicesProblems(\n problems: { issues: BindParamIssue[]; missing: Array<{ slot: string; token: string }>; failed: Array<{ slot: string; token: string }> },\n w: BoundDevicesWording,\n): string[] {\n const out: string[] = [];\n for (const i of problems.issues) {\n const slot = echo(i.slot);\n if (i.kind === 'unknown-slot') out.push(w.unknownSlot(slot));\n else if (i.kind === 'not-a-device-slot') out.push(w.notADeviceSlot(slot));\n else if (i.kind === 'duplicate-slot') out.push(w.duplicateSlot(slot));\n else if (i.kind === 'derived-slot') out.push(w.derivedSlot(slot));\n else if (i.kind === 'invalid-token') out.push(w.invalidToken(slot, echo(i.token)));\n else {\n // A new kind must be worded, not shown as some other kind's sentence.\n const unhandled: never = i;\n throw new Error(`describeBoundDevicesProblems: unworded link issue ${JSON.stringify(unhandled)}`);\n }\n }\n for (const m of problems.missing) out.push(w.missing(m.slot, m.token));\n for (const f of problems.failed) out.push(w.failed(f.slot, f.token));\n return out;\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The built-in descriptors AS PUBLISHED: the runtime descriptors of builtin-descriptors.ts with each\n// option's authoring `doc` attached from builtin-option-docs.ts.\n//\n// \uD83D\uDD11 WHY TWO. The renderer needs a widget's channel, options, defaults and binding -- not the prose\n// that explains an option to an author. Prose is the heaviest part of a descriptor, and a descriptor\n// is read eagerly, so it rode in the first download of every host (the replay player's initial bundle\n// grew with each widget for exactly this reason). The runtime descriptors therefore carry no `doc`;\n// this module rebuilds the documented form for EVERY public export that always carried it:\n// `builtinWidgetDescriptors`, `builtinWidgetCatalog`, `builtinWidgetDefinitions`,\n// `createBuiltinWidgetRegistry` and `WIDGET_OPTIONS`. These are published API -- an embedder's config\n// panel may read `doc` off any of them -- so none of them may lose it. The doc-free definitions are\n// published separately, and additively, as `builtinWidgetDefinitionsWithoutDocs`: what a render-only\n// host (the shared host-widgets composition) registers.\n//\n// Every value here is a /* @__PURE__ */ call, so a host that imports none of them -- the replay\n// player, the dashboard viewer -- has the whole module, and the doc table behind it, dropped by its\n// bundler. Nothing in this package's own runtime path imports this file; the replay build's size\n// gate (its absence check) is what would show it if that changed.\n\nimport { createWidgetCatalog, type WidgetDescriptor, type WidgetOptionSpecs } from '@devicechain/dashboards';\nimport { createWidgetRegistry, type WidgetRegistry } from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors as runtimeDescriptors } from './builtin-descriptors';\nimport { OPTION_DOCS, OPTION_DOC_OVERRIDES } from './builtin-option-docs';\nimport { builtinWidgetDefinitions as runtimeDefinitions } from './builtin-registry';\n\n// A copy of an option table with every spec's (and list item field's) doc attached. A COPY, never an\n// edit in place: the runtime descriptors are frozen by the runtime catalog, and a documented\n// descriptor sharing their spec objects would freeze/alias them too.\nfunction documentOptions(widgetId: string, specs: WidgetOptionSpecs, prefix: string): WidgetOptionSpecs {\n const out: Record<string, unknown> = {};\n for (const [key, spec] of Object.entries(specs)) {\n const path = `${prefix}${key}`;\n const copy: Record<string, unknown> = { ...spec };\n const doc = OPTION_DOC_OVERRIDES[widgetId]?.[path] ?? OPTION_DOCS[path];\n if (doc !== undefined) copy.doc = doc;\n if ('item' in spec && spec.item) copy.item = documentOptions(widgetId, spec.item as WidgetOptionSpecs, `${path}.`);\n // Arrays and nested plain data (enum values, labels) are shared by reference with the\n // runtime spec; they are read-only data on both sides.\n out[key] = copy;\n }\n return out as WidgetOptionSpecs;\n}\n\nfunction documentDescriptor<D extends WidgetDescriptor>(descriptor: D): D {\n return { ...descriptor, options: documentOptions(descriptor.id, descriptor.options, '') };\n}\n\nfunction documentAll<T extends Record<string, WidgetDescriptor>>(descriptors: T): T {\n return Object.fromEntries(Object.entries(descriptors).map(([id, d]) => [id, documentDescriptor(d)])) as T;\n}\n\nexport const builtinWidgetDescriptors = /* @__PURE__ */ documentAll(runtimeDescriptors);\n\nfunction catalogOf(descriptors: Record<string, WidgetDescriptor>) {\n return createWidgetCatalog(Object.values(descriptors));\n}\n\nexport const builtinWidgetCatalog = /* @__PURE__ */ catalogOf(builtinWidgetDescriptors);\n\n// The registrations, each paired with its documented descriptor (the component is the same one).\nfunction documentDefinitions<T extends readonly { descriptor: WidgetDescriptor }[]>(definitions: T): T {\n const byId: Record<string, WidgetDescriptor> = builtinWidgetDescriptors;\n return definitions.map((d) => ({ ...d, descriptor: byId[d.descriptor.id] })) as unknown as T;\n}\n\nexport const builtinWidgetDefinitions = /* @__PURE__ */ documentDefinitions(runtimeDefinitions);\n\n// A fresh, sealed registry holding exactly the built-ins, documented. Every call returns an\n// independent instance.\nexport function createBuiltinWidgetRegistry(): WidgetRegistry {\n return createWidgetRegistry(builtinWidgetDefinitions);\n}\n\n// Every built-in's option schema keyed by id, documented: the same projection options.ts makes of\n// the runtime descriptors (its type is that one's), by identity with the documented descriptors.\nfunction optionsById<T extends Record<string, WidgetDescriptor>>(descriptors: T): { readonly [K in keyof T]: T[K]['options'] } {\n return Object.freeze(Object.fromEntries(Object.entries(descriptors).map(([id, d]) => [id, d.options]))) as {\n readonly [K in keyof T]: T[K]['options'];\n };\n}\n\nexport const WIDGET_OPTIONS = /* @__PURE__ */ optionsById(builtinWidgetDescriptors);\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The authoring documentation of every built-in widget option -- the `doc` text each option spec\n// carries for the config panel's help and the published \"available widgets\" page.\n//\n// \uD83D\uDD34 WHY THIS IS NOT IN builtin-descriptors.ts. A `doc` is read by nothing that RENDERS a board,\n// only by authoring surfaces, yet it is prose, and prose is the most expensive thing per byte that\n// a descriptor carries: kept inline it shipped in the first download of every host (the replay\n// player's was ~2 KB gzip, growing with each widget). So the runtime descriptors\n// (builtin-descriptors.ts) carry none, and `builtinWidgetDescriptors` / `builtinWidgetCatalog` as\n// PUBLIC exports are rebuilt from them plus this table (documented-descriptors.ts), which a host that\n// never imports those two drops from its bundle.\n//\n// Keys are option PATHS: `thresholds` for an option, `thresholds.value` for a list option's item\n// field. `OPTION_DOCS` is the text an option has on most widgets; `OPTION_DOC_OVERRIDES` is where a\n// widget words one differently. A built-in option with no doc here fails\n// documented-descriptors.test.ts, which is where the \"every option is documented\" rule that\n// validateWidgetDescriptor applies to extensions is enforced for the built-ins.\n\nexport const OPTION_DOCS: Readonly<Record<string, string>> = {\n title: 'Heading shown in the widget frame. Blank hides the frame heading.',\n unit: 'Unit suffix shown beside the value.',\n precision: 'Decimal places to round displayed values to. Unset rounds to at most 3 decimals (4 significant digits under 1).',\n thresholds: 'Severity bands over the value. Each entry starts a band at its value that runs to the next entry; below the first, and in a normal band, the widget keeps its own colour.',\n 'thresholds.value': 'The value at which this band starts.',\n 'thresholds.level': 'The severity of this band. The theme decides the colour; normal has none.',\n 'thresholds.label': 'Text shown on the chart line for this threshold. Defaults to its value.',\n staleAfterSeconds: 'Seconds after which the newest sample is called stale: the value is greyed out and badged. Unset shows the sample age only and never marks the widget stale.',\n windowSeconds: 'Seconds of history the widget covers, back from now. Leave unset to follow the board\u2019s time range; set it to pin this widget to a fixed span that the viewer\u2019s range picker does not change. 60 to 604800.',\n measurement: 'Which measurement to display. Defaults to the first the datasource selects.',\n flashOnChange: 'Briefly tint a value green on a rise and red on a fall when it changes.',\n window: \"Samples retained across ALL of the widget's measurements before the oldest are dropped. Bounds memory; only the chart draws them. Default 300.\",\n min: 'Value at the empty end of the scale. Required: the widget does not guess a range.',\n max: 'Value at the full end of the scale. Required, and above min.',\n text: 'The text to show. Rendered as plain text \u2014 markup is never interpreted.',\n align: 'Horizontal alignment of the text. Default center.',\n fontSize: 'Text size in pixels at the comfortable density; it scales with the board density. Default 16.',\n url: 'Source URL of the image.',\n alt: 'Alternative text describing the image for assistive technology.',\n fit: 'How the image fills its box. Default contain.',\n state: 'Show only alarms in this state. Unset shows every state.',\n severity: 'Show only alarms at this severity. Unset shows every severity.',\n acknowledged: \"Show only acknowledged ('true') or unacknowledged ('false') alarms. Unset shows both.\",\n groupBy: 'deviceType: a tab per device type.',\n deviceType: 'Only alarms on devices of this type (token).',\n deviceTypes: 'Types to tab, in order; unset tabs all.',\n 'deviceTypes.token': 'Type token.',\n maxRows: 'Alarms loaded into the table. Default 50.',\n selectionTarget: 'Name of the slot this widget re-points when the viewer picks an entity.',\n commandName: 'Command key issued to the target device. Without it the control cannot send.',\n commandLabel: 'Name of the control for assistive technology. Defaults to the command key.',\n parameterSchema: \"The command's parameter descriptors, baked in as JSON at author time. Gives the control its range and its refusals.\",\n tileUrl: \"Raster tile URL template, e.g. https://tiles.example.com/{z}/{x}/{y}.png. Leave empty to inherit the tenant's basemap; setting one overrides it for this board only.\",\n attribution: 'Credit line the tile source requires, shown on the map. Set whatever the provider you chose asks for.',\n style: 'A plain bar (default) or a thermometer: a vertical tube with a bulb. A thermometer is always vertical.',\n markAlarms: 'Mark this device\u2019s alarms on the chart, from raise to clear.',\n markAlarmsScope: 'Which alarms to mark: only those about what this chart plots (series, the default for a new chart), or every alarm on the device. An alarm with no known measurement is never marked in series mode; it is listed under the chart as another alarm on the device. A chart saved before this option marks the whole device.',\n markCommands: 'Mark the commands sent to this device on the chart.',\n orientation: 'Direction of a bar: horizontal (default) or vertical. Ignored by a thermometer.',\n readout: 'What the readout shows: the value with its unit (default) or the percent of the scale.',\n onAt: 'For an on/off signal: the lamp is lit at or above this value and dark below it. Unset keeps the lamp lit while a value is present, coloured by its threshold band.',\n parameter: 'Which parameter of the command this control sets. May be left blank when the command has exactly one parameter of the right type.',\n step: 'Distance between values. Defaults to 1 for a whole-number parameter, else a hundredth of the range.',\n mode: 'Slider (default) or stepper: \u2212 / + and Send.',\n stat: 'Which figure to show. Default average.',\n sparkline: 'Draw the measurement\u2019s trend over the span under the figure. Default off.',\n sort: 'Order of the categories. Default: as the data source lists them.',\n columns: 'Heading, unit and precision per measurement column; a column with none shows its name.',\n 'columns.measurement': 'The measurement column this entry applies to.',\n 'columns.label': 'Column heading. Defaults to the measurement name.',\n 'columns.unit': 'Unit suffix shown beside the value.',\n 'columns.precision': 'Decimal places to round displayed values to. Unset rounds to at most 3 decimals (4 significant digits under 1).',\n 'thresholds.measurement': 'The measurement column this entry applies to.',\n ageLagSeconds: \"Show a reading's age under it only when the reading is at least this many seconds older than the newest reading in the table (or stale). Unset shows every reading's age.\",\n sortBy: 'The measurement the table is ordered by. Blank orders by device name.',\n sortDescending: 'Largest first.',\n oldestFirst: 'List the oldest bucket first. Unset lists the newest first.',\n pageSize: 'Devices per page. Default 20.',\n maxSeries: 'Most lines drawn when the chart shows one line per device. Default 5, at most 12. Each line costs one stored-history read, and the chart colours repeat after five; a group larger than this shows the first devices of the group and says how many it left out.',\n show: 'What to count: devices in an abnormal band of the measurement (default), or all devices.',\n};\n\nexport const OPTION_DOC_OVERRIDES: Readonly<Record<string, Readonly<Record<string, string>>>> = {\n 'latest-card': {\n title: 'Heading shown in the widget frame. Defaults to the displayed measurement name.',\n },\n gauge: {\n title: 'Heading shown in the widget frame. Defaults to the displayed measurement name.',\n min: 'Low end of the gauge scale. Default 0.',\n max: 'High end of the gauge scale. Default 100.',\n },\n 'linear-gauge': {\n title: 'Heading shown in the widget frame. Defaults to the displayed measurement name.',\n },\n 'level-gauge': {\n title: 'Heading shown in the widget frame. Defaults to the displayed measurement name.',\n },\n battery: {\n title: 'Heading shown in the widget frame. Defaults to the displayed measurement name.',\n min: 'Value of an empty battery. Default 0 (the scale is percent unless you set min and max).',\n max: 'Value of a full battery. Default 100 (the scale is percent unless you set min and max).',\n },\n 'status-light': {\n title: 'Heading shown in the widget frame. Defaults to the displayed measurement name.',\n },\n 'signal-bars': {\n title: 'Heading shown in the widget frame. Defaults to the displayed measurement name.',\n thresholds: 'The steps of the signal, lowest first: one bar per entry, lit once the value reaches it and coloured by its level. At least two, at most eight.',\n },\n compass: {\n title: 'Heading shown in the widget frame. Defaults to the displayed measurement name.',\n precision: 'Decimal places of the heading. Default 0 (whole degrees). The heading is rounded first, then folded onto 0 to 360, so it never reads 360.',\n thresholds: 'Severity bands over the heading in degrees (0 to 360, after folding). Each entry starts a band at its value that runs to the next entry; below the first, and in a normal band, the needle keeps its own colour.',\n },\n 'progress-ring': {\n title: 'Heading shown in the widget frame. Defaults to the displayed measurement name.',\n readout: 'What the middle of the ring shows: the percent of the scale (default) or the value with its unit.',\n },\n 'stat-card': {\n title: 'Heading shown in the widget frame. Defaults to the displayed measurement name.',\n },\n 'device-status': {\n staleAfterSeconds: 'Marks the card stale once its status has not been read for longer than this many seconds (it is re-read every 15 seconds, so only reads that keep failing make it stale). A device that is merely silent is not stale: whether it is online is the status itself. Unset, the age is shown and nothing is marked stale.',\n },\n 'online-doughnut': {\n staleAfterSeconds: 'Marks the ring stale once the status of its devices has not been read for longer than this many seconds (it is re-read every 15 seconds, so only reads that keep failing make it stale). Unset, the age is shown and nothing is marked stale.',\n },\n 'history-table': {\n columns: 'Which measurements are columns, in order, with a heading, unit and precision each. With none, the columns are the datasource\u2019s measurements (or, when it names none, every measurement the device reported in the range). Every figure is the average of the readings in a time bucket.',\n precision: 'Decimal places to round displayed averages to, for a column that sets none. Unset rounds to at most 3 decimals (4 significant digits under 1). The CSV export is rounded the same way.',\n pageSize: 'Rows per page. Default 10. The CSV export holds every row, not just the page.',\n staleAfterSeconds: 'Marks the table stale once its history has not been read for longer than this many seconds (it is re-read at the end of each time bucket, so only reads that keep failing make it stale). Unset, the age is shown and nothing is marked stale.',\n },\n 'fleet-count': {\n measurement: 'The measurement whose bands flag a device. Defaults to the first the datasource selects.',\n },\n 'command-slider': {\n min: \"Lowest value, used only when the command's parameter declares no minimum.\",\n max: \"Highest value, used only when the command's parameter declares no maximum.\",\n },\n 'timeseries-chart': {\n min: 'Low end of the value axis. Unset, the axis starts where the chart picks. A reading or threshold below it still shows: the axis widens to take it in.',\n max: 'High end of the value axis, above min. Unset, the chart picks. A reading or threshold above it still shows: the axis widens to take it in.',\n groupBy: 'One line per measurement of one device (the default), or one line per device of a group for the measurement set below. Per device, stored history is drawn as the average of each time bucket (the chart says so), and thresholds are reference lines over it.',\n measurement: 'The measurement compared across the group. Defaults to the first the datasource selects. Used only with one line per device.',\n markAlarms: 'Mark this device\u2019s alarms on the chart, from raise to clear. Not drawn with one line per device.',\n markCommands: 'Mark the commands sent to this device on the chart. Not drawn with one line per device.',\n },\n 'bar-chart': {\n groupBy: 'One bar per measurement (the default), or per device of the group for the measurement set below.',\n },\n 'command-button': {\n maxRows: 'Recent commands shown in the history. Default 20.',\n commandName: 'Command key issued to the target device. Without it the widget cannot send.',\n commandLabel: 'Text on the send button. Defaults to the command key.',\n parameterSchema: \"The command's parameter descriptors, baked in as JSON at author time. Drives the typed form.\",\n },\n};\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// preloadWidgets fetches the lazily loaded code of the given widget types, so a host that awaits\n// it before rendering a board draws every widget on the first frame instead of an empty box\n// while a chunk is in flight. A host that never calls it loses nothing: each widget still loads\n// its own chunk on first mount.\n//\n// A type with no lazy code (an eager built-in, an extension, an unknown id) is skipped. A chunk\n// that fails to load does not reject this: a failed load is not remembered, so the widget fetches\n// its chunk again on mount, and if that fails too the error is thrown to its error boundary, which\n// is where the failure belongs.\n\nimport type { WidgetRegistry } from '@devicechain/widget-sdk';\n\nexport async function preloadWidgets(registry: WidgetRegistry, types: Iterable<string>): Promise<void> {\n const loads: Promise<unknown>[] = [];\n for (const type of new Set(types)) {\n const preload = (registry.implementation(type)?.component as { preload?: unknown } | undefined)?.preload;\n if (typeof preload === 'function') loads.push((preload as () => Promise<unknown>)().catch(() => undefined));\n }\n await Promise.all(loads);\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The by-id views of the built-in registrations that older consumers still import.\n//\n// \uD83D\uDD34 READ-ONLY PROJECTIONS, NOT A REGISTRY. A widget's channel and whether it binds a\n// datasource are declared once, on its descriptor (builtin-descriptors.ts), and the\n// renderer resolves everything through a registry instance (createWidgetRegistry) -- never\n// through these. They exist so code that wants to ask \"which channel is this built-in on?\"\n// without building a registry (the console's config panel, fixtures) keeps working. They are\n// frozen, computed from the descriptors at module load, and there is no way to add an\n// entry: an extension widget registers through createWidgetRegistry, not here.\n\nimport type { BuiltinWidgetId, WidgetChannel } from '@devicechain/dashboards';\n\nimport { builtinWidgetDescriptors } from './builtin-descriptors';\n\n// WidgetChannel itself is declared once, in @devicechain/dashboards; re-exported so this\n// module's importers are unchanged.\nexport type { WidgetChannel };\n\ntype Descriptors = typeof builtinWidgetDescriptors;\n\nconst entries = Object.entries(builtinWidgetDescriptors) as Array<[BuiltinWidgetId, Descriptors[BuiltinWidgetId]]>;\n\n// A built-in's data channel, as its descriptor declares it.\nexport const WIDGET_CHANNEL: { readonly [K in BuiltinWidgetId]: Descriptors[K]['channel'] } = Object.freeze(\n Object.fromEntries(entries.map(([id, d]) => [id, d.channel])),\n) as { readonly [K in BuiltinWidgetId]: Descriptors[K]['channel'] };\n\n// Whether a built-in binds a DATASOURCE -- the entity whose data it reads. Derived from the\n// descriptor's datasource mode: `none` binds nothing (label, image, the entity selector).\nexport const WIDGET_BINDS_DATASOURCE: { readonly [K in BuiltinWidgetId]: boolean } = Object.freeze(\n Object.fromEntries(entries.map(([id, d]) => [id, d.datasource.mode !== 'none'])),\n) as { readonly [K in BuiltinWidgetId]: boolean };\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// @devicechain/widgets \u2014 presentational dashboard widgets (ADR-039).\n//\n// Eleven built-ins over the DashboardHub's live data, themed via CSS custom\n// properties (no Tailwind leakage \u2014 embeddable in any React host). Each is a\n// registration declared with the public `defineWidget` from @devicechain/widget-sdk;\n// a renderer resolves a widget through a registry instance.\n\n// The view-only dashboard renderer: lays a parsed definition's widgets on the\n// canvas and binds each to the hub. The shared viewer for the console + external apps.\nexport { DashboardRenderer, resolveWidgets, widgetSubjectLabel, type DashboardRendererProps } from './dashboard-renderer';\nexport {\n AbsoluteIndicator,\n DEFAULT_ABSOLUTE_LABELS,\n DEFAULT_TIME_RANGE_LABELS,\n PausedIndicator,\n TimeRangeBar,\n absoluteLinkFor,\n formatAbsoluteRange,\n rejectedLinkNote,\n useBoardTimeRange,\n type AbsoluteLabels,\n type TimeRangeControls,\n type TimeRangeLabels,\n} from './time-range-bar';\n\n// Deep links that open a board with a device bound: the hook that keeps the address and the\n// selection in step (and checks the named devices against the caller's scope), and the notice a\n// host shows instead of the board when a link cannot be honoured.\nexport {\n useBoundDevices,\n type BoundDevices,\n type BoundDevicesAddress,\n type BoundDevicesPhase,\n type LinkProblems,\n} from './use-bound-devices';\nexport {\n BoundDevicesNotice,\n describeBoundDevicesProblems,\n type BoundDevicesNoticeProps,\n type BoundDevicesWording,\n} from './bound-devices-notice';\n\n// Renderer entry point: binds the hub to a widget by type.\nexport { ConnectedWidget, type ConnectedWidgetProps } from './connected-widget';\n\n// The built-ins as registrations (the same descriptor + component pairing a third-party\n// package supplies), and the factory for a sealed registry holding exactly them.\n//\n// Every one of these carries each option's `doc`. `builtinWidgetDefinitionsWithoutDocs` is the same\n// registrations without it -- for a host that only renders boards and never shows an option's help,\n// which then does not download the prose (a built-in id is the one place the registry excuses a\n// missing doc). Its descriptors are TYPED as documented; their `doc` is absent at runtime.\nexport {\n builtinWidgetCatalog,\n builtinWidgetDescriptors,\n builtinWidgetDefinitions,\n createBuiltinWidgetRegistry,\n WIDGET_OPTIONS,\n} from './documented-descriptors';\nexport { builtinWidgetDefinitions as builtinWidgetDefinitionsWithoutDocs } from './builtin-registry';\nexport { preloadWidgets } from './preload';\n\n// Read-only by-id views of the built-in descriptors (channel, datasource binding), and the\n// widget contract. The registrations above are the source of truth; these are derived.\nexport { WIDGET_CHANNEL, WIDGET_BINDS_DATASOURCE, type WidgetChannel } from './registry';\nexport { pickSample, optBoolean, type WidgetProps, type WidgetComponent } from '@devicechain/widget-sdk';\n\n// The tenant basemap seam. A host installs the provider; map widgets read it.\nexport { TenantBasemapProvider, useTenantBasemap } from './basemap-context';\n\n// The map RUNTIME seam \u2014 the MapLibre pieces only the host's bundler can emit.\n//\n// \uD83D\uDD34 Unlike the basemap provider above, this one is REQUIRED by any host that renders a\n// map widget: without it the widget shows a notice instead of a map. That is deliberate.\n// The alternative to a host-supplied worker URL is MapLibre's own runtime derivation,\n// which no bundler can follow, and which fails as a map that renders nothing at all.\nexport { MapRuntimeProvider, useMapRuntime, type MapRuntime } from './map-runtime-context';\n\n// The typed schema for each widget's options bag: what the renderer reads, at what type,\n// with what legal values. WidgetOptions<T> types code that BUILDS options;\n// validateWidgetOptions reports where a stored bag disagrees with the renderer.\nexport {\n validateWidgetOptions,\n numberOptionSpec,\n clampNumberOption,\n enumOptionValues,\n type WidgetOptions,\n type WidgetOptionSpecs,\n type OptionSpec,\n type StringOptionSpec,\n type NumberOptionSpec,\n type BooleanOptionSpec,\n type EnumOptionSpec,\n type ListItemFieldSpec,\n type ListOptionSpec,\n type OptionIssue,\n type OptionIssueCode,\n} from './options';\n\n// The same schemas applied to a whole board: what a producer of definitions asks\n// before it publishes one, plus the repair for the one issue an author cannot fix in\n// a config panel.\nexport {\n validateDefinitionOptions,\n stripUnknownOptions,\n type DefinitionOptionIssue,\n type DefinitionValidationOptions,\n} from './definition-options';\n\n// Individual widgets (for direct/custom use).\nexport { LatestCard } from './widgets/latest-card';\nexport { Gauge } from './widgets/gauge';\nexport { TimeSeriesChart } from './widgets/time-series-chart';\nexport { Table } from './widgets/table';\nexport { Label } from './widgets/label';\nexport { Image } from './widgets/image';\nexport { AlarmTable } from './widgets/alarm-table';\nexport { AlarmCount } from './widgets/alarm-count';\nexport { AlarmSeverity } from './widgets/alarm-severity';\nexport { CommandButton } from './widgets/command-button';\nexport { EntitySelector } from './widgets/entity-selector';\nexport { MapWidget } from './widgets/map';\n// The map's pure parts: which samples can be placed, where they land on a tile-less\n// panel, and how a fix is described without inventing the fields it does not carry.\n//\n// loadLandStyle is the bundled world basemap \u2014 the style used when no tile source\n// is configured. Exported so the console's fence editor and this package's map\n// widget cannot end up drawing two different worlds; the geometry itself stays\n// behind a dynamic import inside that module, so naming it here costs nothing.\nexport {\n placeable,\n projectToPanel,\n describePosition,\n formatDegrees,\n rasterStyleFor,\n landStyleFrom,\n loadLandStyle,\n BUNDLED_BASEMAP_ATTRIBUTION,\n type PlaceableLocation,\n type PanelPoint,\n} from './widgets/map-geometry';\nexport {\n severityColor,\n severityLabel,\n severityRank,\n highestSeverity,\n} from './widgets/severity';\nexport { commandStatusColor, commandStatusLabel, isTerminalStatus } from './widgets/command-status';\nexport {\n parseParameterSchema,\n defaultValues,\n validateParams,\n buildPayload,\n isScalar,\n} from './widgets/command-params';\n\n// Building blocks for custom widgets. They live in @devicechain/widget-sdk (the one place the\n// ambient host contexts may be defined) and are re-exported so existing imports keep resolving;\n// the chart helpers come from its `/echarts` subpath.\nexport {\n WidgetFrame,\n WidgetSubjectProvider,\n WidgetSelectProvider,\n useWidgetSelect,\n WidgetTimeZoneProvider,\n useWidgetTimeZone,\n WidgetThemeRootProvider,\n useWidgetThemeRoot,\n WidgetCandidatesProvider,\n useWidgetCandidates,\n useFlashOnChange,\n flashTextStyle,\n flashBackgroundStyle,\n FlashValue,\n fitValueFont,\n useMeasurementStream,\n useAlarmStream,\n useCommandStream,\n useLocationStream,\n useDatasourceAvailability,\n useDashboardHub,\n useHubConnectionState,\n HubConnectionBadge,\n useResolvedBindings,\n useViewerBindings,\n useSlotCandidates,\n useCandidates,\n css,\n type FlashDirection,\n type WidgetFrameProps,\n type WidgetSelect,\n type WidgetCandidates,\n type MeasurementStreamState,\n type AlarmStreamState,\n type CommandStreamState,\n type LocationStreamState,\n type CandidatesState,\n type DatasourceAvailability,\n type HubConnectionBadgeProps,\n type ThemeVar,\n} from '@devicechain/widget-sdk';\nexport {\n EChart,\n buildLineOption,\n buildGaugeOption,\n resolveChartTheme,\n useChartTheme,\n type EChartOption,\n type LineChartOptions,\n type GaugeChartOptions,\n type ChartTheme,\n} from '@devicechain/widget-sdk/echarts';\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// WIDGET_OPTIONS \u2014 the typed schema for each widget type's `options` bag, as a by-id view.\n//\n// A WidgetInstance's `options` is `Record<string, unknown>` in the stored definition:\n// dashboard-management keeps a definition as opaque JSON, and the definition parser does\n// not look inside `options` at all. Each built-in's descriptor (builtin-descriptors.ts)\n// declares every option the RENDERER actually reads, with its type and legal values; this\n// module projects those schemas by id and wraps the shared engine under the by-type names\n// the console and fixtures use:\n// \u2022 validateWidgetOptions() \u2014 the runtime check, for anything that PRODUCES a definition\n// (a generated dashboard must not ship an options blob the renderer ignores).\n// \u2022 WidgetOptions<T> \u2014 the compile-time shape, for code that builds options.\n//\n// The schema describes the RENDERER, because that is the contract deciding what a viewer\n// actually sees. Where the console's authoring UI offers fewer keys than this \u2014 it does:\n// `align`, `fontSize`, `fit`, `window` and `measurement` are all honored by the renderer\n// and not authorable in the config panel \u2014 the gap is in the panel, not here.\n//\n// The spec VOCABULARY and the engine that checks a bag against a schema live in\n// @devicechain/dashboards (option-schema.ts) \u2014 they know no widget type, so the SDK's\n// registry validates an extension's schema with the very code that validates this one.\n\nimport {\n clampNumberOption,\n enumValues,\n numberSpec,\n validateOptions,\n type NumberOptionSpec,\n type OptionConstraint,\n type OptionIssueCode,\n type BuiltinWidgetId,\n type OptionsOf,\n type WidgetOptionSpecs,\n type WidgetType,\n} from '@devicechain/dashboards';\n\nimport { builtinWidgetCatalog, builtinWidgetDescriptors } from './builtin-descriptors';\n\nexport type {\n BooleanOptionSpec,\n EnumOptionSpec,\n ListItemFieldSpec,\n ListOptionSpec,\n NumberOptionSpec,\n OptionIssueCode,\n OptionSpec,\n StringOptionSpec,\n WidgetOptionSpecs,\n} from '@devicechain/dashboards';\nexport { clampNumberOption };\n\n// ---- The derived by-id view -------------------------------------------------\n\n// Every built-in's option schema, keyed by id. A frozen PROJECTION of the descriptors in\n// builtin-descriptors.ts (each schema is declared there, once, beside the widget's channel and\n// binding policy); it holds no schema of its own, so it cannot drift from what the registry\n// validates. The cross-field rules (gauge's max > min) travel on the descriptor as data.\ntype OptionsById = { readonly [K in BuiltinWidgetId]: (typeof builtinWidgetDescriptors)[K]['options'] };\n\nexport const WIDGET_OPTIONS: OptionsById = Object.freeze(\n Object.fromEntries(Object.entries(builtinWidgetDescriptors).map(([id, d]) => [id, d.options])),\n) as OptionsById;\n\nfunction constraintsFor(widgetType: WidgetType): readonly OptionConstraint[] {\n return builtinWidgetCatalog.get(widgetType)?.constraints ?? [];\n}\n\n// ---- Derived compile-time types ---------------------------------------------\n\n// WidgetOptions<'gauge'> is the typed options bag for a gauge: every declared key at its\n// declared type, required ones mandatory. Code that BUILDS a definition should type its\n// options with this \u2014 a typo is then a compile error rather than a key nothing reads.\n//\n// DISTRIBUTIVE over T, which is the whole reason it is written as a conditional. `keyof` a\n// union of the built-in tables is their INTERSECTION \u2014 only `title` \u2014 and the required-keys\n// computation over that union collapses to never, so the undistributed form silently\n// degenerates for any generic T: it would reject `{ text: 'body' }` as an excess property\n// while accepting `{}` for a widget that requires an option. That is exactly the position a\n// generator writing one widget of each type sits in. Distributing makes\n// WidgetOptions<WidgetType> the union of the per-type bags instead.\nexport type WidgetOptions<T extends WidgetType> = T extends WidgetType ? OptionsOf<(typeof WIDGET_OPTIONS)[T]> : never;\n\n// ---- Runtime validation -----------------------------------------------------\n\n// The by-type issue shape the console reads. `widgetType` keeps its name so existing\n// consumers compile unchanged; the engine's own issue calls the same value `widgetId`.\nexport interface OptionIssue {\n widgetType: WidgetType;\n // The offending option key. For a cross-field rule, the key the fix belongs on.\n key: string;\n code: OptionIssueCode;\n message: string;\n}\n\n// validateWidgetOptions reports every way a widget's stored options bag disagrees with\n// what the renderer reads. An empty result means every key present is one the renderer\n// honors, at a value it accepts, and no required option is missing.\n//\n// It is deliberately a REPORT rather than a throw: the renderer is tolerant by design and\n// must stay that way for a hand-edited definition, so the strictness belongs to whoever\n// produces definitions (fixtures, generators, the config panel) and to the tests that\n// gate them. Callers decide which codes are fatal \u2014 a stored dashboard carrying an\n// 'unknown' leftover is untidy; a generated one carrying 'missing' is broken.\nexport function validateWidgetOptions(\n widgetType: WidgetType,\n options: Record<string, unknown> | undefined,\n): OptionIssue[] {\n const specs: WidgetOptionSpecs = WIDGET_OPTIONS[widgetType];\n return validateOptions(specs, options, { constraints: constraintsFor(widgetType), label: widgetType }).map(\n ({ key, code, message }) => ({ widgetType, key, code, message }),\n );\n}\n\n// numberOptionSpec returns the declared bounds for a numeric option, so an authoring\n// UI can constrain its input from the schema rather than from a second, hand-written\n// copy of the same numbers. See numberSpec for why it exists.\nexport function numberOptionSpec(type: WidgetType, key: string): NumberOptionSpec | undefined {\n return numberSpec(WIDGET_OPTIONS[type], key);\n}\n\n// enumOptionValues returns the legal values of an enum option, so an authoring UI can\n// build its dropdown from the schema instead of a private copy of the same list.\nexport function enumOptionValues(type: WidgetType, key: string): readonly string[] | undefined {\n return enumValues(WIDGET_OPTIONS[type], key);\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The definition-level layer over validateWidgetOptions: \"is every widget on this\n// board configured with options the renderer actually reads?\"\n//\n// WHY IT IS A SEPARATE FUNCTION RATHER THAN A LOOP AT EACH CALL SITE. Every consumer\n// wants the same three things \u2014 walk the widgets, keep the issues, and know WHICH\n// widget each belongs to \u2014 and the third is the one a hand-rolled loop forgets. An\n// issue reported without its widget id tells an author that `commandName` is missing\n// on a board with three command buttons, which is a report they cannot act on.\n//\n// \uD83D\uDD11 THE OPTION SCHEMAS ARE TYPESCRIPT, AND THAT DECIDES WHERE THE GATE CAN LIVE.\n// dashboard-management stores a definition as opaque JSON and checks only that it is\n// a JSON object; it is Go, so it cannot run these schemas, and a Go copy of them\n// would be a THIRD representation of the same table (the reason ADR-076 declined a\n// cross-language widget manifest). So the strictness belongs to whoever PRODUCES a\n// definition, and \uD83D\uDD34 EACH PRODUCER HAS TO WIRE IT FOR ITSELF \u2014 there is no chokepoint\n// downstream that would catch a producer nobody thought about:\n//\n// \u2022 the console, by its publish action (apps/console/src/lib/api/dashboards.ts);\n// \u2022 the sim, by the golden-fixture gate over frontend/testdata/sim-dashboards, which\n// covers every dashboard of every REGISTERED scenario. It was widgetlab-only when\n// this function was written, and the sentence here claimed otherwise \u2014 buildingpulse,\n// the demo board, was gated by nothing. Two reviewers found the same overclaim\n// independently. The gate walks sim.Registry now, so the claim is true by\n// construction rather than by a list someone has to remember to extend.\n//\n// Anything ELSE writing a definition \u2014 raw GraphQL, a future importer \u2014 is unchecked,\n// because dashboard-management deliberately validates nothing. This is not the\n// server-side, ADR-044-style publish gate it superficially resembles, and calling it one\n// would misdescribe exactly which documents are protected.\n\nimport {\n UNKNOWN_WIDGET_TYPE,\n validateOptions,\n type DashboardDefinition,\n type WidgetCatalog,\n type WidgetDescriptor,\n type WidgetInstance,\n} from '@devicechain/dashboards';\n\nimport { builtinWidgetCatalog } from './builtin-descriptors';\nimport type { OptionIssue } from './options';\n\n// A DefinitionOptionIssue is an OptionIssue plus the widget that carries it.\n//\n// It deliberately carries the ID and nothing friendlier. An earlier version also read\n// `options.title` so a consumer could label the issue \u2014 and that one read, purely for\n// presentation, put this file into the option-read scan in options.test.ts, where every\n// other entry is evidence that a RENDERER reads a key. It needed a paragraph explaining\n// why it did not mean what its neighbours meant. A consumer that wants a title already\n// holds the definition and can join on the id; the scan goes back to meaning one thing.\nexport interface DefinitionOptionIssue extends Omit<OptionIssue, 'widgetType'> {\n // The stored widget id: a built-in type, or an extension's namespaced id.\n widgetType: string;\n widgetId: string;\n}\n\n// A definition as this module reads it: only the widget list matters, so the fixture\n// tests and the console's in-flight editor state both satisfy it without either having\n// to be a fully parsed DashboardDefinition.\ntype WidgetCarrier = Pick<DashboardDefinition, 'widgets'>;\n\n// validateDefinitionOptions reports every option issue on the board, in widget order.\n// An empty result means every widget's bag is one the renderer honors in full.\n//\n// A placeholder for a widget type this build does not know reports nothing: it carries\n// no options of its own (its stored object is kept verbatim, options and all), and this\n// build has no schema to judge a newer widget's options against.\n//\n// `options.catalog` is the host's widget catalog (registry.catalog): an extension widget is\n// judged against ITS registered schema. Omitted = the built-ins only, so a board carrying an\n// extension widget must be validated with the catalog it was parsed with.\nexport interface DefinitionValidationOptions {\n catalog?: WidgetCatalog;\n}\n\nexport function validateDefinitionOptions(\n definition: WidgetCarrier,\n options: DefinitionValidationOptions = {},\n): DefinitionOptionIssue[] {\n return definition.widgets.flatMap((widget) => {\n if (widget.type === UNKNOWN_WIDGET_TYPE) return [];\n const type = widget.type;\n const descriptor = descriptorFor(type, options.catalog);\n return validateOptions(descriptor.options, widget.options, {\n constraints: descriptor.constraints,\n label: type,\n }).map(({ key, code, message }) => ({ widgetType: type, key, code, message, widgetId: widget.id }));\n });\n}\n\n// The schema a recognized widget is judged against comes from the built-in CATALOG \u2014 the\n// same descriptors a registry holds \u2014 rather than from a by-type table, so this gate is the\n// live consumer of the registry's data. Every built-in type is in the catalog by\n// construction (builtin-registry.test.ts), so a miss is a defect to surface, not a widget\n// to skip.\n//\n// A catalog the host supplies is consulted first (an extension lives only there); a built-in\n// the supplied catalog omits falls back to the built-in descriptor, since its schema is the\n// same everywhere. An id neither holds is a defect \u2014 the board was parsed against a catalog\n// other than the one it is validated with \u2014 so it throws rather than skipping the widget.\nfunction descriptorFor(type: string, catalog: WidgetCatalog | undefined): WidgetDescriptor {\n const descriptor = catalog?.get(type) ?? builtinWidgetCatalog.get(type);\n if (!descriptor) {\n throw new Error(`no widget descriptor for \"${type}\"; validate with the catalog the definition was parsed with`);\n }\n return descriptor;\n}\n\n// stripUnknownOptions removes every option key no widget of that type reads, leaving\n// everything else untouched.\n//\n// \uD83D\uDD34 IT EXISTS BECAUSE 'unknown' IS THE ONE ISSUE CODE AN AUTHOR CANNOT FIX IN THE UI.\n// This is the canonical statement of that reasoning; the call sites point here.\n// Every other code sits on a DECLARED key, so the config panel renders a control for it\n// and the author edits or clears it. An unknown key is by definition one the panel has\n// no control for \u2014 and the panel preserves the bag it did not write (it spreads\n// `widget.options` on every edit), so the key survives every subsequent change. Without\n// this, a publish gate that treats 'unknown' as fatal is a dead end: a dashboard that\n// acquired a leftover key \u2014 from a version predating an option rename, or from a\n// producer other than the console \u2014 could never be published again through the UI.\n//\n// Returns the SAME object when there is nothing to strip, so a caller can detect a\n// no-op with `next === before`.\n//\n// \uD83D\uDD34 THE OBVIOUS REASON TO WANT THIS IS NOT THE REAL ONE, and the first version of this\n// comment gave the wrong one: it claimed a fresh-but-equal object would read as an\n// unsaved edit. It would not \u2014 the console's isDirty compares SERIALIZATIONS\n// (dashboards/src/definition.ts), so an equal-but-new object is not dirty. What the\n// identity actually buys is smaller and still worth having: the caller can tell \"there\n// was nothing to remove\" from \"I removed something\" without diffing, and it avoids a\n// state write that would re-render the editor for no change.\nexport function stripUnknownOptions<T extends WidgetCarrier>(definition: T, options: DefinitionValidationOptions = {}): T {\n let changed = false;\n const widgets = definition.widgets.map((widget) => {\n const stripped = stripUnknownWidgetOptions(widget, options.catalog);\n if (stripped !== widget) changed = true;\n return stripped;\n });\n return changed ? { ...definition, widgets } : definition;\n}\n\nfunction stripUnknownWidgetOptions(widget: WidgetInstance, catalog: WidgetCatalog | undefined): WidgetInstance {\n // A placeholder for an unknown widget type carries no options (they stay in its raw\n // object, which is never rewritten), so it returns here unchanged.\n const bag = widget.options;\n if (!bag) return widget;\n const specs = descriptorFor(widget.type, catalog).options;\n // hasOwnProperty.call, not `in` \u2014 see validateWidgetOptions: every specs table\n // inherits Object.prototype, so `in` would report '__proto__' and 'constructor' as\n // declared and leave exactly the keys a JSON.parse'd definition can smuggle in.\n const keys = Object.keys(bag);\n const kept = keys.filter((key) => Object.prototype.hasOwnProperty.call(specs, key));\n if (kept.length === keys.length) return widget;\n const options: Record<string, unknown> = {};\n for (const key of kept) options[key] = bag[key];\n return { ...widget, options };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["UNKNOWN_WIDGET_TYPE", "useCallback", "useEffect", "useMemo", "useRef", "useState", "useWidgetScale", "useWidgetTimeRange", "useCallback", "useEffect", "useMemo", "useState", "defineWidget", "chunk", "defineWidget", "defineWidget", "chunk", "defineWidget", "defineWidget", "chunk", "defineWidget", "defineWidget", "chunk", "defineWidget", "defineWidget", "chunk", "defineWidget", "defineWidget", "defineWidget", "defineWidget", "optString", "WidgetFrame", "jsx", "optString", "WidgetFrame", "defineWidget", "css", "defineWidget", "fontVar", "optNumber", "optString", "WidgetFrame", "jsx", "optString", "optNumber", "fontVar", "WidgetFrame", "css", "defineWidget", "useMemo", "css", "defineWidget", "fontVar", "formatValue", "optBoolean", "optNumber", "optString", "optThresholds", "pickSample", "primaryMeasurementName", "spaceVar", "useFlashOnChange", "WidgetFrame", "jsx", "jsxs", "primaryMeasurementName", "pickSample", "optString", "optNumber", "formatValue", "useMemo", "optThresholds", "css", "useFlashOnChange", "optBoolean", "WidgetFrame", "spaceVar", "fontVar", "defineWidget", "defineWidget", "loadChartEngine", "chunk", "defineWidget", "loadChartEngine", "useEffect", "useState", "css", "fontVar", "defineWidget", "optString", "WidgetFrame", "jsx", "jsxs", "optString", "WidgetFrame", "css", "fontVar", "useState", "useEffect", "defineWidget", "defineWidget", "chunk", "defineWidget", "useMemo", "css", "defineWidget", "fontVar", "formatTimestamp", "optNumber", "optString", "optThresholds", "pickSample", "primaryMeasurementName", "spaceVar", "useWidgetScale", "useWidgetTimeZone", "WidgetFrame", "EChart", "loadChartEngine", "useChartTheme", "jsx", "jsxs", "optNumber", "optString", "WidgetFrame", "useChartTheme", "useWidgetScale", "useMemo", "optThresholds", "primaryMeasurementName", "pickSample", "EChart", "useWidgetTimeZone", "formatTimestamp", "spaceVar", "fontVar", "css", "loadChartEngine", "defineWidget", "css", "fontVar", "optString", "spaceVar", "viewerLocale", "useWidgetSelect", "WidgetFrame", "useState", "WidgetFrame", "jsx", "jsxs", "WidgetFrame", "useState", "jsx", "jsxs", "optString", "useWidgetTimeRange", "viewerLocale", "spaceVar", "fontVar", "css", "useState", "useEffect", "useCallback", "useMemo", "useWidgetSelect", "Component", "WidgetFrame", "useWidgetScale", "WidgetCandidatesProvider", "WidgetSelectProvider", "Fragment", "jsx", "jsxs", "useMemo", "useCallback", "UNKNOWN_WIDGET_TYPE", "WidgetSelectProvider", "WidgetCandidatesProvider", "useRef", "useState", "useEffect", "DEFAULT_TIME_RANGE_SECONDS", "initialTimeRange", "isValidSpanSeconds", "spanLabel", "useCallback", "useEffect", "useMemo", "useRef", "useState", "Fragment", "jsx", "jsxs", "useCallback", "useEffect", "useRef", "useState", "css", "fontVar", "jsx", "jsxs", "button", "createWidgetCatalog", "createWidgetRegistry", "builtinWidgetDescriptors", "createWidgetCatalog", "builtinWidgetCatalog", "builtinWidgetDefinitions", "createBuiltinWidgetRegistry", "createWidgetRegistry", "pickSample", "optBoolean", "WIDGET_OPTIONS", "UNKNOWN_WIDGET_TYPE", "validateOptions", "UNKNOWN_WIDGET_TYPE", "validateOptions", "WidgetFrame", "WidgetSubjectProvider", "WidgetSelectProvider", "useWidgetSelect", "WidgetTimeZoneProvider", "useWidgetTimeZone", "WidgetThemeRootProvider", "WidgetCandidatesProvider", "useWidgetCandidates", "useFlashOnChange", "flashTextStyle", "flashBackgroundStyle", "fitValueFont", "useMeasurementStream", "useAlarmStream", "useCommandStream", "useLocationStream", "useDatasourceAvailability", "css", "EChart", "buildLineOption", "buildGaugeOption", "useChartTheme"]
|
|
7
7
|
}
|