@camstack/types 1.2.442 → 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 +25 -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 +8 -3
- package/dist/capabilities/metrics-provider.cap.d.ts +16 -16
- package/dist/capabilities/node-removal-hook.cap.d.ts +67 -0
- 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 +3 -4
- 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 +149 -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 +10 -4
- 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 +1616 -607
- package/dist/index.mjs +1581 -596
- 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-DJws6ho7.mjs → sleep-6eG9C8Xl.mjs} +224 -72
- package/dist/{sleep-BpwNJ1Su.js → sleep-UXDHn-oJ.js} +247 -71
- package/dist/types/agent-pipeline-settings.d.ts +2 -2
- package/dist/utils/oauth-landing.d.ts +1 -1
- package/dist/vendor-login-proxy/flow-trace.d.ts +29 -0
- 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
|
};
|
|
@@ -43463,6 +44221,64 @@ var embeddingEncoderCapability = {
|
|
|
43463
44221
|
}
|
|
43464
44222
|
};
|
|
43465
44223
|
//#endregion
|
|
44224
|
+
//#region src/capabilities/node-removal-hook.cap.ts
|
|
44225
|
+
/**
|
|
44226
|
+
* `node-removal-hook` — the reliable way an addon learns a cluster node was
|
|
44227
|
+
* FORGOTTEN, so it can remove or re-point what it keeps for that node. The
|
|
44228
|
+
* node-scoped twin of `device-removal-hook` (D865); same shape, same rules.
|
|
44229
|
+
*
|
|
44230
|
+
* ## Why not "the node is absent"
|
|
44231
|
+
*
|
|
44232
|
+
* A node missing from topology is offline, restarting or not yet re-registered —
|
|
44233
|
+
* it is not forgotten. Deleting node-scoped data from absence destroys a live
|
|
44234
|
+
* node's configuration on any failed or partial read (D49). So the hook is
|
|
44235
|
+
* driven by a TOMBSTONE the hub records when the operator forgets a node
|
|
44236
|
+
* (`AgentRegistryService.forgetClusterNode`); nothing else produces one.
|
|
44237
|
+
*
|
|
44238
|
+
* ## The pieces
|
|
44239
|
+
*
|
|
44240
|
+
* 1. The hub records a tombstone `{ nodeId, removedAt, pending }` before it calls
|
|
44241
|
+
* anyone. `pending` is the set of implementers that have not yet acknowledged.
|
|
44242
|
+
* 2. The hub calls `onNodeRemoved` on EVERY provider of this collection, one by
|
|
44243
|
+
* one, with bounded retries, logged; an acknowledgement removes the
|
|
44244
|
+
* implementer from `pending`.
|
|
44245
|
+
* 3. The hub re-drives still-pending tombstones at boot, so an implementer that
|
|
44246
|
+
* was down at forget time is told when it is back.
|
|
44247
|
+
*
|
|
44248
|
+
* ## Contract for an implementer
|
|
44249
|
+
*
|
|
44250
|
+
* - **Idempotent.** Called again by a retry and by the boot re-drive. A node with
|
|
44251
|
+
* nothing left answers zero counts.
|
|
44252
|
+
* - **One key per store** in `counts`, rows changed per store, so the log line
|
|
44253
|
+
* can say where the data was.
|
|
44254
|
+
* - **Re-point or remove, never guess.** A row that merely MENTIONS the node as
|
|
44255
|
+
* a preference is re-pointed to "unset"; a row that only means something on
|
|
44256
|
+
* that node (a runtime bound to it) is removed.
|
|
44257
|
+
* - A provider that cannot tell is allowed to throw; the caller retries it.
|
|
44258
|
+
*/
|
|
44259
|
+
/** What a hook is told about the removal. */
|
|
44260
|
+
var NodeRemovedInputSchema = zod.z.object({
|
|
44261
|
+
nodeId: zod.z.string().min(1),
|
|
44262
|
+
/** Epoch ms the node was forgotten (the tombstone's `removedAt`). */
|
|
44263
|
+
removedAt: zod.z.number()
|
|
44264
|
+
});
|
|
44265
|
+
/** Rows changed (removed or re-pointed), per store this implementer owns. */
|
|
44266
|
+
var NodeRemovedResultSchema = zod.z.object({ counts: zod.z.record(zod.z.string(), zod.z.number().int().nonnegative()) });
|
|
44267
|
+
var nodeRemovalHookCapability = {
|
|
44268
|
+
name: "node-removal-hook",
|
|
44269
|
+
scope: "system",
|
|
44270
|
+
mode: "collection",
|
|
44271
|
+
internal: true,
|
|
44272
|
+
methods: {
|
|
44273
|
+
/** Remove or re-point everything this addon keeps for the forgotten node. Idempotent. */
|
|
44274
|
+
onNodeRemoved: require_sleep.method(NodeRemovedInputSchema, NodeRemovedResultSchema, {
|
|
44275
|
+
kind: "mutation",
|
|
44276
|
+
auth: "admin"
|
|
44277
|
+
}) },
|
|
44278
|
+
/** In-process only — enumerated through `addons.listCapabilityProviders`. */
|
|
44279
|
+
mount: { kind: "skip" }
|
|
44280
|
+
};
|
|
44281
|
+
//#endregion
|
|
43466
44282
|
//#region src/capabilities/device-removal-hook.cap.ts
|
|
43467
44283
|
/**
|
|
43468
44284
|
* `device-removal-hook` — the reliable way an addon learns a device was DELETED,
|
|
@@ -44737,7 +45553,7 @@ var LlmProviderWidgetSchema = zod.z.object({
|
|
|
44737
45553
|
/** ConfigUISchema tree passed through untyped on the wire (the
|
|
44738
45554
|
* notification-output `ConfigSchemaPassthrough` precedent at
|
|
44739
45555
|
* notification-output.cap.ts:151); the exported TS type re-tightens it. */
|
|
44740
|
-
var ConfigSchemaPassthrough$
|
|
45556
|
+
var ConfigSchemaPassthrough$2 = zod.z.unknown();
|
|
44741
45557
|
var LlmProfileKindDescriptorSchema = zod.z.object({
|
|
44742
45558
|
kind: LlmProfileKindSchema,
|
|
44743
45559
|
label: zod.z.string(),
|
|
@@ -44746,9 +45562,9 @@ var LlmProfileKindDescriptorSchema = zod.z.object({
|
|
|
44746
45562
|
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
44747
45563
|
addonId: zod.z.string(),
|
|
44748
45564
|
/** The provider's own fields (`providerConfig`); `password` fields are keychain-held. */
|
|
44749
|
-
connectionSchema: ConfigSchemaPassthrough$
|
|
45565
|
+
connectionSchema: ConfigSchemaPassthrough$2,
|
|
44750
45566
|
/** Provider fields that belong under "Advanced" (extra headers, runtime tuning). */
|
|
44751
|
-
advancedSchema: ConfigSchemaPassthrough$
|
|
45567
|
+
advancedSchema: ConfigSchemaPassthrough$2.optional(),
|
|
44752
45568
|
/** The kind's defaults; a model from `listModels` may override any of them. */
|
|
44753
45569
|
features: LlmModelFeaturesSchema,
|
|
44754
45570
|
/** `false` = the provider stamps `supportsVision` itself (from what a node reports). */
|
|
@@ -45505,10 +46321,10 @@ var CpuBreakdownSchema = zod.z.object({
|
|
|
45505
46321
|
cores: zod.z.number()
|
|
45506
46322
|
});
|
|
45507
46323
|
var MemoryInfoSchema = zod.z.object({
|
|
45508
|
-
percent: zod.z.number(),
|
|
46324
|
+
percent: zod.z.number().nullable(),
|
|
45509
46325
|
totalBytes: zod.z.number(),
|
|
45510
|
-
usedBytes: zod.z.number(),
|
|
45511
|
-
availableBytes: zod.z.number(),
|
|
46326
|
+
usedBytes: zod.z.number().nullable(),
|
|
46327
|
+
availableBytes: zod.z.number().nullable(),
|
|
45512
46328
|
swapUsedBytes: zod.z.number(),
|
|
45513
46329
|
swapTotalBytes: zod.z.number()
|
|
45514
46330
|
});
|
|
@@ -45812,8 +46628,9 @@ var GetLoadSeriesInputSchema = zod.z.object({
|
|
|
45812
46628
|
});
|
|
45813
46629
|
var SystemMetricsSchema = zod.z.object({
|
|
45814
46630
|
cpuPercent: zod.z.number(),
|
|
45815
|
-
|
|
45816
|
-
|
|
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(),
|
|
45817
46634
|
memoryTotalMB: zod.z.number(),
|
|
45818
46635
|
diskPercent: zod.z.number().optional(),
|
|
45819
46636
|
temperature: zod.z.number().optional(),
|
|
@@ -46215,453 +47032,6 @@ var networkAccessCapability = {
|
|
|
46215
47032
|
}
|
|
46216
47033
|
};
|
|
46217
47034
|
//#endregion
|
|
46218
|
-
//#region src/capabilities/notification-output.cap.ts
|
|
46219
|
-
/**
|
|
46220
|
-
* notification-output — canonical, capability-gated notification delivery.
|
|
46221
|
-
*
|
|
46222
|
-
* Apprise-derived model (see
|
|
46223
|
-
* `docs/superpowers/specs/2026-07-03-notification-output-notifier-matrix.md`):
|
|
46224
|
-
* callers emit ONE canonical `Notification`; each provider declares a
|
|
46225
|
-
* per-kind capability descriptor (`TargetKind`), and the pure degrade
|
|
46226
|
-
* engine (`@camstack/types` `prepareNotification`) transcodes / degrades the
|
|
46227
|
-
* message to what the kind supports — callers never special-case a service.
|
|
46228
|
-
*
|
|
46229
|
-
* DESIGN DECISIONS (locked):
|
|
46230
|
-
* - Target CRUD lives on THIS cap (`upsertTarget` / `deleteTarget` /
|
|
46231
|
-
* `setTargetEnabled`), each provider persisting via the `settings-store`
|
|
46232
|
-
* cap. Rationale: the admin UI needs one uniform surface across the
|
|
46233
|
-
* notifiers addon AND the HA addon; the addon-`globalSettingsSchema`-array
|
|
46234
|
-
* alternative would fork the UI per addon and cannot host the
|
|
46235
|
-
* discovery→adopt flow.
|
|
46236
|
-
* - `listTargetKinds` / `listTargets` / `discoverTargets` return arrays →
|
|
46237
|
-
* the generated cap-mount auto-`concatCollection`-fans them across every
|
|
46238
|
-
* registered provider (notifiers addon + HA addon) so one catalog is
|
|
46239
|
-
* routable. `send` / `testTarget` / CRUD route to ONE provider by the
|
|
46240
|
-
* `addonId` the generated collection router extracts from the call input.
|
|
46241
|
-
* - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
|
|
46242
|
-
* transformer) + UDS MsgPack both round-trip typed arrays — already used by
|
|
46243
|
-
* `storage` / `storage-provider` / `recording` caps over the same path. No
|
|
46244
|
-
* base64 fallback needed.
|
|
46245
|
-
*
|
|
46246
|
-
* TODO (deferred, closed-set change — separate decision): add
|
|
46247
|
-
* `providerKind: 'notify'` so notification providers surface on the unified
|
|
46248
|
-
* admin "Integrations" page.
|
|
46249
|
-
*/
|
|
46250
|
-
/**
|
|
46251
|
-
* Zentik-derived typed-media enum — the superset across every kind. Each
|
|
46252
|
-
* adapter picks what it supports and the degrade engine filters the rest.
|
|
46253
|
-
*/
|
|
46254
|
-
var AttachmentMediaTypeSchema = zod.z.enum([
|
|
46255
|
-
"image",
|
|
46256
|
-
"video",
|
|
46257
|
-
"gif",
|
|
46258
|
-
"audio",
|
|
46259
|
-
"icon"
|
|
46260
|
-
]);
|
|
46261
|
-
/**
|
|
46262
|
-
* A single attachment. Exactly one of `url` (remote source, most adapters
|
|
46263
|
-
* prefer this) or `bytes` (inline source; required for Pushover-style
|
|
46264
|
-
* bytes-only kinds) MUST be present — the degrade engine expresses a
|
|
46265
|
-
* url→bytes fetch as a `needsFetch` directive the adapter executes.
|
|
46266
|
-
*/
|
|
46267
|
-
var AttachmentSchema = zod.z.object({
|
|
46268
|
-
mediaType: AttachmentMediaTypeSchema,
|
|
46269
|
-
url: zod.z.string().optional(),
|
|
46270
|
-
bytes: zod.z.instanceof(Uint8Array).optional(),
|
|
46271
|
-
mime: zod.z.string().optional(),
|
|
46272
|
-
name: zod.z.string().optional()
|
|
46273
|
-
}).refine((a) => a.url !== void 0 || a.bytes !== void 0, { message: "Attachment requires either `url` or `bytes`" });
|
|
46274
|
-
var NotificationFormatSchema = zod.z.enum([
|
|
46275
|
-
"text",
|
|
46276
|
-
"markdown",
|
|
46277
|
-
"html"
|
|
46278
|
-
]);
|
|
46279
|
-
/**
|
|
46280
|
-
* The CLOSED icon vocabulary an action button may use.
|
|
46281
|
-
*
|
|
46282
|
-
* A closed set, not a free string, and that is the whole point: an arbitrary
|
|
46283
|
-
* icon name is one that ntfy renders, zentik silently drops, and nobody
|
|
46284
|
-
* notices — the same class of gap as a zone vocabulary nothing produced
|
|
46285
|
-
* ([D35](../../../docs/decisions/adr-0035.md)). Every adapter maps this set or
|
|
46286
|
-
* declares `actionIcons: false` and the degrade engine strips the field.
|
|
46287
|
-
*
|
|
46288
|
-
* Named by INTENT, never by glyph. "check" would tie the vocabulary to one
|
|
46289
|
-
* renderer's icon set; "acknowledge" survives an adapter that draws it
|
|
46290
|
-
* differently.
|
|
46291
|
-
*
|
|
46292
|
-
* ── A TOKEN IS NOT A WIRE VALUE ─────────────────────────────────────
|
|
46293
|
-
*
|
|
46294
|
-
* These names are for US. **No adapter may forward one verbatim.** Each maps
|
|
46295
|
-
* the whole set onto its own renderer's vocabulary through a
|
|
46296
|
-
* `Record<NotificationActionIcon, string>` — a Record, never a lookup with a
|
|
46297
|
-
* fallback, so adding a member here fails every adapter's build until someone
|
|
46298
|
-
* decides its glyph, which is the only place that decision can be made
|
|
46299
|
-
* honestly.
|
|
46300
|
-
*
|
|
46301
|
-
* This paragraph is the bug. Zentik declared `actionIcons: true` and passed
|
|
46302
|
-
* `disarm` straight through; iOS feeds that string to
|
|
46303
|
-
* `UNNotificationActionIcon(systemImageName:)`, `disarm` is not an SF Symbol,
|
|
46304
|
-
* and every snooze and alarm button arrived BLANK. A pass-through is not a
|
|
46305
|
-
* mapping, and "the field is documented" is not "the value renders".
|
|
46306
|
-
*
|
|
46307
|
-
* Adding a member is TRAIN-BOUND. The enum lives in the published
|
|
46308
|
-
* `@camstack/server` closure and the cap seam validates against the HUB's copy,
|
|
46309
|
-
* so an addon that emits a token the running hub does not know does not lose an
|
|
46310
|
-
* icon — its whole `send` fails Zod validation and the notification never
|
|
46311
|
-
* arrives. Never emit a new token from an addon before the train carrying it.
|
|
46312
|
-
*/
|
|
46313
|
-
var NotificationActionIconSchema = zod.z.enum([
|
|
46314
|
-
"acknowledge",
|
|
46315
|
-
"dismiss",
|
|
46316
|
-
"silence",
|
|
46317
|
-
"snooze",
|
|
46318
|
-
"view",
|
|
46319
|
-
"play",
|
|
46320
|
-
"open",
|
|
46321
|
-
"close",
|
|
46322
|
-
"lock",
|
|
46323
|
-
"unlock",
|
|
46324
|
-
"arm",
|
|
46325
|
-
"arm-home",
|
|
46326
|
-
"arm-away",
|
|
46327
|
-
"arm-night",
|
|
46328
|
-
"disarm",
|
|
46329
|
-
"light",
|
|
46330
|
-
"alert",
|
|
46331
|
-
"camera"
|
|
46332
|
-
]);
|
|
46333
|
-
/** A single tap-through action button. */
|
|
46334
|
-
var NotificationActionSchema = zod.z.object({
|
|
46335
|
-
id: zod.z.string(),
|
|
46336
|
-
label: zod.z.string(),
|
|
46337
|
-
url: zod.z.string().optional(),
|
|
46338
|
-
/** Dropped by the degrade engine for a kind with `caps.actionIcons: false`. */
|
|
46339
|
-
icon: NotificationActionIconSchema.optional(),
|
|
46340
|
-
/**
|
|
46341
|
-
* Renders in a warning style where the notifier supports it.
|
|
46342
|
-
*
|
|
46343
|
-
* A HINT, never a gate. The callback's authority is its token and nothing
|
|
46344
|
-
* else — see `notification-center/action-token.ts` for what that does and
|
|
46345
|
-
* does not buy.
|
|
46346
|
-
*/
|
|
46347
|
-
destructive: zod.z.boolean().optional(),
|
|
46348
|
-
/**
|
|
46349
|
-
* How the tap should REACH the url.
|
|
46350
|
-
*
|
|
46351
|
-
* `navigate` (absent, and every button authored before this field) opens it:
|
|
46352
|
-
* the phone leaves the notification and shows whatever the callback returns.
|
|
46353
|
-
* That is right for a button whose answer the operator wants to read.
|
|
46354
|
-
*
|
|
46355
|
-
* `background` fires it as a POST and stays put. It exists for the buttons
|
|
46356
|
-
* whose whole point is not to interrupt — "silence this for 30 minutes" is
|
|
46357
|
-
* an answer to the notification, and being thrown into a browser tab to
|
|
46358
|
-
* confirm it costs more attention than the notification did. A backend that
|
|
46359
|
-
* cannot do a background call renders it as an ordinary link (the adapters
|
|
46360
|
-
* fall back rather than dropping the button), so this is a preference, never
|
|
46361
|
-
* a requirement.
|
|
46362
|
-
*/
|
|
46363
|
-
mode: zod.z.enum(["navigate", "background"]).optional()
|
|
46364
|
-
});
|
|
46365
|
-
/** A delivery parameter value: what a notifier declared it takes. */
|
|
46366
|
-
var DeliveryParamValueSchema = zod.z.union([
|
|
46367
|
-
zod.z.string(),
|
|
46368
|
-
zod.z.number(),
|
|
46369
|
-
zod.z.boolean()
|
|
46370
|
-
]);
|
|
46371
|
-
/**
|
|
46372
|
-
* One extra delivery parameter a notifier KIND declares (D938). A rule that
|
|
46373
|
-
* addresses a target of that kind may set it; a kind that declares nothing is
|
|
46374
|
-
* never handed one. The admin UI derives its control from this descriptor —
|
|
46375
|
-
* no editor knows a service by name.
|
|
46376
|
-
*
|
|
46377
|
-
* Optional fields are `.optional()`, never `.default()` (a Zod default does not
|
|
46378
|
-
* run on the addon cap path).
|
|
46379
|
-
*/
|
|
46380
|
-
var DeliveryParamSchema = zod.z.object({
|
|
46381
|
-
key: zod.z.string().min(1),
|
|
46382
|
-
label: zod.z.string(),
|
|
46383
|
-
/** i18n key of the label, resolved by the declaring addon's namespace. */
|
|
46384
|
-
labelKey: zod.z.string().optional(),
|
|
46385
|
-
type: zod.z.enum([
|
|
46386
|
-
"enum",
|
|
46387
|
-
"number",
|
|
46388
|
-
"boolean",
|
|
46389
|
-
"string"
|
|
46390
|
-
]),
|
|
46391
|
-
/** `enum` only: the closed set of accepted values. */
|
|
46392
|
-
options: zod.z.array(zod.z.object({
|
|
46393
|
-
value: zod.z.string(),
|
|
46394
|
-
label: zod.z.string()
|
|
46395
|
-
})).optional(),
|
|
46396
|
-
/** `number` only. */
|
|
46397
|
-
min: zod.z.number().optional(),
|
|
46398
|
-
max: zod.z.number().optional(),
|
|
46399
|
-
/** What the notifier does when the rule sets nothing; shown as the placeholder. */
|
|
46400
|
-
default: DeliveryParamValueSchema.optional()
|
|
46401
|
-
});
|
|
46402
|
-
/**
|
|
46403
|
-
* The canonical notification. `body` is the only hard field (Apprise model).
|
|
46404
|
-
* `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
|
|
46405
|
-
* NOT a fixed severity enum — each kind declares its own `caps.levels` and
|
|
46406
|
-
* the adapter maps this ordinal onto its native level. `level?` is an
|
|
46407
|
-
* optional kind-native level id (`emergency`, `silent`, …) that overrides
|
|
46408
|
-
* `priority` for that one target.
|
|
46409
|
-
*/
|
|
46410
|
-
var NotificationSchema = zod.z.object({
|
|
46411
|
-
body: zod.z.string(),
|
|
46412
|
-
title: zod.z.string().optional(),
|
|
46413
|
-
format: NotificationFormatSchema.default("text"),
|
|
46414
|
-
priority: zod.z.number().int().min(1).max(5).default(3),
|
|
46415
|
-
level: zod.z.string().optional(),
|
|
46416
|
-
attachments: zod.z.array(AttachmentSchema).optional(),
|
|
46417
|
-
clickUrl: zod.z.string().optional(),
|
|
46418
|
-
actions: zod.z.array(NotificationActionSchema).optional(),
|
|
46419
|
-
sound: zod.z.string().optional(),
|
|
46420
|
-
ttl: zod.z.number().optional(),
|
|
46421
|
-
tag: zod.z.string().optional(),
|
|
46422
|
-
deviceId: zod.z.number().optional(),
|
|
46423
|
-
eventId: zod.z.string().optional(),
|
|
46424
|
-
metadata: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
|
|
46425
|
-
/**
|
|
46426
|
-
* Values for the parameters the target's kind DECLARES in
|
|
46427
|
-
* {@link TargetKindSchema} `deliveryParams`. Already validated against the
|
|
46428
|
-
* declaration by the sender; a notifier reads only the keys it declared.
|
|
46429
|
-
*/
|
|
46430
|
-
delivery: zod.z.record(zod.z.string(), DeliveryParamValueSchema).optional()
|
|
46431
|
-
});
|
|
46432
|
-
/** One declared native severity/priority level for a kind. */
|
|
46433
|
-
var TargetKindLevelSchema = zod.z.object({
|
|
46434
|
-
id: zod.z.string(),
|
|
46435
|
-
label: zod.z.string(),
|
|
46436
|
-
/** Which canonical priority (1..5) this level maps to. `null` = qualitative-only. */
|
|
46437
|
-
ordinal: zod.z.number().int().min(1).max(5).nullable(),
|
|
46438
|
-
flags: zod.z.object({
|
|
46439
|
-
critical: zod.z.boolean().optional(),
|
|
46440
|
-
silent: zod.z.boolean().optional(),
|
|
46441
|
-
noPush: zod.z.boolean().optional()
|
|
46442
|
-
}).optional(),
|
|
46443
|
-
/** e.g. Pushover `emergency` requires `retry` / `expire`. */
|
|
46444
|
-
requires: zod.z.array(zod.z.string()).optional(),
|
|
46445
|
-
description: zod.z.string().optional()
|
|
46446
|
-
});
|
|
46447
|
-
/** Attachment capabilities for a kind (drives the degrade engine + test panel). */
|
|
46448
|
-
var TargetKindAttachmentsCapsSchema = zod.z.object({
|
|
46449
|
-
mediaTypes: zod.z.array(AttachmentMediaTypeSchema),
|
|
46450
|
-
mode: zod.z.enum([
|
|
46451
|
-
"url",
|
|
46452
|
-
"bytes",
|
|
46453
|
-
"both"
|
|
46454
|
-
]),
|
|
46455
|
-
max: zod.z.number().int().nonnegative(),
|
|
46456
|
-
maxBytes: zod.z.number().int().positive().optional()
|
|
46457
|
-
});
|
|
46458
|
-
/** The full capability block consulted before dispatch. */
|
|
46459
|
-
var TargetKindCapsSchema = zod.z.object({
|
|
46460
|
-
attachments: TargetKindAttachmentsCapsSchema,
|
|
46461
|
-
/** Max action buttons (0 = none). */
|
|
46462
|
-
actions: zod.z.number().int().nonnegative(),
|
|
46463
|
-
/**
|
|
46464
|
-
* Whether this kind renders a per-action ICON.
|
|
46465
|
-
*
|
|
46466
|
-
* `.optional()`, deliberately NOT `.default(false)`: a Zod default does not
|
|
46467
|
-
* run on the addon cap path — three production failures in one day taught
|
|
46468
|
-
* this repo that once. Absent is read as false by the degrade engine, which
|
|
46469
|
-
* is the safe direction: an icon that is not rendered costs nothing, an icon
|
|
46470
|
-
* assumed and dropped costs the operator's trust in the field.
|
|
46471
|
-
*/
|
|
46472
|
-
actionIcons: zod.z.boolean().optional(),
|
|
46473
|
-
levels: zod.z.array(TargetKindLevelSchema),
|
|
46474
|
-
format: zod.z.array(NotificationFormatSchema),
|
|
46475
|
-
clickUrl: zod.z.boolean(),
|
|
46476
|
-
sound: zod.z.boolean(),
|
|
46477
|
-
ttl: zod.z.boolean(),
|
|
46478
|
-
bodyMaxLen: zod.z.number().int().positive()
|
|
46479
|
-
});
|
|
46480
|
-
/**
|
|
46481
|
-
* `configSchema` is a `ConfigUISchema` tree passed through to the admin
|
|
46482
|
-
* FormBuilder. Stored as `z.unknown()` at the cap seam (mirrors
|
|
46483
|
-
* `device-provider.getChildCreationSchema` `CreationSchemaOutputSchema`) —
|
|
46484
|
-
* the union is large and not meant for runtime validation here; the exported
|
|
46485
|
-
* `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
|
|
46486
|
-
*/
|
|
46487
|
-
var ConfigSchemaPassthrough$2 = zod.z.unknown();
|
|
46488
|
-
var TargetKindSchema = zod.z.object({
|
|
46489
|
-
kind: zod.z.string(),
|
|
46490
|
-
label: zod.z.string(),
|
|
46491
|
-
icon: zod.z.string(),
|
|
46492
|
-
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
46493
|
-
addonId: zod.z.string(),
|
|
46494
|
-
/**
|
|
46495
|
-
* URL of the kind's bundled BRAND icon, served by the providing addon over
|
|
46496
|
-
* its own `addon-routes` surface (`/addon/<addonId>/icons/<kind>`). Absent
|
|
46497
|
-
* when the addon bundles no icon for that kind — the client then falls back
|
|
46498
|
-
* to a neutral glyph rather than rendering the raw `icon` NAME as text.
|
|
46499
|
-
*
|
|
46500
|
-
* Root-relative on purpose: it resolves against whatever origin serves a web
|
|
46501
|
-
* client, and a native client joins it onto its own hub base.
|
|
46502
|
-
*
|
|
46503
|
-
* DECLARED here deliberately. It used to travel as an undeclared passthrough
|
|
46504
|
-
* field that survived only because the runtime cap-router forwards provider
|
|
46505
|
-
* output verbatim — so every consumer had to re-declare it by hand to stop
|
|
46506
|
-
* its own Zod parse from stripping it, and the whole arrangement would have
|
|
46507
|
-
* broken silently the moment output validation was tightened anywhere.
|
|
46508
|
-
*/
|
|
46509
|
-
iconUrl: zod.z.string().optional(),
|
|
46510
|
-
/**
|
|
46511
|
-
* Media type of {@link iconUrl} (`image/svg+xml`, `image/png`, …).
|
|
46512
|
-
*
|
|
46513
|
-
* The server knows this and therefore says it, because the client cannot
|
|
46514
|
-
* safely guess: a React-Native client renders SVG and raster through two
|
|
46515
|
-
* DIFFERENT components (`react-native-svg` vs `expo-image` — expo-image does
|
|
46516
|
-
* not decode SVG on iOS/Android), so without this it silently fell back to a
|
|
46517
|
-
* placeholder glyph for every vector icon while the web build looked fine.
|
|
46518
|
-
*
|
|
46519
|
-
* Absent when {@link iconUrl} is absent, or for a legacy provider that has
|
|
46520
|
-
* not been updated — a client that cannot determine the type should prefer
|
|
46521
|
-
* its raster path, which is the safe default for an unknown image.
|
|
46522
|
-
*/
|
|
46523
|
-
iconMediaType: zod.z.string().optional(),
|
|
46524
|
-
configSchema: ConfigSchemaPassthrough$2,
|
|
46525
|
-
/**
|
|
46526
|
-
* The config keys that decide WHERE this kind's secrets are sent (server,
|
|
46527
|
-
* base URL, instance, chat, recipient). A save that changes any of them
|
|
46528
|
-
* while leaving a secret redacted is refused by the provider (D634), so an
|
|
46529
|
-
* editor uses this to ask for the secret on exactly those edits instead of
|
|
46530
|
-
* on every edit.
|
|
46531
|
-
*
|
|
46532
|
-
* Optional: absent from a provider that holds no secret (the Home Assistant
|
|
46533
|
-
* kinds) and from a provider older than this field — an editor that finds
|
|
46534
|
-
* it absent must assume ANY edit may need the secret.
|
|
46535
|
-
*/
|
|
46536
|
-
destinationKeys: zod.z.array(zod.z.string()).optional(),
|
|
46537
|
-
supportsDiscovery: zod.z.boolean(),
|
|
46538
|
-
/**
|
|
46539
|
-
* Extra delivery parameters a rule may set for a target of this kind (D938).
|
|
46540
|
-
* Absent = none; the rule editor then offers nothing.
|
|
46541
|
-
*/
|
|
46542
|
-
deliveryParams: zod.z.array(DeliveryParamSchema).optional(),
|
|
46543
|
-
caps: TargetKindCapsSchema
|
|
46544
|
-
});
|
|
46545
|
-
/**
|
|
46546
|
-
* A persisted target. `config` holds secrets; providers REDACT secret fields
|
|
46547
|
-
* (return a presence marker only) when serving `listTargets` — never
|
|
46548
|
-
* round-trip a stored secret to the UI.
|
|
46549
|
-
*/
|
|
46550
|
-
var TargetSchema = zod.z.object({
|
|
46551
|
-
id: zod.z.string(),
|
|
46552
|
-
name: zod.z.string(),
|
|
46553
|
-
kind: zod.z.string(),
|
|
46554
|
-
addonId: zod.z.string(),
|
|
46555
|
-
enabled: zod.z.boolean(),
|
|
46556
|
-
config: zod.z.record(zod.z.string(), zod.z.unknown())
|
|
46557
|
-
});
|
|
46558
|
-
/** A discovery-surfaced candidate (config is partial + non-secret). */
|
|
46559
|
-
var DiscoveredTargetSchema = zod.z.object({
|
|
46560
|
-
kind: zod.z.string(),
|
|
46561
|
-
suggestedName: zod.z.string(),
|
|
46562
|
-
config: zod.z.record(zod.z.string(), zod.z.unknown())
|
|
46563
|
-
});
|
|
46564
|
-
/** The degrade engine's report — what was resolved / dropped / degraded. */
|
|
46565
|
-
var RenderedAsSchema = zod.z.object({
|
|
46566
|
-
level: zod.z.string(),
|
|
46567
|
-
format: NotificationFormatSchema,
|
|
46568
|
-
attachmentsSent: zod.z.number().int().nonnegative(),
|
|
46569
|
-
actionsSent: zod.z.number().int().nonnegative(),
|
|
46570
|
-
truncated: zod.z.boolean(),
|
|
46571
|
-
dropped: zod.z.array(zod.z.string())
|
|
46572
|
-
});
|
|
46573
|
-
var SendResultSchema = zod.z.object({
|
|
46574
|
-
success: zod.z.boolean(),
|
|
46575
|
-
error: zod.z.string().optional(),
|
|
46576
|
-
renderedAs: RenderedAsSchema.optional()
|
|
46577
|
-
});
|
|
46578
|
-
/** Same shape as SendResult — kept as a distinct name for the test panel. */
|
|
46579
|
-
var TestResultSchema = SendResultSchema;
|
|
46580
|
-
/**
|
|
46581
|
-
* Pre-save credential probe against a partial (unsaved) target config.
|
|
46582
|
-
* `resolvedUrl` never includes secrets (token stripped from path).
|
|
46583
|
-
*/
|
|
46584
|
-
var ProbeTargetConfigResultSchema = zod.z.object({
|
|
46585
|
-
ok: zod.z.boolean(),
|
|
46586
|
-
resolvedUrl: zod.z.string(),
|
|
46587
|
-
httpStatus: zod.z.number().int().optional(),
|
|
46588
|
-
stateInstance: zod.z.string().optional(),
|
|
46589
|
-
error: zod.z.string().optional()
|
|
46590
|
-
});
|
|
46591
|
-
var notificationOutputCapability = {
|
|
46592
|
-
name: "notification-output",
|
|
46593
|
-
scope: "system",
|
|
46594
|
-
mode: "collection",
|
|
46595
|
-
methods: {
|
|
46596
|
-
listTargetKinds: require_sleep.method(zod.z.object({}), zod.z.array(TargetKindSchema)),
|
|
46597
|
-
listTargets: require_sleep.method(zod.z.object({}), zod.z.array(TargetSchema), { auth: "admin" }),
|
|
46598
|
-
/**
|
|
46599
|
-
* One target WITH secrets — admin edit / duplicate hydration only.
|
|
46600
|
-
* `listTargets` stays redacted; the editor loads this so password fields
|
|
46601
|
-
* are filled (masked in the input) and a save can round-trip the token
|
|
46602
|
-
* when a destination changes (Duplicate with a new chatId, etc.).
|
|
46603
|
-
*/
|
|
46604
|
-
getTarget: require_sleep.method(zod.z.object({ targetId: zod.z.string() }), TargetSchema, { auth: "admin" }),
|
|
46605
|
-
discoverTargets: require_sleep.method(zod.z.object({
|
|
46606
|
-
kind: zod.z.string(),
|
|
46607
|
-
config: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
|
|
46608
|
-
/**
|
|
46609
|
-
* When editing / duplicating, the blank password field never round-trips
|
|
46610
|
-
* the stored token. Pass the source target id so the provider can restore
|
|
46611
|
-
* secrets server-side before dialling (same merge as upsert).
|
|
46612
|
-
*/
|
|
46613
|
-
targetId: zod.z.string().optional()
|
|
46614
|
-
}), zod.z.array(DiscoveredTargetSchema), { auth: "admin" }),
|
|
46615
|
-
probeTargetConfig: require_sleep.method(zod.z.object({
|
|
46616
|
-
kind: zod.z.string(),
|
|
46617
|
-
config: zod.z.record(zod.z.string(), zod.z.unknown()),
|
|
46618
|
-
/** See `discoverTargets.targetId` — restore stored secrets for a blank password. */
|
|
46619
|
-
targetId: zod.z.string().optional()
|
|
46620
|
-
}), ProbeTargetConfigResultSchema, {
|
|
46621
|
-
kind: "mutation",
|
|
46622
|
-
auth: "admin"
|
|
46623
|
-
}),
|
|
46624
|
-
send: require_sleep.method(zod.z.object({
|
|
46625
|
-
targetId: zod.z.string(),
|
|
46626
|
-
notification: NotificationSchema
|
|
46627
|
-
}), SendResultSchema, {
|
|
46628
|
-
kind: "mutation",
|
|
46629
|
-
auth: "admin"
|
|
46630
|
-
}),
|
|
46631
|
-
testTarget: require_sleep.method(zod.z.object({
|
|
46632
|
-
targetId: zod.z.string(),
|
|
46633
|
-
sample: NotificationSchema.optional()
|
|
46634
|
-
}), TestResultSchema, {
|
|
46635
|
-
kind: "mutation",
|
|
46636
|
-
auth: "admin"
|
|
46637
|
-
}),
|
|
46638
|
-
upsertTarget: require_sleep.method(zod.z.object({
|
|
46639
|
-
target: TargetSchema,
|
|
46640
|
-
/**
|
|
46641
|
-
* Duplicate flow: create a NEW target id while copying secrets from an
|
|
46642
|
-
* existing row. The UI never holds the stored token; blank / redacted
|
|
46643
|
-
* password fields are restored from this source (D634 still applies if
|
|
46644
|
-
* destinations diverge without a re-typed secret).
|
|
46645
|
-
*/
|
|
46646
|
-
cloneSecretsFrom: zod.z.string().optional()
|
|
46647
|
-
}), TargetSchema, {
|
|
46648
|
-
kind: "mutation",
|
|
46649
|
-
auth: "admin"
|
|
46650
|
-
}),
|
|
46651
|
-
deleteTarget: require_sleep.method(zod.z.object({ targetId: zod.z.string() }), zod.z.void(), {
|
|
46652
|
-
kind: "mutation",
|
|
46653
|
-
auth: "admin"
|
|
46654
|
-
}),
|
|
46655
|
-
setTargetEnabled: require_sleep.method(zod.z.object({
|
|
46656
|
-
targetId: zod.z.string(),
|
|
46657
|
-
enabled: zod.z.boolean()
|
|
46658
|
-
}), zod.z.void(), {
|
|
46659
|
-
kind: "mutation",
|
|
46660
|
-
auth: "admin"
|
|
46661
|
-
})
|
|
46662
|
-
}
|
|
46663
|
-
};
|
|
46664
|
-
//#endregion
|
|
46665
47035
|
//#region src/catalogs/audio-classmap.ts
|
|
46666
47036
|
var AUDIO_MACRO_LABELS = [
|
|
46667
47037
|
{
|
|
@@ -55536,14 +55906,6 @@ var EngineProvisioningSchema = zod.z.object({
|
|
|
55536
55906
|
*/
|
|
55537
55907
|
configIssues: zod.z.array(zod.z.string()).optional()
|
|
55538
55908
|
});
|
|
55539
|
-
var PipelineStepInputSchema = zod.z.lazy(() => zod.z.object({
|
|
55540
|
-
addonId: zod.z.string(),
|
|
55541
|
-
modelId: zod.z.string().optional(),
|
|
55542
|
-
enabled: zod.z.boolean().default(true),
|
|
55543
|
-
children: zod.z.array(PipelineStepInputSchema).optional(),
|
|
55544
|
-
settings: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
|
|
55545
|
-
jumpDeviceKey: zod.z.string().optional()
|
|
55546
|
-
}));
|
|
55547
55909
|
var ModelSubstitutionSchema = zod.z.object({
|
|
55548
55910
|
addonId: zod.z.string(),
|
|
55549
55911
|
chosen: zod.z.string(),
|
|
@@ -55622,7 +55984,6 @@ var ConfigUISchemaBridge = zod.z.custom();
|
|
|
55622
55984
|
var ConfigUISchemaNullableBridge = zod.z.custom();
|
|
55623
55985
|
var InferenceCapabilitiesBridge = zod.z.custom();
|
|
55624
55986
|
var ModelAvailabilityListBridge = zod.z.custom();
|
|
55625
|
-
var PipelineRunResultBridge = zod.z.custom();
|
|
55626
55987
|
/**
|
|
55627
55988
|
* Pipeline executor — detection engine + configuration + inference API.
|
|
55628
55989
|
*
|
|
@@ -55735,7 +56096,7 @@ var pipelineExecutorCapability = {
|
|
|
55735
56096
|
* reads any media: can this (node, deviceKey) run exactly this model?
|
|
55736
56097
|
*/
|
|
55737
56098
|
validatePipeline: require_sleep.method(zod.z.object({
|
|
55738
|
-
steps: zod.z.array(PipelineStepInputSchema),
|
|
56099
|
+
steps: zod.z.array(require_sleep.PipelineStepInputSchema),
|
|
55739
56100
|
deviceKey: zod.z.string().optional()
|
|
55740
56101
|
}), PipelineValidationResultSchema),
|
|
55741
56102
|
getCapabilities: require_sleep.method(zod.z.void(), InferenceCapabilitiesBridge),
|
|
@@ -55779,7 +56140,7 @@ var pipelineExecutorCapability = {
|
|
|
55779
56140
|
* - `referenceImage`: named file from the reference-image store.
|
|
55780
56141
|
*/
|
|
55781
56142
|
runPipeline: require_sleep.method(zod.z.object({
|
|
55782
|
-
steps: zod.z.array(PipelineStepInputSchema).min(1),
|
|
56143
|
+
steps: zod.z.array(require_sleep.PipelineStepInputSchema).min(1),
|
|
55783
56144
|
frame: FrameInputSchema.optional(),
|
|
55784
56145
|
/**
|
|
55785
56146
|
* Process-local lazy frame. Valid only when caller and provider resolve
|
|
@@ -55853,7 +56214,7 @@ var pipelineExecutorCapability = {
|
|
|
55853
56214
|
* PIXELS of the image this call carries. Absent ⇒ the root step runs.
|
|
55854
56215
|
*/
|
|
55855
56216
|
suppliedRoot: SuppliedRootOutputSchema.optional()
|
|
55856
|
-
}), PipelineRunResultBridge, { kind: "mutation" }),
|
|
56217
|
+
}), require_sleep.PipelineRunResultBridge, { kind: "mutation" }),
|
|
55857
56218
|
/**
|
|
55858
56219
|
* Batched run — N raw frames packed into one cap call. The provider
|
|
55859
56220
|
* routes the batch through `SharedInferencePool.inferBatch`
|
|
@@ -55866,7 +56227,7 @@ var pipelineExecutorCapability = {
|
|
|
55866
56227
|
* N frames in one call to amortise per-call IPC overhead.
|
|
55867
56228
|
*/
|
|
55868
56229
|
runPipelineBatch: require_sleep.method(zod.z.object({
|
|
55869
|
-
steps: zod.z.array(PipelineStepInputSchema).min(1),
|
|
56230
|
+
steps: zod.z.array(require_sleep.PipelineStepInputSchema).min(1),
|
|
55870
56231
|
frames: zod.z.array(FrameInputSchema).min(1).max(255),
|
|
55871
56232
|
deviceId: zod.z.number().optional(),
|
|
55872
56233
|
sessionId: zod.z.string().optional(),
|
|
@@ -55883,7 +56244,7 @@ var pipelineExecutorCapability = {
|
|
|
55883
56244
|
frameId: zod.z.number().int().nonnegative().optional(),
|
|
55884
56245
|
/** Inference-device selector (Phase 2 multi-device); see runPipeline. */
|
|
55885
56246
|
deviceKey: zod.z.string().optional()
|
|
55886
|
-
}), 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" }),
|
|
55887
56248
|
/**
|
|
55888
56249
|
* Cache a raw frame inside the Python inference pool's memory.
|
|
55889
56250
|
* Returns a numeric `frameId` that `inferCached` references —
|
|
@@ -57586,7 +57947,7 @@ var RunnerCameraConfigSchema = zod.z.object({
|
|
|
57586
57947
|
detectionSources: DetectionSourcesSchema.default(["pipeline"]),
|
|
57587
57948
|
pipelineEnabled: zod.z.boolean().default(true),
|
|
57588
57949
|
/** Ordered tree of video steps. Absent → runner skips video detection. */
|
|
57589
|
-
steps: zod.z.array(PipelineStepInputSchema).readonly().optional(),
|
|
57950
|
+
steps: zod.z.array(require_sleep.PipelineStepInputSchema).readonly().optional(),
|
|
57590
57951
|
/** Audio classification branch. `enabled:false` disables, null skips. */
|
|
57591
57952
|
audio: zod.z.object({
|
|
57592
57953
|
modelId: zod.z.string().optional(),
|
|
@@ -58321,7 +58682,7 @@ var pipelineRunnerCapability = {
|
|
|
58321
58682
|
//#region src/capabilities/pipeline-orchestrator.cap.ts
|
|
58322
58683
|
var CameraPipelineConfigSchema = zod.z.object({
|
|
58323
58684
|
engine: PipelineEngineChoiceSchema.optional(),
|
|
58324
|
-
steps: zod.z.array(PipelineStepInputSchema).readonly(),
|
|
58685
|
+
steps: zod.z.array(require_sleep.PipelineStepInputSchema).readonly(),
|
|
58325
58686
|
audio: zod.z.object({
|
|
58326
58687
|
engine: PipelineEngineChoiceSchema.optional(),
|
|
58327
58688
|
modelId: zod.z.string().optional(),
|
|
@@ -59120,8 +59481,7 @@ var pipelineOrchestratorCapability = {
|
|
|
59120
59481
|
* replaced the four flat orchestrator lists (`enabledNodes`,
|
|
59121
59482
|
* `enabledDecoderNodes`, `enabledAudioNodes`, `remoteSourcingNodes`).
|
|
59122
59483
|
* Each flag is optional in the patch: omit a flag to leave it unchanged,
|
|
59123
|
-
* pass `null` to reset it to the
|
|
59124
|
-
* other node → not). Detection/audio eligibility is derived from these
|
|
59484
|
+
* pass `null` to reset it to the default (ON for every node). Detection/audio eligibility is derived from these
|
|
59125
59485
|
* flags across the cluster; changing them re-derives the enabled sets
|
|
59126
59486
|
* and reconciles dispatch immediately. There is NO separate decode flag:
|
|
59127
59487
|
* decode is always co-located with its frame consumer, so decode
|
|
@@ -66927,14 +67287,13 @@ reset: require_sleep.method(zod.z.object({
|
|
|
66927
67287
|
auth: "admin"
|
|
66928
67288
|
}) },
|
|
66929
67289
|
/**
|
|
66930
|
-
* A
|
|
66931
|
-
*
|
|
66932
|
-
*
|
|
66933
|
-
* 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).
|
|
66934
67293
|
*/
|
|
66935
67294
|
composedMethods: { reset: {
|
|
66936
67295
|
kind: "refuse",
|
|
66937
|
-
reason: "a
|
|
67296
|
+
reason: "a consumable added to an existing device is not resettable — only a new composed device forwards a reset"
|
|
66938
67297
|
} },
|
|
66939
67298
|
status: {
|
|
66940
67299
|
schema: ConsumablesStatusSchema,
|
|
@@ -67597,7 +67956,7 @@ var DishwasherStatusSchema = zod.z.object({
|
|
|
67597
67956
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
67598
67957
|
lastFetchedAt: zod.z.number()
|
|
67599
67958
|
});
|
|
67600
|
-
var DeviceIdSchema = zod.z.number().int().nonnegative();
|
|
67959
|
+
var DeviceIdSchema$1 = zod.z.number().int().nonnegative();
|
|
67601
67960
|
/** A value a program option or setting can take. */
|
|
67602
67961
|
var DishwasherValueSchema = zod.z.union([
|
|
67603
67962
|
zod.z.boolean(),
|
|
@@ -67672,77 +68031,77 @@ var dishwasherCapability = {
|
|
|
67672
68031
|
* option feature keys; each is checked against the program's constraints.
|
|
67673
68032
|
*/
|
|
67674
68033
|
start: require_sleep.method(zod.z.object({
|
|
67675
|
-
deviceId: DeviceIdSchema,
|
|
68034
|
+
deviceId: DeviceIdSchema$1,
|
|
67676
68035
|
program: zod.z.string().min(1).optional(),
|
|
67677
68036
|
options: zod.z.record(zod.z.string(), DishwasherValueSchema).optional()
|
|
67678
68037
|
}), zod.z.void(), {
|
|
67679
68038
|
kind: "mutation",
|
|
67680
68039
|
auth: "protected"
|
|
67681
68040
|
}),
|
|
67682
|
-
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(), {
|
|
67683
68042
|
kind: "mutation",
|
|
67684
68043
|
auth: "protected"
|
|
67685
68044
|
}),
|
|
67686
|
-
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(), {
|
|
67687
68046
|
kind: "mutation",
|
|
67688
68047
|
auth: "protected"
|
|
67689
68048
|
}),
|
|
67690
|
-
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(), {
|
|
67691
68050
|
kind: "mutation",
|
|
67692
68051
|
auth: "protected"
|
|
67693
68052
|
}),
|
|
67694
68053
|
/** Select (not start) a program; refused when the appliance does not offer it. */
|
|
67695
68054
|
setProgram: require_sleep.method(zod.z.object({
|
|
67696
|
-
deviceId: DeviceIdSchema,
|
|
68055
|
+
deviceId: DeviceIdSchema$1,
|
|
67697
68056
|
program: zod.z.string().min(1)
|
|
67698
68057
|
}), zod.z.void(), {
|
|
67699
68058
|
kind: "mutation",
|
|
67700
68059
|
auth: "protected"
|
|
67701
68060
|
}),
|
|
67702
68061
|
setPower: require_sleep.method(zod.z.object({
|
|
67703
|
-
deviceId: DeviceIdSchema,
|
|
68062
|
+
deviceId: DeviceIdSchema$1,
|
|
67704
68063
|
on: zod.z.boolean()
|
|
67705
68064
|
}), zod.z.void(), {
|
|
67706
68065
|
kind: "mutation",
|
|
67707
68066
|
auth: "protected"
|
|
67708
68067
|
}),
|
|
67709
68068
|
setHalfLoad: require_sleep.method(zod.z.object({
|
|
67710
|
-
deviceId: DeviceIdSchema,
|
|
68069
|
+
deviceId: DeviceIdSchema$1,
|
|
67711
68070
|
on: zod.z.boolean()
|
|
67712
68071
|
}), zod.z.void(), {
|
|
67713
68072
|
kind: "mutation",
|
|
67714
68073
|
auth: "protected"
|
|
67715
68074
|
}),
|
|
67716
68075
|
setHygienePlus: require_sleep.method(zod.z.object({
|
|
67717
|
-
deviceId: DeviceIdSchema,
|
|
68076
|
+
deviceId: DeviceIdSchema$1,
|
|
67718
68077
|
on: zod.z.boolean()
|
|
67719
68078
|
}), zod.z.void(), {
|
|
67720
68079
|
kind: "mutation",
|
|
67721
68080
|
auth: "protected"
|
|
67722
68081
|
}),
|
|
67723
68082
|
setExtraDry: require_sleep.method(zod.z.object({
|
|
67724
|
-
deviceId: DeviceIdSchema,
|
|
68083
|
+
deviceId: DeviceIdSchema$1,
|
|
67725
68084
|
on: zod.z.boolean()
|
|
67726
68085
|
}), zod.z.void(), {
|
|
67727
68086
|
kind: "mutation",
|
|
67728
68087
|
auth: "protected"
|
|
67729
68088
|
}),
|
|
67730
68089
|
setIntensiveZone: require_sleep.method(zod.z.object({
|
|
67731
|
-
deviceId: DeviceIdSchema,
|
|
68090
|
+
deviceId: DeviceIdSchema$1,
|
|
67732
68091
|
on: zod.z.boolean()
|
|
67733
68092
|
}), zod.z.void(), {
|
|
67734
68093
|
kind: "mutation",
|
|
67735
68094
|
auth: "protected"
|
|
67736
68095
|
}),
|
|
67737
68096
|
setVarioSpeedPlus: require_sleep.method(zod.z.object({
|
|
67738
|
-
deviceId: DeviceIdSchema,
|
|
68097
|
+
deviceId: DeviceIdSchema$1,
|
|
67739
68098
|
on: zod.z.boolean()
|
|
67740
68099
|
}), zod.z.void(), {
|
|
67741
68100
|
kind: "mutation",
|
|
67742
68101
|
auth: "protected"
|
|
67743
68102
|
}),
|
|
67744
68103
|
setChildLock: require_sleep.method(zod.z.object({
|
|
67745
|
-
deviceId: DeviceIdSchema,
|
|
68104
|
+
deviceId: DeviceIdSchema$1,
|
|
67746
68105
|
on: zod.z.boolean()
|
|
67747
68106
|
}), zod.z.void(), {
|
|
67748
68107
|
kind: "mutation",
|
|
@@ -67754,7 +68113,7 @@ var dishwasherCapability = {
|
|
|
67754
68113
|
* its declared range / members.
|
|
67755
68114
|
*/
|
|
67756
68115
|
setOption: require_sleep.method(zod.z.object({
|
|
67757
|
-
deviceId: DeviceIdSchema,
|
|
68116
|
+
deviceId: DeviceIdSchema$1,
|
|
67758
68117
|
key: zod.z.string().min(1),
|
|
67759
68118
|
value: DishwasherValueSchema
|
|
67760
68119
|
}), zod.z.void(), {
|
|
@@ -67762,7 +68121,7 @@ var dishwasherCapability = {
|
|
|
67762
68121
|
auth: "protected"
|
|
67763
68122
|
}),
|
|
67764
68123
|
/** What this appliance can do, from its own description — the UI is derived from it. */
|
|
67765
|
-
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" })
|
|
67766
68125
|
},
|
|
67767
68126
|
status: {
|
|
67768
68127
|
schema: DishwasherStatusSchema,
|
|
@@ -72065,7 +72424,8 @@ var TopologyNodeSchema = zod.z.object({
|
|
|
72065
72424
|
isHub: zod.z.boolean(),
|
|
72066
72425
|
isOnline: zod.z.boolean(),
|
|
72067
72426
|
cpuPercent: zod.z.number(),
|
|
72068
|
-
|
|
72427
|
+
/** `null` when the node's memory read failed or it has not reported one (D393). */
|
|
72428
|
+
memoryPercent: zod.z.number().nullable(),
|
|
72069
72429
|
uptime: zod.z.number(),
|
|
72070
72430
|
lastSeen: zod.z.string(),
|
|
72071
72431
|
localIps: zod.z.array(zod.z.string()).readonly(),
|
|
@@ -72906,9 +73266,10 @@ var PetFeederStatusSchema = zod.z.object({
|
|
|
72906
73266
|
* combined reading; per-hopper levels live in `food1`/`food2`. Null when
|
|
72907
73267
|
* the device has not reported yet. */
|
|
72908
73268
|
foodLevel: zod.z.number().nullable().meta(require_sleep.readingMeta("none")),
|
|
72909
|
-
/** Food in the BOWL
|
|
72910
|
-
* feeder
|
|
72911
|
-
|
|
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")),
|
|
72912
73273
|
/** True while the pet is eating (`state.eating`). */
|
|
72913
73274
|
eating: zod.z.boolean(),
|
|
72914
73275
|
/** Whether `markFoodReplenished` does anything on this model. When false
|
|
@@ -73093,6 +73454,139 @@ var petFeederCapability = {
|
|
|
73093
73454
|
} }
|
|
73094
73455
|
};
|
|
73095
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
|
|
73096
73590
|
//#region src/capabilities/plate-gallery.cap.ts
|
|
73097
73591
|
var VehicleSchema = zod.z.object({
|
|
73098
73592
|
id: zod.z.string(),
|
|
@@ -82985,7 +83479,7 @@ var ROOM_EXAMPLE_MOTION_SOURCES = [{
|
|
|
82985
83479
|
addonId: "provider-homeassistant",
|
|
82986
83480
|
stableId: "binary_sensor.living_room_presence"
|
|
82987
83481
|
}];
|
|
82988
|
-
function from(source, cap, fieldPath) {
|
|
83482
|
+
function from$1(source, cap, fieldPath) {
|
|
82989
83483
|
return {
|
|
82990
83484
|
kind: "from",
|
|
82991
83485
|
source,
|
|
@@ -82994,7 +83488,7 @@ function from(source, cap, fieldPath) {
|
|
|
82994
83488
|
};
|
|
82995
83489
|
}
|
|
82996
83490
|
function named(prefix, sources, cap, fieldPath) {
|
|
82997
|
-
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)]));
|
|
82998
83492
|
}
|
|
82999
83493
|
function roomCompositionExample(input) {
|
|
83000
83494
|
const t = named("t", input.temperatureSources, "temperature-sensor", "temperature");
|
|
@@ -83082,7 +83576,7 @@ function feederExampleSources(brokerId) {
|
|
|
83082
83576
|
};
|
|
83083
83577
|
}
|
|
83084
83578
|
function feederCustomizationExample(sources) {
|
|
83085
|
-
const days = { d: from(sources.desiccantDays, "enum-sensor", "value") };
|
|
83579
|
+
const days = { d: from$1(sources.desiccantDays, "enum-sensor", "value") };
|
|
83086
83580
|
return require_composition.CompositionSchema.parse({
|
|
83087
83581
|
target: {
|
|
83088
83582
|
kind: "existing",
|
|
@@ -83130,7 +83624,7 @@ function feederCustomizationExample(sources) {
|
|
|
83130
83624
|
level: {
|
|
83131
83625
|
kind: "expression",
|
|
83132
83626
|
expr: "s == \"low\" ? 15 : (s == \"normal\" ? 100 : null)",
|
|
83133
|
-
bindings: { s: from(sources.batteryStatus, "enum-sensor", "value") }
|
|
83627
|
+
bindings: { s: from$1(sources.batteryStatus, "enum-sensor", "value") }
|
|
83134
83628
|
},
|
|
83135
83629
|
binary: {
|
|
83136
83630
|
kind: "expression",
|
|
@@ -83140,7 +83634,7 @@ function feederCustomizationExample(sources) {
|
|
|
83140
83634
|
charging: {
|
|
83141
83635
|
kind: "expression",
|
|
83142
83636
|
expr: "c ? \"dc\" : \"unknown\"",
|
|
83143
|
-
bindings: { c: from(sources.batteryCharging, "binary", "on") }
|
|
83637
|
+
bindings: { c: from$1(sources.batteryCharging, "binary", "on") }
|
|
83144
83638
|
},
|
|
83145
83639
|
sleeping: {
|
|
83146
83640
|
kind: "expression",
|
|
@@ -83226,6 +83720,158 @@ function convertPresetFeature(input) {
|
|
|
83226
83720
|
};
|
|
83227
83721
|
}
|
|
83228
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
|
|
83229
83875
|
//#region src/composition/cards/classify-field.ts
|
|
83230
83876
|
function fromSources(binding) {
|
|
83231
83877
|
return {
|
|
@@ -83475,6 +84121,7 @@ var CAP_CUSTOMIZE_CATALOG = {
|
|
|
83475
84121
|
require_err_msg.DeviceType.Container,
|
|
83476
84122
|
require_err_msg.DeviceType.Image,
|
|
83477
84123
|
require_err_msg.DeviceType.PetFeeder,
|
|
84124
|
+
require_err_msg.DeviceType.PetFountain,
|
|
83478
84125
|
require_err_msg.DeviceType.Dishwasher,
|
|
83479
84126
|
require_err_msg.DeviceType.Washer,
|
|
83480
84127
|
require_err_msg.DeviceType.Dryer
|
|
@@ -85987,6 +86634,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
85987
86634
|
notifier: notifierCapability,
|
|
85988
86635
|
numericSensor: numericSensorCapability,
|
|
85989
86636
|
petFeeder: petFeederCapability,
|
|
86637
|
+
petFountain: petFountainCapability,
|
|
85990
86638
|
powerMeter: powerMeterCapability,
|
|
85991
86639
|
presence: presenceCapability,
|
|
85992
86640
|
pressureSensor: pressureSensorCapability,
|
|
@@ -87975,6 +88623,7 @@ var DEVICE_TYPE_CONTROL_KIND = {
|
|
|
87975
88623
|
[require_err_msg.DeviceType.Container]: "dummy",
|
|
87976
88624
|
[require_err_msg.DeviceType.Image]: "image",
|
|
87977
88625
|
[require_err_msg.DeviceType.PetFeeder]: "pet-feeder",
|
|
88626
|
+
[require_err_msg.DeviceType.PetFountain]: "pet-fountain",
|
|
87978
88627
|
[require_err_msg.DeviceType.Dishwasher]: "dishwasher",
|
|
87979
88628
|
[require_err_msg.DeviceType.Washer]: "dummy",
|
|
87980
88629
|
[require_err_msg.DeviceType.Dryer]: "dummy"
|
|
@@ -90017,6 +90666,13 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
90017
90666
|
access: "create",
|
|
90018
90667
|
role: "admin"
|
|
90019
90668
|
},
|
|
90669
|
+
"deviceExport.exposeEntity": {
|
|
90670
|
+
capName: "device-export",
|
|
90671
|
+
capScope: "system",
|
|
90672
|
+
addonId: null,
|
|
90673
|
+
access: "create",
|
|
90674
|
+
role: "admin"
|
|
90675
|
+
},
|
|
90020
90676
|
"deviceExport.getDeviceLiveContribution": {
|
|
90021
90677
|
capName: "device-export",
|
|
90022
90678
|
capScope: "system",
|
|
@@ -90045,6 +90701,13 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
90045
90701
|
access: "view",
|
|
90046
90702
|
role: "admin"
|
|
90047
90703
|
},
|
|
90704
|
+
"deviceExport.listExposedEntities": {
|
|
90705
|
+
capName: "device-export",
|
|
90706
|
+
capScope: "system",
|
|
90707
|
+
addonId: null,
|
|
90708
|
+
access: "view",
|
|
90709
|
+
role: "admin"
|
|
90710
|
+
},
|
|
90048
90711
|
"deviceExport.listSupportedDeviceKinds": {
|
|
90049
90712
|
capName: "device-export",
|
|
90050
90713
|
capScope: "system",
|
|
@@ -90052,6 +90715,13 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
90052
90715
|
access: "view",
|
|
90053
90716
|
role: "admin"
|
|
90054
90717
|
},
|
|
90718
|
+
"deviceExport.listSupportedEntityKinds": {
|
|
90719
|
+
capName: "device-export",
|
|
90720
|
+
capScope: "system",
|
|
90721
|
+
addonId: null,
|
|
90722
|
+
access: "view",
|
|
90723
|
+
role: "admin"
|
|
90724
|
+
},
|
|
90055
90725
|
"deviceExport.unexposeDevice": {
|
|
90056
90726
|
capName: "device-export",
|
|
90057
90727
|
capScope: "system",
|
|
@@ -90059,6 +90729,13 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
90059
90729
|
access: "create",
|
|
90060
90730
|
role: "admin"
|
|
90061
90731
|
},
|
|
90732
|
+
"deviceExport.unexposeEntity": {
|
|
90733
|
+
capName: "device-export",
|
|
90734
|
+
capScope: "system",
|
|
90735
|
+
addonId: null,
|
|
90736
|
+
access: "create",
|
|
90737
|
+
role: "admin"
|
|
90738
|
+
},
|
|
90062
90739
|
"deviceExtension.listCandidates": {
|
|
90063
90740
|
capName: "device-extension",
|
|
90064
90741
|
capScope: "device",
|
|
@@ -92880,6 +93557,13 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
92880
93557
|
access: "create",
|
|
92881
93558
|
role: "admin"
|
|
92882
93559
|
},
|
|
93560
|
+
"nodeRemovalHook.onNodeRemoved": {
|
|
93561
|
+
capName: "node-removal-hook",
|
|
93562
|
+
capScope: "system",
|
|
93563
|
+
addonId: null,
|
|
93564
|
+
access: "create",
|
|
93565
|
+
role: "admin"
|
|
93566
|
+
},
|
|
92883
93567
|
"nodes.clusterAddonStatus": {
|
|
92884
93568
|
capName: "nodes",
|
|
92885
93569
|
capScope: "system",
|
|
@@ -93517,6 +94201,48 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
93517
94201
|
access: "create",
|
|
93518
94202
|
role: "viewer"
|
|
93519
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
|
+
},
|
|
93520
94246
|
"pipelineAnalytics.addRetrainFrameFromRecording": {
|
|
93521
94247
|
capName: "pipeline-analytics",
|
|
93522
94248
|
capScope: "device",
|
|
@@ -98115,6 +98841,7 @@ var KNOWN_CAP_NAMES = [
|
|
|
98115
98841
|
"network-link",
|
|
98116
98842
|
"network-quality",
|
|
98117
98843
|
"node-certificates",
|
|
98844
|
+
"node-removal-hook",
|
|
98118
98845
|
"nodes",
|
|
98119
98846
|
"notification-output",
|
|
98120
98847
|
"notification-rules",
|
|
@@ -98125,6 +98852,7 @@ var KNOWN_CAP_NAMES = [
|
|
|
98125
98852
|
"osd",
|
|
98126
98853
|
"osd-manager",
|
|
98127
98854
|
"pet-feeder",
|
|
98855
|
+
"pet-fountain",
|
|
98128
98856
|
"pipeline-analytics",
|
|
98129
98857
|
"pipeline-executor",
|
|
98130
98858
|
"pipeline-orchestrator",
|
|
@@ -98256,6 +98984,7 @@ var DEVICE_CAP_NAMES = [
|
|
|
98256
98984
|
"numeric-sensor",
|
|
98257
98985
|
"osd",
|
|
98258
98986
|
"pet-feeder",
|
|
98987
|
+
"pet-fountain",
|
|
98259
98988
|
"pipeline-analytics",
|
|
98260
98989
|
"power-meter",
|
|
98261
98990
|
"presence",
|
|
@@ -98348,6 +99077,7 @@ var SYSTEM_CAP_NAMES = [
|
|
|
98348
99077
|
"network-access",
|
|
98349
99078
|
"network-quality",
|
|
98350
99079
|
"node-certificates",
|
|
99080
|
+
"node-removal-hook",
|
|
98351
99081
|
"nodes",
|
|
98352
99082
|
"notification-output",
|
|
98353
99083
|
"notification-rules",
|
|
@@ -100394,6 +101124,100 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
100394
101124
|
}
|
|
100395
101125
|
]
|
|
100396
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
|
+
},
|
|
100397
101221
|
"media-player": {
|
|
100398
101222
|
scope: "device",
|
|
100399
101223
|
noun: t("Media player", "Lettore multimediale"),
|
|
@@ -102224,6 +103048,7 @@ var SYSTEM_CAP_VOCABULARY = {
|
|
|
102224
103048
|
"device-manager": system("the device registry itself — rename, move and remove are administration"),
|
|
102225
103049
|
"device-provider": system(INTERNAL),
|
|
102226
103050
|
"device-removal-hook": system(INTERNAL),
|
|
103051
|
+
"node-removal-hook": system(INTERNAL),
|
|
102227
103052
|
"device-state": system("the runtime-state mirror every trigger already reads through"),
|
|
102228
103053
|
"display-palette": system("the cluster display palette — one colour table for every client, not a device action"),
|
|
102229
103054
|
"embedding-encoder": system(ML),
|
|
@@ -102455,6 +103280,7 @@ var DEVICE_TYPE_DO_CAPS = {
|
|
|
102455
103280
|
[require_err_msg.DeviceType.Container]: [],
|
|
102456
103281
|
[require_err_msg.DeviceType.Image]: [],
|
|
102457
103282
|
[require_err_msg.DeviceType.PetFeeder]: ["pet-feeder"],
|
|
103283
|
+
[require_err_msg.DeviceType.PetFountain]: ["pet-fountain"],
|
|
102458
103284
|
[require_err_msg.DeviceType.Dishwasher]: ["dishwasher"],
|
|
102459
103285
|
[require_err_msg.DeviceType.Washer]: [],
|
|
102460
103286
|
[require_err_msg.DeviceType.Dryer]: []
|
|
@@ -104073,6 +104899,7 @@ var CAP_NAMES_WITH_STATUS = [
|
|
|
104073
104899
|
"numeric-sensor",
|
|
104074
104900
|
"osd",
|
|
104075
104901
|
"pet-feeder",
|
|
104902
|
+
"pet-fountain",
|
|
104076
104903
|
"power-meter",
|
|
104077
104904
|
"presence",
|
|
104078
104905
|
"pressure-sensor",
|
|
@@ -104216,6 +105043,7 @@ var CAPABILITY_NAMES = {
|
|
|
104216
105043
|
networkLink: "network-link",
|
|
104217
105044
|
networkQuality: "network-quality",
|
|
104218
105045
|
nodeCertificates: "node-certificates",
|
|
105046
|
+
nodeRemovalHook: "node-removal-hook",
|
|
104219
105047
|
nodes: "nodes",
|
|
104220
105048
|
notificationOutput: "notification-output",
|
|
104221
105049
|
notificationRules: "notification-rules",
|
|
@@ -104226,6 +105054,7 @@ var CAPABILITY_NAMES = {
|
|
|
104226
105054
|
osd: "osd",
|
|
104227
105055
|
osdManager: "osd-manager",
|
|
104228
105056
|
petFeeder: "pet-feeder",
|
|
105057
|
+
petFountain: "pet-fountain",
|
|
104229
105058
|
pipelineAnalytics: "pipeline-analytics",
|
|
104230
105059
|
pipelineExecutor: "pipeline-executor",
|
|
104231
105060
|
pipelineOrchestrator: "pipeline-orchestrator",
|
|
@@ -104754,6 +105583,10 @@ var CAPABILITY_ROUTER_KEYS = [
|
|
|
104754
105583
|
key: "nodeCertificates",
|
|
104755
105584
|
name: "node-certificates"
|
|
104756
105585
|
},
|
|
105586
|
+
{
|
|
105587
|
+
key: "nodeRemovalHook",
|
|
105588
|
+
name: "node-removal-hook"
|
|
105589
|
+
},
|
|
104757
105590
|
{
|
|
104758
105591
|
key: "nodes",
|
|
104759
105592
|
name: "nodes"
|
|
@@ -104794,6 +105627,10 @@ var CAPABILITY_ROUTER_KEYS = [
|
|
|
104794
105627
|
key: "petFeeder",
|
|
104795
105628
|
name: "pet-feeder"
|
|
104796
105629
|
},
|
|
105630
|
+
{
|
|
105631
|
+
key: "petFountain",
|
|
105632
|
+
name: "pet-fountain"
|
|
105633
|
+
},
|
|
104797
105634
|
{
|
|
104798
105635
|
key: "pipelineAnalytics",
|
|
104799
105636
|
name: "pipeline-analytics"
|
|
@@ -105069,7 +105906,7 @@ var ALL_CAPABILITY_DEFINITIONS = [
|
|
|
105069
105906
|
actionSourceCapability,
|
|
105070
105907
|
actionsCapability,
|
|
105071
105908
|
addonPagesCapability,
|
|
105072
|
-
addonPagesSourceCapability,
|
|
105909
|
+
require_sleep.addonPagesSourceCapability,
|
|
105073
105910
|
addonRoutesCapability,
|
|
105074
105911
|
addonSettingsCapability,
|
|
105075
105912
|
addonWidgetsCapability,
|
|
@@ -105180,6 +106017,7 @@ var ALL_CAPABILITY_DEFINITIONS = [
|
|
|
105180
106017
|
networkLinkCapability,
|
|
105181
106018
|
networkQualityCapability,
|
|
105182
106019
|
nodeCertificatesCapability,
|
|
106020
|
+
nodeRemovalHookCapability,
|
|
105183
106021
|
nodesCapability,
|
|
105184
106022
|
notificationOutputCapability,
|
|
105185
106023
|
notificationRulesCapability,
|
|
@@ -105190,6 +106028,7 @@ var ALL_CAPABILITY_DEFINITIONS = [
|
|
|
105190
106028
|
osdCapability,
|
|
105191
106029
|
osdManagerCapability,
|
|
105192
106030
|
petFeederCapability,
|
|
106031
|
+
petFountainCapability,
|
|
105193
106032
|
pipelineAnalyticsCapability,
|
|
105194
106033
|
pipelineExecutorCapability,
|
|
105195
106034
|
pipelineOrchestratorCapability,
|
|
@@ -106768,6 +107607,36 @@ var METHOD_DEVICE_SELECTORS = Object.freeze({
|
|
|
106768
107607
|
form: "single",
|
|
106769
107608
|
optional: false
|
|
106770
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
|
+
}],
|
|
106771
107640
|
"pipelineAnalytics.addRetrainFrameFromRecording": [{
|
|
106772
107641
|
name: "deviceId",
|
|
106773
107642
|
form: "single",
|
|
@@ -108325,7 +109194,7 @@ function getCapsByProviderKind(kind) {
|
|
|
108325
109194
|
//#region src/generated/runtime-state-durability.ts
|
|
108326
109195
|
/**
|
|
108327
109196
|
* Per-cap runtime-state policy, projected from every `*.cap.ts` that declares
|
|
108328
|
-
* `runtimeState`.
|
|
109197
|
+
* `runtimeState`. 77 caps: 39 `restored`, 38 `session`.
|
|
108329
109198
|
*
|
|
108330
109199
|
* A cap absent from this map has no runtime-state slice at all. A cap PRESENT
|
|
108331
109200
|
* with `durability: 'session'` has one and has decided not to keep it.
|
|
@@ -108531,6 +109400,10 @@ var RUNTIME_STATE_POLICY = {
|
|
|
108531
109400
|
durability: "session",
|
|
108532
109401
|
volatileFields: []
|
|
108533
109402
|
},
|
|
109403
|
+
"pet-fountain": {
|
|
109404
|
+
durability: "session",
|
|
109405
|
+
volatileFields: []
|
|
109406
|
+
},
|
|
108534
109407
|
"power-meter": {
|
|
108535
109408
|
durability: "restored",
|
|
108536
109409
|
volatileFields: ["lastFetchedAt"]
|
|
@@ -109518,7 +110391,11 @@ function createSystemProxy(api) {
|
|
|
109518
110391
|
listSupportedDeviceKinds: (input) => dispatch("deviceExport", "listSupportedDeviceKinds", "query", input),
|
|
109519
110392
|
listExposedDevices: (input) => dispatch("deviceExport", "listExposedDevices", "query", input),
|
|
109520
110393
|
exposeDevice: (input) => dispatch("deviceExport", "exposeDevice", "mutation", input),
|
|
109521
|
-
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)
|
|
109522
110399
|
},
|
|
109523
110400
|
deviceHistory: {
|
|
109524
110401
|
listNodeSeries: (input) => dispatch("deviceHistory", "listNodeSeries", "query", input),
|
|
@@ -119078,6 +119955,7 @@ var OAUTH_LANDING_REASONS = [
|
|
|
119078
119955
|
"unknown_broker",
|
|
119079
119956
|
"not_configured",
|
|
119080
119957
|
"exchange_failed",
|
|
119958
|
+
"no_authorization_code",
|
|
119081
119959
|
"no_refresh_token",
|
|
119082
119960
|
"unavailable",
|
|
119083
119961
|
"unknown"
|
|
@@ -119305,6 +120183,83 @@ function filterForwardedCookies(cookieHeader) {
|
|
|
119305
120183
|
return cookieHeader.split(";").map((part) => part.trim()).filter((part) => part.length > 0 && !part.toLowerCase().startsWith("camstack_")).join("; ");
|
|
119306
120184
|
}
|
|
119307
120185
|
//#endregion
|
|
120186
|
+
//#region src/vendor-login-proxy/flow-trace.ts
|
|
120187
|
+
/** A short stable label for the attempt: enough to group lines, useless as a capability. */
|
|
120188
|
+
function attemptLabel(attemptId) {
|
|
120189
|
+
let hash = 2166136261;
|
|
120190
|
+
for (let i = 0; i < attemptId.length; i += 1) hash = Math.imul(hash ^ attemptId.charCodeAt(i), 16777619) >>> 0;
|
|
120191
|
+
return hash.toString(16).padStart(8, "0");
|
|
120192
|
+
}
|
|
120193
|
+
/** Distinct parameter names of a `?a=1&b=2` string (or of a urlencoded body), in order. */
|
|
120194
|
+
function paramNames(query) {
|
|
120195
|
+
const names = [];
|
|
120196
|
+
const raw = query.startsWith("?") ? query.slice(1) : query;
|
|
120197
|
+
for (const pair of raw.split("&")) {
|
|
120198
|
+
if (pair.length === 0) continue;
|
|
120199
|
+
const eq = pair.indexOf("=");
|
|
120200
|
+
const rawName = eq === -1 ? pair : pair.slice(0, eq);
|
|
120201
|
+
let name;
|
|
120202
|
+
try {
|
|
120203
|
+
name = decodeURIComponent(rawName.replace(/\+/g, " "));
|
|
120204
|
+
} catch {
|
|
120205
|
+
name = rawName;
|
|
120206
|
+
}
|
|
120207
|
+
if (!names.includes(name)) names.push(name);
|
|
120208
|
+
}
|
|
120209
|
+
return names;
|
|
120210
|
+
}
|
|
120211
|
+
function hasOa2(names) {
|
|
120212
|
+
return names.some((name) => name.startsWith("openid.oa2.") || name === "openid.ns.oa2");
|
|
120213
|
+
}
|
|
120214
|
+
function cookieNamesOf(setCookies) {
|
|
120215
|
+
return setCookies.map((c) => c.split(";")[0]?.split("=")[0]?.trim() ?? "");
|
|
120216
|
+
}
|
|
120217
|
+
function mediaType(contentType) {
|
|
120218
|
+
return (contentType ?? "none").split(";")[0]?.trim().toLowerCase() || "none";
|
|
120219
|
+
}
|
|
120220
|
+
/** Host and path of a Location (no query), or 'unparsable'. */
|
|
120221
|
+
function locationShape(location, base) {
|
|
120222
|
+
try {
|
|
120223
|
+
const url = new URL(location, base);
|
|
120224
|
+
return {
|
|
120225
|
+
target: `${url.host}${url.pathname}`,
|
|
120226
|
+
names: paramNames(url.search)
|
|
120227
|
+
};
|
|
120228
|
+
} catch {
|
|
120229
|
+
return {
|
|
120230
|
+
target: "unparsable",
|
|
120231
|
+
names: []
|
|
120232
|
+
};
|
|
120233
|
+
}
|
|
120234
|
+
}
|
|
120235
|
+
/** The `meta` of one trace line. Values: never. */
|
|
120236
|
+
function flowTraceMeta(input) {
|
|
120237
|
+
const queryNames = paramNames(input.requestSearch);
|
|
120238
|
+
const formNames = input.formBody === null ? null : paramNames(input.formBody);
|
|
120239
|
+
const meta = {
|
|
120240
|
+
session: attemptLabel(input.attemptId),
|
|
120241
|
+
method: input.method,
|
|
120242
|
+
upstream: `${input.upstreamHost}${input.upstreamPath}`,
|
|
120243
|
+
queryNames: queryNames.join(",") || "none",
|
|
120244
|
+
oa2InQuery: hasOa2(queryNames),
|
|
120245
|
+
status: input.status,
|
|
120246
|
+
setCookieNames: cookieNamesOf(input.setCookies).join(",") || "none",
|
|
120247
|
+
cookiesSent: (input.cookieHeader ?? "").split(";").filter((p) => p.trim().length > 0).length
|
|
120248
|
+
};
|
|
120249
|
+
if (formNames !== null) {
|
|
120250
|
+
meta["contentType"] = mediaType(input.contentType);
|
|
120251
|
+
meta["formNames"] = formNames.join(",") || "none";
|
|
120252
|
+
meta["oa2InForm"] = hasOa2(formNames);
|
|
120253
|
+
}
|
|
120254
|
+
if (input.location !== null) {
|
|
120255
|
+
const loc = locationShape(input.location, `http://${input.upstreamHost}/`);
|
|
120256
|
+
meta["location"] = loc.target;
|
|
120257
|
+
meta["locationQueryNames"] = loc.names.join(",") || "none";
|
|
120258
|
+
meta["oa2InLocation"] = hasOa2(loc.names);
|
|
120259
|
+
}
|
|
120260
|
+
return meta;
|
|
120261
|
+
}
|
|
120262
|
+
//#endregion
|
|
119308
120263
|
//#region src/vendor-login-proxy/login-proxy.ts
|
|
119309
120264
|
var MAX_REQUEST_BODY_BYTES = 2 * 1024 * 1024;
|
|
119310
120265
|
var MAX_TEXT_BODY_BYTES = 4 * 1024 * 1024;
|
|
@@ -119410,6 +120365,8 @@ var VendorLoginProxy = class {
|
|
|
119410
120365
|
#now;
|
|
119411
120366
|
#fetch;
|
|
119412
120367
|
#attempts = /* @__PURE__ */ new Map();
|
|
120368
|
+
/** Trace lines written per attempt (bounded by FLOW_TRACE_MAX_LINES). */
|
|
120369
|
+
#traced = /* @__PURE__ */ new Map();
|
|
119413
120370
|
constructor(options) {
|
|
119414
120371
|
this.#addonId = options.addonId;
|
|
119415
120372
|
this.#logger = options.logger;
|
|
@@ -119436,6 +120393,7 @@ var VendorLoginProxy = class {
|
|
|
119436
120393
|
}
|
|
119437
120394
|
close(attemptId) {
|
|
119438
120395
|
this.#attempts.delete(attemptId);
|
|
120396
|
+
this.#traced.delete(attemptId);
|
|
119439
120397
|
}
|
|
119440
120398
|
isOpen(attemptId) {
|
|
119441
120399
|
const attempt = this.#attempts.get(attemptId);
|
|
@@ -119482,7 +120440,7 @@ var VendorLoginProxy = class {
|
|
|
119482
120440
|
const forwardedPrefix = (firstHeader(req.headers["x-forwarded-prefix"]) ?? "").replace(/\/+$/, "");
|
|
119483
120441
|
const attempt = this.#attempts.get(parsed.attemptId);
|
|
119484
120442
|
if (attempt === void 0 || this.#now() > attempt.expiresAtMs) {
|
|
119485
|
-
if (attempt !== void 0) this
|
|
120443
|
+
if (attempt !== void 0) this.close(parsed.attemptId);
|
|
119486
120444
|
this.#logger.info("vendor login proxy: attempt refused", { meta: {
|
|
119487
120445
|
addonId: this.#addonId,
|
|
119488
120446
|
reason: attempt === void 0 ? "missing" : "expired"
|
|
@@ -119507,13 +120465,17 @@ var VendorLoginProxy = class {
|
|
|
119507
120465
|
}
|
|
119508
120466
|
const method = (req.method ?? "GET").toUpperCase();
|
|
119509
120467
|
let body;
|
|
120468
|
+
let formBodyRaw = null;
|
|
119510
120469
|
if (method !== "GET" && method !== "HEAD") {
|
|
119511
120470
|
const read = await readRequestBody(req);
|
|
119512
120471
|
if (read === "too-large") {
|
|
119513
120472
|
sendPlain(res, 413, "Request too large");
|
|
119514
120473
|
return;
|
|
119515
120474
|
}
|
|
119516
|
-
|
|
120475
|
+
if (isFormEncoded(req.headers["content-type"])) {
|
|
120476
|
+
formBodyRaw = read.toString("utf8");
|
|
120477
|
+
body = Buffer.from(rewriteFormBody(formBodyRaw, route), "utf8");
|
|
120478
|
+
} else body = read;
|
|
119517
120479
|
}
|
|
119518
120480
|
const headers = this.#requestHeaders(req, route, upstream);
|
|
119519
120481
|
const upstreamRes = await this.#fetch(target, {
|
|
@@ -119538,6 +120500,19 @@ var VendorLoginProxy = class {
|
|
|
119538
120500
|
sentNames: cookieNames(headers["cookie"]),
|
|
119539
120501
|
vendorSets: setCookies.map(setCookieShape).join(" | ")
|
|
119540
120502
|
} });
|
|
120503
|
+
this.#trace(parsed.attemptId, {
|
|
120504
|
+
attemptId: parsed.attemptId,
|
|
120505
|
+
method,
|
|
120506
|
+
upstreamHost: upstream.host,
|
|
120507
|
+
upstreamPath: target.pathname,
|
|
120508
|
+
requestSearch: target.search,
|
|
120509
|
+
formBody: formBodyRaw,
|
|
120510
|
+
contentType: firstHeader(req.headers["content-type"]),
|
|
120511
|
+
status: upstreamRes.status,
|
|
120512
|
+
location,
|
|
120513
|
+
setCookies,
|
|
120514
|
+
cookieHeader: headers["cookie"]
|
|
120515
|
+
});
|
|
119541
120516
|
const settled = await attempt.evaluate({
|
|
119542
120517
|
status: upstreamRes.status,
|
|
119543
120518
|
url: target.toString(),
|
|
@@ -119546,7 +120521,7 @@ var VendorLoginProxy = class {
|
|
|
119546
120521
|
bodyText: text
|
|
119547
120522
|
});
|
|
119548
120523
|
if (settled.kind === "done") {
|
|
119549
|
-
this
|
|
120524
|
+
this.close(parsed.attemptId);
|
|
119550
120525
|
this.#logger.info("vendor login proxy: sign-in finished", { meta: {
|
|
119551
120526
|
addonId: this.#addonId,
|
|
119552
120527
|
status: settled.landing.status
|
|
@@ -119570,6 +120545,16 @@ var VendorLoginProxy = class {
|
|
|
119570
120545
|
res.writeHead(upstreamRes.status, out);
|
|
119571
120546
|
await this.#pipeBody(upstreamRes, res);
|
|
119572
120547
|
}
|
|
120548
|
+
/** One names-only line per proxied request, at most FLOW_TRACE_MAX_LINES per attempt. */
|
|
120549
|
+
#trace(attemptId, input) {
|
|
120550
|
+
const written = this.#traced.get(attemptId) ?? 0;
|
|
120551
|
+
if (written >= 200) return;
|
|
120552
|
+
this.#traced.set(attemptId, written + 1);
|
|
120553
|
+
this.#logger.info("vendor login proxy: flow", { meta: {
|
|
120554
|
+
addonId: this.#addonId,
|
|
120555
|
+
...flowTraceMeta(input)
|
|
120556
|
+
} });
|
|
120557
|
+
}
|
|
119573
120558
|
#requestHeaders(req, route, upstream) {
|
|
119574
120559
|
const headers = {};
|
|
119575
120560
|
for (const [name, value] of Object.entries(req.headers)) {
|
|
@@ -120833,7 +121818,7 @@ exports.AddBrokerInputSchema = AddBrokerInputSchema;
|
|
|
120833
121818
|
exports.AddRetrainFrameFromRecordingResultSchema = AddRetrainFrameFromRecordingResultSchema;
|
|
120834
121819
|
exports.AddonAutoUpdateSchema = AddonAutoUpdateSchema;
|
|
120835
121820
|
exports.AddonListItemSchema = AddonListItemSchema;
|
|
120836
|
-
exports.AddonPageDeclarationSchema = AddonPageDeclarationSchema;
|
|
121821
|
+
exports.AddonPageDeclarationSchema = require_sleep.AddonPageDeclarationSchema;
|
|
120837
121822
|
exports.AddonPageInfoSchema = AddonPageInfoSchema;
|
|
120838
121823
|
exports.AddonRoutesScopeSchema = AddonRoutesScopeSchema;
|
|
120839
121824
|
exports.AdminLinkTargetEnum = AdminLinkTargetEnum;
|
|
@@ -121164,6 +122149,7 @@ exports.CompositionFieldSourceSchema = require_composition.CompositionFieldSourc
|
|
|
121164
122149
|
exports.CompositionFieldStateKindSchema = CompositionFieldStateKindSchema;
|
|
121165
122150
|
exports.CompositionFieldStateSchema = CompositionFieldStateSchema;
|
|
121166
122151
|
exports.CompositionFieldsFeatureSchema = require_composition.CompositionFieldsFeatureSchema;
|
|
122152
|
+
exports.CompositionForwardArgSchema = require_composition.CompositionForwardArgSchema;
|
|
121167
122153
|
exports.CompositionForwardCommandSchema = require_composition.CompositionForwardCommandSchema;
|
|
121168
122154
|
exports.CompositionFromSourceSchema = require_composition.CompositionFromSourceSchema;
|
|
121169
122155
|
exports.CompositionGetReadSchema = CompositionGetReadSchema;
|
|
@@ -121290,6 +122276,7 @@ exports.DEVICE_HISTORY_ENERGY_KEY = DEVICE_HISTORY_ENERGY_KEY;
|
|
|
121290
122276
|
exports.DEVICE_HISTORY_ORPHAN_DELETE_MAX = DEVICE_HISTORY_ORPHAN_DELETE_MAX;
|
|
121291
122277
|
exports.DEVICE_HISTORY_ORPHAN_LIST_MAX = DEVICE_HISTORY_ORPHAN_LIST_MAX;
|
|
121292
122278
|
exports.DEVICE_HISTORY_QUERY_MANY_MAX_ITEMS = DEVICE_HISTORY_QUERY_MANY_MAX_ITEMS;
|
|
122279
|
+
exports.DEVICE_ID_FIELD = DEVICE_ID_FIELD;
|
|
121293
122280
|
exports.DEVICE_NONCE_TTL_MS = DEVICE_NONCE_TTL_MS;
|
|
121294
122281
|
exports.DEVICE_PROFILES = DEVICE_PROFILES;
|
|
121295
122282
|
exports.DEVICE_RAMP = DEVICE_RAMP;
|
|
@@ -121472,6 +122459,8 @@ exports.ExportClipSubjectSchema = ExportClipSubjectSchema;
|
|
|
121472
122459
|
exports.ExportDenseRangeSchema = ExportDenseRangeSchema;
|
|
121473
122460
|
exports.ExportDenseSchema = ExportDenseSchema;
|
|
121474
122461
|
exports.ExportDownloadSchema = ExportDownloadSchema;
|
|
122462
|
+
exports.ExportEntityKindSchema = ExportEntityKindSchema;
|
|
122463
|
+
exports.ExportEntityRefSchema = ExportEntityRefSchema;
|
|
121475
122464
|
exports.ExportFootageSubjectSchema = ExportFootageSubjectSchema;
|
|
121476
122465
|
exports.ExportOptionsSchema = ExportOptionsSchema;
|
|
121477
122466
|
exports.ExportRecordSchema = ExportRecordSchema;
|
|
@@ -121481,7 +122470,9 @@ exports.ExportSpeedSchema = ExportSpeedSchema;
|
|
|
121481
122470
|
exports.ExportStateSchema = ExportStateSchema;
|
|
121482
122471
|
exports.ExportSubjectSchema = ExportSubjectSchema;
|
|
121483
122472
|
exports.ExportTimelapseSchema = ExportTimelapseSchema;
|
|
122473
|
+
exports.ExposeEntityInputSchema = ExposeEntityInputSchema;
|
|
121484
122474
|
exports.ExposedDeviceSchema = ExposedDeviceSchema;
|
|
122475
|
+
exports.ExposedEntitySchema = ExposedEntitySchema;
|
|
121485
122476
|
exports.ExposureModeSchema = ExposureModeSchema;
|
|
121486
122477
|
exports.ExpressionBindingSourceSchema = ExpressionBindingSourceSchema;
|
|
121487
122478
|
exports.ExpressionEvalError = require_composition.ExpressionEvalError;
|
|
@@ -121517,6 +122508,7 @@ exports.FEEDER_EXAMPLE_ADDON_ID = FEEDER_EXAMPLE_ADDON_ID;
|
|
|
121517
122508
|
exports.FEEDER_EXAMPLE_HA_DEVICE_ID = FEEDER_EXAMPLE_HA_DEVICE_ID;
|
|
121518
122509
|
exports.FFMPEG_PATH_ENV = require_composition.FFMPEG_PATH_ENV;
|
|
121519
122510
|
exports.FIRST_LEVEL_MACRO_CLASSES = FIRST_LEVEL_MACRO_CLASSES;
|
|
122511
|
+
exports.FORWARD_INPUT_KEY = require_composition.FORWARD_INPUT_KEY;
|
|
121520
122512
|
exports.FULL_IMAGE_BBOX = FULL_IMAGE_BBOX;
|
|
121521
122513
|
exports.FailureContributionSchema = FailureContributionSchema;
|
|
121522
122514
|
exports.FailureCounters = FailureCounters;
|
|
@@ -122125,6 +123117,8 @@ exports.NodeDirectoryEntrySchema = NodeDirectoryEntrySchema;
|
|
|
122125
123117
|
exports.NodeDirectorySchema = NodeDirectorySchema;
|
|
122126
123118
|
exports.NodeHttpsStateSchema = NodeHttpsStateSchema;
|
|
122127
123119
|
exports.NodeRecommendationSchema = NodeRecommendationSchema;
|
|
123120
|
+
exports.NodeRemovedInputSchema = NodeRemovedInputSchema;
|
|
123121
|
+
exports.NodeRemovedResultSchema = NodeRemovedResultSchema;
|
|
122128
123122
|
exports.NotificationActionIconSchema = NotificationActionIconSchema;
|
|
122129
123123
|
exports.NotificationActionSchema = NotificationActionSchema;
|
|
122130
123124
|
exports.NotificationFormatSchema = NotificationFormatSchema;
|
|
@@ -122227,6 +123221,7 @@ exports.PcmSampleFormatSchema = PcmSampleFormatSchema;
|
|
|
122227
123221
|
exports.PeerBytesTicketSchema = require_sleep.PeerBytesTicketSchema;
|
|
122228
123222
|
exports.PerScopeBreakdownSchema = PerScopeBreakdownSchema;
|
|
122229
123223
|
exports.PetFeederStatusSchema = PetFeederStatusSchema;
|
|
123224
|
+
exports.PetFountainStatusSchema = PetFountainStatusSchema;
|
|
122230
123225
|
exports.PickStreamPreferencesSchema = PickStreamPreferencesSchema;
|
|
122231
123226
|
exports.PickStreamRequirementsSchema = PickStreamRequirementsSchema;
|
|
122232
123227
|
exports.PickedCamStreamSchema = PickedCamStreamSchema;
|
|
@@ -122234,8 +123229,8 @@ exports.PipelineAssignmentSchema = PipelineAssignmentSchema;
|
|
|
122234
123229
|
exports.PipelineDefaultStepSchema = PipelineDefaultStepSchema;
|
|
122235
123230
|
exports.PipelineEngineChoiceSchema = PipelineEngineChoiceSchema;
|
|
122236
123231
|
exports.PipelineModelFormatStatusSchema = PipelineModelFormatStatusSchema;
|
|
122237
|
-
exports.PipelineRunResultBridge = PipelineRunResultBridge;
|
|
122238
|
-
exports.PipelineStepInputSchema = PipelineStepInputSchema;
|
|
123232
|
+
exports.PipelineRunResultBridge = require_sleep.PipelineRunResultBridge;
|
|
123233
|
+
exports.PipelineStepInputSchema = require_sleep.PipelineStepInputSchema;
|
|
122239
123234
|
exports.PipelineValidationIssueSchema = PipelineValidationIssueSchema;
|
|
122240
123235
|
exports.PipelineValidationResultSchema = PipelineValidationResultSchema;
|
|
122241
123236
|
exports.PlaceholderReasonSchema = PlaceholderReasonSchema;
|
|
@@ -122824,6 +123819,7 @@ exports.UNIT_TABLE = UNIT_TABLE;
|
|
|
122824
123819
|
exports.UNLOCK_CONFIRMATION = UNLOCK_CONFIRMATION;
|
|
122825
123820
|
exports.USE_ROOT_MODEL_DEFAULTS = USE_ROOT_MODEL_DEFAULTS;
|
|
122826
123821
|
exports.USE_ROOT_MODEL_SETTING_KEY = USE_ROOT_MODEL_SETTING_KEY;
|
|
123822
|
+
exports.UnexposeEntityInputSchema = UnexposeEntityInputSchema;
|
|
122827
123823
|
exports.UnifiedBrokerInfoSchema = BrokerInfoSchema;
|
|
122828
123824
|
exports.UnindexedFilterError = require_sleep.UnindexedFilterError;
|
|
122829
123825
|
exports.UninstallNodeOutcomeSchema = UninstallNodeOutcomeSchema;
|
|
@@ -122928,7 +123924,7 @@ exports.actuatorMethodRow = actuatorMethodRow;
|
|
|
122928
123924
|
exports.addonCatalogHref = addonCatalogHref;
|
|
122929
123925
|
exports.addonIdOfActionId = addonIdOfActionId;
|
|
122930
123926
|
exports.addonPagesCapability = addonPagesCapability;
|
|
122931
|
-
exports.addonPagesSourceCapability = addonPagesSourceCapability;
|
|
123927
|
+
exports.addonPagesSourceCapability = require_sleep.addonPagesSourceCapability;
|
|
122932
123928
|
exports.addonRoutesCapability = addonRoutesCapability;
|
|
122933
123929
|
exports.addonSettingsCapability = addonSettingsCapability;
|
|
122934
123930
|
exports.addonWidgetsCapability = addonWidgetsCapability;
|
|
@@ -123084,6 +124080,8 @@ exports.collectSecretMarkerRefs = require_sleep.collectSecretMarkerRefs;
|
|
|
123084
124080
|
exports.collectZodSecretPaths = require_sleep.collectZodSecretPaths;
|
|
123085
124081
|
exports.colorCapability = colorCapability;
|
|
123086
124082
|
exports.colorForKind = colorForKind;
|
|
124083
|
+
exports.commandMethodProblems = commandMethodProblems;
|
|
124084
|
+
exports.commandedMethods = commandedMethods;
|
|
123087
124085
|
exports.commitWatchdogRestart = commitWatchdogRestart;
|
|
123088
124086
|
exports.compareToTarget = compareToTarget;
|
|
123089
124087
|
exports.compileExpression = require_composition.compileExpression;
|
|
@@ -123297,6 +124295,7 @@ exports.failureRate = failureRate;
|
|
|
123297
124295
|
exports.fanControlCapability = fanControlCapability;
|
|
123298
124296
|
exports.fanOutTargets = fanOutTargets;
|
|
123299
124297
|
exports.featureFieldEntries = require_composition.featureFieldEntries;
|
|
124298
|
+
exports.featureForwards = featureForwards;
|
|
123300
124299
|
exports.featureOfRole = featureOfRole;
|
|
123301
124300
|
exports.featureProbeCapability = featureProbeCapability;
|
|
123302
124301
|
exports.featureSources = require_composition.featureSources;
|
|
@@ -123324,6 +124323,9 @@ exports.formatParkedFor = formatParkedFor;
|
|
|
123324
124323
|
exports.formatReading = formatReading;
|
|
123325
124324
|
exports.formatSecretScope = require_sleep.formatSecretScope;
|
|
123326
124325
|
exports.formulaProblem = formulaProblem;
|
|
124326
|
+
exports.forwardProblems = forwardProblems;
|
|
124327
|
+
exports.forwardSourceProblems = forwardSourceProblems;
|
|
124328
|
+
exports.forwardSourceRefs = forwardSourceRefs;
|
|
123327
124329
|
exports.freshResults = freshResults;
|
|
123328
124330
|
exports.fuseRecoveredDetections = fuseRecoveredDetections;
|
|
123329
124331
|
exports.gasCapability = gasCapability;
|
|
@@ -123414,6 +124416,7 @@ exports.isEvent = require_sleep.isEvent;
|
|
|
123414
124416
|
exports.isEventKindLabelKey = isEventKindLabelKey;
|
|
123415
124417
|
exports.isEventOwnerType = isEventOwnerType;
|
|
123416
124418
|
exports.isFirstLevelMacroClass = isFirstLevelMacroClass;
|
|
124419
|
+
exports.isForwardInputRef = require_composition.isForwardInputRef;
|
|
123417
124420
|
exports.isHeldBackTemplateVar = isHeldBackTemplateVar;
|
|
123418
124421
|
exports.isHistoryHelper = require_composition.isHistoryHelper;
|
|
123419
124422
|
exports.isIconKey = isIconKey;
|
|
@@ -123559,6 +124562,7 @@ exports.nodeBenchmarkRefusals = nodeBenchmarkRefusals;
|
|
|
123559
124562
|
exports.nodeCertificatesCapability = nodeCertificatesCapability;
|
|
123560
124563
|
exports.nodePickerItems = nodePickerItems;
|
|
123561
124564
|
exports.nodePin = require_sleep.nodePin;
|
|
124565
|
+
exports.nodeRemovalHookCapability = nodeRemovalHookCapability;
|
|
123562
124566
|
exports.nodesCapability = nodesCapability;
|
|
123563
124567
|
exports.normalizeAddonInitResult = require_sleep.normalizeAddonInitResult;
|
|
123564
124568
|
exports.normalizeAudioLabel = normalizeAudioLabel;
|
|
@@ -123628,6 +124632,8 @@ exports.parseStreamParamsFormPatch = parseStreamParamsFormPatch;
|
|
|
123628
124632
|
exports.parseTrainingEventLine = parseTrainingEventLine;
|
|
123629
124633
|
exports.patchAudio = patchAudio;
|
|
123630
124634
|
exports.petFeederCapability = petFeederCapability;
|
|
124635
|
+
exports.petFountainCapability = petFountainCapability;
|
|
124636
|
+
exports.petFountainFromEntitiesComposition = petFountainFromEntitiesComposition;
|
|
123631
124637
|
exports.pickAccessoryControl = pickAccessoryControl;
|
|
123632
124638
|
exports.pickAppLinkHub = pickAppLinkHub;
|
|
123633
124639
|
exports.pickClusterStepModels = pickClusterStepModels;
|
|
@@ -123676,6 +124682,7 @@ exports.projectScalarAssignment = projectScalarAssignment;
|
|
|
123676
124682
|
exports.projectSpanAssignment = projectSpanAssignment;
|
|
123677
124683
|
exports.projectSubjectPath = projectSubjectPath;
|
|
123678
124684
|
exports.providerMotionEvent = providerMotionEvent;
|
|
124685
|
+
exports.pruneDeletedEntities = pruneDeletedEntities;
|
|
123679
124686
|
exports.ptzAutotrackCapability = ptzAutotrackCapability;
|
|
123680
124687
|
exports.ptzCapability = ptzCapability;
|
|
123681
124688
|
exports.publicEventCategories = require_event_category.publicEventCategories;
|
|
@@ -123805,6 +124812,7 @@ exports.ruleSection = ruleSection;
|
|
|
123805
124812
|
exports.ruleSectionOf = ruleSectionOf;
|
|
123806
124813
|
exports.ruleSeedForSection = ruleSeedForSection;
|
|
123807
124814
|
exports.ruleTriggerZoneIds = ruleTriggerZoneIds;
|
|
124815
|
+
exports.runExportedAction = runExportedAction;
|
|
123808
124816
|
exports.runFanOut = runFanOut;
|
|
123809
124817
|
exports.runInferenceStep = runInferenceStep;
|
|
123810
124818
|
exports.runSteps = runSteps;
|
|
@@ -123843,6 +124851,7 @@ exports.selectAssignedProfileSlots = require_sleep.selectAssignedProfileSlots;
|
|
|
123843
124851
|
exports.selectRecoveryStep = selectRecoveryStep;
|
|
123844
124852
|
exports.sendTimesForEditor = sendTimesForEditor;
|
|
123845
124853
|
exports.sendTimesOfSchedule = sendTimesOfSchedule;
|
|
124854
|
+
exports.sendToExportedTarget = sendToExportedTarget;
|
|
123846
124855
|
exports.sensorRaisedOf = sensorRaisedOf;
|
|
123847
124856
|
exports.sensorTransitionNeverFires = sensorTransitionNeverFires;
|
|
123848
124857
|
exports.sensorTransitionOffered = sensorTransitionOffered;
|