@camstack/types 1.2.409 → 1.2.411

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/index.js CHANGED
@@ -43297,6 +43297,674 @@ function getAudioMacroClassIds() {
43297
43297
  return AUDIO_MACRO_LABELS.map((l) => l.id);
43298
43298
  }
43299
43299
  //#endregion
43300
+ //#region src/catalogs/palette-entries.ts
43301
+ /**
43302
+ * Palette entry ids (D939). Audio is the one gradient; `audio-*` leaves are
43303
+ * not entries. `heatmapScrub` is a mark, not an event kind.
43304
+ */
43305
+ var PALETTE_ENTRY_IDS = [
43306
+ "motion",
43307
+ "audio",
43308
+ "recording",
43309
+ "live",
43310
+ "heatmapScrub",
43311
+ "person",
43312
+ "vehicle",
43313
+ "animal",
43314
+ "package",
43315
+ "sensor",
43316
+ "control",
43317
+ "face",
43318
+ "plate",
43319
+ "car",
43320
+ "truck",
43321
+ "bus",
43322
+ "motorcycle",
43323
+ "bicycle",
43324
+ "airplane",
43325
+ "boat",
43326
+ "train",
43327
+ "bird",
43328
+ "dog",
43329
+ "cat",
43330
+ "horse",
43331
+ "sheep",
43332
+ "cow",
43333
+ "elephant",
43334
+ "bear",
43335
+ "zebra",
43336
+ "giraffe",
43337
+ "package-delivered",
43338
+ "package-picked-up",
43339
+ "suitcase",
43340
+ "backpack",
43341
+ "handbag",
43342
+ "contact",
43343
+ "motion-sensor",
43344
+ "smoke",
43345
+ "flood",
43346
+ "gas",
43347
+ "carbon-monoxide",
43348
+ "vibration",
43349
+ "tamper",
43350
+ "presence",
43351
+ "enum-sensor",
43352
+ "device-event",
43353
+ "lock",
43354
+ "cover",
43355
+ "switch",
43356
+ "siren",
43357
+ "button",
43358
+ "doorbell"
43359
+ ];
43360
+ var AUDIO_ENTRY_ID = "audio";
43361
+ /** Six rungs, quiet → loud. The opaque end is the entry's hex. */
43362
+ var AUDIO_GRADIENT_ALPHAS = [
43363
+ .3,
43364
+ .42,
43365
+ .55,
43366
+ .7,
43367
+ .85,
43368
+ 1
43369
+ ];
43370
+ var PALETTE_PRESET_IDS = [
43371
+ "camstack",
43372
+ "high-contrast",
43373
+ "okabe-ito"
43374
+ ];
43375
+ function isPaletteEntryId(id) {
43376
+ return PALETTE_ENTRY_IDS.includes(id);
43377
+ }
43378
+ function isPalettePresetId(id) {
43379
+ return PALETTE_PRESET_IDS.includes(id);
43380
+ }
43381
+ //#endregion
43382
+ //#region src/catalogs/palette-cie.ts
43383
+ /**
43384
+ * CIEDE2000 and WCAG contrast for the display palette (D939).
43385
+ *
43386
+ * One implementation, shared by the hub validator, the admin editor and
43387
+ * (phase 2) the viewer. The arithmetic matches the viewer's `src/theme/cie.ts`.
43388
+ */
43389
+ /** Page backgrounds the contrast rule is measured against. */
43390
+ var PALETTE_BACKGROUNDS = {
43391
+ dark: "#0c0a09",
43392
+ light: "#fafaf9"
43393
+ };
43394
+ /** Two entries closer than this read as one mark. */
43395
+ var PALETTE_MIN_DELTA_E = 7;
43396
+ /**
43397
+ * The live cursor and the heatmap handle sit next to each other as small
43398
+ * swatches. ΔE 7 still lets two olives read as one (the old CamStack pair
43399
+ * was 12.8 on the same hue). The global floor stays 7 — the presets' closest
43400
+ * pairs are 7.30, 7.49 and 7.01 — and these two marks must clear 20.
43401
+ */
43402
+ var PALETTE_MIN_DELTA_E_MARK = 20;
43403
+ /** Marks that are not event kinds and share the raised distance floor. */
43404
+ var PALETTE_MARK_PAIR = ["live", "heatmapScrub"];
43405
+ /** Minimum WCAG contrast of an entry against either theme background. */
43406
+ var PALETTE_MIN_CONTRAST = 3;
43407
+ var HEX = /^#[0-9a-fA-F]{6}$/;
43408
+ function srgbChannel(hex, start) {
43409
+ return Number.parseInt(hex.slice(start, start + 2), 16);
43410
+ }
43411
+ function srgbToLin(channel) {
43412
+ const x = channel / 255;
43413
+ return x <= .04045 ? x / 12.92 : ((x + .055) / 1.055) ** 2.4;
43414
+ }
43415
+ function relativeLuminance(hex) {
43416
+ const r = srgbToLin(srgbChannel(hex, 1));
43417
+ const g = srgbToLin(srgbChannel(hex, 3));
43418
+ const b = srgbToLin(srgbChannel(hex, 5));
43419
+ return .2126 * r + .7152 * g + .0722 * b;
43420
+ }
43421
+ /** WCAG contrast ratio of two `#rrggbb` colours. Non-hex returns 0. */
43422
+ function contrastRatio(a, b) {
43423
+ if (!HEX.test(a) || !HEX.test(b)) return 0;
43424
+ const hi = Math.max(relativeLuminance(a), relativeLuminance(b));
43425
+ const lo = Math.min(relativeLuminance(a), relativeLuminance(b));
43426
+ return (hi + .05) / (lo + .05);
43427
+ }
43428
+ function xyzToLab(hex) {
43429
+ const r = srgbToLin(srgbChannel(hex, 1));
43430
+ const g = srgbToLin(srgbChannel(hex, 3));
43431
+ const bl = srgbToLin(srgbChannel(hex, 5));
43432
+ const x = .4124564 * r + .3575761 * g + .1804375 * bl;
43433
+ const y = .2126729 * r + .7151522 * g + .072175 * bl;
43434
+ const z = .0193339 * r + .119192 * g + .9503041 * bl;
43435
+ const f = (t) => t > .008856 ? Math.cbrt(t) : 7.787 * t + 16 / 116;
43436
+ const fx = f(x / .95047);
43437
+ const fy = f(y);
43438
+ const fz = f(z / 1.08883);
43439
+ return {
43440
+ L: 116 * fy - 16,
43441
+ a: 500 * (fx - fy),
43442
+ b: 200 * (fy - fz)
43443
+ };
43444
+ }
43445
+ function hueDeg(ap, b) {
43446
+ if (ap === 0 && b === 0) return 0;
43447
+ const ang = Math.atan2(b, ap) * 180 / Math.PI;
43448
+ return ang < 0 ? ang + 360 : ang;
43449
+ }
43450
+ /** CIEDE2000. Non-hex returns 0 so a bad swatch fails the distinctness rule. */
43451
+ function deltaE00(hex1, hex2) {
43452
+ if (!HEX.test(hex1) || !HEX.test(hex2)) return 0;
43453
+ const lab1 = xyzToLab(hex1);
43454
+ const lab2 = xyzToLab(hex2);
43455
+ const cab7 = ((Math.hypot(lab1.a, lab1.b) + Math.hypot(lab2.a, lab2.b)) / 2) ** 7;
43456
+ const g = .5 * (1 - Math.sqrt(cab7 / (cab7 + 25 ** 7)));
43457
+ const a1p = (1 + g) * lab1.a;
43458
+ const a2p = (1 + g) * lab2.a;
43459
+ const c1p = Math.hypot(a1p, lab1.b);
43460
+ const c2p = Math.hypot(a2p, lab2.b);
43461
+ const h1p = hueDeg(a1p, lab1.b);
43462
+ const h2p = hueDeg(a2p, lab2.b);
43463
+ let dhp = 0;
43464
+ if (c1p * c2p !== 0) {
43465
+ dhp = h2p - h1p;
43466
+ if (dhp > 180) dhp -= 360;
43467
+ else if (dhp < -180) dhp += 360;
43468
+ }
43469
+ const dHp = 2 * Math.sqrt(c1p * c2p) * Math.sin(dhp * Math.PI / 360);
43470
+ const lbp = (lab1.L + lab2.L) / 2;
43471
+ const cbp = (c1p + c2p) / 2;
43472
+ let hbp = h1p + h2p;
43473
+ if (c1p * c2p !== 0) {
43474
+ if (Math.abs(h1p - h2p) > 180) hbp += hbp < 360 ? 360 : -360;
43475
+ hbp /= 2;
43476
+ }
43477
+ const t = 1 - .17 * Math.cos((hbp - 30) * Math.PI / 180) + .24 * Math.cos(2 * hbp * Math.PI / 180) + .32 * Math.cos((3 * hbp + 6) * Math.PI / 180) - .2 * Math.cos((4 * hbp - 63) * Math.PI / 180);
43478
+ const dTheta = 30 * Math.exp(-(((hbp - 275) / 25) ** 2));
43479
+ const cbp7 = cbp ** 7;
43480
+ const rc = 2 * Math.sqrt(cbp7 / (cbp7 + 25 ** 7));
43481
+ const sl = 1 + .015 * (lbp - 50) ** 2 / Math.sqrt(20 + (lbp - 50) ** 2);
43482
+ const sc = 1 + .045 * cbp;
43483
+ const sh = 1 + .015 * cbp * t;
43484
+ const rt = -Math.sin(2 * dTheta * Math.PI / 180) * rc;
43485
+ const dLp = lab2.L - lab1.L;
43486
+ const dCp = c2p - c1p;
43487
+ return Math.sqrt((dLp / sl) ** 2 + (dCp / sc) ** 2 + (dHp / sh) ** 2 + rt * (dCp / sc) * (dHp / sh));
43488
+ }
43489
+ //#endregion
43490
+ //#region src/catalogs/display-palette-tables.ts
43491
+ /** Frozen palette tables (D939). The spec refuses a table that breaks the rule. */
43492
+ var CAMSTACK_HEX = {
43493
+ motion: "#d946ef",
43494
+ audio: "#059eb8",
43495
+ recording: "#ef4444",
43496
+ live: "#8d7a00",
43497
+ heatmapScrub: "#4b32ff",
43498
+ person: "#11a64c",
43499
+ vehicle: "#3b82f6",
43500
+ animal: "#ea6a09",
43501
+ package: "#924667",
43502
+ sensor: "#624bbc",
43503
+ control: "#944d24",
43504
+ face: "#ed4f8d",
43505
+ plate: "#4b7027",
43506
+ car: "#9684cf",
43507
+ truck: "#0f9b89",
43508
+ bus: "#a734a9",
43509
+ motorcycle: "#c1133a",
43510
+ bicycle: "#0e6a9b",
43511
+ airplane: "#7c9928",
43512
+ boat: "#b17933",
43513
+ train: "#ad6ca3",
43514
+ bird: "#0f7c55",
43515
+ dog: "#c82700",
43516
+ cat: "#7268f2",
43517
+ horse: "#cb795e",
43518
+ sheep: "#b8636b",
43519
+ cow: "#cb2969",
43520
+ elephant: "#1158d2",
43521
+ bear: "#8d5e00",
43522
+ zebra: "#0097d6",
43523
+ giraffe: "#8f61bb",
43524
+ "package-delivered": "#cd3f9b",
43525
+ "package-picked-up": "#388a08",
43526
+ suitcase: "#666800",
43527
+ backpack: "#ec5022",
43528
+ handbag: "#a76ef8",
43529
+ contact: "#ab5a49",
43530
+ "motion-sensor": "#b95d1a",
43531
+ smoke: "#dd3858",
43532
+ flood: "#b31e7d",
43533
+ gas: "#5b70b5",
43534
+ "carbon-monoxide": "#7b4e8e",
43535
+ vibration: "#e65bba",
43536
+ tamper: "#98464b",
43537
+ presence: "#3a9468",
43538
+ "enum-sensor": "#7885f8",
43539
+ "device-event": "#8c43c8",
43540
+ lock: "#649653",
43541
+ cover: "#c67597",
43542
+ switch: "#7a812a",
43543
+ siren: "#ac5d7f",
43544
+ button: "#b276cd",
43545
+ doorbell: "#0087ab"
43546
+ };
43547
+ var CAMSTACK_FALLBACK = [
43548
+ "#b34dc7",
43549
+ "#1d7d34",
43550
+ "#db6b6c",
43551
+ "#a43d29",
43552
+ "#0e6ee6",
43553
+ "#29a10b",
43554
+ "#a98731",
43555
+ "#0181c6"
43556
+ ];
43557
+ var HIGH_CONTRAST_HEX = {
43558
+ motion: "#964360",
43559
+ audio: "#23a132",
43560
+ recording: "#2494ca",
43561
+ live: "#bd7e2b",
43562
+ heatmapScrub: "#ad6eea",
43563
+ person: "#62611e",
43564
+ vehicle: "#f4534c",
43565
+ animal: "#1556cd",
43566
+ package: "#9c4415",
43567
+ sensor: "#066c48",
43568
+ control: "#f2479f",
43569
+ face: "#139d8a",
43570
+ plate: "#909024",
43571
+ car: "#8e35ab",
43572
+ truck: "#bd0b2b",
43573
+ bus: "#7a88ca",
43574
+ motorcycle: "#e26725",
43575
+ bicycle: "#a6679b",
43576
+ airplane: "#7c5720",
43577
+ boat: "#467a1b",
43578
+ train: "#6f65a4",
43579
+ bird: "#cb717f",
43580
+ dog: "#c62490",
43581
+ cat: "#b36850",
43582
+ horse: "#1872ac",
43583
+ sheep: "#927939",
43584
+ cow: "#428a5c",
43585
+ elephant: "#d41160",
43586
+ bear: "#799453",
43587
+ zebra: "#a85455",
43588
+ giraffe: "#746be8",
43589
+ "package-delivered": "#824a80",
43590
+ "package-picked-up": "#614ac1",
43591
+ suitcase: "#2f77f3",
43592
+ backpack: "#fa476d",
43593
+ handbag: "#c14cbe",
43594
+ contact: "#c83921",
43595
+ "motion-sensor": "#a07ebd",
43596
+ smoke: "#a25b13",
43597
+ flood: "#526bab",
43598
+ gas: "#924938",
43599
+ "carbon-monoxide": "#bb7e53",
43600
+ vibration: "#b66182",
43601
+ tamper: "#3c6931",
43602
+ presence: "#6c851d",
43603
+ "enum-sensor": "#ad2d48",
43604
+ "device-event": "#5e9b04",
43605
+ lock: "#00a062",
43606
+ cover: "#ad8624",
43607
+ switch: "#d05259",
43608
+ siren: "#cd67b3",
43609
+ button: "#c9746a",
43610
+ doorbell: "#338eeb"
43611
+ };
43612
+ var HIGH_CONTRAST_FALLBACK = [
43613
+ "#817f3b",
43614
+ "#a0733e",
43615
+ "#8658b2",
43616
+ "#956301",
43617
+ "#bc652d",
43618
+ "#647331",
43619
+ "#a14c9e",
43620
+ "#d14e71"
43621
+ ];
43622
+ var OKABE_ITO_HEX = {
43623
+ motion: "#b88128",
43624
+ audio: "#1096c8",
43625
+ recording: "#009e73",
43626
+ live: "#9c8c22",
43627
+ heatmapScrub: "#0072b2",
43628
+ person: "#d55e00",
43629
+ vehicle: "#c0739f",
43630
+ animal: "#226d18",
43631
+ package: "#91446c",
43632
+ sensor: "#217b56",
43633
+ control: "#648647",
43634
+ face: "#c22998",
43635
+ plate: "#fa4575",
43636
+ car: "#956301",
43637
+ truck: "#2f77f3",
43638
+ bus: "#7a4e86",
43639
+ motorcycle: "#f54597",
43640
+ bicycle: "#bb3e75",
43641
+ airplane: "#e054c0",
43642
+ boat: "#457942",
43643
+ train: "#867afa",
43644
+ bird: "#88914c",
43645
+ dog: "#1556cd",
43646
+ cat: "#71702c",
43647
+ horse: "#9b4fa4",
43648
+ sheep: "#c0559d",
43649
+ cow: "#d14f65",
43650
+ elephant: "#98470f",
43651
+ bear: "#595896",
43652
+ zebra: "#96790e",
43653
+ giraffe: "#cb717b",
43654
+ "package-delivered": "#139d8a",
43655
+ "package-picked-up": "#906ead",
43656
+ suitcase: "#d02939",
43657
+ backpack: "#d41160",
43658
+ handbag: "#f64f54",
43659
+ contact: "#7258d2",
43660
+ "motion-sensor": "#b66182",
43661
+ smoke: "#627abb",
43662
+ flood: "#b86ae4",
43663
+ gas: "#a95261",
43664
+ "carbon-monoxide": "#c65d3c",
43665
+ vibration: "#7a40b7",
43666
+ tamper: "#914b34",
43667
+ presence: "#9481c3",
43668
+ "enum-sensor": "#ac6d47",
43669
+ "device-event": "#7b6fce",
43670
+ lock: "#c67662",
43671
+ cover: "#a6564d",
43672
+ switch: "#ad2c4e",
43673
+ siren: "#348e08",
43674
+ button: "#d27303",
43675
+ doorbell: "#55770f"
43676
+ };
43677
+ var OKABE_ITO_FALLBACK = [
43678
+ "#9a3784",
43679
+ "#a7392c",
43680
+ "#409d50",
43681
+ "#6987e7",
43682
+ "#ee5b3d",
43683
+ "#c0430d",
43684
+ "#af79b3",
43685
+ "#4b6628"
43686
+ ];
43687
+ //#endregion
43688
+ //#region src/catalogs/display-palette.ts
43689
+ /**
43690
+ * The display palette (D939). One table of colours, three presets, one
43691
+ * validator. Taxonomy colours and every consumer read this — there is no
43692
+ * second hex table.
43693
+ */
43694
+ var paletteHexSchema = zod.z.string().regex(/^#[0-9a-f]{6}$/);
43695
+ var paletteSolidSchema = zod.z.object({
43696
+ form: zod.z.literal("solid"),
43697
+ hex: paletteHexSchema
43698
+ });
43699
+ var paletteGradientSchema = zod.z.object({
43700
+ form: zod.z.literal("gradient"),
43701
+ hex: paletteHexSchema,
43702
+ alphas: zod.z.array(zod.z.number().gt(0).lte(1)).length(AUDIO_GRADIENT_ALPHAS.length)
43703
+ });
43704
+ var paletteSwatchSchema = zod.z.discriminatedUnion("form", [paletteSolidSchema, paletteGradientSchema]);
43705
+ var paletteReadySchema = zod.z.object({
43706
+ status: zod.z.literal("ready"),
43707
+ presetId: zod.z.enum(PALETTE_PRESET_IDS),
43708
+ customized: zod.z.boolean(),
43709
+ source: zod.z.enum(["stored", "unconfigured"]),
43710
+ swatches: zod.z.record(zod.z.string(), paletteSwatchSchema),
43711
+ fallbacks: zod.z.array(paletteHexSchema).length(8)
43712
+ });
43713
+ var paletteUnknownSchema = zod.z.object({
43714
+ status: zod.z.literal("unknown"),
43715
+ reason: zod.z.string()
43716
+ });
43717
+ var paletteResultSchema = zod.z.discriminatedUnion("status", [paletteReadySchema, paletteUnknownSchema]);
43718
+ var setPaletteInputSchema = zod.z.union([zod.z.object({ presetId: zod.z.string() }), zod.z.object({
43719
+ presetId: zod.z.string(),
43720
+ overrides: zod.z.record(zod.z.string(), paletteSwatchSchema)
43721
+ })]);
43722
+ var storedPaletteSchema = zod.z.object({
43723
+ presetId: zod.z.string(),
43724
+ overrides: zod.z.record(zod.z.string(), paletteSwatchSchema)
43725
+ });
43726
+ function solid(hex) {
43727
+ return {
43728
+ form: "solid",
43729
+ hex
43730
+ };
43731
+ }
43732
+ function audioGradient(hex) {
43733
+ return {
43734
+ form: "gradient",
43735
+ hex,
43736
+ alphas: [...AUDIO_GRADIENT_ALPHAS]
43737
+ };
43738
+ }
43739
+ function swatchesFrom(hexes) {
43740
+ const out = {};
43741
+ for (const id of PALETTE_ENTRY_IDS) {
43742
+ const hex = hexes[id];
43743
+ if (hex === void 0) throw new Error(`palette table missing ${id}`);
43744
+ out[id] = id === "audio" ? audioGradient(hex) : solid(hex);
43745
+ }
43746
+ return out;
43747
+ }
43748
+ function preset(id, name, hexes, fallbacks) {
43749
+ return {
43750
+ id,
43751
+ name,
43752
+ swatches: swatchesFrom(hexes),
43753
+ fallbacks
43754
+ };
43755
+ }
43756
+ var DISPLAY_PRESETS = [
43757
+ preset("camstack", "CamStack", CAMSTACK_HEX, CAMSTACK_FALLBACK),
43758
+ preset("high-contrast", "High contrast", HIGH_CONTRAST_HEX, HIGH_CONTRAST_FALLBACK),
43759
+ preset("okabe-ito", "Colour-blind safe", OKABE_ITO_HEX, OKABE_ITO_FALLBACK)
43760
+ ];
43761
+ function presetById(id) {
43762
+ return DISPLAY_PRESETS.find((item) => item.id === id);
43763
+ }
43764
+ function bundledCamstack() {
43765
+ const presetRow = presetById("camstack");
43766
+ if (presetRow === void 0) throw new Error("CamStack preset missing");
43767
+ return readyOf(presetRow, "unconfigured", false);
43768
+ }
43769
+ function readyOf(row, source, customized) {
43770
+ return {
43771
+ status: "ready",
43772
+ presetId: row.id,
43773
+ customized,
43774
+ source,
43775
+ swatches: row.swatches,
43776
+ fallbacks: [...row.fallbacks]
43777
+ };
43778
+ }
43779
+ function swatchHex(swatch) {
43780
+ return swatch.hex;
43781
+ }
43782
+ function namedColours(swatches, fallbacks) {
43783
+ const rows = [];
43784
+ for (const id of PALETTE_ENTRY_IDS) {
43785
+ const swatch = swatches[id];
43786
+ if (swatch !== void 0) rows.push({
43787
+ name: id,
43788
+ hex: swatch.hex
43789
+ });
43790
+ }
43791
+ fallbacks.forEach((hex, index) => {
43792
+ rows.push({
43793
+ name: `fallback-${index}`,
43794
+ hex
43795
+ });
43796
+ });
43797
+ return rows;
43798
+ }
43799
+ function gradientViolations(swatches) {
43800
+ const audio = swatches[AUDIO_ENTRY_ID];
43801
+ if (audio === void 0) return [];
43802
+ if (audio.form !== "gradient") return [{
43803
+ code: "bad-gradient",
43804
+ entry: AUDIO_ENTRY_ID
43805
+ }];
43806
+ return AUDIO_GRADIENT_ALPHAS.every((alpha, index) => audio.alphas[index] === alpha) ? [] : [{
43807
+ code: "bad-gradient",
43808
+ entry: AUDIO_ENTRY_ID
43809
+ }];
43810
+ }
43811
+ function isMarkPair(left, right) {
43812
+ const marks = PALETTE_MARK_PAIR;
43813
+ return marks.includes(left) && marks.includes(right);
43814
+ }
43815
+ /** Refuse a palette whose entries are not pairwise distinct on both themes. */
43816
+ function validatePalette(swatches, fallbacks) {
43817
+ const violations = [];
43818
+ for (const id of PALETTE_ENTRY_IDS) if (swatches[id] === void 0) violations.push({
43819
+ code: "missing-entry",
43820
+ entry: id
43821
+ });
43822
+ for (const key of Object.keys(swatches)) if (!isPaletteEntryId(key)) violations.push({
43823
+ code: "unknown-entry",
43824
+ entry: key
43825
+ });
43826
+ if (fallbacks.length !== 8) violations.push({ code: "bad-fallbacks" });
43827
+ violations.push(...gradientViolations(swatches));
43828
+ const rows = namedColours(swatches, fallbacks);
43829
+ for (let i = 0; i < rows.length; i++) for (let j = i + 1; j < rows.length; j++) {
43830
+ const left = rows[i];
43831
+ const right = rows[j];
43832
+ if (left === void 0 || right === void 0) continue;
43833
+ const deltaE = deltaE00(left.hex, right.hex);
43834
+ if (deltaE < (isMarkPair(left.name, right.name) ? 20 : 7)) violations.push({
43835
+ code: "too-close",
43836
+ left: left.name,
43837
+ right: right.name,
43838
+ deltaE
43839
+ });
43840
+ }
43841
+ for (const row of rows) for (const background of ["dark", "light"]) {
43842
+ const contrast = contrastRatio(row.hex, PALETTE_BACKGROUNDS[background]);
43843
+ if (contrast < 3) violations.push({
43844
+ code: "low-contrast",
43845
+ entry: row.name,
43846
+ background,
43847
+ contrast
43848
+ });
43849
+ }
43850
+ return violations.length === 0 ? { ok: true } : {
43851
+ ok: false,
43852
+ violations
43853
+ };
43854
+ }
43855
+ function formatPaletteViolation(violation) {
43856
+ switch (violation.code) {
43857
+ case "too-close": return `${violation.left} vs ${violation.right} (ΔE ${violation.deltaE.toFixed(1)})`;
43858
+ case "low-contrast": return `${violation.entry} on ${violation.background} (${violation.contrast.toFixed(1)}:1)`;
43859
+ case "missing-entry": return `${violation.entry} is missing`;
43860
+ case "unknown-entry": return `${violation.entry} is not a palette entry`;
43861
+ case "bad-gradient": return `${violation.entry} gradient is not the six canonical steps`;
43862
+ case "bad-fallbacks": return "fallback list must hold eight colours";
43863
+ case "unknown-preset": return `${violation.presetId} is not a preset`;
43864
+ }
43865
+ }
43866
+ function formatPaletteViolations(violations) {
43867
+ return violations.map(formatPaletteViolation).join("; ");
43868
+ }
43869
+ var PaletteRejectedError = class extends Error {
43870
+ violations;
43871
+ constructor(violations) {
43872
+ super(formatPaletteViolations(violations));
43873
+ this.name = "PaletteRejectedError";
43874
+ this.violations = violations;
43875
+ }
43876
+ };
43877
+ function hashFallback(kind, fallbacks) {
43878
+ let hash = 0;
43879
+ for (let i = 0; i < kind.length; i++) hash = hash * 31 + (kind.codePointAt(i) ?? 0) >>> 0;
43880
+ const hex = fallbacks[hash % fallbacks.length];
43881
+ if (hex === void 0) throw new Error("display palette has no fallback colour");
43882
+ return hex;
43883
+ }
43884
+ /** Colour a kind paints with. Audio leaves share the audio gradient's hex. */
43885
+ function paintHex(swatches, fallbacks, kind) {
43886
+ const key = kind.trim().toLowerCase();
43887
+ if (key.startsWith("audio-")) {
43888
+ const audio = swatches[AUDIO_ENTRY_ID];
43889
+ return audio !== void 0 ? audio.hex : hashFallback(key, fallbacks);
43890
+ }
43891
+ const direct = swatches[key];
43892
+ if (direct !== void 0) return direct.hex;
43893
+ return hashFallback(key, fallbacks);
43894
+ }
43895
+ function mergeOverrides(base, overrides) {
43896
+ return {
43897
+ ...base,
43898
+ ...overrides
43899
+ };
43900
+ }
43901
+ function overridesOf(input) {
43902
+ return "overrides" in input ? input.overrides : {};
43903
+ }
43904
+ /** The palette a `setPalette` input would store. Invalid input is a refusal. */
43905
+ function paletteFromInput(input) {
43906
+ const row = presetById(input.presetId);
43907
+ if (row === void 0 || !isPalettePresetId(input.presetId)) throw new PaletteRejectedError([{
43908
+ code: "unknown-preset",
43909
+ presetId: input.presetId
43910
+ }]);
43911
+ const overrides = overridesOf(input);
43912
+ const swatches = mergeOverrides(row.swatches, overrides);
43913
+ const verdict = validatePalette(swatches, row.fallbacks);
43914
+ if (!verdict.ok) throw new PaletteRejectedError(verdict.violations);
43915
+ const customized = Object.keys(overrides).length > 0;
43916
+ return {
43917
+ status: "ready",
43918
+ presetId: row.id,
43919
+ customized,
43920
+ source: "stored",
43921
+ swatches,
43922
+ fallbacks: [...row.fallbacks]
43923
+ };
43924
+ }
43925
+ function isEmptyRecord(value) {
43926
+ return typeof value === "object" && value !== null && !Array.isArray(value) && Object.keys(value).length === 0;
43927
+ }
43928
+ /**
43929
+ * Interpret a settings blob. A missing row is the bundled preset and says so.
43930
+ * A blob that does not parse, names an unknown preset, or fails the rule is
43931
+ * `unknown` — never the default wearing the stored preset's name.
43932
+ */
43933
+ function paletteFromStored(value) {
43934
+ if (value === void 0 || value === null || isEmptyRecord(value)) return bundledCamstack();
43935
+ const parsed = storedPaletteSchema.safeParse(value);
43936
+ if (!parsed.success) return {
43937
+ status: "unknown",
43938
+ reason: "stored palette is unreadable"
43939
+ };
43940
+ const row = presetById(parsed.data.presetId);
43941
+ if (row === void 0) return {
43942
+ status: "unknown",
43943
+ reason: `unknown preset ${parsed.data.presetId}`
43944
+ };
43945
+ const swatches = mergeOverrides(row.swatches, parsed.data.overrides);
43946
+ const verdict = validatePalette(swatches, row.fallbacks);
43947
+ if (!verdict.ok) return {
43948
+ status: "unknown",
43949
+ reason: formatPaletteViolations(verdict.violations)
43950
+ };
43951
+ const customized = Object.keys(parsed.data.overrides).length > 0;
43952
+ return {
43953
+ status: "ready",
43954
+ presetId: row.id,
43955
+ customized,
43956
+ source: "stored",
43957
+ swatches,
43958
+ fallbacks: [...row.fallbacks]
43959
+ };
43960
+ }
43961
+ function storedFromReady(ready, overrides) {
43962
+ return {
43963
+ presetId: ready.presetId,
43964
+ overrides: { ...overrides }
43965
+ };
43966
+ }
43967
+ //#endregion
43300
43968
  //#region src/catalogs/event-taxonomy.ts
43301
43969
  /**
43302
43970
  * Unified event-kind taxonomy — THE single source of truth for
@@ -43312,111 +43980,89 @@ function getAudioMacroClassIds() {
43312
43980
  * - `addon-post-analysis/shared/frame/box-drawer.ts` (DEFAULT_COLOR)
43313
43981
  * - the COCO / audio class maps (macro ↔ sub relationships)
43314
43982
  *
43315
- * The DATA (serializable — color/iconId/labelKey/parentKind) lives here in
43316
- * `@camstack/types`. The UI-side mapping `iconId → lucide component` and
43317
- * `labelKey → t()` lives in `@camstack/ui-library`. UIs never hardcode a
43318
- * color or an icon: they read this dictionary (server descriptors carry the
43319
- * fields inline; the client resolves color/icon/label from `iconId`/`kind`).
43983
+ * The DATA (serializable — parentKind / iconId / labelKey) lives here in
43984
+ * `@camstack/types`. Colour is NOT a second table: each entry's `color` is
43985
+ * the bundled CamStack display palette (D939). The effective cluster palette
43986
+ * is the `display-palette` capability. The UI-side mapping `iconId → lucide
43987
+ * component` and `labelKey → t()` lives in `@camstack/ui-library`.
43320
43988
  *
43321
43989
  * Two levels only (v1 YAGNI): macro → sub. `person` is a leaf macro.
43322
43990
  */
43323
- var TAXONOMY_COLORS = {
43324
- motion: "#f59e0b",
43325
- audio: "#06b6d4",
43326
- person: "#22c55e",
43327
- vehicle: "#3b82f6",
43328
- animal: "#f97316",
43329
- package: "#a855f7",
43330
- sensor: "#8b5cf6",
43331
- control: "#10b981",
43332
- genericDetection: "#64748b"
43333
- };
43334
- /** Global default color when a kind is unknown (matches legacy box-drawer). */
43335
- var DEFAULT_EVENT_COLOR = "#22ff55";
43336
- var DETECTION_SUB_COLORS = {
43337
- car: "#f59e0b",
43338
- truck: "#d97706",
43339
- bus: "#b45309",
43340
- motorcycle: "#eab308",
43341
- bicycle: "#ca8a04",
43342
- airplane: "#60a5fa",
43343
- boat: "#2563eb",
43344
- train: "#1d4ed8",
43345
- bird: "#14b8a6",
43346
- dog: "#84cc16",
43347
- cat: "#f97316",
43348
- horse: "#a16207",
43349
- sheep: "#a3a3a3",
43350
- cow: "#78716c",
43351
- elephant: "#6b7280",
43352
- bear: "#7c2d12",
43353
- zebra: "#404040",
43354
- giraffe: "#d4a373"
43355
- };
43991
+ var BUNDLED_PALETTE = bundledCamstack();
43992
+ function kindColor(kind) {
43993
+ return paintHex(BUNDLED_PALETTE.swatches, BUNDLED_PALETTE.fallbacks, kind);
43994
+ }
43995
+ function firstFallback(fallbacks) {
43996
+ const hex = fallbacks[0];
43997
+ if (hex === void 0) throw new Error("display palette has no fallback colour");
43998
+ return hex;
43999
+ }
44000
+ /** Global default when a kind is unknown — the palette's first fallback. */
44001
+ var DEFAULT_EVENT_COLOR = firstFallback(BUNDLED_PALETTE.fallbacks);
43356
44002
  function titleCase(id) {
43357
44003
  return id.split(/[-_ ]/).filter((p) => p.length > 0).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(" ");
43358
44004
  }
43359
44005
  var entries = /* @__PURE__ */ new Map();
43360
- function macro(kind, category, color, iconId, label) {
44006
+ function macro(kind, category, iconId, label) {
43361
44007
  entries.set(kind, {
43362
44008
  kind,
43363
44009
  parentKind: null,
43364
44010
  level: "macro",
43365
44011
  category,
43366
- color,
44012
+ color: kindColor(kind),
43367
44013
  iconId,
43368
44014
  labelKey: `eventKind.${kind}`,
43369
44015
  label
43370
44016
  });
43371
44017
  }
43372
- function sub(kind, parentKind, category, color, iconId, label) {
44018
+ function sub(kind, parentKind, category, iconId, label) {
43373
44019
  entries.set(kind, {
43374
44020
  kind,
43375
44021
  parentKind,
43376
44022
  level: "sub",
43377
44023
  category,
43378
- color,
44024
+ color: kindColor(kind),
43379
44025
  iconId,
43380
44026
  labelKey: `eventKind.${kind}`,
43381
44027
  label
43382
44028
  });
43383
44029
  }
43384
- macro("motion", "motion", TAXONOMY_COLORS.motion, "motion", "Motion");
43385
- macro("audio", "audio", TAXONOMY_COLORS.audio, "audio", "Audio");
43386
- macro("person", "detection", TAXONOMY_COLORS.person, "person", "Person");
43387
- macro("vehicle", "detection", TAXONOMY_COLORS.vehicle, "vehicle", "Vehicle");
43388
- macro("animal", "detection", TAXONOMY_COLORS.animal, "animal", "Animal");
43389
- macro("package", "package", TAXONOMY_COLORS.package, "package", "Package");
43390
- macro("sensor", "sensor", TAXONOMY_COLORS.sensor, "sensor", "Sensor");
43391
- macro("control", "control", TAXONOMY_COLORS.control, "control", "Control");
44030
+ macro("motion", "motion", "motion", "Motion");
44031
+ macro("audio", "audio", "audio", "Audio");
44032
+ macro("person", "detection", "person", "Person");
44033
+ macro("vehicle", "detection", "vehicle", "Vehicle");
44034
+ macro("animal", "detection", "animal", "Animal");
44035
+ macro("package", "package", "package", "Package");
44036
+ macro("sensor", "sensor", "sensor", "Sensor");
44037
+ macro("control", "control", "control", "Control");
43392
44038
  for (const [cocoClass, macroClass] of Object.entries(COCO_TO_MACRO.mapping)) {
43393
44039
  if (macroClass !== "vehicle" && macroClass !== "animal") continue;
43394
44040
  if (entries.has(cocoClass)) continue;
43395
- sub(cocoClass, macroClass, "detection", DETECTION_SUB_COLORS[cocoClass] ?? TAXONOMY_COLORS.genericDetection, cocoClass, titleCase(cocoClass));
43396
- }
43397
- sub("package-delivered", "package", "package", TAXONOMY_COLORS.package, "package", "Package delivered");
43398
- sub("package-picked-up", "package", "package", TAXONOMY_COLORS.package, "package", "Package picked up");
43399
- sub("contact", "sensor", "sensor", "#f59e0b", "door", "Contact");
43400
- sub("motion-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "pir", "Motion sensor");
43401
- sub("smoke", "sensor", "sensor", "#ef4444", "smoke", "Smoke");
43402
- sub("flood", "sensor", "sensor", "#3b82f6", "water", "Water leak");
43403
- sub("gas", "sensor", "sensor", "#ef4444", "gas", "Gas");
43404
- sub("carbon-monoxide", "sensor", "sensor", "#dc2626", "smoke", "Carbon monoxide");
43405
- sub("vibration", "sensor", "sensor", "#eab308", "vibration", "Vibration");
43406
- sub("tamper", "sensor", "sensor", "#f97316", "tamper", "Tamper");
43407
- sub("presence", "sensor", "sensor", "#22c55e", "presence", "Presence");
43408
- sub("enum-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "generic", "Sensor state");
43409
- sub("device-event", "sensor", "sensor", "#10b981", "button", "Device event");
43410
- sub("lock", "control", "control", "#0ea5e9", "lock", "Lock");
43411
- sub("cover", "control", "control", "#0ea5e9", "door", "Cover");
43412
- sub("switch", "control", "control", TAXONOMY_COLORS.control, "switch", "Switch");
43413
- sub("siren", "control", "control", "#dc2626", "siren", "Siren");
43414
- sub("button", "control", "control", "#10b981", "button", "Button");
43415
- sub("doorbell", "control", "control", "#a855f7", "doorbell", "Doorbell");
44041
+ sub(cocoClass, macroClass, "detection", cocoClass, titleCase(cocoClass));
44042
+ }
44043
+ sub("package-delivered", "package", "package", "package", "Package delivered");
44044
+ sub("package-picked-up", "package", "package", "package", "Package picked up");
44045
+ sub("contact", "sensor", "sensor", "door", "Contact");
44046
+ sub("motion-sensor", "sensor", "sensor", "pir", "Motion sensor");
44047
+ sub("smoke", "sensor", "sensor", "smoke", "Smoke");
44048
+ sub("flood", "sensor", "sensor", "water", "Water leak");
44049
+ sub("gas", "sensor", "sensor", "gas", "Gas");
44050
+ sub("carbon-monoxide", "sensor", "sensor", "smoke", "Carbon monoxide");
44051
+ sub("vibration", "sensor", "sensor", "vibration", "Vibration");
44052
+ sub("tamper", "sensor", "sensor", "tamper", "Tamper");
44053
+ sub("presence", "sensor", "sensor", "presence", "Presence");
44054
+ sub("enum-sensor", "sensor", "sensor", "generic", "Sensor state");
44055
+ sub("device-event", "sensor", "sensor", "button", "Device event");
44056
+ sub("lock", "control", "control", "lock", "Lock");
44057
+ sub("cover", "control", "control", "door", "Cover");
44058
+ sub("switch", "control", "control", "switch", "Switch");
44059
+ sub("siren", "control", "control", "siren", "Siren");
44060
+ sub("button", "control", "control", "button", "Button");
44061
+ sub("doorbell", "control", "control", "doorbell", "Doorbell");
43416
44062
  for (const l of AUDIO_MACRO_LABELS) {
43417
44063
  const kind = `audio-${l.id}`;
43418
44064
  if (entries.has(kind)) continue;
43419
- sub(kind, "audio", "audio", TAXONOMY_COLORS.audio, kind, l.name);
44065
+ sub(kind, "audio", "audio", kind, l.name);
43420
44066
  }
43421
44067
  /** The complete taxonomy dictionary, keyed by kind. */
43422
44068
  var EVENT_TAXONOMY = Object.freeze(Object.fromEntries(entries));
@@ -43424,9 +44070,9 @@ var EVENT_TAXONOMY = Object.freeze(Object.fromEntries(entries));
43424
44070
  function getTaxonomyEntry(kind) {
43425
44071
  return EVENT_TAXONOMY[kind];
43426
44072
  }
43427
- /** Color for a kind — dictionary value, else the global default. */
44073
+ /** Color for a kind — the bundled palette, else a stable fallback. */
43428
44074
  function colorForKind(kind) {
43429
- return EVENT_TAXONOMY[kind]?.color ?? "#22ff55";
44075
+ return kindColor(kind);
43430
44076
  }
43431
44077
  /** The sub kinds whose `parentKind` is `macro` (empty for a leaf macro). */
43432
44078
  function subKindsOf(macro) {
@@ -62296,6 +62942,41 @@ var dayNightCapability = {
62296
62942
  volatileStateFields: ["lastFetchedAt"]
62297
62943
  };
62298
62944
  //#endregion
62945
+ //#region src/capabilities/display-palette.cap.ts
62946
+ /**
62947
+ * display-palette — the cluster's one colour table (D939).
62948
+ *
62949
+ * Hub singleton. `getPalette` reports `unknown` when the settings store
62950
+ * cannot be read; it does not pretend the bundled preset was stored.
62951
+ * `setPalette` refuses a palette that fails the ΔE / contrast rule and names
62952
+ * the pairs.
62953
+ */
62954
+ var presetSummarySchema = zod.z.object({
62955
+ id: zod.z.string(),
62956
+ name: zod.z.string(),
62957
+ swatches: zod.z.record(zod.z.string(), paletteSwatchSchema),
62958
+ fallbacks: zod.z.array(zod.z.string())
62959
+ });
62960
+ var displayPaletteCapability = {
62961
+ name: "display-palette",
62962
+ scope: "system",
62963
+ mode: "singleton",
62964
+ methods: {
62965
+ getPalette: require_sleep.method(zod.z.void(), paletteResultSchema, {
62966
+ auth: "protected",
62967
+ role: "viewer"
62968
+ }),
62969
+ listPresets: require_sleep.method(zod.z.void(), zod.z.array(presetSummarySchema).readonly(), {
62970
+ auth: "protected",
62971
+ role: "viewer"
62972
+ }),
62973
+ setPalette: require_sleep.method(setPaletteInputSchema, paletteReadySchema, {
62974
+ kind: "mutation",
62975
+ auth: "admin"
62976
+ })
62977
+ }
62978
+ };
62979
+ //#endregion
62299
62980
  //#region src/capabilities/device-status.cap.ts
62300
62981
  /**
62301
62982
  * Generic device-level status snapshot. Auto-registered by `BaseDevice`
@@ -77400,6 +78081,67 @@ function stateVocabularyFor(runtimeState, alarmStates = []) {
77400
78081
  return [];
77401
78082
  }
77402
78083
  //#endregion
78084
+ //#region src/catalogs/palette-legend.ts
78085
+ /**
78086
+ * Legend grouping for the palette editor (D939). Subclasses sit under the
78087
+ * macro that already owns them in the taxonomy. Marks that are not kinds
78088
+ * (recording, the live cursor, the heatmap handle, face, plate) are roots.
78089
+ */
78090
+ var LEGEND_ROOTS = [
78091
+ "person",
78092
+ "vehicle",
78093
+ "animal",
78094
+ "motion",
78095
+ "audio",
78096
+ "recording",
78097
+ "live",
78098
+ "heatmapScrub",
78099
+ "package",
78100
+ "sensor",
78101
+ "control",
78102
+ "face",
78103
+ "plate"
78104
+ ];
78105
+ var MARK_LABELS = {
78106
+ recording: "Recording",
78107
+ live: "Live cursor",
78108
+ heatmapScrub: "Heatmap handle",
78109
+ face: "Face",
78110
+ plate: "Plate"
78111
+ };
78112
+ function parentOf(id) {
78113
+ const fromTaxonomy = getTaxonomyEntry(id)?.parentKind;
78114
+ if (fromTaxonomy !== void 0 && fromTaxonomy !== null) return fromTaxonomy;
78115
+ return Object.entries(COCO_TO_MACRO.mapping).find(([key]) => key === id)?.[1] ?? null;
78116
+ }
78117
+ function paletteEntryLabel(id) {
78118
+ const mark = MARK_LABELS[id];
78119
+ if (mark !== void 0) return mark;
78120
+ const fromTaxonomy = getTaxonomyEntry(id)?.label;
78121
+ if (fromTaxonomy !== void 0) return fromTaxonomy;
78122
+ return COCO_80_LABELS.find((row) => row.id === id)?.name ?? id;
78123
+ }
78124
+ /** One row per root, subclasses underneath. Every palette entry appears once. */
78125
+ function paletteLegend() {
78126
+ const roots = new Set(LEGEND_ROOTS);
78127
+ return LEGEND_ROOTS.map((id) => {
78128
+ const children = [];
78129
+ for (const entryId of PALETTE_ENTRY_IDS) {
78130
+ if (roots.has(entryId)) continue;
78131
+ if (parentOf(entryId) !== id) continue;
78132
+ children.push({
78133
+ id: entryId,
78134
+ label: paletteEntryLabel(entryId)
78135
+ });
78136
+ }
78137
+ return {
78138
+ id,
78139
+ label: paletteEntryLabel(id),
78140
+ children
78141
+ };
78142
+ });
78143
+ }
78144
+ //#endregion
77403
78145
  //#region src/device/accessory.ts
77404
78146
  /**
77405
78147
  * Accessory device helpers — shared across drivers.
@@ -82813,6 +83555,27 @@ var METHOD_ACCESS_MAP = Object.freeze({
82813
83555
  access: "create",
82814
83556
  role: "viewer"
82815
83557
  },
83558
+ "displayPalette.getPalette": {
83559
+ capName: "display-palette",
83560
+ capScope: "system",
83561
+ addonId: null,
83562
+ access: "view",
83563
+ role: "viewer"
83564
+ },
83565
+ "displayPalette.listPresets": {
83566
+ capName: "display-palette",
83567
+ capScope: "system",
83568
+ addonId: null,
83569
+ access: "view",
83570
+ role: "viewer"
83571
+ },
83572
+ "displayPalette.setPalette": {
83573
+ capName: "display-palette",
83574
+ capScope: "system",
83575
+ addonId: null,
83576
+ access: "create",
83577
+ role: "admin"
83578
+ },
82816
83579
  "doorbell.getStatus": {
82817
83580
  capName: "doorbell",
82818
83581
  capScope: "device",
@@ -89584,6 +90347,7 @@ var KNOWN_CAP_NAMES = [
89584
90347
  "device-state",
89585
90348
  "device-status",
89586
90349
  "dishwasher",
90350
+ "display-palette",
89587
90351
  "doorbell",
89588
90352
  "embedding-encoder",
89589
90353
  "enum-sensor",
@@ -89830,6 +90594,7 @@ var SYSTEM_CAP_NAMES = [
89830
90594
  "device-provider",
89831
90595
  "device-removal-hook",
89832
90596
  "device-state",
90597
+ "display-palette",
89833
90598
  "embedding-encoder",
89834
90599
  "face-gallery",
89835
90600
  "failure-contribution",
@@ -93650,6 +94415,7 @@ var SYSTEM_CAP_VOCABULARY = {
93650
94415
  "device-provider": system(INTERNAL),
93651
94416
  "device-removal-hook": system(INTERNAL),
93652
94417
  "device-state": system("the runtime-state mirror every trigger already reads through"),
94418
+ "display-palette": system("the cluster display palette — one colour table for every client, not a device action"),
93653
94419
  "embedding-encoder": system(ML),
93654
94420
  "face-gallery": system("the face gallery — curated on its own page"),
93655
94421
  "failure-contribution": system(INTERNAL),
@@ -95506,6 +96272,7 @@ var CAPABILITY_NAMES = {
95506
96272
  deviceState: "device-state",
95507
96273
  deviceStatus: "device-status",
95508
96274
  dishwasher: "dishwasher",
96275
+ displayPalette: "display-palette",
95509
96276
  doorbell: "doorbell",
95510
96277
  embeddingEncoder: "embedding-encoder",
95511
96278
  enumSensor: "enum-sensor",
@@ -95875,6 +96642,10 @@ var CAPABILITY_ROUTER_KEYS = [
95875
96642
  key: "dishwasher",
95876
96643
  name: "dishwasher"
95877
96644
  },
96645
+ {
96646
+ key: "displayPalette",
96647
+ name: "display-palette"
96648
+ },
95878
96649
  {
95879
96650
  key: "doorbell",
95880
96651
  name: "doorbell"
@@ -96420,6 +97191,7 @@ var ALL_CAPABILITY_DEFINITIONS = [
96420
97191
  deviceStateCapability,
96421
97192
  deviceStatusCapability,
96422
97193
  dishwasherCapability,
97194
+ displayPaletteCapability,
96423
97195
  doorbellCapability,
96424
97196
  embeddingEncoderCapability,
96425
97197
  enumSensorCapability,
@@ -102601,6 +103373,11 @@ function createSystemProxy(api) {
102601
103373
  getAllSnapshots: (input) => dispatch("deviceState", "getAllSnapshots", "query", input),
102602
103374
  listClaims: (input) => dispatch("deviceState", "listClaims", "query", input)
102603
103375
  },
103376
+ displayPalette: {
103377
+ getPalette: (input) => dispatch("displayPalette", "getPalette", "query", input),
103378
+ listPresets: (input) => dispatch("displayPalette", "listPresets", "query", input),
103379
+ setPalette: (input) => dispatch("displayPalette", "setPalette", "mutation", input)
103380
+ },
102604
103381
  faceGallery: {
102605
103382
  listIdentities: (input) => dispatch("faceGallery", "listIdentities", "query", input),
102606
103383
  createIdentity: (input) => dispatch("faceGallery", "createIdentity", "mutation", input),
@@ -112835,6 +113612,7 @@ exports.ARCHIVED_DEBUG_NOTES_DEFAULT_LIMIT = ARCHIVED_DEBUG_NOTES_DEFAULT_LIMIT;
112835
113612
  exports.AUDIO_ANALYSIS_CAP_NAME = AUDIO_ANALYSIS_CAP_NAME;
112836
113613
  exports.AUDIO_BACKEND_CHOICES = AUDIO_BACKEND_CHOICES;
112837
113614
  exports.AUDIO_CHUNK_FORMATS = require_sleep.AUDIO_CHUNK_FORMATS;
113615
+ exports.AUDIO_GRADIENT_ALPHAS = AUDIO_GRADIENT_ALPHAS;
112838
113616
  exports.AUDIO_MACRO_LABELS = AUDIO_MACRO_LABELS;
112839
113617
  exports.AUDIO_NOT_CLASSIFIED_REASONS = AUDIO_NOT_CLASSIFIED_REASONS;
112840
113618
  exports.AUDIO_PRESETS = require_composition.AUDIO_PRESETS;
@@ -113299,6 +114077,7 @@ exports.DEVICE_TOMBSTONE_RETENTION_MS = DEVICE_TOMBSTONE_RETENTION_MS;
113299
114077
  exports.DEVICE_TYPE_CONTROL_KIND = DEVICE_TYPE_CONTROL_KIND;
113300
114078
  exports.DEVICE_TYPE_DO_CAPS = DEVICE_TYPE_DO_CAPS;
113301
114079
  exports.DEVICE_TYPE_INFO = DEVICE_TYPE_INFO;
114080
+ exports.DISPLAY_PRESETS = DISPLAY_PRESETS;
113302
114081
  exports.DOORBELL_RISE_DEBOUNCE_MS = DOORBELL_RISE_DEBOUNCE_MS;
113303
114082
  exports.DataStoreDatabaseSchema = DataStoreDatabaseSchema;
113304
114083
  exports.DataStoreEngineInfoSchema = EngineInfoSchema;
@@ -114123,6 +114902,12 @@ exports.OsdTemplateFormatSchema = OsdTemplateFormatSchema;
114123
114902
  exports.OsdTemplatePickSchema = OsdTemplatePickSchema;
114124
114903
  exports.OsdTemplateTokenKindSchema = OsdTemplateTokenKindSchema;
114125
114904
  exports.OverrideDraftSchema = OverrideDraftSchema;
114905
+ exports.PALETTE_BACKGROUNDS = PALETTE_BACKGROUNDS;
114906
+ exports.PALETTE_ENTRY_IDS = PALETTE_ENTRY_IDS;
114907
+ exports.PALETTE_MIN_CONTRAST = PALETTE_MIN_CONTRAST;
114908
+ exports.PALETTE_MIN_DELTA_E = PALETTE_MIN_DELTA_E;
114909
+ exports.PALETTE_MIN_DELTA_E_MARK = PALETTE_MIN_DELTA_E_MARK;
114910
+ exports.PALETTE_PRESET_IDS = PALETTE_PRESET_IDS;
114126
114911
  exports.PEER_BYTES_CHUNK_BYTES = require_sleep.PEER_BYTES_CHUNK_BYTES;
114127
114912
  exports.PEER_BYTES_MAX_OUTSTANDING = require_sleep.PEER_BYTES_MAX_OUTSTANDING;
114128
114913
  exports.PEER_BYTES_STALL_MS = require_sleep.PEER_BYTES_STALL_MS;
@@ -114150,6 +114935,7 @@ exports.PackageInstallationsSchema = PackageInstallationsSchema;
114150
114935
  exports.PackageLlmVerdictSchema = PackageLlmVerdictSchema;
114151
114936
  exports.PackageUpdateSchema = PackageUpdateSchema;
114152
114937
  exports.PackageVersionInfoSchema = PackageVersionInfoSchema;
114938
+ exports.PaletteRejectedError = PaletteRejectedError;
114153
114939
  exports.ParkRefusalSchema = ParkRefusalSchema;
114154
114940
  exports.ParkTrackFrameResultSchema = ParkTrackFrameResultSchema;
114155
114941
  exports.ParkedFrameKindSchema = ParkedFrameKindSchema;
@@ -114616,7 +115402,6 @@ exports.SwitchStatusSchema = SwitchStatusSchema;
114616
115402
  exports.SystemHeldSecretNameSchema = SystemHeldSecretNameSchema;
114617
115403
  exports.SystemMetricsSchema = SystemMetricsSchema;
114618
115404
  exports.SystemMirror = SystemMirror;
114619
- exports.TAXONOMY_COLORS = TAXONOMY_COLORS;
114620
115405
  exports.TIMELAPSE_DENSE_FLOOR_SEC = TIMELAPSE_DENSE_FLOOR_SEC;
114621
115406
  exports.TIMEZONES = TIMEZONES;
114622
115407
  exports.TRACK_RELATIONS_DEFAULT_LIMIT = TRACK_RELATIONS_DEFAULT_LIMIT;
@@ -114893,6 +115678,7 @@ exports.buildSubjectPath = buildSubjectPath;
114893
115678
  exports.buildVideoArgs = require_composition.buildVideoArgs;
114894
115679
  exports.buildViewerLink = buildViewerLink;
114895
115680
  exports.builtCapabilityBlockers = builtCapabilityBlockers;
115681
+ exports.bundledCamstack = bundledCamstack;
114896
115682
  exports.buttonCapability = buttonCapability;
114897
115683
  exports.calendarEventLocalSpan = calendarEventLocalSpan;
114898
115684
  exports.calendarEventOnLocalDay = calendarEventOnLocalDay;
@@ -115079,6 +115865,7 @@ exports.deviceStatusCapability = deviceStatusCapability;
115079
115865
  exports.diffStepSettings = diffStepSettings;
115080
115866
  exports.disarmRoseMemory = require_composition.disarmRoseMemory;
115081
115867
  exports.dishwasherCapability = dishwasherCapability;
115868
+ exports.displayPaletteCapability = displayPaletteCapability;
115082
115869
  exports.doActionSelectValue = doActionSelectValue;
115083
115870
  exports.dominantClipLabels = dominantClipLabels;
115084
115871
  exports.doorbellCapability = doorbellCapability;
@@ -115161,6 +115948,7 @@ exports.formatDeviceRevoker = formatDeviceRevoker;
115161
115948
  exports.formatForRuntime = formatForRuntime;
115162
115949
  exports.formatMediaOwnerKey = formatMediaOwnerKey;
115163
115950
  exports.formatMinutes = formatMinutes;
115951
+ exports.formatPaletteViolations = formatPaletteViolations;
115164
115952
  exports.formatParkedFor = formatParkedFor;
115165
115953
  exports.formatSecretScope = require_sleep.formatSecretScope;
115166
115954
  exports.freshResults = freshResults;
@@ -115334,6 +116122,7 @@ exports.mediaPlayerCapability = mediaPlayerCapability;
115334
116122
  exports.memoizePinnedFfmpeg = memoizePinnedFfmpeg;
115335
116123
  exports.mergeClipLabels = mergeClipLabels;
115336
116124
  exports.mergeKeyedArrayItem = mergeKeyedArrayItem;
116125
+ exports.mergeOverrides = mergeOverrides;
115337
116126
  exports.mergeSecretStatePaths = require_sleep.mergeSecretStatePaths;
115338
116127
  exports.mergeSettingsBags = mergeSettingsBags;
115339
116128
  exports.mergeSourceInfo = mergeSourceInfo;
@@ -115396,6 +116185,13 @@ exports.osdCapability = osdCapability;
115396
116185
  exports.osdManagerCapability = osdManagerCapability;
115397
116186
  exports.overlayClusterStepSettings = overlayClusterStepSettings;
115398
116187
  exports.packagePickerItems = packagePickerItems;
116188
+ exports.paintHex = paintHex;
116189
+ exports.paletteEntryLabel = paletteEntryLabel;
116190
+ exports.paletteFromInput = paletteFromInput;
116191
+ exports.paletteFromStored = paletteFromStored;
116192
+ exports.paletteLegend = paletteLegend;
116193
+ exports.paletteResultSchema = paletteResultSchema;
116194
+ exports.paletteSwatchSchema = paletteSwatchSchema;
115399
116195
  exports.parseAcceleratorFactsJson = parseAcceleratorFactsJson;
115400
116196
  exports.parseAdminBase = parseAdminBase;
115401
116197
  exports.parseAlertEpisodePayload = parseAlertEpisodePayload;
@@ -115456,6 +116252,7 @@ exports.poolMemoryThreshold = poolMemoryThreshold;
115456
116252
  exports.powerMeterCapability = powerMeterCapability;
115457
116253
  exports.prepareNotification = prepareNotification;
115458
116254
  exports.presenceCapability = presenceCapability;
116255
+ exports.presetById = presetById;
115459
116256
  exports.pressureSensorCapability = pressureSensorCapability;
115460
116257
  exports.principalMayReachAddon = principalMayReachAddon;
115461
116258
  exports.privacyMaskCapability = privacyMaskCapability;
@@ -115620,6 +116417,7 @@ exports.servedTemplateVars = servedTemplateVars;
115620
116417
  exports.serverManagementCapability = serverManagementCapability;
115621
116418
  exports.sessionsOfDeviceCell = sessionsOfDeviceCell;
115622
116419
  exports.setByPath = setByPath;
116420
+ exports.setPaletteInputSchema = setPaletteInputSchema;
115623
116421
  exports.settingValuesEqual = settingValuesEqual;
115624
116422
  exports.settingsBelow = settingsBelow;
115625
116423
  exports.settingsStoreCapability = settingsStoreCapability;
@@ -115653,6 +116451,8 @@ exports.storageEvictableCapability = storageEvictableCapability;
115653
116451
  exports.storageMigrationCapability = storageMigrationCapability;
115654
116452
  exports.storageOccupancyCapability = storageOccupancyCapability;
115655
116453
  exports.storageProviderCapability = storageProviderCapability;
116454
+ exports.storedFromReady = storedFromReady;
116455
+ exports.storedPaletteSchema = storedPaletteSchema;
115656
116456
  exports.streamBrokerCapability = streamBrokerCapability;
115657
116457
  exports.streamCatalogCapability = streamCatalogCapability;
115658
116458
  exports.streamParamsCapability = streamParamsCapability;
@@ -115670,6 +116470,7 @@ exports.summarizeEffectiveScope = summarizeEffectiveScope;
115670
116470
  exports.summarizeReview = summarizeReview;
115671
116471
  exports.supplyFor = supplyFor;
115672
116472
  exports.supportedRuntimes = supportedRuntimes;
116473
+ exports.swatchHex = swatchHex;
115673
116474
  exports.switchCapability = switchCapability;
115674
116475
  exports.switchedOffIds = switchedOffIds;
115675
116476
  exports.syncActiveAlarmProfileSettings = syncActiveAlarmProfileSettings;
@@ -115730,6 +116531,7 @@ exports.vacuumControlCapability = vacuumControlCapability;
115730
116531
  exports.validateComposition = validateComposition;
115731
116532
  exports.validateCustomAddress = validateCustomAddress;
115732
116533
  exports.validateExpressionSource = require_composition.validateExpressionSource;
116534
+ exports.validatePalette = validatePalette;
115733
116535
  exports.validateRecipeBounds = validateRecipeBounds;
115734
116536
  exports.valveCapability = valveCapability;
115735
116537
  exports.vectorDimFromBase64 = vectorDimFromBase64;