@camstack/addon-model-studio 1.1.318 → 1.1.320
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 +12 -0
- package/dist/{MotionZonesSettings-DNN9QEA3.mjs → MotionZonesSettings-Bb_BJah5.mjs} +2 -2
- package/dist/{PrivacyMaskSettings-CwE32Qhm.mjs → PrivacyMaskSettings-kCHid95c.mjs} +4 -4
- package/dist/{SceneMonitorEditor-SNXiXvXt.mjs → SceneMonitorEditor-BqNgh047.mjs} +3 -3
- package/dist/_stub.js +4628 -4283
- package/dist/{_virtual_mf-localSharedImportMap___mfe_internal__addon_model_studio_page-BaMcMPS8.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_model_studio_page-Dng9ZasK.mjs} +3 -3
- package/dist/_virtual_mf___mfe_internal__addon_model_studio_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DF4vj9Lw.mjs +26 -0
- package/dist/addon-model-studio.css +1 -1
- package/dist/{hostInit-C6xHvsEb.mjs → hostInit-B87DDaID.mjs} +2 -2
- package/dist/model-studio.addon.js +1288 -877
- package/dist/model-studio.addon.mjs +1288 -877
- package/dist/{player-overlays-BmZ_qrdR.mjs → player-overlays-CNVhS2-N.mjs} +1 -1
- package/dist/remoteEntry.js +1 -1
- package/dist/{responsive-Dypi_Y-V.mjs → responsive-oPhme86z.mjs} +1 -1
- package/dist/{scene-monitor-copy-Bafz9ZMd.mjs → scene-monitor-copy-Ct1WyOQx.mjs} +1 -1
- package/dist/{square-BhfFFjT7.mjs → square-WmNfgZ5W.mjs} +1 -1
- package/dist/{trash-2-BAyfEZwH.mjs → trash-2-BUJwssR_.mjs} +1 -1
- package/dist/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_model_studio_page__remoteEntry_js-DyWlwmuC.mjs → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_model_studio_page__remoteEntry_js-Ca412ASr.mjs} +1 -1
- package/package.json +1 -1
- package/dist/_virtual_mf___mfe_internal__addon_model_studio_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-D_KssOQn.mjs +0 -26
|
@@ -5437,6 +5437,14 @@ function object(shape, params) {
|
|
|
5437
5437
|
...normalizeParams(params)
|
|
5438
5438
|
});
|
|
5439
5439
|
}
|
|
5440
|
+
function strictObject(shape, params) {
|
|
5441
|
+
return new ZodObject({
|
|
5442
|
+
type: "object",
|
|
5443
|
+
shape,
|
|
5444
|
+
catchall: never(),
|
|
5445
|
+
...normalizeParams(params)
|
|
5446
|
+
});
|
|
5447
|
+
}
|
|
5440
5448
|
function looseObject(shape, params) {
|
|
5441
5449
|
return new ZodObject({
|
|
5442
5450
|
type: "object",
|
|
@@ -5816,7 +5824,7 @@ var ZodIssueCode = {
|
|
|
5816
5824
|
var ZodFirstPartyTypeKind;
|
|
5817
5825
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5818
5826
|
//#endregion
|
|
5819
|
-
//#region ../types/dist/sleep-
|
|
5827
|
+
//#region ../types/dist/sleep-6eG9C8Xl.mjs
|
|
5820
5828
|
/**
|
|
5821
5829
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5822
5830
|
* window to float samples (D455).
|
|
@@ -8704,65 +8712,6 @@ var MODEL_FORMATS = [
|
|
|
8704
8712
|
"pt",
|
|
8705
8713
|
"gguf"
|
|
8706
8714
|
];
|
|
8707
|
-
/**
|
|
8708
|
-
* Per-call node pinning for `ctx.api` capability calls.
|
|
8709
|
-
*
|
|
8710
|
-
* A capability call normally resolves to its DEFAULT provider — a `singleton`
|
|
8711
|
-
* cap resolves to the hub, a device-scoped cap to the device's owning node. To
|
|
8712
|
-
* query a SPECIFIC node's provider instead (e.g. a remote agent's own
|
|
8713
|
-
* in-process `platform-probe` hardware, which the hub cannot probe), pin the
|
|
8714
|
-
* call to that node.
|
|
8715
|
-
*
|
|
8716
|
-
* The nodeId rides OUT-OF-BAND in the tRPC call context (NOT in the validated
|
|
8717
|
-
* method args), so capability method signatures stay `nodeId`-free — node
|
|
8718
|
-
* targeting is a property of the CALL, not of the method. The transport lifts
|
|
8719
|
-
* it from `op.context` onto the `CapCallInput.nodeId` field (`ipcParentLink`),
|
|
8720
|
-
* and the hub parent's `onUnownedCall` passes it to the `CapRouteResolver`,
|
|
8721
|
-
* which classifies a pinned agent node as `agent-child-forward`
|
|
8722
|
-
* (`$agent-cap-fwd.forward` → the agent's in-process provider).
|
|
8723
|
-
*
|
|
8724
|
-
* Usage at a call site:
|
|
8725
|
-
*
|
|
8726
|
-
* await api.platformProbe.getCapabilities.query(undefined, nodePin(nodeId))
|
|
8727
|
-
*/
|
|
8728
|
-
/** tRPC `op.context` key carrying a per-call node pin. */
|
|
8729
|
-
var CAP_NODE_PIN_CONTEXT_KEY = "__camstackNodePin";
|
|
8730
|
-
/**
|
|
8731
|
-
* Build the tRPC request options that pin a single capability call to `nodeId`.
|
|
8732
|
-
* Pass as the second argument to `.query(input, …)` / `.mutate(input, …)`.
|
|
8733
|
-
*
|
|
8734
|
-
* ## The id is normalised here, and it has to be
|
|
8735
|
-
*
|
|
8736
|
-
* A forked addon reads its own node from `ctx.kernel.localNodeId`, and inside a
|
|
8737
|
-
* worker that value is a RUNNER id — `hub/export-hap`, not `hub`. Routing
|
|
8738
|
-
* compares a pin against real node ids, so such a pin matches nothing and the
|
|
8739
|
-
* call fails with `no provider registered for cap "…"`. The local-first
|
|
8740
|
-
* resolver already guarded against this (`localNodeId.split('/')[0]`), which
|
|
8741
|
-
* made the hazard invisible: unpinned calls worked, and only an explicit pin —
|
|
8742
|
-
* the thing you reach for when you specifically need THIS node — silently
|
|
8743
|
-
* addressed a node that does not exist.
|
|
8744
|
-
*
|
|
8745
|
-
* Cost of it being missing: `addon-export-hap` pinned `decoder.getInfo` to its
|
|
8746
|
-
* own node to read the host's hardware-decode backend. It never once answered,
|
|
8747
|
-
* so every HomeKit egress transcode decoded in SOFTWARE — including 4K H.265 —
|
|
8748
|
-
* while D67's whole premise was that the decoder addon is the authority on
|
|
8749
|
-
* hardware. The warn said `decoding in SOFTWARE` and read as "this node has no
|
|
8750
|
-
* hardware", which was false.
|
|
8751
|
-
*
|
|
8752
|
-
* Normalising in the ONE constructor fixes every caller at once, which is why
|
|
8753
|
-
* it is here and not at the call sites.
|
|
8754
|
-
*/
|
|
8755
|
-
function nodePin(nodeId) {
|
|
8756
|
-
return { context: { [CAP_NODE_PIN_CONTEXT_KEY]: toNodeId(nodeId) } };
|
|
8757
|
-
}
|
|
8758
|
-
/**
|
|
8759
|
-
* A runner id is `<nodeId>/<addonId>`; a node id has no slash. Taking the head
|
|
8760
|
-
* is idempotent, so passing an already-clean id costs nothing.
|
|
8761
|
-
*/
|
|
8762
|
-
function toNodeId(idOrRunnerId) {
|
|
8763
|
-
const head = idOrRunnerId.split("/")[0];
|
|
8764
|
-
return head === void 0 || head.length === 0 ? idOrRunnerId : head;
|
|
8765
|
-
}
|
|
8766
8715
|
object({
|
|
8767
8716
|
field: string().min(1),
|
|
8768
8717
|
on: literal("advance")
|
|
@@ -8851,6 +8800,128 @@ function optionalMethod(input, output, options) {
|
|
|
8851
8800
|
providerOptional: true
|
|
8852
8801
|
};
|
|
8853
8802
|
}
|
|
8803
|
+
/**
|
|
8804
|
+
* Per-call node pinning for `ctx.api` capability calls.
|
|
8805
|
+
*
|
|
8806
|
+
* A capability call normally resolves to its DEFAULT provider — a `singleton`
|
|
8807
|
+
* cap resolves to the hub, a device-scoped cap to the device's owning node. To
|
|
8808
|
+
* query a SPECIFIC node's provider instead (e.g. a remote agent's own
|
|
8809
|
+
* in-process `platform-probe` hardware, which the hub cannot probe), pin the
|
|
8810
|
+
* call to that node.
|
|
8811
|
+
*
|
|
8812
|
+
* The nodeId rides OUT-OF-BAND in the tRPC call context (NOT in the validated
|
|
8813
|
+
* method args), so capability method signatures stay `nodeId`-free — node
|
|
8814
|
+
* targeting is a property of the CALL, not of the method. The transport lifts
|
|
8815
|
+
* it from `op.context` onto the `CapCallInput.nodeId` field (`ipcParentLink`),
|
|
8816
|
+
* and the hub parent's `onUnownedCall` passes it to the `CapRouteResolver`,
|
|
8817
|
+
* which classifies a pinned agent node as `agent-child-forward`
|
|
8818
|
+
* (`$agent-cap-fwd.forward` → the agent's in-process provider).
|
|
8819
|
+
*
|
|
8820
|
+
* Usage at a call site:
|
|
8821
|
+
*
|
|
8822
|
+
* await api.platformProbe.getCapabilities.query(undefined, nodePin(nodeId))
|
|
8823
|
+
*/
|
|
8824
|
+
/** tRPC `op.context` key carrying a per-call node pin. */
|
|
8825
|
+
var CAP_NODE_PIN_CONTEXT_KEY = "__camstackNodePin";
|
|
8826
|
+
/**
|
|
8827
|
+
* Build the tRPC request options that pin a single capability call to `nodeId`.
|
|
8828
|
+
* Pass as the second argument to `.query(input, …)` / `.mutate(input, …)`.
|
|
8829
|
+
*
|
|
8830
|
+
* ## The id is normalised here, and it has to be
|
|
8831
|
+
*
|
|
8832
|
+
* A forked addon reads its own node from `ctx.kernel.localNodeId`, and inside a
|
|
8833
|
+
* worker that value is a RUNNER id — `hub/export-hap`, not `hub`. Routing
|
|
8834
|
+
* compares a pin against real node ids, so such a pin matches nothing and the
|
|
8835
|
+
* call fails with `no provider registered for cap "…"`. The local-first
|
|
8836
|
+
* resolver already guarded against this (`localNodeId.split('/')[0]`), which
|
|
8837
|
+
* made the hazard invisible: unpinned calls worked, and only an explicit pin —
|
|
8838
|
+
* the thing you reach for when you specifically need THIS node — silently
|
|
8839
|
+
* addressed a node that does not exist.
|
|
8840
|
+
*
|
|
8841
|
+
* Cost of it being missing: `addon-export-hap` pinned `decoder.getInfo` to its
|
|
8842
|
+
* own node to read the host's hardware-decode backend. It never once answered,
|
|
8843
|
+
* so every HomeKit egress transcode decoded in SOFTWARE — including 4K H.265 —
|
|
8844
|
+
* while D67's whole premise was that the decoder addon is the authority on
|
|
8845
|
+
* hardware. The warn said `decoding in SOFTWARE` and read as "this node has no
|
|
8846
|
+
* hardware", which was false.
|
|
8847
|
+
*
|
|
8848
|
+
* Normalising in the ONE constructor fixes every caller at once, which is why
|
|
8849
|
+
* it is here and not at the call sites.
|
|
8850
|
+
*/
|
|
8851
|
+
function nodePin(nodeId) {
|
|
8852
|
+
return { context: { [CAP_NODE_PIN_CONTEXT_KEY]: toNodeId(nodeId) } };
|
|
8853
|
+
}
|
|
8854
|
+
/**
|
|
8855
|
+
* A runner id is `<nodeId>/<addonId>`; a node id has no slash. Taking the head
|
|
8856
|
+
* is idempotent, so passing an already-clean id costs nothing.
|
|
8857
|
+
*/
|
|
8858
|
+
function toNodeId(idOrRunnerId) {
|
|
8859
|
+
const head = idOrRunnerId.split("/")[0];
|
|
8860
|
+
return head === void 0 || head.length === 0 ? idOrRunnerId : head;
|
|
8861
|
+
}
|
|
8862
|
+
/**
|
|
8863
|
+
* `addon-pages-source` — collection cap exposing per-provider raw page
|
|
8864
|
+
* declarations. Every addon that contributes a UI page registers a
|
|
8865
|
+
* provider here. The hub-side singleton aggregator (`addon-pages` cap,
|
|
8866
|
+
* see `addon-pages.cap.ts`) walks this collection, stamps versioned
|
|
8867
|
+
* `bundleUrl` values, and returns the enriched `AddonPageInfo[]` list
|
|
8868
|
+
* that admin-ui consumes.
|
|
8869
|
+
*
|
|
8870
|
+
* The split exists because the public listing has a different output
|
|
8871
|
+
* shape than the per-provider raw declarations, and we want both ends
|
|
8872
|
+
* to flow through codegen instead of relying on a hand-written wrapper.
|
|
8873
|
+
*/
|
|
8874
|
+
var AddonPageDeclarationSchema = object({
|
|
8875
|
+
id: string(),
|
|
8876
|
+
label: string(),
|
|
8877
|
+
icon: string(),
|
|
8878
|
+
path: string(),
|
|
8879
|
+
/**
|
|
8880
|
+
* Module Federation remote name — must match the `name` field on the
|
|
8881
|
+
* page addon's `federation()` plugin config. Used by admin-ui's
|
|
8882
|
+
* `<AddonPageLoader>` to call `loadRemote('<remoteName>/page')`.
|
|
8883
|
+
* Conventionally `addon_<id>_page` (snake_case; MF names cannot
|
|
8884
|
+
* contain hyphens).
|
|
8885
|
+
*/
|
|
8886
|
+
remoteName: string(),
|
|
8887
|
+
/**
|
|
8888
|
+
* Bundle filename inside the addon's `dist/` dir served at
|
|
8889
|
+
* `/api/addon-pages/<addonId>/<bundle>`. With Module Federation this
|
|
8890
|
+
* is always `'remoteEntry.js'`; the value is kept on the metadata so
|
|
8891
|
+
* the static-file route can compute an mtime-based cache-buster URL
|
|
8892
|
+
* without a separate filesystem stat.
|
|
8893
|
+
*/
|
|
8894
|
+
bundle: string(),
|
|
8895
|
+
/**
|
|
8896
|
+
* Sidebar section this page docks into. Well-known ids: `'detection'`,
|
|
8897
|
+
* `'cluster'`, `'administration'` — the page renders inside that group.
|
|
8898
|
+
* Any OTHER string creates (or joins) a custom section rendered after
|
|
8899
|
+
* the built-in groups; its label comes from `sectionLabel` (first
|
|
8900
|
+
* declaration wins), falling back to the id. Absent → the legacy
|
|
8901
|
+
* "Addon Pages" group.
|
|
8902
|
+
*/
|
|
8903
|
+
section: string().optional(),
|
|
8904
|
+
/** Display label for a CUSTOM `section` id (ignored for well-known ids). */
|
|
8905
|
+
sectionLabel: string().optional()
|
|
8906
|
+
});
|
|
8907
|
+
var addonPagesSourceCapability = {
|
|
8908
|
+
name: "addon-pages-source",
|
|
8909
|
+
scope: "system",
|
|
8910
|
+
mode: "collection",
|
|
8911
|
+
internal: true,
|
|
8912
|
+
methods: {
|
|
8913
|
+
/**
|
|
8914
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
8915
|
+
* `data-store-provider`) — this was reachable on the AppRouter by ANY
|
|
8916
|
+
* authenticated session at the default `auth: 'protected'`. The only
|
|
8917
|
+
* consumer, the `addon-pages-aggregator` builtin, reads it via
|
|
8918
|
+
* `ctx.capabilities.getCollection('addon-pages-source')` — LOCAL-PROCESS
|
|
8919
|
+
* only, never tRPC (per `ctx.capabilities` seeing only the local
|
|
8920
|
+
* process). The public, enriched listing admin-ui actually consumes is
|
|
8921
|
+
* the separate `addon-pages` cap, unaffected by this change.
|
|
8922
|
+
*/
|
|
8923
|
+
listPages: method(_void(), array(AddonPageDeclarationSchema).readonly(), { auth: "admin" }) }
|
|
8924
|
+
};
|
|
8854
8925
|
var StaticDirOutputSchema$1 = object({ staticDir: string() });
|
|
8855
8926
|
var VersionOutputSchema$1 = object({ version: string() });
|
|
8856
8927
|
method(_void(), StaticDirOutputSchema$1, { auth: "admin" }), method(_void(), VersionOutputSchema$1, { auth: "admin" });
|
|
@@ -8876,6 +8947,27 @@ function customAction(input, output, options) {
|
|
|
8876
8947
|
...options?.caller ? { caller: "required" } : {}
|
|
8877
8948
|
};
|
|
8878
8949
|
}
|
|
8950
|
+
/**
|
|
8951
|
+
* The pipeline step-input shape and the run-result bridge, in a module that
|
|
8952
|
+
* imports nothing but zod and types.
|
|
8953
|
+
*
|
|
8954
|
+
* WHY A SEPARATE FILE (addon footprint, D28): both were declared in
|
|
8955
|
+
* `pipeline-executor.cap.ts`, whose import evaluates the whole executor schema
|
|
8956
|
+
* graph. An addon that only needs these two (the benchmark's `runPipelineTest`
|
|
8957
|
+
* action) paid ~130 MB of heap at load. `pipeline-executor.cap.ts` re-exports
|
|
8958
|
+
* them, so every existing import keeps working; addon server code takes them
|
|
8959
|
+
* from `@camstack/types/addon`.
|
|
8960
|
+
*/
|
|
8961
|
+
var PipelineStepInputSchema = lazy(() => object({
|
|
8962
|
+
addonId: string(),
|
|
8963
|
+
modelId: string().optional(),
|
|
8964
|
+
enabled: boolean().default(true),
|
|
8965
|
+
children: array(PipelineStepInputSchema).optional(),
|
|
8966
|
+
settings: record(string(), unknown()).optional(),
|
|
8967
|
+
jumpDeviceKey: string().optional()
|
|
8968
|
+
}));
|
|
8969
|
+
/** Typed bridge to the recursive `FrameResult` graph; validation is structural. */
|
|
8970
|
+
var PipelineRunResultBridge = custom();
|
|
8879
8971
|
var StaticDirOutputSchema = object({ staticDir: string() });
|
|
8880
8972
|
var VersionOutputSchema = object({ version: string() });
|
|
8881
8973
|
method(_void(), StaticDirOutputSchema, { auth: "admin" }), method(_void(), VersionOutputSchema, { auth: "admin" });
|
|
@@ -9060,6 +9152,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
9060
9152
|
"network-link",
|
|
9061
9153
|
"network-quality",
|
|
9062
9154
|
"node-certificates",
|
|
9155
|
+
"node-removal-hook",
|
|
9063
9156
|
"nodes",
|
|
9064
9157
|
"notification-output",
|
|
9065
9158
|
"notification-rules",
|
|
@@ -9070,6 +9163,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
9070
9163
|
"osd",
|
|
9071
9164
|
"osd-manager",
|
|
9072
9165
|
"pet-feeder",
|
|
9166
|
+
"pet-fountain",
|
|
9073
9167
|
"pipeline-analytics",
|
|
9074
9168
|
"pipeline-executor",
|
|
9075
9169
|
"pipeline-orchestrator",
|
|
@@ -10349,6 +10443,56 @@ Object.freeze({
|
|
|
10349
10443
|
"valueType": "number"
|
|
10350
10444
|
}
|
|
10351
10445
|
],
|
|
10446
|
+
"pet-fountain": [
|
|
10447
|
+
{
|
|
10448
|
+
"path": "waterLevel",
|
|
10449
|
+
"valueType": "number"
|
|
10450
|
+
},
|
|
10451
|
+
{
|
|
10452
|
+
"path": "waterVolume",
|
|
10453
|
+
"valueType": "number"
|
|
10454
|
+
},
|
|
10455
|
+
{
|
|
10456
|
+
"path": "empty",
|
|
10457
|
+
"valueType": "boolean"
|
|
10458
|
+
},
|
|
10459
|
+
{
|
|
10460
|
+
"path": "pumpRunning",
|
|
10461
|
+
"valueType": "boolean"
|
|
10462
|
+
},
|
|
10463
|
+
{
|
|
10464
|
+
"path": "pumpIntervalEnabled",
|
|
10465
|
+
"valueType": "boolean"
|
|
10466
|
+
},
|
|
10467
|
+
{
|
|
10468
|
+
"path": "pumpOnTime",
|
|
10469
|
+
"valueType": "number"
|
|
10470
|
+
},
|
|
10471
|
+
{
|
|
10472
|
+
"path": "pumpOffTime",
|
|
10473
|
+
"valueType": "number"
|
|
10474
|
+
},
|
|
10475
|
+
{
|
|
10476
|
+
"path": "lastDrink",
|
|
10477
|
+
"valueType": "number"
|
|
10478
|
+
},
|
|
10479
|
+
{
|
|
10480
|
+
"path": "currentHourDrink",
|
|
10481
|
+
"valueType": "number"
|
|
10482
|
+
},
|
|
10483
|
+
{
|
|
10484
|
+
"path": "last24hDrink",
|
|
10485
|
+
"valueType": "number"
|
|
10486
|
+
},
|
|
10487
|
+
{
|
|
10488
|
+
"path": "todayDrink",
|
|
10489
|
+
"valueType": "number"
|
|
10490
|
+
},
|
|
10491
|
+
{
|
|
10492
|
+
"path": "error",
|
|
10493
|
+
"valueType": "string"
|
|
10494
|
+
}
|
|
10495
|
+
],
|
|
10352
10496
|
"power-meter": [
|
|
10353
10497
|
{
|
|
10354
10498
|
"path": "power",
|
|
@@ -10886,7 +11030,7 @@ object({
|
|
|
10886
11030
|
params: record(string(), union([string(), number()])).optional()
|
|
10887
11031
|
});
|
|
10888
11032
|
//#endregion
|
|
10889
|
-
//#region ../types/dist/err-msg-
|
|
11033
|
+
//#region ../types/dist/err-msg-DWXWc0Di.mjs
|
|
10890
11034
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
10891
11035
|
DeviceType["Camera"] = "camera";
|
|
10892
11036
|
DeviceType["Hub"] = "hub";
|
|
@@ -10978,6 +11122,10 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
10978
11122
|
* native PetKit (`nodepetkit` `FeederDevice`), reusable by other feeder
|
|
10979
11123
|
* integrations sharing the same food/desiccant/hopper surface. */
|
|
10980
11124
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
11125
|
+
/** Pet water fountain — tank level, water drunk, pump and its duty cycle.
|
|
11126
|
+
* Installed with the `pet-fountain` cap. Reaches CamStack as loose entities
|
|
11127
|
+
* of a container and is BUILT as a composed device (D967). */
|
|
11128
|
+
DeviceType["PetFountain"] = "pet-fountain";
|
|
10981
11129
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
10982
11130
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
10983
11131
|
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
@@ -11238,7 +11386,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
11238
11386
|
return DeviceRole;
|
|
11239
11387
|
}({});
|
|
11240
11388
|
//#endregion
|
|
11241
|
-
//#region ../types/dist/composition-
|
|
11389
|
+
//#region ../types/dist/composition-kSuOifuG.mjs
|
|
11242
11390
|
/**
|
|
11243
11391
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11244
11392
|
*
|
|
@@ -12323,12 +12471,28 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
|
12323
12471
|
])
|
|
12324
12472
|
})
|
|
12325
12473
|
]);
|
|
12326
|
-
var
|
|
12474
|
+
var forwardArgUnion = union([
|
|
12475
|
+
string(),
|
|
12476
|
+
number(),
|
|
12477
|
+
boolean(),
|
|
12478
|
+
strictObject({ ["$input"]: string().min(1) }),
|
|
12479
|
+
record(string().min(1), lazy(() => forwardArgUnion))
|
|
12480
|
+
]);
|
|
12481
|
+
var CompositionForwardArgSchema = forwardArgUnion;
|
|
12482
|
+
/**
|
|
12483
|
+
* `forward` (D659, amended by D967): one method of a BUILT capability is one
|
|
12484
|
+
* call of `cap.method` on `source`. Without `args` the built method's input
|
|
12485
|
+
* passes through minus `deviceId`; with `args` the template IS the source's
|
|
12486
|
+
* whole input. `deviceId` is always the source's own, never an argument.
|
|
12487
|
+
*/
|
|
12488
|
+
var CompositionForwardCommandSchema = object({
|
|
12327
12489
|
kind: literal("forward"),
|
|
12328
12490
|
source: CompositionSourceRefSchema,
|
|
12329
12491
|
cap: string().min(1),
|
|
12330
|
-
method: string().min(1)
|
|
12331
|
-
|
|
12492
|
+
method: string().min(1),
|
|
12493
|
+
args: record(string().min(1), CompositionForwardArgSchema).optional()
|
|
12494
|
+
});
|
|
12495
|
+
var CompositionCommandTargetSchema = discriminatedUnion("kind", [CompositionForwardCommandSchema, CompositionCodeSourceSchema]);
|
|
12332
12496
|
/** An item key inside an item-array cap (`consumables.items[<key>]`). */
|
|
12333
12497
|
var COMPOSITION_ITEM_KEY_RE = /^[a-z0-9][a-z0-9-]{0,47}$/;
|
|
12334
12498
|
/**
|
|
@@ -12338,7 +12502,13 @@ var COMPOSITION_ITEM_KEY_RE = /^[a-z0-9][a-z0-9-]{0,47}$/;
|
|
|
12338
12502
|
*/
|
|
12339
12503
|
var CompositionItemEntrySchema = object({
|
|
12340
12504
|
label: string().min(1).max(80),
|
|
12341
|
-
fields: record(string().min(1), CompositionFieldSourceSchema)
|
|
12505
|
+
fields: record(string().min(1), CompositionFieldSourceSchema),
|
|
12506
|
+
/**
|
|
12507
|
+
* What the cap's `reset` does for THIS item (consumables). Present = the item
|
|
12508
|
+
* is resettable and a `reset` call naming its key forwards here. The item key
|
|
12509
|
+
* selects the command, so it is never an argument: there is no pass-through.
|
|
12510
|
+
*/
|
|
12511
|
+
reset: CompositionForwardCommandSchema.optional()
|
|
12342
12512
|
});
|
|
12343
12513
|
var CompositionFeatureSchema = discriminatedUnion("kind", [object({
|
|
12344
12514
|
kind: literal("fields"),
|
|
@@ -12350,7 +12520,7 @@ var CompositionFeatureSchema = discriminatedUnion("kind", [object({
|
|
|
12350
12520
|
* owns the WHOLE array field: the composed value holds exactly these items.
|
|
12351
12521
|
*/
|
|
12352
12522
|
items: record(string().regex(COMPOSITION_ITEM_KEY_RE), CompositionItemEntrySchema).refine((items) => Object.keys(items).length <= 16, { message: `at most 16 items` }).optional(),
|
|
12353
|
-
/**
|
|
12523
|
+
/** Method name → what serves it. Only a BUILT capability takes commands (D967). */
|
|
12354
12524
|
commands: record(string().min(1), CompositionCommandTargetSchema).optional()
|
|
12355
12525
|
}), object({
|
|
12356
12526
|
kind: literal("passthrough"),
|
|
@@ -16429,120 +16599,478 @@ object({
|
|
|
16429
16599
|
lastError: string().nullable()
|
|
16430
16600
|
});
|
|
16431
16601
|
/**
|
|
16432
|
-
*
|
|
16433
|
-
* surface that admin-ui consumes through `useAddonPagesListPages()`.
|
|
16602
|
+
* notification-output — canonical, capability-gated notification delivery.
|
|
16434
16603
|
*
|
|
16435
|
-
*
|
|
16436
|
-
*
|
|
16437
|
-
*
|
|
16438
|
-
*
|
|
16439
|
-
*
|
|
16604
|
+
* Apprise-derived model (see
|
|
16605
|
+
* `docs/superpowers/specs/2026-07-03-notification-output-notifier-matrix.md`):
|
|
16606
|
+
* callers emit ONE canonical `Notification`; each provider declares a
|
|
16607
|
+
* per-kind capability descriptor (`TargetKind`), and the pure degrade
|
|
16608
|
+
* engine (`@camstack/types` `prepareNotification`) transcodes / degrades the
|
|
16609
|
+
* message to what the kind supports — callers never special-case a service.
|
|
16440
16610
|
*
|
|
16441
|
-
*
|
|
16442
|
-
*
|
|
16443
|
-
* provider
|
|
16444
|
-
*
|
|
16445
|
-
*
|
|
16611
|
+
* DESIGN DECISIONS (locked):
|
|
16612
|
+
* - Target CRUD lives on THIS cap (`upsertTarget` / `deleteTarget` /
|
|
16613
|
+
* `setTargetEnabled`), each provider persisting via the `settings-store`
|
|
16614
|
+
* cap. Rationale: the admin UI needs one uniform surface across the
|
|
16615
|
+
* notifiers addon AND the HA addon; the addon-`globalSettingsSchema`-array
|
|
16616
|
+
* alternative would fork the UI per addon and cannot host the
|
|
16617
|
+
* discovery→adopt flow.
|
|
16618
|
+
* - `listTargetKinds` / `listTargets` / `discoverTargets` return arrays →
|
|
16619
|
+
* the generated cap-mount auto-`concatCollection`-fans them across every
|
|
16620
|
+
* registered provider (notifiers addon + HA addon) so one catalog is
|
|
16621
|
+
* routable. `send` / `testTarget` / CRUD route to ONE provider by the
|
|
16622
|
+
* `addonId` the generated collection router extracts from the call input.
|
|
16623
|
+
* - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
|
|
16624
|
+
* transformer) + UDS MsgPack both round-trip typed arrays — already used by
|
|
16625
|
+
* `storage` / `storage-provider` / `recording` caps over the same path. No
|
|
16626
|
+
* base64 fallback needed.
|
|
16627
|
+
*
|
|
16628
|
+
* TODO (deferred, closed-set change — separate decision): add
|
|
16629
|
+
* `providerKind: 'notify'` so notification providers surface on the unified
|
|
16630
|
+
* admin "Integrations" page.
|
|
16446
16631
|
*/
|
|
16447
|
-
var AddonPageDeclarationSchema$1 = object({
|
|
16448
|
-
id: string(),
|
|
16449
|
-
label: string(),
|
|
16450
|
-
icon: string(),
|
|
16451
|
-
path: string(),
|
|
16452
|
-
remoteName: string(),
|
|
16453
|
-
bundle: string(),
|
|
16454
|
-
section: string().optional(),
|
|
16455
|
-
sectionLabel: string().optional()
|
|
16456
|
-
});
|
|
16457
|
-
var AddonPageInfoSchema = object({
|
|
16458
|
-
addonId: string(),
|
|
16459
|
-
page: AddonPageDeclarationSchema$1,
|
|
16460
|
-
bundleUrl: string()
|
|
16461
|
-
});
|
|
16462
|
-
method(_void(), array(AddonPageInfoSchema).readonly());
|
|
16463
16632
|
/**
|
|
16464
|
-
*
|
|
16465
|
-
*
|
|
16466
|
-
|
|
16467
|
-
|
|
16468
|
-
|
|
16469
|
-
|
|
16633
|
+
* Zentik-derived typed-media enum — the superset across every kind. Each
|
|
16634
|
+
* adapter picks what it supports and the degrade engine filters the rest.
|
|
16635
|
+
*/
|
|
16636
|
+
var AttachmentMediaTypeSchema = _enum([
|
|
16637
|
+
"image",
|
|
16638
|
+
"video",
|
|
16639
|
+
"gif",
|
|
16640
|
+
"audio",
|
|
16641
|
+
"icon"
|
|
16642
|
+
]);
|
|
16643
|
+
/**
|
|
16644
|
+
* A single attachment. Exactly one of `url` (remote source, most adapters
|
|
16645
|
+
* prefer this) or `bytes` (inline source; required for Pushover-style
|
|
16646
|
+
* bytes-only kinds) MUST be present — the degrade engine expresses a
|
|
16647
|
+
* url→bytes fetch as a `needsFetch` directive the adapter executes.
|
|
16648
|
+
*/
|
|
16649
|
+
var AttachmentSchema = object({
|
|
16650
|
+
mediaType: AttachmentMediaTypeSchema,
|
|
16651
|
+
url: string().optional(),
|
|
16652
|
+
bytes: _instanceof(Uint8Array).optional(),
|
|
16653
|
+
mime: string().optional(),
|
|
16654
|
+
name: string().optional()
|
|
16655
|
+
}).refine((a) => a.url !== void 0 || a.bytes !== void 0, { message: "Attachment requires either `url` or `bytes`" });
|
|
16656
|
+
var NotificationFormatSchema = _enum([
|
|
16657
|
+
"text",
|
|
16658
|
+
"markdown",
|
|
16659
|
+
"html"
|
|
16660
|
+
]);
|
|
16661
|
+
/**
|
|
16662
|
+
* The CLOSED icon vocabulary an action button may use.
|
|
16470
16663
|
*
|
|
16471
|
-
*
|
|
16472
|
-
*
|
|
16473
|
-
*
|
|
16664
|
+
* A closed set, not a free string, and that is the whole point: an arbitrary
|
|
16665
|
+
* icon name is one that ntfy renders, zentik silently drops, and nobody
|
|
16666
|
+
* notices — the same class of gap as a zone vocabulary nothing produced
|
|
16667
|
+
* ([D35](../../../docs/decisions/adr-0035.md)). Every adapter maps this set or
|
|
16668
|
+
* declares `actionIcons: false` and the degrade engine strips the field.
|
|
16669
|
+
*
|
|
16670
|
+
* Named by INTENT, never by glyph. "check" would tie the vocabulary to one
|
|
16671
|
+
* renderer's icon set; "acknowledge" survives an adapter that draws it
|
|
16672
|
+
* differently.
|
|
16673
|
+
*
|
|
16674
|
+
* ── A TOKEN IS NOT A WIRE VALUE ─────────────────────────────────────
|
|
16675
|
+
*
|
|
16676
|
+
* These names are for US. **No adapter may forward one verbatim.** Each maps
|
|
16677
|
+
* the whole set onto its own renderer's vocabulary through a
|
|
16678
|
+
* `Record<NotificationActionIcon, string>` — a Record, never a lookup with a
|
|
16679
|
+
* fallback, so adding a member here fails every adapter's build until someone
|
|
16680
|
+
* decides its glyph, which is the only place that decision can be made
|
|
16681
|
+
* honestly.
|
|
16682
|
+
*
|
|
16683
|
+
* This paragraph is the bug. Zentik declared `actionIcons: true` and passed
|
|
16684
|
+
* `disarm` straight through; iOS feeds that string to
|
|
16685
|
+
* `UNNotificationActionIcon(systemImageName:)`, `disarm` is not an SF Symbol,
|
|
16686
|
+
* and every snooze and alarm button arrived BLANK. A pass-through is not a
|
|
16687
|
+
* mapping, and "the field is documented" is not "the value renders".
|
|
16688
|
+
*
|
|
16689
|
+
* Adding a member is TRAIN-BOUND. The enum lives in the published
|
|
16690
|
+
* `@camstack/server` closure and the cap seam validates against the HUB's copy,
|
|
16691
|
+
* so an addon that emits a token the running hub does not know does not lose an
|
|
16692
|
+
* icon — its whole `send` fails Zod validation and the notification never
|
|
16693
|
+
* arrives. Never emit a new token from an addon before the train carrying it.
|
|
16474
16694
|
*/
|
|
16475
|
-
var
|
|
16695
|
+
var NotificationActionIconSchema = _enum([
|
|
16696
|
+
"acknowledge",
|
|
16697
|
+
"dismiss",
|
|
16698
|
+
"silence",
|
|
16699
|
+
"snooze",
|
|
16700
|
+
"view",
|
|
16701
|
+
"play",
|
|
16702
|
+
"open",
|
|
16703
|
+
"close",
|
|
16704
|
+
"lock",
|
|
16705
|
+
"unlock",
|
|
16706
|
+
"arm",
|
|
16707
|
+
"arm-home",
|
|
16708
|
+
"arm-away",
|
|
16709
|
+
"arm-night",
|
|
16710
|
+
"disarm",
|
|
16711
|
+
"light",
|
|
16712
|
+
"alert",
|
|
16713
|
+
"camera"
|
|
16714
|
+
]);
|
|
16715
|
+
/** A single tap-through action button. */
|
|
16716
|
+
var NotificationActionSchema = object({
|
|
16476
16717
|
id: string(),
|
|
16477
16718
|
label: string(),
|
|
16478
|
-
|
|
16479
|
-
|
|
16480
|
-
|
|
16481
|
-
* Module Federation remote name — must match the `name` field on the
|
|
16482
|
-
* page addon's `federation()` plugin config. Used by admin-ui's
|
|
16483
|
-
* `<AddonPageLoader>` to call `loadRemote('<remoteName>/page')`.
|
|
16484
|
-
* Conventionally `addon_<id>_page` (snake_case; MF names cannot
|
|
16485
|
-
* contain hyphens).
|
|
16486
|
-
*/
|
|
16487
|
-
remoteName: string(),
|
|
16719
|
+
url: string().optional(),
|
|
16720
|
+
/** Dropped by the degrade engine for a kind with `caps.actionIcons: false`. */
|
|
16721
|
+
icon: NotificationActionIconSchema.optional(),
|
|
16488
16722
|
/**
|
|
16489
|
-
*
|
|
16490
|
-
*
|
|
16491
|
-
*
|
|
16492
|
-
*
|
|
16493
|
-
*
|
|
16723
|
+
* Renders in a warning style where the notifier supports it.
|
|
16724
|
+
*
|
|
16725
|
+
* A HINT, never a gate. The callback's authority is its token and nothing
|
|
16726
|
+
* else — see `notification-center/action-token.ts` for what that does and
|
|
16727
|
+
* does not buy.
|
|
16494
16728
|
*/
|
|
16495
|
-
|
|
16729
|
+
destructive: boolean().optional(),
|
|
16496
16730
|
/**
|
|
16497
|
-
*
|
|
16498
|
-
*
|
|
16499
|
-
*
|
|
16500
|
-
* the
|
|
16501
|
-
*
|
|
16502
|
-
*
|
|
16731
|
+
* How the tap should REACH the url.
|
|
16732
|
+
*
|
|
16733
|
+
* `navigate` (absent, and every button authored before this field) opens it:
|
|
16734
|
+
* the phone leaves the notification and shows whatever the callback returns.
|
|
16735
|
+
* That is right for a button whose answer the operator wants to read.
|
|
16736
|
+
*
|
|
16737
|
+
* `background` fires it as a POST and stays put. It exists for the buttons
|
|
16738
|
+
* whose whole point is not to interrupt — "silence this for 30 minutes" is
|
|
16739
|
+
* an answer to the notification, and being thrown into a browser tab to
|
|
16740
|
+
* confirm it costs more attention than the notification did. A backend that
|
|
16741
|
+
* cannot do a background call renders it as an ordinary link (the adapters
|
|
16742
|
+
* fall back rather than dropping the button), so this is a preference, never
|
|
16743
|
+
* a requirement.
|
|
16503
16744
|
*/
|
|
16504
|
-
|
|
16505
|
-
/** Display label for a CUSTOM `section` id (ignored for well-known ids). */
|
|
16506
|
-
sectionLabel: string().optional()
|
|
16745
|
+
mode: _enum(["navigate", "background"]).optional()
|
|
16507
16746
|
});
|
|
16508
|
-
|
|
16509
|
-
|
|
16510
|
-
|
|
16511
|
-
|
|
16512
|
-
|
|
16513
|
-
|
|
16514
|
-
|
|
16515
|
-
|
|
16516
|
-
|
|
16517
|
-
|
|
16518
|
-
|
|
16519
|
-
|
|
16520
|
-
|
|
16521
|
-
|
|
16522
|
-
|
|
16523
|
-
|
|
16524
|
-
|
|
16525
|
-
|
|
16526
|
-
|
|
16527
|
-
|
|
16528
|
-
|
|
16529
|
-
"
|
|
16530
|
-
"
|
|
16531
|
-
"
|
|
16532
|
-
"
|
|
16747
|
+
/** A delivery parameter value: what a notifier declared it takes. */
|
|
16748
|
+
var DeliveryParamValueSchema = union([
|
|
16749
|
+
string(),
|
|
16750
|
+
number(),
|
|
16751
|
+
boolean()
|
|
16752
|
+
]);
|
|
16753
|
+
/**
|
|
16754
|
+
* One extra delivery parameter a notifier KIND declares (D938). A rule that
|
|
16755
|
+
* addresses a target of that kind may set it; a kind that declares nothing is
|
|
16756
|
+
* never handed one. The admin UI derives its control from this descriptor —
|
|
16757
|
+
* no editor knows a service by name.
|
|
16758
|
+
*
|
|
16759
|
+
* Optional fields are `.optional()`, never `.default()` (a Zod default does not
|
|
16760
|
+
* run on the addon cap path).
|
|
16761
|
+
*/
|
|
16762
|
+
var DeliveryParamSchema = object({
|
|
16763
|
+
key: string().min(1),
|
|
16764
|
+
label: string(),
|
|
16765
|
+
/** i18n key of the label, resolved by the declaring addon's namespace. */
|
|
16766
|
+
labelKey: string().optional(),
|
|
16767
|
+
type: _enum([
|
|
16768
|
+
"enum",
|
|
16769
|
+
"number",
|
|
16770
|
+
"boolean",
|
|
16771
|
+
"string"
|
|
16533
16772
|
]),
|
|
16534
|
-
|
|
16535
|
-
|
|
16536
|
-
|
|
16537
|
-
|
|
16538
|
-
|
|
16539
|
-
|
|
16540
|
-
|
|
16541
|
-
|
|
16542
|
-
|
|
16773
|
+
/** `enum` only: the closed set of accepted values. */
|
|
16774
|
+
options: array(object({
|
|
16775
|
+
value: string(),
|
|
16776
|
+
label: string()
|
|
16777
|
+
})).optional(),
|
|
16778
|
+
/** `number` only. */
|
|
16779
|
+
min: number().optional(),
|
|
16780
|
+
max: number().optional(),
|
|
16781
|
+
/** What the notifier does when the rule sets nothing; shown as the placeholder. */
|
|
16782
|
+
default: DeliveryParamValueSchema.optional()
|
|
16543
16783
|
});
|
|
16544
16784
|
/**
|
|
16545
|
-
*
|
|
16785
|
+
* The canonical notification. `body` is the only hard field (Apprise model).
|
|
16786
|
+
* `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
|
|
16787
|
+
* NOT a fixed severity enum — each kind declares its own `caps.levels` and
|
|
16788
|
+
* the adapter maps this ordinal onto its native level. `level?` is an
|
|
16789
|
+
* optional kind-native level id (`emergency`, `silent`, …) that overrides
|
|
16790
|
+
* `priority` for that one target.
|
|
16791
|
+
*/
|
|
16792
|
+
var NotificationSchema = object({
|
|
16793
|
+
body: string(),
|
|
16794
|
+
title: string().optional(),
|
|
16795
|
+
format: NotificationFormatSchema.default("text"),
|
|
16796
|
+
priority: number().int().min(1).max(5).default(3),
|
|
16797
|
+
level: string().optional(),
|
|
16798
|
+
attachments: array(AttachmentSchema).optional(),
|
|
16799
|
+
clickUrl: string().optional(),
|
|
16800
|
+
actions: array(NotificationActionSchema).optional(),
|
|
16801
|
+
sound: string().optional(),
|
|
16802
|
+
ttl: number().optional(),
|
|
16803
|
+
tag: string().optional(),
|
|
16804
|
+
deviceId: number().optional(),
|
|
16805
|
+
eventId: string().optional(),
|
|
16806
|
+
metadata: record(string(), unknown()).optional(),
|
|
16807
|
+
/**
|
|
16808
|
+
* Values for the parameters the target's kind DECLARES in
|
|
16809
|
+
* {@link TargetKindSchema} `deliveryParams`. Already validated against the
|
|
16810
|
+
* declaration by the sender; a notifier reads only the keys it declared.
|
|
16811
|
+
*/
|
|
16812
|
+
delivery: record(string(), DeliveryParamValueSchema).optional()
|
|
16813
|
+
});
|
|
16814
|
+
/** One declared native severity/priority level for a kind. */
|
|
16815
|
+
var TargetKindLevelSchema = object({
|
|
16816
|
+
id: string(),
|
|
16817
|
+
label: string(),
|
|
16818
|
+
/** Which canonical priority (1..5) this level maps to. `null` = qualitative-only. */
|
|
16819
|
+
ordinal: number().int().min(1).max(5).nullable(),
|
|
16820
|
+
flags: object({
|
|
16821
|
+
critical: boolean().optional(),
|
|
16822
|
+
silent: boolean().optional(),
|
|
16823
|
+
noPush: boolean().optional()
|
|
16824
|
+
}).optional(),
|
|
16825
|
+
/** e.g. Pushover `emergency` requires `retry` / `expire`. */
|
|
16826
|
+
requires: array(string()).optional(),
|
|
16827
|
+
description: string().optional()
|
|
16828
|
+
});
|
|
16829
|
+
/** The full capability block consulted before dispatch. */
|
|
16830
|
+
var TargetKindCapsSchema = object({
|
|
16831
|
+
attachments: object({
|
|
16832
|
+
mediaTypes: array(AttachmentMediaTypeSchema),
|
|
16833
|
+
mode: _enum([
|
|
16834
|
+
"url",
|
|
16835
|
+
"bytes",
|
|
16836
|
+
"both"
|
|
16837
|
+
]),
|
|
16838
|
+
max: number().int().nonnegative(),
|
|
16839
|
+
maxBytes: number().int().positive().optional()
|
|
16840
|
+
}),
|
|
16841
|
+
/** Max action buttons (0 = none). */
|
|
16842
|
+
actions: number().int().nonnegative(),
|
|
16843
|
+
/**
|
|
16844
|
+
* Whether this kind renders a per-action ICON.
|
|
16845
|
+
*
|
|
16846
|
+
* `.optional()`, deliberately NOT `.default(false)`: a Zod default does not
|
|
16847
|
+
* run on the addon cap path — three production failures in one day taught
|
|
16848
|
+
* this repo that once. Absent is read as false by the degrade engine, which
|
|
16849
|
+
* is the safe direction: an icon that is not rendered costs nothing, an icon
|
|
16850
|
+
* assumed and dropped costs the operator's trust in the field.
|
|
16851
|
+
*/
|
|
16852
|
+
actionIcons: boolean().optional(),
|
|
16853
|
+
levels: array(TargetKindLevelSchema),
|
|
16854
|
+
format: array(NotificationFormatSchema),
|
|
16855
|
+
clickUrl: boolean(),
|
|
16856
|
+
sound: boolean(),
|
|
16857
|
+
ttl: boolean(),
|
|
16858
|
+
bodyMaxLen: number().int().positive()
|
|
16859
|
+
});
|
|
16860
|
+
/**
|
|
16861
|
+
* `configSchema` is a `ConfigUISchema` tree passed through to the admin
|
|
16862
|
+
* FormBuilder. Stored as `z.unknown()` at the cap seam (mirrors
|
|
16863
|
+
* `device-provider.getChildCreationSchema` `CreationSchemaOutputSchema`) —
|
|
16864
|
+
* the union is large and not meant for runtime validation here; the exported
|
|
16865
|
+
* `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
|
|
16866
|
+
*/
|
|
16867
|
+
var ConfigSchemaPassthrough$3 = unknown();
|
|
16868
|
+
var TargetKindSchema = object({
|
|
16869
|
+
kind: string(),
|
|
16870
|
+
label: string(),
|
|
16871
|
+
icon: string(),
|
|
16872
|
+
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
16873
|
+
addonId: string(),
|
|
16874
|
+
/**
|
|
16875
|
+
* URL of the kind's bundled BRAND icon, served by the providing addon over
|
|
16876
|
+
* its own `addon-routes` surface (`/addon/<addonId>/icons/<kind>`). Absent
|
|
16877
|
+
* when the addon bundles no icon for that kind — the client then falls back
|
|
16878
|
+
* to a neutral glyph rather than rendering the raw `icon` NAME as text.
|
|
16879
|
+
*
|
|
16880
|
+
* Root-relative on purpose: it resolves against whatever origin serves a web
|
|
16881
|
+
* client, and a native client joins it onto its own hub base.
|
|
16882
|
+
*
|
|
16883
|
+
* DECLARED here deliberately. It used to travel as an undeclared passthrough
|
|
16884
|
+
* field that survived only because the runtime cap-router forwards provider
|
|
16885
|
+
* output verbatim — so every consumer had to re-declare it by hand to stop
|
|
16886
|
+
* its own Zod parse from stripping it, and the whole arrangement would have
|
|
16887
|
+
* broken silently the moment output validation was tightened anywhere.
|
|
16888
|
+
*/
|
|
16889
|
+
iconUrl: string().optional(),
|
|
16890
|
+
/**
|
|
16891
|
+
* Media type of {@link iconUrl} (`image/svg+xml`, `image/png`, …).
|
|
16892
|
+
*
|
|
16893
|
+
* The server knows this and therefore says it, because the client cannot
|
|
16894
|
+
* safely guess: a React-Native client renders SVG and raster through two
|
|
16895
|
+
* DIFFERENT components (`react-native-svg` vs `expo-image` — expo-image does
|
|
16896
|
+
* not decode SVG on iOS/Android), so without this it silently fell back to a
|
|
16897
|
+
* placeholder glyph for every vector icon while the web build looked fine.
|
|
16898
|
+
*
|
|
16899
|
+
* Absent when {@link iconUrl} is absent, or for a legacy provider that has
|
|
16900
|
+
* not been updated — a client that cannot determine the type should prefer
|
|
16901
|
+
* its raster path, which is the safe default for an unknown image.
|
|
16902
|
+
*/
|
|
16903
|
+
iconMediaType: string().optional(),
|
|
16904
|
+
configSchema: ConfigSchemaPassthrough$3,
|
|
16905
|
+
/**
|
|
16906
|
+
* The config keys that decide WHERE this kind's secrets are sent (server,
|
|
16907
|
+
* base URL, instance, chat, recipient). A save that changes any of them
|
|
16908
|
+
* while leaving a secret redacted is refused by the provider (D634), so an
|
|
16909
|
+
* editor uses this to ask for the secret on exactly those edits instead of
|
|
16910
|
+
* on every edit.
|
|
16911
|
+
*
|
|
16912
|
+
* Optional: absent from a provider that holds no secret (the Home Assistant
|
|
16913
|
+
* kinds) and from a provider older than this field — an editor that finds
|
|
16914
|
+
* it absent must assume ANY edit may need the secret.
|
|
16915
|
+
*/
|
|
16916
|
+
destinationKeys: array(string()).optional(),
|
|
16917
|
+
supportsDiscovery: boolean(),
|
|
16918
|
+
/**
|
|
16919
|
+
* Extra delivery parameters a rule may set for a target of this kind (D938).
|
|
16920
|
+
* Absent = none; the rule editor then offers nothing.
|
|
16921
|
+
*/
|
|
16922
|
+
deliveryParams: array(DeliveryParamSchema).optional(),
|
|
16923
|
+
caps: TargetKindCapsSchema
|
|
16924
|
+
});
|
|
16925
|
+
/**
|
|
16926
|
+
* A persisted target. `config` holds secrets; providers REDACT secret fields
|
|
16927
|
+
* (return a presence marker only) when serving `listTargets` — never
|
|
16928
|
+
* round-trip a stored secret to the UI.
|
|
16929
|
+
*/
|
|
16930
|
+
var TargetSchema = object({
|
|
16931
|
+
id: string(),
|
|
16932
|
+
name: string(),
|
|
16933
|
+
kind: string(),
|
|
16934
|
+
addonId: string(),
|
|
16935
|
+
enabled: boolean(),
|
|
16936
|
+
config: record(string(), unknown())
|
|
16937
|
+
});
|
|
16938
|
+
/** A discovery-surfaced candidate (config is partial + non-secret). */
|
|
16939
|
+
var DiscoveredTargetSchema = object({
|
|
16940
|
+
kind: string(),
|
|
16941
|
+
suggestedName: string(),
|
|
16942
|
+
config: record(string(), unknown())
|
|
16943
|
+
});
|
|
16944
|
+
/** The degrade engine's report — what was resolved / dropped / degraded. */
|
|
16945
|
+
var RenderedAsSchema = object({
|
|
16946
|
+
level: string(),
|
|
16947
|
+
format: NotificationFormatSchema,
|
|
16948
|
+
attachmentsSent: number().int().nonnegative(),
|
|
16949
|
+
actionsSent: number().int().nonnegative(),
|
|
16950
|
+
truncated: boolean(),
|
|
16951
|
+
dropped: array(string())
|
|
16952
|
+
});
|
|
16953
|
+
var SendResultSchema = object({
|
|
16954
|
+
success: boolean(),
|
|
16955
|
+
error: string().optional(),
|
|
16956
|
+
renderedAs: RenderedAsSchema.optional()
|
|
16957
|
+
});
|
|
16958
|
+
/** Same shape as SendResult — kept as a distinct name for the test panel. */
|
|
16959
|
+
var TestResultSchema = SendResultSchema;
|
|
16960
|
+
/**
|
|
16961
|
+
* Pre-save credential probe against a partial (unsaved) target config.
|
|
16962
|
+
* `resolvedUrl` never includes secrets (token stripped from path).
|
|
16963
|
+
*/
|
|
16964
|
+
var ProbeTargetConfigResultSchema = object({
|
|
16965
|
+
ok: boolean(),
|
|
16966
|
+
resolvedUrl: string(),
|
|
16967
|
+
httpStatus: number().int().optional(),
|
|
16968
|
+
stateInstance: string().optional(),
|
|
16969
|
+
error: string().optional()
|
|
16970
|
+
});
|
|
16971
|
+
method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSchema), { auth: "admin" }), method(object({ targetId: string() }), TargetSchema, { auth: "admin" }), method(object({
|
|
16972
|
+
kind: string(),
|
|
16973
|
+
config: record(string(), unknown()).optional(),
|
|
16974
|
+
/**
|
|
16975
|
+
* When editing / duplicating, the blank password field never round-trips
|
|
16976
|
+
* the stored token. Pass the source target id so the provider can restore
|
|
16977
|
+
* secrets server-side before dialling (same merge as upsert).
|
|
16978
|
+
*/
|
|
16979
|
+
targetId: string().optional()
|
|
16980
|
+
}), array(DiscoveredTargetSchema), { auth: "admin" }), method(object({
|
|
16981
|
+
kind: string(),
|
|
16982
|
+
config: record(string(), unknown()),
|
|
16983
|
+
/** See `discoverTargets.targetId` — restore stored secrets for a blank password. */
|
|
16984
|
+
targetId: string().optional()
|
|
16985
|
+
}), ProbeTargetConfigResultSchema, {
|
|
16986
|
+
kind: "mutation",
|
|
16987
|
+
auth: "admin"
|
|
16988
|
+
}), method(object({
|
|
16989
|
+
targetId: string(),
|
|
16990
|
+
notification: NotificationSchema
|
|
16991
|
+
}), SendResultSchema, {
|
|
16992
|
+
kind: "mutation",
|
|
16993
|
+
auth: "admin"
|
|
16994
|
+
}), method(object({
|
|
16995
|
+
targetId: string(),
|
|
16996
|
+
sample: NotificationSchema.optional()
|
|
16997
|
+
}), TestResultSchema, {
|
|
16998
|
+
kind: "mutation",
|
|
16999
|
+
auth: "admin"
|
|
17000
|
+
}), method(object({
|
|
17001
|
+
target: TargetSchema,
|
|
17002
|
+
/**
|
|
17003
|
+
* Duplicate flow: create a NEW target id while copying secrets from an
|
|
17004
|
+
* existing row. The UI never holds the stored token; blank / redacted
|
|
17005
|
+
* password fields are restored from this source (D634 still applies if
|
|
17006
|
+
* destinations diverge without a re-typed secret).
|
|
17007
|
+
*/
|
|
17008
|
+
cloneSecretsFrom: string().optional()
|
|
17009
|
+
}), TargetSchema, {
|
|
17010
|
+
kind: "mutation",
|
|
17011
|
+
auth: "admin"
|
|
17012
|
+
}), method(object({ targetId: string() }), _void(), {
|
|
17013
|
+
kind: "mutation",
|
|
17014
|
+
auth: "admin"
|
|
17015
|
+
}), method(object({
|
|
17016
|
+
targetId: string(),
|
|
17017
|
+
enabled: boolean()
|
|
17018
|
+
}), _void(), {
|
|
17019
|
+
kind: "mutation",
|
|
17020
|
+
auth: "admin"
|
|
17021
|
+
});
|
|
17022
|
+
/**
|
|
17023
|
+
* `addon-pages` — system-scoped singleton aggregator cap. Public-facing
|
|
17024
|
+
* surface that admin-ui consumes through `useAddonPagesListPages()`.
|
|
17025
|
+
*
|
|
17026
|
+
* The provider iterates every `addon-pages-source` (collection) provider
|
|
17027
|
+
* and emits `AddonPageInfo[]` enriched with versioned `bundleUrl` strings
|
|
17028
|
+
* pointing at `/api/addon-pages/<addonId>/<bundle>?v=<mtime>`. The
|
|
17029
|
+
* filesystem `mtime` cache-buster lets the browser pick up addon
|
|
17030
|
+
* rebuilds without manual reload.
|
|
17031
|
+
*
|
|
17032
|
+
* The hub-local builtin `addon-pages-aggregator` (see
|
|
17033
|
+
* `@camstack/system/builtins/addon-pages-aggregator`) registers the
|
|
17034
|
+
* provider. Splitting the public aggregator from the raw collection
|
|
17035
|
+
* keeps both ends in codegen — there's no hand-written
|
|
17036
|
+
* `addon-pages.router.ts` wrapper anymore.
|
|
17037
|
+
*/
|
|
17038
|
+
var AddonPageDeclarationSchema$1 = object({
|
|
17039
|
+
id: string(),
|
|
17040
|
+
label: string(),
|
|
17041
|
+
icon: string(),
|
|
17042
|
+
path: string(),
|
|
17043
|
+
remoteName: string(),
|
|
17044
|
+
bundle: string(),
|
|
17045
|
+
section: string().optional(),
|
|
17046
|
+
sectionLabel: string().optional()
|
|
17047
|
+
});
|
|
17048
|
+
var AddonPageInfoSchema = object({
|
|
17049
|
+
addonId: string(),
|
|
17050
|
+
page: AddonPageDeclarationSchema$1,
|
|
17051
|
+
bundleUrl: string()
|
|
17052
|
+
});
|
|
17053
|
+
method(_void(), array(AddonPageInfoSchema).readonly());
|
|
17054
|
+
var AddonHttpRouteSchema = object({
|
|
17055
|
+
method: _enum([
|
|
17056
|
+
"GET",
|
|
17057
|
+
"POST",
|
|
17058
|
+
"PUT",
|
|
17059
|
+
"DELETE",
|
|
17060
|
+
"PATCH"
|
|
17061
|
+
]),
|
|
17062
|
+
path: string(),
|
|
17063
|
+
access: _enum([
|
|
17064
|
+
"public",
|
|
17065
|
+
"authenticated",
|
|
17066
|
+
"admin"
|
|
17067
|
+
]).optional(),
|
|
17068
|
+
description: string().optional(),
|
|
17069
|
+
/** The hub limits this route per client address before the handler runs. */
|
|
17070
|
+
rateLimit: _enum(["auth"]).optional()
|
|
17071
|
+
});
|
|
17072
|
+
/**
|
|
17073
|
+
* Cross-process route invocation envelope. The hub captures the
|
|
16546
17074
|
* request as plain data, ships it to the worker via Moleculer, and
|
|
16547
17075
|
* the worker runs the local handler against a capturing reply. The
|
|
16548
17076
|
* envelope returned describes what the handler intended (status,
|
|
@@ -19065,7 +19593,11 @@ var CompositionProblemSchema = object({
|
|
|
19065
19593
|
"mixed-quantity",
|
|
19066
19594
|
"helper-mismatch",
|
|
19067
19595
|
"member-constraint",
|
|
19068
|
-
"retention"
|
|
19596
|
+
"retention",
|
|
19597
|
+
"command-method-unknown",
|
|
19598
|
+
"command-source-unknown",
|
|
19599
|
+
"command-input-unknown",
|
|
19600
|
+
"command-input-missing"
|
|
19069
19601
|
]),
|
|
19070
19602
|
path: string(),
|
|
19071
19603
|
message: string()
|
|
@@ -19104,7 +19636,9 @@ var CompositionFieldRoleSchema = _enum([
|
|
|
19104
19636
|
var CompositionFieldItemSchema = object({
|
|
19105
19637
|
arrayPath: string(),
|
|
19106
19638
|
key: string(),
|
|
19107
|
-
label: string()
|
|
19639
|
+
label: string(),
|
|
19640
|
+
/** True when the item carries a `reset` forward: the composer writes `resettable` from this (D967). */
|
|
19641
|
+
resettable: boolean().optional()
|
|
19108
19642
|
});
|
|
19109
19643
|
var CompositionFieldPlanSchema = object({
|
|
19110
19644
|
cap: string(),
|
|
@@ -19309,7 +19843,7 @@ Object.freeze({
|
|
|
19309
19843
|
* One catalog row per base reading a group helper can build (D944 §3).
|
|
19310
19844
|
* Data, not a form default written into the block.
|
|
19311
19845
|
*/
|
|
19312
|
-
var NOW$
|
|
19846
|
+
var NOW$3 = {
|
|
19313
19847
|
fieldPath: "lastFetchedAt",
|
|
19314
19848
|
expr: "now"
|
|
19315
19849
|
};
|
|
@@ -19361,7 +19895,7 @@ var GROUP_TEMPLATES = [
|
|
|
19361
19895
|
quantity: "temperature",
|
|
19362
19896
|
defaultAggregate: "mean",
|
|
19363
19897
|
empty: "null",
|
|
19364
|
-
companions: [NOW$
|
|
19898
|
+
companions: [NOW$3],
|
|
19365
19899
|
alsoFrom: {
|
|
19366
19900
|
deviceTypes: CLIMATE_DEVICES,
|
|
19367
19901
|
accept: {
|
|
@@ -19379,7 +19913,7 @@ var GROUP_TEMPLATES = [
|
|
|
19379
19913
|
quantity: "humidity",
|
|
19380
19914
|
defaultAggregate: "mean",
|
|
19381
19915
|
empty: "null",
|
|
19382
|
-
companions: [NOW$
|
|
19916
|
+
companions: [NOW$3],
|
|
19383
19917
|
alsoFrom: {
|
|
19384
19918
|
deviceTypes: CLIMATE_DEVICES,
|
|
19385
19919
|
accept: {
|
|
@@ -19397,7 +19931,7 @@ var GROUP_TEMPLATES = [
|
|
|
19397
19931
|
quantity: "pressure",
|
|
19398
19932
|
defaultAggregate: "mean",
|
|
19399
19933
|
empty: "null",
|
|
19400
|
-
companions: [NOW$
|
|
19934
|
+
companions: [NOW$3]
|
|
19401
19935
|
}),
|
|
19402
19936
|
numeric({
|
|
19403
19937
|
id: "illuminance",
|
|
@@ -19408,7 +19942,7 @@ var GROUP_TEMPLATES = [
|
|
|
19408
19942
|
quantity: "illuminance",
|
|
19409
19943
|
defaultAggregate: "mean",
|
|
19410
19944
|
empty: "null",
|
|
19411
|
-
companions: [NOW$
|
|
19945
|
+
companions: [NOW$3]
|
|
19412
19946
|
}),
|
|
19413
19947
|
numeric({
|
|
19414
19948
|
id: "power",
|
|
@@ -19419,7 +19953,7 @@ var GROUP_TEMPLATES = [
|
|
|
19419
19953
|
quantity: "power",
|
|
19420
19954
|
defaultAggregate: "sum",
|
|
19421
19955
|
empty: "omit",
|
|
19422
|
-
companions: [NOW$
|
|
19956
|
+
companions: [NOW$3]
|
|
19423
19957
|
}),
|
|
19424
19958
|
numeric({
|
|
19425
19959
|
id: "energy",
|
|
@@ -19430,7 +19964,7 @@ var GROUP_TEMPLATES = [
|
|
|
19430
19964
|
quantity: "energy",
|
|
19431
19965
|
defaultAggregate: "sum",
|
|
19432
19966
|
empty: "omit",
|
|
19433
|
-
companions: [NOW$
|
|
19967
|
+
companions: [NOW$3]
|
|
19434
19968
|
}),
|
|
19435
19969
|
numeric({
|
|
19436
19970
|
id: "battery",
|
|
@@ -19465,7 +19999,7 @@ var GROUP_TEMPLATES = [
|
|
|
19465
19999
|
quantity: "device",
|
|
19466
20000
|
defaultAggregate: "mean",
|
|
19467
20001
|
empty: "null",
|
|
19468
|
-
companions: [NOW$
|
|
20002
|
+
companions: [NOW$3]
|
|
19469
20003
|
}),
|
|
19470
20004
|
binary({
|
|
19471
20005
|
id: "motion",
|
|
@@ -21839,12 +22373,48 @@ var ExposeInputSchema = object({
|
|
|
21839
22373
|
capabilities: array(string()).optional()
|
|
21840
22374
|
});
|
|
21841
22375
|
var UnexposeInputSchema = object({ deviceId: string() });
|
|
22376
|
+
/**
|
|
22377
|
+
* What an exporter may expose besides devices (D968). An action and a
|
|
22378
|
+
* notification target are LIST ENTRIES, never devices (D954): they enter an
|
|
22379
|
+
* exporter's own selection, not the device registry.
|
|
22380
|
+
*/
|
|
22381
|
+
var ExportEntityKindSchema = _enum([
|
|
22382
|
+
"device",
|
|
22383
|
+
"action",
|
|
22384
|
+
"notifier"
|
|
22385
|
+
]);
|
|
22386
|
+
var ExportEntityRefSchema = discriminatedUnion("kind", [
|
|
22387
|
+
object({
|
|
22388
|
+
kind: literal("device"),
|
|
22389
|
+
deviceId: string()
|
|
22390
|
+
}),
|
|
22391
|
+
object({
|
|
22392
|
+
kind: literal("action"),
|
|
22393
|
+
actionId: string().min(1)
|
|
22394
|
+
}),
|
|
22395
|
+
object({
|
|
22396
|
+
kind: literal("notifier"),
|
|
22397
|
+
targetId: string().min(1)
|
|
22398
|
+
})
|
|
22399
|
+
]);
|
|
22400
|
+
var ExposedEntitySchema = object({
|
|
22401
|
+
entity: ExportEntityRefSchema,
|
|
22402
|
+
exposedAs: string().optional()
|
|
22403
|
+
});
|
|
22404
|
+
var ExposeEntityInputSchema = object({ entity: ExportEntityRefSchema });
|
|
22405
|
+
var UnexposeEntityInputSchema = object({ entity: ExportEntityRefSchema });
|
|
21842
22406
|
method(_void(), DeviceExportStatusSchema), method(_void(), array(DeviceKindSchema)), method(_void(), array(ExposedDeviceSchema)), method(ExposeInputSchema, _void(), {
|
|
21843
22407
|
kind: "mutation",
|
|
21844
22408
|
auth: "admin"
|
|
21845
22409
|
}), method(UnexposeInputSchema, _void(), {
|
|
21846
22410
|
kind: "mutation",
|
|
21847
22411
|
auth: "admin"
|
|
22412
|
+
}), optionalMethod(_void(), array(ExportEntityKindSchema)), optionalMethod(_void(), array(ExposedEntitySchema)), optionalMethod(ExposeEntityInputSchema, _void(), {
|
|
22413
|
+
kind: "mutation",
|
|
22414
|
+
auth: "admin"
|
|
22415
|
+
}), optionalMethod(UnexposeEntityInputSchema, _void(), {
|
|
22416
|
+
kind: "mutation",
|
|
22417
|
+
auth: "admin"
|
|
21848
22418
|
});
|
|
21849
22419
|
/** Lucide category ids, alphabetical. `ICON_META` indexes into this. */
|
|
21850
22420
|
var ICON_CATEGORY_IDS = [
|
|
@@ -42985,6 +43555,14 @@ method(object({
|
|
|
42985
43555
|
kind: "mutation",
|
|
42986
43556
|
auth: "admin"
|
|
42987
43557
|
});
|
|
43558
|
+
method(object({
|
|
43559
|
+
nodeId: string().min(1),
|
|
43560
|
+
/** Epoch ms the node was forgotten (the tombstone's `removedAt`). */
|
|
43561
|
+
removedAt: number()
|
|
43562
|
+
}), object({ counts: record(string(), number().int().nonnegative()) }), {
|
|
43563
|
+
kind: "mutation",
|
|
43564
|
+
auth: "admin"
|
|
43565
|
+
});
|
|
42988
43566
|
/**
|
|
42989
43567
|
* `device-removal-hook` — the reliable way an addon learns a device was DELETED,
|
|
42990
43568
|
* so it can delete what it keeps for that device (D865).
|
|
@@ -43705,7 +44283,7 @@ var LlmProviderWidgetSchema = object({
|
|
|
43705
44283
|
/** ConfigUISchema tree passed through untyped on the wire (the
|
|
43706
44284
|
* notification-output `ConfigSchemaPassthrough` precedent at
|
|
43707
44285
|
* notification-output.cap.ts:151); the exported TS type re-tightens it. */
|
|
43708
|
-
var ConfigSchemaPassthrough$
|
|
44286
|
+
var ConfigSchemaPassthrough$2 = unknown();
|
|
43709
44287
|
var LlmProfileKindDescriptorSchema = object({
|
|
43710
44288
|
kind: LlmProfileKindSchema,
|
|
43711
44289
|
label: string(),
|
|
@@ -43714,9 +44292,9 @@ var LlmProfileKindDescriptorSchema = object({
|
|
|
43714
44292
|
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
43715
44293
|
addonId: string(),
|
|
43716
44294
|
/** The provider's own fields (`providerConfig`); `password` fields are keychain-held. */
|
|
43717
|
-
connectionSchema: ConfigSchemaPassthrough$
|
|
44295
|
+
connectionSchema: ConfigSchemaPassthrough$2,
|
|
43718
44296
|
/** Provider fields that belong under "Advanced" (extra headers, runtime tuning). */
|
|
43719
|
-
advancedSchema: ConfigSchemaPassthrough$
|
|
44297
|
+
advancedSchema: ConfigSchemaPassthrough$2.optional(),
|
|
43720
44298
|
/** The kind's defaults; a model from `listModels` may override any of them. */
|
|
43721
44299
|
features: LlmModelFeaturesSchema,
|
|
43722
44300
|
/** `false` = the provider stamps `supportsVision` itself (from what a node reports). */
|
|
@@ -44242,10 +44820,10 @@ var CpuBreakdownSchema = object({
|
|
|
44242
44820
|
cores: number()
|
|
44243
44821
|
});
|
|
44244
44822
|
var MemoryInfoSchema = object({
|
|
44245
|
-
percent: number(),
|
|
44823
|
+
percent: number().nullable(),
|
|
44246
44824
|
totalBytes: number(),
|
|
44247
|
-
usedBytes: number(),
|
|
44248
|
-
availableBytes: number(),
|
|
44825
|
+
usedBytes: number().nullable(),
|
|
44826
|
+
availableBytes: number().nullable(),
|
|
44249
44827
|
swapUsedBytes: number(),
|
|
44250
44828
|
swapTotalBytes: number()
|
|
44251
44829
|
});
|
|
@@ -44522,697 +45100,277 @@ var NodeLoadSeriesSchema = object({
|
|
|
44522
45100
|
});
|
|
44523
45101
|
var GetLoadSeriesInputSchema = object({
|
|
44524
45102
|
/**
|
|
44525
|
-
* The node whose series is wanted.
|
|
44526
|
-
*
|
|
44527
|
-
* NOT named `nodeId`: the generated cap router strips a top-level
|
|
44528
|
-
* `nodeId` from every method input and uses it to ROUTE the call to
|
|
44529
|
-
* that node's provider (`generated-cap-routers.ts`). A series target
|
|
44530
|
-
* called `nodeId` would silently become a routing pin and never reach
|
|
44531
|
-
* the provider. The hub holds every node it hears from, so the
|
|
44532
|
-
* ordinary call is unpinned — answered by the hub, for any node.
|
|
44533
|
-
*/
|
|
44534
|
-
forNodeId: string(),
|
|
44535
|
-
/**
|
|
44536
|
-
* EXCLUSIVE lower bound. A caller passes the newest `atMs` it already
|
|
44537
|
-
* holds and receives only what it is missing, so seeding a live chart
|
|
44538
|
-
* from this method cannot double a point already drawn.
|
|
44539
|
-
*/
|
|
44540
|
-
sinceMs: number().optional(),
|
|
44541
|
-
/**
|
|
44542
|
-
* Most points the caller wants PER FUNCTION. The window is reduced to fit,
|
|
44543
|
-
* preserving min and max per bucket.
|
|
44544
|
-
*
|
|
44545
|
-
* Absent means NO reduction — legitimate for a short window and a trap for a
|
|
44546
|
-
* long one, which is why a chart passes its own pixel width.
|
|
44547
|
-
*/
|
|
44548
|
-
maxPoints: number().int().positive().optional()
|
|
44549
|
-
});
|
|
44550
|
-
var SystemMetricsSchema = object({
|
|
44551
|
-
cpuPercent: number(),
|
|
44552
|
-
memoryPercent: number(),
|
|
44553
|
-
memoryUsedMB: number(),
|
|
44554
|
-
memoryTotalMB: number(),
|
|
44555
|
-
diskPercent: number().optional(),
|
|
44556
|
-
temperature: number().optional(),
|
|
44557
|
-
gpuPercent: number().optional(),
|
|
44558
|
-
gpuMemoryPercent: number().optional()
|
|
44559
|
-
});
|
|
44560
|
-
method(_void(), SystemResourceSnapshotSchema), method(_void(), SystemResourceSnapshotSchema.nullable()), method(_void(), SystemMetricsSchema), method(object({ dirPath: string() }), DiskSpaceInfoSchema), method(_void(), MetricsGpuInfoSchema.nullable()), method(_void(), number().nullable()), method(object({ pids: array(number()) }), array(PidResourceStatsSchema)), method(_void(), array(AddonInstanceSchema).readonly()), method(object({ addonId: string() }), PidResourceStatsSchema.nullable()), method(_void(), array(NodeProcessSchema).readonly()), method(GetLoadSeriesInputSchema, NodeLoadSeriesSchema);
|
|
44561
|
-
var modelConvertCapability = {
|
|
44562
|
-
name: "model-convert",
|
|
44563
|
-
scope: "system",
|
|
44564
|
-
mode: "singleton",
|
|
44565
|
-
internal: true,
|
|
44566
|
-
methods: { convert: method(object({
|
|
44567
|
-
sourceUrl: string(),
|
|
44568
|
-
metadata: ModelConvertMetadataSchema,
|
|
44569
|
-
targets: array(ConvertTargetSchema).min(1).readonly(),
|
|
44570
|
-
calibrationRef: string().optional(),
|
|
44571
|
-
sessionId: string().optional()
|
|
44572
|
-
}), ConvertResultSchema, {
|
|
44573
|
-
kind: "mutation",
|
|
44574
|
-
auth: "admin",
|
|
44575
|
-
timeoutMs: 6e5
|
|
44576
|
-
}) }
|
|
44577
|
-
};
|
|
44578
|
-
method(object({
|
|
44579
|
-
targetNodeId: string(),
|
|
44580
|
-
modelId: string(),
|
|
44581
|
-
format: _enum(MODEL_FORMATS),
|
|
44582
|
-
entry: ModelCatalogEntrySchema
|
|
44583
|
-
}), object({
|
|
44584
|
-
ok: boolean(),
|
|
44585
|
-
/** sha256 of the staged tarball (empty for a hub-local no-op). */
|
|
44586
|
-
sha256: string(),
|
|
44587
|
-
bytes: number(),
|
|
44588
|
-
/** The target node's modelsDir the artifact landed in. */
|
|
44589
|
-
path: string()
|
|
44590
|
-
}), {
|
|
44591
|
-
kind: "mutation",
|
|
44592
|
-
auth: "admin"
|
|
44593
|
-
});
|
|
44594
|
-
var MotionRegionSchema = object({
|
|
44595
|
-
bbox: BoundingBoxSchema,
|
|
44596
|
-
pixelCount: number(),
|
|
44597
|
-
intensity: number()
|
|
44598
|
-
});
|
|
44599
|
-
var MotionAnalysisResultSchema = object({
|
|
44600
|
-
detected: boolean(),
|
|
44601
|
-
regionCount: number(),
|
|
44602
|
-
/** Regions passing minArea filter — used for pipeline triggering. */
|
|
44603
|
-
regions: array(MotionRegionSchema).readonly(),
|
|
44604
|
-
/** All raw regions from CCL before minArea filter — used for UI debug overlay. */
|
|
44605
|
-
rawRegions: array(MotionRegionSchema).readonly(),
|
|
44606
|
-
frameWidth: number(),
|
|
44607
|
-
frameHeight: number(),
|
|
44608
|
-
analysisMs: number()
|
|
44609
|
-
});
|
|
44610
|
-
DeviceType.Camera, method(object({
|
|
44611
|
-
deviceId: number(),
|
|
44612
|
-
frame: FrameInputSchema.optional(),
|
|
44613
|
-
frameHandle: FrameHandleSchema.optional()
|
|
44614
|
-
}), MotionAnalysisResultSchema, {
|
|
44615
|
-
role: "admin",
|
|
44616
|
-
kind: "mutation"
|
|
44617
|
-
}), method(object({ deviceId: number() }), _void(), {
|
|
44618
|
-
role: "admin",
|
|
44619
|
-
kind: "mutation"
|
|
44620
|
-
}), method(_void(), _void(), {
|
|
44621
|
-
role: "admin",
|
|
44622
|
-
kind: "mutation"
|
|
44623
|
-
}), object({
|
|
44624
|
-
deviceId: number(),
|
|
44625
|
-
detected: boolean(),
|
|
44626
|
-
regionCount: number()
|
|
44627
|
-
});
|
|
44628
|
-
/**
|
|
44629
|
-
* `mqtt-broker` — broker-registry cap.
|
|
44630
|
-
*
|
|
44631
|
-
* NOT a pub/sub proxy. The cap exposes (a) a registry of configured
|
|
44632
|
-
* MQTT brokers (external + optionally an embedded `aedes`-backed one)
|
|
44633
|
-
* and (b) the connection details a consumer addon needs to spin up
|
|
44634
|
-
* its OWN `mqtt.js` client.
|
|
44635
|
-
*
|
|
44636
|
-
* Why: pub/sub routing over the system event-bus loses fidelity
|
|
44637
|
-
* (callback shape, QoS guarantees, will/retain semantics) and adds
|
|
44638
|
-
* refcount bookkeeping that addons would rather own themselves. The
|
|
44639
|
-
* canonical consumer needs raw `mqtt.js`
|
|
44640
|
-
* features anyway — give it the connection config, get out of the way.
|
|
44641
|
-
*
|
|
44642
|
-
* Consumer flow:
|
|
44643
|
-
* const cfg = await ctx.api.mqttBroker.getBrokerConfig({ id })
|
|
44644
|
-
* const client = mqtt.connect(cfg.url, { username: cfg.username, … })
|
|
44645
|
-
* client.subscribe('zigbee2mqtt/+')
|
|
44646
|
-
*
|
|
44647
|
-
* Collection mode: multiple brokers (e.g. one local mosquitto + one
|
|
44648
|
-
* cloud bridge). The "embedded" entry (when present) is just another
|
|
44649
|
-
* broker in the registry — its lifecycle is owned by the addon that
|
|
44650
|
-
* spawned it.
|
|
44651
|
-
*/
|
|
44652
|
-
var BrokerKindSchema = _enum(["external", "embedded"]);
|
|
44653
|
-
/**
|
|
44654
|
-
* Broker live-probe status.
|
|
44655
|
-
*
|
|
44656
|
-
* - `connected` — last probe completed a clean CONNACK
|
|
44657
|
-
* - `disconnected` — no probe has run yet (cold cache)
|
|
44658
|
-
* - `auth-failed` — CONNACK refused with auth error (RC 4 / 5)
|
|
44659
|
-
* - `unreachable` — TCP connect timed out / refused
|
|
44660
|
-
* - `tls-error` — TLS handshake failed (cert / SNI / cipher)
|
|
44661
|
-
*/
|
|
44662
|
-
var BrokerStatusSchema$1 = _enum([
|
|
44663
|
-
"connected",
|
|
44664
|
-
"disconnected",
|
|
44665
|
-
"auth-failed",
|
|
44666
|
-
"unreachable",
|
|
44667
|
-
"tls-error"
|
|
44668
|
-
]);
|
|
44669
|
-
var BrokerInfoSchema$1 = object({
|
|
44670
|
-
id: string(),
|
|
44671
|
-
name: string(),
|
|
44672
|
-
url: string(),
|
|
44673
|
-
kind: BrokerKindSchema,
|
|
44674
|
-
status: BrokerStatusSchema$1,
|
|
44675
|
-
latencyMs: number().nullable(),
|
|
44676
|
-
error: string().optional(),
|
|
44677
|
-
/** Embedded brokers only: number of MQTT clients currently connected. */
|
|
44678
|
-
connectedClients: number().int().nonnegative().optional(),
|
|
44679
|
-
/** Epoch ms of the last live probe (external) or aedes snapshot (embedded). */
|
|
44680
|
-
lastCheckedAt: number().optional()
|
|
44681
|
-
});
|
|
44682
|
-
/**
|
|
44683
|
-
* Connection details — what a consumer needs to call
|
|
44684
|
-
* `mqtt.connect(url, options)`. We split URL + credentials so the
|
|
44685
|
-
* consumer can pass them as `mqtt.connect(url, { username, password })`
|
|
44686
|
-
* instead of stuffing creds into the URL (which leaks them into logs).
|
|
44687
|
-
*/
|
|
44688
|
-
var BrokerConnectionDetailsSchema = object({
|
|
44689
|
-
url: string(),
|
|
44690
|
-
username: string().optional(),
|
|
44691
|
-
password: string().optional(),
|
|
44692
|
-
/**
|
|
44693
|
-
* Suggested prefix for `clientId`. Each consumer should suffix this
|
|
44694
|
-
* with its own discriminator (addon id, instance id) so reconnects
|
|
44695
|
-
* don't kick each other off (MQTT spec: clientId must be unique per
|
|
44696
|
-
* broker).
|
|
44697
|
-
*/
|
|
44698
|
-
clientIdPrefix: string().optional()
|
|
44699
|
-
});
|
|
44700
|
-
var AddBrokerInputSchema = object({
|
|
44701
|
-
name: string().min(1),
|
|
44702
|
-
url: string().regex(/^(mqtt|mqtts|ws|wss):\/\//, "URL must start with mqtt(s):// or ws(s)://"),
|
|
44703
|
-
username: string().optional(),
|
|
44704
|
-
password: string().optional(),
|
|
44705
|
-
clientIdPrefix: string().optional()
|
|
44706
|
-
});
|
|
44707
|
-
var AddBrokerResultSchema = object({ id: string() });
|
|
44708
|
-
var IdInputSchema = object({ id: string() });
|
|
44709
|
-
var TestResultSchema$1 = discriminatedUnion("ok", [object({
|
|
44710
|
-
ok: literal(true),
|
|
44711
|
-
latencyMs: number()
|
|
44712
|
-
}), object({
|
|
44713
|
-
ok: literal(false),
|
|
44714
|
-
error: string()
|
|
44715
|
-
})]);
|
|
44716
|
-
var StartEmbeddedInputSchema = object({
|
|
44717
|
-
port: number().int().min(1).max(65535).default(1883),
|
|
44718
|
-
/** Allow anonymous connect (no username/password). Default: false. */
|
|
44719
|
-
allowAnonymous: boolean().default(false),
|
|
44720
|
-
/** Optional shared username/password for clients. */
|
|
44721
|
-
username: string().optional(),
|
|
44722
|
-
password: string().optional()
|
|
44723
|
-
});
|
|
44724
|
-
var StartEmbeddedResultSchema = object({
|
|
44725
|
-
id: string(),
|
|
44726
|
-
url: string()
|
|
44727
|
-
});
|
|
44728
|
-
var StatusSchema = object({
|
|
44729
|
-
brokerCount: number(),
|
|
44730
|
-
embeddedRunning: boolean()
|
|
44731
|
-
});
|
|
44732
|
-
method(_void(), array(BrokerInfoSchema$1)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
|
|
44733
|
-
kind: "mutation",
|
|
44734
|
-
auth: "admin"
|
|
44735
|
-
}), method(IdInputSchema, _void(), {
|
|
44736
|
-
kind: "mutation",
|
|
44737
|
-
auth: "admin"
|
|
44738
|
-
}), method(IdInputSchema, TestResultSchema$1, {
|
|
44739
|
-
kind: "mutation",
|
|
44740
|
-
auth: "admin"
|
|
44741
|
-
}), method(StartEmbeddedInputSchema, StartEmbeddedResultSchema, {
|
|
44742
|
-
kind: "mutation",
|
|
44743
|
-
auth: "admin"
|
|
44744
|
-
}), method(IdInputSchema, _void(), {
|
|
44745
|
-
kind: "mutation",
|
|
44746
|
-
auth: "admin"
|
|
44747
|
-
}), method(_void(), StatusSchema);
|
|
44748
|
-
var NetworkEndpointSchema = object({
|
|
44749
|
-
url: string(),
|
|
44750
|
-
hostname: string(),
|
|
44751
|
-
port: number(),
|
|
44752
|
-
protocol: _enum(["http", "https"]),
|
|
44753
|
-
/**
|
|
44754
|
-
* Whether this address survives a restart of its provider. `false` = it is
|
|
44755
|
-
* re-issued every time (a Quick tunnel's random `*.trycloudflare.com`); the
|
|
44756
|
-
* hub never selects such an address AUTOMATICALLY for a role (D860), though
|
|
44757
|
-
* it stays visible and an operator may still flag it. Absent = stable: every
|
|
44758
|
-
* provider except a Quick tunnel owns a name that does not change.
|
|
44759
|
-
*/
|
|
44760
|
-
stable: boolean().optional()
|
|
44761
|
-
});
|
|
44762
|
-
object({
|
|
44763
|
-
url: string(),
|
|
44764
|
-
/** Mirrors {@link NetworkEndpointSchema} `stable`; absent = stable. */
|
|
44765
|
-
stable: boolean().optional(),
|
|
44766
|
-
updated: boolean().optional()
|
|
44767
|
-
});
|
|
44768
|
-
var NetworkAccessStatusSchema = object({
|
|
44769
|
-
connected: boolean(),
|
|
44770
|
-
endpoint: NetworkEndpointSchema.nullable(),
|
|
44771
|
-
error: string().optional()
|
|
44772
|
-
});
|
|
44773
|
-
/**
|
|
44774
|
-
* Optional, richer endpoint shape returned by providers that expose
|
|
44775
|
-
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
44776
|
-
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
44777
|
-
* the originating provider config (mode + sourcePort) so the
|
|
44778
|
-
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
44779
|
-
* one endpoint just omit `listEndpoints` from their provider impl.
|
|
44780
|
-
*/
|
|
44781
|
-
var NetworkEndpointEntrySchema = NetworkEndpointSchema.extend({
|
|
44782
|
-
/**
|
|
44783
|
-
* Stable id within the provider — typically `<mode>-<sourcePort>` so
|
|
44784
|
-
* the orchestrator can dedupe across `listEndpoints` polls.
|
|
44785
|
-
*/
|
|
44786
|
-
id: string(),
|
|
44787
|
-
/** Operator-facing label (mirrors `MeshEndpoint.label`). */
|
|
44788
|
-
label: string(),
|
|
44789
|
-
/** Optional provider-specific mode tag, used for icon/colour in admin UI. */
|
|
44790
|
-
mode: string().optional(),
|
|
44791
|
-
/** Originating local port the ingress fronts (informational). */
|
|
44792
|
-
sourcePort: number().optional()
|
|
44793
|
-
});
|
|
44794
|
-
method(_void(), NetworkEndpointSchema, { kind: "mutation" }), method(_void(), _void(), { kind: "mutation" }), method(_void(), NetworkEndpointSchema.nullable()), method(_void(), NetworkAccessStatusSchema), method(_void(), array(NetworkEndpointEntrySchema).readonly());
|
|
44795
|
-
/**
|
|
44796
|
-
* notification-output — canonical, capability-gated notification delivery.
|
|
44797
|
-
*
|
|
44798
|
-
* Apprise-derived model (see
|
|
44799
|
-
* `docs/superpowers/specs/2026-07-03-notification-output-notifier-matrix.md`):
|
|
44800
|
-
* callers emit ONE canonical `Notification`; each provider declares a
|
|
44801
|
-
* per-kind capability descriptor (`TargetKind`), and the pure degrade
|
|
44802
|
-
* engine (`@camstack/types` `prepareNotification`) transcodes / degrades the
|
|
44803
|
-
* message to what the kind supports — callers never special-case a service.
|
|
44804
|
-
*
|
|
44805
|
-
* DESIGN DECISIONS (locked):
|
|
44806
|
-
* - Target CRUD lives on THIS cap (`upsertTarget` / `deleteTarget` /
|
|
44807
|
-
* `setTargetEnabled`), each provider persisting via the `settings-store`
|
|
44808
|
-
* cap. Rationale: the admin UI needs one uniform surface across the
|
|
44809
|
-
* notifiers addon AND the HA addon; the addon-`globalSettingsSchema`-array
|
|
44810
|
-
* alternative would fork the UI per addon and cannot host the
|
|
44811
|
-
* discovery→adopt flow.
|
|
44812
|
-
* - `listTargetKinds` / `listTargets` / `discoverTargets` return arrays →
|
|
44813
|
-
* the generated cap-mount auto-`concatCollection`-fans them across every
|
|
44814
|
-
* registered provider (notifiers addon + HA addon) so one catalog is
|
|
44815
|
-
* routable. `send` / `testTarget` / CRUD route to ONE provider by the
|
|
44816
|
-
* `addonId` the generated collection router extracts from the call input.
|
|
44817
|
-
* - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
|
|
44818
|
-
* transformer) + UDS MsgPack both round-trip typed arrays — already used by
|
|
44819
|
-
* `storage` / `storage-provider` / `recording` caps over the same path. No
|
|
44820
|
-
* base64 fallback needed.
|
|
44821
|
-
*
|
|
44822
|
-
* TODO (deferred, closed-set change — separate decision): add
|
|
44823
|
-
* `providerKind: 'notify'` so notification providers surface on the unified
|
|
44824
|
-
* admin "Integrations" page.
|
|
44825
|
-
*/
|
|
44826
|
-
/**
|
|
44827
|
-
* Zentik-derived typed-media enum — the superset across every kind. Each
|
|
44828
|
-
* adapter picks what it supports and the degrade engine filters the rest.
|
|
44829
|
-
*/
|
|
44830
|
-
var AttachmentMediaTypeSchema = _enum([
|
|
44831
|
-
"image",
|
|
44832
|
-
"video",
|
|
44833
|
-
"gif",
|
|
44834
|
-
"audio",
|
|
44835
|
-
"icon"
|
|
44836
|
-
]);
|
|
44837
|
-
/**
|
|
44838
|
-
* A single attachment. Exactly one of `url` (remote source, most adapters
|
|
44839
|
-
* prefer this) or `bytes` (inline source; required for Pushover-style
|
|
44840
|
-
* bytes-only kinds) MUST be present — the degrade engine expresses a
|
|
44841
|
-
* url→bytes fetch as a `needsFetch` directive the adapter executes.
|
|
44842
|
-
*/
|
|
44843
|
-
var AttachmentSchema = object({
|
|
44844
|
-
mediaType: AttachmentMediaTypeSchema,
|
|
44845
|
-
url: string().optional(),
|
|
44846
|
-
bytes: _instanceof(Uint8Array).optional(),
|
|
44847
|
-
mime: string().optional(),
|
|
44848
|
-
name: string().optional()
|
|
44849
|
-
}).refine((a) => a.url !== void 0 || a.bytes !== void 0, { message: "Attachment requires either `url` or `bytes`" });
|
|
44850
|
-
var NotificationFormatSchema = _enum([
|
|
44851
|
-
"text",
|
|
44852
|
-
"markdown",
|
|
44853
|
-
"html"
|
|
44854
|
-
]);
|
|
44855
|
-
/**
|
|
44856
|
-
* The CLOSED icon vocabulary an action button may use.
|
|
44857
|
-
*
|
|
44858
|
-
* A closed set, not a free string, and that is the whole point: an arbitrary
|
|
44859
|
-
* icon name is one that ntfy renders, zentik silently drops, and nobody
|
|
44860
|
-
* notices — the same class of gap as a zone vocabulary nothing produced
|
|
44861
|
-
* ([D35](../../../docs/decisions/adr-0035.md)). Every adapter maps this set or
|
|
44862
|
-
* declares `actionIcons: false` and the degrade engine strips the field.
|
|
44863
|
-
*
|
|
44864
|
-
* Named by INTENT, never by glyph. "check" would tie the vocabulary to one
|
|
44865
|
-
* renderer's icon set; "acknowledge" survives an adapter that draws it
|
|
44866
|
-
* differently.
|
|
44867
|
-
*
|
|
44868
|
-
* ── A TOKEN IS NOT A WIRE VALUE ─────────────────────────────────────
|
|
44869
|
-
*
|
|
44870
|
-
* These names are for US. **No adapter may forward one verbatim.** Each maps
|
|
44871
|
-
* the whole set onto its own renderer's vocabulary through a
|
|
44872
|
-
* `Record<NotificationActionIcon, string>` — a Record, never a lookup with a
|
|
44873
|
-
* fallback, so adding a member here fails every adapter's build until someone
|
|
44874
|
-
* decides its glyph, which is the only place that decision can be made
|
|
44875
|
-
* honestly.
|
|
44876
|
-
*
|
|
44877
|
-
* This paragraph is the bug. Zentik declared `actionIcons: true` and passed
|
|
44878
|
-
* `disarm` straight through; iOS feeds that string to
|
|
44879
|
-
* `UNNotificationActionIcon(systemImageName:)`, `disarm` is not an SF Symbol,
|
|
44880
|
-
* and every snooze and alarm button arrived BLANK. A pass-through is not a
|
|
44881
|
-
* mapping, and "the field is documented" is not "the value renders".
|
|
44882
|
-
*
|
|
44883
|
-
* Adding a member is TRAIN-BOUND. The enum lives in the published
|
|
44884
|
-
* `@camstack/server` closure and the cap seam validates against the HUB's copy,
|
|
44885
|
-
* so an addon that emits a token the running hub does not know does not lose an
|
|
44886
|
-
* icon — its whole `send` fails Zod validation and the notification never
|
|
44887
|
-
* arrives. Never emit a new token from an addon before the train carrying it.
|
|
44888
|
-
*/
|
|
44889
|
-
var NotificationActionIconSchema = _enum([
|
|
44890
|
-
"acknowledge",
|
|
44891
|
-
"dismiss",
|
|
44892
|
-
"silence",
|
|
44893
|
-
"snooze",
|
|
44894
|
-
"view",
|
|
44895
|
-
"play",
|
|
44896
|
-
"open",
|
|
44897
|
-
"close",
|
|
44898
|
-
"lock",
|
|
44899
|
-
"unlock",
|
|
44900
|
-
"arm",
|
|
44901
|
-
"arm-home",
|
|
44902
|
-
"arm-away",
|
|
44903
|
-
"arm-night",
|
|
44904
|
-
"disarm",
|
|
44905
|
-
"light",
|
|
44906
|
-
"alert",
|
|
44907
|
-
"camera"
|
|
44908
|
-
]);
|
|
44909
|
-
/** A single tap-through action button. */
|
|
44910
|
-
var NotificationActionSchema = object({
|
|
44911
|
-
id: string(),
|
|
44912
|
-
label: string(),
|
|
44913
|
-
url: string().optional(),
|
|
44914
|
-
/** Dropped by the degrade engine for a kind with `caps.actionIcons: false`. */
|
|
44915
|
-
icon: NotificationActionIconSchema.optional(),
|
|
44916
|
-
/**
|
|
44917
|
-
* Renders in a warning style where the notifier supports it.
|
|
44918
|
-
*
|
|
44919
|
-
* A HINT, never a gate. The callback's authority is its token and nothing
|
|
44920
|
-
* else — see `notification-center/action-token.ts` for what that does and
|
|
44921
|
-
* does not buy.
|
|
44922
|
-
*/
|
|
44923
|
-
destructive: boolean().optional(),
|
|
44924
|
-
/**
|
|
44925
|
-
* How the tap should REACH the url.
|
|
44926
|
-
*
|
|
44927
|
-
* `navigate` (absent, and every button authored before this field) opens it:
|
|
44928
|
-
* the phone leaves the notification and shows whatever the callback returns.
|
|
44929
|
-
* That is right for a button whose answer the operator wants to read.
|
|
44930
|
-
*
|
|
44931
|
-
* `background` fires it as a POST and stays put. It exists for the buttons
|
|
44932
|
-
* whose whole point is not to interrupt — "silence this for 30 minutes" is
|
|
44933
|
-
* an answer to the notification, and being thrown into a browser tab to
|
|
44934
|
-
* confirm it costs more attention than the notification did. A backend that
|
|
44935
|
-
* cannot do a background call renders it as an ordinary link (the adapters
|
|
44936
|
-
* fall back rather than dropping the button), so this is a preference, never
|
|
44937
|
-
* a requirement.
|
|
44938
|
-
*/
|
|
44939
|
-
mode: _enum(["navigate", "background"]).optional()
|
|
44940
|
-
});
|
|
44941
|
-
/** A delivery parameter value: what a notifier declared it takes. */
|
|
44942
|
-
var DeliveryParamValueSchema = union([
|
|
44943
|
-
string(),
|
|
44944
|
-
number(),
|
|
44945
|
-
boolean()
|
|
44946
|
-
]);
|
|
44947
|
-
/**
|
|
44948
|
-
* One extra delivery parameter a notifier KIND declares (D938). A rule that
|
|
44949
|
-
* addresses a target of that kind may set it; a kind that declares nothing is
|
|
44950
|
-
* never handed one. The admin UI derives its control from this descriptor —
|
|
44951
|
-
* no editor knows a service by name.
|
|
44952
|
-
*
|
|
44953
|
-
* Optional fields are `.optional()`, never `.default()` (a Zod default does not
|
|
44954
|
-
* run on the addon cap path).
|
|
44955
|
-
*/
|
|
44956
|
-
var DeliveryParamSchema = object({
|
|
44957
|
-
key: string().min(1),
|
|
44958
|
-
label: string(),
|
|
44959
|
-
/** i18n key of the label, resolved by the declaring addon's namespace. */
|
|
44960
|
-
labelKey: string().optional(),
|
|
44961
|
-
type: _enum([
|
|
44962
|
-
"enum",
|
|
44963
|
-
"number",
|
|
44964
|
-
"boolean",
|
|
44965
|
-
"string"
|
|
44966
|
-
]),
|
|
44967
|
-
/** `enum` only: the closed set of accepted values. */
|
|
44968
|
-
options: array(object({
|
|
44969
|
-
value: string(),
|
|
44970
|
-
label: string()
|
|
44971
|
-
})).optional(),
|
|
44972
|
-
/** `number` only. */
|
|
44973
|
-
min: number().optional(),
|
|
44974
|
-
max: number().optional(),
|
|
44975
|
-
/** What the notifier does when the rule sets nothing; shown as the placeholder. */
|
|
44976
|
-
default: DeliveryParamValueSchema.optional()
|
|
44977
|
-
});
|
|
44978
|
-
/**
|
|
44979
|
-
* The canonical notification. `body` is the only hard field (Apprise model).
|
|
44980
|
-
* `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
|
|
44981
|
-
* NOT a fixed severity enum — each kind declares its own `caps.levels` and
|
|
44982
|
-
* the adapter maps this ordinal onto its native level. `level?` is an
|
|
44983
|
-
* optional kind-native level id (`emergency`, `silent`, …) that overrides
|
|
44984
|
-
* `priority` for that one target.
|
|
44985
|
-
*/
|
|
44986
|
-
var NotificationSchema = object({
|
|
44987
|
-
body: string(),
|
|
44988
|
-
title: string().optional(),
|
|
44989
|
-
format: NotificationFormatSchema.default("text"),
|
|
44990
|
-
priority: number().int().min(1).max(5).default(3),
|
|
44991
|
-
level: string().optional(),
|
|
44992
|
-
attachments: array(AttachmentSchema).optional(),
|
|
44993
|
-
clickUrl: string().optional(),
|
|
44994
|
-
actions: array(NotificationActionSchema).optional(),
|
|
44995
|
-
sound: string().optional(),
|
|
44996
|
-
ttl: number().optional(),
|
|
44997
|
-
tag: string().optional(),
|
|
44998
|
-
deviceId: number().optional(),
|
|
44999
|
-
eventId: string().optional(),
|
|
45000
|
-
metadata: record(string(), unknown()).optional(),
|
|
45001
|
-
/**
|
|
45002
|
-
* Values for the parameters the target's kind DECLARES in
|
|
45003
|
-
* {@link TargetKindSchema} `deliveryParams`. Already validated against the
|
|
45004
|
-
* declaration by the sender; a notifier reads only the keys it declared.
|
|
45005
|
-
*/
|
|
45006
|
-
delivery: record(string(), DeliveryParamValueSchema).optional()
|
|
45007
|
-
});
|
|
45008
|
-
/** One declared native severity/priority level for a kind. */
|
|
45009
|
-
var TargetKindLevelSchema = object({
|
|
45010
|
-
id: string(),
|
|
45011
|
-
label: string(),
|
|
45012
|
-
/** Which canonical priority (1..5) this level maps to. `null` = qualitative-only. */
|
|
45013
|
-
ordinal: number().int().min(1).max(5).nullable(),
|
|
45014
|
-
flags: object({
|
|
45015
|
-
critical: boolean().optional(),
|
|
45016
|
-
silent: boolean().optional(),
|
|
45017
|
-
noPush: boolean().optional()
|
|
45018
|
-
}).optional(),
|
|
45019
|
-
/** e.g. Pushover `emergency` requires `retry` / `expire`. */
|
|
45020
|
-
requires: array(string()).optional(),
|
|
45021
|
-
description: string().optional()
|
|
45022
|
-
});
|
|
45023
|
-
/** The full capability block consulted before dispatch. */
|
|
45024
|
-
var TargetKindCapsSchema = object({
|
|
45025
|
-
attachments: object({
|
|
45026
|
-
mediaTypes: array(AttachmentMediaTypeSchema),
|
|
45027
|
-
mode: _enum([
|
|
45028
|
-
"url",
|
|
45029
|
-
"bytes",
|
|
45030
|
-
"both"
|
|
45031
|
-
]),
|
|
45032
|
-
max: number().int().nonnegative(),
|
|
45033
|
-
maxBytes: number().int().positive().optional()
|
|
45034
|
-
}),
|
|
45035
|
-
/** Max action buttons (0 = none). */
|
|
45036
|
-
actions: number().int().nonnegative(),
|
|
45037
|
-
/**
|
|
45038
|
-
* Whether this kind renders a per-action ICON.
|
|
45039
|
-
*
|
|
45040
|
-
* `.optional()`, deliberately NOT `.default(false)`: a Zod default does not
|
|
45041
|
-
* run on the addon cap path — three production failures in one day taught
|
|
45042
|
-
* this repo that once. Absent is read as false by the degrade engine, which
|
|
45043
|
-
* is the safe direction: an icon that is not rendered costs nothing, an icon
|
|
45044
|
-
* assumed and dropped costs the operator's trust in the field.
|
|
45045
|
-
*/
|
|
45046
|
-
actionIcons: boolean().optional(),
|
|
45047
|
-
levels: array(TargetKindLevelSchema),
|
|
45048
|
-
format: array(NotificationFormatSchema),
|
|
45049
|
-
clickUrl: boolean(),
|
|
45050
|
-
sound: boolean(),
|
|
45051
|
-
ttl: boolean(),
|
|
45052
|
-
bodyMaxLen: number().int().positive()
|
|
45053
|
-
});
|
|
45054
|
-
/**
|
|
45055
|
-
* `configSchema` is a `ConfigUISchema` tree passed through to the admin
|
|
45056
|
-
* FormBuilder. Stored as `z.unknown()` at the cap seam (mirrors
|
|
45057
|
-
* `device-provider.getChildCreationSchema` `CreationSchemaOutputSchema`) —
|
|
45058
|
-
* the union is large and not meant for runtime validation here; the exported
|
|
45059
|
-
* `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
|
|
45060
|
-
*/
|
|
45061
|
-
var ConfigSchemaPassthrough$2 = unknown();
|
|
45062
|
-
var TargetKindSchema = object({
|
|
45063
|
-
kind: string(),
|
|
45064
|
-
label: string(),
|
|
45065
|
-
icon: string(),
|
|
45066
|
-
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
45067
|
-
addonId: string(),
|
|
45068
|
-
/**
|
|
45069
|
-
* URL of the kind's bundled BRAND icon, served by the providing addon over
|
|
45070
|
-
* its own `addon-routes` surface (`/addon/<addonId>/icons/<kind>`). Absent
|
|
45071
|
-
* when the addon bundles no icon for that kind — the client then falls back
|
|
45072
|
-
* to a neutral glyph rather than rendering the raw `icon` NAME as text.
|
|
45073
|
-
*
|
|
45074
|
-
* Root-relative on purpose: it resolves against whatever origin serves a web
|
|
45075
|
-
* client, and a native client joins it onto its own hub base.
|
|
45076
|
-
*
|
|
45077
|
-
* DECLARED here deliberately. It used to travel as an undeclared passthrough
|
|
45078
|
-
* field that survived only because the runtime cap-router forwards provider
|
|
45079
|
-
* output verbatim — so every consumer had to re-declare it by hand to stop
|
|
45080
|
-
* its own Zod parse from stripping it, and the whole arrangement would have
|
|
45081
|
-
* broken silently the moment output validation was tightened anywhere.
|
|
45082
|
-
*/
|
|
45083
|
-
iconUrl: string().optional(),
|
|
45084
|
-
/**
|
|
45085
|
-
* Media type of {@link iconUrl} (`image/svg+xml`, `image/png`, …).
|
|
45086
|
-
*
|
|
45087
|
-
* The server knows this and therefore says it, because the client cannot
|
|
45088
|
-
* safely guess: a React-Native client renders SVG and raster through two
|
|
45089
|
-
* DIFFERENT components (`react-native-svg` vs `expo-image` — expo-image does
|
|
45090
|
-
* not decode SVG on iOS/Android), so without this it silently fell back to a
|
|
45091
|
-
* placeholder glyph for every vector icon while the web build looked fine.
|
|
45092
|
-
*
|
|
45093
|
-
* Absent when {@link iconUrl} is absent, or for a legacy provider that has
|
|
45094
|
-
* not been updated — a client that cannot determine the type should prefer
|
|
45095
|
-
* its raster path, which is the safe default for an unknown image.
|
|
45096
|
-
*/
|
|
45097
|
-
iconMediaType: string().optional(),
|
|
45098
|
-
configSchema: ConfigSchemaPassthrough$2,
|
|
45099
|
-
/**
|
|
45100
|
-
* The config keys that decide WHERE this kind's secrets are sent (server,
|
|
45101
|
-
* base URL, instance, chat, recipient). A save that changes any of them
|
|
45102
|
-
* while leaving a secret redacted is refused by the provider (D634), so an
|
|
45103
|
-
* editor uses this to ask for the secret on exactly those edits instead of
|
|
45104
|
-
* on every edit.
|
|
45103
|
+
* The node whose series is wanted.
|
|
45105
45104
|
*
|
|
45106
|
-
*
|
|
45107
|
-
*
|
|
45108
|
-
*
|
|
45105
|
+
* NOT named `nodeId`: the generated cap router strips a top-level
|
|
45106
|
+
* `nodeId` from every method input and uses it to ROUTE the call to
|
|
45107
|
+
* that node's provider (`generated-cap-routers.ts`). A series target
|
|
45108
|
+
* called `nodeId` would silently become a routing pin and never reach
|
|
45109
|
+
* the provider. The hub holds every node it hears from, so the
|
|
45110
|
+
* ordinary call is unpinned — answered by the hub, for any node.
|
|
45109
45111
|
*/
|
|
45110
|
-
|
|
45111
|
-
supportsDiscovery: boolean(),
|
|
45112
|
+
forNodeId: string(),
|
|
45112
45113
|
/**
|
|
45113
|
-
*
|
|
45114
|
-
*
|
|
45114
|
+
* EXCLUSIVE lower bound. A caller passes the newest `atMs` it already
|
|
45115
|
+
* holds and receives only what it is missing, so seeding a live chart
|
|
45116
|
+
* from this method cannot double a point already drawn.
|
|
45115
45117
|
*/
|
|
45116
|
-
|
|
45117
|
-
|
|
45118
|
+
sinceMs: number().optional(),
|
|
45119
|
+
/**
|
|
45120
|
+
* Most points the caller wants PER FUNCTION. The window is reduced to fit,
|
|
45121
|
+
* preserving min and max per bucket.
|
|
45122
|
+
*
|
|
45123
|
+
* Absent means NO reduction — legitimate for a short window and a trap for a
|
|
45124
|
+
* long one, which is why a chart passes its own pixel width.
|
|
45125
|
+
*/
|
|
45126
|
+
maxPoints: number().int().positive().optional()
|
|
45127
|
+
});
|
|
45128
|
+
var SystemMetricsSchema = object({
|
|
45129
|
+
cpuPercent: number(),
|
|
45130
|
+
/** `null` when the memory sample failed or was not taken yet (D393). */
|
|
45131
|
+
memoryPercent: number().nullable(),
|
|
45132
|
+
memoryUsedMB: number().nullable(),
|
|
45133
|
+
memoryTotalMB: number(),
|
|
45134
|
+
diskPercent: number().optional(),
|
|
45135
|
+
temperature: number().optional(),
|
|
45136
|
+
gpuPercent: number().optional(),
|
|
45137
|
+
gpuMemoryPercent: number().optional()
|
|
45138
|
+
});
|
|
45139
|
+
method(_void(), SystemResourceSnapshotSchema), method(_void(), SystemResourceSnapshotSchema.nullable()), method(_void(), SystemMetricsSchema), method(object({ dirPath: string() }), DiskSpaceInfoSchema), method(_void(), MetricsGpuInfoSchema.nullable()), method(_void(), number().nullable()), method(object({ pids: array(number()) }), array(PidResourceStatsSchema)), method(_void(), array(AddonInstanceSchema).readonly()), method(object({ addonId: string() }), PidResourceStatsSchema.nullable()), method(_void(), array(NodeProcessSchema).readonly()), method(GetLoadSeriesInputSchema, NodeLoadSeriesSchema);
|
|
45140
|
+
var modelConvertCapability = {
|
|
45141
|
+
name: "model-convert",
|
|
45142
|
+
scope: "system",
|
|
45143
|
+
mode: "singleton",
|
|
45144
|
+
internal: true,
|
|
45145
|
+
methods: { convert: method(object({
|
|
45146
|
+
sourceUrl: string(),
|
|
45147
|
+
metadata: ModelConvertMetadataSchema,
|
|
45148
|
+
targets: array(ConvertTargetSchema).min(1).readonly(),
|
|
45149
|
+
calibrationRef: string().optional(),
|
|
45150
|
+
sessionId: string().optional()
|
|
45151
|
+
}), ConvertResultSchema, {
|
|
45152
|
+
kind: "mutation",
|
|
45153
|
+
auth: "admin",
|
|
45154
|
+
timeoutMs: 6e5
|
|
45155
|
+
}) }
|
|
45156
|
+
};
|
|
45157
|
+
method(object({
|
|
45158
|
+
targetNodeId: string(),
|
|
45159
|
+
modelId: string(),
|
|
45160
|
+
format: _enum(MODEL_FORMATS),
|
|
45161
|
+
entry: ModelCatalogEntrySchema
|
|
45162
|
+
}), object({
|
|
45163
|
+
ok: boolean(),
|
|
45164
|
+
/** sha256 of the staged tarball (empty for a hub-local no-op). */
|
|
45165
|
+
sha256: string(),
|
|
45166
|
+
bytes: number(),
|
|
45167
|
+
/** The target node's modelsDir the artifact landed in. */
|
|
45168
|
+
path: string()
|
|
45169
|
+
}), {
|
|
45170
|
+
kind: "mutation",
|
|
45171
|
+
auth: "admin"
|
|
45172
|
+
});
|
|
45173
|
+
var MotionRegionSchema = object({
|
|
45174
|
+
bbox: BoundingBoxSchema,
|
|
45175
|
+
pixelCount: number(),
|
|
45176
|
+
intensity: number()
|
|
45177
|
+
});
|
|
45178
|
+
var MotionAnalysisResultSchema = object({
|
|
45179
|
+
detected: boolean(),
|
|
45180
|
+
regionCount: number(),
|
|
45181
|
+
/** Regions passing minArea filter — used for pipeline triggering. */
|
|
45182
|
+
regions: array(MotionRegionSchema).readonly(),
|
|
45183
|
+
/** All raw regions from CCL before minArea filter — used for UI debug overlay. */
|
|
45184
|
+
rawRegions: array(MotionRegionSchema).readonly(),
|
|
45185
|
+
frameWidth: number(),
|
|
45186
|
+
frameHeight: number(),
|
|
45187
|
+
analysisMs: number()
|
|
45188
|
+
});
|
|
45189
|
+
DeviceType.Camera, method(object({
|
|
45190
|
+
deviceId: number(),
|
|
45191
|
+
frame: FrameInputSchema.optional(),
|
|
45192
|
+
frameHandle: FrameHandleSchema.optional()
|
|
45193
|
+
}), MotionAnalysisResultSchema, {
|
|
45194
|
+
role: "admin",
|
|
45195
|
+
kind: "mutation"
|
|
45196
|
+
}), method(object({ deviceId: number() }), _void(), {
|
|
45197
|
+
role: "admin",
|
|
45198
|
+
kind: "mutation"
|
|
45199
|
+
}), method(_void(), _void(), {
|
|
45200
|
+
role: "admin",
|
|
45201
|
+
kind: "mutation"
|
|
45202
|
+
}), object({
|
|
45203
|
+
deviceId: number(),
|
|
45204
|
+
detected: boolean(),
|
|
45205
|
+
regionCount: number()
|
|
45118
45206
|
});
|
|
45119
45207
|
/**
|
|
45120
|
-
*
|
|
45121
|
-
*
|
|
45122
|
-
*
|
|
45208
|
+
* `mqtt-broker` — broker-registry cap.
|
|
45209
|
+
*
|
|
45210
|
+
* NOT a pub/sub proxy. The cap exposes (a) a registry of configured
|
|
45211
|
+
* MQTT brokers (external + optionally an embedded `aedes`-backed one)
|
|
45212
|
+
* and (b) the connection details a consumer addon needs to spin up
|
|
45213
|
+
* its OWN `mqtt.js` client.
|
|
45214
|
+
*
|
|
45215
|
+
* Why: pub/sub routing over the system event-bus loses fidelity
|
|
45216
|
+
* (callback shape, QoS guarantees, will/retain semantics) and adds
|
|
45217
|
+
* refcount bookkeeping that addons would rather own themselves. The
|
|
45218
|
+
* canonical consumer needs raw `mqtt.js`
|
|
45219
|
+
* features anyway — give it the connection config, get out of the way.
|
|
45220
|
+
*
|
|
45221
|
+
* Consumer flow:
|
|
45222
|
+
* const cfg = await ctx.api.mqttBroker.getBrokerConfig({ id })
|
|
45223
|
+
* const client = mqtt.connect(cfg.url, { username: cfg.username, … })
|
|
45224
|
+
* client.subscribe('zigbee2mqtt/+')
|
|
45225
|
+
*
|
|
45226
|
+
* Collection mode: multiple brokers (e.g. one local mosquitto + one
|
|
45227
|
+
* cloud bridge). The "embedded" entry (when present) is just another
|
|
45228
|
+
* broker in the registry — its lifecycle is owned by the addon that
|
|
45229
|
+
* spawned it.
|
|
45123
45230
|
*/
|
|
45124
|
-
var
|
|
45231
|
+
var BrokerKindSchema = _enum(["external", "embedded"]);
|
|
45232
|
+
/**
|
|
45233
|
+
* Broker live-probe status.
|
|
45234
|
+
*
|
|
45235
|
+
* - `connected` — last probe completed a clean CONNACK
|
|
45236
|
+
* - `disconnected` — no probe has run yet (cold cache)
|
|
45237
|
+
* - `auth-failed` — CONNACK refused with auth error (RC 4 / 5)
|
|
45238
|
+
* - `unreachable` — TCP connect timed out / refused
|
|
45239
|
+
* - `tls-error` — TLS handshake failed (cert / SNI / cipher)
|
|
45240
|
+
*/
|
|
45241
|
+
var BrokerStatusSchema$1 = _enum([
|
|
45242
|
+
"connected",
|
|
45243
|
+
"disconnected",
|
|
45244
|
+
"auth-failed",
|
|
45245
|
+
"unreachable",
|
|
45246
|
+
"tls-error"
|
|
45247
|
+
]);
|
|
45248
|
+
var BrokerInfoSchema$1 = object({
|
|
45125
45249
|
id: string(),
|
|
45126
45250
|
name: string(),
|
|
45127
|
-
|
|
45128
|
-
|
|
45129
|
-
|
|
45130
|
-
|
|
45131
|
-
});
|
|
45132
|
-
/** A discovery-surfaced candidate (config is partial + non-secret). */
|
|
45133
|
-
var DiscoveredTargetSchema = object({
|
|
45134
|
-
kind: string(),
|
|
45135
|
-
suggestedName: string(),
|
|
45136
|
-
config: record(string(), unknown())
|
|
45137
|
-
});
|
|
45138
|
-
/** The degrade engine's report — what was resolved / dropped / degraded. */
|
|
45139
|
-
var RenderedAsSchema = object({
|
|
45140
|
-
level: string(),
|
|
45141
|
-
format: NotificationFormatSchema,
|
|
45142
|
-
attachmentsSent: number().int().nonnegative(),
|
|
45143
|
-
actionsSent: number().int().nonnegative(),
|
|
45144
|
-
truncated: boolean(),
|
|
45145
|
-
dropped: array(string())
|
|
45146
|
-
});
|
|
45147
|
-
var SendResultSchema = object({
|
|
45148
|
-
success: boolean(),
|
|
45251
|
+
url: string(),
|
|
45252
|
+
kind: BrokerKindSchema,
|
|
45253
|
+
status: BrokerStatusSchema$1,
|
|
45254
|
+
latencyMs: number().nullable(),
|
|
45149
45255
|
error: string().optional(),
|
|
45150
|
-
|
|
45256
|
+
/** Embedded brokers only: number of MQTT clients currently connected. */
|
|
45257
|
+
connectedClients: number().int().nonnegative().optional(),
|
|
45258
|
+
/** Epoch ms of the last live probe (external) or aedes snapshot (embedded). */
|
|
45259
|
+
lastCheckedAt: number().optional()
|
|
45151
45260
|
});
|
|
45152
|
-
/** Same shape as SendResult — kept as a distinct name for the test panel. */
|
|
45153
|
-
var TestResultSchema = SendResultSchema;
|
|
45154
45261
|
/**
|
|
45155
|
-
*
|
|
45156
|
-
* `
|
|
45262
|
+
* Connection details — what a consumer needs to call
|
|
45263
|
+
* `mqtt.connect(url, options)`. We split URL + credentials so the
|
|
45264
|
+
* consumer can pass them as `mqtt.connect(url, { username, password })`
|
|
45265
|
+
* instead of stuffing creds into the URL (which leaks them into logs).
|
|
45157
45266
|
*/
|
|
45158
|
-
var
|
|
45159
|
-
|
|
45160
|
-
|
|
45161
|
-
|
|
45162
|
-
stateInstance: string().optional(),
|
|
45163
|
-
error: string().optional()
|
|
45164
|
-
});
|
|
45165
|
-
method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSchema), { auth: "admin" }), method(object({ targetId: string() }), TargetSchema, { auth: "admin" }), method(object({
|
|
45166
|
-
kind: string(),
|
|
45167
|
-
config: record(string(), unknown()).optional(),
|
|
45267
|
+
var BrokerConnectionDetailsSchema = object({
|
|
45268
|
+
url: string(),
|
|
45269
|
+
username: string().optional(),
|
|
45270
|
+
password: string().optional(),
|
|
45168
45271
|
/**
|
|
45169
|
-
*
|
|
45170
|
-
*
|
|
45171
|
-
*
|
|
45272
|
+
* Suggested prefix for `clientId`. Each consumer should suffix this
|
|
45273
|
+
* with its own discriminator (addon id, instance id) so reconnects
|
|
45274
|
+
* don't kick each other off (MQTT spec: clientId must be unique per
|
|
45275
|
+
* broker).
|
|
45172
45276
|
*/
|
|
45173
|
-
|
|
45174
|
-
})
|
|
45175
|
-
|
|
45176
|
-
|
|
45177
|
-
|
|
45178
|
-
|
|
45179
|
-
|
|
45180
|
-
|
|
45181
|
-
|
|
45182
|
-
|
|
45183
|
-
|
|
45184
|
-
|
|
45185
|
-
|
|
45277
|
+
clientIdPrefix: string().optional()
|
|
45278
|
+
});
|
|
45279
|
+
var AddBrokerInputSchema = object({
|
|
45280
|
+
name: string().min(1),
|
|
45281
|
+
url: string().regex(/^(mqtt|mqtts|ws|wss):\/\//, "URL must start with mqtt(s):// or ws(s)://"),
|
|
45282
|
+
username: string().optional(),
|
|
45283
|
+
password: string().optional(),
|
|
45284
|
+
clientIdPrefix: string().optional()
|
|
45285
|
+
});
|
|
45286
|
+
var AddBrokerResultSchema = object({ id: string() });
|
|
45287
|
+
var IdInputSchema = object({ id: string() });
|
|
45288
|
+
var TestResultSchema$1 = discriminatedUnion("ok", [object({
|
|
45289
|
+
ok: literal(true),
|
|
45290
|
+
latencyMs: number()
|
|
45291
|
+
}), object({
|
|
45292
|
+
ok: literal(false),
|
|
45293
|
+
error: string()
|
|
45294
|
+
})]);
|
|
45295
|
+
var StartEmbeddedInputSchema = object({
|
|
45296
|
+
port: number().int().min(1).max(65535).default(1883),
|
|
45297
|
+
/** Allow anonymous connect (no username/password). Default: false. */
|
|
45298
|
+
allowAnonymous: boolean().default(false),
|
|
45299
|
+
/** Optional shared username/password for clients. */
|
|
45300
|
+
username: string().optional(),
|
|
45301
|
+
password: string().optional()
|
|
45302
|
+
});
|
|
45303
|
+
var StartEmbeddedResultSchema = object({
|
|
45304
|
+
id: string(),
|
|
45305
|
+
url: string()
|
|
45306
|
+
});
|
|
45307
|
+
var StatusSchema = object({
|
|
45308
|
+
brokerCount: number(),
|
|
45309
|
+
embeddedRunning: boolean()
|
|
45310
|
+
});
|
|
45311
|
+
method(_void(), array(BrokerInfoSchema$1)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
|
|
45186
45312
|
kind: "mutation",
|
|
45187
45313
|
auth: "admin"
|
|
45188
|
-
}), method(
|
|
45189
|
-
targetId: string(),
|
|
45190
|
-
sample: NotificationSchema.optional()
|
|
45191
|
-
}), TestResultSchema, {
|
|
45314
|
+
}), method(IdInputSchema, _void(), {
|
|
45192
45315
|
kind: "mutation",
|
|
45193
45316
|
auth: "admin"
|
|
45194
|
-
}), method(
|
|
45195
|
-
target: TargetSchema,
|
|
45196
|
-
/**
|
|
45197
|
-
* Duplicate flow: create a NEW target id while copying secrets from an
|
|
45198
|
-
* existing row. The UI never holds the stored token; blank / redacted
|
|
45199
|
-
* password fields are restored from this source (D634 still applies if
|
|
45200
|
-
* destinations diverge without a re-typed secret).
|
|
45201
|
-
*/
|
|
45202
|
-
cloneSecretsFrom: string().optional()
|
|
45203
|
-
}), TargetSchema, {
|
|
45317
|
+
}), method(IdInputSchema, TestResultSchema$1, {
|
|
45204
45318
|
kind: "mutation",
|
|
45205
45319
|
auth: "admin"
|
|
45206
|
-
}), method(
|
|
45320
|
+
}), method(StartEmbeddedInputSchema, StartEmbeddedResultSchema, {
|
|
45207
45321
|
kind: "mutation",
|
|
45208
45322
|
auth: "admin"
|
|
45209
|
-
}), method(
|
|
45210
|
-
targetId: string(),
|
|
45211
|
-
enabled: boolean()
|
|
45212
|
-
}), _void(), {
|
|
45323
|
+
}), method(IdInputSchema, _void(), {
|
|
45213
45324
|
kind: "mutation",
|
|
45214
45325
|
auth: "admin"
|
|
45326
|
+
}), method(_void(), StatusSchema);
|
|
45327
|
+
var NetworkEndpointSchema = object({
|
|
45328
|
+
url: string(),
|
|
45329
|
+
hostname: string(),
|
|
45330
|
+
port: number(),
|
|
45331
|
+
protocol: _enum(["http", "https"]),
|
|
45332
|
+
/**
|
|
45333
|
+
* Whether this address survives a restart of its provider. `false` = it is
|
|
45334
|
+
* re-issued every time (a Quick tunnel's random `*.trycloudflare.com`); the
|
|
45335
|
+
* hub never selects such an address AUTOMATICALLY for a role (D860), though
|
|
45336
|
+
* it stays visible and an operator may still flag it. Absent = stable: every
|
|
45337
|
+
* provider except a Quick tunnel owns a name that does not change.
|
|
45338
|
+
*/
|
|
45339
|
+
stable: boolean().optional()
|
|
45340
|
+
});
|
|
45341
|
+
object({
|
|
45342
|
+
url: string(),
|
|
45343
|
+
/** Mirrors {@link NetworkEndpointSchema} `stable`; absent = stable. */
|
|
45344
|
+
stable: boolean().optional(),
|
|
45345
|
+
updated: boolean().optional()
|
|
45346
|
+
});
|
|
45347
|
+
var NetworkAccessStatusSchema = object({
|
|
45348
|
+
connected: boolean(),
|
|
45349
|
+
endpoint: NetworkEndpointSchema.nullable(),
|
|
45350
|
+
error: string().optional()
|
|
45351
|
+
});
|
|
45352
|
+
/**
|
|
45353
|
+
* Optional, richer endpoint shape returned by providers that expose
|
|
45354
|
+
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
45355
|
+
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
45356
|
+
* the originating provider config (mode + sourcePort) so the
|
|
45357
|
+
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
45358
|
+
* one endpoint just omit `listEndpoints` from their provider impl.
|
|
45359
|
+
*/
|
|
45360
|
+
var NetworkEndpointEntrySchema = NetworkEndpointSchema.extend({
|
|
45361
|
+
/**
|
|
45362
|
+
* Stable id within the provider — typically `<mode>-<sourcePort>` so
|
|
45363
|
+
* the orchestrator can dedupe across `listEndpoints` polls.
|
|
45364
|
+
*/
|
|
45365
|
+
id: string(),
|
|
45366
|
+
/** Operator-facing label (mirrors `MeshEndpoint.label`). */
|
|
45367
|
+
label: string(),
|
|
45368
|
+
/** Optional provider-specific mode tag, used for icon/colour in admin UI. */
|
|
45369
|
+
mode: string().optional(),
|
|
45370
|
+
/** Originating local port the ingress fronts (informational). */
|
|
45371
|
+
sourcePort: number().optional()
|
|
45215
45372
|
});
|
|
45373
|
+
method(_void(), NetworkEndpointSchema, { kind: "mutation" }), method(_void(), _void(), { kind: "mutation" }), method(_void(), NetworkEndpointSchema.nullable()), method(_void(), NetworkAccessStatusSchema), method(_void(), array(NetworkEndpointEntrySchema).readonly());
|
|
45216
45374
|
var AUDIO_MACRO_LABELS = [
|
|
45217
45375
|
{
|
|
45218
45376
|
id: "speech",
|
|
@@ -51613,14 +51771,6 @@ var EngineProvisioningSchema = object({
|
|
|
51613
51771
|
*/
|
|
51614
51772
|
configIssues: array(string()).optional()
|
|
51615
51773
|
});
|
|
51616
|
-
var PipelineStepInputSchema = lazy(() => object({
|
|
51617
|
-
addonId: string(),
|
|
51618
|
-
modelId: string().optional(),
|
|
51619
|
-
enabled: boolean().default(true),
|
|
51620
|
-
children: array(PipelineStepInputSchema).optional(),
|
|
51621
|
-
settings: record(string(), unknown()).optional(),
|
|
51622
|
-
jumpDeviceKey: string().optional()
|
|
51623
|
-
}));
|
|
51624
51774
|
var ModelSubstitutionSchema = object({
|
|
51625
51775
|
addonId: string(),
|
|
51626
51776
|
chosen: string(),
|
|
@@ -51699,7 +51849,6 @@ var ConfigUISchemaBridge = custom();
|
|
|
51699
51849
|
var ConfigUISchemaNullableBridge = custom();
|
|
51700
51850
|
var InferenceCapabilitiesBridge = custom();
|
|
51701
51851
|
var ModelAvailabilityListBridge = custom();
|
|
51702
|
-
var PipelineRunResultBridge = custom();
|
|
51703
51852
|
method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
|
|
51704
51853
|
modelId: string(),
|
|
51705
51854
|
settings: record(string(), unknown()).readonly()
|
|
@@ -59373,7 +59522,7 @@ object({
|
|
|
59373
59522
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
59374
59523
|
lastFetchedAt: number()
|
|
59375
59524
|
});
|
|
59376
|
-
var DeviceIdSchema = number().int().nonnegative();
|
|
59525
|
+
var DeviceIdSchema$1 = number().int().nonnegative();
|
|
59377
59526
|
/** A value a program option or setting can take. */
|
|
59378
59527
|
var DishwasherValueSchema = union([
|
|
59379
59528
|
boolean(),
|
|
@@ -59437,77 +59586,77 @@ var DishwasherOptionsSchema = object({
|
|
|
59437
59586
|
options: array(DishwasherOptionDescriptorSchema)
|
|
59438
59587
|
});
|
|
59439
59588
|
DeviceType.Dishwasher, method(object({
|
|
59440
|
-
deviceId: DeviceIdSchema,
|
|
59589
|
+
deviceId: DeviceIdSchema$1,
|
|
59441
59590
|
program: string().min(1).optional(),
|
|
59442
59591
|
options: record(string(), DishwasherValueSchema).optional()
|
|
59443
59592
|
}), _void(), {
|
|
59444
59593
|
kind: "mutation",
|
|
59445
59594
|
auth: "protected"
|
|
59446
|
-
}), method(object({ deviceId: DeviceIdSchema }), _void(), {
|
|
59595
|
+
}), method(object({ deviceId: DeviceIdSchema$1 }), _void(), {
|
|
59447
59596
|
kind: "mutation",
|
|
59448
59597
|
auth: "protected"
|
|
59449
|
-
}), method(object({ deviceId: DeviceIdSchema }), _void(), {
|
|
59598
|
+
}), method(object({ deviceId: DeviceIdSchema$1 }), _void(), {
|
|
59450
59599
|
kind: "mutation",
|
|
59451
59600
|
auth: "protected"
|
|
59452
|
-
}), method(object({ deviceId: DeviceIdSchema }), _void(), {
|
|
59601
|
+
}), method(object({ deviceId: DeviceIdSchema$1 }), _void(), {
|
|
59453
59602
|
kind: "mutation",
|
|
59454
59603
|
auth: "protected"
|
|
59455
59604
|
}), method(object({
|
|
59456
|
-
deviceId: DeviceIdSchema,
|
|
59605
|
+
deviceId: DeviceIdSchema$1,
|
|
59457
59606
|
program: string().min(1)
|
|
59458
59607
|
}), _void(), {
|
|
59459
59608
|
kind: "mutation",
|
|
59460
59609
|
auth: "protected"
|
|
59461
59610
|
}), method(object({
|
|
59462
|
-
deviceId: DeviceIdSchema,
|
|
59611
|
+
deviceId: DeviceIdSchema$1,
|
|
59463
59612
|
on: boolean()
|
|
59464
59613
|
}), _void(), {
|
|
59465
59614
|
kind: "mutation",
|
|
59466
59615
|
auth: "protected"
|
|
59467
59616
|
}), method(object({
|
|
59468
|
-
deviceId: DeviceIdSchema,
|
|
59617
|
+
deviceId: DeviceIdSchema$1,
|
|
59469
59618
|
on: boolean()
|
|
59470
59619
|
}), _void(), {
|
|
59471
59620
|
kind: "mutation",
|
|
59472
59621
|
auth: "protected"
|
|
59473
59622
|
}), method(object({
|
|
59474
|
-
deviceId: DeviceIdSchema,
|
|
59623
|
+
deviceId: DeviceIdSchema$1,
|
|
59475
59624
|
on: boolean()
|
|
59476
59625
|
}), _void(), {
|
|
59477
59626
|
kind: "mutation",
|
|
59478
59627
|
auth: "protected"
|
|
59479
59628
|
}), method(object({
|
|
59480
|
-
deviceId: DeviceIdSchema,
|
|
59629
|
+
deviceId: DeviceIdSchema$1,
|
|
59481
59630
|
on: boolean()
|
|
59482
59631
|
}), _void(), {
|
|
59483
59632
|
kind: "mutation",
|
|
59484
59633
|
auth: "protected"
|
|
59485
59634
|
}), method(object({
|
|
59486
|
-
deviceId: DeviceIdSchema,
|
|
59635
|
+
deviceId: DeviceIdSchema$1,
|
|
59487
59636
|
on: boolean()
|
|
59488
59637
|
}), _void(), {
|
|
59489
59638
|
kind: "mutation",
|
|
59490
59639
|
auth: "protected"
|
|
59491
59640
|
}), method(object({
|
|
59492
|
-
deviceId: DeviceIdSchema,
|
|
59641
|
+
deviceId: DeviceIdSchema$1,
|
|
59493
59642
|
on: boolean()
|
|
59494
59643
|
}), _void(), {
|
|
59495
59644
|
kind: "mutation",
|
|
59496
59645
|
auth: "protected"
|
|
59497
59646
|
}), method(object({
|
|
59498
|
-
deviceId: DeviceIdSchema,
|
|
59647
|
+
deviceId: DeviceIdSchema$1,
|
|
59499
59648
|
on: boolean()
|
|
59500
59649
|
}), _void(), {
|
|
59501
59650
|
kind: "mutation",
|
|
59502
59651
|
auth: "protected"
|
|
59503
59652
|
}), method(object({
|
|
59504
|
-
deviceId: DeviceIdSchema,
|
|
59653
|
+
deviceId: DeviceIdSchema$1,
|
|
59505
59654
|
key: string().min(1),
|
|
59506
59655
|
value: DishwasherValueSchema
|
|
59507
59656
|
}), _void(), {
|
|
59508
59657
|
kind: "mutation",
|
|
59509
59658
|
auth: "protected"
|
|
59510
|
-
}), method(object({ deviceId: DeviceIdSchema }), DishwasherOptionsSchema, { auth: "protected" });
|
|
59659
|
+
}), method(object({ deviceId: DeviceIdSchema$1 }), DishwasherOptionsSchema, { auth: "protected" });
|
|
59511
59660
|
DeviceType.Camera;
|
|
59512
59661
|
object({
|
|
59513
59662
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
@@ -61945,7 +62094,8 @@ var TopologyNodeSchema = object({
|
|
|
61945
62094
|
isHub: boolean(),
|
|
61946
62095
|
isOnline: boolean(),
|
|
61947
62096
|
cpuPercent: number(),
|
|
61948
|
-
|
|
62097
|
+
/** `null` when the node's memory read failed or it has not reported one (D393). */
|
|
62098
|
+
memoryPercent: number().nullable(),
|
|
61949
62099
|
uptime: number(),
|
|
61950
62100
|
lastSeen: string(),
|
|
61951
62101
|
localIps: array(string()).readonly(),
|
|
@@ -62480,9 +62630,10 @@ object({
|
|
|
62480
62630
|
* combined reading; per-hopper levels live in `food1`/`food2`. Null when
|
|
62481
62631
|
* the device has not reported yet. */
|
|
62482
62632
|
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
62483
|
-
/** Food in the BOWL
|
|
62484
|
-
* feeder
|
|
62485
|
-
|
|
62633
|
+
/** Food in the BOWL, a mass (stored in kilograms, D944). Reported only by a
|
|
62634
|
+
* feeder with a bowl scale; null when the model has none or its reading is
|
|
62635
|
+
* of an unproven unit. */
|
|
62636
|
+
bowlFood: number().nullable().meta(readingMeta("mass")),
|
|
62486
62637
|
/** True while the pet is eating (`state.eating`). */
|
|
62487
62638
|
eating: boolean(),
|
|
62488
62639
|
/** Whether `markFoodReplenished` does anything on this model. When false
|
|
@@ -62595,6 +62746,64 @@ DeviceType.PetFeeder, method(object({
|
|
|
62595
62746
|
kind: "mutation",
|
|
62596
62747
|
auth: "protected"
|
|
62597
62748
|
});
|
|
62749
|
+
object({
|
|
62750
|
+
/** Water in the tank, 0..100 (%). Null while the source has not reported. */
|
|
62751
|
+
waterLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
62752
|
+
/** Water in the tank, in litres. Null while the source has not reported. */
|
|
62753
|
+
waterVolume: number().min(0).nullable().meta(readingMeta("volume")),
|
|
62754
|
+
/** True when the tank is empty. Null while unknown. */
|
|
62755
|
+
empty: boolean().nullable(),
|
|
62756
|
+
/** True while the pump is running. Null while unknown. */
|
|
62757
|
+
pumpRunning: boolean().nullable(),
|
|
62758
|
+
/** True when the pump works on an on/off duty cycle rather than continuously. */
|
|
62759
|
+
pumpIntervalEnabled: boolean().nullable(),
|
|
62760
|
+
/** How long the pump runs per cycle, in seconds. */
|
|
62761
|
+
pumpOnTime: number().min(0).nullable().meta(readingMeta("duration")),
|
|
62762
|
+
/** How long the pump rests per cycle, in seconds. */
|
|
62763
|
+
pumpOffTime: number().min(0).nullable().meta(readingMeta("duration")),
|
|
62764
|
+
/** Water drunk in the last drink, in litres. */
|
|
62765
|
+
lastDrink: number().min(0).nullable().meta(readingMeta("volume")),
|
|
62766
|
+
/** Water drunk in the current hour, in litres. */
|
|
62767
|
+
currentHourDrink: number().min(0).nullable().meta(readingMeta("volume")),
|
|
62768
|
+
/** Water drunk over the last 24 hours (rolling), in litres. */
|
|
62769
|
+
last24hDrink: number().min(0).nullable().meta(readingMeta("volume")),
|
|
62770
|
+
/** Water drunk since local midnight, in litres. */
|
|
62771
|
+
todayDrink: number().min(0).nullable().meta(readingMeta("volume")),
|
|
62772
|
+
/** Decoded fault message. Null means healthy; a non-null string is an active fault. */
|
|
62773
|
+
error: string().nullable(),
|
|
62774
|
+
/** Ms epoch when the slice was last refreshed. */
|
|
62775
|
+
lastFetchedAt: number()
|
|
62776
|
+
});
|
|
62777
|
+
var DeviceIdSchema = number().int().nonnegative();
|
|
62778
|
+
var MinutesSchema = number().int().min(0);
|
|
62779
|
+
DeviceType.PetFountain, method(object({
|
|
62780
|
+
deviceId: DeviceIdSchema,
|
|
62781
|
+
on: boolean()
|
|
62782
|
+
}), _void(), {
|
|
62783
|
+
kind: "mutation",
|
|
62784
|
+
auth: "protected"
|
|
62785
|
+
}), method(object({
|
|
62786
|
+
deviceId: DeviceIdSchema,
|
|
62787
|
+
on: boolean()
|
|
62788
|
+
}), _void(), {
|
|
62789
|
+
kind: "mutation",
|
|
62790
|
+
auth: "protected"
|
|
62791
|
+
}), method(object({
|
|
62792
|
+
deviceId: DeviceIdSchema,
|
|
62793
|
+
minutes: MinutesSchema
|
|
62794
|
+
}), _void(), {
|
|
62795
|
+
kind: "mutation",
|
|
62796
|
+
auth: "protected"
|
|
62797
|
+
}), method(object({
|
|
62798
|
+
deviceId: DeviceIdSchema,
|
|
62799
|
+
minutes: MinutesSchema
|
|
62800
|
+
}), _void(), {
|
|
62801
|
+
kind: "mutation",
|
|
62802
|
+
auth: "protected"
|
|
62803
|
+
}), method(object({ deviceId: DeviceIdSchema }), _void(), {
|
|
62804
|
+
kind: "mutation",
|
|
62805
|
+
auth: "protected"
|
|
62806
|
+
});
|
|
62598
62807
|
var VehicleSchema = object({
|
|
62599
62808
|
id: string(),
|
|
62600
62809
|
name: string(),
|
|
@@ -67192,7 +67401,7 @@ discriminatedUnion("kind", [object({
|
|
|
67192
67401
|
})]);
|
|
67193
67402
|
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
67194
67403
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
67195
|
-
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Camera, DeviceType.Camera, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
67404
|
+
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.PetFountain, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Camera, DeviceType.Camera, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
67196
67405
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
67197
67406
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
67198
67407
|
new Set(CAP_NAMES);
|
|
@@ -67343,7 +67552,7 @@ var AccessoryKind = {
|
|
|
67343
67552
|
PrivacyMask: DeviceRole.PrivacyMask
|
|
67344
67553
|
};
|
|
67345
67554
|
AccessoryKind.Siren, AccessoryKind.Floodlight, AccessoryKind.Spotlight, AccessoryKind.PirSensor, AccessoryKind.Chime, AccessoryKind.Autotrack, AccessoryKind.Nightvision, AccessoryKind.PrivacyMask;
|
|
67346
|
-
DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer;
|
|
67555
|
+
DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.PetFountain, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer;
|
|
67347
67556
|
new Set(Object.values(DeviceType));
|
|
67348
67557
|
Object.freeze({
|
|
67349
67558
|
"accessories.getStatus": {
|
|
@@ -69278,6 +69487,13 @@ Object.freeze({
|
|
|
69278
69487
|
access: "create",
|
|
69279
69488
|
role: "admin"
|
|
69280
69489
|
},
|
|
69490
|
+
"deviceExport.exposeEntity": {
|
|
69491
|
+
capName: "device-export",
|
|
69492
|
+
capScope: "system",
|
|
69493
|
+
addonId: null,
|
|
69494
|
+
access: "create",
|
|
69495
|
+
role: "admin"
|
|
69496
|
+
},
|
|
69281
69497
|
"deviceExport.getDeviceLiveContribution": {
|
|
69282
69498
|
capName: "device-export",
|
|
69283
69499
|
capScope: "system",
|
|
@@ -69306,6 +69522,13 @@ Object.freeze({
|
|
|
69306
69522
|
access: "view",
|
|
69307
69523
|
role: "admin"
|
|
69308
69524
|
},
|
|
69525
|
+
"deviceExport.listExposedEntities": {
|
|
69526
|
+
capName: "device-export",
|
|
69527
|
+
capScope: "system",
|
|
69528
|
+
addonId: null,
|
|
69529
|
+
access: "view",
|
|
69530
|
+
role: "admin"
|
|
69531
|
+
},
|
|
69309
69532
|
"deviceExport.listSupportedDeviceKinds": {
|
|
69310
69533
|
capName: "device-export",
|
|
69311
69534
|
capScope: "system",
|
|
@@ -69313,6 +69536,13 @@ Object.freeze({
|
|
|
69313
69536
|
access: "view",
|
|
69314
69537
|
role: "admin"
|
|
69315
69538
|
},
|
|
69539
|
+
"deviceExport.listSupportedEntityKinds": {
|
|
69540
|
+
capName: "device-export",
|
|
69541
|
+
capScope: "system",
|
|
69542
|
+
addonId: null,
|
|
69543
|
+
access: "view",
|
|
69544
|
+
role: "admin"
|
|
69545
|
+
},
|
|
69316
69546
|
"deviceExport.unexposeDevice": {
|
|
69317
69547
|
capName: "device-export",
|
|
69318
69548
|
capScope: "system",
|
|
@@ -69320,6 +69550,13 @@ Object.freeze({
|
|
|
69320
69550
|
access: "create",
|
|
69321
69551
|
role: "admin"
|
|
69322
69552
|
},
|
|
69553
|
+
"deviceExport.unexposeEntity": {
|
|
69554
|
+
capName: "device-export",
|
|
69555
|
+
capScope: "system",
|
|
69556
|
+
addonId: null,
|
|
69557
|
+
access: "create",
|
|
69558
|
+
role: "admin"
|
|
69559
|
+
},
|
|
69323
69560
|
"deviceExtension.listCandidates": {
|
|
69324
69561
|
capName: "device-extension",
|
|
69325
69562
|
capScope: "device",
|
|
@@ -72141,6 +72378,13 @@ Object.freeze({
|
|
|
72141
72378
|
access: "create",
|
|
72142
72379
|
role: "admin"
|
|
72143
72380
|
},
|
|
72381
|
+
"nodeRemovalHook.onNodeRemoved": {
|
|
72382
|
+
capName: "node-removal-hook",
|
|
72383
|
+
capScope: "system",
|
|
72384
|
+
addonId: null,
|
|
72385
|
+
access: "create",
|
|
72386
|
+
role: "admin"
|
|
72387
|
+
},
|
|
72144
72388
|
"nodes.clusterAddonStatus": {
|
|
72145
72389
|
capName: "nodes",
|
|
72146
72390
|
capScope: "system",
|
|
@@ -72778,6 +73022,48 @@ Object.freeze({
|
|
|
72778
73022
|
access: "create",
|
|
72779
73023
|
role: "viewer"
|
|
72780
73024
|
},
|
|
73025
|
+
"petFountain.getStatus": {
|
|
73026
|
+
capName: "pet-fountain",
|
|
73027
|
+
capScope: "device",
|
|
73028
|
+
addonId: null,
|
|
73029
|
+
access: "view",
|
|
73030
|
+
role: "viewer"
|
|
73031
|
+
},
|
|
73032
|
+
"petFountain.resetDailyConsumption": {
|
|
73033
|
+
capName: "pet-fountain",
|
|
73034
|
+
capScope: "device",
|
|
73035
|
+
addonId: null,
|
|
73036
|
+
access: "delete",
|
|
73037
|
+
role: "viewer"
|
|
73038
|
+
},
|
|
73039
|
+
"petFountain.setPump": {
|
|
73040
|
+
capName: "pet-fountain",
|
|
73041
|
+
capScope: "device",
|
|
73042
|
+
addonId: null,
|
|
73043
|
+
access: "create",
|
|
73044
|
+
role: "viewer"
|
|
73045
|
+
},
|
|
73046
|
+
"petFountain.setPumpInterval": {
|
|
73047
|
+
capName: "pet-fountain",
|
|
73048
|
+
capScope: "device",
|
|
73049
|
+
addonId: null,
|
|
73050
|
+
access: "create",
|
|
73051
|
+
role: "viewer"
|
|
73052
|
+
},
|
|
73053
|
+
"petFountain.setPumpOffMinutes": {
|
|
73054
|
+
capName: "pet-fountain",
|
|
73055
|
+
capScope: "device",
|
|
73056
|
+
addonId: null,
|
|
73057
|
+
access: "create",
|
|
73058
|
+
role: "viewer"
|
|
73059
|
+
},
|
|
73060
|
+
"petFountain.setPumpOnMinutes": {
|
|
73061
|
+
capName: "pet-fountain",
|
|
73062
|
+
capScope: "device",
|
|
73063
|
+
addonId: null,
|
|
73064
|
+
access: "create",
|
|
73065
|
+
role: "viewer"
|
|
73066
|
+
},
|
|
72781
73067
|
"pipelineAnalytics.addRetrainFrameFromRecording": {
|
|
72782
73068
|
capName: "pipeline-analytics",
|
|
72783
73069
|
capScope: "device",
|
|
@@ -79260,6 +79546,100 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
79260
79546
|
}
|
|
79261
79547
|
]
|
|
79262
79548
|
},
|
|
79549
|
+
"pet-fountain": {
|
|
79550
|
+
scope: "device",
|
|
79551
|
+
noun: t("Pet fountain", "Fontana per animali"),
|
|
79552
|
+
actions: [
|
|
79553
|
+
{
|
|
79554
|
+
id: "petFountain.pumpOn",
|
|
79555
|
+
method: "setPump",
|
|
79556
|
+
label: t("Pump on", "Pompa accesa"),
|
|
79557
|
+
phrase: t("Start the pump of {device}", "Avvia la pompa di {device}"),
|
|
79558
|
+
icon: "play",
|
|
79559
|
+
args: { on: true }
|
|
79560
|
+
},
|
|
79561
|
+
{
|
|
79562
|
+
id: "petFountain.pumpOff",
|
|
79563
|
+
method: "setPump",
|
|
79564
|
+
label: t("Pump off", "Pompa spenta"),
|
|
79565
|
+
phrase: t("Stop the pump of {device}", "Ferma la pompa di {device}"),
|
|
79566
|
+
icon: "square",
|
|
79567
|
+
args: { on: false }
|
|
79568
|
+
},
|
|
79569
|
+
{
|
|
79570
|
+
id: "petFountain.intervalOn",
|
|
79571
|
+
method: "setPumpInterval",
|
|
79572
|
+
label: t("Pump cycle on", "Ciclo pompa attivo"),
|
|
79573
|
+
phrase: t("Run the pump of {device} on its on/off cycle", "Fai lavorare la pompa di {device} a ciclo acceso/spento"),
|
|
79574
|
+
icon: "timer",
|
|
79575
|
+
args: { on: true }
|
|
79576
|
+
},
|
|
79577
|
+
{
|
|
79578
|
+
id: "petFountain.intervalOff",
|
|
79579
|
+
method: "setPumpInterval",
|
|
79580
|
+
label: t("Pump cycle off", "Ciclo pompa spento"),
|
|
79581
|
+
phrase: t("Run the pump of {device} continuously", "Fai lavorare la pompa di {device} in continuo"),
|
|
79582
|
+
icon: "timer-off",
|
|
79583
|
+
args: { on: false }
|
|
79584
|
+
},
|
|
79585
|
+
{
|
|
79586
|
+
id: "petFountain.pumpOnMinutes",
|
|
79587
|
+
method: "setPumpOnMinutes",
|
|
79588
|
+
label: t("Set pump run time", "Imposta il tempo di lavoro della pompa"),
|
|
79589
|
+
phrase: t("Set the pump of {device} to run {minutes} minutes per cycle", "Imposta la pompa di {device} a lavorare {minutes} minuti per ciclo"),
|
|
79590
|
+
icon: "timer",
|
|
79591
|
+
openArgs: [{
|
|
79592
|
+
key: "minutes",
|
|
79593
|
+
label: t("Minutes", "Minuti"),
|
|
79594
|
+
offer: {
|
|
79595
|
+
kind: "number",
|
|
79596
|
+
min: 0,
|
|
79597
|
+
step: 1,
|
|
79598
|
+
unit: "min"
|
|
79599
|
+
}
|
|
79600
|
+
}]
|
|
79601
|
+
},
|
|
79602
|
+
{
|
|
79603
|
+
id: "petFountain.pumpOffMinutes",
|
|
79604
|
+
method: "setPumpOffMinutes",
|
|
79605
|
+
label: t("Set pump rest time", "Imposta il tempo di riposo della pompa"),
|
|
79606
|
+
phrase: t("Set the pump of {device} to rest {minutes} minutes per cycle", "Imposta la pompa di {device} a riposare {minutes} minuti per ciclo"),
|
|
79607
|
+
icon: "timer-off",
|
|
79608
|
+
openArgs: [{
|
|
79609
|
+
key: "minutes",
|
|
79610
|
+
label: t("Minutes", "Minuti"),
|
|
79611
|
+
offer: {
|
|
79612
|
+
kind: "number",
|
|
79613
|
+
min: 0,
|
|
79614
|
+
step: 1,
|
|
79615
|
+
unit: "min"
|
|
79616
|
+
}
|
|
79617
|
+
}]
|
|
79618
|
+
},
|
|
79619
|
+
{
|
|
79620
|
+
id: "petFountain.resetDailyConsumption",
|
|
79621
|
+
method: "resetDailyConsumption",
|
|
79622
|
+
label: t("Clear daily consumption", "Azzera il consumo giornaliero"),
|
|
79623
|
+
phrase: t("Clear the daily water consumption of {device}", "Azzera il consumo giornaliero di acqua di {device}"),
|
|
79624
|
+
icon: "rotate-ccw"
|
|
79625
|
+
}
|
|
79626
|
+
],
|
|
79627
|
+
state: [{
|
|
79628
|
+
kind: "boolean",
|
|
79629
|
+
field: "empty",
|
|
79630
|
+
label: t("Tank empty", "Serbatoio vuoto"),
|
|
79631
|
+
whenTrue: t("When the tank of {device} is empty", "Quando il serbatoio di {device} è vuoto"),
|
|
79632
|
+
whenFalse: t("When the tank of {device} is refilled", "Quando il serbatoio di {device} viene riempito"),
|
|
79633
|
+
icon: "droplet"
|
|
79634
|
+
}, {
|
|
79635
|
+
kind: "numeric",
|
|
79636
|
+
field: "waterLevel",
|
|
79637
|
+
quantity: t("the water level", "il livello dell’acqua"),
|
|
79638
|
+
label: t("Water level", "Livello dell’acqua"),
|
|
79639
|
+
unit: "%",
|
|
79640
|
+
icon: "droplets"
|
|
79641
|
+
}]
|
|
79642
|
+
},
|
|
79263
79643
|
"media-player": {
|
|
79264
79644
|
scope: "device",
|
|
79265
79645
|
noun: t("Media player", "Lettore multimediale"),
|
|
@@ -81084,6 +81464,7 @@ var SYSTEM_CAP_VOCABULARY = {
|
|
|
81084
81464
|
"device-manager": system("the device registry itself — rename, move and remove are administration"),
|
|
81085
81465
|
"device-provider": system(INTERNAL),
|
|
81086
81466
|
"device-removal-hook": system(INTERNAL),
|
|
81467
|
+
"node-removal-hook": system(INTERNAL),
|
|
81087
81468
|
"device-state": system("the runtime-state mirror every trigger already reads through"),
|
|
81088
81469
|
"display-palette": system("the cluster display palette — one colour table for every client, not a device action"),
|
|
81089
81470
|
"embedding-encoder": system(ML),
|
|
@@ -81196,7 +81577,7 @@ function projectAction(cap, action) {
|
|
|
81196
81577
|
};
|
|
81197
81578
|
}
|
|
81198
81579
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
81199
|
-
DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer;
|
|
81580
|
+
DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.PetFountain, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer;
|
|
81200
81581
|
DeviceFeature.BatteryOperated;
|
|
81201
81582
|
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
81202
81583
|
var HA_AS = "a power sensor (device_class power). Home Assistant has no laundry domain. running-state stays unexported until a null reading can be published as unavailable.";
|
|
@@ -82747,6 +83128,36 @@ Object.freeze({
|
|
|
82747
83128
|
form: "single",
|
|
82748
83129
|
optional: false
|
|
82749
83130
|
}],
|
|
83131
|
+
"petFountain.getStatus": [{
|
|
83132
|
+
name: "deviceId",
|
|
83133
|
+
form: "single",
|
|
83134
|
+
optional: false
|
|
83135
|
+
}],
|
|
83136
|
+
"petFountain.resetDailyConsumption": [{
|
|
83137
|
+
name: "deviceId",
|
|
83138
|
+
form: "single",
|
|
83139
|
+
optional: false
|
|
83140
|
+
}],
|
|
83141
|
+
"petFountain.setPump": [{
|
|
83142
|
+
name: "deviceId",
|
|
83143
|
+
form: "single",
|
|
83144
|
+
optional: false
|
|
83145
|
+
}],
|
|
83146
|
+
"petFountain.setPumpInterval": [{
|
|
83147
|
+
name: "deviceId",
|
|
83148
|
+
form: "single",
|
|
83149
|
+
optional: false
|
|
83150
|
+
}],
|
|
83151
|
+
"petFountain.setPumpOffMinutes": [{
|
|
83152
|
+
name: "deviceId",
|
|
83153
|
+
form: "single",
|
|
83154
|
+
optional: false
|
|
83155
|
+
}],
|
|
83156
|
+
"petFountain.setPumpOnMinutes": [{
|
|
83157
|
+
name: "deviceId",
|
|
83158
|
+
form: "single",
|
|
83159
|
+
optional: false
|
|
83160
|
+
}],
|
|
82750
83161
|
"pipelineAnalytics.addRetrainFrameFromRecording": [{
|
|
82751
83162
|
name: "deviceId",
|
|
82752
83163
|
form: "single",
|