@camstack/types 1.2.443 → 1.2.444
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/CHANGELOG.md +13 -0
- package/dist/addon.d.ts +5 -1
- package/dist/addon.js +21 -5
- package/dist/addon.mjs +17 -6
- package/dist/automation/export-entities.d.ts +98 -0
- package/dist/capabilities/capability-definition.d.ts +1 -1
- package/dist/capabilities/composer.cap.d.ts +34 -0
- package/dist/capabilities/consumables.cap.d.ts +4 -5
- package/dist/capabilities/core-blocks.cap.d.ts +244 -0
- package/dist/capabilities/device-export.cap.d.ts +111 -1
- package/dist/capabilities/index.d.ts +5 -3
- package/dist/capabilities/metrics-provider.cap.d.ts +16 -16
- package/dist/capabilities/nodes.cap.d.ts +2 -2
- package/dist/capabilities/pet-fountain.cap.d.ts +138 -0
- package/dist/capabilities/pipeline-executor.cap.d.ts +6 -22
- package/dist/capabilities/pipeline-orchestrator.cap.d.ts +2 -2
- package/dist/capabilities/pipeline-runner.cap.d.ts +2 -2
- package/dist/capabilities/pipeline-step-input.d.ts +33 -0
- package/dist/client.js +817 -798
- package/dist/client.mjs +817 -798
- package/dist/composition/composition-items.d.ts +3 -3
- package/dist/composition/composition-report.d.ts +17 -0
- package/dist/composition/composition.d.ts +68 -1
- package/dist/composition/index.d.ts +2 -0
- package/dist/composition/presets/pet-fountain.d.ts +36 -0
- package/dist/composition/validate-forward.d.ts +31 -0
- package/dist/{composition-C0dlyG9U.js → composition-CO6Sak-s.js} +49 -5
- package/dist/{composition-bIBW5_13.mjs → composition-kSuOifuG.mjs} +32 -6
- package/dist/device/cap-vocabulary/entries/appliances.d.ts +1 -1
- package/dist/device/device-control-resolution.d.ts +1 -1
- package/dist/device/device-type.d.ts +4 -0
- package/dist/{err-msg-BCdlR2Li.mjs → err-msg-DWXWc0Di.mjs} +4 -0
- package/dist/{err-msg-COHgq7Mb.js → err-msg-EJhsFHqa.js} +4 -0
- package/dist/generated/addon-api.d.ts +134 -32
- package/dist/generated/addon-cap-facts.d.ts +1 -1
- package/dist/generated/cap-status-types.d.ts +3 -1
- package/dist/generated/capability-router-map.d.ts +5 -2
- package/dist/generated/collection-array-methods.d.ts +2 -2
- package/dist/generated/customize-catalog.d.ts +1 -1
- package/dist/generated/device-local-state.d.ts +3 -0
- package/dist/generated/device-proxy.d.ts +3 -0
- package/dist/generated/device-scoped-caps.d.ts +1 -1
- package/dist/generated/history-catalog.d.ts +1 -1
- package/dist/generated/method-access-map.d.ts +1 -1
- package/dist/generated/method-device-selectors.d.ts +1 -1
- package/dist/generated/runtime-state-durability.d.ts +1 -1
- package/dist/generated/system-proxy.d.ts +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1427 -602
- package/dist/index.mjs +1395 -591
- package/dist/interfaces/agent.d.ts +6 -2
- package/dist/interfaces/event-bus.d.ts +1 -1
- package/dist/node.js +2 -2
- package/dist/node.mjs +2 -2
- package/dist/{sleep-C_u6cEAJ.mjs → sleep-6eG9C8Xl.mjs} +223 -72
- package/dist/{sleep-E7qAQwTE.js → sleep-UXDHn-oJ.js} +246 -71
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_sleep = require("./sleep-
|
|
2
|
+
const require_sleep = require("./sleep-UXDHn-oJ.js");
|
|
3
3
|
const require_event_category = require("./event-category-E17zaHjN.js");
|
|
4
|
-
const require_composition = require("./composition-
|
|
4
|
+
const require_composition = require("./composition-CO6Sak-s.js");
|
|
5
5
|
const require_node_color = require("./node-color.js");
|
|
6
|
-
const require_err_msg = require("./err-msg-
|
|
6
|
+
const require_err_msg = require("./err-msg-EJhsFHqa.js");
|
|
7
7
|
const require_enums = require("./enums.js");
|
|
8
8
|
let zod = require("zod");
|
|
9
9
|
//#region src/media/media-owner-key.ts
|
|
@@ -10705,6 +10705,593 @@ function buildActionSteps(steps, vars, deps) {
|
|
|
10705
10705
|
});
|
|
10706
10706
|
}
|
|
10707
10707
|
//#endregion
|
|
10708
|
+
//#region src/capabilities/notification-output.cap.ts
|
|
10709
|
+
/**
|
|
10710
|
+
* notification-output — canonical, capability-gated notification delivery.
|
|
10711
|
+
*
|
|
10712
|
+
* Apprise-derived model (see
|
|
10713
|
+
* `docs/superpowers/specs/2026-07-03-notification-output-notifier-matrix.md`):
|
|
10714
|
+
* callers emit ONE canonical `Notification`; each provider declares a
|
|
10715
|
+
* per-kind capability descriptor (`TargetKind`), and the pure degrade
|
|
10716
|
+
* engine (`@camstack/types` `prepareNotification`) transcodes / degrades the
|
|
10717
|
+
* message to what the kind supports — callers never special-case a service.
|
|
10718
|
+
*
|
|
10719
|
+
* DESIGN DECISIONS (locked):
|
|
10720
|
+
* - Target CRUD lives on THIS cap (`upsertTarget` / `deleteTarget` /
|
|
10721
|
+
* `setTargetEnabled`), each provider persisting via the `settings-store`
|
|
10722
|
+
* cap. Rationale: the admin UI needs one uniform surface across the
|
|
10723
|
+
* notifiers addon AND the HA addon; the addon-`globalSettingsSchema`-array
|
|
10724
|
+
* alternative would fork the UI per addon and cannot host the
|
|
10725
|
+
* discovery→adopt flow.
|
|
10726
|
+
* - `listTargetKinds` / `listTargets` / `discoverTargets` return arrays →
|
|
10727
|
+
* the generated cap-mount auto-`concatCollection`-fans them across every
|
|
10728
|
+
* registered provider (notifiers addon + HA addon) so one catalog is
|
|
10729
|
+
* routable. `send` / `testTarget` / CRUD route to ONE provider by the
|
|
10730
|
+
* `addonId` the generated collection router extracts from the call input.
|
|
10731
|
+
* - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
|
|
10732
|
+
* transformer) + UDS MsgPack both round-trip typed arrays — already used by
|
|
10733
|
+
* `storage` / `storage-provider` / `recording` caps over the same path. No
|
|
10734
|
+
* base64 fallback needed.
|
|
10735
|
+
*
|
|
10736
|
+
* TODO (deferred, closed-set change — separate decision): add
|
|
10737
|
+
* `providerKind: 'notify'` so notification providers surface on the unified
|
|
10738
|
+
* admin "Integrations" page.
|
|
10739
|
+
*/
|
|
10740
|
+
/**
|
|
10741
|
+
* Zentik-derived typed-media enum — the superset across every kind. Each
|
|
10742
|
+
* adapter picks what it supports and the degrade engine filters the rest.
|
|
10743
|
+
*/
|
|
10744
|
+
var AttachmentMediaTypeSchema = zod.z.enum([
|
|
10745
|
+
"image",
|
|
10746
|
+
"video",
|
|
10747
|
+
"gif",
|
|
10748
|
+
"audio",
|
|
10749
|
+
"icon"
|
|
10750
|
+
]);
|
|
10751
|
+
/**
|
|
10752
|
+
* A single attachment. Exactly one of `url` (remote source, most adapters
|
|
10753
|
+
* prefer this) or `bytes` (inline source; required for Pushover-style
|
|
10754
|
+
* bytes-only kinds) MUST be present — the degrade engine expresses a
|
|
10755
|
+
* url→bytes fetch as a `needsFetch` directive the adapter executes.
|
|
10756
|
+
*/
|
|
10757
|
+
var AttachmentSchema = zod.z.object({
|
|
10758
|
+
mediaType: AttachmentMediaTypeSchema,
|
|
10759
|
+
url: zod.z.string().optional(),
|
|
10760
|
+
bytes: zod.z.instanceof(Uint8Array).optional(),
|
|
10761
|
+
mime: zod.z.string().optional(),
|
|
10762
|
+
name: zod.z.string().optional()
|
|
10763
|
+
}).refine((a) => a.url !== void 0 || a.bytes !== void 0, { message: "Attachment requires either `url` or `bytes`" });
|
|
10764
|
+
var NotificationFormatSchema = zod.z.enum([
|
|
10765
|
+
"text",
|
|
10766
|
+
"markdown",
|
|
10767
|
+
"html"
|
|
10768
|
+
]);
|
|
10769
|
+
/**
|
|
10770
|
+
* The CLOSED icon vocabulary an action button may use.
|
|
10771
|
+
*
|
|
10772
|
+
* A closed set, not a free string, and that is the whole point: an arbitrary
|
|
10773
|
+
* icon name is one that ntfy renders, zentik silently drops, and nobody
|
|
10774
|
+
* notices — the same class of gap as a zone vocabulary nothing produced
|
|
10775
|
+
* ([D35](../../../docs/decisions/adr-0035.md)). Every adapter maps this set or
|
|
10776
|
+
* declares `actionIcons: false` and the degrade engine strips the field.
|
|
10777
|
+
*
|
|
10778
|
+
* Named by INTENT, never by glyph. "check" would tie the vocabulary to one
|
|
10779
|
+
* renderer's icon set; "acknowledge" survives an adapter that draws it
|
|
10780
|
+
* differently.
|
|
10781
|
+
*
|
|
10782
|
+
* ── A TOKEN IS NOT A WIRE VALUE ─────────────────────────────────────
|
|
10783
|
+
*
|
|
10784
|
+
* These names are for US. **No adapter may forward one verbatim.** Each maps
|
|
10785
|
+
* the whole set onto its own renderer's vocabulary through a
|
|
10786
|
+
* `Record<NotificationActionIcon, string>` — a Record, never a lookup with a
|
|
10787
|
+
* fallback, so adding a member here fails every adapter's build until someone
|
|
10788
|
+
* decides its glyph, which is the only place that decision can be made
|
|
10789
|
+
* honestly.
|
|
10790
|
+
*
|
|
10791
|
+
* This paragraph is the bug. Zentik declared `actionIcons: true` and passed
|
|
10792
|
+
* `disarm` straight through; iOS feeds that string to
|
|
10793
|
+
* `UNNotificationActionIcon(systemImageName:)`, `disarm` is not an SF Symbol,
|
|
10794
|
+
* and every snooze and alarm button arrived BLANK. A pass-through is not a
|
|
10795
|
+
* mapping, and "the field is documented" is not "the value renders".
|
|
10796
|
+
*
|
|
10797
|
+
* Adding a member is TRAIN-BOUND. The enum lives in the published
|
|
10798
|
+
* `@camstack/server` closure and the cap seam validates against the HUB's copy,
|
|
10799
|
+
* so an addon that emits a token the running hub does not know does not lose an
|
|
10800
|
+
* icon — its whole `send` fails Zod validation and the notification never
|
|
10801
|
+
* arrives. Never emit a new token from an addon before the train carrying it.
|
|
10802
|
+
*/
|
|
10803
|
+
var NotificationActionIconSchema = zod.z.enum([
|
|
10804
|
+
"acknowledge",
|
|
10805
|
+
"dismiss",
|
|
10806
|
+
"silence",
|
|
10807
|
+
"snooze",
|
|
10808
|
+
"view",
|
|
10809
|
+
"play",
|
|
10810
|
+
"open",
|
|
10811
|
+
"close",
|
|
10812
|
+
"lock",
|
|
10813
|
+
"unlock",
|
|
10814
|
+
"arm",
|
|
10815
|
+
"arm-home",
|
|
10816
|
+
"arm-away",
|
|
10817
|
+
"arm-night",
|
|
10818
|
+
"disarm",
|
|
10819
|
+
"light",
|
|
10820
|
+
"alert",
|
|
10821
|
+
"camera"
|
|
10822
|
+
]);
|
|
10823
|
+
/** A single tap-through action button. */
|
|
10824
|
+
var NotificationActionSchema = zod.z.object({
|
|
10825
|
+
id: zod.z.string(),
|
|
10826
|
+
label: zod.z.string(),
|
|
10827
|
+
url: zod.z.string().optional(),
|
|
10828
|
+
/** Dropped by the degrade engine for a kind with `caps.actionIcons: false`. */
|
|
10829
|
+
icon: NotificationActionIconSchema.optional(),
|
|
10830
|
+
/**
|
|
10831
|
+
* Renders in a warning style where the notifier supports it.
|
|
10832
|
+
*
|
|
10833
|
+
* A HINT, never a gate. The callback's authority is its token and nothing
|
|
10834
|
+
* else — see `notification-center/action-token.ts` for what that does and
|
|
10835
|
+
* does not buy.
|
|
10836
|
+
*/
|
|
10837
|
+
destructive: zod.z.boolean().optional(),
|
|
10838
|
+
/**
|
|
10839
|
+
* How the tap should REACH the url.
|
|
10840
|
+
*
|
|
10841
|
+
* `navigate` (absent, and every button authored before this field) opens it:
|
|
10842
|
+
* the phone leaves the notification and shows whatever the callback returns.
|
|
10843
|
+
* That is right for a button whose answer the operator wants to read.
|
|
10844
|
+
*
|
|
10845
|
+
* `background` fires it as a POST and stays put. It exists for the buttons
|
|
10846
|
+
* whose whole point is not to interrupt — "silence this for 30 minutes" is
|
|
10847
|
+
* an answer to the notification, and being thrown into a browser tab to
|
|
10848
|
+
* confirm it costs more attention than the notification did. A backend that
|
|
10849
|
+
* cannot do a background call renders it as an ordinary link (the adapters
|
|
10850
|
+
* fall back rather than dropping the button), so this is a preference, never
|
|
10851
|
+
* a requirement.
|
|
10852
|
+
*/
|
|
10853
|
+
mode: zod.z.enum(["navigate", "background"]).optional()
|
|
10854
|
+
});
|
|
10855
|
+
/** A delivery parameter value: what a notifier declared it takes. */
|
|
10856
|
+
var DeliveryParamValueSchema = zod.z.union([
|
|
10857
|
+
zod.z.string(),
|
|
10858
|
+
zod.z.number(),
|
|
10859
|
+
zod.z.boolean()
|
|
10860
|
+
]);
|
|
10861
|
+
/**
|
|
10862
|
+
* One extra delivery parameter a notifier KIND declares (D938). A rule that
|
|
10863
|
+
* addresses a target of that kind may set it; a kind that declares nothing is
|
|
10864
|
+
* never handed one. The admin UI derives its control from this descriptor —
|
|
10865
|
+
* no editor knows a service by name.
|
|
10866
|
+
*
|
|
10867
|
+
* Optional fields are `.optional()`, never `.default()` (a Zod default does not
|
|
10868
|
+
* run on the addon cap path).
|
|
10869
|
+
*/
|
|
10870
|
+
var DeliveryParamSchema = zod.z.object({
|
|
10871
|
+
key: zod.z.string().min(1),
|
|
10872
|
+
label: zod.z.string(),
|
|
10873
|
+
/** i18n key of the label, resolved by the declaring addon's namespace. */
|
|
10874
|
+
labelKey: zod.z.string().optional(),
|
|
10875
|
+
type: zod.z.enum([
|
|
10876
|
+
"enum",
|
|
10877
|
+
"number",
|
|
10878
|
+
"boolean",
|
|
10879
|
+
"string"
|
|
10880
|
+
]),
|
|
10881
|
+
/** `enum` only: the closed set of accepted values. */
|
|
10882
|
+
options: zod.z.array(zod.z.object({
|
|
10883
|
+
value: zod.z.string(),
|
|
10884
|
+
label: zod.z.string()
|
|
10885
|
+
})).optional(),
|
|
10886
|
+
/** `number` only. */
|
|
10887
|
+
min: zod.z.number().optional(),
|
|
10888
|
+
max: zod.z.number().optional(),
|
|
10889
|
+
/** What the notifier does when the rule sets nothing; shown as the placeholder. */
|
|
10890
|
+
default: DeliveryParamValueSchema.optional()
|
|
10891
|
+
});
|
|
10892
|
+
/**
|
|
10893
|
+
* The canonical notification. `body` is the only hard field (Apprise model).
|
|
10894
|
+
* `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
|
|
10895
|
+
* NOT a fixed severity enum — each kind declares its own `caps.levels` and
|
|
10896
|
+
* the adapter maps this ordinal onto its native level. `level?` is an
|
|
10897
|
+
* optional kind-native level id (`emergency`, `silent`, …) that overrides
|
|
10898
|
+
* `priority` for that one target.
|
|
10899
|
+
*/
|
|
10900
|
+
var NotificationSchema = zod.z.object({
|
|
10901
|
+
body: zod.z.string(),
|
|
10902
|
+
title: zod.z.string().optional(),
|
|
10903
|
+
format: NotificationFormatSchema.default("text"),
|
|
10904
|
+
priority: zod.z.number().int().min(1).max(5).default(3),
|
|
10905
|
+
level: zod.z.string().optional(),
|
|
10906
|
+
attachments: zod.z.array(AttachmentSchema).optional(),
|
|
10907
|
+
clickUrl: zod.z.string().optional(),
|
|
10908
|
+
actions: zod.z.array(NotificationActionSchema).optional(),
|
|
10909
|
+
sound: zod.z.string().optional(),
|
|
10910
|
+
ttl: zod.z.number().optional(),
|
|
10911
|
+
tag: zod.z.string().optional(),
|
|
10912
|
+
deviceId: zod.z.number().optional(),
|
|
10913
|
+
eventId: zod.z.string().optional(),
|
|
10914
|
+
metadata: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
|
|
10915
|
+
/**
|
|
10916
|
+
* Values for the parameters the target's kind DECLARES in
|
|
10917
|
+
* {@link TargetKindSchema} `deliveryParams`. Already validated against the
|
|
10918
|
+
* declaration by the sender; a notifier reads only the keys it declared.
|
|
10919
|
+
*/
|
|
10920
|
+
delivery: zod.z.record(zod.z.string(), DeliveryParamValueSchema).optional()
|
|
10921
|
+
});
|
|
10922
|
+
/** One declared native severity/priority level for a kind. */
|
|
10923
|
+
var TargetKindLevelSchema = zod.z.object({
|
|
10924
|
+
id: zod.z.string(),
|
|
10925
|
+
label: zod.z.string(),
|
|
10926
|
+
/** Which canonical priority (1..5) this level maps to. `null` = qualitative-only. */
|
|
10927
|
+
ordinal: zod.z.number().int().min(1).max(5).nullable(),
|
|
10928
|
+
flags: zod.z.object({
|
|
10929
|
+
critical: zod.z.boolean().optional(),
|
|
10930
|
+
silent: zod.z.boolean().optional(),
|
|
10931
|
+
noPush: zod.z.boolean().optional()
|
|
10932
|
+
}).optional(),
|
|
10933
|
+
/** e.g. Pushover `emergency` requires `retry` / `expire`. */
|
|
10934
|
+
requires: zod.z.array(zod.z.string()).optional(),
|
|
10935
|
+
description: zod.z.string().optional()
|
|
10936
|
+
});
|
|
10937
|
+
/** Attachment capabilities for a kind (drives the degrade engine + test panel). */
|
|
10938
|
+
var TargetKindAttachmentsCapsSchema = zod.z.object({
|
|
10939
|
+
mediaTypes: zod.z.array(AttachmentMediaTypeSchema),
|
|
10940
|
+
mode: zod.z.enum([
|
|
10941
|
+
"url",
|
|
10942
|
+
"bytes",
|
|
10943
|
+
"both"
|
|
10944
|
+
]),
|
|
10945
|
+
max: zod.z.number().int().nonnegative(),
|
|
10946
|
+
maxBytes: zod.z.number().int().positive().optional()
|
|
10947
|
+
});
|
|
10948
|
+
/** The full capability block consulted before dispatch. */
|
|
10949
|
+
var TargetKindCapsSchema = zod.z.object({
|
|
10950
|
+
attachments: TargetKindAttachmentsCapsSchema,
|
|
10951
|
+
/** Max action buttons (0 = none). */
|
|
10952
|
+
actions: zod.z.number().int().nonnegative(),
|
|
10953
|
+
/**
|
|
10954
|
+
* Whether this kind renders a per-action ICON.
|
|
10955
|
+
*
|
|
10956
|
+
* `.optional()`, deliberately NOT `.default(false)`: a Zod default does not
|
|
10957
|
+
* run on the addon cap path — three production failures in one day taught
|
|
10958
|
+
* this repo that once. Absent is read as false by the degrade engine, which
|
|
10959
|
+
* is the safe direction: an icon that is not rendered costs nothing, an icon
|
|
10960
|
+
* assumed and dropped costs the operator's trust in the field.
|
|
10961
|
+
*/
|
|
10962
|
+
actionIcons: zod.z.boolean().optional(),
|
|
10963
|
+
levels: zod.z.array(TargetKindLevelSchema),
|
|
10964
|
+
format: zod.z.array(NotificationFormatSchema),
|
|
10965
|
+
clickUrl: zod.z.boolean(),
|
|
10966
|
+
sound: zod.z.boolean(),
|
|
10967
|
+
ttl: zod.z.boolean(),
|
|
10968
|
+
bodyMaxLen: zod.z.number().int().positive()
|
|
10969
|
+
});
|
|
10970
|
+
/**
|
|
10971
|
+
* `configSchema` is a `ConfigUISchema` tree passed through to the admin
|
|
10972
|
+
* FormBuilder. Stored as `z.unknown()` at the cap seam (mirrors
|
|
10973
|
+
* `device-provider.getChildCreationSchema` `CreationSchemaOutputSchema`) —
|
|
10974
|
+
* the union is large and not meant for runtime validation here; the exported
|
|
10975
|
+
* `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
|
|
10976
|
+
*/
|
|
10977
|
+
var ConfigSchemaPassthrough$3 = zod.z.unknown();
|
|
10978
|
+
var TargetKindSchema = zod.z.object({
|
|
10979
|
+
kind: zod.z.string(),
|
|
10980
|
+
label: zod.z.string(),
|
|
10981
|
+
icon: zod.z.string(),
|
|
10982
|
+
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
10983
|
+
addonId: zod.z.string(),
|
|
10984
|
+
/**
|
|
10985
|
+
* URL of the kind's bundled BRAND icon, served by the providing addon over
|
|
10986
|
+
* its own `addon-routes` surface (`/addon/<addonId>/icons/<kind>`). Absent
|
|
10987
|
+
* when the addon bundles no icon for that kind — the client then falls back
|
|
10988
|
+
* to a neutral glyph rather than rendering the raw `icon` NAME as text.
|
|
10989
|
+
*
|
|
10990
|
+
* Root-relative on purpose: it resolves against whatever origin serves a web
|
|
10991
|
+
* client, and a native client joins it onto its own hub base.
|
|
10992
|
+
*
|
|
10993
|
+
* DECLARED here deliberately. It used to travel as an undeclared passthrough
|
|
10994
|
+
* field that survived only because the runtime cap-router forwards provider
|
|
10995
|
+
* output verbatim — so every consumer had to re-declare it by hand to stop
|
|
10996
|
+
* its own Zod parse from stripping it, and the whole arrangement would have
|
|
10997
|
+
* broken silently the moment output validation was tightened anywhere.
|
|
10998
|
+
*/
|
|
10999
|
+
iconUrl: zod.z.string().optional(),
|
|
11000
|
+
/**
|
|
11001
|
+
* Media type of {@link iconUrl} (`image/svg+xml`, `image/png`, …).
|
|
11002
|
+
*
|
|
11003
|
+
* The server knows this and therefore says it, because the client cannot
|
|
11004
|
+
* safely guess: a React-Native client renders SVG and raster through two
|
|
11005
|
+
* DIFFERENT components (`react-native-svg` vs `expo-image` — expo-image does
|
|
11006
|
+
* not decode SVG on iOS/Android), so without this it silently fell back to a
|
|
11007
|
+
* placeholder glyph for every vector icon while the web build looked fine.
|
|
11008
|
+
*
|
|
11009
|
+
* Absent when {@link iconUrl} is absent, or for a legacy provider that has
|
|
11010
|
+
* not been updated — a client that cannot determine the type should prefer
|
|
11011
|
+
* its raster path, which is the safe default for an unknown image.
|
|
11012
|
+
*/
|
|
11013
|
+
iconMediaType: zod.z.string().optional(),
|
|
11014
|
+
configSchema: ConfigSchemaPassthrough$3,
|
|
11015
|
+
/**
|
|
11016
|
+
* The config keys that decide WHERE this kind's secrets are sent (server,
|
|
11017
|
+
* base URL, instance, chat, recipient). A save that changes any of them
|
|
11018
|
+
* while leaving a secret redacted is refused by the provider (D634), so an
|
|
11019
|
+
* editor uses this to ask for the secret on exactly those edits instead of
|
|
11020
|
+
* on every edit.
|
|
11021
|
+
*
|
|
11022
|
+
* Optional: absent from a provider that holds no secret (the Home Assistant
|
|
11023
|
+
* kinds) and from a provider older than this field — an editor that finds
|
|
11024
|
+
* it absent must assume ANY edit may need the secret.
|
|
11025
|
+
*/
|
|
11026
|
+
destinationKeys: zod.z.array(zod.z.string()).optional(),
|
|
11027
|
+
supportsDiscovery: zod.z.boolean(),
|
|
11028
|
+
/**
|
|
11029
|
+
* Extra delivery parameters a rule may set for a target of this kind (D938).
|
|
11030
|
+
* Absent = none; the rule editor then offers nothing.
|
|
11031
|
+
*/
|
|
11032
|
+
deliveryParams: zod.z.array(DeliveryParamSchema).optional(),
|
|
11033
|
+
caps: TargetKindCapsSchema
|
|
11034
|
+
});
|
|
11035
|
+
/**
|
|
11036
|
+
* A persisted target. `config` holds secrets; providers REDACT secret fields
|
|
11037
|
+
* (return a presence marker only) when serving `listTargets` — never
|
|
11038
|
+
* round-trip a stored secret to the UI.
|
|
11039
|
+
*/
|
|
11040
|
+
var TargetSchema = zod.z.object({
|
|
11041
|
+
id: zod.z.string(),
|
|
11042
|
+
name: zod.z.string(),
|
|
11043
|
+
kind: zod.z.string(),
|
|
11044
|
+
addonId: zod.z.string(),
|
|
11045
|
+
enabled: zod.z.boolean(),
|
|
11046
|
+
config: zod.z.record(zod.z.string(), zod.z.unknown())
|
|
11047
|
+
});
|
|
11048
|
+
/** A discovery-surfaced candidate (config is partial + non-secret). */
|
|
11049
|
+
var DiscoveredTargetSchema = zod.z.object({
|
|
11050
|
+
kind: zod.z.string(),
|
|
11051
|
+
suggestedName: zod.z.string(),
|
|
11052
|
+
config: zod.z.record(zod.z.string(), zod.z.unknown())
|
|
11053
|
+
});
|
|
11054
|
+
/** The degrade engine's report — what was resolved / dropped / degraded. */
|
|
11055
|
+
var RenderedAsSchema = zod.z.object({
|
|
11056
|
+
level: zod.z.string(),
|
|
11057
|
+
format: NotificationFormatSchema,
|
|
11058
|
+
attachmentsSent: zod.z.number().int().nonnegative(),
|
|
11059
|
+
actionsSent: zod.z.number().int().nonnegative(),
|
|
11060
|
+
truncated: zod.z.boolean(),
|
|
11061
|
+
dropped: zod.z.array(zod.z.string())
|
|
11062
|
+
});
|
|
11063
|
+
var SendResultSchema = zod.z.object({
|
|
11064
|
+
success: zod.z.boolean(),
|
|
11065
|
+
error: zod.z.string().optional(),
|
|
11066
|
+
renderedAs: RenderedAsSchema.optional()
|
|
11067
|
+
});
|
|
11068
|
+
/** Same shape as SendResult — kept as a distinct name for the test panel. */
|
|
11069
|
+
var TestResultSchema = SendResultSchema;
|
|
11070
|
+
/**
|
|
11071
|
+
* Pre-save credential probe against a partial (unsaved) target config.
|
|
11072
|
+
* `resolvedUrl` never includes secrets (token stripped from path).
|
|
11073
|
+
*/
|
|
11074
|
+
var ProbeTargetConfigResultSchema = zod.z.object({
|
|
11075
|
+
ok: zod.z.boolean(),
|
|
11076
|
+
resolvedUrl: zod.z.string(),
|
|
11077
|
+
httpStatus: zod.z.number().int().optional(),
|
|
11078
|
+
stateInstance: zod.z.string().optional(),
|
|
11079
|
+
error: zod.z.string().optional()
|
|
11080
|
+
});
|
|
11081
|
+
var notificationOutputCapability = {
|
|
11082
|
+
name: "notification-output",
|
|
11083
|
+
scope: "system",
|
|
11084
|
+
mode: "collection",
|
|
11085
|
+
methods: {
|
|
11086
|
+
listTargetKinds: require_sleep.method(zod.z.object({}), zod.z.array(TargetKindSchema)),
|
|
11087
|
+
listTargets: require_sleep.method(zod.z.object({}), zod.z.array(TargetSchema), { auth: "admin" }),
|
|
11088
|
+
/**
|
|
11089
|
+
* One target WITH secrets — admin edit / duplicate hydration only.
|
|
11090
|
+
* `listTargets` stays redacted; the editor loads this so password fields
|
|
11091
|
+
* are filled (masked in the input) and a save can round-trip the token
|
|
11092
|
+
* when a destination changes (Duplicate with a new chatId, etc.).
|
|
11093
|
+
*/
|
|
11094
|
+
getTarget: require_sleep.method(zod.z.object({ targetId: zod.z.string() }), TargetSchema, { auth: "admin" }),
|
|
11095
|
+
discoverTargets: require_sleep.method(zod.z.object({
|
|
11096
|
+
kind: zod.z.string(),
|
|
11097
|
+
config: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
|
|
11098
|
+
/**
|
|
11099
|
+
* When editing / duplicating, the blank password field never round-trips
|
|
11100
|
+
* the stored token. Pass the source target id so the provider can restore
|
|
11101
|
+
* secrets server-side before dialling (same merge as upsert).
|
|
11102
|
+
*/
|
|
11103
|
+
targetId: zod.z.string().optional()
|
|
11104
|
+
}), zod.z.array(DiscoveredTargetSchema), { auth: "admin" }),
|
|
11105
|
+
probeTargetConfig: require_sleep.method(zod.z.object({
|
|
11106
|
+
kind: zod.z.string(),
|
|
11107
|
+
config: zod.z.record(zod.z.string(), zod.z.unknown()),
|
|
11108
|
+
/** See `discoverTargets.targetId` — restore stored secrets for a blank password. */
|
|
11109
|
+
targetId: zod.z.string().optional()
|
|
11110
|
+
}), ProbeTargetConfigResultSchema, {
|
|
11111
|
+
kind: "mutation",
|
|
11112
|
+
auth: "admin"
|
|
11113
|
+
}),
|
|
11114
|
+
send: require_sleep.method(zod.z.object({
|
|
11115
|
+
targetId: zod.z.string(),
|
|
11116
|
+
notification: NotificationSchema
|
|
11117
|
+
}), SendResultSchema, {
|
|
11118
|
+
kind: "mutation",
|
|
11119
|
+
auth: "admin"
|
|
11120
|
+
}),
|
|
11121
|
+
testTarget: require_sleep.method(zod.z.object({
|
|
11122
|
+
targetId: zod.z.string(),
|
|
11123
|
+
sample: NotificationSchema.optional()
|
|
11124
|
+
}), TestResultSchema, {
|
|
11125
|
+
kind: "mutation",
|
|
11126
|
+
auth: "admin"
|
|
11127
|
+
}),
|
|
11128
|
+
upsertTarget: require_sleep.method(zod.z.object({
|
|
11129
|
+
target: TargetSchema,
|
|
11130
|
+
/**
|
|
11131
|
+
* Duplicate flow: create a NEW target id while copying secrets from an
|
|
11132
|
+
* existing row. The UI never holds the stored token; blank / redacted
|
|
11133
|
+
* password fields are restored from this source (D634 still applies if
|
|
11134
|
+
* destinations diverge without a re-typed secret).
|
|
11135
|
+
*/
|
|
11136
|
+
cloneSecretsFrom: zod.z.string().optional()
|
|
11137
|
+
}), TargetSchema, {
|
|
11138
|
+
kind: "mutation",
|
|
11139
|
+
auth: "admin"
|
|
11140
|
+
}),
|
|
11141
|
+
deleteTarget: require_sleep.method(zod.z.object({ targetId: zod.z.string() }), zod.z.void(), {
|
|
11142
|
+
kind: "mutation",
|
|
11143
|
+
auth: "admin"
|
|
11144
|
+
}),
|
|
11145
|
+
setTargetEnabled: require_sleep.method(zod.z.object({
|
|
11146
|
+
targetId: zod.z.string(),
|
|
11147
|
+
enabled: zod.z.boolean()
|
|
11148
|
+
}), zod.z.void(), {
|
|
11149
|
+
kind: "mutation",
|
|
11150
|
+
auth: "admin"
|
|
11151
|
+
})
|
|
11152
|
+
}
|
|
11153
|
+
};
|
|
11154
|
+
//#endregion
|
|
11155
|
+
//#region src/automation/export-entities.ts
|
|
11156
|
+
function errorText(err) {
|
|
11157
|
+
return err instanceof Error ? err.message : String(err);
|
|
11158
|
+
}
|
|
11159
|
+
/** `actions.run` flattens a refusal to `[code] text`; the code leads. */
|
|
11160
|
+
function refusalFromThrown(message) {
|
|
11161
|
+
if (message.startsWith("[busy]")) return "already-running";
|
|
11162
|
+
if (message.startsWith("[not-found]")) return "not-found";
|
|
11163
|
+
return null;
|
|
11164
|
+
}
|
|
11165
|
+
async function runExportedAction(api, log, input) {
|
|
11166
|
+
const { exporter, actionId } = input;
|
|
11167
|
+
const tags = { actionId };
|
|
11168
|
+
const refuse = (reason, detail) => {
|
|
11169
|
+
log.warn(`${exporter}: exported action not run — ${reason}`, {
|
|
11170
|
+
tags,
|
|
11171
|
+
meta: {
|
|
11172
|
+
reason,
|
|
11173
|
+
...detail ? { detail } : {}
|
|
11174
|
+
}
|
|
11175
|
+
});
|
|
11176
|
+
return {
|
|
11177
|
+
status: "refused",
|
|
11178
|
+
reason
|
|
11179
|
+
};
|
|
11180
|
+
};
|
|
11181
|
+
try {
|
|
11182
|
+
const result = await api.actions.run.mutate({ actionId });
|
|
11183
|
+
if (result.outcome === "skipped-overlap") return refuse("already-running", result.message);
|
|
11184
|
+
if (result.outcome === "skipped-cooldown") return refuse("cooldown", result.message);
|
|
11185
|
+
if (result.outcome === "failed" || result.outcome === "aborted") {
|
|
11186
|
+
const message = result.message ?? result.outcome;
|
|
11187
|
+
log.warn(`${exporter}: exported action failed`, {
|
|
11188
|
+
tags,
|
|
11189
|
+
meta: {
|
|
11190
|
+
outcome: result.outcome,
|
|
11191
|
+
message
|
|
11192
|
+
}
|
|
11193
|
+
});
|
|
11194
|
+
return {
|
|
11195
|
+
status: "failed",
|
|
11196
|
+
message
|
|
11197
|
+
};
|
|
11198
|
+
}
|
|
11199
|
+
log.info(`${exporter}: exported action ran`, {
|
|
11200
|
+
tags,
|
|
11201
|
+
meta: { outcome: result.outcome }
|
|
11202
|
+
});
|
|
11203
|
+
return { status: "started" };
|
|
11204
|
+
} catch (err) {
|
|
11205
|
+
const message = errorText(err);
|
|
11206
|
+
const reason = refusalFromThrown(message);
|
|
11207
|
+
if (reason !== null) return refuse(reason, message);
|
|
11208
|
+
log.warn(`${exporter}: exported action failed`, {
|
|
11209
|
+
tags,
|
|
11210
|
+
meta: { message }
|
|
11211
|
+
});
|
|
11212
|
+
return {
|
|
11213
|
+
status: "failed",
|
|
11214
|
+
message
|
|
11215
|
+
};
|
|
11216
|
+
}
|
|
11217
|
+
}
|
|
11218
|
+
/** Send through one CamStack notification target on behalf of an exporter. */
|
|
11219
|
+
async function sendToExportedTarget(api, log, input) {
|
|
11220
|
+
const { exporter, targetId } = input;
|
|
11221
|
+
const tags = { targetId };
|
|
11222
|
+
try {
|
|
11223
|
+
const target = (await api.notificationOutput.listTargets.query({})).find((t) => t.id === targetId);
|
|
11224
|
+
if (target === void 0) {
|
|
11225
|
+
log.warn(`${exporter}: exported notifier not used — target-gone`, {
|
|
11226
|
+
tags,
|
|
11227
|
+
meta: { reason: "target-gone" }
|
|
11228
|
+
});
|
|
11229
|
+
return {
|
|
11230
|
+
status: "refused",
|
|
11231
|
+
reason: "target-gone"
|
|
11232
|
+
};
|
|
11233
|
+
}
|
|
11234
|
+
if (!target.enabled) {
|
|
11235
|
+
log.warn(`${exporter}: exported notifier not used — target-disabled`, {
|
|
11236
|
+
tags,
|
|
11237
|
+
meta: { reason: "target-disabled" }
|
|
11238
|
+
});
|
|
11239
|
+
return {
|
|
11240
|
+
status: "refused",
|
|
11241
|
+
reason: "target-disabled"
|
|
11242
|
+
};
|
|
11243
|
+
}
|
|
11244
|
+
const result = await api.notificationOutput.send.mutate({
|
|
11245
|
+
targetId,
|
|
11246
|
+
addonId: target.addonId,
|
|
11247
|
+
notification: NotificationSchema.parse(input.notification)
|
|
11248
|
+
});
|
|
11249
|
+
if (!result.success) {
|
|
11250
|
+
const message = result.error ?? "send failed";
|
|
11251
|
+
log.warn(`${exporter}: exported notifier send failed`, {
|
|
11252
|
+
tags,
|
|
11253
|
+
meta: { message }
|
|
11254
|
+
});
|
|
11255
|
+
return {
|
|
11256
|
+
status: "failed",
|
|
11257
|
+
message
|
|
11258
|
+
};
|
|
11259
|
+
}
|
|
11260
|
+
return { status: "sent" };
|
|
11261
|
+
} catch (err) {
|
|
11262
|
+
const message = errorText(err);
|
|
11263
|
+
log.warn(`${exporter}: exported notifier send failed`, {
|
|
11264
|
+
tags,
|
|
11265
|
+
meta: { message }
|
|
11266
|
+
});
|
|
11267
|
+
return {
|
|
11268
|
+
status: "failed",
|
|
11269
|
+
message
|
|
11270
|
+
};
|
|
11271
|
+
}
|
|
11272
|
+
}
|
|
11273
|
+
/**
|
|
11274
|
+
* Split an exporter's selection into what still exists and what was deleted.
|
|
11275
|
+
* Devices are never judged here (their lifecycle is the tombstone, D865).
|
|
11276
|
+
* Callers pass ids from a query that ANSWERED — an unanswered list must not
|
|
11277
|
+
* reach this function (D49: a failed read changes nothing).
|
|
11278
|
+
*/
|
|
11279
|
+
function pruneDeletedEntities(selection, live, log, exporter) {
|
|
11280
|
+
const kept = [];
|
|
11281
|
+
const dropped = [];
|
|
11282
|
+
for (const ref of selection) if (ref.kind === "action" && !live.actionIds.has(ref.actionId)) {
|
|
11283
|
+
dropped.push(ref);
|
|
11284
|
+
log.warn(`${exporter}: exported action was deleted — dropped from the export`, { tags: { actionId: ref.actionId } });
|
|
11285
|
+
} else if (ref.kind === "notifier" && !live.targetIds.has(ref.targetId)) {
|
|
11286
|
+
dropped.push(ref);
|
|
11287
|
+
log.warn(`${exporter}: exported notifier target was deleted — dropped from the export`, { tags: { targetId: ref.targetId } });
|
|
11288
|
+
} else kept.push(ref);
|
|
11289
|
+
return {
|
|
11290
|
+
kept,
|
|
11291
|
+
dropped
|
|
11292
|
+
};
|
|
11293
|
+
}
|
|
11294
|
+
//#endregion
|
|
10708
11295
|
//#region src/capabilities/addon-pages.cap.ts
|
|
10709
11296
|
/**
|
|
10710
11297
|
* `addon-pages` — system-scoped singleton aggregator cap. Public-facing
|
|
@@ -10744,71 +11331,6 @@ var addonPagesCapability = {
|
|
|
10744
11331
|
methods: { listPages: require_sleep.method(zod.z.void(), zod.z.array(AddonPageInfoSchema).readonly()) }
|
|
10745
11332
|
};
|
|
10746
11333
|
//#endregion
|
|
10747
|
-
//#region src/capabilities/addon-pages-source.cap.ts
|
|
10748
|
-
/**
|
|
10749
|
-
* `addon-pages-source` — collection cap exposing per-provider raw page
|
|
10750
|
-
* declarations. Every addon that contributes a UI page registers a
|
|
10751
|
-
* provider here. The hub-side singleton aggregator (`addon-pages` cap,
|
|
10752
|
-
* see `addon-pages.cap.ts`) walks this collection, stamps versioned
|
|
10753
|
-
* `bundleUrl` values, and returns the enriched `AddonPageInfo[]` list
|
|
10754
|
-
* that admin-ui consumes.
|
|
10755
|
-
*
|
|
10756
|
-
* The split exists because the public listing has a different output
|
|
10757
|
-
* shape than the per-provider raw declarations, and we want both ends
|
|
10758
|
-
* to flow through codegen instead of relying on a hand-written wrapper.
|
|
10759
|
-
*/
|
|
10760
|
-
var AddonPageDeclarationSchema = zod.z.object({
|
|
10761
|
-
id: zod.z.string(),
|
|
10762
|
-
label: zod.z.string(),
|
|
10763
|
-
icon: zod.z.string(),
|
|
10764
|
-
path: zod.z.string(),
|
|
10765
|
-
/**
|
|
10766
|
-
* Module Federation remote name — must match the `name` field on the
|
|
10767
|
-
* page addon's `federation()` plugin config. Used by admin-ui's
|
|
10768
|
-
* `<AddonPageLoader>` to call `loadRemote('<remoteName>/page')`.
|
|
10769
|
-
* Conventionally `addon_<id>_page` (snake_case; MF names cannot
|
|
10770
|
-
* contain hyphens).
|
|
10771
|
-
*/
|
|
10772
|
-
remoteName: zod.z.string(),
|
|
10773
|
-
/**
|
|
10774
|
-
* Bundle filename inside the addon's `dist/` dir served at
|
|
10775
|
-
* `/api/addon-pages/<addonId>/<bundle>`. With Module Federation this
|
|
10776
|
-
* is always `'remoteEntry.js'`; the value is kept on the metadata so
|
|
10777
|
-
* the static-file route can compute an mtime-based cache-buster URL
|
|
10778
|
-
* without a separate filesystem stat.
|
|
10779
|
-
*/
|
|
10780
|
-
bundle: zod.z.string(),
|
|
10781
|
-
/**
|
|
10782
|
-
* Sidebar section this page docks into. Well-known ids: `'detection'`,
|
|
10783
|
-
* `'cluster'`, `'administration'` — the page renders inside that group.
|
|
10784
|
-
* Any OTHER string creates (or joins) a custom section rendered after
|
|
10785
|
-
* the built-in groups; its label comes from `sectionLabel` (first
|
|
10786
|
-
* declaration wins), falling back to the id. Absent → the legacy
|
|
10787
|
-
* "Addon Pages" group.
|
|
10788
|
-
*/
|
|
10789
|
-
section: zod.z.string().optional(),
|
|
10790
|
-
/** Display label for a CUSTOM `section` id (ignored for well-known ids). */
|
|
10791
|
-
sectionLabel: zod.z.string().optional()
|
|
10792
|
-
});
|
|
10793
|
-
var addonPagesSourceCapability = {
|
|
10794
|
-
name: "addon-pages-source",
|
|
10795
|
-
scope: "system",
|
|
10796
|
-
mode: "collection",
|
|
10797
|
-
internal: true,
|
|
10798
|
-
methods: {
|
|
10799
|
-
/**
|
|
10800
|
-
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
10801
|
-
* `data-store-provider`) — this was reachable on the AppRouter by ANY
|
|
10802
|
-
* authenticated session at the default `auth: 'protected'`. The only
|
|
10803
|
-
* consumer, the `addon-pages-aggregator` builtin, reads it via
|
|
10804
|
-
* `ctx.capabilities.getCollection('addon-pages-source')` — LOCAL-PROCESS
|
|
10805
|
-
* only, never tRPC (per `ctx.capabilities` seeing only the local
|
|
10806
|
-
* process). The public, enriched listing admin-ui actually consumes is
|
|
10807
|
-
* the separate `addon-pages` cap, unaffected by this change.
|
|
10808
|
-
*/
|
|
10809
|
-
listPages: require_sleep.method(zod.z.void(), zod.z.array(AddonPageDeclarationSchema).readonly(), { auth: "admin" }) }
|
|
10810
|
-
};
|
|
10811
|
-
//#endregion
|
|
10812
11334
|
//#region src/capabilities/addon-routes.cap.ts
|
|
10813
11335
|
var AddonHttpRouteSchema = zod.z.object({
|
|
10814
11336
|
method: zod.z.enum([
|
|
@@ -14915,7 +15437,11 @@ var CompositionProblemCodeSchema = zod.z.enum([
|
|
|
14915
15437
|
"mixed-quantity",
|
|
14916
15438
|
"helper-mismatch",
|
|
14917
15439
|
"member-constraint",
|
|
14918
|
-
"retention"
|
|
15440
|
+
"retention",
|
|
15441
|
+
"command-method-unknown",
|
|
15442
|
+
"command-source-unknown",
|
|
15443
|
+
"command-input-unknown",
|
|
15444
|
+
"command-input-missing"
|
|
14919
15445
|
]);
|
|
14920
15446
|
/** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.temperature`. */
|
|
14921
15447
|
var CompositionProblemSchema = zod.z.object({
|
|
@@ -14957,7 +15483,9 @@ var CompositionFieldRoleSchema = zod.z.enum([
|
|
|
14957
15483
|
var CompositionFieldItemSchema = zod.z.object({
|
|
14958
15484
|
arrayPath: zod.z.string(),
|
|
14959
15485
|
key: zod.z.string(),
|
|
14960
|
-
label: zod.z.string()
|
|
15486
|
+
label: zod.z.string(),
|
|
15487
|
+
/** True when the item carries a `reset` forward: the composer writes `resettable` from this (D967). */
|
|
15488
|
+
resettable: zod.z.boolean().optional()
|
|
14961
15489
|
});
|
|
14962
15490
|
var CompositionFieldPlanSchema = zod.z.object({
|
|
14963
15491
|
cap: zod.z.string(),
|
|
@@ -15478,7 +16006,7 @@ function unavailableFor(tf, role, mode, cap, at) {
|
|
|
15478
16006
|
}
|
|
15479
16007
|
//#endregion
|
|
15480
16008
|
//#region src/composition/composition-items.ts
|
|
15481
|
-
/** Item fields the composer writes itself, with the value it writes. */
|
|
16009
|
+
/** Item fields the composer writes itself, with the value it writes. `resettable` is the default: an item with a `reset` forward writes `true` (D967). */
|
|
15482
16010
|
var COMPOSED_ITEM_FIXED_FIELDS = { resettable: false };
|
|
15483
16011
|
function reservedItemFields(itemArray) {
|
|
15484
16012
|
return new Set([
|
|
@@ -15521,7 +16049,8 @@ function planItemField(ctx, leaf) {
|
|
|
15521
16049
|
item: {
|
|
15522
16050
|
arrayPath: itemArray.path,
|
|
15523
16051
|
key,
|
|
15524
|
-
label
|
|
16052
|
+
label,
|
|
16053
|
+
...leaf.resettable ? { resettable: true } : {}
|
|
15525
16054
|
},
|
|
15526
16055
|
featureIndex,
|
|
15527
16056
|
kind: tf.kind,
|
|
@@ -15561,6 +16090,7 @@ function planItems(def, feature, featureIndex, lookupCap, mode = "new") {
|
|
|
15561
16090
|
}, ...Object.entries(item.fields).map(([path, source]) => planItemField(ctx, {
|
|
15562
16091
|
key,
|
|
15563
16092
|
label: item.label,
|
|
16093
|
+
resettable: item.reset !== void 0,
|
|
15564
16094
|
path,
|
|
15565
16095
|
source
|
|
15566
16096
|
}))]);
|
|
@@ -15572,12 +16102,163 @@ function planItems(def, feature, featureIndex, lookupCap, mode = "new") {
|
|
|
15572
16102
|
};
|
|
15573
16103
|
}
|
|
15574
16104
|
//#endregion
|
|
16105
|
+
//#region src/composition/validate-forward.ts
|
|
16106
|
+
/**
|
|
16107
|
+
* Save-time validation of `forward` commands (D659, amended by D967).
|
|
16108
|
+
*
|
|
16109
|
+
* A BUILT capability serves a method only through a command, so every method
|
|
16110
|
+
* the cap serves needs one. A forward is checked against the two input schemas
|
|
16111
|
+
* it joins: the BUILT method's (what the caller sends) and the SOURCE method's
|
|
16112
|
+
* (what is called). An input field in neither place is refused BY NAME, and so
|
|
16113
|
+
* is a required source input nothing provides. `deviceId` is the source's own
|
|
16114
|
+
* and is never an argument.
|
|
16115
|
+
*
|
|
16116
|
+
* Static: it needs only the capability definitions. That the source DEVICE
|
|
16117
|
+
* exists and binds the cap is `forwardSourceProblems`, with the sources read.
|
|
16118
|
+
*/
|
|
16119
|
+
var DEVICE_ID_FIELD = "deviceId";
|
|
16120
|
+
/** Every forward of a feature: the method commands, then each item's `reset`. */
|
|
16121
|
+
function featureForwards(feature, featureIndex) {
|
|
16122
|
+
const at = `features[${featureIndex}]`;
|
|
16123
|
+
const commands = Object.entries(feature.commands ?? {}).flatMap(([method, target]) => target.kind === "forward" ? [{
|
|
16124
|
+
at: `${at}.commands.${method}`,
|
|
16125
|
+
method,
|
|
16126
|
+
command: target
|
|
16127
|
+
}] : []);
|
|
16128
|
+
const resets = Object.entries(feature.items ?? {}).flatMap(([key, item]) => item.reset === void 0 ? [] : [{
|
|
16129
|
+
at: `${at}.items.${key}.reset`,
|
|
16130
|
+
method: "reset",
|
|
16131
|
+
itemKey: key,
|
|
16132
|
+
command: item.reset
|
|
16133
|
+
}]);
|
|
16134
|
+
return [...commands, ...resets];
|
|
16135
|
+
}
|
|
16136
|
+
/** Every source a forward of an enabled feature calls, once. */
|
|
16137
|
+
function forwardSourceRefs(composition) {
|
|
16138
|
+
const refs = composition.features.flatMap((feature, index) => feature.kind === "fields" && require_composition.compositionFeatureEnabled(feature) ? featureForwards(feature, index).map((forward) => forward.command.source) : []);
|
|
16139
|
+
return [...new Map(refs.map((ref) => [require_composition.compositionSourceKey(ref), ref])).values()];
|
|
16140
|
+
}
|
|
16141
|
+
/** The methods a BUILT cap must give a command: served, and not answered by the composer itself. */
|
|
16142
|
+
function commandedMethods(def) {
|
|
16143
|
+
return Object.entries(def.methods).filter(([name, m]) => m.systemOnly !== true && def.composedMethods?.[name] === void 0).map(([name]) => name);
|
|
16144
|
+
}
|
|
16145
|
+
var NO_INPUT = {
|
|
16146
|
+
all: /* @__PURE__ */ new Set(),
|
|
16147
|
+
required: /* @__PURE__ */ new Set()
|
|
16148
|
+
};
|
|
16149
|
+
/** The top-level input fields of a method, `deviceId` removed; null when the input is not an object. */
|
|
16150
|
+
function inputFields(def, method) {
|
|
16151
|
+
const input = def.methods[method]?.input;
|
|
16152
|
+
if (input === void 0) return null;
|
|
16153
|
+
const root = unwrapSchema(input);
|
|
16154
|
+
if (!(root instanceof zod.z.ZodObject)) return null;
|
|
16155
|
+
const entries = Object.entries(root.shape).filter(([name]) => name !== DEVICE_ID_FIELD);
|
|
16156
|
+
return {
|
|
16157
|
+
all: new Set(entries.map(([name]) => name)),
|
|
16158
|
+
required: new Set(entries.flatMap(([name, field]) => field instanceof zod.z.ZodType && !field.safeParse(void 0).success ? [name] : []))
|
|
16159
|
+
};
|
|
16160
|
+
}
|
|
16161
|
+
function inputRefs(arg) {
|
|
16162
|
+
if (typeof arg !== "object") return [];
|
|
16163
|
+
if (require_composition.isForwardInputRef(arg)) return [arg.$input];
|
|
16164
|
+
return Object.values(arg).flatMap(inputRefs);
|
|
16165
|
+
}
|
|
16166
|
+
function names(list) {
|
|
16167
|
+
return [...list].map((name) => `\`${name}\``).join(", ");
|
|
16168
|
+
}
|
|
16169
|
+
function sourceMethodOf(forward, lookupCap) {
|
|
16170
|
+
const { command, at } = forward;
|
|
16171
|
+
const def = lookupCap(command.cap);
|
|
16172
|
+
if (def === null) return {
|
|
16173
|
+
def: null,
|
|
16174
|
+
problems: [problem("command-source-unknown", `${at}.cap`, `no capability is named \`${command.cap}\``)]
|
|
16175
|
+
};
|
|
16176
|
+
const served = def.methods[command.method];
|
|
16177
|
+
if (served === void 0 || served.systemOnly === true) return {
|
|
16178
|
+
def: null,
|
|
16179
|
+
problems: [problem("command-source-unknown", `${at}.method`, `\`${command.cap}\` has no method \`${command.method}\` to forward to`)]
|
|
16180
|
+
};
|
|
16181
|
+
if (served.kind !== "mutation") return {
|
|
16182
|
+
def: null,
|
|
16183
|
+
problems: [problem("command-source-unknown", `${at}.method`, `\`${command.cap}.${command.method}\` is a query — a command calls a mutation of the source`)]
|
|
16184
|
+
};
|
|
16185
|
+
return {
|
|
16186
|
+
def,
|
|
16187
|
+
problems: []
|
|
16188
|
+
};
|
|
16189
|
+
}
|
|
16190
|
+
function mappedInputProblems(forward, built, source, args) {
|
|
16191
|
+
const { at, command } = forward;
|
|
16192
|
+
const where = `${command.cap}.${command.method}`;
|
|
16193
|
+
const problems = [];
|
|
16194
|
+
if ("deviceId" in args) problems.push(problem("command-input-unknown", `${at}.args.${DEVICE_ID_FIELD}`, `\`${DEVICE_ID_FIELD}\` is the source device's own — a forward never takes it as an argument`));
|
|
16195
|
+
if (source !== null) {
|
|
16196
|
+
for (const key of Object.keys(args).filter((k) => k !== "deviceId" && !source.all.has(k))) problems.push(problem("command-input-unknown", `${at}.args.${key}`, `\`${where}\` has no input field \`${key}\` (it takes ${names(source.all)})`));
|
|
16197
|
+
const missing = [...source.required].filter((k) => !(k in args));
|
|
16198
|
+
if (missing.length > 0) problems.push(problem("command-input-missing", `${at}.args`, `\`${where}\` needs ${names(missing)}, which \`args\` does not provide`));
|
|
16199
|
+
}
|
|
16200
|
+
const readable = forward.itemKey === void 0 ? built : NO_INPUT;
|
|
16201
|
+
if (readable !== null) for (const ref of Object.values(args).flatMap(inputRefs)) {
|
|
16202
|
+
if (readable.all.has(ref)) continue;
|
|
16203
|
+
problems.push(problem("command-input-unknown", `${at}.args`, readable === NO_INPUT ? `an item's \`reset\` takes no input — \`$input: ${ref}\` has nothing to read` : `\`$input: ${ref}\` is not a field of the \`${forward.method}\` input (it takes ${names(readable.all)})`));
|
|
16204
|
+
}
|
|
16205
|
+
return problems;
|
|
16206
|
+
}
|
|
16207
|
+
function passthroughInputProblems(forward, built, source) {
|
|
16208
|
+
const { at, command } = forward;
|
|
16209
|
+
const where = `${command.cap}.${command.method}`;
|
|
16210
|
+
const sent = forward.itemKey === void 0 ? built : NO_INPUT;
|
|
16211
|
+
if (sent === null || source === null) return [];
|
|
16212
|
+
const problems = [];
|
|
16213
|
+
for (const field of [...sent.all].filter((f) => !source.all.has(f))) problems.push(problem("command-input-unknown", `${at}.args`, `\`${forward.method}\` takes \`${field}\`, which \`${where}\` does not (it takes ${names(source.all)}) — add \`args\` to map it`));
|
|
16214
|
+
const missing = [...source.required].filter((k) => !sent.all.has(k));
|
|
16215
|
+
if (missing.length > 0) problems.push(problem("command-input-missing", `${at}.args`, `\`${where}\` needs ${names(missing)}, which \`${forward.method}\` does not take — add \`args\` to provide it`));
|
|
16216
|
+
return problems;
|
|
16217
|
+
}
|
|
16218
|
+
/** One forward against the built cap's method and the source cap's method. */
|
|
16219
|
+
function forwardProblems(built, forward, lookupCap) {
|
|
16220
|
+
const source = sourceMethodOf(forward, lookupCap);
|
|
16221
|
+
if (source.def === null) return source.problems;
|
|
16222
|
+
const builtFields = inputFields(built, forward.method);
|
|
16223
|
+
const sourceFields = inputFields(source.def, forward.command.method);
|
|
16224
|
+
const mapping = forward.command.args;
|
|
16225
|
+
return mapping === void 0 ? passthroughInputProblems(forward, builtFields, sourceFields) : mappedInputProblems(forward, builtFields, sourceFields, mapping);
|
|
16226
|
+
}
|
|
16227
|
+
/** A command must name a method the built cap serves and the composer does not answer itself. */
|
|
16228
|
+
function commandMethodProblems(built, feature, at) {
|
|
16229
|
+
const commanded = new Set(commandedMethods(built));
|
|
16230
|
+
return Object.keys(feature.commands ?? {}).flatMap((method) => {
|
|
16231
|
+
if (commanded.has(method)) return [];
|
|
16232
|
+
const answered = built.composedMethods?.[method] !== void 0;
|
|
16233
|
+
return [problem("command-method-unknown", `${at}.commands.${method}`, answered ? `\`${built.name}.${method}\` is answered by the composer itself — an item's \`reset\` serves it` : `\`${built.name}\` has no method \`${method}\` to serve`)];
|
|
16234
|
+
});
|
|
16235
|
+
}
|
|
16236
|
+
/**
|
|
16237
|
+
* The source DEVICES of the forwards, read: each must exist and bind the cap it
|
|
16238
|
+
* is called on. A forward onto an unread device is refused rather than stored
|
|
16239
|
+
* unchecked, like every other source (D391).
|
|
16240
|
+
*/
|
|
16241
|
+
function forwardSourceProblems(composition, sources) {
|
|
16242
|
+
return composition.features.flatMap((feature, index) => {
|
|
16243
|
+
if (feature.kind !== "fields" || !require_composition.compositionFeatureEnabled(feature)) return [];
|
|
16244
|
+
return featureForwards(feature, index).flatMap((forward) => {
|
|
16245
|
+
const key = require_composition.compositionSourceKey(forward.command.source);
|
|
16246
|
+
const desc = sources.get(key);
|
|
16247
|
+
const at = `${forward.at}.source`;
|
|
16248
|
+
if (desc === void 0 || desc.kind === "unreadable") return [problem("source-unreadable", at, `could not read source \`${key}\` (${desc === void 0 ? "it was not read" : desc.error}) — the save is refused rather than stored unchecked`)];
|
|
16249
|
+
if (desc.kind === "absent") return [problem("source-missing", at, `source \`${key}\` does not exist`)];
|
|
16250
|
+
if (!desc.caps.has(forward.command.cap)) return [problem("source-capability-missing", at, `source \`${key}\` (device ${desc.deviceId}) has no \`${forward.command.cap}\``)];
|
|
16251
|
+
return [];
|
|
16252
|
+
});
|
|
16253
|
+
});
|
|
16254
|
+
}
|
|
16255
|
+
//#endregion
|
|
15575
16256
|
//#region src/composition/helpers/catalog.ts
|
|
15576
16257
|
/**
|
|
15577
16258
|
* One catalog row per base reading a group helper can build (D944 §3).
|
|
15578
16259
|
* Data, not a form default written into the block.
|
|
15579
16260
|
*/
|
|
15580
|
-
var NOW$
|
|
16261
|
+
var NOW$3 = {
|
|
15581
16262
|
fieldPath: "lastFetchedAt",
|
|
15582
16263
|
expr: "now"
|
|
15583
16264
|
};
|
|
@@ -15629,7 +16310,7 @@ var GROUP_TEMPLATES = [
|
|
|
15629
16310
|
quantity: "temperature",
|
|
15630
16311
|
defaultAggregate: "mean",
|
|
15631
16312
|
empty: "null",
|
|
15632
|
-
companions: [NOW$
|
|
16313
|
+
companions: [NOW$3],
|
|
15633
16314
|
alsoFrom: {
|
|
15634
16315
|
deviceTypes: CLIMATE_DEVICES,
|
|
15635
16316
|
accept: {
|
|
@@ -15647,7 +16328,7 @@ var GROUP_TEMPLATES = [
|
|
|
15647
16328
|
quantity: "humidity",
|
|
15648
16329
|
defaultAggregate: "mean",
|
|
15649
16330
|
empty: "null",
|
|
15650
|
-
companions: [NOW$
|
|
16331
|
+
companions: [NOW$3],
|
|
15651
16332
|
alsoFrom: {
|
|
15652
16333
|
deviceTypes: CLIMATE_DEVICES,
|
|
15653
16334
|
accept: {
|
|
@@ -15665,7 +16346,7 @@ var GROUP_TEMPLATES = [
|
|
|
15665
16346
|
quantity: "pressure",
|
|
15666
16347
|
defaultAggregate: "mean",
|
|
15667
16348
|
empty: "null",
|
|
15668
|
-
companions: [NOW$
|
|
16349
|
+
companions: [NOW$3]
|
|
15669
16350
|
}),
|
|
15670
16351
|
numeric({
|
|
15671
16352
|
id: "illuminance",
|
|
@@ -15676,7 +16357,7 @@ var GROUP_TEMPLATES = [
|
|
|
15676
16357
|
quantity: "illuminance",
|
|
15677
16358
|
defaultAggregate: "mean",
|
|
15678
16359
|
empty: "null",
|
|
15679
|
-
companions: [NOW$
|
|
16360
|
+
companions: [NOW$3]
|
|
15680
16361
|
}),
|
|
15681
16362
|
numeric({
|
|
15682
16363
|
id: "power",
|
|
@@ -15687,7 +16368,7 @@ var GROUP_TEMPLATES = [
|
|
|
15687
16368
|
quantity: "power",
|
|
15688
16369
|
defaultAggregate: "sum",
|
|
15689
16370
|
empty: "omit",
|
|
15690
|
-
companions: [NOW$
|
|
16371
|
+
companions: [NOW$3]
|
|
15691
16372
|
}),
|
|
15692
16373
|
numeric({
|
|
15693
16374
|
id: "energy",
|
|
@@ -15698,7 +16379,7 @@ var GROUP_TEMPLATES = [
|
|
|
15698
16379
|
quantity: "energy",
|
|
15699
16380
|
defaultAggregate: "sum",
|
|
15700
16381
|
empty: "omit",
|
|
15701
|
-
companions: [NOW$
|
|
16382
|
+
companions: [NOW$3]
|
|
15702
16383
|
}),
|
|
15703
16384
|
numeric({
|
|
15704
16385
|
id: "battery",
|
|
@@ -15733,7 +16414,7 @@ var GROUP_TEMPLATES = [
|
|
|
15733
16414
|
quantity: "device",
|
|
15734
16415
|
defaultAggregate: "mean",
|
|
15735
16416
|
empty: "null",
|
|
15736
|
-
companions: [NOW$
|
|
16417
|
+
companions: [NOW$3]
|
|
15737
16418
|
}),
|
|
15738
16419
|
binary({
|
|
15739
16420
|
id: "motion",
|
|
@@ -16159,7 +16840,7 @@ async function runFanOut(calls, invoke) {
|
|
|
16159
16840
|
//#region src/generated/history-catalog.ts
|
|
16160
16841
|
/**
|
|
16161
16842
|
* Cap history catalog, projected from every `*.cap.ts` `history` block.
|
|
16162
|
-
*
|
|
16843
|
+
* 42 caps with series (80 series), 34 caps answered `'none'`.
|
|
16163
16844
|
* Field keys are `runtimeState` paths (`a.b` into fixed objects only).
|
|
16164
16845
|
*/
|
|
16165
16846
|
var HISTORY_CATALOG = {
|
|
@@ -16399,6 +17080,25 @@ var HISTORY_CATALOG = {
|
|
|
16399
17080
|
unit: "s"
|
|
16400
17081
|
}
|
|
16401
17082
|
},
|
|
17083
|
+
"pet-fountain": {
|
|
17084
|
+
"waterLevel": {
|
|
17085
|
+
kind: "gauge",
|
|
17086
|
+
unit: "%",
|
|
17087
|
+
deadband: 1
|
|
17088
|
+
},
|
|
17089
|
+
"waterVolume": {
|
|
17090
|
+
kind: "gauge",
|
|
17091
|
+
unit: "L"
|
|
17092
|
+
},
|
|
17093
|
+
"todayDrink": {
|
|
17094
|
+
kind: "gauge",
|
|
17095
|
+
unit: "L"
|
|
17096
|
+
},
|
|
17097
|
+
"last24hDrink": {
|
|
17098
|
+
kind: "gauge",
|
|
17099
|
+
unit: "L"
|
|
17100
|
+
}
|
|
17101
|
+
},
|
|
16402
17102
|
"power-meter": {
|
|
16403
17103
|
"power": {
|
|
16404
17104
|
kind: "gauge",
|
|
@@ -16596,7 +17296,7 @@ function historyFieldsFor(capName) {
|
|
|
16596
17296
|
* Project a statistics or integral helper onto a new device (D944 §3).
|
|
16597
17297
|
* The value field is `series`: the composer fills it from history.
|
|
16598
17298
|
*/
|
|
16599
|
-
var NOW$
|
|
17299
|
+
var NOW$2 = {
|
|
16600
17300
|
kind: "expression",
|
|
16601
17301
|
expr: "now",
|
|
16602
17302
|
bindings: {}
|
|
@@ -16656,7 +17356,7 @@ function draft(input) {
|
|
|
16656
17356
|
cap: input.cap,
|
|
16657
17357
|
fields: {
|
|
16658
17358
|
[input.field]: series(input.member, "value", input.empty),
|
|
16659
|
-
lastFetchedAt: NOW$
|
|
17359
|
+
lastFetchedAt: NOW$2
|
|
16660
17360
|
}
|
|
16661
17361
|
}, {
|
|
16662
17362
|
kind: "fields",
|
|
@@ -16738,12 +17438,12 @@ function integralDraft(spec, retention = require_composition.DEFAULT_HISTORY_RET
|
|
|
16738
17438
|
* a free expression is the expression engine unchanged — it still includes a
|
|
16739
17439
|
* stale input, and the template says so.
|
|
16740
17440
|
*/
|
|
16741
|
-
var NOW = {
|
|
17441
|
+
var NOW$1 = {
|
|
16742
17442
|
kind: "expression",
|
|
16743
17443
|
expr: "now",
|
|
16744
17444
|
bindings: {}
|
|
16745
17445
|
};
|
|
16746
|
-
function from$
|
|
17446
|
+
function from$2(member) {
|
|
16747
17447
|
return {
|
|
16748
17448
|
kind: "from",
|
|
16749
17449
|
source: member.source,
|
|
@@ -16774,7 +17474,7 @@ function numericSensor(helper, value, extra = []) {
|
|
|
16774
17474
|
cap: "numeric-sensor",
|
|
16775
17475
|
fields: {
|
|
16776
17476
|
value,
|
|
16777
|
-
lastFetchedAt: NOW
|
|
17477
|
+
lastFetchedAt: NOW$1
|
|
16778
17478
|
}
|
|
16779
17479
|
}, ...extra]
|
|
16780
17480
|
};
|
|
@@ -16792,7 +17492,7 @@ function binarySensor(helper, on) {
|
|
|
16792
17492
|
cap: "binary",
|
|
16793
17493
|
fields: {
|
|
16794
17494
|
on,
|
|
16795
|
-
lastChangedAt: NOW
|
|
17495
|
+
lastChangedAt: NOW$1
|
|
16796
17496
|
}
|
|
16797
17497
|
}]
|
|
16798
17498
|
};
|
|
@@ -16810,7 +17510,7 @@ function thresholdDraft(spec) {
|
|
|
16810
17510
|
const delays = onFor !== null && offFor !== null && (spec.onForMs > 0 || spec.offForMs > 0) ? `, ${onFor}, ${offFor}` : "";
|
|
16811
17511
|
return {
|
|
16812
17512
|
problems,
|
|
16813
|
-
draft: binarySensor(spec, expression$1(`coalesce(schmitt(x, ${high ?? "0"}, ${low ?? "0"}${delays}), false)`, { x: from$
|
|
17513
|
+
draft: binarySensor(spec, expression$1(`coalesce(schmitt(x, ${high ?? "0"}, ${low ?? "0"}${delays}), false)`, { x: from$2(spec.source) }))
|
|
16814
17514
|
};
|
|
16815
17515
|
}
|
|
16816
17516
|
var NAMES = ["a", "b"];
|
|
@@ -16854,7 +17554,7 @@ function arithmeticDraft(spec) {
|
|
|
16854
17554
|
}])
|
|
16855
17555
|
};
|
|
16856
17556
|
}
|
|
16857
|
-
const bindings = Object.fromEntries(spec.inputs.slice(0, 2).map((input, index) => [NAMES[index] ?? "a", from$
|
|
17557
|
+
const bindings = Object.fromEntries(spec.inputs.slice(0, 2).map((input, index) => [NAMES[index] ?? "a", from$2(input)]));
|
|
16858
17558
|
return {
|
|
16859
17559
|
problems,
|
|
16860
17560
|
draft: numericSensor(spec, expression$1(spec.op === "difference" ? "a - b" : "b == 0 ? null : a / b", bindings))
|
|
@@ -16870,7 +17570,7 @@ function expressionProblems(spec) {
|
|
|
16870
17570
|
seen.add(input.name);
|
|
16871
17571
|
});
|
|
16872
17572
|
if (problems.length > 0) return problems;
|
|
16873
|
-
const bindings = Object.fromEntries(spec.inputs.map((input) => [input.name, from$
|
|
17573
|
+
const bindings = Object.fromEntries(spec.inputs.map((input) => [input.name, from$2(input.member)]));
|
|
16874
17574
|
const message = require_composition.validateExpressionSource({
|
|
16875
17575
|
expr: spec.expr,
|
|
16876
17576
|
bindings
|
|
@@ -16879,7 +17579,7 @@ function expressionProblems(spec) {
|
|
|
16879
17579
|
}
|
|
16880
17580
|
function expressionDraft(spec) {
|
|
16881
17581
|
const problems = expressionProblems(spec);
|
|
16882
|
-
const bindings = Object.fromEntries(spec.inputs.map((input) => [input.name, from$
|
|
17582
|
+
const bindings = Object.fromEntries(spec.inputs.map((input) => [input.name, from$2(input.member)]));
|
|
16883
17583
|
const source = expression$1(spec.expr, bindings);
|
|
16884
17584
|
return {
|
|
16885
17585
|
problems,
|
|
@@ -17396,8 +18096,9 @@ function actuatorCommandCaps(composition) {
|
|
|
17396
18096
|
function builtCapProblems({ def, state, fields: targetFields }, feature, at, deviceType, servedCommands) {
|
|
17397
18097
|
const problems = [];
|
|
17398
18098
|
if (def.deviceTypes !== void 0 && !def.deviceTypes.includes(deviceType)) problems.push(problem("wrong-device-type", `${at}.cap`, `\`${def.name}\` is not offered on a \`${deviceType}\` device (it allows ${def.deviceTypes.join(", ")})`));
|
|
17399
|
-
const
|
|
17400
|
-
|
|
18099
|
+
const commanded = new Set(Object.entries(feature.commands ?? {}).flatMap(([name, target]) => target.kind === "forward" ? [name] : []));
|
|
18100
|
+
const unserved = commandedMethods(def).filter((name) => !commanded.has(name)).map((name) => `\`${name}\``);
|
|
18101
|
+
if (unserved.length > 0 && !servedCommands.has(def.name)) problems.push(problem("has-commands", `${at}.cap`, `\`${def.name}\` has ${unserved.join(", ")} with no command — a composed device serves a method only through a \`forward\` (D967)`));
|
|
17401
18102
|
const itemArrayPath = feature.items === void 0 ? null : def.status?.itemArray?.path ?? null;
|
|
17402
18103
|
for (const key of requiredTopLevelKeys(state)) {
|
|
17403
18104
|
if (key === itemArrayPath) continue;
|
|
@@ -17438,12 +18139,28 @@ function planTopLevelField({ def, fields }, field, mode, lookupCap) {
|
|
|
17438
18139
|
events: []
|
|
17439
18140
|
};
|
|
17440
18141
|
}
|
|
18142
|
+
/**
|
|
18143
|
+
* The commands of a feature (D967). Only a BUILT capability on a NEW device
|
|
18144
|
+
* serves a method through a `forward`; on an existing device the native keeps
|
|
18145
|
+
* its methods, and a `code` command is slice 4.
|
|
18146
|
+
*/
|
|
18147
|
+
function commandProblems(def, feature, featureIndex, mode, lookupCap) {
|
|
18148
|
+
const at = `features[${featureIndex}]`;
|
|
18149
|
+
const forwards = featureForwards(feature, featureIndex);
|
|
18150
|
+
const problems = Object.entries(feature.commands ?? {}).filter(([, t]) => t.kind === "code").map(([method]) => problem("reserved-variant", `${at}.commands.${method}`, "a `code` command arrives in slice 4"));
|
|
18151
|
+
if (forwards.length > 0 && mode !== "new") return [...problems, problem("reserved-variant", `${at}.commands`, "commands (`forward`) are served only by a capability a NEW device builds — not on an existing device")];
|
|
18152
|
+
return [
|
|
18153
|
+
...problems,
|
|
18154
|
+
...commandMethodProblems(def, feature, at),
|
|
18155
|
+
...forwards.flatMap((forward) => forwardProblems(def, forward, lookupCap))
|
|
18156
|
+
];
|
|
18157
|
+
}
|
|
17441
18158
|
function planFeature(feature, featureIndex, target, lookupCap, servedCommands) {
|
|
17442
18159
|
const at = `features[${featureIndex}]`;
|
|
17443
18160
|
const cap = composableCap(feature, at, lookupCap);
|
|
17444
18161
|
if ("code" in cap) return refused(cap);
|
|
17445
18162
|
const capProblems = target.mode === "replace" ? [] : [...builtCapProblems(cap, feature, at, target.deviceType, servedCommands)];
|
|
17446
|
-
|
|
18163
|
+
capProblems.push(...commandProblems(cap.def, feature, featureIndex, target.mode, lookupCap));
|
|
17447
18164
|
const perField = Object.entries(feature.fields).map(([path, source]) => planTopLevelField(cap, {
|
|
17448
18165
|
featureIndex,
|
|
17449
18166
|
path,
|
|
@@ -17562,7 +18279,7 @@ function planComposition(composition, lookupCap, target) {
|
|
|
17562
18279
|
}
|
|
17563
18280
|
function compositionSourceRefs(composition) {
|
|
17564
18281
|
const refs = composition.features.flatMap((f) => require_composition.compositionFeatureEnabled(f) && f.kind === "fields" ? require_composition.featureSources(f).flatMap(require_composition.fieldReads).map((r) => r.source) : []);
|
|
17565
|
-
return [...new Map(refs.map((r) => [require_composition.compositionSourceKey(r), r])).values()];
|
|
18282
|
+
return [...new Map([...refs, ...forwardSourceRefs(composition)].map((r) => [require_composition.compositionSourceKey(r), r])).values()];
|
|
17566
18283
|
}
|
|
17567
18284
|
/**
|
|
17568
18285
|
* The candidate's device: the existing target itself, else `self`, else a
|
|
@@ -17698,6 +18415,7 @@ function validateComposition(composition, ctx) {
|
|
|
17698
18415
|
const problems = [
|
|
17699
18416
|
...plan.problems,
|
|
17700
18417
|
...sourceProblems(plan.fields, ctx, self),
|
|
18418
|
+
...forwardSourceProblems(composition, ctx.sources),
|
|
17701
18419
|
...cycles,
|
|
17702
18420
|
...helperSaveProblems(composition, facts)
|
|
17703
18421
|
];
|
|
@@ -21058,6 +21776,36 @@ var ExposeInputSchema = zod.z.object({
|
|
|
21058
21776
|
capabilities: zod.z.array(zod.z.string()).optional()
|
|
21059
21777
|
});
|
|
21060
21778
|
var UnexposeInputSchema = zod.z.object({ deviceId: zod.z.string() });
|
|
21779
|
+
/**
|
|
21780
|
+
* What an exporter may expose besides devices (D968). An action and a
|
|
21781
|
+
* notification target are LIST ENTRIES, never devices (D954): they enter an
|
|
21782
|
+
* exporter's own selection, not the device registry.
|
|
21783
|
+
*/
|
|
21784
|
+
var ExportEntityKindSchema = zod.z.enum([
|
|
21785
|
+
"device",
|
|
21786
|
+
"action",
|
|
21787
|
+
"notifier"
|
|
21788
|
+
]);
|
|
21789
|
+
var ExportEntityRefSchema = zod.z.discriminatedUnion("kind", [
|
|
21790
|
+
zod.z.object({
|
|
21791
|
+
kind: zod.z.literal("device"),
|
|
21792
|
+
deviceId: zod.z.string()
|
|
21793
|
+
}),
|
|
21794
|
+
zod.z.object({
|
|
21795
|
+
kind: zod.z.literal("action"),
|
|
21796
|
+
actionId: zod.z.string().min(1)
|
|
21797
|
+
}),
|
|
21798
|
+
zod.z.object({
|
|
21799
|
+
kind: zod.z.literal("notifier"),
|
|
21800
|
+
targetId: zod.z.string().min(1)
|
|
21801
|
+
})
|
|
21802
|
+
]);
|
|
21803
|
+
var ExposedEntitySchema = zod.z.object({
|
|
21804
|
+
entity: ExportEntityRefSchema,
|
|
21805
|
+
exposedAs: zod.z.string().optional()
|
|
21806
|
+
});
|
|
21807
|
+
var ExposeEntityInputSchema = zod.z.object({ entity: ExportEntityRefSchema });
|
|
21808
|
+
var UnexposeEntityInputSchema = zod.z.object({ entity: ExportEntityRefSchema });
|
|
21061
21809
|
var deviceExportCapability = {
|
|
21062
21810
|
name: "device-export",
|
|
21063
21811
|
scope: "system",
|
|
@@ -21087,6 +21835,16 @@ var deviceExportCapability = {
|
|
|
21087
21835
|
unexposeDevice: require_sleep.method(UnexposeInputSchema, zod.z.void(), {
|
|
21088
21836
|
kind: "mutation",
|
|
21089
21837
|
auth: "admin"
|
|
21838
|
+
}),
|
|
21839
|
+
listSupportedEntityKinds: require_sleep.optionalMethod(zod.z.void(), zod.z.array(ExportEntityKindSchema)),
|
|
21840
|
+
listExposedEntities: require_sleep.optionalMethod(zod.z.void(), zod.z.array(ExposedEntitySchema)),
|
|
21841
|
+
exposeEntity: require_sleep.optionalMethod(ExposeEntityInputSchema, zod.z.void(), {
|
|
21842
|
+
kind: "mutation",
|
|
21843
|
+
auth: "admin"
|
|
21844
|
+
}),
|
|
21845
|
+
unexposeEntity: require_sleep.optionalMethod(UnexposeEntityInputSchema, zod.z.void(), {
|
|
21846
|
+
kind: "mutation",
|
|
21847
|
+
auth: "admin"
|
|
21090
21848
|
})
|
|
21091
21849
|
}
|
|
21092
21850
|
};
|
|
@@ -44795,7 +45553,7 @@ var LlmProviderWidgetSchema = zod.z.object({
|
|
|
44795
45553
|
/** ConfigUISchema tree passed through untyped on the wire (the
|
|
44796
45554
|
* notification-output `ConfigSchemaPassthrough` precedent at
|
|
44797
45555
|
* notification-output.cap.ts:151); the exported TS type re-tightens it. */
|
|
44798
|
-
var ConfigSchemaPassthrough$
|
|
45556
|
+
var ConfigSchemaPassthrough$2 = zod.z.unknown();
|
|
44799
45557
|
var LlmProfileKindDescriptorSchema = zod.z.object({
|
|
44800
45558
|
kind: LlmProfileKindSchema,
|
|
44801
45559
|
label: zod.z.string(),
|
|
@@ -44804,9 +45562,9 @@ var LlmProfileKindDescriptorSchema = zod.z.object({
|
|
|
44804
45562
|
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
44805
45563
|
addonId: zod.z.string(),
|
|
44806
45564
|
/** The provider's own fields (`providerConfig`); `password` fields are keychain-held. */
|
|
44807
|
-
connectionSchema: ConfigSchemaPassthrough$
|
|
45565
|
+
connectionSchema: ConfigSchemaPassthrough$2,
|
|
44808
45566
|
/** Provider fields that belong under "Advanced" (extra headers, runtime tuning). */
|
|
44809
|
-
advancedSchema: ConfigSchemaPassthrough$
|
|
45567
|
+
advancedSchema: ConfigSchemaPassthrough$2.optional(),
|
|
44810
45568
|
/** The kind's defaults; a model from `listModels` may override any of them. */
|
|
44811
45569
|
features: LlmModelFeaturesSchema,
|
|
44812
45570
|
/** `false` = the provider stamps `supportsVision` itself (from what a node reports). */
|
|
@@ -45563,10 +46321,10 @@ var CpuBreakdownSchema = zod.z.object({
|
|
|
45563
46321
|
cores: zod.z.number()
|
|
45564
46322
|
});
|
|
45565
46323
|
var MemoryInfoSchema = zod.z.object({
|
|
45566
|
-
percent: zod.z.number(),
|
|
46324
|
+
percent: zod.z.number().nullable(),
|
|
45567
46325
|
totalBytes: zod.z.number(),
|
|
45568
|
-
usedBytes: zod.z.number(),
|
|
45569
|
-
availableBytes: zod.z.number(),
|
|
46326
|
+
usedBytes: zod.z.number().nullable(),
|
|
46327
|
+
availableBytes: zod.z.number().nullable(),
|
|
45570
46328
|
swapUsedBytes: zod.z.number(),
|
|
45571
46329
|
swapTotalBytes: zod.z.number()
|
|
45572
46330
|
});
|
|
@@ -45870,8 +46628,9 @@ var GetLoadSeriesInputSchema = zod.z.object({
|
|
|
45870
46628
|
});
|
|
45871
46629
|
var SystemMetricsSchema = zod.z.object({
|
|
45872
46630
|
cpuPercent: zod.z.number(),
|
|
45873
|
-
|
|
45874
|
-
|
|
46631
|
+
/** `null` when the memory sample failed or was not taken yet (D393). */
|
|
46632
|
+
memoryPercent: zod.z.number().nullable(),
|
|
46633
|
+
memoryUsedMB: zod.z.number().nullable(),
|
|
45875
46634
|
memoryTotalMB: zod.z.number(),
|
|
45876
46635
|
diskPercent: zod.z.number().optional(),
|
|
45877
46636
|
temperature: zod.z.number().optional(),
|
|
@@ -46273,453 +47032,6 @@ var networkAccessCapability = {
|
|
|
46273
47032
|
}
|
|
46274
47033
|
};
|
|
46275
47034
|
//#endregion
|
|
46276
|
-
//#region src/capabilities/notification-output.cap.ts
|
|
46277
|
-
/**
|
|
46278
|
-
* notification-output — canonical, capability-gated notification delivery.
|
|
46279
|
-
*
|
|
46280
|
-
* Apprise-derived model (see
|
|
46281
|
-
* `docs/superpowers/specs/2026-07-03-notification-output-notifier-matrix.md`):
|
|
46282
|
-
* callers emit ONE canonical `Notification`; each provider declares a
|
|
46283
|
-
* per-kind capability descriptor (`TargetKind`), and the pure degrade
|
|
46284
|
-
* engine (`@camstack/types` `prepareNotification`) transcodes / degrades the
|
|
46285
|
-
* message to what the kind supports — callers never special-case a service.
|
|
46286
|
-
*
|
|
46287
|
-
* DESIGN DECISIONS (locked):
|
|
46288
|
-
* - Target CRUD lives on THIS cap (`upsertTarget` / `deleteTarget` /
|
|
46289
|
-
* `setTargetEnabled`), each provider persisting via the `settings-store`
|
|
46290
|
-
* cap. Rationale: the admin UI needs one uniform surface across the
|
|
46291
|
-
* notifiers addon AND the HA addon; the addon-`globalSettingsSchema`-array
|
|
46292
|
-
* alternative would fork the UI per addon and cannot host the
|
|
46293
|
-
* discovery→adopt flow.
|
|
46294
|
-
* - `listTargetKinds` / `listTargets` / `discoverTargets` return arrays →
|
|
46295
|
-
* the generated cap-mount auto-`concatCollection`-fans them across every
|
|
46296
|
-
* registered provider (notifiers addon + HA addon) so one catalog is
|
|
46297
|
-
* routable. `send` / `testTarget` / CRUD route to ONE provider by the
|
|
46298
|
-
* `addonId` the generated collection router extracts from the call input.
|
|
46299
|
-
* - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
|
|
46300
|
-
* transformer) + UDS MsgPack both round-trip typed arrays — already used by
|
|
46301
|
-
* `storage` / `storage-provider` / `recording` caps over the same path. No
|
|
46302
|
-
* base64 fallback needed.
|
|
46303
|
-
*
|
|
46304
|
-
* TODO (deferred, closed-set change — separate decision): add
|
|
46305
|
-
* `providerKind: 'notify'` so notification providers surface on the unified
|
|
46306
|
-
* admin "Integrations" page.
|
|
46307
|
-
*/
|
|
46308
|
-
/**
|
|
46309
|
-
* Zentik-derived typed-media enum — the superset across every kind. Each
|
|
46310
|
-
* adapter picks what it supports and the degrade engine filters the rest.
|
|
46311
|
-
*/
|
|
46312
|
-
var AttachmentMediaTypeSchema = zod.z.enum([
|
|
46313
|
-
"image",
|
|
46314
|
-
"video",
|
|
46315
|
-
"gif",
|
|
46316
|
-
"audio",
|
|
46317
|
-
"icon"
|
|
46318
|
-
]);
|
|
46319
|
-
/**
|
|
46320
|
-
* A single attachment. Exactly one of `url` (remote source, most adapters
|
|
46321
|
-
* prefer this) or `bytes` (inline source; required for Pushover-style
|
|
46322
|
-
* bytes-only kinds) MUST be present — the degrade engine expresses a
|
|
46323
|
-
* url→bytes fetch as a `needsFetch` directive the adapter executes.
|
|
46324
|
-
*/
|
|
46325
|
-
var AttachmentSchema = zod.z.object({
|
|
46326
|
-
mediaType: AttachmentMediaTypeSchema,
|
|
46327
|
-
url: zod.z.string().optional(),
|
|
46328
|
-
bytes: zod.z.instanceof(Uint8Array).optional(),
|
|
46329
|
-
mime: zod.z.string().optional(),
|
|
46330
|
-
name: zod.z.string().optional()
|
|
46331
|
-
}).refine((a) => a.url !== void 0 || a.bytes !== void 0, { message: "Attachment requires either `url` or `bytes`" });
|
|
46332
|
-
var NotificationFormatSchema = zod.z.enum([
|
|
46333
|
-
"text",
|
|
46334
|
-
"markdown",
|
|
46335
|
-
"html"
|
|
46336
|
-
]);
|
|
46337
|
-
/**
|
|
46338
|
-
* The CLOSED icon vocabulary an action button may use.
|
|
46339
|
-
*
|
|
46340
|
-
* A closed set, not a free string, and that is the whole point: an arbitrary
|
|
46341
|
-
* icon name is one that ntfy renders, zentik silently drops, and nobody
|
|
46342
|
-
* notices — the same class of gap as a zone vocabulary nothing produced
|
|
46343
|
-
* ([D35](../../../docs/decisions/adr-0035.md)). Every adapter maps this set or
|
|
46344
|
-
* declares `actionIcons: false` and the degrade engine strips the field.
|
|
46345
|
-
*
|
|
46346
|
-
* Named by INTENT, never by glyph. "check" would tie the vocabulary to one
|
|
46347
|
-
* renderer's icon set; "acknowledge" survives an adapter that draws it
|
|
46348
|
-
* differently.
|
|
46349
|
-
*
|
|
46350
|
-
* ── A TOKEN IS NOT A WIRE VALUE ─────────────────────────────────────
|
|
46351
|
-
*
|
|
46352
|
-
* These names are for US. **No adapter may forward one verbatim.** Each maps
|
|
46353
|
-
* the whole set onto its own renderer's vocabulary through a
|
|
46354
|
-
* `Record<NotificationActionIcon, string>` — a Record, never a lookup with a
|
|
46355
|
-
* fallback, so adding a member here fails every adapter's build until someone
|
|
46356
|
-
* decides its glyph, which is the only place that decision can be made
|
|
46357
|
-
* honestly.
|
|
46358
|
-
*
|
|
46359
|
-
* This paragraph is the bug. Zentik declared `actionIcons: true` and passed
|
|
46360
|
-
* `disarm` straight through; iOS feeds that string to
|
|
46361
|
-
* `UNNotificationActionIcon(systemImageName:)`, `disarm` is not an SF Symbol,
|
|
46362
|
-
* and every snooze and alarm button arrived BLANK. A pass-through is not a
|
|
46363
|
-
* mapping, and "the field is documented" is not "the value renders".
|
|
46364
|
-
*
|
|
46365
|
-
* Adding a member is TRAIN-BOUND. The enum lives in the published
|
|
46366
|
-
* `@camstack/server` closure and the cap seam validates against the HUB's copy,
|
|
46367
|
-
* so an addon that emits a token the running hub does not know does not lose an
|
|
46368
|
-
* icon — its whole `send` fails Zod validation and the notification never
|
|
46369
|
-
* arrives. Never emit a new token from an addon before the train carrying it.
|
|
46370
|
-
*/
|
|
46371
|
-
var NotificationActionIconSchema = zod.z.enum([
|
|
46372
|
-
"acknowledge",
|
|
46373
|
-
"dismiss",
|
|
46374
|
-
"silence",
|
|
46375
|
-
"snooze",
|
|
46376
|
-
"view",
|
|
46377
|
-
"play",
|
|
46378
|
-
"open",
|
|
46379
|
-
"close",
|
|
46380
|
-
"lock",
|
|
46381
|
-
"unlock",
|
|
46382
|
-
"arm",
|
|
46383
|
-
"arm-home",
|
|
46384
|
-
"arm-away",
|
|
46385
|
-
"arm-night",
|
|
46386
|
-
"disarm",
|
|
46387
|
-
"light",
|
|
46388
|
-
"alert",
|
|
46389
|
-
"camera"
|
|
46390
|
-
]);
|
|
46391
|
-
/** A single tap-through action button. */
|
|
46392
|
-
var NotificationActionSchema = zod.z.object({
|
|
46393
|
-
id: zod.z.string(),
|
|
46394
|
-
label: zod.z.string(),
|
|
46395
|
-
url: zod.z.string().optional(),
|
|
46396
|
-
/** Dropped by the degrade engine for a kind with `caps.actionIcons: false`. */
|
|
46397
|
-
icon: NotificationActionIconSchema.optional(),
|
|
46398
|
-
/**
|
|
46399
|
-
* Renders in a warning style where the notifier supports it.
|
|
46400
|
-
*
|
|
46401
|
-
* A HINT, never a gate. The callback's authority is its token and nothing
|
|
46402
|
-
* else — see `notification-center/action-token.ts` for what that does and
|
|
46403
|
-
* does not buy.
|
|
46404
|
-
*/
|
|
46405
|
-
destructive: zod.z.boolean().optional(),
|
|
46406
|
-
/**
|
|
46407
|
-
* How the tap should REACH the url.
|
|
46408
|
-
*
|
|
46409
|
-
* `navigate` (absent, and every button authored before this field) opens it:
|
|
46410
|
-
* the phone leaves the notification and shows whatever the callback returns.
|
|
46411
|
-
* That is right for a button whose answer the operator wants to read.
|
|
46412
|
-
*
|
|
46413
|
-
* `background` fires it as a POST and stays put. It exists for the buttons
|
|
46414
|
-
* whose whole point is not to interrupt — "silence this for 30 minutes" is
|
|
46415
|
-
* an answer to the notification, and being thrown into a browser tab to
|
|
46416
|
-
* confirm it costs more attention than the notification did. A backend that
|
|
46417
|
-
* cannot do a background call renders it as an ordinary link (the adapters
|
|
46418
|
-
* fall back rather than dropping the button), so this is a preference, never
|
|
46419
|
-
* a requirement.
|
|
46420
|
-
*/
|
|
46421
|
-
mode: zod.z.enum(["navigate", "background"]).optional()
|
|
46422
|
-
});
|
|
46423
|
-
/** A delivery parameter value: what a notifier declared it takes. */
|
|
46424
|
-
var DeliveryParamValueSchema = zod.z.union([
|
|
46425
|
-
zod.z.string(),
|
|
46426
|
-
zod.z.number(),
|
|
46427
|
-
zod.z.boolean()
|
|
46428
|
-
]);
|
|
46429
|
-
/**
|
|
46430
|
-
* One extra delivery parameter a notifier KIND declares (D938). A rule that
|
|
46431
|
-
* addresses a target of that kind may set it; a kind that declares nothing is
|
|
46432
|
-
* never handed one. The admin UI derives its control from this descriptor —
|
|
46433
|
-
* no editor knows a service by name.
|
|
46434
|
-
*
|
|
46435
|
-
* Optional fields are `.optional()`, never `.default()` (a Zod default does not
|
|
46436
|
-
* run on the addon cap path).
|
|
46437
|
-
*/
|
|
46438
|
-
var DeliveryParamSchema = zod.z.object({
|
|
46439
|
-
key: zod.z.string().min(1),
|
|
46440
|
-
label: zod.z.string(),
|
|
46441
|
-
/** i18n key of the label, resolved by the declaring addon's namespace. */
|
|
46442
|
-
labelKey: zod.z.string().optional(),
|
|
46443
|
-
type: zod.z.enum([
|
|
46444
|
-
"enum",
|
|
46445
|
-
"number",
|
|
46446
|
-
"boolean",
|
|
46447
|
-
"string"
|
|
46448
|
-
]),
|
|
46449
|
-
/** `enum` only: the closed set of accepted values. */
|
|
46450
|
-
options: zod.z.array(zod.z.object({
|
|
46451
|
-
value: zod.z.string(),
|
|
46452
|
-
label: zod.z.string()
|
|
46453
|
-
})).optional(),
|
|
46454
|
-
/** `number` only. */
|
|
46455
|
-
min: zod.z.number().optional(),
|
|
46456
|
-
max: zod.z.number().optional(),
|
|
46457
|
-
/** What the notifier does when the rule sets nothing; shown as the placeholder. */
|
|
46458
|
-
default: DeliveryParamValueSchema.optional()
|
|
46459
|
-
});
|
|
46460
|
-
/**
|
|
46461
|
-
* The canonical notification. `body` is the only hard field (Apprise model).
|
|
46462
|
-
* `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
|
|
46463
|
-
* NOT a fixed severity enum — each kind declares its own `caps.levels` and
|
|
46464
|
-
* the adapter maps this ordinal onto its native level. `level?` is an
|
|
46465
|
-
* optional kind-native level id (`emergency`, `silent`, …) that overrides
|
|
46466
|
-
* `priority` for that one target.
|
|
46467
|
-
*/
|
|
46468
|
-
var NotificationSchema = zod.z.object({
|
|
46469
|
-
body: zod.z.string(),
|
|
46470
|
-
title: zod.z.string().optional(),
|
|
46471
|
-
format: NotificationFormatSchema.default("text"),
|
|
46472
|
-
priority: zod.z.number().int().min(1).max(5).default(3),
|
|
46473
|
-
level: zod.z.string().optional(),
|
|
46474
|
-
attachments: zod.z.array(AttachmentSchema).optional(),
|
|
46475
|
-
clickUrl: zod.z.string().optional(),
|
|
46476
|
-
actions: zod.z.array(NotificationActionSchema).optional(),
|
|
46477
|
-
sound: zod.z.string().optional(),
|
|
46478
|
-
ttl: zod.z.number().optional(),
|
|
46479
|
-
tag: zod.z.string().optional(),
|
|
46480
|
-
deviceId: zod.z.number().optional(),
|
|
46481
|
-
eventId: zod.z.string().optional(),
|
|
46482
|
-
metadata: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
|
|
46483
|
-
/**
|
|
46484
|
-
* Values for the parameters the target's kind DECLARES in
|
|
46485
|
-
* {@link TargetKindSchema} `deliveryParams`. Already validated against the
|
|
46486
|
-
* declaration by the sender; a notifier reads only the keys it declared.
|
|
46487
|
-
*/
|
|
46488
|
-
delivery: zod.z.record(zod.z.string(), DeliveryParamValueSchema).optional()
|
|
46489
|
-
});
|
|
46490
|
-
/** One declared native severity/priority level for a kind. */
|
|
46491
|
-
var TargetKindLevelSchema = zod.z.object({
|
|
46492
|
-
id: zod.z.string(),
|
|
46493
|
-
label: zod.z.string(),
|
|
46494
|
-
/** Which canonical priority (1..5) this level maps to. `null` = qualitative-only. */
|
|
46495
|
-
ordinal: zod.z.number().int().min(1).max(5).nullable(),
|
|
46496
|
-
flags: zod.z.object({
|
|
46497
|
-
critical: zod.z.boolean().optional(),
|
|
46498
|
-
silent: zod.z.boolean().optional(),
|
|
46499
|
-
noPush: zod.z.boolean().optional()
|
|
46500
|
-
}).optional(),
|
|
46501
|
-
/** e.g. Pushover `emergency` requires `retry` / `expire`. */
|
|
46502
|
-
requires: zod.z.array(zod.z.string()).optional(),
|
|
46503
|
-
description: zod.z.string().optional()
|
|
46504
|
-
});
|
|
46505
|
-
/** Attachment capabilities for a kind (drives the degrade engine + test panel). */
|
|
46506
|
-
var TargetKindAttachmentsCapsSchema = zod.z.object({
|
|
46507
|
-
mediaTypes: zod.z.array(AttachmentMediaTypeSchema),
|
|
46508
|
-
mode: zod.z.enum([
|
|
46509
|
-
"url",
|
|
46510
|
-
"bytes",
|
|
46511
|
-
"both"
|
|
46512
|
-
]),
|
|
46513
|
-
max: zod.z.number().int().nonnegative(),
|
|
46514
|
-
maxBytes: zod.z.number().int().positive().optional()
|
|
46515
|
-
});
|
|
46516
|
-
/** The full capability block consulted before dispatch. */
|
|
46517
|
-
var TargetKindCapsSchema = zod.z.object({
|
|
46518
|
-
attachments: TargetKindAttachmentsCapsSchema,
|
|
46519
|
-
/** Max action buttons (0 = none). */
|
|
46520
|
-
actions: zod.z.number().int().nonnegative(),
|
|
46521
|
-
/**
|
|
46522
|
-
* Whether this kind renders a per-action ICON.
|
|
46523
|
-
*
|
|
46524
|
-
* `.optional()`, deliberately NOT `.default(false)`: a Zod default does not
|
|
46525
|
-
* run on the addon cap path — three production failures in one day taught
|
|
46526
|
-
* this repo that once. Absent is read as false by the degrade engine, which
|
|
46527
|
-
* is the safe direction: an icon that is not rendered costs nothing, an icon
|
|
46528
|
-
* assumed and dropped costs the operator's trust in the field.
|
|
46529
|
-
*/
|
|
46530
|
-
actionIcons: zod.z.boolean().optional(),
|
|
46531
|
-
levels: zod.z.array(TargetKindLevelSchema),
|
|
46532
|
-
format: zod.z.array(NotificationFormatSchema),
|
|
46533
|
-
clickUrl: zod.z.boolean(),
|
|
46534
|
-
sound: zod.z.boolean(),
|
|
46535
|
-
ttl: zod.z.boolean(),
|
|
46536
|
-
bodyMaxLen: zod.z.number().int().positive()
|
|
46537
|
-
});
|
|
46538
|
-
/**
|
|
46539
|
-
* `configSchema` is a `ConfigUISchema` tree passed through to the admin
|
|
46540
|
-
* FormBuilder. Stored as `z.unknown()` at the cap seam (mirrors
|
|
46541
|
-
* `device-provider.getChildCreationSchema` `CreationSchemaOutputSchema`) —
|
|
46542
|
-
* the union is large and not meant for runtime validation here; the exported
|
|
46543
|
-
* `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
|
|
46544
|
-
*/
|
|
46545
|
-
var ConfigSchemaPassthrough$2 = zod.z.unknown();
|
|
46546
|
-
var TargetKindSchema = zod.z.object({
|
|
46547
|
-
kind: zod.z.string(),
|
|
46548
|
-
label: zod.z.string(),
|
|
46549
|
-
icon: zod.z.string(),
|
|
46550
|
-
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
46551
|
-
addonId: zod.z.string(),
|
|
46552
|
-
/**
|
|
46553
|
-
* URL of the kind's bundled BRAND icon, served by the providing addon over
|
|
46554
|
-
* its own `addon-routes` surface (`/addon/<addonId>/icons/<kind>`). Absent
|
|
46555
|
-
* when the addon bundles no icon for that kind — the client then falls back
|
|
46556
|
-
* to a neutral glyph rather than rendering the raw `icon` NAME as text.
|
|
46557
|
-
*
|
|
46558
|
-
* Root-relative on purpose: it resolves against whatever origin serves a web
|
|
46559
|
-
* client, and a native client joins it onto its own hub base.
|
|
46560
|
-
*
|
|
46561
|
-
* DECLARED here deliberately. It used to travel as an undeclared passthrough
|
|
46562
|
-
* field that survived only because the runtime cap-router forwards provider
|
|
46563
|
-
* output verbatim — so every consumer had to re-declare it by hand to stop
|
|
46564
|
-
* its own Zod parse from stripping it, and the whole arrangement would have
|
|
46565
|
-
* broken silently the moment output validation was tightened anywhere.
|
|
46566
|
-
*/
|
|
46567
|
-
iconUrl: zod.z.string().optional(),
|
|
46568
|
-
/**
|
|
46569
|
-
* Media type of {@link iconUrl} (`image/svg+xml`, `image/png`, …).
|
|
46570
|
-
*
|
|
46571
|
-
* The server knows this and therefore says it, because the client cannot
|
|
46572
|
-
* safely guess: a React-Native client renders SVG and raster through two
|
|
46573
|
-
* DIFFERENT components (`react-native-svg` vs `expo-image` — expo-image does
|
|
46574
|
-
* not decode SVG on iOS/Android), so without this it silently fell back to a
|
|
46575
|
-
* placeholder glyph for every vector icon while the web build looked fine.
|
|
46576
|
-
*
|
|
46577
|
-
* Absent when {@link iconUrl} is absent, or for a legacy provider that has
|
|
46578
|
-
* not been updated — a client that cannot determine the type should prefer
|
|
46579
|
-
* its raster path, which is the safe default for an unknown image.
|
|
46580
|
-
*/
|
|
46581
|
-
iconMediaType: zod.z.string().optional(),
|
|
46582
|
-
configSchema: ConfigSchemaPassthrough$2,
|
|
46583
|
-
/**
|
|
46584
|
-
* The config keys that decide WHERE this kind's secrets are sent (server,
|
|
46585
|
-
* base URL, instance, chat, recipient). A save that changes any of them
|
|
46586
|
-
* while leaving a secret redacted is refused by the provider (D634), so an
|
|
46587
|
-
* editor uses this to ask for the secret on exactly those edits instead of
|
|
46588
|
-
* on every edit.
|
|
46589
|
-
*
|
|
46590
|
-
* Optional: absent from a provider that holds no secret (the Home Assistant
|
|
46591
|
-
* kinds) and from a provider older than this field — an editor that finds
|
|
46592
|
-
* it absent must assume ANY edit may need the secret.
|
|
46593
|
-
*/
|
|
46594
|
-
destinationKeys: zod.z.array(zod.z.string()).optional(),
|
|
46595
|
-
supportsDiscovery: zod.z.boolean(),
|
|
46596
|
-
/**
|
|
46597
|
-
* Extra delivery parameters a rule may set for a target of this kind (D938).
|
|
46598
|
-
* Absent = none; the rule editor then offers nothing.
|
|
46599
|
-
*/
|
|
46600
|
-
deliveryParams: zod.z.array(DeliveryParamSchema).optional(),
|
|
46601
|
-
caps: TargetKindCapsSchema
|
|
46602
|
-
});
|
|
46603
|
-
/**
|
|
46604
|
-
* A persisted target. `config` holds secrets; providers REDACT secret fields
|
|
46605
|
-
* (return a presence marker only) when serving `listTargets` — never
|
|
46606
|
-
* round-trip a stored secret to the UI.
|
|
46607
|
-
*/
|
|
46608
|
-
var TargetSchema = zod.z.object({
|
|
46609
|
-
id: zod.z.string(),
|
|
46610
|
-
name: zod.z.string(),
|
|
46611
|
-
kind: zod.z.string(),
|
|
46612
|
-
addonId: zod.z.string(),
|
|
46613
|
-
enabled: zod.z.boolean(),
|
|
46614
|
-
config: zod.z.record(zod.z.string(), zod.z.unknown())
|
|
46615
|
-
});
|
|
46616
|
-
/** A discovery-surfaced candidate (config is partial + non-secret). */
|
|
46617
|
-
var DiscoveredTargetSchema = zod.z.object({
|
|
46618
|
-
kind: zod.z.string(),
|
|
46619
|
-
suggestedName: zod.z.string(),
|
|
46620
|
-
config: zod.z.record(zod.z.string(), zod.z.unknown())
|
|
46621
|
-
});
|
|
46622
|
-
/** The degrade engine's report — what was resolved / dropped / degraded. */
|
|
46623
|
-
var RenderedAsSchema = zod.z.object({
|
|
46624
|
-
level: zod.z.string(),
|
|
46625
|
-
format: NotificationFormatSchema,
|
|
46626
|
-
attachmentsSent: zod.z.number().int().nonnegative(),
|
|
46627
|
-
actionsSent: zod.z.number().int().nonnegative(),
|
|
46628
|
-
truncated: zod.z.boolean(),
|
|
46629
|
-
dropped: zod.z.array(zod.z.string())
|
|
46630
|
-
});
|
|
46631
|
-
var SendResultSchema = zod.z.object({
|
|
46632
|
-
success: zod.z.boolean(),
|
|
46633
|
-
error: zod.z.string().optional(),
|
|
46634
|
-
renderedAs: RenderedAsSchema.optional()
|
|
46635
|
-
});
|
|
46636
|
-
/** Same shape as SendResult — kept as a distinct name for the test panel. */
|
|
46637
|
-
var TestResultSchema = SendResultSchema;
|
|
46638
|
-
/**
|
|
46639
|
-
* Pre-save credential probe against a partial (unsaved) target config.
|
|
46640
|
-
* `resolvedUrl` never includes secrets (token stripped from path).
|
|
46641
|
-
*/
|
|
46642
|
-
var ProbeTargetConfigResultSchema = zod.z.object({
|
|
46643
|
-
ok: zod.z.boolean(),
|
|
46644
|
-
resolvedUrl: zod.z.string(),
|
|
46645
|
-
httpStatus: zod.z.number().int().optional(),
|
|
46646
|
-
stateInstance: zod.z.string().optional(),
|
|
46647
|
-
error: zod.z.string().optional()
|
|
46648
|
-
});
|
|
46649
|
-
var notificationOutputCapability = {
|
|
46650
|
-
name: "notification-output",
|
|
46651
|
-
scope: "system",
|
|
46652
|
-
mode: "collection",
|
|
46653
|
-
methods: {
|
|
46654
|
-
listTargetKinds: require_sleep.method(zod.z.object({}), zod.z.array(TargetKindSchema)),
|
|
46655
|
-
listTargets: require_sleep.method(zod.z.object({}), zod.z.array(TargetSchema), { auth: "admin" }),
|
|
46656
|
-
/**
|
|
46657
|
-
* One target WITH secrets — admin edit / duplicate hydration only.
|
|
46658
|
-
* `listTargets` stays redacted; the editor loads this so password fields
|
|
46659
|
-
* are filled (masked in the input) and a save can round-trip the token
|
|
46660
|
-
* when a destination changes (Duplicate with a new chatId, etc.).
|
|
46661
|
-
*/
|
|
46662
|
-
getTarget: require_sleep.method(zod.z.object({ targetId: zod.z.string() }), TargetSchema, { auth: "admin" }),
|
|
46663
|
-
discoverTargets: require_sleep.method(zod.z.object({
|
|
46664
|
-
kind: zod.z.string(),
|
|
46665
|
-
config: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
|
|
46666
|
-
/**
|
|
46667
|
-
* When editing / duplicating, the blank password field never round-trips
|
|
46668
|
-
* the stored token. Pass the source target id so the provider can restore
|
|
46669
|
-
* secrets server-side before dialling (same merge as upsert).
|
|
46670
|
-
*/
|
|
46671
|
-
targetId: zod.z.string().optional()
|
|
46672
|
-
}), zod.z.array(DiscoveredTargetSchema), { auth: "admin" }),
|
|
46673
|
-
probeTargetConfig: require_sleep.method(zod.z.object({
|
|
46674
|
-
kind: zod.z.string(),
|
|
46675
|
-
config: zod.z.record(zod.z.string(), zod.z.unknown()),
|
|
46676
|
-
/** See `discoverTargets.targetId` — restore stored secrets for a blank password. */
|
|
46677
|
-
targetId: zod.z.string().optional()
|
|
46678
|
-
}), ProbeTargetConfigResultSchema, {
|
|
46679
|
-
kind: "mutation",
|
|
46680
|
-
auth: "admin"
|
|
46681
|
-
}),
|
|
46682
|
-
send: require_sleep.method(zod.z.object({
|
|
46683
|
-
targetId: zod.z.string(),
|
|
46684
|
-
notification: NotificationSchema
|
|
46685
|
-
}), SendResultSchema, {
|
|
46686
|
-
kind: "mutation",
|
|
46687
|
-
auth: "admin"
|
|
46688
|
-
}),
|
|
46689
|
-
testTarget: require_sleep.method(zod.z.object({
|
|
46690
|
-
targetId: zod.z.string(),
|
|
46691
|
-
sample: NotificationSchema.optional()
|
|
46692
|
-
}), TestResultSchema, {
|
|
46693
|
-
kind: "mutation",
|
|
46694
|
-
auth: "admin"
|
|
46695
|
-
}),
|
|
46696
|
-
upsertTarget: require_sleep.method(zod.z.object({
|
|
46697
|
-
target: TargetSchema,
|
|
46698
|
-
/**
|
|
46699
|
-
* Duplicate flow: create a NEW target id while copying secrets from an
|
|
46700
|
-
* existing row. The UI never holds the stored token; blank / redacted
|
|
46701
|
-
* password fields are restored from this source (D634 still applies if
|
|
46702
|
-
* destinations diverge without a re-typed secret).
|
|
46703
|
-
*/
|
|
46704
|
-
cloneSecretsFrom: zod.z.string().optional()
|
|
46705
|
-
}), TargetSchema, {
|
|
46706
|
-
kind: "mutation",
|
|
46707
|
-
auth: "admin"
|
|
46708
|
-
}),
|
|
46709
|
-
deleteTarget: require_sleep.method(zod.z.object({ targetId: zod.z.string() }), zod.z.void(), {
|
|
46710
|
-
kind: "mutation",
|
|
46711
|
-
auth: "admin"
|
|
46712
|
-
}),
|
|
46713
|
-
setTargetEnabled: require_sleep.method(zod.z.object({
|
|
46714
|
-
targetId: zod.z.string(),
|
|
46715
|
-
enabled: zod.z.boolean()
|
|
46716
|
-
}), zod.z.void(), {
|
|
46717
|
-
kind: "mutation",
|
|
46718
|
-
auth: "admin"
|
|
46719
|
-
})
|
|
46720
|
-
}
|
|
46721
|
-
};
|
|
46722
|
-
//#endregion
|
|
46723
47035
|
//#region src/catalogs/audio-classmap.ts
|
|
46724
47036
|
var AUDIO_MACRO_LABELS = [
|
|
46725
47037
|
{
|
|
@@ -55594,14 +55906,6 @@ var EngineProvisioningSchema = zod.z.object({
|
|
|
55594
55906
|
*/
|
|
55595
55907
|
configIssues: zod.z.array(zod.z.string()).optional()
|
|
55596
55908
|
});
|
|
55597
|
-
var PipelineStepInputSchema = zod.z.lazy(() => zod.z.object({
|
|
55598
|
-
addonId: zod.z.string(),
|
|
55599
|
-
modelId: zod.z.string().optional(),
|
|
55600
|
-
enabled: zod.z.boolean().default(true),
|
|
55601
|
-
children: zod.z.array(PipelineStepInputSchema).optional(),
|
|
55602
|
-
settings: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
|
|
55603
|
-
jumpDeviceKey: zod.z.string().optional()
|
|
55604
|
-
}));
|
|
55605
55909
|
var ModelSubstitutionSchema = zod.z.object({
|
|
55606
55910
|
addonId: zod.z.string(),
|
|
55607
55911
|
chosen: zod.z.string(),
|
|
@@ -55680,7 +55984,6 @@ var ConfigUISchemaBridge = zod.z.custom();
|
|
|
55680
55984
|
var ConfigUISchemaNullableBridge = zod.z.custom();
|
|
55681
55985
|
var InferenceCapabilitiesBridge = zod.z.custom();
|
|
55682
55986
|
var ModelAvailabilityListBridge = zod.z.custom();
|
|
55683
|
-
var PipelineRunResultBridge = zod.z.custom();
|
|
55684
55987
|
/**
|
|
55685
55988
|
* Pipeline executor — detection engine + configuration + inference API.
|
|
55686
55989
|
*
|
|
@@ -55793,7 +56096,7 @@ var pipelineExecutorCapability = {
|
|
|
55793
56096
|
* reads any media: can this (node, deviceKey) run exactly this model?
|
|
55794
56097
|
*/
|
|
55795
56098
|
validatePipeline: require_sleep.method(zod.z.object({
|
|
55796
|
-
steps: zod.z.array(PipelineStepInputSchema),
|
|
56099
|
+
steps: zod.z.array(require_sleep.PipelineStepInputSchema),
|
|
55797
56100
|
deviceKey: zod.z.string().optional()
|
|
55798
56101
|
}), PipelineValidationResultSchema),
|
|
55799
56102
|
getCapabilities: require_sleep.method(zod.z.void(), InferenceCapabilitiesBridge),
|
|
@@ -55837,7 +56140,7 @@ var pipelineExecutorCapability = {
|
|
|
55837
56140
|
* - `referenceImage`: named file from the reference-image store.
|
|
55838
56141
|
*/
|
|
55839
56142
|
runPipeline: require_sleep.method(zod.z.object({
|
|
55840
|
-
steps: zod.z.array(PipelineStepInputSchema).min(1),
|
|
56143
|
+
steps: zod.z.array(require_sleep.PipelineStepInputSchema).min(1),
|
|
55841
56144
|
frame: FrameInputSchema.optional(),
|
|
55842
56145
|
/**
|
|
55843
56146
|
* Process-local lazy frame. Valid only when caller and provider resolve
|
|
@@ -55911,7 +56214,7 @@ var pipelineExecutorCapability = {
|
|
|
55911
56214
|
* PIXELS of the image this call carries. Absent ⇒ the root step runs.
|
|
55912
56215
|
*/
|
|
55913
56216
|
suppliedRoot: SuppliedRootOutputSchema.optional()
|
|
55914
|
-
}), PipelineRunResultBridge, { kind: "mutation" }),
|
|
56217
|
+
}), require_sleep.PipelineRunResultBridge, { kind: "mutation" }),
|
|
55915
56218
|
/**
|
|
55916
56219
|
* Batched run — N raw frames packed into one cap call. The provider
|
|
55917
56220
|
* routes the batch through `SharedInferencePool.inferBatch`
|
|
@@ -55924,7 +56227,7 @@ var pipelineExecutorCapability = {
|
|
|
55924
56227
|
* N frames in one call to amortise per-call IPC overhead.
|
|
55925
56228
|
*/
|
|
55926
56229
|
runPipelineBatch: require_sleep.method(zod.z.object({
|
|
55927
|
-
steps: zod.z.array(PipelineStepInputSchema).min(1),
|
|
56230
|
+
steps: zod.z.array(require_sleep.PipelineStepInputSchema).min(1),
|
|
55928
56231
|
frames: zod.z.array(FrameInputSchema).min(1).max(255),
|
|
55929
56232
|
deviceId: zod.z.number().optional(),
|
|
55930
56233
|
sessionId: zod.z.string().optional(),
|
|
@@ -55941,7 +56244,7 @@ var pipelineExecutorCapability = {
|
|
|
55941
56244
|
frameId: zod.z.number().int().nonnegative().optional(),
|
|
55942
56245
|
/** Inference-device selector (Phase 2 multi-device); see runPipeline. */
|
|
55943
56246
|
deviceKey: zod.z.string().optional()
|
|
55944
|
-
}), zod.z.object({ results: zod.z.array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }),
|
|
56247
|
+
}), zod.z.object({ results: zod.z.array(require_sleep.PipelineRunResultBridge).readonly() }), { kind: "mutation" }),
|
|
55945
56248
|
/**
|
|
55946
56249
|
* Cache a raw frame inside the Python inference pool's memory.
|
|
55947
56250
|
* Returns a numeric `frameId` that `inferCached` references —
|
|
@@ -57644,7 +57947,7 @@ var RunnerCameraConfigSchema = zod.z.object({
|
|
|
57644
57947
|
detectionSources: DetectionSourcesSchema.default(["pipeline"]),
|
|
57645
57948
|
pipelineEnabled: zod.z.boolean().default(true),
|
|
57646
57949
|
/** Ordered tree of video steps. Absent → runner skips video detection. */
|
|
57647
|
-
steps: zod.z.array(PipelineStepInputSchema).readonly().optional(),
|
|
57950
|
+
steps: zod.z.array(require_sleep.PipelineStepInputSchema).readonly().optional(),
|
|
57648
57951
|
/** Audio classification branch. `enabled:false` disables, null skips. */
|
|
57649
57952
|
audio: zod.z.object({
|
|
57650
57953
|
modelId: zod.z.string().optional(),
|
|
@@ -58379,7 +58682,7 @@ var pipelineRunnerCapability = {
|
|
|
58379
58682
|
//#region src/capabilities/pipeline-orchestrator.cap.ts
|
|
58380
58683
|
var CameraPipelineConfigSchema = zod.z.object({
|
|
58381
58684
|
engine: PipelineEngineChoiceSchema.optional(),
|
|
58382
|
-
steps: zod.z.array(PipelineStepInputSchema).readonly(),
|
|
58685
|
+
steps: zod.z.array(require_sleep.PipelineStepInputSchema).readonly(),
|
|
58383
58686
|
audio: zod.z.object({
|
|
58384
58687
|
engine: PipelineEngineChoiceSchema.optional(),
|
|
58385
58688
|
modelId: zod.z.string().optional(),
|
|
@@ -66984,14 +67287,13 @@ reset: require_sleep.method(zod.z.object({
|
|
|
66984
67287
|
auth: "admin"
|
|
66985
67288
|
}) },
|
|
66986
67289
|
/**
|
|
66987
|
-
* A
|
|
66988
|
-
*
|
|
66989
|
-
*
|
|
66990
|
-
* commands (`forward`) arrive in slice 3 (D663).
|
|
67290
|
+
* A consumable ADDED to an existing device (a graft) refuses `reset` by
|
|
67291
|
+
* name: only a composed device of a NEW type forwards an item's reset to a
|
|
67292
|
+
* source button, and marks that item `resettable` (D967).
|
|
66991
67293
|
*/
|
|
66992
67294
|
composedMethods: { reset: {
|
|
66993
67295
|
kind: "refuse",
|
|
66994
|
-
reason: "a
|
|
67296
|
+
reason: "a consumable added to an existing device is not resettable — only a new composed device forwards a reset"
|
|
66995
67297
|
} },
|
|
66996
67298
|
status: {
|
|
66997
67299
|
schema: ConsumablesStatusSchema,
|
|
@@ -67654,7 +67956,7 @@ var DishwasherStatusSchema = zod.z.object({
|
|
|
67654
67956
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
67655
67957
|
lastFetchedAt: zod.z.number()
|
|
67656
67958
|
});
|
|
67657
|
-
var DeviceIdSchema = zod.z.number().int().nonnegative();
|
|
67959
|
+
var DeviceIdSchema$1 = zod.z.number().int().nonnegative();
|
|
67658
67960
|
/** A value a program option or setting can take. */
|
|
67659
67961
|
var DishwasherValueSchema = zod.z.union([
|
|
67660
67962
|
zod.z.boolean(),
|
|
@@ -67729,77 +68031,77 @@ var dishwasherCapability = {
|
|
|
67729
68031
|
* option feature keys; each is checked against the program's constraints.
|
|
67730
68032
|
*/
|
|
67731
68033
|
start: require_sleep.method(zod.z.object({
|
|
67732
|
-
deviceId: DeviceIdSchema,
|
|
68034
|
+
deviceId: DeviceIdSchema$1,
|
|
67733
68035
|
program: zod.z.string().min(1).optional(),
|
|
67734
68036
|
options: zod.z.record(zod.z.string(), DishwasherValueSchema).optional()
|
|
67735
68037
|
}), zod.z.void(), {
|
|
67736
68038
|
kind: "mutation",
|
|
67737
68039
|
auth: "protected"
|
|
67738
68040
|
}),
|
|
67739
|
-
pause: require_sleep.method(zod.z.object({ deviceId: DeviceIdSchema }), zod.z.void(), {
|
|
68041
|
+
pause: require_sleep.method(zod.z.object({ deviceId: DeviceIdSchema$1 }), zod.z.void(), {
|
|
67740
68042
|
kind: "mutation",
|
|
67741
68043
|
auth: "protected"
|
|
67742
68044
|
}),
|
|
67743
|
-
resume: require_sleep.method(zod.z.object({ deviceId: DeviceIdSchema }), zod.z.void(), {
|
|
68045
|
+
resume: require_sleep.method(zod.z.object({ deviceId: DeviceIdSchema$1 }), zod.z.void(), {
|
|
67744
68046
|
kind: "mutation",
|
|
67745
68047
|
auth: "protected"
|
|
67746
68048
|
}),
|
|
67747
|
-
stop: require_sleep.method(zod.z.object({ deviceId: DeviceIdSchema }), zod.z.void(), {
|
|
68049
|
+
stop: require_sleep.method(zod.z.object({ deviceId: DeviceIdSchema$1 }), zod.z.void(), {
|
|
67748
68050
|
kind: "mutation",
|
|
67749
68051
|
auth: "protected"
|
|
67750
68052
|
}),
|
|
67751
68053
|
/** Select (not start) a program; refused when the appliance does not offer it. */
|
|
67752
68054
|
setProgram: require_sleep.method(zod.z.object({
|
|
67753
|
-
deviceId: DeviceIdSchema,
|
|
68055
|
+
deviceId: DeviceIdSchema$1,
|
|
67754
68056
|
program: zod.z.string().min(1)
|
|
67755
68057
|
}), zod.z.void(), {
|
|
67756
68058
|
kind: "mutation",
|
|
67757
68059
|
auth: "protected"
|
|
67758
68060
|
}),
|
|
67759
68061
|
setPower: require_sleep.method(zod.z.object({
|
|
67760
|
-
deviceId: DeviceIdSchema,
|
|
68062
|
+
deviceId: DeviceIdSchema$1,
|
|
67761
68063
|
on: zod.z.boolean()
|
|
67762
68064
|
}), zod.z.void(), {
|
|
67763
68065
|
kind: "mutation",
|
|
67764
68066
|
auth: "protected"
|
|
67765
68067
|
}),
|
|
67766
68068
|
setHalfLoad: require_sleep.method(zod.z.object({
|
|
67767
|
-
deviceId: DeviceIdSchema,
|
|
68069
|
+
deviceId: DeviceIdSchema$1,
|
|
67768
68070
|
on: zod.z.boolean()
|
|
67769
68071
|
}), zod.z.void(), {
|
|
67770
68072
|
kind: "mutation",
|
|
67771
68073
|
auth: "protected"
|
|
67772
68074
|
}),
|
|
67773
68075
|
setHygienePlus: require_sleep.method(zod.z.object({
|
|
67774
|
-
deviceId: DeviceIdSchema,
|
|
68076
|
+
deviceId: DeviceIdSchema$1,
|
|
67775
68077
|
on: zod.z.boolean()
|
|
67776
68078
|
}), zod.z.void(), {
|
|
67777
68079
|
kind: "mutation",
|
|
67778
68080
|
auth: "protected"
|
|
67779
68081
|
}),
|
|
67780
68082
|
setExtraDry: require_sleep.method(zod.z.object({
|
|
67781
|
-
deviceId: DeviceIdSchema,
|
|
68083
|
+
deviceId: DeviceIdSchema$1,
|
|
67782
68084
|
on: zod.z.boolean()
|
|
67783
68085
|
}), zod.z.void(), {
|
|
67784
68086
|
kind: "mutation",
|
|
67785
68087
|
auth: "protected"
|
|
67786
68088
|
}),
|
|
67787
68089
|
setIntensiveZone: require_sleep.method(zod.z.object({
|
|
67788
|
-
deviceId: DeviceIdSchema,
|
|
68090
|
+
deviceId: DeviceIdSchema$1,
|
|
67789
68091
|
on: zod.z.boolean()
|
|
67790
68092
|
}), zod.z.void(), {
|
|
67791
68093
|
kind: "mutation",
|
|
67792
68094
|
auth: "protected"
|
|
67793
68095
|
}),
|
|
67794
68096
|
setVarioSpeedPlus: require_sleep.method(zod.z.object({
|
|
67795
|
-
deviceId: DeviceIdSchema,
|
|
68097
|
+
deviceId: DeviceIdSchema$1,
|
|
67796
68098
|
on: zod.z.boolean()
|
|
67797
68099
|
}), zod.z.void(), {
|
|
67798
68100
|
kind: "mutation",
|
|
67799
68101
|
auth: "protected"
|
|
67800
68102
|
}),
|
|
67801
68103
|
setChildLock: require_sleep.method(zod.z.object({
|
|
67802
|
-
deviceId: DeviceIdSchema,
|
|
68104
|
+
deviceId: DeviceIdSchema$1,
|
|
67803
68105
|
on: zod.z.boolean()
|
|
67804
68106
|
}), zod.z.void(), {
|
|
67805
68107
|
kind: "mutation",
|
|
@@ -67811,7 +68113,7 @@ var dishwasherCapability = {
|
|
|
67811
68113
|
* its declared range / members.
|
|
67812
68114
|
*/
|
|
67813
68115
|
setOption: require_sleep.method(zod.z.object({
|
|
67814
|
-
deviceId: DeviceIdSchema,
|
|
68116
|
+
deviceId: DeviceIdSchema$1,
|
|
67815
68117
|
key: zod.z.string().min(1),
|
|
67816
68118
|
value: DishwasherValueSchema
|
|
67817
68119
|
}), zod.z.void(), {
|
|
@@ -67819,7 +68121,7 @@ var dishwasherCapability = {
|
|
|
67819
68121
|
auth: "protected"
|
|
67820
68122
|
}),
|
|
67821
68123
|
/** What this appliance can do, from its own description — the UI is derived from it. */
|
|
67822
|
-
getOptions: require_sleep.method(zod.z.object({ deviceId: DeviceIdSchema }), DishwasherOptionsSchema, { auth: "protected" })
|
|
68124
|
+
getOptions: require_sleep.method(zod.z.object({ deviceId: DeviceIdSchema$1 }), DishwasherOptionsSchema, { auth: "protected" })
|
|
67823
68125
|
},
|
|
67824
68126
|
status: {
|
|
67825
68127
|
schema: DishwasherStatusSchema,
|
|
@@ -72122,7 +72424,8 @@ var TopologyNodeSchema = zod.z.object({
|
|
|
72122
72424
|
isHub: zod.z.boolean(),
|
|
72123
72425
|
isOnline: zod.z.boolean(),
|
|
72124
72426
|
cpuPercent: zod.z.number(),
|
|
72125
|
-
|
|
72427
|
+
/** `null` when the node's memory read failed or it has not reported one (D393). */
|
|
72428
|
+
memoryPercent: zod.z.number().nullable(),
|
|
72126
72429
|
uptime: zod.z.number(),
|
|
72127
72430
|
lastSeen: zod.z.string(),
|
|
72128
72431
|
localIps: zod.z.array(zod.z.string()).readonly(),
|
|
@@ -72963,9 +73266,10 @@ var PetFeederStatusSchema = zod.z.object({
|
|
|
72963
73266
|
* combined reading; per-hopper levels live in `food1`/`food2`. Null when
|
|
72964
73267
|
* the device has not reported yet. */
|
|
72965
73268
|
foodLevel: zod.z.number().nullable().meta(require_sleep.readingMeta("none")),
|
|
72966
|
-
/** Food in the BOWL
|
|
72967
|
-
* feeder
|
|
72968
|
-
|
|
73269
|
+
/** Food in the BOWL, a mass (stored in kilograms, D944). Reported only by a
|
|
73270
|
+
* feeder with a bowl scale; null when the model has none or its reading is
|
|
73271
|
+
* of an unproven unit. */
|
|
73272
|
+
bowlFood: zod.z.number().nullable().meta(require_sleep.readingMeta("mass")),
|
|
72969
73273
|
/** True while the pet is eating (`state.eating`). */
|
|
72970
73274
|
eating: zod.z.boolean(),
|
|
72971
73275
|
/** Whether `markFoodReplenished` does anything on this model. When false
|
|
@@ -73150,6 +73454,139 @@ var petFeederCapability = {
|
|
|
73150
73454
|
} }
|
|
73151
73455
|
};
|
|
73152
73456
|
//#endregion
|
|
73457
|
+
//#region src/capabilities/pet-fountain.cap.ts
|
|
73458
|
+
/**
|
|
73459
|
+
* Pet water-fountain cap. Models the telemetry and the control surface of a
|
|
73460
|
+
* circulating drinking fountain: how much water is in the tank, how much the
|
|
73461
|
+
* pet drank, whether the pump runs and on what duty cycle.
|
|
73462
|
+
*
|
|
73463
|
+
* It has no native vendor provider of its own: a fountain reaches CamStack as
|
|
73464
|
+
* a container of loose entities (a pump switch, two number boxes, a "filter
|
|
73465
|
+
* changed" button), and an operator BUILDS the device from them — a composed
|
|
73466
|
+
* device of this type (D659, D967). Every method is therefore a forward to ONE
|
|
73467
|
+
* method of ONE source entity, and every reading is a field derived from a
|
|
73468
|
+
* source entity; the provider-shaped interface below exists so the composed
|
|
73469
|
+
* device and any future native provider answer the same contract.
|
|
73470
|
+
*
|
|
73471
|
+
* Quantities are stored in the base unit of their kind (D944): volumes in
|
|
73472
|
+
* LITRES, durations in SECONDS, the tank level in percent. A source that
|
|
73473
|
+
* reports millilitres or minutes is converted in the composition's expression,
|
|
73474
|
+
* never here. Every reading may be `null`: a source that is offline or does
|
|
73475
|
+
* not report is unknown, never zero.
|
|
73476
|
+
*
|
|
73477
|
+
* The filter is not a field of this cap: it is an item of the `consumables`
|
|
73478
|
+
* cap on the same device (kind `wear`), reset by the same forward mechanism.
|
|
73479
|
+
*/
|
|
73480
|
+
var PetFountainStatusSchema = zod.z.object({
|
|
73481
|
+
/** Water in the tank, 0..100 (%). Null while the source has not reported. */
|
|
73482
|
+
waterLevel: zod.z.number().min(0).max(100).nullable().meta(require_sleep.readingMeta("percentage")),
|
|
73483
|
+
/** Water in the tank, in litres. Null while the source has not reported. */
|
|
73484
|
+
waterVolume: zod.z.number().min(0).nullable().meta(require_sleep.readingMeta("volume")),
|
|
73485
|
+
/** True when the tank is empty. Null while unknown. */
|
|
73486
|
+
empty: zod.z.boolean().nullable(),
|
|
73487
|
+
/** True while the pump is running. Null while unknown. */
|
|
73488
|
+
pumpRunning: zod.z.boolean().nullable(),
|
|
73489
|
+
/** True when the pump works on an on/off duty cycle rather than continuously. */
|
|
73490
|
+
pumpIntervalEnabled: zod.z.boolean().nullable(),
|
|
73491
|
+
/** How long the pump runs per cycle, in seconds. */
|
|
73492
|
+
pumpOnTime: zod.z.number().min(0).nullable().meta(require_sleep.readingMeta("duration")),
|
|
73493
|
+
/** How long the pump rests per cycle, in seconds. */
|
|
73494
|
+
pumpOffTime: zod.z.number().min(0).nullable().meta(require_sleep.readingMeta("duration")),
|
|
73495
|
+
/** Water drunk in the last drink, in litres. */
|
|
73496
|
+
lastDrink: zod.z.number().min(0).nullable().meta(require_sleep.readingMeta("volume")),
|
|
73497
|
+
/** Water drunk in the current hour, in litres. */
|
|
73498
|
+
currentHourDrink: zod.z.number().min(0).nullable().meta(require_sleep.readingMeta("volume")),
|
|
73499
|
+
/** Water drunk over the last 24 hours (rolling), in litres. */
|
|
73500
|
+
last24hDrink: zod.z.number().min(0).nullable().meta(require_sleep.readingMeta("volume")),
|
|
73501
|
+
/** Water drunk since local midnight, in litres. */
|
|
73502
|
+
todayDrink: zod.z.number().min(0).nullable().meta(require_sleep.readingMeta("volume")),
|
|
73503
|
+
/** Decoded fault message. Null means healthy; a non-null string is an active fault. */
|
|
73504
|
+
error: zod.z.string().nullable(),
|
|
73505
|
+
/** Ms epoch when the slice was last refreshed. */
|
|
73506
|
+
lastFetchedAt: zod.z.number()
|
|
73507
|
+
});
|
|
73508
|
+
var DeviceIdSchema = zod.z.number().int().nonnegative();
|
|
73509
|
+
var MinutesSchema = zod.z.number().int().min(0);
|
|
73510
|
+
var petFountainCapability = {
|
|
73511
|
+
name: "pet-fountain",
|
|
73512
|
+
scope: "device",
|
|
73513
|
+
deviceNative: true,
|
|
73514
|
+
mode: "singleton",
|
|
73515
|
+
deviceTypes: [require_err_msg.DeviceType.PetFountain],
|
|
73516
|
+
methods: {
|
|
73517
|
+
/** Start or stop the pump. */
|
|
73518
|
+
setPump: require_sleep.method(zod.z.object({
|
|
73519
|
+
deviceId: DeviceIdSchema,
|
|
73520
|
+
on: zod.z.boolean()
|
|
73521
|
+
}), zod.z.void(), {
|
|
73522
|
+
kind: "mutation",
|
|
73523
|
+
auth: "protected"
|
|
73524
|
+
}),
|
|
73525
|
+
/** Switch the on/off duty cycle on or off (off = the pump runs continuously). */
|
|
73526
|
+
setPumpInterval: require_sleep.method(zod.z.object({
|
|
73527
|
+
deviceId: DeviceIdSchema,
|
|
73528
|
+
on: zod.z.boolean()
|
|
73529
|
+
}), zod.z.void(), {
|
|
73530
|
+
kind: "mutation",
|
|
73531
|
+
auth: "protected"
|
|
73532
|
+
}),
|
|
73533
|
+
/** Set how many minutes the pump runs per cycle. */
|
|
73534
|
+
setPumpOnMinutes: require_sleep.method(zod.z.object({
|
|
73535
|
+
deviceId: DeviceIdSchema,
|
|
73536
|
+
minutes: MinutesSchema
|
|
73537
|
+
}), zod.z.void(), {
|
|
73538
|
+
kind: "mutation",
|
|
73539
|
+
auth: "protected"
|
|
73540
|
+
}),
|
|
73541
|
+
/** Set how many minutes the pump rests per cycle. */
|
|
73542
|
+
setPumpOffMinutes: require_sleep.method(zod.z.object({
|
|
73543
|
+
deviceId: DeviceIdSchema,
|
|
73544
|
+
minutes: MinutesSchema
|
|
73545
|
+
}), zod.z.void(), {
|
|
73546
|
+
kind: "mutation",
|
|
73547
|
+
auth: "protected"
|
|
73548
|
+
}),
|
|
73549
|
+
/** Clear the rolling daily consumption counters on the device. */
|
|
73550
|
+
resetDailyConsumption: require_sleep.method(zod.z.object({ deviceId: DeviceIdSchema }), zod.z.void(), {
|
|
73551
|
+
kind: "mutation",
|
|
73552
|
+
auth: "protected"
|
|
73553
|
+
})
|
|
73554
|
+
},
|
|
73555
|
+
status: {
|
|
73556
|
+
schema: PetFountainStatusSchema,
|
|
73557
|
+
kind: "push"
|
|
73558
|
+
},
|
|
73559
|
+
/** Runtime-state slice — mirrored by the kernel; the hero card reads it whole. */
|
|
73560
|
+
runtimeState: PetFountainStatusSchema,
|
|
73561
|
+
/**
|
|
73562
|
+
* Runtime-state durability: **session** — live appliance state re-published on connect.
|
|
73563
|
+
*
|
|
73564
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
73565
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
73566
|
+
*/
|
|
73567
|
+
durability: "session",
|
|
73568
|
+
/** History (D850): recorded series. */
|
|
73569
|
+
history: { fields: {
|
|
73570
|
+
waterLevel: {
|
|
73571
|
+
kind: "gauge",
|
|
73572
|
+
unit: "%",
|
|
73573
|
+
deadband: 1
|
|
73574
|
+
},
|
|
73575
|
+
waterVolume: {
|
|
73576
|
+
kind: "gauge",
|
|
73577
|
+
unit: "L"
|
|
73578
|
+
},
|
|
73579
|
+
todayDrink: {
|
|
73580
|
+
kind: "gauge",
|
|
73581
|
+
unit: "L"
|
|
73582
|
+
},
|
|
73583
|
+
last24hDrink: {
|
|
73584
|
+
kind: "gauge",
|
|
73585
|
+
unit: "L"
|
|
73586
|
+
}
|
|
73587
|
+
} }
|
|
73588
|
+
};
|
|
73589
|
+
//#endregion
|
|
73153
73590
|
//#region src/capabilities/plate-gallery.cap.ts
|
|
73154
73591
|
var VehicleSchema = zod.z.object({
|
|
73155
73592
|
id: zod.z.string(),
|
|
@@ -83042,7 +83479,7 @@ var ROOM_EXAMPLE_MOTION_SOURCES = [{
|
|
|
83042
83479
|
addonId: "provider-homeassistant",
|
|
83043
83480
|
stableId: "binary_sensor.living_room_presence"
|
|
83044
83481
|
}];
|
|
83045
|
-
function from(source, cap, fieldPath) {
|
|
83482
|
+
function from$1(source, cap, fieldPath) {
|
|
83046
83483
|
return {
|
|
83047
83484
|
kind: "from",
|
|
83048
83485
|
source,
|
|
@@ -83051,7 +83488,7 @@ function from(source, cap, fieldPath) {
|
|
|
83051
83488
|
};
|
|
83052
83489
|
}
|
|
83053
83490
|
function named(prefix, sources, cap, fieldPath) {
|
|
83054
|
-
return Object.fromEntries(sources.map((s, i) => [`${prefix}${i + 1}`, from(s, cap, fieldPath)]));
|
|
83491
|
+
return Object.fromEntries(sources.map((s, i) => [`${prefix}${i + 1}`, from$1(s, cap, fieldPath)]));
|
|
83055
83492
|
}
|
|
83056
83493
|
function roomCompositionExample(input) {
|
|
83057
83494
|
const t = named("t", input.temperatureSources, "temperature-sensor", "temperature");
|
|
@@ -83139,7 +83576,7 @@ function feederExampleSources(brokerId) {
|
|
|
83139
83576
|
};
|
|
83140
83577
|
}
|
|
83141
83578
|
function feederCustomizationExample(sources) {
|
|
83142
|
-
const days = { d: from(sources.desiccantDays, "enum-sensor", "value") };
|
|
83579
|
+
const days = { d: from$1(sources.desiccantDays, "enum-sensor", "value") };
|
|
83143
83580
|
return require_composition.CompositionSchema.parse({
|
|
83144
83581
|
target: {
|
|
83145
83582
|
kind: "existing",
|
|
@@ -83187,7 +83624,7 @@ function feederCustomizationExample(sources) {
|
|
|
83187
83624
|
level: {
|
|
83188
83625
|
kind: "expression",
|
|
83189
83626
|
expr: "s == \"low\" ? 15 : (s == \"normal\" ? 100 : null)",
|
|
83190
|
-
bindings: { s: from(sources.batteryStatus, "enum-sensor", "value") }
|
|
83627
|
+
bindings: { s: from$1(sources.batteryStatus, "enum-sensor", "value") }
|
|
83191
83628
|
},
|
|
83192
83629
|
binary: {
|
|
83193
83630
|
kind: "expression",
|
|
@@ -83197,7 +83634,7 @@ function feederCustomizationExample(sources) {
|
|
|
83197
83634
|
charging: {
|
|
83198
83635
|
kind: "expression",
|
|
83199
83636
|
expr: "c ? \"dc\" : \"unknown\"",
|
|
83200
|
-
bindings: { c: from(sources.batteryCharging, "binary", "on") }
|
|
83637
|
+
bindings: { c: from$1(sources.batteryCharging, "binary", "on") }
|
|
83201
83638
|
},
|
|
83202
83639
|
sleeping: {
|
|
83203
83640
|
kind: "expression",
|
|
@@ -83283,6 +83720,158 @@ function convertPresetFeature(input) {
|
|
|
83283
83720
|
};
|
|
83284
83721
|
}
|
|
83285
83722
|
//#endregion
|
|
83723
|
+
//#region src/composition/presets/pet-fountain.ts
|
|
83724
|
+
/**
|
|
83725
|
+
* The preset for a pet water fountain built from loose entities (D659, D967).
|
|
83726
|
+
*
|
|
83727
|
+
* A fountain reaches CamStack as a container of single-purpose entities: a
|
|
83728
|
+
* pump switch, a cycle switch, two number boxes, a handful of sensors that
|
|
83729
|
+
* report millilitres as text, and a few buttons. This preset names the
|
|
83730
|
+
* `pet-fountain` cap's fields over those entities, forwards each of its five
|
|
83731
|
+
* methods to ONE entity method, and adds the filter as a resettable
|
|
83732
|
+
* `consumables` item.
|
|
83733
|
+
*
|
|
83734
|
+
* Stored quantities are base units (D944): litres for volume, seconds for
|
|
83735
|
+
* duration. The cycle times cannot be read back (see `pumpOnTime` below). The sensors are `enum-sensor`s, so their value is a STRING:
|
|
83736
|
+
* `number(x)` reads it and anything that is not a number stays `null`, never
|
|
83737
|
+
* 0 (D393). The caller supplies the sources — it knows which entity is which;
|
|
83738
|
+
* the preset guesses no entity id.
|
|
83739
|
+
*/
|
|
83740
|
+
var UNKNOWN = {
|
|
83741
|
+
kind: "expression",
|
|
83742
|
+
expr: "null",
|
|
83743
|
+
bindings: {}
|
|
83744
|
+
};
|
|
83745
|
+
var NOW = {
|
|
83746
|
+
kind: "expression",
|
|
83747
|
+
expr: "now",
|
|
83748
|
+
bindings: {}
|
|
83749
|
+
};
|
|
83750
|
+
function from(source, cap, fieldPath) {
|
|
83751
|
+
return {
|
|
83752
|
+
kind: "from",
|
|
83753
|
+
source,
|
|
83754
|
+
cap,
|
|
83755
|
+
fieldPath
|
|
83756
|
+
};
|
|
83757
|
+
}
|
|
83758
|
+
function over(name, binding, expr) {
|
|
83759
|
+
return {
|
|
83760
|
+
kind: "expression",
|
|
83761
|
+
expr,
|
|
83762
|
+
bindings: { [name]: binding }
|
|
83763
|
+
};
|
|
83764
|
+
}
|
|
83765
|
+
/** A text reading in millilitres, as litres; unreadable stays unknown. */
|
|
83766
|
+
function millilitresAsLitres(source) {
|
|
83767
|
+
return over("v", from(source, "enum-sensor", "value"), "number(v) == null ? null : number(v) / 1000");
|
|
83768
|
+
}
|
|
83769
|
+
function percentOf(source) {
|
|
83770
|
+
return over("l", from(source, "enum-sensor", "value"), "number(l)");
|
|
83771
|
+
}
|
|
83772
|
+
function filterFeature(filter) {
|
|
83773
|
+
const days = { d: from(filter.daysRemaining, "enum-sensor", "value") };
|
|
83774
|
+
return {
|
|
83775
|
+
kind: "fields",
|
|
83776
|
+
cap: "consumables",
|
|
83777
|
+
fields: {
|
|
83778
|
+
lastChangedAt: NOW,
|
|
83779
|
+
lastFetchedAt: NOW
|
|
83780
|
+
},
|
|
83781
|
+
items: { filter: {
|
|
83782
|
+
label: "Filter",
|
|
83783
|
+
fields: {
|
|
83784
|
+
"remaining.value": {
|
|
83785
|
+
kind: "expression",
|
|
83786
|
+
expr: "number(d)",
|
|
83787
|
+
bindings: days
|
|
83788
|
+
},
|
|
83789
|
+
"remaining.kind": {
|
|
83790
|
+
kind: "expression",
|
|
83791
|
+
expr: "\"duration\"",
|
|
83792
|
+
bindings: {}
|
|
83793
|
+
},
|
|
83794
|
+
status: {
|
|
83795
|
+
kind: "expression",
|
|
83796
|
+
expr: "number(d) == null ? null : (number(d) <= 0 ? \"replace\" : \"ok\")",
|
|
83797
|
+
bindings: days
|
|
83798
|
+
}
|
|
83799
|
+
},
|
|
83800
|
+
reset: {
|
|
83801
|
+
kind: "forward",
|
|
83802
|
+
source: filter.changed,
|
|
83803
|
+
cap: "button",
|
|
83804
|
+
method: "press"
|
|
83805
|
+
}
|
|
83806
|
+
} }
|
|
83807
|
+
};
|
|
83808
|
+
}
|
|
83809
|
+
function petFountainFromEntitiesComposition(sources) {
|
|
83810
|
+
const minutes = {
|
|
83811
|
+
kind: "numeric",
|
|
83812
|
+
value: { $input: "minutes" }
|
|
83813
|
+
};
|
|
83814
|
+
return require_composition.CompositionSchema.parse({
|
|
83815
|
+
target: {
|
|
83816
|
+
kind: "new",
|
|
83817
|
+
type: require_err_msg.DeviceType.PetFountain
|
|
83818
|
+
},
|
|
83819
|
+
features: [{
|
|
83820
|
+
kind: "fields",
|
|
83821
|
+
cap: "pet-fountain",
|
|
83822
|
+
fields: {
|
|
83823
|
+
waterLevel: percentOf(sources.waterLevel),
|
|
83824
|
+
waterVolume: millilitresAsLitres(sources.waterVolume),
|
|
83825
|
+
empty: over("l", from(sources.waterLevel, "enum-sensor", "value"), "number(l) == null ? null : number(l) <= 0"),
|
|
83826
|
+
pumpRunning: from(sources.pump, "switch", "on"),
|
|
83827
|
+
pumpIntervalEnabled: from(sources.pumpInterval, "switch", "on"),
|
|
83828
|
+
pumpOnTime: UNKNOWN,
|
|
83829
|
+
pumpOffTime: UNKNOWN,
|
|
83830
|
+
lastDrink: millilitresAsLitres(sources.lastDrink),
|
|
83831
|
+
currentHourDrink: millilitresAsLitres(sources.currentHourDrink),
|
|
83832
|
+
last24hDrink: millilitresAsLitres(sources.last24hDrink),
|
|
83833
|
+
todayDrink: millilitresAsLitres(sources.todayDrink),
|
|
83834
|
+
error: UNKNOWN,
|
|
83835
|
+
lastFetchedAt: NOW
|
|
83836
|
+
},
|
|
83837
|
+
commands: {
|
|
83838
|
+
setPump: {
|
|
83839
|
+
kind: "forward",
|
|
83840
|
+
source: sources.pump,
|
|
83841
|
+
cap: "switch",
|
|
83842
|
+
method: "setState"
|
|
83843
|
+
},
|
|
83844
|
+
setPumpInterval: {
|
|
83845
|
+
kind: "forward",
|
|
83846
|
+
source: sources.pumpInterval,
|
|
83847
|
+
cap: "switch",
|
|
83848
|
+
method: "setState"
|
|
83849
|
+
},
|
|
83850
|
+
setPumpOnMinutes: {
|
|
83851
|
+
kind: "forward",
|
|
83852
|
+
source: sources.pumpOnMinutes,
|
|
83853
|
+
cap: "control",
|
|
83854
|
+
method: "setValue",
|
|
83855
|
+
args: { control: minutes }
|
|
83856
|
+
},
|
|
83857
|
+
setPumpOffMinutes: {
|
|
83858
|
+
kind: "forward",
|
|
83859
|
+
source: sources.pumpOffMinutes,
|
|
83860
|
+
cap: "control",
|
|
83861
|
+
method: "setValue",
|
|
83862
|
+
args: { control: minutes }
|
|
83863
|
+
},
|
|
83864
|
+
resetDailyConsumption: {
|
|
83865
|
+
kind: "forward",
|
|
83866
|
+
source: sources.clearDaily,
|
|
83867
|
+
cap: "button",
|
|
83868
|
+
method: "press"
|
|
83869
|
+
}
|
|
83870
|
+
}
|
|
83871
|
+
}, ...sources.filter === void 0 ? [] : [filterFeature(sources.filter)]]
|
|
83872
|
+
});
|
|
83873
|
+
}
|
|
83874
|
+
//#endregion
|
|
83286
83875
|
//#region src/composition/cards/classify-field.ts
|
|
83287
83876
|
function fromSources(binding) {
|
|
83288
83877
|
return {
|
|
@@ -83532,6 +84121,7 @@ var CAP_CUSTOMIZE_CATALOG = {
|
|
|
83532
84121
|
require_err_msg.DeviceType.Container,
|
|
83533
84122
|
require_err_msg.DeviceType.Image,
|
|
83534
84123
|
require_err_msg.DeviceType.PetFeeder,
|
|
84124
|
+
require_err_msg.DeviceType.PetFountain,
|
|
83535
84125
|
require_err_msg.DeviceType.Dishwasher,
|
|
83536
84126
|
require_err_msg.DeviceType.Washer,
|
|
83537
84127
|
require_err_msg.DeviceType.Dryer
|
|
@@ -86044,6 +86634,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
86044
86634
|
notifier: notifierCapability,
|
|
86045
86635
|
numericSensor: numericSensorCapability,
|
|
86046
86636
|
petFeeder: petFeederCapability,
|
|
86637
|
+
petFountain: petFountainCapability,
|
|
86047
86638
|
powerMeter: powerMeterCapability,
|
|
86048
86639
|
presence: presenceCapability,
|
|
86049
86640
|
pressureSensor: pressureSensorCapability,
|
|
@@ -88032,6 +88623,7 @@ var DEVICE_TYPE_CONTROL_KIND = {
|
|
|
88032
88623
|
[require_err_msg.DeviceType.Container]: "dummy",
|
|
88033
88624
|
[require_err_msg.DeviceType.Image]: "image",
|
|
88034
88625
|
[require_err_msg.DeviceType.PetFeeder]: "pet-feeder",
|
|
88626
|
+
[require_err_msg.DeviceType.PetFountain]: "pet-fountain",
|
|
88035
88627
|
[require_err_msg.DeviceType.Dishwasher]: "dishwasher",
|
|
88036
88628
|
[require_err_msg.DeviceType.Washer]: "dummy",
|
|
88037
88629
|
[require_err_msg.DeviceType.Dryer]: "dummy"
|
|
@@ -90074,6 +90666,13 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
90074
90666
|
access: "create",
|
|
90075
90667
|
role: "admin"
|
|
90076
90668
|
},
|
|
90669
|
+
"deviceExport.exposeEntity": {
|
|
90670
|
+
capName: "device-export",
|
|
90671
|
+
capScope: "system",
|
|
90672
|
+
addonId: null,
|
|
90673
|
+
access: "create",
|
|
90674
|
+
role: "admin"
|
|
90675
|
+
},
|
|
90077
90676
|
"deviceExport.getDeviceLiveContribution": {
|
|
90078
90677
|
capName: "device-export",
|
|
90079
90678
|
capScope: "system",
|
|
@@ -90102,6 +90701,13 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
90102
90701
|
access: "view",
|
|
90103
90702
|
role: "admin"
|
|
90104
90703
|
},
|
|
90704
|
+
"deviceExport.listExposedEntities": {
|
|
90705
|
+
capName: "device-export",
|
|
90706
|
+
capScope: "system",
|
|
90707
|
+
addonId: null,
|
|
90708
|
+
access: "view",
|
|
90709
|
+
role: "admin"
|
|
90710
|
+
},
|
|
90105
90711
|
"deviceExport.listSupportedDeviceKinds": {
|
|
90106
90712
|
capName: "device-export",
|
|
90107
90713
|
capScope: "system",
|
|
@@ -90109,6 +90715,13 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
90109
90715
|
access: "view",
|
|
90110
90716
|
role: "admin"
|
|
90111
90717
|
},
|
|
90718
|
+
"deviceExport.listSupportedEntityKinds": {
|
|
90719
|
+
capName: "device-export",
|
|
90720
|
+
capScope: "system",
|
|
90721
|
+
addonId: null,
|
|
90722
|
+
access: "view",
|
|
90723
|
+
role: "admin"
|
|
90724
|
+
},
|
|
90112
90725
|
"deviceExport.unexposeDevice": {
|
|
90113
90726
|
capName: "device-export",
|
|
90114
90727
|
capScope: "system",
|
|
@@ -90116,6 +90729,13 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
90116
90729
|
access: "create",
|
|
90117
90730
|
role: "admin"
|
|
90118
90731
|
},
|
|
90732
|
+
"deviceExport.unexposeEntity": {
|
|
90733
|
+
capName: "device-export",
|
|
90734
|
+
capScope: "system",
|
|
90735
|
+
addonId: null,
|
|
90736
|
+
access: "create",
|
|
90737
|
+
role: "admin"
|
|
90738
|
+
},
|
|
90119
90739
|
"deviceExtension.listCandidates": {
|
|
90120
90740
|
capName: "device-extension",
|
|
90121
90741
|
capScope: "device",
|
|
@@ -93581,6 +94201,48 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
93581
94201
|
access: "create",
|
|
93582
94202
|
role: "viewer"
|
|
93583
94203
|
},
|
|
94204
|
+
"petFountain.getStatus": {
|
|
94205
|
+
capName: "pet-fountain",
|
|
94206
|
+
capScope: "device",
|
|
94207
|
+
addonId: null,
|
|
94208
|
+
access: "view",
|
|
94209
|
+
role: "viewer"
|
|
94210
|
+
},
|
|
94211
|
+
"petFountain.resetDailyConsumption": {
|
|
94212
|
+
capName: "pet-fountain",
|
|
94213
|
+
capScope: "device",
|
|
94214
|
+
addonId: null,
|
|
94215
|
+
access: "delete",
|
|
94216
|
+
role: "viewer"
|
|
94217
|
+
},
|
|
94218
|
+
"petFountain.setPump": {
|
|
94219
|
+
capName: "pet-fountain",
|
|
94220
|
+
capScope: "device",
|
|
94221
|
+
addonId: null,
|
|
94222
|
+
access: "create",
|
|
94223
|
+
role: "viewer"
|
|
94224
|
+
},
|
|
94225
|
+
"petFountain.setPumpInterval": {
|
|
94226
|
+
capName: "pet-fountain",
|
|
94227
|
+
capScope: "device",
|
|
94228
|
+
addonId: null,
|
|
94229
|
+
access: "create",
|
|
94230
|
+
role: "viewer"
|
|
94231
|
+
},
|
|
94232
|
+
"petFountain.setPumpOffMinutes": {
|
|
94233
|
+
capName: "pet-fountain",
|
|
94234
|
+
capScope: "device",
|
|
94235
|
+
addonId: null,
|
|
94236
|
+
access: "create",
|
|
94237
|
+
role: "viewer"
|
|
94238
|
+
},
|
|
94239
|
+
"petFountain.setPumpOnMinutes": {
|
|
94240
|
+
capName: "pet-fountain",
|
|
94241
|
+
capScope: "device",
|
|
94242
|
+
addonId: null,
|
|
94243
|
+
access: "create",
|
|
94244
|
+
role: "viewer"
|
|
94245
|
+
},
|
|
93584
94246
|
"pipelineAnalytics.addRetrainFrameFromRecording": {
|
|
93585
94247
|
capName: "pipeline-analytics",
|
|
93586
94248
|
capScope: "device",
|
|
@@ -98190,6 +98852,7 @@ var KNOWN_CAP_NAMES = [
|
|
|
98190
98852
|
"osd",
|
|
98191
98853
|
"osd-manager",
|
|
98192
98854
|
"pet-feeder",
|
|
98855
|
+
"pet-fountain",
|
|
98193
98856
|
"pipeline-analytics",
|
|
98194
98857
|
"pipeline-executor",
|
|
98195
98858
|
"pipeline-orchestrator",
|
|
@@ -98321,6 +98984,7 @@ var DEVICE_CAP_NAMES = [
|
|
|
98321
98984
|
"numeric-sensor",
|
|
98322
98985
|
"osd",
|
|
98323
98986
|
"pet-feeder",
|
|
98987
|
+
"pet-fountain",
|
|
98324
98988
|
"pipeline-analytics",
|
|
98325
98989
|
"power-meter",
|
|
98326
98990
|
"presence",
|
|
@@ -100460,6 +101124,100 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
100460
101124
|
}
|
|
100461
101125
|
]
|
|
100462
101126
|
},
|
|
101127
|
+
"pet-fountain": {
|
|
101128
|
+
scope: "device",
|
|
101129
|
+
noun: t("Pet fountain", "Fontana per animali"),
|
|
101130
|
+
actions: [
|
|
101131
|
+
{
|
|
101132
|
+
id: "petFountain.pumpOn",
|
|
101133
|
+
method: "setPump",
|
|
101134
|
+
label: t("Pump on", "Pompa accesa"),
|
|
101135
|
+
phrase: t("Start the pump of {device}", "Avvia la pompa di {device}"),
|
|
101136
|
+
icon: "play",
|
|
101137
|
+
args: { on: true }
|
|
101138
|
+
},
|
|
101139
|
+
{
|
|
101140
|
+
id: "petFountain.pumpOff",
|
|
101141
|
+
method: "setPump",
|
|
101142
|
+
label: t("Pump off", "Pompa spenta"),
|
|
101143
|
+
phrase: t("Stop the pump of {device}", "Ferma la pompa di {device}"),
|
|
101144
|
+
icon: "square",
|
|
101145
|
+
args: { on: false }
|
|
101146
|
+
},
|
|
101147
|
+
{
|
|
101148
|
+
id: "petFountain.intervalOn",
|
|
101149
|
+
method: "setPumpInterval",
|
|
101150
|
+
label: t("Pump cycle on", "Ciclo pompa attivo"),
|
|
101151
|
+
phrase: t("Run the pump of {device} on its on/off cycle", "Fai lavorare la pompa di {device} a ciclo acceso/spento"),
|
|
101152
|
+
icon: "timer",
|
|
101153
|
+
args: { on: true }
|
|
101154
|
+
},
|
|
101155
|
+
{
|
|
101156
|
+
id: "petFountain.intervalOff",
|
|
101157
|
+
method: "setPumpInterval",
|
|
101158
|
+
label: t("Pump cycle off", "Ciclo pompa spento"),
|
|
101159
|
+
phrase: t("Run the pump of {device} continuously", "Fai lavorare la pompa di {device} in continuo"),
|
|
101160
|
+
icon: "timer-off",
|
|
101161
|
+
args: { on: false }
|
|
101162
|
+
},
|
|
101163
|
+
{
|
|
101164
|
+
id: "petFountain.pumpOnMinutes",
|
|
101165
|
+
method: "setPumpOnMinutes",
|
|
101166
|
+
label: t("Set pump run time", "Imposta il tempo di lavoro della pompa"),
|
|
101167
|
+
phrase: t("Set the pump of {device} to run {minutes} minutes per cycle", "Imposta la pompa di {device} a lavorare {minutes} minuti per ciclo"),
|
|
101168
|
+
icon: "timer",
|
|
101169
|
+
openArgs: [{
|
|
101170
|
+
key: "minutes",
|
|
101171
|
+
label: t("Minutes", "Minuti"),
|
|
101172
|
+
offer: {
|
|
101173
|
+
kind: "number",
|
|
101174
|
+
min: 0,
|
|
101175
|
+
step: 1,
|
|
101176
|
+
unit: "min"
|
|
101177
|
+
}
|
|
101178
|
+
}]
|
|
101179
|
+
},
|
|
101180
|
+
{
|
|
101181
|
+
id: "petFountain.pumpOffMinutes",
|
|
101182
|
+
method: "setPumpOffMinutes",
|
|
101183
|
+
label: t("Set pump rest time", "Imposta il tempo di riposo della pompa"),
|
|
101184
|
+
phrase: t("Set the pump of {device} to rest {minutes} minutes per cycle", "Imposta la pompa di {device} a riposare {minutes} minuti per ciclo"),
|
|
101185
|
+
icon: "timer-off",
|
|
101186
|
+
openArgs: [{
|
|
101187
|
+
key: "minutes",
|
|
101188
|
+
label: t("Minutes", "Minuti"),
|
|
101189
|
+
offer: {
|
|
101190
|
+
kind: "number",
|
|
101191
|
+
min: 0,
|
|
101192
|
+
step: 1,
|
|
101193
|
+
unit: "min"
|
|
101194
|
+
}
|
|
101195
|
+
}]
|
|
101196
|
+
},
|
|
101197
|
+
{
|
|
101198
|
+
id: "petFountain.resetDailyConsumption",
|
|
101199
|
+
method: "resetDailyConsumption",
|
|
101200
|
+
label: t("Clear daily consumption", "Azzera il consumo giornaliero"),
|
|
101201
|
+
phrase: t("Clear the daily water consumption of {device}", "Azzera il consumo giornaliero di acqua di {device}"),
|
|
101202
|
+
icon: "rotate-ccw"
|
|
101203
|
+
}
|
|
101204
|
+
],
|
|
101205
|
+
state: [{
|
|
101206
|
+
kind: "boolean",
|
|
101207
|
+
field: "empty",
|
|
101208
|
+
label: t("Tank empty", "Serbatoio vuoto"),
|
|
101209
|
+
whenTrue: t("When the tank of {device} is empty", "Quando il serbatoio di {device} è vuoto"),
|
|
101210
|
+
whenFalse: t("When the tank of {device} is refilled", "Quando il serbatoio di {device} viene riempito"),
|
|
101211
|
+
icon: "droplet"
|
|
101212
|
+
}, {
|
|
101213
|
+
kind: "numeric",
|
|
101214
|
+
field: "waterLevel",
|
|
101215
|
+
quantity: t("the water level", "il livello dell’acqua"),
|
|
101216
|
+
label: t("Water level", "Livello dell’acqua"),
|
|
101217
|
+
unit: "%",
|
|
101218
|
+
icon: "droplets"
|
|
101219
|
+
}]
|
|
101220
|
+
},
|
|
100463
101221
|
"media-player": {
|
|
100464
101222
|
scope: "device",
|
|
100465
101223
|
noun: t("Media player", "Lettore multimediale"),
|
|
@@ -102522,6 +103280,7 @@ var DEVICE_TYPE_DO_CAPS = {
|
|
|
102522
103280
|
[require_err_msg.DeviceType.Container]: [],
|
|
102523
103281
|
[require_err_msg.DeviceType.Image]: [],
|
|
102524
103282
|
[require_err_msg.DeviceType.PetFeeder]: ["pet-feeder"],
|
|
103283
|
+
[require_err_msg.DeviceType.PetFountain]: ["pet-fountain"],
|
|
102525
103284
|
[require_err_msg.DeviceType.Dishwasher]: ["dishwasher"],
|
|
102526
103285
|
[require_err_msg.DeviceType.Washer]: [],
|
|
102527
103286
|
[require_err_msg.DeviceType.Dryer]: []
|
|
@@ -104140,6 +104899,7 @@ var CAP_NAMES_WITH_STATUS = [
|
|
|
104140
104899
|
"numeric-sensor",
|
|
104141
104900
|
"osd",
|
|
104142
104901
|
"pet-feeder",
|
|
104902
|
+
"pet-fountain",
|
|
104143
104903
|
"power-meter",
|
|
104144
104904
|
"presence",
|
|
104145
104905
|
"pressure-sensor",
|
|
@@ -104294,6 +105054,7 @@ var CAPABILITY_NAMES = {
|
|
|
104294
105054
|
osd: "osd",
|
|
104295
105055
|
osdManager: "osd-manager",
|
|
104296
105056
|
petFeeder: "pet-feeder",
|
|
105057
|
+
petFountain: "pet-fountain",
|
|
104297
105058
|
pipelineAnalytics: "pipeline-analytics",
|
|
104298
105059
|
pipelineExecutor: "pipeline-executor",
|
|
104299
105060
|
pipelineOrchestrator: "pipeline-orchestrator",
|
|
@@ -104866,6 +105627,10 @@ var CAPABILITY_ROUTER_KEYS = [
|
|
|
104866
105627
|
key: "petFeeder",
|
|
104867
105628
|
name: "pet-feeder"
|
|
104868
105629
|
},
|
|
105630
|
+
{
|
|
105631
|
+
key: "petFountain",
|
|
105632
|
+
name: "pet-fountain"
|
|
105633
|
+
},
|
|
104869
105634
|
{
|
|
104870
105635
|
key: "pipelineAnalytics",
|
|
104871
105636
|
name: "pipeline-analytics"
|
|
@@ -105141,7 +105906,7 @@ var ALL_CAPABILITY_DEFINITIONS = [
|
|
|
105141
105906
|
actionSourceCapability,
|
|
105142
105907
|
actionsCapability,
|
|
105143
105908
|
addonPagesCapability,
|
|
105144
|
-
addonPagesSourceCapability,
|
|
105909
|
+
require_sleep.addonPagesSourceCapability,
|
|
105145
105910
|
addonRoutesCapability,
|
|
105146
105911
|
addonSettingsCapability,
|
|
105147
105912
|
addonWidgetsCapability,
|
|
@@ -105263,6 +106028,7 @@ var ALL_CAPABILITY_DEFINITIONS = [
|
|
|
105263
106028
|
osdCapability,
|
|
105264
106029
|
osdManagerCapability,
|
|
105265
106030
|
petFeederCapability,
|
|
106031
|
+
petFountainCapability,
|
|
105266
106032
|
pipelineAnalyticsCapability,
|
|
105267
106033
|
pipelineExecutorCapability,
|
|
105268
106034
|
pipelineOrchestratorCapability,
|
|
@@ -106841,6 +107607,36 @@ var METHOD_DEVICE_SELECTORS = Object.freeze({
|
|
|
106841
107607
|
form: "single",
|
|
106842
107608
|
optional: false
|
|
106843
107609
|
}],
|
|
107610
|
+
"petFountain.getStatus": [{
|
|
107611
|
+
name: "deviceId",
|
|
107612
|
+
form: "single",
|
|
107613
|
+
optional: false
|
|
107614
|
+
}],
|
|
107615
|
+
"petFountain.resetDailyConsumption": [{
|
|
107616
|
+
name: "deviceId",
|
|
107617
|
+
form: "single",
|
|
107618
|
+
optional: false
|
|
107619
|
+
}],
|
|
107620
|
+
"petFountain.setPump": [{
|
|
107621
|
+
name: "deviceId",
|
|
107622
|
+
form: "single",
|
|
107623
|
+
optional: false
|
|
107624
|
+
}],
|
|
107625
|
+
"petFountain.setPumpInterval": [{
|
|
107626
|
+
name: "deviceId",
|
|
107627
|
+
form: "single",
|
|
107628
|
+
optional: false
|
|
107629
|
+
}],
|
|
107630
|
+
"petFountain.setPumpOffMinutes": [{
|
|
107631
|
+
name: "deviceId",
|
|
107632
|
+
form: "single",
|
|
107633
|
+
optional: false
|
|
107634
|
+
}],
|
|
107635
|
+
"petFountain.setPumpOnMinutes": [{
|
|
107636
|
+
name: "deviceId",
|
|
107637
|
+
form: "single",
|
|
107638
|
+
optional: false
|
|
107639
|
+
}],
|
|
106844
107640
|
"pipelineAnalytics.addRetrainFrameFromRecording": [{
|
|
106845
107641
|
name: "deviceId",
|
|
106846
107642
|
form: "single",
|
|
@@ -108398,7 +109194,7 @@ function getCapsByProviderKind(kind) {
|
|
|
108398
109194
|
//#region src/generated/runtime-state-durability.ts
|
|
108399
109195
|
/**
|
|
108400
109196
|
* Per-cap runtime-state policy, projected from every `*.cap.ts` that declares
|
|
108401
|
-
* `runtimeState`.
|
|
109197
|
+
* `runtimeState`. 77 caps: 39 `restored`, 38 `session`.
|
|
108402
109198
|
*
|
|
108403
109199
|
* A cap absent from this map has no runtime-state slice at all. A cap PRESENT
|
|
108404
109200
|
* with `durability: 'session'` has one and has decided not to keep it.
|
|
@@ -108604,6 +109400,10 @@ var RUNTIME_STATE_POLICY = {
|
|
|
108604
109400
|
durability: "session",
|
|
108605
109401
|
volatileFields: []
|
|
108606
109402
|
},
|
|
109403
|
+
"pet-fountain": {
|
|
109404
|
+
durability: "session",
|
|
109405
|
+
volatileFields: []
|
|
109406
|
+
},
|
|
108607
109407
|
"power-meter": {
|
|
108608
109408
|
durability: "restored",
|
|
108609
109409
|
volatileFields: ["lastFetchedAt"]
|
|
@@ -109591,7 +110391,11 @@ function createSystemProxy(api) {
|
|
|
109591
110391
|
listSupportedDeviceKinds: (input) => dispatch("deviceExport", "listSupportedDeviceKinds", "query", input),
|
|
109592
110392
|
listExposedDevices: (input) => dispatch("deviceExport", "listExposedDevices", "query", input),
|
|
109593
110393
|
exposeDevice: (input) => dispatch("deviceExport", "exposeDevice", "mutation", input),
|
|
109594
|
-
unexposeDevice: (input) => dispatch("deviceExport", "unexposeDevice", "mutation", input)
|
|
110394
|
+
unexposeDevice: (input) => dispatch("deviceExport", "unexposeDevice", "mutation", input),
|
|
110395
|
+
listSupportedEntityKinds: (input) => dispatch("deviceExport", "listSupportedEntityKinds", "query", input),
|
|
110396
|
+
listExposedEntities: (input) => dispatch("deviceExport", "listExposedEntities", "query", input),
|
|
110397
|
+
exposeEntity: (input) => dispatch("deviceExport", "exposeEntity", "mutation", input),
|
|
110398
|
+
unexposeEntity: (input) => dispatch("deviceExport", "unexposeEntity", "mutation", input)
|
|
109595
110399
|
},
|
|
109596
110400
|
deviceHistory: {
|
|
109597
110401
|
listNodeSeries: (input) => dispatch("deviceHistory", "listNodeSeries", "query", input),
|
|
@@ -121014,7 +121818,7 @@ exports.AddBrokerInputSchema = AddBrokerInputSchema;
|
|
|
121014
121818
|
exports.AddRetrainFrameFromRecordingResultSchema = AddRetrainFrameFromRecordingResultSchema;
|
|
121015
121819
|
exports.AddonAutoUpdateSchema = AddonAutoUpdateSchema;
|
|
121016
121820
|
exports.AddonListItemSchema = AddonListItemSchema;
|
|
121017
|
-
exports.AddonPageDeclarationSchema = AddonPageDeclarationSchema;
|
|
121821
|
+
exports.AddonPageDeclarationSchema = require_sleep.AddonPageDeclarationSchema;
|
|
121018
121822
|
exports.AddonPageInfoSchema = AddonPageInfoSchema;
|
|
121019
121823
|
exports.AddonRoutesScopeSchema = AddonRoutesScopeSchema;
|
|
121020
121824
|
exports.AdminLinkTargetEnum = AdminLinkTargetEnum;
|
|
@@ -121345,6 +122149,7 @@ exports.CompositionFieldSourceSchema = require_composition.CompositionFieldSourc
|
|
|
121345
122149
|
exports.CompositionFieldStateKindSchema = CompositionFieldStateKindSchema;
|
|
121346
122150
|
exports.CompositionFieldStateSchema = CompositionFieldStateSchema;
|
|
121347
122151
|
exports.CompositionFieldsFeatureSchema = require_composition.CompositionFieldsFeatureSchema;
|
|
122152
|
+
exports.CompositionForwardArgSchema = require_composition.CompositionForwardArgSchema;
|
|
121348
122153
|
exports.CompositionForwardCommandSchema = require_composition.CompositionForwardCommandSchema;
|
|
121349
122154
|
exports.CompositionFromSourceSchema = require_composition.CompositionFromSourceSchema;
|
|
121350
122155
|
exports.CompositionGetReadSchema = CompositionGetReadSchema;
|
|
@@ -121471,6 +122276,7 @@ exports.DEVICE_HISTORY_ENERGY_KEY = DEVICE_HISTORY_ENERGY_KEY;
|
|
|
121471
122276
|
exports.DEVICE_HISTORY_ORPHAN_DELETE_MAX = DEVICE_HISTORY_ORPHAN_DELETE_MAX;
|
|
121472
122277
|
exports.DEVICE_HISTORY_ORPHAN_LIST_MAX = DEVICE_HISTORY_ORPHAN_LIST_MAX;
|
|
121473
122278
|
exports.DEVICE_HISTORY_QUERY_MANY_MAX_ITEMS = DEVICE_HISTORY_QUERY_MANY_MAX_ITEMS;
|
|
122279
|
+
exports.DEVICE_ID_FIELD = DEVICE_ID_FIELD;
|
|
121474
122280
|
exports.DEVICE_NONCE_TTL_MS = DEVICE_NONCE_TTL_MS;
|
|
121475
122281
|
exports.DEVICE_PROFILES = DEVICE_PROFILES;
|
|
121476
122282
|
exports.DEVICE_RAMP = DEVICE_RAMP;
|
|
@@ -121653,6 +122459,8 @@ exports.ExportClipSubjectSchema = ExportClipSubjectSchema;
|
|
|
121653
122459
|
exports.ExportDenseRangeSchema = ExportDenseRangeSchema;
|
|
121654
122460
|
exports.ExportDenseSchema = ExportDenseSchema;
|
|
121655
122461
|
exports.ExportDownloadSchema = ExportDownloadSchema;
|
|
122462
|
+
exports.ExportEntityKindSchema = ExportEntityKindSchema;
|
|
122463
|
+
exports.ExportEntityRefSchema = ExportEntityRefSchema;
|
|
121656
122464
|
exports.ExportFootageSubjectSchema = ExportFootageSubjectSchema;
|
|
121657
122465
|
exports.ExportOptionsSchema = ExportOptionsSchema;
|
|
121658
122466
|
exports.ExportRecordSchema = ExportRecordSchema;
|
|
@@ -121662,7 +122470,9 @@ exports.ExportSpeedSchema = ExportSpeedSchema;
|
|
|
121662
122470
|
exports.ExportStateSchema = ExportStateSchema;
|
|
121663
122471
|
exports.ExportSubjectSchema = ExportSubjectSchema;
|
|
121664
122472
|
exports.ExportTimelapseSchema = ExportTimelapseSchema;
|
|
122473
|
+
exports.ExposeEntityInputSchema = ExposeEntityInputSchema;
|
|
121665
122474
|
exports.ExposedDeviceSchema = ExposedDeviceSchema;
|
|
122475
|
+
exports.ExposedEntitySchema = ExposedEntitySchema;
|
|
121666
122476
|
exports.ExposureModeSchema = ExposureModeSchema;
|
|
121667
122477
|
exports.ExpressionBindingSourceSchema = ExpressionBindingSourceSchema;
|
|
121668
122478
|
exports.ExpressionEvalError = require_composition.ExpressionEvalError;
|
|
@@ -121698,6 +122508,7 @@ exports.FEEDER_EXAMPLE_ADDON_ID = FEEDER_EXAMPLE_ADDON_ID;
|
|
|
121698
122508
|
exports.FEEDER_EXAMPLE_HA_DEVICE_ID = FEEDER_EXAMPLE_HA_DEVICE_ID;
|
|
121699
122509
|
exports.FFMPEG_PATH_ENV = require_composition.FFMPEG_PATH_ENV;
|
|
121700
122510
|
exports.FIRST_LEVEL_MACRO_CLASSES = FIRST_LEVEL_MACRO_CLASSES;
|
|
122511
|
+
exports.FORWARD_INPUT_KEY = require_composition.FORWARD_INPUT_KEY;
|
|
121701
122512
|
exports.FULL_IMAGE_BBOX = FULL_IMAGE_BBOX;
|
|
121702
122513
|
exports.FailureContributionSchema = FailureContributionSchema;
|
|
121703
122514
|
exports.FailureCounters = FailureCounters;
|
|
@@ -122410,6 +123221,7 @@ exports.PcmSampleFormatSchema = PcmSampleFormatSchema;
|
|
|
122410
123221
|
exports.PeerBytesTicketSchema = require_sleep.PeerBytesTicketSchema;
|
|
122411
123222
|
exports.PerScopeBreakdownSchema = PerScopeBreakdownSchema;
|
|
122412
123223
|
exports.PetFeederStatusSchema = PetFeederStatusSchema;
|
|
123224
|
+
exports.PetFountainStatusSchema = PetFountainStatusSchema;
|
|
122413
123225
|
exports.PickStreamPreferencesSchema = PickStreamPreferencesSchema;
|
|
122414
123226
|
exports.PickStreamRequirementsSchema = PickStreamRequirementsSchema;
|
|
122415
123227
|
exports.PickedCamStreamSchema = PickedCamStreamSchema;
|
|
@@ -122417,8 +123229,8 @@ exports.PipelineAssignmentSchema = PipelineAssignmentSchema;
|
|
|
122417
123229
|
exports.PipelineDefaultStepSchema = PipelineDefaultStepSchema;
|
|
122418
123230
|
exports.PipelineEngineChoiceSchema = PipelineEngineChoiceSchema;
|
|
122419
123231
|
exports.PipelineModelFormatStatusSchema = PipelineModelFormatStatusSchema;
|
|
122420
|
-
exports.PipelineRunResultBridge = PipelineRunResultBridge;
|
|
122421
|
-
exports.PipelineStepInputSchema = PipelineStepInputSchema;
|
|
123232
|
+
exports.PipelineRunResultBridge = require_sleep.PipelineRunResultBridge;
|
|
123233
|
+
exports.PipelineStepInputSchema = require_sleep.PipelineStepInputSchema;
|
|
122422
123234
|
exports.PipelineValidationIssueSchema = PipelineValidationIssueSchema;
|
|
122423
123235
|
exports.PipelineValidationResultSchema = PipelineValidationResultSchema;
|
|
122424
123236
|
exports.PlaceholderReasonSchema = PlaceholderReasonSchema;
|
|
@@ -123007,6 +123819,7 @@ exports.UNIT_TABLE = UNIT_TABLE;
|
|
|
123007
123819
|
exports.UNLOCK_CONFIRMATION = UNLOCK_CONFIRMATION;
|
|
123008
123820
|
exports.USE_ROOT_MODEL_DEFAULTS = USE_ROOT_MODEL_DEFAULTS;
|
|
123009
123821
|
exports.USE_ROOT_MODEL_SETTING_KEY = USE_ROOT_MODEL_SETTING_KEY;
|
|
123822
|
+
exports.UnexposeEntityInputSchema = UnexposeEntityInputSchema;
|
|
123010
123823
|
exports.UnifiedBrokerInfoSchema = BrokerInfoSchema;
|
|
123011
123824
|
exports.UnindexedFilterError = require_sleep.UnindexedFilterError;
|
|
123012
123825
|
exports.UninstallNodeOutcomeSchema = UninstallNodeOutcomeSchema;
|
|
@@ -123111,7 +123924,7 @@ exports.actuatorMethodRow = actuatorMethodRow;
|
|
|
123111
123924
|
exports.addonCatalogHref = addonCatalogHref;
|
|
123112
123925
|
exports.addonIdOfActionId = addonIdOfActionId;
|
|
123113
123926
|
exports.addonPagesCapability = addonPagesCapability;
|
|
123114
|
-
exports.addonPagesSourceCapability = addonPagesSourceCapability;
|
|
123927
|
+
exports.addonPagesSourceCapability = require_sleep.addonPagesSourceCapability;
|
|
123115
123928
|
exports.addonRoutesCapability = addonRoutesCapability;
|
|
123116
123929
|
exports.addonSettingsCapability = addonSettingsCapability;
|
|
123117
123930
|
exports.addonWidgetsCapability = addonWidgetsCapability;
|
|
@@ -123267,6 +124080,8 @@ exports.collectSecretMarkerRefs = require_sleep.collectSecretMarkerRefs;
|
|
|
123267
124080
|
exports.collectZodSecretPaths = require_sleep.collectZodSecretPaths;
|
|
123268
124081
|
exports.colorCapability = colorCapability;
|
|
123269
124082
|
exports.colorForKind = colorForKind;
|
|
124083
|
+
exports.commandMethodProblems = commandMethodProblems;
|
|
124084
|
+
exports.commandedMethods = commandedMethods;
|
|
123270
124085
|
exports.commitWatchdogRestart = commitWatchdogRestart;
|
|
123271
124086
|
exports.compareToTarget = compareToTarget;
|
|
123272
124087
|
exports.compileExpression = require_composition.compileExpression;
|
|
@@ -123480,6 +124295,7 @@ exports.failureRate = failureRate;
|
|
|
123480
124295
|
exports.fanControlCapability = fanControlCapability;
|
|
123481
124296
|
exports.fanOutTargets = fanOutTargets;
|
|
123482
124297
|
exports.featureFieldEntries = require_composition.featureFieldEntries;
|
|
124298
|
+
exports.featureForwards = featureForwards;
|
|
123483
124299
|
exports.featureOfRole = featureOfRole;
|
|
123484
124300
|
exports.featureProbeCapability = featureProbeCapability;
|
|
123485
124301
|
exports.featureSources = require_composition.featureSources;
|
|
@@ -123507,6 +124323,9 @@ exports.formatParkedFor = formatParkedFor;
|
|
|
123507
124323
|
exports.formatReading = formatReading;
|
|
123508
124324
|
exports.formatSecretScope = require_sleep.formatSecretScope;
|
|
123509
124325
|
exports.formulaProblem = formulaProblem;
|
|
124326
|
+
exports.forwardProblems = forwardProblems;
|
|
124327
|
+
exports.forwardSourceProblems = forwardSourceProblems;
|
|
124328
|
+
exports.forwardSourceRefs = forwardSourceRefs;
|
|
123510
124329
|
exports.freshResults = freshResults;
|
|
123511
124330
|
exports.fuseRecoveredDetections = fuseRecoveredDetections;
|
|
123512
124331
|
exports.gasCapability = gasCapability;
|
|
@@ -123597,6 +124416,7 @@ exports.isEvent = require_sleep.isEvent;
|
|
|
123597
124416
|
exports.isEventKindLabelKey = isEventKindLabelKey;
|
|
123598
124417
|
exports.isEventOwnerType = isEventOwnerType;
|
|
123599
124418
|
exports.isFirstLevelMacroClass = isFirstLevelMacroClass;
|
|
124419
|
+
exports.isForwardInputRef = require_composition.isForwardInputRef;
|
|
123600
124420
|
exports.isHeldBackTemplateVar = isHeldBackTemplateVar;
|
|
123601
124421
|
exports.isHistoryHelper = require_composition.isHistoryHelper;
|
|
123602
124422
|
exports.isIconKey = isIconKey;
|
|
@@ -123812,6 +124632,8 @@ exports.parseStreamParamsFormPatch = parseStreamParamsFormPatch;
|
|
|
123812
124632
|
exports.parseTrainingEventLine = parseTrainingEventLine;
|
|
123813
124633
|
exports.patchAudio = patchAudio;
|
|
123814
124634
|
exports.petFeederCapability = petFeederCapability;
|
|
124635
|
+
exports.petFountainCapability = petFountainCapability;
|
|
124636
|
+
exports.petFountainFromEntitiesComposition = petFountainFromEntitiesComposition;
|
|
123815
124637
|
exports.pickAccessoryControl = pickAccessoryControl;
|
|
123816
124638
|
exports.pickAppLinkHub = pickAppLinkHub;
|
|
123817
124639
|
exports.pickClusterStepModels = pickClusterStepModels;
|
|
@@ -123860,6 +124682,7 @@ exports.projectScalarAssignment = projectScalarAssignment;
|
|
|
123860
124682
|
exports.projectSpanAssignment = projectSpanAssignment;
|
|
123861
124683
|
exports.projectSubjectPath = projectSubjectPath;
|
|
123862
124684
|
exports.providerMotionEvent = providerMotionEvent;
|
|
124685
|
+
exports.pruneDeletedEntities = pruneDeletedEntities;
|
|
123863
124686
|
exports.ptzAutotrackCapability = ptzAutotrackCapability;
|
|
123864
124687
|
exports.ptzCapability = ptzCapability;
|
|
123865
124688
|
exports.publicEventCategories = require_event_category.publicEventCategories;
|
|
@@ -123989,6 +124812,7 @@ exports.ruleSection = ruleSection;
|
|
|
123989
124812
|
exports.ruleSectionOf = ruleSectionOf;
|
|
123990
124813
|
exports.ruleSeedForSection = ruleSeedForSection;
|
|
123991
124814
|
exports.ruleTriggerZoneIds = ruleTriggerZoneIds;
|
|
124815
|
+
exports.runExportedAction = runExportedAction;
|
|
123992
124816
|
exports.runFanOut = runFanOut;
|
|
123993
124817
|
exports.runInferenceStep = runInferenceStep;
|
|
123994
124818
|
exports.runSteps = runSteps;
|
|
@@ -124027,6 +124851,7 @@ exports.selectAssignedProfileSlots = require_sleep.selectAssignedProfileSlots;
|
|
|
124027
124851
|
exports.selectRecoveryStep = selectRecoveryStep;
|
|
124028
124852
|
exports.sendTimesForEditor = sendTimesForEditor;
|
|
124029
124853
|
exports.sendTimesOfSchedule = sendTimesOfSchedule;
|
|
124854
|
+
exports.sendToExportedTarget = sendToExportedTarget;
|
|
124030
124855
|
exports.sensorRaisedOf = sensorRaisedOf;
|
|
124031
124856
|
exports.sensorTransitionNeverFires = sensorTransitionNeverFires;
|
|
124032
124857
|
exports.sensorTransitionOffered = sensorTransitionOffered;
|