@camstack/types 1.2.420 → 1.2.422

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.
Files changed (50) hide show
  1. package/dist/addon.js +2 -2
  2. package/dist/addon.mjs +2 -2
  3. package/dist/capabilities/composer.cap.d.ts +129 -21
  4. package/dist/capabilities/core-blocks.cap.d.ts +929 -151
  5. package/dist/capabilities/index.d.ts +3 -1
  6. package/dist/capabilities/meter.cap.d.ts +53 -0
  7. package/dist/capabilities/power-meter.cap.d.ts +1 -1
  8. package/dist/capabilities/running-state.cap.d.ts +1 -1
  9. package/dist/client.js +12 -1
  10. package/dist/client.mjs +12 -1
  11. package/dist/composition/composition-report.d.ts +45 -0
  12. package/dist/composition/composition.d.ts +196 -7
  13. package/dist/composition/helpers/appliance.d.ts +28 -0
  14. package/dist/composition/helpers/compile-history.d.ts +13 -0
  15. package/dist/composition/helpers/compile.d.ts +3 -2
  16. package/dist/composition/helpers/energy.d.ts +8 -0
  17. package/dist/composition/helpers/history-math.d.ts +39 -0
  18. package/dist/composition/helpers/history-window.d.ts +71 -0
  19. package/dist/composition/helpers/index.d.ts +7 -2
  20. package/dist/composition/helpers/save.d.ts +1 -1
  21. package/dist/composition/helpers/source-pick.d.ts +2 -0
  22. package/dist/composition/helpers/spec.d.ts +39 -6
  23. package/dist/{composition-re1aezX9.js → composition-CPRAP41h.js} +924 -7
  24. package/dist/{composition-OhpuespA.mjs → composition-CpETZ4HL.mjs} +679 -8
  25. package/dist/device/appliance-export.d.ts +25 -0
  26. package/dist/device/cap-vocabulary/entries/sensors.d.ts +1 -1
  27. package/dist/device/cap-vocabulary/types.d.ts +10 -0
  28. package/dist/device/device-type.d.ts +8 -2
  29. package/dist/{err-msg-BXKzRBwg.mjs → err-msg-DIorGYeC.mjs} +7 -1
  30. package/dist/{err-msg-BhVbr0NX.js → err-msg-U7lLUMNz.js} +7 -1
  31. package/dist/generated/addon-api.d.ts +14 -0
  32. package/dist/generated/addon-cap-facts.d.ts +1 -1
  33. package/dist/generated/cap-status-types.d.ts +3 -1
  34. package/dist/generated/capability-router-map.d.ts +5 -2
  35. package/dist/generated/customize-catalog.d.ts +2 -2
  36. package/dist/generated/device-local-state.d.ts +3 -0
  37. package/dist/generated/device-proxy.d.ts +3 -0
  38. package/dist/generated/device-scoped-caps.d.ts +1 -1
  39. package/dist/generated/history-catalog.d.ts +1 -1
  40. package/dist/generated/method-access-map.d.ts +1 -1
  41. package/dist/generated/method-device-selectors.d.ts +1 -1
  42. package/dist/generated/runtime-state-durability.d.ts +1 -1
  43. package/dist/index.d.ts +1 -0
  44. package/dist/index.js +1063 -562
  45. package/dist/index.mjs +1013 -563
  46. package/dist/node.js +2 -2
  47. package/dist/node.mjs +2 -2
  48. package/dist/{sleep-bykKrTgu.mjs → sleep-0sD_LHLI.mjs} +10 -1
  49. package/dist/{sleep-YJ6FVsUu.js → sleep-CEKGW7A5.js} +10 -1
  50. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- const require_err_msg = require("./err-msg-BhVbr0NX.js");
1
+ const require_err_msg = require("./err-msg-U7lLUMNz.js");
2
2
  let zod = require("zod");
3
3
  let node_crypto = require("node:crypto");
4
4
  //#region src/ffmpeg/invocation.ts
@@ -2160,6 +2160,616 @@ function evaluateExpressionSource(expr, bindingValues, now, opts) {
2160
2160
  }
2161
2161
  }
2162
2162
  //#endregion
2163
+ //#region src/composition/helpers/appliance.ts
2164
+ /**
2165
+ * One power reading becomes a washer, dryer or dishwasher (D944 helper).
2166
+ *
2167
+ * Standby of the control board is under 5 W; a motor or a heater is far
2168
+ * above that, so 5 W is the line. A door lock or a short pump spike is not
2169
+ * a cycle, so running starts only after 30 s above the line.
2170
+ *
2171
+ * A wash, dry or dishwasher pause (soak, heat-wait, heater off between
2172
+ * bursts) lasts several minutes. Ending the cycle on the first dip would
2173
+ * report "finished" in the middle of the program, so the stop dwell is
2174
+ * 10 minutes on every type. The number is stored per type so one machine
2175
+ * can move later without moving the others.
2176
+ */
2177
+ var APPLIANCE_TEMPLATE_ID = "appliance";
2178
+ var APPLIANCE_KINDS = [
2179
+ "washer",
2180
+ "dryer",
2181
+ "dishwasher"
2182
+ ];
2183
+ var START_DWELL_MS = 3e4;
2184
+ var STOP_DWELL_MS = 6e5;
2185
+ var THRESHOLD_WATTS = 5;
2186
+ var APPLIANCE_DEFAULTS = {
2187
+ washer: {
2188
+ thresholdWatts: THRESHOLD_WATTS,
2189
+ startDwellMs: START_DWELL_MS,
2190
+ stopDwellMs: STOP_DWELL_MS
2191
+ },
2192
+ dryer: {
2193
+ thresholdWatts: THRESHOLD_WATTS,
2194
+ startDwellMs: START_DWELL_MS,
2195
+ stopDwellMs: STOP_DWELL_MS
2196
+ },
2197
+ dishwasher: {
2198
+ thresholdWatts: THRESHOLD_WATTS,
2199
+ startDwellMs: START_DWELL_MS,
2200
+ stopDwellMs: STOP_DWELL_MS
2201
+ }
2202
+ };
2203
+ var DEVICE_TYPE = {
2204
+ washer: require_err_msg.DeviceType.Washer,
2205
+ dryer: require_err_msg.DeviceType.Dryer,
2206
+ dishwasher: require_err_msg.DeviceType.Dishwasher
2207
+ };
2208
+ function applianceDeviceType(kind) {
2209
+ return DEVICE_TYPE[kind];
2210
+ }
2211
+ function isApplianceKind(value) {
2212
+ return APPLIANCE_KINDS.some((kind) => kind === value);
2213
+ }
2214
+ /** The member step: one watts reading, from a sensor or from the plug itself. */
2215
+ function sourcePickForAppliance() {
2216
+ return {
2217
+ purpose: "reading",
2218
+ multiple: false,
2219
+ max: 1,
2220
+ deviceTypes: [require_err_msg.DeviceType.Sensor, require_err_msg.DeviceType.Switch],
2221
+ accept: [{
2222
+ cap: "power-meter",
2223
+ fieldPath: "watts",
2224
+ valueKind: "number"
2225
+ }],
2226
+ history: {
2227
+ required: false,
2228
+ minRetentionMs: null
2229
+ },
2230
+ mustBindCaps: [],
2231
+ exclude: []
2232
+ };
2233
+ }
2234
+ //#endregion
2235
+ //#region src/composition/helpers/energy.ts
2236
+ /**
2237
+ * Watts integrated over time, in kWh (D944).
2238
+ *
2239
+ * 1 kWh = 1 000 W × 3 600 000 ms. The history energy series uses the same
2240
+ * factor (`tw_sum / 3.6e9`), so a chart and an integral helper cannot diverge.
2241
+ */
2242
+ var KWH_PER_WATT_MS = 1 / 36e8;
2243
+ function wattMillisecondsToKwh(wattMilliseconds) {
2244
+ return wattMilliseconds * KWH_PER_WATT_MS;
2245
+ }
2246
+ //#endregion
2247
+ //#region src/composition/helpers/history-math.ts
2248
+ /**
2249
+ * Statistics and integrals over a history read (D944).
2250
+ *
2251
+ * Pure: the same points always give the same answer, so a restart recomputes
2252
+ * rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
2253
+ * never the mean of the samples. A hole with no held value is not integrated
2254
+ * as zero. A truncated read is not published.
2255
+ */
2256
+ var STATISTIC_STATS = [
2257
+ "min",
2258
+ "max",
2259
+ "mean",
2260
+ "sum",
2261
+ "count",
2262
+ "change"
2263
+ ];
2264
+ var SERIES_KINDS = [
2265
+ "gauge",
2266
+ "counter",
2267
+ "boolean"
2268
+ ];
2269
+ function finite(value) {
2270
+ return typeof value === "number" && Number.isFinite(value);
2271
+ }
2272
+ function pointValue(point) {
2273
+ if (finite(point.value)) return point.value;
2274
+ if (finite(point.last)) return point.last;
2275
+ return null;
2276
+ }
2277
+ function stepCoverage(read) {
2278
+ const points = read.points.filter((point) => point.t >= read.from && point.t < read.to);
2279
+ const start = finite(read.before?.value) ? read.before.value : null;
2280
+ let held = start;
2281
+ let cursor = read.from;
2282
+ let gaps = 0;
2283
+ const segments = [];
2284
+ if (held === null) {
2285
+ const first = points.find((point) => pointValue(point) !== null);
2286
+ if (first === void 0) return {
2287
+ segments,
2288
+ included: 0,
2289
+ gaps: 1,
2290
+ end: null,
2291
+ start: null
2292
+ };
2293
+ if (first.t > read.from) gaps += 1;
2294
+ cursor = first.t;
2295
+ held = pointValue(first);
2296
+ }
2297
+ for (const point of points) {
2298
+ const next = pointValue(point);
2299
+ if (held !== null && point.t > cursor) segments.push({
2300
+ value: held,
2301
+ ms: point.t - cursor
2302
+ });
2303
+ if (next !== null) held = next;
2304
+ if (point.t > cursor) cursor = point.t;
2305
+ }
2306
+ if (held !== null && read.to > cursor) segments.push({
2307
+ value: held,
2308
+ ms: read.to - cursor
2309
+ });
2310
+ const end = points.reduce((latest, point) => pointValue(point) ?? latest, held);
2311
+ return {
2312
+ segments,
2313
+ included: points.length,
2314
+ gaps,
2315
+ end,
2316
+ start
2317
+ };
2318
+ }
2319
+ function rollupCoverage(read) {
2320
+ const weighted = read.points.filter((point) => finite(point.twMean) && finite(point.twMs) && point.twMs > 0);
2321
+ if (weighted.length === 0) return null;
2322
+ const first = weighted[0];
2323
+ const gaps = read.before === null && first !== void 0 && first.t > read.from ? 1 : 0;
2324
+ const levels = read.points.flatMap((point) => finite(point.last) ? [point.last] : []);
2325
+ const end = levels.length > 0 ? levels[levels.length - 1] ?? null : null;
2326
+ return {
2327
+ segments: weighted.flatMap((point) => finite(point.twMean) && finite(point.twMs) ? [{
2328
+ value: point.twMean,
2329
+ ms: point.twMs
2330
+ }] : []),
2331
+ included: weighted.length,
2332
+ gaps,
2333
+ end,
2334
+ start: finite(read.before?.value) ? read.before.value : null
2335
+ };
2336
+ }
2337
+ function coverageOf(read) {
2338
+ if (read.tier !== "raw") {
2339
+ const rolled = rollupCoverage(read);
2340
+ if (rolled !== null) return rolled;
2341
+ }
2342
+ return stepCoverage(read);
2343
+ }
2344
+ function timeWeighted(segments) {
2345
+ let ms = 0;
2346
+ let sum = 0;
2347
+ for (const segment of segments) {
2348
+ ms += segment.ms;
2349
+ sum += segment.value * segment.ms;
2350
+ }
2351
+ if (ms <= 0) return null;
2352
+ return sum / ms;
2353
+ }
2354
+ function extremes(read, covered) {
2355
+ const lows = [];
2356
+ const highs = [];
2357
+ for (const point of read.points) {
2358
+ if (finite(point.min)) lows.push(point.min);
2359
+ if (finite(point.max)) highs.push(point.max);
2360
+ }
2361
+ if (covered.start !== null) {
2362
+ lows.push(covered.start);
2363
+ highs.push(covered.start);
2364
+ }
2365
+ return {
2366
+ min: lows.length === 0 ? null : Math.min(...lows),
2367
+ max: highs.length === 0 ? null : Math.max(...highs)
2368
+ };
2369
+ }
2370
+ function counterGrowth(read) {
2371
+ const deltas = read.points.flatMap((point) => finite(point.delta) ? [point.delta] : []);
2372
+ if (deltas.length === 0) return null;
2373
+ return deltas.reduce((sum, delta) => sum + delta, 0);
2374
+ }
2375
+ function hold(reason) {
2376
+ return {
2377
+ write: "hold",
2378
+ value: null,
2379
+ included: 0,
2380
+ excluded: 0,
2381
+ reason
2382
+ };
2383
+ }
2384
+ function gapValue(reason, included) {
2385
+ return {
2386
+ write: "null",
2387
+ value: null,
2388
+ included,
2389
+ excluded: 1,
2390
+ reason
2391
+ };
2392
+ }
2393
+ function numberValue(value, included, gaps, reason) {
2394
+ return {
2395
+ write: "number",
2396
+ value,
2397
+ included,
2398
+ excluded: gaps,
2399
+ reason: gaps > 0 ? reason : null
2400
+ };
2401
+ }
2402
+ var GAP_REASON = "history has a gap — that interval was not counted as zero";
2403
+ function evaluateStatistic(stat, read) {
2404
+ if (read.truncated) return hold("the history query was truncated — the last statistic is kept");
2405
+ if (stat === "sum" && read.kind !== "counter") return hold("a gauge has no sum — that is the integral template");
2406
+ if (read.to <= read.from) return gapValue("the range is empty", 0);
2407
+ const covered = coverageOf(read);
2408
+ if (covered.segments.length === 0 && covered.start === null) return gapValue(GAP_REASON, covered.included);
2409
+ if (stat === "count") return numberValue(covered.included, covered.included, covered.gaps, GAP_REASON);
2410
+ if (stat === "sum" || stat === "change" && read.kind === "counter") {
2411
+ const growth = counterGrowth(read);
2412
+ if (growth === null) return gapValue("the counter has no growth in this range", covered.included);
2413
+ return numberValue(growth, covered.included, covered.gaps, GAP_REASON);
2414
+ }
2415
+ if (stat === "change") {
2416
+ if (covered.start === null || covered.end === null) return gapValue("the change has no value at the start of the range", covered.included);
2417
+ return numberValue(covered.end - covered.start, covered.included, covered.gaps, GAP_REASON);
2418
+ }
2419
+ if (stat === "min" || stat === "max") {
2420
+ const ends = extremes(read, covered);
2421
+ const value = stat === "min" ? ends.min : ends.max;
2422
+ if (value === null) return gapValue(GAP_REASON, covered.included);
2423
+ return numberValue(value, covered.included, covered.gaps, GAP_REASON);
2424
+ }
2425
+ const mean = timeWeighted(covered.segments);
2426
+ if (mean === null) return gapValue(GAP_REASON, covered.included);
2427
+ return numberValue(mean, covered.included, covered.gaps, GAP_REASON);
2428
+ }
2429
+ function integrateReading(read, scale) {
2430
+ if (read.truncated) return hold("the history query was truncated — the last total is kept");
2431
+ if (read.kind === "counter") return hold("a counter is already a total — it is not integrated again");
2432
+ if (read.to <= read.from) return gapValue("the range is empty", 0);
2433
+ const covered = coverageOf(read);
2434
+ if (covered.segments.length === 0) return {
2435
+ write: "hold",
2436
+ value: null,
2437
+ included: covered.included,
2438
+ excluded: covered.gaps,
2439
+ reason: GAP_REASON
2440
+ };
2441
+ let unitMs = 0;
2442
+ for (const segment of covered.segments) unitMs += segment.value * segment.ms;
2443
+ return numberValue(scale === "energy-kwh" ? wattMillisecondsToKwh(unitMs) : unitMs / 1e3, covered.included, covered.gaps, GAP_REASON);
2444
+ }
2445
+ //#endregion
2446
+ //#region src/composition/helpers/history-window.ts
2447
+ /**
2448
+ * The range a statistics or integral helper asks history for (D944).
2449
+ *
2450
+ * Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
2451
+ * or 25 hours across a DST change. A tier is eligible only when its retention
2452
+ * is strictly longer than the longest that range can be. Forever qualifies.
2453
+ * Equal to a tier's retention is a refusal, not a short answer.
2454
+ */
2455
+ var MINUTE_MS = 6e4;
2456
+ var HOUR_MS = 60 * MINUTE_MS;
2457
+ var DAY_MS = 24 * HOUR_MS;
2458
+ var ROLLING_SPANS = [
2459
+ "1h",
2460
+ "24h",
2461
+ "2d",
2462
+ "7d",
2463
+ "30d",
2464
+ "custom"
2465
+ ];
2466
+ var CALENDAR_PERIODS = [
2467
+ "today",
2468
+ "yesterday",
2469
+ "this-week",
2470
+ "this-month"
2471
+ ];
2472
+ var HISTORY_TIERS = [
2473
+ "raw",
2474
+ "5m",
2475
+ "1h",
2476
+ "1d"
2477
+ ];
2478
+ var RESET_PERIODS = [
2479
+ "never",
2480
+ "daily",
2481
+ "weekly",
2482
+ "monthly"
2483
+ ];
2484
+ var MIN_CUSTOM_MINUTES = 5;
2485
+ /** Faster than this is not a history query. Rolling windows at most this often. */
2486
+ var HISTORY_FAST_MS = 6e4;
2487
+ var HISTORY_SLOW_MS = 5 * MINUTE_MS;
2488
+ var ROLLING_MS = {
2489
+ "1h": HOUR_MS,
2490
+ "24h": 24 * HOUR_MS,
2491
+ "2d": 2 * DAY_MS,
2492
+ "7d": 7 * DAY_MS,
2493
+ "30d": 30 * DAY_MS
2494
+ };
2495
+ /** The device-history defaults: raw 7 d, 5 m 30 d, 1 h 365 d, 1 d forever. */
2496
+ var DEFAULT_HISTORY_RETENTION = {
2497
+ rawMs: 7 * DAY_MS,
2498
+ fiveMinuteMs: 30 * DAY_MS,
2499
+ hourMs: 365 * DAY_MS,
2500
+ dayMs: null
2501
+ };
2502
+ var rollingWindowObject = zod.z.object({
2503
+ kind: zod.z.literal("rolling"),
2504
+ span: zod.z.enum(ROLLING_SPANS),
2505
+ customMinutes: zod.z.number().int().min(5).optional()
2506
+ }).check((payload) => {
2507
+ if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
2508
+ code: "custom",
2509
+ message: "a custom range needs a duration in minutes",
2510
+ path: ["customMinutes"],
2511
+ input: payload.value
2512
+ });
2513
+ if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
2514
+ code: "custom",
2515
+ message: "only a custom range carries a duration",
2516
+ path: ["customMinutes"],
2517
+ input: payload.value
2518
+ });
2519
+ });
2520
+ var RollingWindowSchema = rollingWindowObject;
2521
+ var calendarWindowObject = zod.z.object({
2522
+ kind: zod.z.literal("calendar"),
2523
+ period: zod.z.enum(CALENDAR_PERIODS)
2524
+ });
2525
+ var CalendarWindowSchema = calendarWindowObject;
2526
+ var StatisticWindowSchema = zod.z.discriminatedUnion("kind", [rollingWindowObject, calendarWindowObject]);
2527
+ var WEEKDAY_INDEX = {
2528
+ Sun: 0,
2529
+ Mon: 1,
2530
+ Tue: 2,
2531
+ Wed: 3,
2532
+ Thu: 4,
2533
+ Fri: 5,
2534
+ Sat: 6
2535
+ };
2536
+ var FORMATTERS = /* @__PURE__ */ new Map();
2537
+ function formatterFor(timeZone) {
2538
+ const held = FORMATTERS.get(timeZone);
2539
+ if (held !== void 0) return held;
2540
+ let made;
2541
+ try {
2542
+ made = new Intl.DateTimeFormat("en-US", {
2543
+ timeZone,
2544
+ weekday: "short",
2545
+ year: "numeric",
2546
+ month: "2-digit",
2547
+ day: "2-digit",
2548
+ hour: "2-digit",
2549
+ minute: "2-digit",
2550
+ second: "2-digit",
2551
+ hourCycle: "h23"
2552
+ });
2553
+ } catch {
2554
+ made = null;
2555
+ }
2556
+ FORMATTERS.set(timeZone, made);
2557
+ return made;
2558
+ }
2559
+ function zonedClock(ms, timeZone) {
2560
+ const formatter = formatterFor(timeZone);
2561
+ if (formatter === null) return null;
2562
+ const parts = formatter.formatToParts(new Date(ms));
2563
+ const read = (type) => parts.find((part) => part.type === type)?.value;
2564
+ const year = Number(read("year"));
2565
+ const month = Number(read("month"));
2566
+ const day = Number(read("day"));
2567
+ const hourRaw = Number(read("hour"));
2568
+ const minute = Number(read("minute"));
2569
+ const second = Number(read("second"));
2570
+ const weekday = WEEKDAY_INDEX[read("weekday") ?? ""];
2571
+ if (!Number.isInteger(year) || !Number.isInteger(month) || !Number.isInteger(day) || !Number.isInteger(hourRaw) || !Number.isInteger(minute) || !Number.isInteger(second) || weekday === void 0) return null;
2572
+ return {
2573
+ year,
2574
+ month,
2575
+ day,
2576
+ hour: hourRaw === 24 ? 0 : hourRaw,
2577
+ minute,
2578
+ second,
2579
+ weekday
2580
+ };
2581
+ }
2582
+ function utcOf(clock, timeZone) {
2583
+ const guess = Date.UTC(clock.year, clock.month - 1, clock.day, clock.hour, clock.minute, clock.second);
2584
+ const first = zonedClock(guess, timeZone);
2585
+ if (first === null) return null;
2586
+ const offset = Date.UTC(first.year, first.month - 1, first.day, first.hour, first.minute, first.second) - guess;
2587
+ const shifted = guess - offset;
2588
+ const second = zonedClock(shifted, timeZone);
2589
+ if (second === null) return null;
2590
+ const offset2 = Date.UTC(second.year, second.month - 1, second.day, second.hour, second.minute, second.second) - shifted;
2591
+ return offset2 === offset ? shifted : guess - offset2;
2592
+ }
2593
+ function midnightOf(ms, timeZone) {
2594
+ const clock = zonedClock(ms, timeZone);
2595
+ if (clock === null) return null;
2596
+ return utcOf({
2597
+ ...clock,
2598
+ hour: 0,
2599
+ minute: 0,
2600
+ second: 0
2601
+ }, timeZone);
2602
+ }
2603
+ function monthStart(ms, timeZone) {
2604
+ const clock = zonedClock(ms, timeZone);
2605
+ if (clock === null) return null;
2606
+ return utcOf({
2607
+ ...clock,
2608
+ day: 1,
2609
+ hour: 0,
2610
+ minute: 0,
2611
+ second: 0
2612
+ }, timeZone);
2613
+ }
2614
+ function weekStart(ms, timeZone) {
2615
+ const clock = zonedClock(ms, timeZone);
2616
+ let cursor = midnightOf(ms, timeZone);
2617
+ if (clock === null || cursor === null) return null;
2618
+ const back = clock.weekday === 0 ? 6 : clock.weekday - 1;
2619
+ for (let step = 0; step < back; step++) {
2620
+ const previous = midnightOf(cursor - 1, timeZone);
2621
+ if (previous === null) return null;
2622
+ cursor = previous;
2623
+ }
2624
+ return cursor;
2625
+ }
2626
+ function keptLabel(ms) {
2627
+ if (ms === null) return "forever";
2628
+ if (ms % 864e5 === 0) return `${ms / DAY_MS} d`;
2629
+ if (ms % 36e5 === 0) return `${ms / HOUR_MS} h`;
2630
+ return `${ms / MINUTE_MS} min`;
2631
+ }
2632
+ function retentionSentence(retention) {
2633
+ return `raw ${keptLabel(retention.rawMs)}, 5m ${keptLabel(retention.fiveMinuteMs)}, 1h ${keptLabel(retention.hourMs)}, 1d ${keptLabel(retention.dayMs)}`;
2634
+ }
2635
+ function tierFor(durationMs, retention) {
2636
+ const rows = [
2637
+ {
2638
+ tier: "raw",
2639
+ keptMs: retention.rawMs
2640
+ },
2641
+ {
2642
+ tier: "5m",
2643
+ keptMs: retention.fiveMinuteMs
2644
+ },
2645
+ {
2646
+ tier: "1h",
2647
+ keptMs: retention.hourMs
2648
+ },
2649
+ {
2650
+ tier: "1d",
2651
+ keptMs: retention.dayMs
2652
+ }
2653
+ ];
2654
+ for (const row of rows) if (row.keptMs === null || row.keptMs > durationMs) return {
2655
+ ok: true,
2656
+ tier: row.tier,
2657
+ maxDurationMs: durationMs
2658
+ };
2659
+ return {
2660
+ ok: false,
2661
+ reason: `the range is ${keptLabel(durationMs)} and no history tier is kept strictly longer (${retentionSentence(retention)})`
2662
+ };
2663
+ }
2664
+ function rollingDurationMs(window) {
2665
+ if (window.span === "custom") return window.customMinutes === void 0 ? null : window.customMinutes * MINUTE_MS;
2666
+ return ROLLING_MS[window.span];
2667
+ }
2668
+ /** Longest the window can be. Calendar periods use their full length, not the elapsed part. */
2669
+ function maxDurationMs(window) {
2670
+ if (window.kind === "rolling") return rollingDurationMs(window);
2671
+ switch (window.period) {
2672
+ case "today":
2673
+ case "yesterday": return 25 * HOUR_MS;
2674
+ case "this-week": return 6084e5;
2675
+ case "this-month": return 2682e6;
2676
+ }
2677
+ }
2678
+ function planStatisticTier(window, retention) {
2679
+ const duration = maxDurationMs(window);
2680
+ if (duration === null) return {
2681
+ ok: false,
2682
+ reason: "a custom range needs a duration of at least 5 minutes"
2683
+ };
2684
+ return tierFor(duration, retention);
2685
+ }
2686
+ function planResetTier(reset, retention) {
2687
+ switch (reset) {
2688
+ case "never": return tierFor(Number.POSITIVE_INFINITY, retention);
2689
+ case "daily": return tierFor(25 * HOUR_MS, retention);
2690
+ case "weekly": return tierFor(6084e5, retention);
2691
+ case "monthly": return tierFor(2682e6, retention);
2692
+ }
2693
+ }
2694
+ function openStatistic(window, now, timeZone) {
2695
+ if (window.kind === "rolling") {
2696
+ const duration = rollingDurationMs(window);
2697
+ if (duration === null) return null;
2698
+ return {
2699
+ from: now - duration,
2700
+ to: now
2701
+ };
2702
+ }
2703
+ const today = midnightOf(now, timeZone);
2704
+ if (today === null) return null;
2705
+ switch (window.period) {
2706
+ case "today": return {
2707
+ from: today,
2708
+ to: now
2709
+ };
2710
+ case "yesterday": {
2711
+ const start = midnightOf(today - 1, timeZone);
2712
+ return start === null ? null : {
2713
+ from: start,
2714
+ to: today
2715
+ };
2716
+ }
2717
+ case "this-week": {
2718
+ const start = weekStart(now, timeZone);
2719
+ return start === null ? null : {
2720
+ from: start,
2721
+ to: now
2722
+ };
2723
+ }
2724
+ case "this-month": {
2725
+ const start = monthStart(now, timeZone);
2726
+ return start === null ? null : {
2727
+ from: start,
2728
+ to: now
2729
+ };
2730
+ }
2731
+ }
2732
+ }
2733
+ function openReset(reset, now, timeZone) {
2734
+ if (reset === "never") return {
2735
+ from: 0,
2736
+ to: now
2737
+ };
2738
+ const today = midnightOf(now, timeZone);
2739
+ if (today === null) return null;
2740
+ if (reset === "daily") return {
2741
+ from: today,
2742
+ to: now
2743
+ };
2744
+ if (reset === "weekly") {
2745
+ const start = weekStart(now, timeZone);
2746
+ return start === null ? null : {
2747
+ from: start,
2748
+ to: now
2749
+ };
2750
+ }
2751
+ const start = monthStart(now, timeZone);
2752
+ return start === null ? null : {
2753
+ from: start,
2754
+ to: now
2755
+ };
2756
+ }
2757
+ /** The next hub-local midnight, strictly after `now`. Monday is one of these. */
2758
+ function nextLocalMidnight(now, timeZone) {
2759
+ const today = midnightOf(now, timeZone);
2760
+ if (today === null) return null;
2761
+ return midnightOf(today + 26 * HOUR_MS, timeZone);
2762
+ }
2763
+ function statisticCadenceMs(window) {
2764
+ if (window.kind === "calendar") return window.period === "today" ? HISTORY_FAST_MS : HISTORY_SLOW_MS;
2765
+ const duration = rollingDurationMs(window);
2766
+ if (duration !== null && duration <= 24 * 36e5) return HISTORY_FAST_MS;
2767
+ return HISTORY_SLOW_MS;
2768
+ }
2769
+ function integralCadenceMs(tier) {
2770
+ return tier === "raw" ? HISTORY_FAST_MS : HISTORY_SLOW_MS;
2771
+ }
2772
+ //#endregion
2163
2773
  //#region src/composition/source-ref.ts
2164
2774
  /**
2165
2775
  * A composition source identity: `(addonId, stableId)`, never a numeric device
@@ -2225,10 +2835,7 @@ var HelperMemberSchema = zod.z.object({
2225
2835
  cap: zod.z.string().min(1),
2226
2836
  fieldPath: zod.z.string().min(1)
2227
2837
  });
2228
- /**
2229
- * Phase 1a is groups only. Math, integral and statistics stay off this union
2230
- * until the composer can run them — a control must not save a spec it cannot.
2231
- */
2838
+ /** A group, a statistic, or an integral (D944). The composer runs all three. */
2232
2839
  var GroupHelperSpecSchema = zod.z.object({
2233
2840
  kind: zod.z.literal("group"),
2234
2841
  templateId: GroupTemplateIdSchema,
@@ -2237,7 +2844,45 @@ var GroupHelperSpecSchema = zod.z.object({
2237
2844
  /** Actuator groups only. Readings leave this unset. */
2238
2845
  active: ActiveCriterionSchema.optional()
2239
2846
  });
2240
- var HelperSpecSchema = zod.z.discriminatedUnion("kind", [GroupHelperSpecSchema]);
2847
+ var ApplianceHelperSpecSchema = zod.z.object({
2848
+ kind: zod.z.literal("appliance"),
2849
+ templateId: zod.z.literal(APPLIANCE_TEMPLATE_ID),
2850
+ appliance: zod.z.enum(APPLIANCE_KINDS),
2851
+ thresholdWatts: zod.z.number().positive(),
2852
+ startDwellMs: zod.z.number().int().nonnegative(),
2853
+ stopDwellMs: zod.z.number().int().nonnegative(),
2854
+ member: HelperMemberSchema
2855
+ });
2856
+ var statisticHelperObject = zod.z.object({
2857
+ kind: zod.z.literal("statistic"),
2858
+ stat: zod.z.enum(STATISTIC_STATS),
2859
+ window: StatisticWindowSchema,
2860
+ source: HelperMemberSchema
2861
+ });
2862
+ var StatisticHelperSpecSchema = statisticHelperObject;
2863
+ var INTEGRAL_OUTPUTS = ["energy", "meter"];
2864
+ var integralHelperObject = zod.z.object({
2865
+ kind: zod.z.literal("integral"),
2866
+ reset: zod.z.enum(RESET_PERIODS),
2867
+ output: zod.z.enum(INTEGRAL_OUTPUTS),
2868
+ source: HelperMemberSchema
2869
+ });
2870
+ var IntegralHelperSpecSchema = integralHelperObject;
2871
+ var HelperSpecSchema = zod.z.discriminatedUnion("kind", [
2872
+ GroupHelperSpecSchema,
2873
+ ApplianceHelperSpecSchema,
2874
+ statisticHelperObject,
2875
+ integralHelperObject
2876
+ ]);
2877
+ /** Every member a helper reads. A group has many; the others have one. */
2878
+ function helperMembers(spec) {
2879
+ switch (spec.kind) {
2880
+ case "group": return spec.members;
2881
+ case "appliance": return [spec.member];
2882
+ case "statistic":
2883
+ case "integral": return [spec.source];
2884
+ }
2885
+ }
2241
2886
  //#endregion
2242
2887
  //#region src/composition/composition.ts
2243
2888
  /**
@@ -2347,11 +2992,36 @@ var CompositionAggregateSourceSchema = zod.z.object({
2347
2992
  "offline"
2348
2993
  ])
2349
2994
  });
2995
+ /**
2996
+ * `series`: a statistics or integral field. The composer writes it from a
2997
+ * history query. The live pass does not recompute it (D944).
2998
+ */
2999
+ var CompositionSeriesSourceSchema = zod.z.object({
3000
+ kind: zod.z.literal("series"),
3001
+ read: CompositionFieldReadSchema,
3002
+ /** `value` is the statistic or the integral. The others are the gap counts. */
3003
+ publish: zod.z.enum([
3004
+ "value",
3005
+ "included",
3006
+ "excluded",
3007
+ "total"
3008
+ ]),
3009
+ /**
3010
+ * What an unanswered `value` does. Counts ignore this. `offline` leaves the
3011
+ * device unseeded until history answers, so a restart cannot publish 0.
3012
+ */
3013
+ empty: zod.z.enum([
3014
+ "null",
3015
+ "omit",
3016
+ "offline"
3017
+ ])
3018
+ });
2350
3019
  var CompositionFieldSourceSchema = zod.z.discriminatedUnion("kind", [
2351
3020
  CompositionFromSourceSchema,
2352
3021
  CompositionExpressionSourceSchema,
2353
3022
  CompositionCodeSourceSchema,
2354
- CompositionAggregateSourceSchema
3023
+ CompositionAggregateSourceSchema,
3024
+ CompositionSeriesSourceSchema
2355
3025
  ]);
2356
3026
  /** `forward`: RESERVED for slice 3. Argument mapping arrives there as an additive optional `args`. */
2357
3027
  var CompositionForwardCommandSchema = zod.z.object({
@@ -2471,6 +3141,7 @@ function fieldReads(source) {
2471
3141
  fieldPath: binding.fieldPath
2472
3142
  }] : []);
2473
3143
  case "aggregate": return source.reads;
3144
+ case "series": return [source.read];
2474
3145
  case "code": return [];
2475
3146
  }
2476
3147
  }
@@ -2509,6 +3180,24 @@ Object.defineProperty(exports, "AGGREGATE_REDUCERS", {
2509
3180
  return AGGREGATE_REDUCERS;
2510
3181
  }
2511
3182
  });
3183
+ Object.defineProperty(exports, "APPLIANCE_DEFAULTS", {
3184
+ enumerable: true,
3185
+ get: function() {
3186
+ return APPLIANCE_DEFAULTS;
3187
+ }
3188
+ });
3189
+ Object.defineProperty(exports, "APPLIANCE_KINDS", {
3190
+ enumerable: true,
3191
+ get: function() {
3192
+ return APPLIANCE_KINDS;
3193
+ }
3194
+ });
3195
+ Object.defineProperty(exports, "APPLIANCE_TEMPLATE_ID", {
3196
+ enumerable: true,
3197
+ get: function() {
3198
+ return APPLIANCE_TEMPLATE_ID;
3199
+ }
3200
+ });
2512
3201
  Object.defineProperty(exports, "AUDIO_PRESETS", {
2513
3202
  enumerable: true,
2514
3203
  get: function() {
@@ -2527,12 +3216,24 @@ Object.defineProperty(exports, "AggregateReducerSchema", {
2527
3216
  return AggregateReducerSchema;
2528
3217
  }
2529
3218
  });
3219
+ Object.defineProperty(exports, "ApplianceHelperSpecSchema", {
3220
+ enumerable: true,
3221
+ get: function() {
3222
+ return ApplianceHelperSpecSchema;
3223
+ }
3224
+ });
2530
3225
  Object.defineProperty(exports, "BINARY_AGGREGATES", {
2531
3226
  enumerable: true,
2532
3227
  get: function() {
2533
3228
  return BINARY_AGGREGATES;
2534
3229
  }
2535
3230
  });
3231
+ Object.defineProperty(exports, "CALENDAR_PERIODS", {
3232
+ enumerable: true,
3233
+ get: function() {
3234
+ return CALENDAR_PERIODS;
3235
+ }
3236
+ });
2536
3237
  Object.defineProperty(exports, "COMPOSED_DEVICE_STABLE_ID_PREFIX", {
2537
3238
  enumerable: true,
2538
3239
  get: function() {
@@ -2563,6 +3264,12 @@ Object.defineProperty(exports, "CUSTOMIZATION_BLOCK_NAME_PREFIX", {
2563
3264
  return CUSTOMIZATION_BLOCK_NAME_PREFIX;
2564
3265
  }
2565
3266
  });
3267
+ Object.defineProperty(exports, "CalendarWindowSchema", {
3268
+ enumerable: true,
3269
+ get: function() {
3270
+ return CalendarWindowSchema;
3271
+ }
3272
+ });
2566
3273
  Object.defineProperty(exports, "CompositionAggregateSourceSchema", {
2567
3274
  enumerable: true,
2568
3275
  get: function() {
@@ -2665,6 +3372,12 @@ Object.defineProperty(exports, "CompositionSchema", {
2665
3372
  return CompositionSchema;
2666
3373
  }
2667
3374
  });
3375
+ Object.defineProperty(exports, "CompositionSeriesSourceSchema", {
3376
+ enumerable: true,
3377
+ get: function() {
3378
+ return CompositionSeriesSourceSchema;
3379
+ }
3380
+ });
2668
3381
  Object.defineProperty(exports, "CompositionSourceRefSchema", {
2669
3382
  enumerable: true,
2670
3383
  get: function() {
@@ -2677,12 +3390,24 @@ Object.defineProperty(exports, "CompositionTargetSchema", {
2677
3390
  return CompositionTargetSchema;
2678
3391
  }
2679
3392
  });
3393
+ Object.defineProperty(exports, "DAY_MS", {
3394
+ enumerable: true,
3395
+ get: function() {
3396
+ return DAY_MS;
3397
+ }
3398
+ });
2680
3399
  Object.defineProperty(exports, "DEFAULT_FIRST_SIGHTING_FRESHNESS_MS", {
2681
3400
  enumerable: true,
2682
3401
  get: function() {
2683
3402
  return DEFAULT_FIRST_SIGHTING_FRESHNESS_MS;
2684
3403
  }
2685
3404
  });
3405
+ Object.defineProperty(exports, "DEFAULT_HISTORY_RETENTION", {
3406
+ enumerable: true,
3407
+ get: function() {
3408
+ return DEFAULT_HISTORY_RETENTION;
3409
+ }
3410
+ });
2686
3411
  Object.defineProperty(exports, "EXPRESSION_BUILTINS", {
2687
3412
  enumerable: true,
2688
3413
  get: function() {
@@ -2761,6 +3486,30 @@ Object.defineProperty(exports, "GroupTemplateIdSchema", {
2761
3486
  return GroupTemplateIdSchema;
2762
3487
  }
2763
3488
  });
3489
+ Object.defineProperty(exports, "HISTORY_FAST_MS", {
3490
+ enumerable: true,
3491
+ get: function() {
3492
+ return HISTORY_FAST_MS;
3493
+ }
3494
+ });
3495
+ Object.defineProperty(exports, "HISTORY_SLOW_MS", {
3496
+ enumerable: true,
3497
+ get: function() {
3498
+ return HISTORY_SLOW_MS;
3499
+ }
3500
+ });
3501
+ Object.defineProperty(exports, "HISTORY_TIERS", {
3502
+ enumerable: true,
3503
+ get: function() {
3504
+ return HISTORY_TIERS;
3505
+ }
3506
+ });
3507
+ Object.defineProperty(exports, "HOUR_MS", {
3508
+ enumerable: true,
3509
+ get: function() {
3510
+ return HOUR_MS;
3511
+ }
3512
+ });
2764
3513
  Object.defineProperty(exports, "HelperMemberSchema", {
2765
3514
  enumerable: true,
2766
3515
  get: function() {
@@ -2773,6 +3522,24 @@ Object.defineProperty(exports, "HelperSpecSchema", {
2773
3522
  return HelperSpecSchema;
2774
3523
  }
2775
3524
  });
3525
+ Object.defineProperty(exports, "INTEGRAL_OUTPUTS", {
3526
+ enumerable: true,
3527
+ get: function() {
3528
+ return INTEGRAL_OUTPUTS;
3529
+ }
3530
+ });
3531
+ Object.defineProperty(exports, "IntegralHelperSpecSchema", {
3532
+ enumerable: true,
3533
+ get: function() {
3534
+ return IntegralHelperSpecSchema;
3535
+ }
3536
+ });
3537
+ Object.defineProperty(exports, "KWH_PER_WATT_MS", {
3538
+ enumerable: true,
3539
+ get: function() {
3540
+ return KWH_PER_WATT_MS;
3541
+ }
3542
+ });
2776
3543
  Object.defineProperty(exports, "MAX_COMPOSITION_CODE_LENGTH", {
2777
3544
  enumerable: true,
2778
3545
  get: function() {
@@ -2833,6 +3600,18 @@ Object.defineProperty(exports, "MAX_HELPER_MEMBERS", {
2833
3600
  return MAX_HELPER_MEMBERS;
2834
3601
  }
2835
3602
  });
3603
+ Object.defineProperty(exports, "MINUTE_MS", {
3604
+ enumerable: true,
3605
+ get: function() {
3606
+ return MINUTE_MS;
3607
+ }
3608
+ });
3609
+ Object.defineProperty(exports, "MIN_CUSTOM_MINUTES", {
3610
+ enumerable: true,
3611
+ get: function() {
3612
+ return MIN_CUSTOM_MINUTES;
3613
+ }
3614
+ });
2836
3615
  Object.defineProperty(exports, "NUMERIC_AGGREGATES", {
2837
3616
  enumerable: true,
2838
3617
  get: function() {
@@ -2845,6 +3624,30 @@ Object.defineProperty(exports, "RESERVED_BINDING_NAMES", {
2845
3624
  return RESERVED_BINDING_NAMES;
2846
3625
  }
2847
3626
  });
3627
+ Object.defineProperty(exports, "RESET_PERIODS", {
3628
+ enumerable: true,
3629
+ get: function() {
3630
+ return RESET_PERIODS;
3631
+ }
3632
+ });
3633
+ Object.defineProperty(exports, "ROLLING_SPANS", {
3634
+ enumerable: true,
3635
+ get: function() {
3636
+ return ROLLING_SPANS;
3637
+ }
3638
+ });
3639
+ Object.defineProperty(exports, "RollingWindowSchema", {
3640
+ enumerable: true,
3641
+ get: function() {
3642
+ return RollingWindowSchema;
3643
+ }
3644
+ });
3645
+ Object.defineProperty(exports, "SERIES_KINDS", {
3646
+ enumerable: true,
3647
+ get: function() {
3648
+ return SERIES_KINDS;
3649
+ }
3650
+ });
2848
3651
  Object.defineProperty(exports, "SOURCE_CAPS", {
2849
3652
  enumerable: true,
2850
3653
  get: function() {
@@ -2869,6 +3672,30 @@ Object.defineProperty(exports, "SOURCE_DEVICE_TYPES", {
2869
3672
  return SOURCE_DEVICE_TYPES;
2870
3673
  }
2871
3674
  });
3675
+ Object.defineProperty(exports, "STATISTIC_STATS", {
3676
+ enumerable: true,
3677
+ get: function() {
3678
+ return STATISTIC_STATS;
3679
+ }
3680
+ });
3681
+ Object.defineProperty(exports, "StatisticHelperSpecSchema", {
3682
+ enumerable: true,
3683
+ get: function() {
3684
+ return StatisticHelperSpecSchema;
3685
+ }
3686
+ });
3687
+ Object.defineProperty(exports, "StatisticWindowSchema", {
3688
+ enumerable: true,
3689
+ get: function() {
3690
+ return StatisticWindowSchema;
3691
+ }
3692
+ });
3693
+ Object.defineProperty(exports, "applianceDeviceType", {
3694
+ enumerable: true,
3695
+ get: function() {
3696
+ return applianceDeviceType;
3697
+ }
3698
+ });
2872
3699
  Object.defineProperty(exports, "audioPlanFromEncodeProfile", {
2873
3700
  enumerable: true,
2874
3701
  get: function() {
@@ -3031,6 +3858,12 @@ Object.defineProperty(exports, "evaluateStatefulExpressionCall", {
3031
3858
  return evaluateStatefulExpressionCall;
3032
3859
  }
3033
3860
  });
3861
+ Object.defineProperty(exports, "evaluateStatistic", {
3862
+ enumerable: true,
3863
+ get: function() {
3864
+ return evaluateStatistic;
3865
+ }
3866
+ });
3034
3867
  Object.defineProperty(exports, "featureFieldEntries", {
3035
3868
  enumerable: true,
3036
3869
  get: function() {
@@ -3067,12 +3900,36 @@ Object.defineProperty(exports, "getFfmpegDownloadUrl", {
3067
3900
  return getFfmpegDownloadUrl;
3068
3901
  }
3069
3902
  });
3903
+ Object.defineProperty(exports, "helperMembers", {
3904
+ enumerable: true,
3905
+ get: function() {
3906
+ return helperMembers;
3907
+ }
3908
+ });
3909
+ Object.defineProperty(exports, "integralCadenceMs", {
3910
+ enumerable: true,
3911
+ get: function() {
3912
+ return integralCadenceMs;
3913
+ }
3914
+ });
3915
+ Object.defineProperty(exports, "integrateReading", {
3916
+ enumerable: true,
3917
+ get: function() {
3918
+ return integrateReading;
3919
+ }
3920
+ });
3070
3921
  Object.defineProperty(exports, "invocationFromEncodeProfile", {
3071
3922
  enumerable: true,
3072
3923
  get: function() {
3073
3924
  return invocationFromEncodeProfile;
3074
3925
  }
3075
3926
  });
3927
+ Object.defineProperty(exports, "isApplianceKind", {
3928
+ enumerable: true,
3929
+ get: function() {
3930
+ return isApplianceKind;
3931
+ }
3932
+ });
3076
3933
  Object.defineProperty(exports, "isSoftwareDecode", {
3077
3934
  enumerable: true,
3078
3935
  get: function() {
@@ -3097,6 +3954,30 @@ Object.defineProperty(exports, "logBannerArgs", {
3097
3954
  return logBannerArgs;
3098
3955
  }
3099
3956
  });
3957
+ Object.defineProperty(exports, "maxDurationMs", {
3958
+ enumerable: true,
3959
+ get: function() {
3960
+ return maxDurationMs;
3961
+ }
3962
+ });
3963
+ Object.defineProperty(exports, "nextLocalMidnight", {
3964
+ enumerable: true,
3965
+ get: function() {
3966
+ return nextLocalMidnight;
3967
+ }
3968
+ });
3969
+ Object.defineProperty(exports, "openReset", {
3970
+ enumerable: true,
3971
+ get: function() {
3972
+ return openReset;
3973
+ }
3974
+ });
3975
+ Object.defineProperty(exports, "openStatistic", {
3976
+ enumerable: true,
3977
+ get: function() {
3978
+ return openStatistic;
3979
+ }
3980
+ });
3100
3981
  Object.defineProperty(exports, "parseExpression", {
3101
3982
  enumerable: true,
3102
3983
  get: function() {
@@ -3109,12 +3990,30 @@ Object.defineProperty(exports, "pickVideoEncoder", {
3109
3990
  return pickVideoEncoder;
3110
3991
  }
3111
3992
  });
3993
+ Object.defineProperty(exports, "planResetTier", {
3994
+ enumerable: true,
3995
+ get: function() {
3996
+ return planResetTier;
3997
+ }
3998
+ });
3999
+ Object.defineProperty(exports, "planStatisticTier", {
4000
+ enumerable: true,
4001
+ get: function() {
4002
+ return planStatisticTier;
4003
+ }
4004
+ });
3112
4005
  Object.defineProperty(exports, "resolveStreamMaps", {
3113
4006
  enumerable: true,
3114
4007
  get: function() {
3115
4008
  return resolveStreamMaps;
3116
4009
  }
3117
4010
  });
4011
+ Object.defineProperty(exports, "rollingDurationMs", {
4012
+ enumerable: true,
4013
+ get: function() {
4014
+ return rollingDurationMs;
4015
+ }
4016
+ });
3118
4017
  Object.defineProperty(exports, "sliceActiveValue", {
3119
4018
  enumerable: true,
3120
4019
  get: function() {
@@ -3127,6 +4026,18 @@ Object.defineProperty(exports, "sliceChangedAt", {
3127
4026
  return sliceChangedAt;
3128
4027
  }
3129
4028
  });
4029
+ Object.defineProperty(exports, "sourcePickForAppliance", {
4030
+ enumerable: true,
4031
+ get: function() {
4032
+ return sourcePickForAppliance;
4033
+ }
4034
+ });
4035
+ Object.defineProperty(exports, "statisticCadenceMs", {
4036
+ enumerable: true,
4037
+ get: function() {
4038
+ return statisticCadenceMs;
4039
+ }
4040
+ });
3130
4041
  Object.defineProperty(exports, "toExpressionValue", {
3131
4042
  enumerable: true,
3132
4043
  get: function() {
@@ -3145,3 +4056,9 @@ Object.defineProperty(exports, "validateExpressionSource", {
3145
4056
  return validateExpressionSource;
3146
4057
  }
3147
4058
  });
4059
+ Object.defineProperty(exports, "wattMillisecondsToKwh", {
4060
+ enumerable: true,
4061
+ get: function() {
4062
+ return wattMillisecondsToKwh;
4063
+ }
4064
+ });