@camstack/addon-training 0.1.105 → 0.1.106
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 +6 -0
- package/dist/{MotionZonesSettings-CTiGmTwm.mjs → MotionZonesSettings-B-HW_hQS.mjs} +2 -2
- package/dist/{PrivacyMaskSettings-evTcHeEU.mjs → PrivacyMaskSettings-D24QEivW.mjs} +2 -2
- package/dist/{SceneMonitorEditor-C03Xg6cM.mjs → SceneMonitorEditor-BJhJhwU_.mjs} +2 -2
- package/dist/_stub.js +6453 -6114
- package/dist/{_virtual_mf-localSharedImportMap___mfe_internal__addon_training_page-1sr2B1A2.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_training_page-DhOREDNB.mjs} +3 -3
- package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CV7yw1Ol.mjs +26 -0
- package/dist/addon-training.css +1 -1
- package/dist/{dist-BhNuTgrA.js → dist-BifGWu-4.js} +1242 -848
- package/dist/{dist-CCRzGEk1.mjs → dist-CSPYj4Bg.mjs} +1243 -849
- package/dist/{hostInit-Cxx4Eh3M.mjs → hostInit-jYho1Uin.mjs} +2 -2
- package/dist/{icons-CXruMajc.mjs → icons-tE-y9KlM.mjs} +521 -527
- package/dist/index.js +1 -1
- package/dist/orchestrator/training.addon.js +1 -1
- package/dist/orchestrator/training.addon.mjs +1 -1
- package/dist/{player-overlays-0haBt2oQ.mjs → player-overlays-CAEteoxw.mjs} +1 -1
- package/dist/providers/modal/training-modal.addon.js +1 -1
- package/dist/providers/modal/training-modal.addon.mjs +1 -1
- package/dist/remoteEntry.js +1 -1
- package/dist/{responsive-BnXGZLBS.mjs → responsive-BJqCg1mL.mjs} +1 -1
- package/dist/{scene-monitor-copy-Bh54RJt8.mjs → scene-monitor-copy-CkZtRtGd.mjs} +1 -1
- package/dist/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_training_page__remoteEntry_js-X8CJUTYR.mjs → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_training_page__remoteEntry_js-Bmx0UoLI.mjs} +1 -1
- package/dist/{zoom-out-D4rm3GoJ.mjs → zoom-out-CWDOvUsr.mjs} +133 -127
- package/package.json +1 -1
- package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-rMgUaeoj.mjs +0 -26
|
@@ -5201,6 +5201,14 @@ function object(shape, params) {
|
|
|
5201
5201
|
...normalizeParams(params)
|
|
5202
5202
|
});
|
|
5203
5203
|
}
|
|
5204
|
+
function strictObject(shape, params) {
|
|
5205
|
+
return new ZodObject({
|
|
5206
|
+
type: "object",
|
|
5207
|
+
shape,
|
|
5208
|
+
catchall: never(),
|
|
5209
|
+
...normalizeParams(params)
|
|
5210
|
+
});
|
|
5211
|
+
}
|
|
5204
5212
|
function looseObject(shape, params) {
|
|
5205
5213
|
return new ZodObject({
|
|
5206
5214
|
type: "object",
|
|
@@ -5580,7 +5588,7 @@ var ZodIssueCode = {
|
|
|
5580
5588
|
var ZodFirstPartyTypeKind;
|
|
5581
5589
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5582
5590
|
//#endregion
|
|
5583
|
-
//#region ../types/dist/sleep-
|
|
5591
|
+
//#region ../types/dist/sleep-6eG9C8Xl.mjs
|
|
5584
5592
|
/**
|
|
5585
5593
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5586
5594
|
* window to float samples (D455).
|
|
@@ -8804,9 +8812,93 @@ function optionalMethod(input, output, options) {
|
|
|
8804
8812
|
providerOptional: true
|
|
8805
8813
|
};
|
|
8806
8814
|
}
|
|
8815
|
+
/**
|
|
8816
|
+
* `addon-pages-source` — collection cap exposing per-provider raw page
|
|
8817
|
+
* declarations. Every addon that contributes a UI page registers a
|
|
8818
|
+
* provider here. The hub-side singleton aggregator (`addon-pages` cap,
|
|
8819
|
+
* see `addon-pages.cap.ts`) walks this collection, stamps versioned
|
|
8820
|
+
* `bundleUrl` values, and returns the enriched `AddonPageInfo[]` list
|
|
8821
|
+
* that admin-ui consumes.
|
|
8822
|
+
*
|
|
8823
|
+
* The split exists because the public listing has a different output
|
|
8824
|
+
* shape than the per-provider raw declarations, and we want both ends
|
|
8825
|
+
* to flow through codegen instead of relying on a hand-written wrapper.
|
|
8826
|
+
*/
|
|
8827
|
+
var AddonPageDeclarationSchema = object({
|
|
8828
|
+
id: string(),
|
|
8829
|
+
label: string(),
|
|
8830
|
+
icon: string(),
|
|
8831
|
+
path: string(),
|
|
8832
|
+
/**
|
|
8833
|
+
* Module Federation remote name — must match the `name` field on the
|
|
8834
|
+
* page addon's `federation()` plugin config. Used by admin-ui's
|
|
8835
|
+
* `<AddonPageLoader>` to call `loadRemote('<remoteName>/page')`.
|
|
8836
|
+
* Conventionally `addon_<id>_page` (snake_case; MF names cannot
|
|
8837
|
+
* contain hyphens).
|
|
8838
|
+
*/
|
|
8839
|
+
remoteName: string(),
|
|
8840
|
+
/**
|
|
8841
|
+
* Bundle filename inside the addon's `dist/` dir served at
|
|
8842
|
+
* `/api/addon-pages/<addonId>/<bundle>`. With Module Federation this
|
|
8843
|
+
* is always `'remoteEntry.js'`; the value is kept on the metadata so
|
|
8844
|
+
* the static-file route can compute an mtime-based cache-buster URL
|
|
8845
|
+
* without a separate filesystem stat.
|
|
8846
|
+
*/
|
|
8847
|
+
bundle: string(),
|
|
8848
|
+
/**
|
|
8849
|
+
* Sidebar section this page docks into. Well-known ids: `'detection'`,
|
|
8850
|
+
* `'cluster'`, `'administration'` — the page renders inside that group.
|
|
8851
|
+
* Any OTHER string creates (or joins) a custom section rendered after
|
|
8852
|
+
* the built-in groups; its label comes from `sectionLabel` (first
|
|
8853
|
+
* declaration wins), falling back to the id. Absent → the legacy
|
|
8854
|
+
* "Addon Pages" group.
|
|
8855
|
+
*/
|
|
8856
|
+
section: string().optional(),
|
|
8857
|
+
/** Display label for a CUSTOM `section` id (ignored for well-known ids). */
|
|
8858
|
+
sectionLabel: string().optional()
|
|
8859
|
+
});
|
|
8860
|
+
var addonPagesSourceCapability = {
|
|
8861
|
+
name: "addon-pages-source",
|
|
8862
|
+
scope: "system",
|
|
8863
|
+
mode: "collection",
|
|
8864
|
+
internal: true,
|
|
8865
|
+
methods: {
|
|
8866
|
+
/**
|
|
8867
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
8868
|
+
* `data-store-provider`) — this was reachable on the AppRouter by ANY
|
|
8869
|
+
* authenticated session at the default `auth: 'protected'`. The only
|
|
8870
|
+
* consumer, the `addon-pages-aggregator` builtin, reads it via
|
|
8871
|
+
* `ctx.capabilities.getCollection('addon-pages-source')` — LOCAL-PROCESS
|
|
8872
|
+
* only, never tRPC (per `ctx.capabilities` seeing only the local
|
|
8873
|
+
* process). The public, enriched listing admin-ui actually consumes is
|
|
8874
|
+
* the separate `addon-pages` cap, unaffected by this change.
|
|
8875
|
+
*/
|
|
8876
|
+
listPages: method(_void(), array(AddonPageDeclarationSchema).readonly(), { auth: "admin" }) }
|
|
8877
|
+
};
|
|
8807
8878
|
var StaticDirOutputSchema$1 = object({ staticDir: string() });
|
|
8808
8879
|
var VersionOutputSchema$1 = object({ version: string() });
|
|
8809
8880
|
method(_void(), StaticDirOutputSchema$1, { auth: "admin" }), method(_void(), VersionOutputSchema$1, { auth: "admin" });
|
|
8881
|
+
/**
|
|
8882
|
+
* The pipeline step-input shape and the run-result bridge, in a module that
|
|
8883
|
+
* imports nothing but zod and types.
|
|
8884
|
+
*
|
|
8885
|
+
* WHY A SEPARATE FILE (addon footprint, D28): both were declared in
|
|
8886
|
+
* `pipeline-executor.cap.ts`, whose import evaluates the whole executor schema
|
|
8887
|
+
* graph. An addon that only needs these two (the benchmark's `runPipelineTest`
|
|
8888
|
+
* action) paid ~130 MB of heap at load. `pipeline-executor.cap.ts` re-exports
|
|
8889
|
+
* them, so every existing import keeps working; addon server code takes them
|
|
8890
|
+
* from `@camstack/types/addon`.
|
|
8891
|
+
*/
|
|
8892
|
+
var PipelineStepInputSchema = lazy(() => object({
|
|
8893
|
+
addonId: string(),
|
|
8894
|
+
modelId: string().optional(),
|
|
8895
|
+
enabled: boolean().default(true),
|
|
8896
|
+
children: array(PipelineStepInputSchema).optional(),
|
|
8897
|
+
settings: record(string(), unknown()).optional(),
|
|
8898
|
+
jumpDeviceKey: string().optional()
|
|
8899
|
+
}));
|
|
8900
|
+
/** Typed bridge to the recursive `FrameResult` graph; validation is structural. */
|
|
8901
|
+
var PipelineRunResultBridge = custom();
|
|
8810
8902
|
var StaticDirOutputSchema = object({ staticDir: string() });
|
|
8811
8903
|
var VersionOutputSchema = object({ version: string() });
|
|
8812
8904
|
method(_void(), StaticDirOutputSchema, { auth: "admin" }), method(_void(), VersionOutputSchema, { auth: "admin" });
|
|
@@ -9002,6 +9094,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
9002
9094
|
"osd",
|
|
9003
9095
|
"osd-manager",
|
|
9004
9096
|
"pet-feeder",
|
|
9097
|
+
"pet-fountain",
|
|
9005
9098
|
"pipeline-analytics",
|
|
9006
9099
|
"pipeline-executor",
|
|
9007
9100
|
"pipeline-orchestrator",
|
|
@@ -10281,6 +10374,56 @@ Object.freeze({
|
|
|
10281
10374
|
"valueType": "number"
|
|
10282
10375
|
}
|
|
10283
10376
|
],
|
|
10377
|
+
"pet-fountain": [
|
|
10378
|
+
{
|
|
10379
|
+
"path": "waterLevel",
|
|
10380
|
+
"valueType": "number"
|
|
10381
|
+
},
|
|
10382
|
+
{
|
|
10383
|
+
"path": "waterVolume",
|
|
10384
|
+
"valueType": "number"
|
|
10385
|
+
},
|
|
10386
|
+
{
|
|
10387
|
+
"path": "empty",
|
|
10388
|
+
"valueType": "boolean"
|
|
10389
|
+
},
|
|
10390
|
+
{
|
|
10391
|
+
"path": "pumpRunning",
|
|
10392
|
+
"valueType": "boolean"
|
|
10393
|
+
},
|
|
10394
|
+
{
|
|
10395
|
+
"path": "pumpIntervalEnabled",
|
|
10396
|
+
"valueType": "boolean"
|
|
10397
|
+
},
|
|
10398
|
+
{
|
|
10399
|
+
"path": "pumpOnTime",
|
|
10400
|
+
"valueType": "number"
|
|
10401
|
+
},
|
|
10402
|
+
{
|
|
10403
|
+
"path": "pumpOffTime",
|
|
10404
|
+
"valueType": "number"
|
|
10405
|
+
},
|
|
10406
|
+
{
|
|
10407
|
+
"path": "lastDrink",
|
|
10408
|
+
"valueType": "number"
|
|
10409
|
+
},
|
|
10410
|
+
{
|
|
10411
|
+
"path": "currentHourDrink",
|
|
10412
|
+
"valueType": "number"
|
|
10413
|
+
},
|
|
10414
|
+
{
|
|
10415
|
+
"path": "last24hDrink",
|
|
10416
|
+
"valueType": "number"
|
|
10417
|
+
},
|
|
10418
|
+
{
|
|
10419
|
+
"path": "todayDrink",
|
|
10420
|
+
"valueType": "number"
|
|
10421
|
+
},
|
|
10422
|
+
{
|
|
10423
|
+
"path": "error",
|
|
10424
|
+
"valueType": "string"
|
|
10425
|
+
}
|
|
10426
|
+
],
|
|
10284
10427
|
"power-meter": [
|
|
10285
10428
|
{
|
|
10286
10429
|
"path": "power",
|
|
@@ -10818,7 +10961,7 @@ object({
|
|
|
10818
10961
|
params: record(string(), union([string(), number()])).optional()
|
|
10819
10962
|
});
|
|
10820
10963
|
//#endregion
|
|
10821
|
-
//#region ../types/dist/err-msg-
|
|
10964
|
+
//#region ../types/dist/err-msg-DWXWc0Di.mjs
|
|
10822
10965
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
10823
10966
|
DeviceType["Camera"] = "camera";
|
|
10824
10967
|
DeviceType["Hub"] = "hub";
|
|
@@ -10910,6 +11053,10 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
10910
11053
|
* native PetKit (`nodepetkit` `FeederDevice`), reusable by other feeder
|
|
10911
11054
|
* integrations sharing the same food/desiccant/hopper surface. */
|
|
10912
11055
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
11056
|
+
/** Pet water fountain — tank level, water drunk, pump and its duty cycle.
|
|
11057
|
+
* Installed with the `pet-fountain` cap. Reaches CamStack as loose entities
|
|
11058
|
+
* of a container and is BUILT as a composed device (D967). */
|
|
11059
|
+
DeviceType["PetFountain"] = "pet-fountain";
|
|
10913
11060
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
10914
11061
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
10915
11062
|
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
@@ -11170,7 +11317,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
11170
11317
|
return DeviceRole;
|
|
11171
11318
|
}({});
|
|
11172
11319
|
//#endregion
|
|
11173
|
-
//#region ../types/dist/composition-
|
|
11320
|
+
//#region ../types/dist/composition-kSuOifuG.mjs
|
|
11174
11321
|
/**
|
|
11175
11322
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11176
11323
|
*
|
|
@@ -12255,12 +12402,28 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
|
12255
12402
|
])
|
|
12256
12403
|
})
|
|
12257
12404
|
]);
|
|
12258
|
-
var
|
|
12405
|
+
var forwardArgUnion = union([
|
|
12406
|
+
string(),
|
|
12407
|
+
number(),
|
|
12408
|
+
boolean(),
|
|
12409
|
+
strictObject({ ["$input"]: string().min(1) }),
|
|
12410
|
+
record(string().min(1), lazy(() => forwardArgUnion))
|
|
12411
|
+
]);
|
|
12412
|
+
var CompositionForwardArgSchema = forwardArgUnion;
|
|
12413
|
+
/**
|
|
12414
|
+
* `forward` (D659, amended by D967): one method of a BUILT capability is one
|
|
12415
|
+
* call of `cap.method` on `source`. Without `args` the built method's input
|
|
12416
|
+
* passes through minus `deviceId`; with `args` the template IS the source's
|
|
12417
|
+
* whole input. `deviceId` is always the source's own, never an argument.
|
|
12418
|
+
*/
|
|
12419
|
+
var CompositionForwardCommandSchema = object({
|
|
12259
12420
|
kind: literal("forward"),
|
|
12260
12421
|
source: CompositionSourceRefSchema,
|
|
12261
12422
|
cap: string().min(1),
|
|
12262
|
-
method: string().min(1)
|
|
12263
|
-
|
|
12423
|
+
method: string().min(1),
|
|
12424
|
+
args: record(string().min(1), CompositionForwardArgSchema).optional()
|
|
12425
|
+
});
|
|
12426
|
+
var CompositionCommandTargetSchema = discriminatedUnion("kind", [CompositionForwardCommandSchema, CompositionCodeSourceSchema]);
|
|
12264
12427
|
/** An item key inside an item-array cap (`consumables.items[<key>]`). */
|
|
12265
12428
|
var COMPOSITION_ITEM_KEY_RE = /^[a-z0-9][a-z0-9-]{0,47}$/;
|
|
12266
12429
|
/**
|
|
@@ -12270,7 +12433,13 @@ var COMPOSITION_ITEM_KEY_RE = /^[a-z0-9][a-z0-9-]{0,47}$/;
|
|
|
12270
12433
|
*/
|
|
12271
12434
|
var CompositionItemEntrySchema = object({
|
|
12272
12435
|
label: string().min(1).max(80),
|
|
12273
|
-
fields: record(string().min(1), CompositionFieldSourceSchema)
|
|
12436
|
+
fields: record(string().min(1), CompositionFieldSourceSchema),
|
|
12437
|
+
/**
|
|
12438
|
+
* What the cap's `reset` does for THIS item (consumables). Present = the item
|
|
12439
|
+
* is resettable and a `reset` call naming its key forwards here. The item key
|
|
12440
|
+
* selects the command, so it is never an argument: there is no pass-through.
|
|
12441
|
+
*/
|
|
12442
|
+
reset: CompositionForwardCommandSchema.optional()
|
|
12274
12443
|
});
|
|
12275
12444
|
var CompositionFeatureSchema = discriminatedUnion("kind", [object({
|
|
12276
12445
|
kind: literal("fields"),
|
|
@@ -12282,7 +12451,7 @@ var CompositionFeatureSchema = discriminatedUnion("kind", [object({
|
|
|
12282
12451
|
* owns the WHOLE array field: the composed value holds exactly these items.
|
|
12283
12452
|
*/
|
|
12284
12453
|
items: record(string().regex(COMPOSITION_ITEM_KEY_RE), CompositionItemEntrySchema).refine((items) => Object.keys(items).length <= 16, { message: `at most 16 items` }).optional(),
|
|
12285
|
-
/**
|
|
12454
|
+
/** Method name → what serves it. Only a BUILT capability takes commands (D967). */
|
|
12286
12455
|
commands: record(string().min(1), CompositionCommandTargetSchema).optional()
|
|
12287
12456
|
}), object({
|
|
12288
12457
|
kind: literal("passthrough"),
|
|
@@ -16240,163 +16409,521 @@ object({
|
|
|
16240
16409
|
lastError: string().nullable()
|
|
16241
16410
|
});
|
|
16242
16411
|
/**
|
|
16243
|
-
*
|
|
16244
|
-
* surface that admin-ui consumes through `useAddonPagesListPages()`.
|
|
16412
|
+
* notification-output — canonical, capability-gated notification delivery.
|
|
16245
16413
|
*
|
|
16246
|
-
*
|
|
16247
|
-
*
|
|
16248
|
-
*
|
|
16249
|
-
*
|
|
16250
|
-
*
|
|
16414
|
+
* Apprise-derived model (see
|
|
16415
|
+
* `docs/superpowers/specs/2026-07-03-notification-output-notifier-matrix.md`):
|
|
16416
|
+
* callers emit ONE canonical `Notification`; each provider declares a
|
|
16417
|
+
* per-kind capability descriptor (`TargetKind`), and the pure degrade
|
|
16418
|
+
* engine (`@camstack/types` `prepareNotification`) transcodes / degrades the
|
|
16419
|
+
* message to what the kind supports — callers never special-case a service.
|
|
16251
16420
|
*
|
|
16252
|
-
*
|
|
16253
|
-
*
|
|
16254
|
-
* provider
|
|
16255
|
-
*
|
|
16256
|
-
*
|
|
16421
|
+
* DESIGN DECISIONS (locked):
|
|
16422
|
+
* - Target CRUD lives on THIS cap (`upsertTarget` / `deleteTarget` /
|
|
16423
|
+
* `setTargetEnabled`), each provider persisting via the `settings-store`
|
|
16424
|
+
* cap. Rationale: the admin UI needs one uniform surface across the
|
|
16425
|
+
* notifiers addon AND the HA addon; the addon-`globalSettingsSchema`-array
|
|
16426
|
+
* alternative would fork the UI per addon and cannot host the
|
|
16427
|
+
* discovery→adopt flow.
|
|
16428
|
+
* - `listTargetKinds` / `listTargets` / `discoverTargets` return arrays →
|
|
16429
|
+
* the generated cap-mount auto-`concatCollection`-fans them across every
|
|
16430
|
+
* registered provider (notifiers addon + HA addon) so one catalog is
|
|
16431
|
+
* routable. `send` / `testTarget` / CRUD route to ONE provider by the
|
|
16432
|
+
* `addonId` the generated collection router extracts from the call input.
|
|
16433
|
+
* - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
|
|
16434
|
+
* transformer) + UDS MsgPack both round-trip typed arrays — already used by
|
|
16435
|
+
* `storage` / `storage-provider` / `recording` caps over the same path. No
|
|
16436
|
+
* base64 fallback needed.
|
|
16437
|
+
*
|
|
16438
|
+
* TODO (deferred, closed-set change — separate decision): add
|
|
16439
|
+
* `providerKind: 'notify'` so notification providers surface on the unified
|
|
16440
|
+
* admin "Integrations" page.
|
|
16257
16441
|
*/
|
|
16258
|
-
var AddonPageDeclarationSchema$1 = object({
|
|
16259
|
-
id: string(),
|
|
16260
|
-
label: string(),
|
|
16261
|
-
icon: string(),
|
|
16262
|
-
path: string(),
|
|
16263
|
-
remoteName: string(),
|
|
16264
|
-
bundle: string(),
|
|
16265
|
-
section: string().optional(),
|
|
16266
|
-
sectionLabel: string().optional()
|
|
16267
|
-
});
|
|
16268
|
-
var AddonPageInfoSchema = object({
|
|
16269
|
-
addonId: string(),
|
|
16270
|
-
page: AddonPageDeclarationSchema$1,
|
|
16271
|
-
bundleUrl: string()
|
|
16272
|
-
});
|
|
16273
|
-
method(_void(), array(AddonPageInfoSchema).readonly());
|
|
16274
16442
|
/**
|
|
16275
|
-
*
|
|
16276
|
-
*
|
|
16277
|
-
|
|
16278
|
-
|
|
16279
|
-
|
|
16280
|
-
|
|
16443
|
+
* Zentik-derived typed-media enum — the superset across every kind. Each
|
|
16444
|
+
* adapter picks what it supports and the degrade engine filters the rest.
|
|
16445
|
+
*/
|
|
16446
|
+
var AttachmentMediaTypeSchema = _enum([
|
|
16447
|
+
"image",
|
|
16448
|
+
"video",
|
|
16449
|
+
"gif",
|
|
16450
|
+
"audio",
|
|
16451
|
+
"icon"
|
|
16452
|
+
]);
|
|
16453
|
+
/**
|
|
16454
|
+
* A single attachment. Exactly one of `url` (remote source, most adapters
|
|
16455
|
+
* prefer this) or `bytes` (inline source; required for Pushover-style
|
|
16456
|
+
* bytes-only kinds) MUST be present — the degrade engine expresses a
|
|
16457
|
+
* url→bytes fetch as a `needsFetch` directive the adapter executes.
|
|
16458
|
+
*/
|
|
16459
|
+
var AttachmentSchema = object({
|
|
16460
|
+
mediaType: AttachmentMediaTypeSchema,
|
|
16461
|
+
url: string().optional(),
|
|
16462
|
+
bytes: _instanceof(Uint8Array).optional(),
|
|
16463
|
+
mime: string().optional(),
|
|
16464
|
+
name: string().optional()
|
|
16465
|
+
}).refine((a) => a.url !== void 0 || a.bytes !== void 0, { message: "Attachment requires either `url` or `bytes`" });
|
|
16466
|
+
var NotificationFormatSchema = _enum([
|
|
16467
|
+
"text",
|
|
16468
|
+
"markdown",
|
|
16469
|
+
"html"
|
|
16470
|
+
]);
|
|
16471
|
+
/**
|
|
16472
|
+
* The CLOSED icon vocabulary an action button may use.
|
|
16281
16473
|
*
|
|
16282
|
-
*
|
|
16283
|
-
*
|
|
16284
|
-
*
|
|
16474
|
+
* A closed set, not a free string, and that is the whole point: an arbitrary
|
|
16475
|
+
* icon name is one that ntfy renders, zentik silently drops, and nobody
|
|
16476
|
+
* notices — the same class of gap as a zone vocabulary nothing produced
|
|
16477
|
+
* ([D35](../../../docs/decisions/adr-0035.md)). Every adapter maps this set or
|
|
16478
|
+
* declares `actionIcons: false` and the degrade engine strips the field.
|
|
16479
|
+
*
|
|
16480
|
+
* Named by INTENT, never by glyph. "check" would tie the vocabulary to one
|
|
16481
|
+
* renderer's icon set; "acknowledge" survives an adapter that draws it
|
|
16482
|
+
* differently.
|
|
16483
|
+
*
|
|
16484
|
+
* ── A TOKEN IS NOT A WIRE VALUE ─────────────────────────────────────
|
|
16485
|
+
*
|
|
16486
|
+
* These names are for US. **No adapter may forward one verbatim.** Each maps
|
|
16487
|
+
* the whole set onto its own renderer's vocabulary through a
|
|
16488
|
+
* `Record<NotificationActionIcon, string>` — a Record, never a lookup with a
|
|
16489
|
+
* fallback, so adding a member here fails every adapter's build until someone
|
|
16490
|
+
* decides its glyph, which is the only place that decision can be made
|
|
16491
|
+
* honestly.
|
|
16492
|
+
*
|
|
16493
|
+
* This paragraph is the bug. Zentik declared `actionIcons: true` and passed
|
|
16494
|
+
* `disarm` straight through; iOS feeds that string to
|
|
16495
|
+
* `UNNotificationActionIcon(systemImageName:)`, `disarm` is not an SF Symbol,
|
|
16496
|
+
* and every snooze and alarm button arrived BLANK. A pass-through is not a
|
|
16497
|
+
* mapping, and "the field is documented" is not "the value renders".
|
|
16498
|
+
*
|
|
16499
|
+
* Adding a member is TRAIN-BOUND. The enum lives in the published
|
|
16500
|
+
* `@camstack/server` closure and the cap seam validates against the HUB's copy,
|
|
16501
|
+
* so an addon that emits a token the running hub does not know does not lose an
|
|
16502
|
+
* icon — its whole `send` fails Zod validation and the notification never
|
|
16503
|
+
* arrives. Never emit a new token from an addon before the train carrying it.
|
|
16285
16504
|
*/
|
|
16286
|
-
var
|
|
16505
|
+
var NotificationActionIconSchema = _enum([
|
|
16506
|
+
"acknowledge",
|
|
16507
|
+
"dismiss",
|
|
16508
|
+
"silence",
|
|
16509
|
+
"snooze",
|
|
16510
|
+
"view",
|
|
16511
|
+
"play",
|
|
16512
|
+
"open",
|
|
16513
|
+
"close",
|
|
16514
|
+
"lock",
|
|
16515
|
+
"unlock",
|
|
16516
|
+
"arm",
|
|
16517
|
+
"arm-home",
|
|
16518
|
+
"arm-away",
|
|
16519
|
+
"arm-night",
|
|
16520
|
+
"disarm",
|
|
16521
|
+
"light",
|
|
16522
|
+
"alert",
|
|
16523
|
+
"camera"
|
|
16524
|
+
]);
|
|
16525
|
+
/** A single tap-through action button. */
|
|
16526
|
+
var NotificationActionSchema = object({
|
|
16287
16527
|
id: string(),
|
|
16288
16528
|
label: string(),
|
|
16289
|
-
|
|
16290
|
-
|
|
16291
|
-
|
|
16292
|
-
* Module Federation remote name — must match the `name` field on the
|
|
16293
|
-
* page addon's `federation()` plugin config. Used by admin-ui's
|
|
16294
|
-
* `<AddonPageLoader>` to call `loadRemote('<remoteName>/page')`.
|
|
16295
|
-
* Conventionally `addon_<id>_page` (snake_case; MF names cannot
|
|
16296
|
-
* contain hyphens).
|
|
16297
|
-
*/
|
|
16298
|
-
remoteName: string(),
|
|
16529
|
+
url: string().optional(),
|
|
16530
|
+
/** Dropped by the degrade engine for a kind with `caps.actionIcons: false`. */
|
|
16531
|
+
icon: NotificationActionIconSchema.optional(),
|
|
16299
16532
|
/**
|
|
16300
|
-
*
|
|
16301
|
-
*
|
|
16302
|
-
*
|
|
16303
|
-
*
|
|
16304
|
-
*
|
|
16533
|
+
* Renders in a warning style where the notifier supports it.
|
|
16534
|
+
*
|
|
16535
|
+
* A HINT, never a gate. The callback's authority is its token and nothing
|
|
16536
|
+
* else — see `notification-center/action-token.ts` for what that does and
|
|
16537
|
+
* does not buy.
|
|
16305
16538
|
*/
|
|
16306
|
-
|
|
16539
|
+
destructive: boolean().optional(),
|
|
16307
16540
|
/**
|
|
16308
|
-
*
|
|
16309
|
-
*
|
|
16310
|
-
*
|
|
16311
|
-
* the
|
|
16312
|
-
*
|
|
16313
|
-
*
|
|
16541
|
+
* How the tap should REACH the url.
|
|
16542
|
+
*
|
|
16543
|
+
* `navigate` (absent, and every button authored before this field) opens it:
|
|
16544
|
+
* the phone leaves the notification and shows whatever the callback returns.
|
|
16545
|
+
* That is right for a button whose answer the operator wants to read.
|
|
16546
|
+
*
|
|
16547
|
+
* `background` fires it as a POST and stays put. It exists for the buttons
|
|
16548
|
+
* whose whole point is not to interrupt — "silence this for 30 minutes" is
|
|
16549
|
+
* an answer to the notification, and being thrown into a browser tab to
|
|
16550
|
+
* confirm it costs more attention than the notification did. A backend that
|
|
16551
|
+
* cannot do a background call renders it as an ordinary link (the adapters
|
|
16552
|
+
* fall back rather than dropping the button), so this is a preference, never
|
|
16553
|
+
* a requirement.
|
|
16314
16554
|
*/
|
|
16315
|
-
|
|
16316
|
-
/** Display label for a CUSTOM `section` id (ignored for well-known ids). */
|
|
16317
|
-
sectionLabel: string().optional()
|
|
16555
|
+
mode: _enum(["navigate", "background"]).optional()
|
|
16318
16556
|
});
|
|
16319
|
-
|
|
16320
|
-
|
|
16321
|
-
|
|
16322
|
-
|
|
16323
|
-
|
|
16324
|
-
|
|
16325
|
-
|
|
16326
|
-
|
|
16327
|
-
|
|
16328
|
-
|
|
16329
|
-
|
|
16330
|
-
|
|
16331
|
-
|
|
16332
|
-
|
|
16333
|
-
|
|
16334
|
-
|
|
16335
|
-
|
|
16336
|
-
|
|
16337
|
-
|
|
16338
|
-
|
|
16339
|
-
|
|
16340
|
-
"
|
|
16341
|
-
"
|
|
16342
|
-
"
|
|
16343
|
-
"
|
|
16557
|
+
/** A delivery parameter value: what a notifier declared it takes. */
|
|
16558
|
+
var DeliveryParamValueSchema = union([
|
|
16559
|
+
string(),
|
|
16560
|
+
number(),
|
|
16561
|
+
boolean()
|
|
16562
|
+
]);
|
|
16563
|
+
/**
|
|
16564
|
+
* One extra delivery parameter a notifier KIND declares (D938). A rule that
|
|
16565
|
+
* addresses a target of that kind may set it; a kind that declares nothing is
|
|
16566
|
+
* never handed one. The admin UI derives its control from this descriptor —
|
|
16567
|
+
* no editor knows a service by name.
|
|
16568
|
+
*
|
|
16569
|
+
* Optional fields are `.optional()`, never `.default()` (a Zod default does not
|
|
16570
|
+
* run on the addon cap path).
|
|
16571
|
+
*/
|
|
16572
|
+
var DeliveryParamSchema = object({
|
|
16573
|
+
key: string().min(1),
|
|
16574
|
+
label: string(),
|
|
16575
|
+
/** i18n key of the label, resolved by the declaring addon's namespace. */
|
|
16576
|
+
labelKey: string().optional(),
|
|
16577
|
+
type: _enum([
|
|
16578
|
+
"enum",
|
|
16579
|
+
"number",
|
|
16580
|
+
"boolean",
|
|
16581
|
+
"string"
|
|
16344
16582
|
]),
|
|
16345
|
-
|
|
16346
|
-
|
|
16347
|
-
|
|
16348
|
-
|
|
16349
|
-
|
|
16350
|
-
|
|
16351
|
-
|
|
16352
|
-
|
|
16353
|
-
|
|
16583
|
+
/** `enum` only: the closed set of accepted values. */
|
|
16584
|
+
options: array(object({
|
|
16585
|
+
value: string(),
|
|
16586
|
+
label: string()
|
|
16587
|
+
})).optional(),
|
|
16588
|
+
/** `number` only. */
|
|
16589
|
+
min: number().optional(),
|
|
16590
|
+
max: number().optional(),
|
|
16591
|
+
/** What the notifier does when the rule sets nothing; shown as the placeholder. */
|
|
16592
|
+
default: DeliveryParamValueSchema.optional()
|
|
16354
16593
|
});
|
|
16355
16594
|
/**
|
|
16356
|
-
*
|
|
16357
|
-
*
|
|
16358
|
-
*
|
|
16359
|
-
*
|
|
16360
|
-
*
|
|
16361
|
-
*
|
|
16595
|
+
* The canonical notification. `body` is the only hard field (Apprise model).
|
|
16596
|
+
* `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
|
|
16597
|
+
* NOT a fixed severity enum — each kind declares its own `caps.levels` and
|
|
16598
|
+
* the adapter maps this ordinal onto its native level. `level?` is an
|
|
16599
|
+
* optional kind-native level id (`emergency`, `silent`, …) that overrides
|
|
16600
|
+
* `priority` for that one target.
|
|
16362
16601
|
*/
|
|
16363
|
-
var
|
|
16364
|
-
|
|
16365
|
-
|
|
16366
|
-
|
|
16367
|
-
|
|
16368
|
-
|
|
16369
|
-
|
|
16370
|
-
|
|
16371
|
-
|
|
16372
|
-
|
|
16373
|
-
|
|
16602
|
+
var NotificationSchema = object({
|
|
16603
|
+
body: string(),
|
|
16604
|
+
title: string().optional(),
|
|
16605
|
+
format: NotificationFormatSchema.default("text"),
|
|
16606
|
+
priority: number().int().min(1).max(5).default(3),
|
|
16607
|
+
level: string().optional(),
|
|
16608
|
+
attachments: array(AttachmentSchema).optional(),
|
|
16609
|
+
clickUrl: string().optional(),
|
|
16610
|
+
actions: array(NotificationActionSchema).optional(),
|
|
16611
|
+
sound: string().optional(),
|
|
16612
|
+
ttl: number().optional(),
|
|
16613
|
+
tag: string().optional(),
|
|
16614
|
+
deviceId: number().optional(),
|
|
16615
|
+
eventId: string().optional(),
|
|
16616
|
+
metadata: record(string(), unknown()).optional(),
|
|
16617
|
+
/**
|
|
16618
|
+
* Values for the parameters the target's kind DECLARES in
|
|
16619
|
+
* {@link TargetKindSchema} `deliveryParams`. Already validated against the
|
|
16620
|
+
* declaration by the sender; a notifier reads only the keys it declared.
|
|
16621
|
+
*/
|
|
16622
|
+
delivery: record(string(), DeliveryParamValueSchema).optional()
|
|
16623
|
+
});
|
|
16624
|
+
/** One declared native severity/priority level for a kind. */
|
|
16625
|
+
var TargetKindLevelSchema = object({
|
|
16626
|
+
id: string(),
|
|
16627
|
+
label: string(),
|
|
16628
|
+
/** Which canonical priority (1..5) this level maps to. `null` = qualitative-only. */
|
|
16629
|
+
ordinal: number().int().min(1).max(5).nullable(),
|
|
16630
|
+
flags: object({
|
|
16631
|
+
critical: boolean().optional(),
|
|
16632
|
+
silent: boolean().optional(),
|
|
16633
|
+
noPush: boolean().optional()
|
|
16374
16634
|
}).optional(),
|
|
16375
|
-
|
|
16635
|
+
/** e.g. Pushover `emergency` requires `retry` / `expire`. */
|
|
16636
|
+
requires: array(string()).optional(),
|
|
16637
|
+
description: string().optional()
|
|
16376
16638
|
});
|
|
16377
|
-
|
|
16378
|
-
|
|
16379
|
-
|
|
16380
|
-
|
|
16381
|
-
|
|
16382
|
-
|
|
16383
|
-
|
|
16384
|
-
|
|
16385
|
-
|
|
16386
|
-
|
|
16387
|
-
|
|
16639
|
+
/** The full capability block consulted before dispatch. */
|
|
16640
|
+
var TargetKindCapsSchema = object({
|
|
16641
|
+
attachments: object({
|
|
16642
|
+
mediaTypes: array(AttachmentMediaTypeSchema),
|
|
16643
|
+
mode: _enum([
|
|
16644
|
+
"url",
|
|
16645
|
+
"bytes",
|
|
16646
|
+
"both"
|
|
16647
|
+
]),
|
|
16648
|
+
max: number().int().nonnegative(),
|
|
16649
|
+
maxBytes: number().int().positive().optional()
|
|
16650
|
+
}),
|
|
16651
|
+
/** Max action buttons (0 = none). */
|
|
16652
|
+
actions: number().int().nonnegative(),
|
|
16653
|
+
/**
|
|
16654
|
+
* Whether this kind renders a per-action ICON.
|
|
16655
|
+
*
|
|
16656
|
+
* `.optional()`, deliberately NOT `.default(false)`: a Zod default does not
|
|
16657
|
+
* run on the addon cap path — three production failures in one day taught
|
|
16658
|
+
* this repo that once. Absent is read as false by the degrade engine, which
|
|
16659
|
+
* is the safe direction: an icon that is not rendered costs nothing, an icon
|
|
16660
|
+
* assumed and dropped costs the operator's trust in the field.
|
|
16661
|
+
*/
|
|
16662
|
+
actionIcons: boolean().optional(),
|
|
16663
|
+
levels: array(TargetKindLevelSchema),
|
|
16664
|
+
format: array(NotificationFormatSchema),
|
|
16665
|
+
clickUrl: boolean(),
|
|
16666
|
+
sound: boolean(),
|
|
16667
|
+
ttl: boolean(),
|
|
16668
|
+
bodyMaxLen: number().int().positive()
|
|
16388
16669
|
});
|
|
16389
|
-
|
|
16390
|
-
|
|
16391
|
-
|
|
16670
|
+
/**
|
|
16671
|
+
* `configSchema` is a `ConfigUISchema` tree passed through to the admin
|
|
16672
|
+
* FormBuilder. Stored as `z.unknown()` at the cap seam (mirrors
|
|
16673
|
+
* `device-provider.getChildCreationSchema` `CreationSchemaOutputSchema`) —
|
|
16674
|
+
* the union is large and not meant for runtime validation here; the exported
|
|
16675
|
+
* `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
|
|
16676
|
+
*/
|
|
16677
|
+
var ConfigSchemaPassthrough$3 = unknown();
|
|
16678
|
+
var TargetKindSchema = object({
|
|
16679
|
+
kind: string(),
|
|
16392
16680
|
label: string(),
|
|
16393
16681
|
icon: string(),
|
|
16394
|
-
|
|
16395
|
-
|
|
16396
|
-
|
|
16397
|
-
|
|
16398
|
-
|
|
16399
|
-
|
|
16682
|
+
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
16683
|
+
addonId: string(),
|
|
16684
|
+
/**
|
|
16685
|
+
* URL of the kind's bundled BRAND icon, served by the providing addon over
|
|
16686
|
+
* its own `addon-routes` surface (`/addon/<addonId>/icons/<kind>`). Absent
|
|
16687
|
+
* when the addon bundles no icon for that kind — the client then falls back
|
|
16688
|
+
* to a neutral glyph rather than rendering the raw `icon` NAME as text.
|
|
16689
|
+
*
|
|
16690
|
+
* Root-relative on purpose: it resolves against whatever origin serves a web
|
|
16691
|
+
* client, and a native client joins it onto its own hub base.
|
|
16692
|
+
*
|
|
16693
|
+
* DECLARED here deliberately. It used to travel as an undeclared passthrough
|
|
16694
|
+
* field that survived only because the runtime cap-router forwards provider
|
|
16695
|
+
* output verbatim — so every consumer had to re-declare it by hand to stop
|
|
16696
|
+
* its own Zod parse from stripping it, and the whole arrangement would have
|
|
16697
|
+
* broken silently the moment output validation was tightened anywhere.
|
|
16698
|
+
*/
|
|
16699
|
+
iconUrl: string().optional(),
|
|
16700
|
+
/**
|
|
16701
|
+
* Media type of {@link iconUrl} (`image/svg+xml`, `image/png`, …).
|
|
16702
|
+
*
|
|
16703
|
+
* The server knows this and therefore says it, because the client cannot
|
|
16704
|
+
* safely guess: a React-Native client renders SVG and raster through two
|
|
16705
|
+
* DIFFERENT components (`react-native-svg` vs `expo-image` — expo-image does
|
|
16706
|
+
* not decode SVG on iOS/Android), so without this it silently fell back to a
|
|
16707
|
+
* placeholder glyph for every vector icon while the web build looked fine.
|
|
16708
|
+
*
|
|
16709
|
+
* Absent when {@link iconUrl} is absent, or for a legacy provider that has
|
|
16710
|
+
* not been updated — a client that cannot determine the type should prefer
|
|
16711
|
+
* its raster path, which is the safe default for an unknown image.
|
|
16712
|
+
*/
|
|
16713
|
+
iconMediaType: string().optional(),
|
|
16714
|
+
configSchema: ConfigSchemaPassthrough$3,
|
|
16715
|
+
/**
|
|
16716
|
+
* The config keys that decide WHERE this kind's secrets are sent (server,
|
|
16717
|
+
* base URL, instance, chat, recipient). A save that changes any of them
|
|
16718
|
+
* while leaving a secret redacted is refused by the provider (D634), so an
|
|
16719
|
+
* editor uses this to ask for the secret on exactly those edits instead of
|
|
16720
|
+
* on every edit.
|
|
16721
|
+
*
|
|
16722
|
+
* Optional: absent from a provider that holds no secret (the Home Assistant
|
|
16723
|
+
* kinds) and from a provider older than this field — an editor that finds
|
|
16724
|
+
* it absent must assume ANY edit may need the secret.
|
|
16725
|
+
*/
|
|
16726
|
+
destinationKeys: array(string()).optional(),
|
|
16727
|
+
supportsDiscovery: boolean(),
|
|
16728
|
+
/**
|
|
16729
|
+
* Extra delivery parameters a rule may set for a target of this kind (D938).
|
|
16730
|
+
* Absent = none; the rule editor then offers nothing.
|
|
16731
|
+
*/
|
|
16732
|
+
deliveryParams: array(DeliveryParamSchema).optional(),
|
|
16733
|
+
caps: TargetKindCapsSchema
|
|
16734
|
+
});
|
|
16735
|
+
/**
|
|
16736
|
+
* A persisted target. `config` holds secrets; providers REDACT secret fields
|
|
16737
|
+
* (return a presence marker only) when serving `listTargets` — never
|
|
16738
|
+
* round-trip a stored secret to the UI.
|
|
16739
|
+
*/
|
|
16740
|
+
var TargetSchema = object({
|
|
16741
|
+
id: string(),
|
|
16742
|
+
name: string(),
|
|
16743
|
+
kind: string(),
|
|
16744
|
+
addonId: string(),
|
|
16745
|
+
enabled: boolean(),
|
|
16746
|
+
config: record(string(), unknown())
|
|
16747
|
+
});
|
|
16748
|
+
/** A discovery-surfaced candidate (config is partial + non-secret). */
|
|
16749
|
+
var DiscoveredTargetSchema = object({
|
|
16750
|
+
kind: string(),
|
|
16751
|
+
suggestedName: string(),
|
|
16752
|
+
config: record(string(), unknown())
|
|
16753
|
+
});
|
|
16754
|
+
/** The degrade engine's report — what was resolved / dropped / degraded. */
|
|
16755
|
+
var RenderedAsSchema = object({
|
|
16756
|
+
level: string(),
|
|
16757
|
+
format: NotificationFormatSchema,
|
|
16758
|
+
attachmentsSent: number().int().nonnegative(),
|
|
16759
|
+
actionsSent: number().int().nonnegative(),
|
|
16760
|
+
truncated: boolean(),
|
|
16761
|
+
dropped: array(string())
|
|
16762
|
+
});
|
|
16763
|
+
var SendResultSchema = object({
|
|
16764
|
+
success: boolean(),
|
|
16765
|
+
error: string().optional(),
|
|
16766
|
+
renderedAs: RenderedAsSchema.optional()
|
|
16767
|
+
});
|
|
16768
|
+
/** Same shape as SendResult — kept as a distinct name for the test panel. */
|
|
16769
|
+
var TestResultSchema = SendResultSchema;
|
|
16770
|
+
/**
|
|
16771
|
+
* Pre-save credential probe against a partial (unsaved) target config.
|
|
16772
|
+
* `resolvedUrl` never includes secrets (token stripped from path).
|
|
16773
|
+
*/
|
|
16774
|
+
var ProbeTargetConfigResultSchema = object({
|
|
16775
|
+
ok: boolean(),
|
|
16776
|
+
resolvedUrl: string(),
|
|
16777
|
+
httpStatus: number().int().optional(),
|
|
16778
|
+
stateInstance: string().optional(),
|
|
16779
|
+
error: string().optional()
|
|
16780
|
+
});
|
|
16781
|
+
method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSchema), { auth: "admin" }), method(object({ targetId: string() }), TargetSchema, { auth: "admin" }), method(object({
|
|
16782
|
+
kind: string(),
|
|
16783
|
+
config: record(string(), unknown()).optional(),
|
|
16784
|
+
/**
|
|
16785
|
+
* When editing / duplicating, the blank password field never round-trips
|
|
16786
|
+
* the stored token. Pass the source target id so the provider can restore
|
|
16787
|
+
* secrets server-side before dialling (same merge as upsert).
|
|
16788
|
+
*/
|
|
16789
|
+
targetId: string().optional()
|
|
16790
|
+
}), array(DiscoveredTargetSchema), { auth: "admin" }), method(object({
|
|
16791
|
+
kind: string(),
|
|
16792
|
+
config: record(string(), unknown()),
|
|
16793
|
+
/** See `discoverTargets.targetId` — restore stored secrets for a blank password. */
|
|
16794
|
+
targetId: string().optional()
|
|
16795
|
+
}), ProbeTargetConfigResultSchema, {
|
|
16796
|
+
kind: "mutation",
|
|
16797
|
+
auth: "admin"
|
|
16798
|
+
}), method(object({
|
|
16799
|
+
targetId: string(),
|
|
16800
|
+
notification: NotificationSchema
|
|
16801
|
+
}), SendResultSchema, {
|
|
16802
|
+
kind: "mutation",
|
|
16803
|
+
auth: "admin"
|
|
16804
|
+
}), method(object({
|
|
16805
|
+
targetId: string(),
|
|
16806
|
+
sample: NotificationSchema.optional()
|
|
16807
|
+
}), TestResultSchema, {
|
|
16808
|
+
kind: "mutation",
|
|
16809
|
+
auth: "admin"
|
|
16810
|
+
}), method(object({
|
|
16811
|
+
target: TargetSchema,
|
|
16812
|
+
/**
|
|
16813
|
+
* Duplicate flow: create a NEW target id while copying secrets from an
|
|
16814
|
+
* existing row. The UI never holds the stored token; blank / redacted
|
|
16815
|
+
* password fields are restored from this source (D634 still applies if
|
|
16816
|
+
* destinations diverge without a re-typed secret).
|
|
16817
|
+
*/
|
|
16818
|
+
cloneSecretsFrom: string().optional()
|
|
16819
|
+
}), TargetSchema, {
|
|
16820
|
+
kind: "mutation",
|
|
16821
|
+
auth: "admin"
|
|
16822
|
+
}), method(object({ targetId: string() }), _void(), {
|
|
16823
|
+
kind: "mutation",
|
|
16824
|
+
auth: "admin"
|
|
16825
|
+
}), method(object({
|
|
16826
|
+
targetId: string(),
|
|
16827
|
+
enabled: boolean()
|
|
16828
|
+
}), _void(), {
|
|
16829
|
+
kind: "mutation",
|
|
16830
|
+
auth: "admin"
|
|
16831
|
+
});
|
|
16832
|
+
/**
|
|
16833
|
+
* `addon-pages` — system-scoped singleton aggregator cap. Public-facing
|
|
16834
|
+
* surface that admin-ui consumes through `useAddonPagesListPages()`.
|
|
16835
|
+
*
|
|
16836
|
+
* The provider iterates every `addon-pages-source` (collection) provider
|
|
16837
|
+
* and emits `AddonPageInfo[]` enriched with versioned `bundleUrl` strings
|
|
16838
|
+
* pointing at `/api/addon-pages/<addonId>/<bundle>?v=<mtime>`. The
|
|
16839
|
+
* filesystem `mtime` cache-buster lets the browser pick up addon
|
|
16840
|
+
* rebuilds without manual reload.
|
|
16841
|
+
*
|
|
16842
|
+
* The hub-local builtin `addon-pages-aggregator` (see
|
|
16843
|
+
* `@camstack/system/builtins/addon-pages-aggregator`) registers the
|
|
16844
|
+
* provider. Splitting the public aggregator from the raw collection
|
|
16845
|
+
* keeps both ends in codegen — there's no hand-written
|
|
16846
|
+
* `addon-pages.router.ts` wrapper anymore.
|
|
16847
|
+
*/
|
|
16848
|
+
var AddonPageDeclarationSchema$1 = object({
|
|
16849
|
+
id: string(),
|
|
16850
|
+
label: string(),
|
|
16851
|
+
icon: string(),
|
|
16852
|
+
path: string(),
|
|
16853
|
+
remoteName: string(),
|
|
16854
|
+
bundle: string(),
|
|
16855
|
+
section: string().optional(),
|
|
16856
|
+
sectionLabel: string().optional()
|
|
16857
|
+
});
|
|
16858
|
+
var AddonPageInfoSchema = object({
|
|
16859
|
+
addonId: string(),
|
|
16860
|
+
page: AddonPageDeclarationSchema$1,
|
|
16861
|
+
bundleUrl: string()
|
|
16862
|
+
});
|
|
16863
|
+
method(_void(), array(AddonPageInfoSchema).readonly());
|
|
16864
|
+
var AddonHttpRouteSchema = object({
|
|
16865
|
+
method: _enum([
|
|
16866
|
+
"GET",
|
|
16867
|
+
"POST",
|
|
16868
|
+
"PUT",
|
|
16869
|
+
"DELETE",
|
|
16870
|
+
"PATCH"
|
|
16871
|
+
]),
|
|
16872
|
+
path: string(),
|
|
16873
|
+
access: _enum([
|
|
16874
|
+
"public",
|
|
16875
|
+
"authenticated",
|
|
16876
|
+
"admin"
|
|
16877
|
+
]).optional(),
|
|
16878
|
+
description: string().optional(),
|
|
16879
|
+
/** The hub limits this route per client address before the handler runs. */
|
|
16880
|
+
rateLimit: _enum(["auth"]).optional()
|
|
16881
|
+
});
|
|
16882
|
+
/**
|
|
16883
|
+
* Cross-process route invocation envelope. The hub captures the
|
|
16884
|
+
* request as plain data, ships it to the worker via Moleculer, and
|
|
16885
|
+
* the worker runs the local handler against a capturing reply. The
|
|
16886
|
+
* envelope returned describes what the handler intended (status,
|
|
16887
|
+
* headers, body, or a redirect) so the hub can translate it back to
|
|
16888
|
+
* the Fastify reply that's actually wired to the socket.
|
|
16889
|
+
*/
|
|
16890
|
+
var InvokeRequestSchema = object({
|
|
16891
|
+
method: string(),
|
|
16892
|
+
path: string(),
|
|
16893
|
+
params: record(string(), string()),
|
|
16894
|
+
query: record(string(), string()),
|
|
16895
|
+
body: unknown(),
|
|
16896
|
+
headers: record(string(), string()),
|
|
16897
|
+
user: object({
|
|
16898
|
+
id: string(),
|
|
16899
|
+
username: string(),
|
|
16900
|
+
isAdmin: boolean()
|
|
16901
|
+
}).optional(),
|
|
16902
|
+
scopedToken: unknown().optional()
|
|
16903
|
+
});
|
|
16904
|
+
var InvokeReplyEnvelopeSchema = object({
|
|
16905
|
+
status: number().int(),
|
|
16906
|
+
headers: record(string(), string()),
|
|
16907
|
+
/** When set, the hub MUST `reply.redirect(redirectUrl)` instead of
|
|
16908
|
+
* sending `body`. Status defaults to 302 when this is set unless
|
|
16909
|
+
* the handler called `reply.code(...)` explicitly. */
|
|
16910
|
+
redirectUrl: string().nullable(),
|
|
16911
|
+
/** JSON-serializable body. `undefined` is treated as "no body". */
|
|
16912
|
+
body: unknown().optional(),
|
|
16913
|
+
/** Set when the handler called `reply.type(mime)`. */
|
|
16914
|
+
contentType: string().optional()
|
|
16915
|
+
});
|
|
16916
|
+
method(_void(), array(AddonHttpRouteSchema)), method(InvokeRequestSchema, InvokeReplyEnvelopeSchema, { kind: "mutation" });
|
|
16917
|
+
var ConfigTabDeclarationSchema = object({
|
|
16918
|
+
id: string(),
|
|
16919
|
+
label: string(),
|
|
16920
|
+
icon: string(),
|
|
16921
|
+
order: number().optional()
|
|
16922
|
+
});
|
|
16923
|
+
var ConfigSectionWithValuesSchema = object({
|
|
16924
|
+
id: string(),
|
|
16925
|
+
title: string(),
|
|
16926
|
+
titleKey: string().optional(),
|
|
16400
16927
|
description: string().optional(),
|
|
16401
16928
|
descriptionKey: string().optional(),
|
|
16402
16929
|
style: _enum(["card", "accordion"]).optional(),
|
|
@@ -18876,7 +19403,11 @@ var CompositionProblemSchema = object({
|
|
|
18876
19403
|
"mixed-quantity",
|
|
18877
19404
|
"helper-mismatch",
|
|
18878
19405
|
"member-constraint",
|
|
18879
|
-
"retention"
|
|
19406
|
+
"retention",
|
|
19407
|
+
"command-method-unknown",
|
|
19408
|
+
"command-source-unknown",
|
|
19409
|
+
"command-input-unknown",
|
|
19410
|
+
"command-input-missing"
|
|
18880
19411
|
]),
|
|
18881
19412
|
path: string(),
|
|
18882
19413
|
message: string()
|
|
@@ -18915,7 +19446,9 @@ var CompositionFieldRoleSchema = _enum([
|
|
|
18915
19446
|
var CompositionFieldItemSchema = object({
|
|
18916
19447
|
arrayPath: string(),
|
|
18917
19448
|
key: string(),
|
|
18918
|
-
label: string()
|
|
19449
|
+
label: string(),
|
|
19450
|
+
/** True when the item carries a `reset` forward: the composer writes `resettable` from this (D967). */
|
|
19451
|
+
resettable: boolean().optional()
|
|
18919
19452
|
});
|
|
18920
19453
|
var CompositionFieldPlanSchema = object({
|
|
18921
19454
|
cap: string(),
|
|
@@ -19120,7 +19653,7 @@ Object.freeze({
|
|
|
19120
19653
|
* One catalog row per base reading a group helper can build (D944 §3).
|
|
19121
19654
|
* Data, not a form default written into the block.
|
|
19122
19655
|
*/
|
|
19123
|
-
var NOW$
|
|
19656
|
+
var NOW$3 = {
|
|
19124
19657
|
fieldPath: "lastFetchedAt",
|
|
19125
19658
|
expr: "now"
|
|
19126
19659
|
};
|
|
@@ -19172,7 +19705,7 @@ var GROUP_TEMPLATES = [
|
|
|
19172
19705
|
quantity: "temperature",
|
|
19173
19706
|
defaultAggregate: "mean",
|
|
19174
19707
|
empty: "null",
|
|
19175
|
-
companions: [NOW$
|
|
19708
|
+
companions: [NOW$3],
|
|
19176
19709
|
alsoFrom: {
|
|
19177
19710
|
deviceTypes: CLIMATE_DEVICES,
|
|
19178
19711
|
accept: {
|
|
@@ -19190,7 +19723,7 @@ var GROUP_TEMPLATES = [
|
|
|
19190
19723
|
quantity: "humidity",
|
|
19191
19724
|
defaultAggregate: "mean",
|
|
19192
19725
|
empty: "null",
|
|
19193
|
-
companions: [NOW$
|
|
19726
|
+
companions: [NOW$3],
|
|
19194
19727
|
alsoFrom: {
|
|
19195
19728
|
deviceTypes: CLIMATE_DEVICES,
|
|
19196
19729
|
accept: {
|
|
@@ -19208,7 +19741,7 @@ var GROUP_TEMPLATES = [
|
|
|
19208
19741
|
quantity: "pressure",
|
|
19209
19742
|
defaultAggregate: "mean",
|
|
19210
19743
|
empty: "null",
|
|
19211
|
-
companions: [NOW$
|
|
19744
|
+
companions: [NOW$3]
|
|
19212
19745
|
}),
|
|
19213
19746
|
numeric({
|
|
19214
19747
|
id: "illuminance",
|
|
@@ -19219,7 +19752,7 @@ var GROUP_TEMPLATES = [
|
|
|
19219
19752
|
quantity: "illuminance",
|
|
19220
19753
|
defaultAggregate: "mean",
|
|
19221
19754
|
empty: "null",
|
|
19222
|
-
companions: [NOW$
|
|
19755
|
+
companions: [NOW$3]
|
|
19223
19756
|
}),
|
|
19224
19757
|
numeric({
|
|
19225
19758
|
id: "power",
|
|
@@ -19230,7 +19763,7 @@ var GROUP_TEMPLATES = [
|
|
|
19230
19763
|
quantity: "power",
|
|
19231
19764
|
defaultAggregate: "sum",
|
|
19232
19765
|
empty: "omit",
|
|
19233
|
-
companions: [NOW$
|
|
19766
|
+
companions: [NOW$3]
|
|
19234
19767
|
}),
|
|
19235
19768
|
numeric({
|
|
19236
19769
|
id: "energy",
|
|
@@ -19241,7 +19774,7 @@ var GROUP_TEMPLATES = [
|
|
|
19241
19774
|
quantity: "energy",
|
|
19242
19775
|
defaultAggregate: "sum",
|
|
19243
19776
|
empty: "omit",
|
|
19244
|
-
companions: [NOW$
|
|
19777
|
+
companions: [NOW$3]
|
|
19245
19778
|
}),
|
|
19246
19779
|
numeric({
|
|
19247
19780
|
id: "battery",
|
|
@@ -19276,7 +19809,7 @@ var GROUP_TEMPLATES = [
|
|
|
19276
19809
|
quantity: "device",
|
|
19277
19810
|
defaultAggregate: "mean",
|
|
19278
19811
|
empty: "null",
|
|
19279
|
-
companions: [NOW$
|
|
19812
|
+
companions: [NOW$3]
|
|
19280
19813
|
}),
|
|
19281
19814
|
binary({
|
|
19282
19815
|
id: "motion",
|
|
@@ -21622,12 +22155,48 @@ var ExposeInputSchema = object({
|
|
|
21622
22155
|
capabilities: array(string()).optional()
|
|
21623
22156
|
});
|
|
21624
22157
|
var UnexposeInputSchema = object({ deviceId: string() });
|
|
22158
|
+
/**
|
|
22159
|
+
* What an exporter may expose besides devices (D968). An action and a
|
|
22160
|
+
* notification target are LIST ENTRIES, never devices (D954): they enter an
|
|
22161
|
+
* exporter's own selection, not the device registry.
|
|
22162
|
+
*/
|
|
22163
|
+
var ExportEntityKindSchema = _enum([
|
|
22164
|
+
"device",
|
|
22165
|
+
"action",
|
|
22166
|
+
"notifier"
|
|
22167
|
+
]);
|
|
22168
|
+
var ExportEntityRefSchema = discriminatedUnion("kind", [
|
|
22169
|
+
object({
|
|
22170
|
+
kind: literal("device"),
|
|
22171
|
+
deviceId: string()
|
|
22172
|
+
}),
|
|
22173
|
+
object({
|
|
22174
|
+
kind: literal("action"),
|
|
22175
|
+
actionId: string().min(1)
|
|
22176
|
+
}),
|
|
22177
|
+
object({
|
|
22178
|
+
kind: literal("notifier"),
|
|
22179
|
+
targetId: string().min(1)
|
|
22180
|
+
})
|
|
22181
|
+
]);
|
|
22182
|
+
var ExposedEntitySchema = object({
|
|
22183
|
+
entity: ExportEntityRefSchema,
|
|
22184
|
+
exposedAs: string().optional()
|
|
22185
|
+
});
|
|
22186
|
+
var ExposeEntityInputSchema = object({ entity: ExportEntityRefSchema });
|
|
22187
|
+
var UnexposeEntityInputSchema = object({ entity: ExportEntityRefSchema });
|
|
21625
22188
|
method(_void(), DeviceExportStatusSchema), method(_void(), array(DeviceKindSchema)), method(_void(), array(ExposedDeviceSchema)), method(ExposeInputSchema, _void(), {
|
|
21626
22189
|
kind: "mutation",
|
|
21627
22190
|
auth: "admin"
|
|
21628
22191
|
}), method(UnexposeInputSchema, _void(), {
|
|
21629
22192
|
kind: "mutation",
|
|
21630
22193
|
auth: "admin"
|
|
22194
|
+
}), optionalMethod(_void(), array(ExportEntityKindSchema)), optionalMethod(_void(), array(ExposedEntitySchema)), optionalMethod(ExposeEntityInputSchema, _void(), {
|
|
22195
|
+
kind: "mutation",
|
|
22196
|
+
auth: "admin"
|
|
22197
|
+
}), optionalMethod(UnexposeEntityInputSchema, _void(), {
|
|
22198
|
+
kind: "mutation",
|
|
22199
|
+
auth: "admin"
|
|
21631
22200
|
});
|
|
21632
22201
|
/** Lucide category ids, alphabetical. `ICON_META` indexes into this. */
|
|
21633
22202
|
var ICON_CATEGORY_IDS = [
|
|
@@ -43496,7 +44065,7 @@ var LlmProviderWidgetSchema = object({
|
|
|
43496
44065
|
/** ConfigUISchema tree passed through untyped on the wire (the
|
|
43497
44066
|
* notification-output `ConfigSchemaPassthrough` precedent at
|
|
43498
44067
|
* notification-output.cap.ts:151); the exported TS type re-tightens it. */
|
|
43499
|
-
var ConfigSchemaPassthrough$
|
|
44068
|
+
var ConfigSchemaPassthrough$2 = unknown();
|
|
43500
44069
|
var LlmProfileKindDescriptorSchema = object({
|
|
43501
44070
|
kind: LlmProfileKindSchema,
|
|
43502
44071
|
label: string(),
|
|
@@ -43505,9 +44074,9 @@ var LlmProfileKindDescriptorSchema = object({
|
|
|
43505
44074
|
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
43506
44075
|
addonId: string(),
|
|
43507
44076
|
/** The provider's own fields (`providerConfig`); `password` fields are keychain-held. */
|
|
43508
|
-
connectionSchema: ConfigSchemaPassthrough$
|
|
44077
|
+
connectionSchema: ConfigSchemaPassthrough$2,
|
|
43509
44078
|
/** Provider fields that belong under "Advanced" (extra headers, runtime tuning). */
|
|
43510
|
-
advancedSchema: ConfigSchemaPassthrough$
|
|
44079
|
+
advancedSchema: ConfigSchemaPassthrough$2.optional(),
|
|
43511
44080
|
/** The kind's defaults; a model from `listModels` may override any of them. */
|
|
43512
44081
|
features: LlmModelFeaturesSchema,
|
|
43513
44082
|
/** `false` = the provider stamps `supportsVision` itself (from what a node reports). */
|
|
@@ -44033,10 +44602,10 @@ var CpuBreakdownSchema = object({
|
|
|
44033
44602
|
cores: number()
|
|
44034
44603
|
});
|
|
44035
44604
|
var MemoryInfoSchema = object({
|
|
44036
|
-
percent: number(),
|
|
44605
|
+
percent: number().nullable(),
|
|
44037
44606
|
totalBytes: number(),
|
|
44038
|
-
usedBytes: number(),
|
|
44039
|
-
availableBytes: number(),
|
|
44607
|
+
usedBytes: number().nullable(),
|
|
44608
|
+
availableBytes: number().nullable(),
|
|
44040
44609
|
swapUsedBytes: number(),
|
|
44041
44610
|
swapTotalBytes: number()
|
|
44042
44611
|
});
|
|
@@ -44311,693 +44880,273 @@ var NodeLoadSeriesSchema = object({
|
|
|
44311
44880
|
*/
|
|
44312
44881
|
durable: boolean()
|
|
44313
44882
|
});
|
|
44314
|
-
var GetLoadSeriesInputSchema = object({
|
|
44315
|
-
/**
|
|
44316
|
-
* The node whose series is wanted.
|
|
44317
|
-
*
|
|
44318
|
-
* NOT named `nodeId`: the generated cap router strips a top-level
|
|
44319
|
-
* `nodeId` from every method input and uses it to ROUTE the call to
|
|
44320
|
-
* that node's provider (`generated-cap-routers.ts`). A series target
|
|
44321
|
-
* called `nodeId` would silently become a routing pin and never reach
|
|
44322
|
-
* the provider. The hub holds every node it hears from, so the
|
|
44323
|
-
* ordinary call is unpinned — answered by the hub, for any node.
|
|
44324
|
-
*/
|
|
44325
|
-
forNodeId: string(),
|
|
44326
|
-
/**
|
|
44327
|
-
* EXCLUSIVE lower bound. A caller passes the newest `atMs` it already
|
|
44328
|
-
* holds and receives only what it is missing, so seeding a live chart
|
|
44329
|
-
* from this method cannot double a point already drawn.
|
|
44330
|
-
*/
|
|
44331
|
-
sinceMs: number().optional(),
|
|
44332
|
-
/**
|
|
44333
|
-
* Most points the caller wants PER FUNCTION. The window is reduced to fit,
|
|
44334
|
-
* preserving min and max per bucket.
|
|
44335
|
-
*
|
|
44336
|
-
* Absent means NO reduction — legitimate for a short window and a trap for a
|
|
44337
|
-
* long one, which is why a chart passes its own pixel width.
|
|
44338
|
-
*/
|
|
44339
|
-
maxPoints: number().int().positive().optional()
|
|
44340
|
-
});
|
|
44341
|
-
var SystemMetricsSchema = object({
|
|
44342
|
-
cpuPercent: number(),
|
|
44343
|
-
memoryPercent: number(),
|
|
44344
|
-
memoryUsedMB: number(),
|
|
44345
|
-
memoryTotalMB: number(),
|
|
44346
|
-
diskPercent: number().optional(),
|
|
44347
|
-
temperature: number().optional(),
|
|
44348
|
-
gpuPercent: number().optional(),
|
|
44349
|
-
gpuMemoryPercent: number().optional()
|
|
44350
|
-
});
|
|
44351
|
-
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);
|
|
44352
|
-
method(object({
|
|
44353
|
-
sourceUrl: string(),
|
|
44354
|
-
metadata: ModelConvertMetadataSchema,
|
|
44355
|
-
targets: array(ConvertTargetSchema).min(1).readonly(),
|
|
44356
|
-
calibrationRef: string().optional(),
|
|
44357
|
-
sessionId: string().optional()
|
|
44358
|
-
}), ConvertResultSchema, {
|
|
44359
|
-
kind: "mutation",
|
|
44360
|
-
auth: "admin",
|
|
44361
|
-
timeoutMs: 6e5
|
|
44362
|
-
});
|
|
44363
|
-
method(object({
|
|
44364
|
-
targetNodeId: string(),
|
|
44365
|
-
modelId: string(),
|
|
44366
|
-
format: _enum(MODEL_FORMATS),
|
|
44367
|
-
entry: ModelCatalogEntrySchema
|
|
44368
|
-
}), object({
|
|
44369
|
-
ok: boolean(),
|
|
44370
|
-
/** sha256 of the staged tarball (empty for a hub-local no-op). */
|
|
44371
|
-
sha256: string(),
|
|
44372
|
-
bytes: number(),
|
|
44373
|
-
/** The target node's modelsDir the artifact landed in. */
|
|
44374
|
-
path: string()
|
|
44375
|
-
}), {
|
|
44376
|
-
kind: "mutation",
|
|
44377
|
-
auth: "admin"
|
|
44378
|
-
});
|
|
44379
|
-
var MotionRegionSchema = object({
|
|
44380
|
-
bbox: BoundingBoxSchema,
|
|
44381
|
-
pixelCount: number(),
|
|
44382
|
-
intensity: number()
|
|
44383
|
-
});
|
|
44384
|
-
var MotionAnalysisResultSchema = object({
|
|
44385
|
-
detected: boolean(),
|
|
44386
|
-
regionCount: number(),
|
|
44387
|
-
/** Regions passing minArea filter — used for pipeline triggering. */
|
|
44388
|
-
regions: array(MotionRegionSchema).readonly(),
|
|
44389
|
-
/** All raw regions from CCL before minArea filter — used for UI debug overlay. */
|
|
44390
|
-
rawRegions: array(MotionRegionSchema).readonly(),
|
|
44391
|
-
frameWidth: number(),
|
|
44392
|
-
frameHeight: number(),
|
|
44393
|
-
analysisMs: number()
|
|
44394
|
-
});
|
|
44395
|
-
DeviceType.Camera, method(object({
|
|
44396
|
-
deviceId: number(),
|
|
44397
|
-
frame: FrameInputSchema.optional(),
|
|
44398
|
-
frameHandle: FrameHandleSchema.optional()
|
|
44399
|
-
}), MotionAnalysisResultSchema, {
|
|
44400
|
-
role: "admin",
|
|
44401
|
-
kind: "mutation"
|
|
44402
|
-
}), method(object({ deviceId: number() }), _void(), {
|
|
44403
|
-
role: "admin",
|
|
44404
|
-
kind: "mutation"
|
|
44405
|
-
}), method(_void(), _void(), {
|
|
44406
|
-
role: "admin",
|
|
44407
|
-
kind: "mutation"
|
|
44408
|
-
}), object({
|
|
44409
|
-
deviceId: number(),
|
|
44410
|
-
detected: boolean(),
|
|
44411
|
-
regionCount: number()
|
|
44412
|
-
});
|
|
44413
|
-
/**
|
|
44414
|
-
* `mqtt-broker` — broker-registry cap.
|
|
44415
|
-
*
|
|
44416
|
-
* NOT a pub/sub proxy. The cap exposes (a) a registry of configured
|
|
44417
|
-
* MQTT brokers (external + optionally an embedded `aedes`-backed one)
|
|
44418
|
-
* and (b) the connection details a consumer addon needs to spin up
|
|
44419
|
-
* its OWN `mqtt.js` client.
|
|
44420
|
-
*
|
|
44421
|
-
* Why: pub/sub routing over the system event-bus loses fidelity
|
|
44422
|
-
* (callback shape, QoS guarantees, will/retain semantics) and adds
|
|
44423
|
-
* refcount bookkeeping that addons would rather own themselves. The
|
|
44424
|
-
* canonical consumer needs raw `mqtt.js`
|
|
44425
|
-
* features anyway — give it the connection config, get out of the way.
|
|
44426
|
-
*
|
|
44427
|
-
* Consumer flow:
|
|
44428
|
-
* const cfg = await ctx.api.mqttBroker.getBrokerConfig({ id })
|
|
44429
|
-
* const client = mqtt.connect(cfg.url, { username: cfg.username, … })
|
|
44430
|
-
* client.subscribe('zigbee2mqtt/+')
|
|
44431
|
-
*
|
|
44432
|
-
* Collection mode: multiple brokers (e.g. one local mosquitto + one
|
|
44433
|
-
* cloud bridge). The "embedded" entry (when present) is just another
|
|
44434
|
-
* broker in the registry — its lifecycle is owned by the addon that
|
|
44435
|
-
* spawned it.
|
|
44436
|
-
*/
|
|
44437
|
-
var BrokerKindSchema = _enum(["external", "embedded"]);
|
|
44438
|
-
/**
|
|
44439
|
-
* Broker live-probe status.
|
|
44440
|
-
*
|
|
44441
|
-
* - `connected` — last probe completed a clean CONNACK
|
|
44442
|
-
* - `disconnected` — no probe has run yet (cold cache)
|
|
44443
|
-
* - `auth-failed` — CONNACK refused with auth error (RC 4 / 5)
|
|
44444
|
-
* - `unreachable` — TCP connect timed out / refused
|
|
44445
|
-
* - `tls-error` — TLS handshake failed (cert / SNI / cipher)
|
|
44446
|
-
*/
|
|
44447
|
-
var BrokerStatusSchema$1 = _enum([
|
|
44448
|
-
"connected",
|
|
44449
|
-
"disconnected",
|
|
44450
|
-
"auth-failed",
|
|
44451
|
-
"unreachable",
|
|
44452
|
-
"tls-error"
|
|
44453
|
-
]);
|
|
44454
|
-
var BrokerInfoSchema$1 = object({
|
|
44455
|
-
id: string(),
|
|
44456
|
-
name: string(),
|
|
44457
|
-
url: string(),
|
|
44458
|
-
kind: BrokerKindSchema,
|
|
44459
|
-
status: BrokerStatusSchema$1,
|
|
44460
|
-
latencyMs: number().nullable(),
|
|
44461
|
-
error: string().optional(),
|
|
44462
|
-
/** Embedded brokers only: number of MQTT clients currently connected. */
|
|
44463
|
-
connectedClients: number().int().nonnegative().optional(),
|
|
44464
|
-
/** Epoch ms of the last live probe (external) or aedes snapshot (embedded). */
|
|
44465
|
-
lastCheckedAt: number().optional()
|
|
44466
|
-
});
|
|
44467
|
-
/**
|
|
44468
|
-
* Connection details — what a consumer needs to call
|
|
44469
|
-
* `mqtt.connect(url, options)`. We split URL + credentials so the
|
|
44470
|
-
* consumer can pass them as `mqtt.connect(url, { username, password })`
|
|
44471
|
-
* instead of stuffing creds into the URL (which leaks them into logs).
|
|
44472
|
-
*/
|
|
44473
|
-
var BrokerConnectionDetailsSchema = object({
|
|
44474
|
-
url: string(),
|
|
44475
|
-
username: string().optional(),
|
|
44476
|
-
password: string().optional(),
|
|
44477
|
-
/**
|
|
44478
|
-
* Suggested prefix for `clientId`. Each consumer should suffix this
|
|
44479
|
-
* with its own discriminator (addon id, instance id) so reconnects
|
|
44480
|
-
* don't kick each other off (MQTT spec: clientId must be unique per
|
|
44481
|
-
* broker).
|
|
44482
|
-
*/
|
|
44483
|
-
clientIdPrefix: string().optional()
|
|
44484
|
-
});
|
|
44485
|
-
var AddBrokerInputSchema = object({
|
|
44486
|
-
name: string().min(1),
|
|
44487
|
-
url: string().regex(/^(mqtt|mqtts|ws|wss):\/\//, "URL must start with mqtt(s):// or ws(s)://"),
|
|
44488
|
-
username: string().optional(),
|
|
44489
|
-
password: string().optional(),
|
|
44490
|
-
clientIdPrefix: string().optional()
|
|
44491
|
-
});
|
|
44492
|
-
var AddBrokerResultSchema = object({ id: string() });
|
|
44493
|
-
var IdInputSchema = object({ id: string() });
|
|
44494
|
-
var TestResultSchema$1 = discriminatedUnion("ok", [object({
|
|
44495
|
-
ok: literal(true),
|
|
44496
|
-
latencyMs: number()
|
|
44497
|
-
}), object({
|
|
44498
|
-
ok: literal(false),
|
|
44499
|
-
error: string()
|
|
44500
|
-
})]);
|
|
44501
|
-
var StartEmbeddedInputSchema = object({
|
|
44502
|
-
port: number().int().min(1).max(65535).default(1883),
|
|
44503
|
-
/** Allow anonymous connect (no username/password). Default: false. */
|
|
44504
|
-
allowAnonymous: boolean().default(false),
|
|
44505
|
-
/** Optional shared username/password for clients. */
|
|
44506
|
-
username: string().optional(),
|
|
44507
|
-
password: string().optional()
|
|
44508
|
-
});
|
|
44509
|
-
var StartEmbeddedResultSchema = object({
|
|
44510
|
-
id: string(),
|
|
44511
|
-
url: string()
|
|
44512
|
-
});
|
|
44513
|
-
var StatusSchema = object({
|
|
44514
|
-
brokerCount: number(),
|
|
44515
|
-
embeddedRunning: boolean()
|
|
44516
|
-
});
|
|
44517
|
-
method(_void(), array(BrokerInfoSchema$1)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
|
|
44518
|
-
kind: "mutation",
|
|
44519
|
-
auth: "admin"
|
|
44520
|
-
}), method(IdInputSchema, _void(), {
|
|
44521
|
-
kind: "mutation",
|
|
44522
|
-
auth: "admin"
|
|
44523
|
-
}), method(IdInputSchema, TestResultSchema$1, {
|
|
44524
|
-
kind: "mutation",
|
|
44525
|
-
auth: "admin"
|
|
44526
|
-
}), method(StartEmbeddedInputSchema, StartEmbeddedResultSchema, {
|
|
44527
|
-
kind: "mutation",
|
|
44528
|
-
auth: "admin"
|
|
44529
|
-
}), method(IdInputSchema, _void(), {
|
|
44530
|
-
kind: "mutation",
|
|
44531
|
-
auth: "admin"
|
|
44532
|
-
}), method(_void(), StatusSchema);
|
|
44533
|
-
var NetworkEndpointSchema = object({
|
|
44534
|
-
url: string(),
|
|
44535
|
-
hostname: string(),
|
|
44536
|
-
port: number(),
|
|
44537
|
-
protocol: _enum(["http", "https"]),
|
|
44538
|
-
/**
|
|
44539
|
-
* Whether this address survives a restart of its provider. `false` = it is
|
|
44540
|
-
* re-issued every time (a Quick tunnel's random `*.trycloudflare.com`); the
|
|
44541
|
-
* hub never selects such an address AUTOMATICALLY for a role (D860), though
|
|
44542
|
-
* it stays visible and an operator may still flag it. Absent = stable: every
|
|
44543
|
-
* provider except a Quick tunnel owns a name that does not change.
|
|
44544
|
-
*/
|
|
44545
|
-
stable: boolean().optional()
|
|
44546
|
-
});
|
|
44547
|
-
object({
|
|
44548
|
-
url: string(),
|
|
44549
|
-
/** Mirrors {@link NetworkEndpointSchema} `stable`; absent = stable. */
|
|
44550
|
-
stable: boolean().optional(),
|
|
44551
|
-
updated: boolean().optional()
|
|
44552
|
-
});
|
|
44553
|
-
var NetworkAccessStatusSchema = object({
|
|
44554
|
-
connected: boolean(),
|
|
44555
|
-
endpoint: NetworkEndpointSchema.nullable(),
|
|
44556
|
-
error: string().optional()
|
|
44557
|
-
});
|
|
44558
|
-
/**
|
|
44559
|
-
* Optional, richer endpoint shape returned by providers that expose
|
|
44560
|
-
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
44561
|
-
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
44562
|
-
* the originating provider config (mode + sourcePort) so the
|
|
44563
|
-
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
44564
|
-
* one endpoint just omit `listEndpoints` from their provider impl.
|
|
44565
|
-
*/
|
|
44566
|
-
var NetworkEndpointEntrySchema = NetworkEndpointSchema.extend({
|
|
44567
|
-
/**
|
|
44568
|
-
* Stable id within the provider — typically `<mode>-<sourcePort>` so
|
|
44569
|
-
* the orchestrator can dedupe across `listEndpoints` polls.
|
|
44570
|
-
*/
|
|
44571
|
-
id: string(),
|
|
44572
|
-
/** Operator-facing label (mirrors `MeshEndpoint.label`). */
|
|
44573
|
-
label: string(),
|
|
44574
|
-
/** Optional provider-specific mode tag, used for icon/colour in admin UI. */
|
|
44575
|
-
mode: string().optional(),
|
|
44576
|
-
/** Originating local port the ingress fronts (informational). */
|
|
44577
|
-
sourcePort: number().optional()
|
|
44578
|
-
});
|
|
44579
|
-
method(_void(), NetworkEndpointSchema, { kind: "mutation" }), method(_void(), _void(), { kind: "mutation" }), method(_void(), NetworkEndpointSchema.nullable()), method(_void(), NetworkAccessStatusSchema), method(_void(), array(NetworkEndpointEntrySchema).readonly());
|
|
44580
|
-
/**
|
|
44581
|
-
* notification-output — canonical, capability-gated notification delivery.
|
|
44582
|
-
*
|
|
44583
|
-
* Apprise-derived model (see
|
|
44584
|
-
* `docs/superpowers/specs/2026-07-03-notification-output-notifier-matrix.md`):
|
|
44585
|
-
* callers emit ONE canonical `Notification`; each provider declares a
|
|
44586
|
-
* per-kind capability descriptor (`TargetKind`), and the pure degrade
|
|
44587
|
-
* engine (`@camstack/types` `prepareNotification`) transcodes / degrades the
|
|
44588
|
-
* message to what the kind supports — callers never special-case a service.
|
|
44589
|
-
*
|
|
44590
|
-
* DESIGN DECISIONS (locked):
|
|
44591
|
-
* - Target CRUD lives on THIS cap (`upsertTarget` / `deleteTarget` /
|
|
44592
|
-
* `setTargetEnabled`), each provider persisting via the `settings-store`
|
|
44593
|
-
* cap. Rationale: the admin UI needs one uniform surface across the
|
|
44594
|
-
* notifiers addon AND the HA addon; the addon-`globalSettingsSchema`-array
|
|
44595
|
-
* alternative would fork the UI per addon and cannot host the
|
|
44596
|
-
* discovery→adopt flow.
|
|
44597
|
-
* - `listTargetKinds` / `listTargets` / `discoverTargets` return arrays →
|
|
44598
|
-
* the generated cap-mount auto-`concatCollection`-fans them across every
|
|
44599
|
-
* registered provider (notifiers addon + HA addon) so one catalog is
|
|
44600
|
-
* routable. `send` / `testTarget` / CRUD route to ONE provider by the
|
|
44601
|
-
* `addonId` the generated collection router extracts from the call input.
|
|
44602
|
-
* - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
|
|
44603
|
-
* transformer) + UDS MsgPack both round-trip typed arrays — already used by
|
|
44604
|
-
* `storage` / `storage-provider` / `recording` caps over the same path. No
|
|
44605
|
-
* base64 fallback needed.
|
|
44606
|
-
*
|
|
44607
|
-
* TODO (deferred, closed-set change — separate decision): add
|
|
44608
|
-
* `providerKind: 'notify'` so notification providers surface on the unified
|
|
44609
|
-
* admin "Integrations" page.
|
|
44610
|
-
*/
|
|
44611
|
-
/**
|
|
44612
|
-
* Zentik-derived typed-media enum — the superset across every kind. Each
|
|
44613
|
-
* adapter picks what it supports and the degrade engine filters the rest.
|
|
44614
|
-
*/
|
|
44615
|
-
var AttachmentMediaTypeSchema = _enum([
|
|
44616
|
-
"image",
|
|
44617
|
-
"video",
|
|
44618
|
-
"gif",
|
|
44619
|
-
"audio",
|
|
44620
|
-
"icon"
|
|
44621
|
-
]);
|
|
44622
|
-
/**
|
|
44623
|
-
* A single attachment. Exactly one of `url` (remote source, most adapters
|
|
44624
|
-
* prefer this) or `bytes` (inline source; required for Pushover-style
|
|
44625
|
-
* bytes-only kinds) MUST be present — the degrade engine expresses a
|
|
44626
|
-
* url→bytes fetch as a `needsFetch` directive the adapter executes.
|
|
44627
|
-
*/
|
|
44628
|
-
var AttachmentSchema = object({
|
|
44629
|
-
mediaType: AttachmentMediaTypeSchema,
|
|
44630
|
-
url: string().optional(),
|
|
44631
|
-
bytes: _instanceof(Uint8Array).optional(),
|
|
44632
|
-
mime: string().optional(),
|
|
44633
|
-
name: string().optional()
|
|
44634
|
-
}).refine((a) => a.url !== void 0 || a.bytes !== void 0, { message: "Attachment requires either `url` or `bytes`" });
|
|
44635
|
-
var NotificationFormatSchema = _enum([
|
|
44636
|
-
"text",
|
|
44637
|
-
"markdown",
|
|
44638
|
-
"html"
|
|
44639
|
-
]);
|
|
44640
|
-
/**
|
|
44641
|
-
* The CLOSED icon vocabulary an action button may use.
|
|
44642
|
-
*
|
|
44643
|
-
* A closed set, not a free string, and that is the whole point: an arbitrary
|
|
44644
|
-
* icon name is one that ntfy renders, zentik silently drops, and nobody
|
|
44645
|
-
* notices — the same class of gap as a zone vocabulary nothing produced
|
|
44646
|
-
* ([D35](../../../docs/decisions/adr-0035.md)). Every adapter maps this set or
|
|
44647
|
-
* declares `actionIcons: false` and the degrade engine strips the field.
|
|
44648
|
-
*
|
|
44649
|
-
* Named by INTENT, never by glyph. "check" would tie the vocabulary to one
|
|
44650
|
-
* renderer's icon set; "acknowledge" survives an adapter that draws it
|
|
44651
|
-
* differently.
|
|
44652
|
-
*
|
|
44653
|
-
* ── A TOKEN IS NOT A WIRE VALUE ─────────────────────────────────────
|
|
44654
|
-
*
|
|
44655
|
-
* These names are for US. **No adapter may forward one verbatim.** Each maps
|
|
44656
|
-
* the whole set onto its own renderer's vocabulary through a
|
|
44657
|
-
* `Record<NotificationActionIcon, string>` — a Record, never a lookup with a
|
|
44658
|
-
* fallback, so adding a member here fails every adapter's build until someone
|
|
44659
|
-
* decides its glyph, which is the only place that decision can be made
|
|
44660
|
-
* honestly.
|
|
44661
|
-
*
|
|
44662
|
-
* This paragraph is the bug. Zentik declared `actionIcons: true` and passed
|
|
44663
|
-
* `disarm` straight through; iOS feeds that string to
|
|
44664
|
-
* `UNNotificationActionIcon(systemImageName:)`, `disarm` is not an SF Symbol,
|
|
44665
|
-
* and every snooze and alarm button arrived BLANK. A pass-through is not a
|
|
44666
|
-
* mapping, and "the field is documented" is not "the value renders".
|
|
44667
|
-
*
|
|
44668
|
-
* Adding a member is TRAIN-BOUND. The enum lives in the published
|
|
44669
|
-
* `@camstack/server` closure and the cap seam validates against the HUB's copy,
|
|
44670
|
-
* so an addon that emits a token the running hub does not know does not lose an
|
|
44671
|
-
* icon — its whole `send` fails Zod validation and the notification never
|
|
44672
|
-
* arrives. Never emit a new token from an addon before the train carrying it.
|
|
44673
|
-
*/
|
|
44674
|
-
var NotificationActionIconSchema = _enum([
|
|
44675
|
-
"acknowledge",
|
|
44676
|
-
"dismiss",
|
|
44677
|
-
"silence",
|
|
44678
|
-
"snooze",
|
|
44679
|
-
"view",
|
|
44680
|
-
"play",
|
|
44681
|
-
"open",
|
|
44682
|
-
"close",
|
|
44683
|
-
"lock",
|
|
44684
|
-
"unlock",
|
|
44685
|
-
"arm",
|
|
44686
|
-
"arm-home",
|
|
44687
|
-
"arm-away",
|
|
44688
|
-
"arm-night",
|
|
44689
|
-
"disarm",
|
|
44690
|
-
"light",
|
|
44691
|
-
"alert",
|
|
44692
|
-
"camera"
|
|
44693
|
-
]);
|
|
44694
|
-
/** A single tap-through action button. */
|
|
44695
|
-
var NotificationActionSchema = object({
|
|
44696
|
-
id: string(),
|
|
44697
|
-
label: string(),
|
|
44698
|
-
url: string().optional(),
|
|
44699
|
-
/** Dropped by the degrade engine for a kind with `caps.actionIcons: false`. */
|
|
44700
|
-
icon: NotificationActionIconSchema.optional(),
|
|
44701
|
-
/**
|
|
44702
|
-
* Renders in a warning style where the notifier supports it.
|
|
44703
|
-
*
|
|
44704
|
-
* A HINT, never a gate. The callback's authority is its token and nothing
|
|
44705
|
-
* else — see `notification-center/action-token.ts` for what that does and
|
|
44706
|
-
* does not buy.
|
|
44707
|
-
*/
|
|
44708
|
-
destructive: boolean().optional(),
|
|
44709
|
-
/**
|
|
44710
|
-
* How the tap should REACH the url.
|
|
44711
|
-
*
|
|
44712
|
-
* `navigate` (absent, and every button authored before this field) opens it:
|
|
44713
|
-
* the phone leaves the notification and shows whatever the callback returns.
|
|
44714
|
-
* That is right for a button whose answer the operator wants to read.
|
|
44715
|
-
*
|
|
44716
|
-
* `background` fires it as a POST and stays put. It exists for the buttons
|
|
44717
|
-
* whose whole point is not to interrupt — "silence this for 30 minutes" is
|
|
44718
|
-
* an answer to the notification, and being thrown into a browser tab to
|
|
44719
|
-
* confirm it costs more attention than the notification did. A backend that
|
|
44720
|
-
* cannot do a background call renders it as an ordinary link (the adapters
|
|
44721
|
-
* fall back rather than dropping the button), so this is a preference, never
|
|
44722
|
-
* a requirement.
|
|
44723
|
-
*/
|
|
44724
|
-
mode: _enum(["navigate", "background"]).optional()
|
|
44725
|
-
});
|
|
44726
|
-
/** A delivery parameter value: what a notifier declared it takes. */
|
|
44727
|
-
var DeliveryParamValueSchema = union([
|
|
44728
|
-
string(),
|
|
44729
|
-
number(),
|
|
44730
|
-
boolean()
|
|
44731
|
-
]);
|
|
44732
|
-
/**
|
|
44733
|
-
* One extra delivery parameter a notifier KIND declares (D938). A rule that
|
|
44734
|
-
* addresses a target of that kind may set it; a kind that declares nothing is
|
|
44735
|
-
* never handed one. The admin UI derives its control from this descriptor —
|
|
44736
|
-
* no editor knows a service by name.
|
|
44737
|
-
*
|
|
44738
|
-
* Optional fields are `.optional()`, never `.default()` (a Zod default does not
|
|
44739
|
-
* run on the addon cap path).
|
|
44740
|
-
*/
|
|
44741
|
-
var DeliveryParamSchema = object({
|
|
44742
|
-
key: string().min(1),
|
|
44743
|
-
label: string(),
|
|
44744
|
-
/** i18n key of the label, resolved by the declaring addon's namespace. */
|
|
44745
|
-
labelKey: string().optional(),
|
|
44746
|
-
type: _enum([
|
|
44747
|
-
"enum",
|
|
44748
|
-
"number",
|
|
44749
|
-
"boolean",
|
|
44750
|
-
"string"
|
|
44751
|
-
]),
|
|
44752
|
-
/** `enum` only: the closed set of accepted values. */
|
|
44753
|
-
options: array(object({
|
|
44754
|
-
value: string(),
|
|
44755
|
-
label: string()
|
|
44756
|
-
})).optional(),
|
|
44757
|
-
/** `number` only. */
|
|
44758
|
-
min: number().optional(),
|
|
44759
|
-
max: number().optional(),
|
|
44760
|
-
/** What the notifier does when the rule sets nothing; shown as the placeholder. */
|
|
44761
|
-
default: DeliveryParamValueSchema.optional()
|
|
44762
|
-
});
|
|
44763
|
-
/**
|
|
44764
|
-
* The canonical notification. `body` is the only hard field (Apprise model).
|
|
44765
|
-
* `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
|
|
44766
|
-
* NOT a fixed severity enum — each kind declares its own `caps.levels` and
|
|
44767
|
-
* the adapter maps this ordinal onto its native level. `level?` is an
|
|
44768
|
-
* optional kind-native level id (`emergency`, `silent`, …) that overrides
|
|
44769
|
-
* `priority` for that one target.
|
|
44770
|
-
*/
|
|
44771
|
-
var NotificationSchema = object({
|
|
44772
|
-
body: string(),
|
|
44773
|
-
title: string().optional(),
|
|
44774
|
-
format: NotificationFormatSchema.default("text"),
|
|
44775
|
-
priority: number().int().min(1).max(5).default(3),
|
|
44776
|
-
level: string().optional(),
|
|
44777
|
-
attachments: array(AttachmentSchema).optional(),
|
|
44778
|
-
clickUrl: string().optional(),
|
|
44779
|
-
actions: array(NotificationActionSchema).optional(),
|
|
44780
|
-
sound: string().optional(),
|
|
44781
|
-
ttl: number().optional(),
|
|
44782
|
-
tag: string().optional(),
|
|
44783
|
-
deviceId: number().optional(),
|
|
44784
|
-
eventId: string().optional(),
|
|
44785
|
-
metadata: record(string(), unknown()).optional(),
|
|
44786
|
-
/**
|
|
44787
|
-
* Values for the parameters the target's kind DECLARES in
|
|
44788
|
-
* {@link TargetKindSchema} `deliveryParams`. Already validated against the
|
|
44789
|
-
* declaration by the sender; a notifier reads only the keys it declared.
|
|
44790
|
-
*/
|
|
44791
|
-
delivery: record(string(), DeliveryParamValueSchema).optional()
|
|
44792
|
-
});
|
|
44793
|
-
/** One declared native severity/priority level for a kind. */
|
|
44794
|
-
var TargetKindLevelSchema = object({
|
|
44795
|
-
id: string(),
|
|
44796
|
-
label: string(),
|
|
44797
|
-
/** Which canonical priority (1..5) this level maps to. `null` = qualitative-only. */
|
|
44798
|
-
ordinal: number().int().min(1).max(5).nullable(),
|
|
44799
|
-
flags: object({
|
|
44800
|
-
critical: boolean().optional(),
|
|
44801
|
-
silent: boolean().optional(),
|
|
44802
|
-
noPush: boolean().optional()
|
|
44803
|
-
}).optional(),
|
|
44804
|
-
/** e.g. Pushover `emergency` requires `retry` / `expire`. */
|
|
44805
|
-
requires: array(string()).optional(),
|
|
44806
|
-
description: string().optional()
|
|
44807
|
-
});
|
|
44808
|
-
/** The full capability block consulted before dispatch. */
|
|
44809
|
-
var TargetKindCapsSchema = object({
|
|
44810
|
-
attachments: object({
|
|
44811
|
-
mediaTypes: array(AttachmentMediaTypeSchema),
|
|
44812
|
-
mode: _enum([
|
|
44813
|
-
"url",
|
|
44814
|
-
"bytes",
|
|
44815
|
-
"both"
|
|
44816
|
-
]),
|
|
44817
|
-
max: number().int().nonnegative(),
|
|
44818
|
-
maxBytes: number().int().positive().optional()
|
|
44819
|
-
}),
|
|
44820
|
-
/** Max action buttons (0 = none). */
|
|
44821
|
-
actions: number().int().nonnegative(),
|
|
44822
|
-
/**
|
|
44823
|
-
* Whether this kind renders a per-action ICON.
|
|
44824
|
-
*
|
|
44825
|
-
* `.optional()`, deliberately NOT `.default(false)`: a Zod default does not
|
|
44826
|
-
* run on the addon cap path — three production failures in one day taught
|
|
44827
|
-
* this repo that once. Absent is read as false by the degrade engine, which
|
|
44828
|
-
* is the safe direction: an icon that is not rendered costs nothing, an icon
|
|
44829
|
-
* assumed and dropped costs the operator's trust in the field.
|
|
44830
|
-
*/
|
|
44831
|
-
actionIcons: boolean().optional(),
|
|
44832
|
-
levels: array(TargetKindLevelSchema),
|
|
44833
|
-
format: array(NotificationFormatSchema),
|
|
44834
|
-
clickUrl: boolean(),
|
|
44835
|
-
sound: boolean(),
|
|
44836
|
-
ttl: boolean(),
|
|
44837
|
-
bodyMaxLen: number().int().positive()
|
|
44838
|
-
});
|
|
44839
|
-
/**
|
|
44840
|
-
* `configSchema` is a `ConfigUISchema` tree passed through to the admin
|
|
44841
|
-
* FormBuilder. Stored as `z.unknown()` at the cap seam (mirrors
|
|
44842
|
-
* `device-provider.getChildCreationSchema` `CreationSchemaOutputSchema`) —
|
|
44843
|
-
* the union is large and not meant for runtime validation here; the exported
|
|
44844
|
-
* `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
|
|
44845
|
-
*/
|
|
44846
|
-
var ConfigSchemaPassthrough$2 = unknown();
|
|
44847
|
-
var TargetKindSchema = object({
|
|
44848
|
-
kind: string(),
|
|
44849
|
-
label: string(),
|
|
44850
|
-
icon: string(),
|
|
44851
|
-
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
44852
|
-
addonId: string(),
|
|
44853
|
-
/**
|
|
44854
|
-
* URL of the kind's bundled BRAND icon, served by the providing addon over
|
|
44855
|
-
* its own `addon-routes` surface (`/addon/<addonId>/icons/<kind>`). Absent
|
|
44856
|
-
* when the addon bundles no icon for that kind — the client then falls back
|
|
44857
|
-
* to a neutral glyph rather than rendering the raw `icon` NAME as text.
|
|
44858
|
-
*
|
|
44859
|
-
* Root-relative on purpose: it resolves against whatever origin serves a web
|
|
44860
|
-
* client, and a native client joins it onto its own hub base.
|
|
44861
|
-
*
|
|
44862
|
-
* DECLARED here deliberately. It used to travel as an undeclared passthrough
|
|
44863
|
-
* field that survived only because the runtime cap-router forwards provider
|
|
44864
|
-
* output verbatim — so every consumer had to re-declare it by hand to stop
|
|
44865
|
-
* its own Zod parse from stripping it, and the whole arrangement would have
|
|
44866
|
-
* broken silently the moment output validation was tightened anywhere.
|
|
44867
|
-
*/
|
|
44868
|
-
iconUrl: string().optional(),
|
|
44883
|
+
var GetLoadSeriesInputSchema = object({
|
|
44869
44884
|
/**
|
|
44870
|
-
*
|
|
44871
|
-
*
|
|
44872
|
-
* The server knows this and therefore says it, because the client cannot
|
|
44873
|
-
* safely guess: a React-Native client renders SVG and raster through two
|
|
44874
|
-
* DIFFERENT components (`react-native-svg` vs `expo-image` — expo-image does
|
|
44875
|
-
* not decode SVG on iOS/Android), so without this it silently fell back to a
|
|
44876
|
-
* placeholder glyph for every vector icon while the web build looked fine.
|
|
44885
|
+
* The node whose series is wanted.
|
|
44877
44886
|
*
|
|
44878
|
-
*
|
|
44879
|
-
*
|
|
44880
|
-
*
|
|
44887
|
+
* NOT named `nodeId`: the generated cap router strips a top-level
|
|
44888
|
+
* `nodeId` from every method input and uses it to ROUTE the call to
|
|
44889
|
+
* that node's provider (`generated-cap-routers.ts`). A series target
|
|
44890
|
+
* called `nodeId` would silently become a routing pin and never reach
|
|
44891
|
+
* the provider. The hub holds every node it hears from, so the
|
|
44892
|
+
* ordinary call is unpinned — answered by the hub, for any node.
|
|
44881
44893
|
*/
|
|
44882
|
-
|
|
44883
|
-
configSchema: ConfigSchemaPassthrough$2,
|
|
44894
|
+
forNodeId: string(),
|
|
44884
44895
|
/**
|
|
44885
|
-
*
|
|
44886
|
-
*
|
|
44887
|
-
*
|
|
44888
|
-
* editor uses this to ask for the secret on exactly those edits instead of
|
|
44889
|
-
* on every edit.
|
|
44890
|
-
*
|
|
44891
|
-
* Optional: absent from a provider that holds no secret (the Home Assistant
|
|
44892
|
-
* kinds) and from a provider older than this field — an editor that finds
|
|
44893
|
-
* it absent must assume ANY edit may need the secret.
|
|
44896
|
+
* EXCLUSIVE lower bound. A caller passes the newest `atMs` it already
|
|
44897
|
+
* holds and receives only what it is missing, so seeding a live chart
|
|
44898
|
+
* from this method cannot double a point already drawn.
|
|
44894
44899
|
*/
|
|
44895
|
-
|
|
44896
|
-
supportsDiscovery: boolean(),
|
|
44900
|
+
sinceMs: number().optional(),
|
|
44897
44901
|
/**
|
|
44898
|
-
*
|
|
44899
|
-
*
|
|
44902
|
+
* Most points the caller wants PER FUNCTION. The window is reduced to fit,
|
|
44903
|
+
* preserving min and max per bucket.
|
|
44904
|
+
*
|
|
44905
|
+
* Absent means NO reduction — legitimate for a short window and a trap for a
|
|
44906
|
+
* long one, which is why a chart passes its own pixel width.
|
|
44900
44907
|
*/
|
|
44901
|
-
|
|
44902
|
-
|
|
44908
|
+
maxPoints: number().int().positive().optional()
|
|
44909
|
+
});
|
|
44910
|
+
var SystemMetricsSchema = object({
|
|
44911
|
+
cpuPercent: number(),
|
|
44912
|
+
/** `null` when the memory sample failed or was not taken yet (D393). */
|
|
44913
|
+
memoryPercent: number().nullable(),
|
|
44914
|
+
memoryUsedMB: number().nullable(),
|
|
44915
|
+
memoryTotalMB: number(),
|
|
44916
|
+
diskPercent: number().optional(),
|
|
44917
|
+
temperature: number().optional(),
|
|
44918
|
+
gpuPercent: number().optional(),
|
|
44919
|
+
gpuMemoryPercent: number().optional()
|
|
44920
|
+
});
|
|
44921
|
+
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);
|
|
44922
|
+
method(object({
|
|
44923
|
+
sourceUrl: string(),
|
|
44924
|
+
metadata: ModelConvertMetadataSchema,
|
|
44925
|
+
targets: array(ConvertTargetSchema).min(1).readonly(),
|
|
44926
|
+
calibrationRef: string().optional(),
|
|
44927
|
+
sessionId: string().optional()
|
|
44928
|
+
}), ConvertResultSchema, {
|
|
44929
|
+
kind: "mutation",
|
|
44930
|
+
auth: "admin",
|
|
44931
|
+
timeoutMs: 6e5
|
|
44932
|
+
});
|
|
44933
|
+
method(object({
|
|
44934
|
+
targetNodeId: string(),
|
|
44935
|
+
modelId: string(),
|
|
44936
|
+
format: _enum(MODEL_FORMATS),
|
|
44937
|
+
entry: ModelCatalogEntrySchema
|
|
44938
|
+
}), object({
|
|
44939
|
+
ok: boolean(),
|
|
44940
|
+
/** sha256 of the staged tarball (empty for a hub-local no-op). */
|
|
44941
|
+
sha256: string(),
|
|
44942
|
+
bytes: number(),
|
|
44943
|
+
/** The target node's modelsDir the artifact landed in. */
|
|
44944
|
+
path: string()
|
|
44945
|
+
}), {
|
|
44946
|
+
kind: "mutation",
|
|
44947
|
+
auth: "admin"
|
|
44948
|
+
});
|
|
44949
|
+
var MotionRegionSchema = object({
|
|
44950
|
+
bbox: BoundingBoxSchema,
|
|
44951
|
+
pixelCount: number(),
|
|
44952
|
+
intensity: number()
|
|
44953
|
+
});
|
|
44954
|
+
var MotionAnalysisResultSchema = object({
|
|
44955
|
+
detected: boolean(),
|
|
44956
|
+
regionCount: number(),
|
|
44957
|
+
/** Regions passing minArea filter — used for pipeline triggering. */
|
|
44958
|
+
regions: array(MotionRegionSchema).readonly(),
|
|
44959
|
+
/** All raw regions from CCL before minArea filter — used for UI debug overlay. */
|
|
44960
|
+
rawRegions: array(MotionRegionSchema).readonly(),
|
|
44961
|
+
frameWidth: number(),
|
|
44962
|
+
frameHeight: number(),
|
|
44963
|
+
analysisMs: number()
|
|
44964
|
+
});
|
|
44965
|
+
DeviceType.Camera, method(object({
|
|
44966
|
+
deviceId: number(),
|
|
44967
|
+
frame: FrameInputSchema.optional(),
|
|
44968
|
+
frameHandle: FrameHandleSchema.optional()
|
|
44969
|
+
}), MotionAnalysisResultSchema, {
|
|
44970
|
+
role: "admin",
|
|
44971
|
+
kind: "mutation"
|
|
44972
|
+
}), method(object({ deviceId: number() }), _void(), {
|
|
44973
|
+
role: "admin",
|
|
44974
|
+
kind: "mutation"
|
|
44975
|
+
}), method(_void(), _void(), {
|
|
44976
|
+
role: "admin",
|
|
44977
|
+
kind: "mutation"
|
|
44978
|
+
}), object({
|
|
44979
|
+
deviceId: number(),
|
|
44980
|
+
detected: boolean(),
|
|
44981
|
+
regionCount: number()
|
|
44903
44982
|
});
|
|
44904
44983
|
/**
|
|
44905
|
-
*
|
|
44906
|
-
*
|
|
44907
|
-
*
|
|
44984
|
+
* `mqtt-broker` — broker-registry cap.
|
|
44985
|
+
*
|
|
44986
|
+
* NOT a pub/sub proxy. The cap exposes (a) a registry of configured
|
|
44987
|
+
* MQTT brokers (external + optionally an embedded `aedes`-backed one)
|
|
44988
|
+
* and (b) the connection details a consumer addon needs to spin up
|
|
44989
|
+
* its OWN `mqtt.js` client.
|
|
44990
|
+
*
|
|
44991
|
+
* Why: pub/sub routing over the system event-bus loses fidelity
|
|
44992
|
+
* (callback shape, QoS guarantees, will/retain semantics) and adds
|
|
44993
|
+
* refcount bookkeeping that addons would rather own themselves. The
|
|
44994
|
+
* canonical consumer needs raw `mqtt.js`
|
|
44995
|
+
* features anyway — give it the connection config, get out of the way.
|
|
44996
|
+
*
|
|
44997
|
+
* Consumer flow:
|
|
44998
|
+
* const cfg = await ctx.api.mqttBroker.getBrokerConfig({ id })
|
|
44999
|
+
* const client = mqtt.connect(cfg.url, { username: cfg.username, … })
|
|
45000
|
+
* client.subscribe('zigbee2mqtt/+')
|
|
45001
|
+
*
|
|
45002
|
+
* Collection mode: multiple brokers (e.g. one local mosquitto + one
|
|
45003
|
+
* cloud bridge). The "embedded" entry (when present) is just another
|
|
45004
|
+
* broker in the registry — its lifecycle is owned by the addon that
|
|
45005
|
+
* spawned it.
|
|
44908
45006
|
*/
|
|
44909
|
-
var
|
|
45007
|
+
var BrokerKindSchema = _enum(["external", "embedded"]);
|
|
45008
|
+
/**
|
|
45009
|
+
* Broker live-probe status.
|
|
45010
|
+
*
|
|
45011
|
+
* - `connected` — last probe completed a clean CONNACK
|
|
45012
|
+
* - `disconnected` — no probe has run yet (cold cache)
|
|
45013
|
+
* - `auth-failed` — CONNACK refused with auth error (RC 4 / 5)
|
|
45014
|
+
* - `unreachable` — TCP connect timed out / refused
|
|
45015
|
+
* - `tls-error` — TLS handshake failed (cert / SNI / cipher)
|
|
45016
|
+
*/
|
|
45017
|
+
var BrokerStatusSchema$1 = _enum([
|
|
45018
|
+
"connected",
|
|
45019
|
+
"disconnected",
|
|
45020
|
+
"auth-failed",
|
|
45021
|
+
"unreachable",
|
|
45022
|
+
"tls-error"
|
|
45023
|
+
]);
|
|
45024
|
+
var BrokerInfoSchema$1 = object({
|
|
44910
45025
|
id: string(),
|
|
44911
45026
|
name: string(),
|
|
44912
|
-
|
|
44913
|
-
|
|
44914
|
-
|
|
44915
|
-
|
|
44916
|
-
});
|
|
44917
|
-
/** A discovery-surfaced candidate (config is partial + non-secret). */
|
|
44918
|
-
var DiscoveredTargetSchema = object({
|
|
44919
|
-
kind: string(),
|
|
44920
|
-
suggestedName: string(),
|
|
44921
|
-
config: record(string(), unknown())
|
|
44922
|
-
});
|
|
44923
|
-
/** The degrade engine's report — what was resolved / dropped / degraded. */
|
|
44924
|
-
var RenderedAsSchema = object({
|
|
44925
|
-
level: string(),
|
|
44926
|
-
format: NotificationFormatSchema,
|
|
44927
|
-
attachmentsSent: number().int().nonnegative(),
|
|
44928
|
-
actionsSent: number().int().nonnegative(),
|
|
44929
|
-
truncated: boolean(),
|
|
44930
|
-
dropped: array(string())
|
|
44931
|
-
});
|
|
44932
|
-
var SendResultSchema = object({
|
|
44933
|
-
success: boolean(),
|
|
45027
|
+
url: string(),
|
|
45028
|
+
kind: BrokerKindSchema,
|
|
45029
|
+
status: BrokerStatusSchema$1,
|
|
45030
|
+
latencyMs: number().nullable(),
|
|
44934
45031
|
error: string().optional(),
|
|
44935
|
-
|
|
45032
|
+
/** Embedded brokers only: number of MQTT clients currently connected. */
|
|
45033
|
+
connectedClients: number().int().nonnegative().optional(),
|
|
45034
|
+
/** Epoch ms of the last live probe (external) or aedes snapshot (embedded). */
|
|
45035
|
+
lastCheckedAt: number().optional()
|
|
44936
45036
|
});
|
|
44937
|
-
/** Same shape as SendResult — kept as a distinct name for the test panel. */
|
|
44938
|
-
var TestResultSchema = SendResultSchema;
|
|
44939
45037
|
/**
|
|
44940
|
-
*
|
|
44941
|
-
* `
|
|
45038
|
+
* Connection details — what a consumer needs to call
|
|
45039
|
+
* `mqtt.connect(url, options)`. We split URL + credentials so the
|
|
45040
|
+
* consumer can pass them as `mqtt.connect(url, { username, password })`
|
|
45041
|
+
* instead of stuffing creds into the URL (which leaks them into logs).
|
|
44942
45042
|
*/
|
|
44943
|
-
var
|
|
44944
|
-
|
|
44945
|
-
|
|
44946
|
-
|
|
44947
|
-
stateInstance: string().optional(),
|
|
44948
|
-
error: string().optional()
|
|
44949
|
-
});
|
|
44950
|
-
method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSchema), { auth: "admin" }), method(object({ targetId: string() }), TargetSchema, { auth: "admin" }), method(object({
|
|
44951
|
-
kind: string(),
|
|
44952
|
-
config: record(string(), unknown()).optional(),
|
|
45043
|
+
var BrokerConnectionDetailsSchema = object({
|
|
45044
|
+
url: string(),
|
|
45045
|
+
username: string().optional(),
|
|
45046
|
+
password: string().optional(),
|
|
44953
45047
|
/**
|
|
44954
|
-
*
|
|
44955
|
-
*
|
|
44956
|
-
*
|
|
45048
|
+
* Suggested prefix for `clientId`. Each consumer should suffix this
|
|
45049
|
+
* with its own discriminator (addon id, instance id) so reconnects
|
|
45050
|
+
* don't kick each other off (MQTT spec: clientId must be unique per
|
|
45051
|
+
* broker).
|
|
44957
45052
|
*/
|
|
44958
|
-
|
|
44959
|
-
})
|
|
44960
|
-
|
|
44961
|
-
|
|
44962
|
-
|
|
44963
|
-
|
|
44964
|
-
|
|
44965
|
-
|
|
44966
|
-
|
|
44967
|
-
|
|
44968
|
-
|
|
44969
|
-
|
|
44970
|
-
|
|
45053
|
+
clientIdPrefix: string().optional()
|
|
45054
|
+
});
|
|
45055
|
+
var AddBrokerInputSchema = object({
|
|
45056
|
+
name: string().min(1),
|
|
45057
|
+
url: string().regex(/^(mqtt|mqtts|ws|wss):\/\//, "URL must start with mqtt(s):// or ws(s)://"),
|
|
45058
|
+
username: string().optional(),
|
|
45059
|
+
password: string().optional(),
|
|
45060
|
+
clientIdPrefix: string().optional()
|
|
45061
|
+
});
|
|
45062
|
+
var AddBrokerResultSchema = object({ id: string() });
|
|
45063
|
+
var IdInputSchema = object({ id: string() });
|
|
45064
|
+
var TestResultSchema$1 = discriminatedUnion("ok", [object({
|
|
45065
|
+
ok: literal(true),
|
|
45066
|
+
latencyMs: number()
|
|
45067
|
+
}), object({
|
|
45068
|
+
ok: literal(false),
|
|
45069
|
+
error: string()
|
|
45070
|
+
})]);
|
|
45071
|
+
var StartEmbeddedInputSchema = object({
|
|
45072
|
+
port: number().int().min(1).max(65535).default(1883),
|
|
45073
|
+
/** Allow anonymous connect (no username/password). Default: false. */
|
|
45074
|
+
allowAnonymous: boolean().default(false),
|
|
45075
|
+
/** Optional shared username/password for clients. */
|
|
45076
|
+
username: string().optional(),
|
|
45077
|
+
password: string().optional()
|
|
45078
|
+
});
|
|
45079
|
+
var StartEmbeddedResultSchema = object({
|
|
45080
|
+
id: string(),
|
|
45081
|
+
url: string()
|
|
45082
|
+
});
|
|
45083
|
+
var StatusSchema = object({
|
|
45084
|
+
brokerCount: number(),
|
|
45085
|
+
embeddedRunning: boolean()
|
|
45086
|
+
});
|
|
45087
|
+
method(_void(), array(BrokerInfoSchema$1)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
|
|
44971
45088
|
kind: "mutation",
|
|
44972
45089
|
auth: "admin"
|
|
44973
|
-
}), method(
|
|
44974
|
-
targetId: string(),
|
|
44975
|
-
sample: NotificationSchema.optional()
|
|
44976
|
-
}), TestResultSchema, {
|
|
45090
|
+
}), method(IdInputSchema, _void(), {
|
|
44977
45091
|
kind: "mutation",
|
|
44978
45092
|
auth: "admin"
|
|
44979
|
-
}), method(
|
|
44980
|
-
target: TargetSchema,
|
|
44981
|
-
/**
|
|
44982
|
-
* Duplicate flow: create a NEW target id while copying secrets from an
|
|
44983
|
-
* existing row. The UI never holds the stored token; blank / redacted
|
|
44984
|
-
* password fields are restored from this source (D634 still applies if
|
|
44985
|
-
* destinations diverge without a re-typed secret).
|
|
44986
|
-
*/
|
|
44987
|
-
cloneSecretsFrom: string().optional()
|
|
44988
|
-
}), TargetSchema, {
|
|
45093
|
+
}), method(IdInputSchema, TestResultSchema$1, {
|
|
44989
45094
|
kind: "mutation",
|
|
44990
45095
|
auth: "admin"
|
|
44991
|
-
}), method(
|
|
45096
|
+
}), method(StartEmbeddedInputSchema, StartEmbeddedResultSchema, {
|
|
44992
45097
|
kind: "mutation",
|
|
44993
45098
|
auth: "admin"
|
|
44994
|
-
}), method(
|
|
44995
|
-
targetId: string(),
|
|
44996
|
-
enabled: boolean()
|
|
44997
|
-
}), _void(), {
|
|
45099
|
+
}), method(IdInputSchema, _void(), {
|
|
44998
45100
|
kind: "mutation",
|
|
44999
45101
|
auth: "admin"
|
|
45102
|
+
}), method(_void(), StatusSchema);
|
|
45103
|
+
var NetworkEndpointSchema = object({
|
|
45104
|
+
url: string(),
|
|
45105
|
+
hostname: string(),
|
|
45106
|
+
port: number(),
|
|
45107
|
+
protocol: _enum(["http", "https"]),
|
|
45108
|
+
/**
|
|
45109
|
+
* Whether this address survives a restart of its provider. `false` = it is
|
|
45110
|
+
* re-issued every time (a Quick tunnel's random `*.trycloudflare.com`); the
|
|
45111
|
+
* hub never selects such an address AUTOMATICALLY for a role (D860), though
|
|
45112
|
+
* it stays visible and an operator may still flag it. Absent = stable: every
|
|
45113
|
+
* provider except a Quick tunnel owns a name that does not change.
|
|
45114
|
+
*/
|
|
45115
|
+
stable: boolean().optional()
|
|
45116
|
+
});
|
|
45117
|
+
object({
|
|
45118
|
+
url: string(),
|
|
45119
|
+
/** Mirrors {@link NetworkEndpointSchema} `stable`; absent = stable. */
|
|
45120
|
+
stable: boolean().optional(),
|
|
45121
|
+
updated: boolean().optional()
|
|
45122
|
+
});
|
|
45123
|
+
var NetworkAccessStatusSchema = object({
|
|
45124
|
+
connected: boolean(),
|
|
45125
|
+
endpoint: NetworkEndpointSchema.nullable(),
|
|
45126
|
+
error: string().optional()
|
|
45127
|
+
});
|
|
45128
|
+
/**
|
|
45129
|
+
* Optional, richer endpoint shape returned by providers that expose
|
|
45130
|
+
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
45131
|
+
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
45132
|
+
* the originating provider config (mode + sourcePort) so the
|
|
45133
|
+
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
45134
|
+
* one endpoint just omit `listEndpoints` from their provider impl.
|
|
45135
|
+
*/
|
|
45136
|
+
var NetworkEndpointEntrySchema = NetworkEndpointSchema.extend({
|
|
45137
|
+
/**
|
|
45138
|
+
* Stable id within the provider — typically `<mode>-<sourcePort>` so
|
|
45139
|
+
* the orchestrator can dedupe across `listEndpoints` polls.
|
|
45140
|
+
*/
|
|
45141
|
+
id: string(),
|
|
45142
|
+
/** Operator-facing label (mirrors `MeshEndpoint.label`). */
|
|
45143
|
+
label: string(),
|
|
45144
|
+
/** Optional provider-specific mode tag, used for icon/colour in admin UI. */
|
|
45145
|
+
mode: string().optional(),
|
|
45146
|
+
/** Originating local port the ingress fronts (informational). */
|
|
45147
|
+
sourcePort: number().optional()
|
|
45000
45148
|
});
|
|
45149
|
+
method(_void(), NetworkEndpointSchema, { kind: "mutation" }), method(_void(), _void(), { kind: "mutation" }), method(_void(), NetworkEndpointSchema.nullable()), method(_void(), NetworkAccessStatusSchema), method(_void(), array(NetworkEndpointEntrySchema).readonly());
|
|
45001
45150
|
var AUDIO_MACRO_LABELS = [
|
|
45002
45151
|
{
|
|
45003
45152
|
id: "speech",
|
|
@@ -51398,14 +51547,6 @@ var EngineProvisioningSchema = object({
|
|
|
51398
51547
|
*/
|
|
51399
51548
|
configIssues: array(string()).optional()
|
|
51400
51549
|
});
|
|
51401
|
-
var PipelineStepInputSchema = lazy(() => object({
|
|
51402
|
-
addonId: string(),
|
|
51403
|
-
modelId: string().optional(),
|
|
51404
|
-
enabled: boolean().default(true),
|
|
51405
|
-
children: array(PipelineStepInputSchema).optional(),
|
|
51406
|
-
settings: record(string(), unknown()).optional(),
|
|
51407
|
-
jumpDeviceKey: string().optional()
|
|
51408
|
-
}));
|
|
51409
51550
|
var ModelSubstitutionSchema = object({
|
|
51410
51551
|
addonId: string(),
|
|
51411
51552
|
chosen: string(),
|
|
@@ -51484,7 +51625,6 @@ var ConfigUISchemaBridge = custom();
|
|
|
51484
51625
|
var ConfigUISchemaNullableBridge = custom();
|
|
51485
51626
|
var InferenceCapabilitiesBridge = custom();
|
|
51486
51627
|
var ModelAvailabilityListBridge = custom();
|
|
51487
|
-
var PipelineRunResultBridge = custom();
|
|
51488
51628
|
method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
|
|
51489
51629
|
modelId: string(),
|
|
51490
51630
|
settings: record(string(), unknown()).readonly()
|
|
@@ -59158,7 +59298,7 @@ object({
|
|
|
59158
59298
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
59159
59299
|
lastFetchedAt: number()
|
|
59160
59300
|
});
|
|
59161
|
-
var DeviceIdSchema = number().int().nonnegative();
|
|
59301
|
+
var DeviceIdSchema$1 = number().int().nonnegative();
|
|
59162
59302
|
/** A value a program option or setting can take. */
|
|
59163
59303
|
var DishwasherValueSchema = union([
|
|
59164
59304
|
boolean(),
|
|
@@ -59222,77 +59362,77 @@ var DishwasherOptionsSchema = object({
|
|
|
59222
59362
|
options: array(DishwasherOptionDescriptorSchema)
|
|
59223
59363
|
});
|
|
59224
59364
|
DeviceType.Dishwasher, method(object({
|
|
59225
|
-
deviceId: DeviceIdSchema,
|
|
59365
|
+
deviceId: DeviceIdSchema$1,
|
|
59226
59366
|
program: string().min(1).optional(),
|
|
59227
59367
|
options: record(string(), DishwasherValueSchema).optional()
|
|
59228
59368
|
}), _void(), {
|
|
59229
59369
|
kind: "mutation",
|
|
59230
59370
|
auth: "protected"
|
|
59231
|
-
}), method(object({ deviceId: DeviceIdSchema }), _void(), {
|
|
59371
|
+
}), method(object({ deviceId: DeviceIdSchema$1 }), _void(), {
|
|
59232
59372
|
kind: "mutation",
|
|
59233
59373
|
auth: "protected"
|
|
59234
|
-
}), method(object({ deviceId: DeviceIdSchema }), _void(), {
|
|
59374
|
+
}), method(object({ deviceId: DeviceIdSchema$1 }), _void(), {
|
|
59235
59375
|
kind: "mutation",
|
|
59236
59376
|
auth: "protected"
|
|
59237
|
-
}), method(object({ deviceId: DeviceIdSchema }), _void(), {
|
|
59377
|
+
}), method(object({ deviceId: DeviceIdSchema$1 }), _void(), {
|
|
59238
59378
|
kind: "mutation",
|
|
59239
59379
|
auth: "protected"
|
|
59240
59380
|
}), method(object({
|
|
59241
|
-
deviceId: DeviceIdSchema,
|
|
59381
|
+
deviceId: DeviceIdSchema$1,
|
|
59242
59382
|
program: string().min(1)
|
|
59243
59383
|
}), _void(), {
|
|
59244
59384
|
kind: "mutation",
|
|
59245
59385
|
auth: "protected"
|
|
59246
59386
|
}), method(object({
|
|
59247
|
-
deviceId: DeviceIdSchema,
|
|
59387
|
+
deviceId: DeviceIdSchema$1,
|
|
59248
59388
|
on: boolean()
|
|
59249
59389
|
}), _void(), {
|
|
59250
59390
|
kind: "mutation",
|
|
59251
59391
|
auth: "protected"
|
|
59252
59392
|
}), method(object({
|
|
59253
|
-
deviceId: DeviceIdSchema,
|
|
59393
|
+
deviceId: DeviceIdSchema$1,
|
|
59254
59394
|
on: boolean()
|
|
59255
59395
|
}), _void(), {
|
|
59256
59396
|
kind: "mutation",
|
|
59257
59397
|
auth: "protected"
|
|
59258
59398
|
}), method(object({
|
|
59259
|
-
deviceId: DeviceIdSchema,
|
|
59399
|
+
deviceId: DeviceIdSchema$1,
|
|
59260
59400
|
on: boolean()
|
|
59261
59401
|
}), _void(), {
|
|
59262
59402
|
kind: "mutation",
|
|
59263
59403
|
auth: "protected"
|
|
59264
59404
|
}), method(object({
|
|
59265
|
-
deviceId: DeviceIdSchema,
|
|
59405
|
+
deviceId: DeviceIdSchema$1,
|
|
59266
59406
|
on: boolean()
|
|
59267
59407
|
}), _void(), {
|
|
59268
59408
|
kind: "mutation",
|
|
59269
59409
|
auth: "protected"
|
|
59270
59410
|
}), method(object({
|
|
59271
|
-
deviceId: DeviceIdSchema,
|
|
59411
|
+
deviceId: DeviceIdSchema$1,
|
|
59272
59412
|
on: boolean()
|
|
59273
59413
|
}), _void(), {
|
|
59274
59414
|
kind: "mutation",
|
|
59275
59415
|
auth: "protected"
|
|
59276
59416
|
}), method(object({
|
|
59277
|
-
deviceId: DeviceIdSchema,
|
|
59417
|
+
deviceId: DeviceIdSchema$1,
|
|
59278
59418
|
on: boolean()
|
|
59279
59419
|
}), _void(), {
|
|
59280
59420
|
kind: "mutation",
|
|
59281
59421
|
auth: "protected"
|
|
59282
59422
|
}), method(object({
|
|
59283
|
-
deviceId: DeviceIdSchema,
|
|
59423
|
+
deviceId: DeviceIdSchema$1,
|
|
59284
59424
|
on: boolean()
|
|
59285
59425
|
}), _void(), {
|
|
59286
59426
|
kind: "mutation",
|
|
59287
59427
|
auth: "protected"
|
|
59288
59428
|
}), method(object({
|
|
59289
|
-
deviceId: DeviceIdSchema,
|
|
59429
|
+
deviceId: DeviceIdSchema$1,
|
|
59290
59430
|
key: string().min(1),
|
|
59291
59431
|
value: DishwasherValueSchema
|
|
59292
59432
|
}), _void(), {
|
|
59293
59433
|
kind: "mutation",
|
|
59294
59434
|
auth: "protected"
|
|
59295
|
-
}), method(object({ deviceId: DeviceIdSchema }), DishwasherOptionsSchema, { auth: "protected" });
|
|
59435
|
+
}), method(object({ deviceId: DeviceIdSchema$1 }), DishwasherOptionsSchema, { auth: "protected" });
|
|
59296
59436
|
DeviceType.Camera;
|
|
59297
59437
|
object({
|
|
59298
59438
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
@@ -61730,7 +61870,8 @@ var TopologyNodeSchema = object({
|
|
|
61730
61870
|
isHub: boolean(),
|
|
61731
61871
|
isOnline: boolean(),
|
|
61732
61872
|
cpuPercent: number(),
|
|
61733
|
-
|
|
61873
|
+
/** `null` when the node's memory read failed or it has not reported one (D393). */
|
|
61874
|
+
memoryPercent: number().nullable(),
|
|
61734
61875
|
uptime: number(),
|
|
61735
61876
|
lastSeen: string(),
|
|
61736
61877
|
localIps: array(string()).readonly(),
|
|
@@ -62265,9 +62406,10 @@ object({
|
|
|
62265
62406
|
* combined reading; per-hopper levels live in `food1`/`food2`. Null when
|
|
62266
62407
|
* the device has not reported yet. */
|
|
62267
62408
|
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
62268
|
-
/** Food in the BOWL
|
|
62269
|
-
* feeder
|
|
62270
|
-
|
|
62409
|
+
/** Food in the BOWL, a mass (stored in kilograms, D944). Reported only by a
|
|
62410
|
+
* feeder with a bowl scale; null when the model has none or its reading is
|
|
62411
|
+
* of an unproven unit. */
|
|
62412
|
+
bowlFood: number().nullable().meta(readingMeta("mass")),
|
|
62271
62413
|
/** True while the pet is eating (`state.eating`). */
|
|
62272
62414
|
eating: boolean(),
|
|
62273
62415
|
/** Whether `markFoodReplenished` does anything on this model. When false
|
|
@@ -62380,6 +62522,64 @@ DeviceType.PetFeeder, method(object({
|
|
|
62380
62522
|
kind: "mutation",
|
|
62381
62523
|
auth: "protected"
|
|
62382
62524
|
});
|
|
62525
|
+
object({
|
|
62526
|
+
/** Water in the tank, 0..100 (%). Null while the source has not reported. */
|
|
62527
|
+
waterLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
62528
|
+
/** Water in the tank, in litres. Null while the source has not reported. */
|
|
62529
|
+
waterVolume: number().min(0).nullable().meta(readingMeta("volume")),
|
|
62530
|
+
/** True when the tank is empty. Null while unknown. */
|
|
62531
|
+
empty: boolean().nullable(),
|
|
62532
|
+
/** True while the pump is running. Null while unknown. */
|
|
62533
|
+
pumpRunning: boolean().nullable(),
|
|
62534
|
+
/** True when the pump works on an on/off duty cycle rather than continuously. */
|
|
62535
|
+
pumpIntervalEnabled: boolean().nullable(),
|
|
62536
|
+
/** How long the pump runs per cycle, in seconds. */
|
|
62537
|
+
pumpOnTime: number().min(0).nullable().meta(readingMeta("duration")),
|
|
62538
|
+
/** How long the pump rests per cycle, in seconds. */
|
|
62539
|
+
pumpOffTime: number().min(0).nullable().meta(readingMeta("duration")),
|
|
62540
|
+
/** Water drunk in the last drink, in litres. */
|
|
62541
|
+
lastDrink: number().min(0).nullable().meta(readingMeta("volume")),
|
|
62542
|
+
/** Water drunk in the current hour, in litres. */
|
|
62543
|
+
currentHourDrink: number().min(0).nullable().meta(readingMeta("volume")),
|
|
62544
|
+
/** Water drunk over the last 24 hours (rolling), in litres. */
|
|
62545
|
+
last24hDrink: number().min(0).nullable().meta(readingMeta("volume")),
|
|
62546
|
+
/** Water drunk since local midnight, in litres. */
|
|
62547
|
+
todayDrink: number().min(0).nullable().meta(readingMeta("volume")),
|
|
62548
|
+
/** Decoded fault message. Null means healthy; a non-null string is an active fault. */
|
|
62549
|
+
error: string().nullable(),
|
|
62550
|
+
/** Ms epoch when the slice was last refreshed. */
|
|
62551
|
+
lastFetchedAt: number()
|
|
62552
|
+
});
|
|
62553
|
+
var DeviceIdSchema = number().int().nonnegative();
|
|
62554
|
+
var MinutesSchema = number().int().min(0);
|
|
62555
|
+
DeviceType.PetFountain, method(object({
|
|
62556
|
+
deviceId: DeviceIdSchema,
|
|
62557
|
+
on: boolean()
|
|
62558
|
+
}), _void(), {
|
|
62559
|
+
kind: "mutation",
|
|
62560
|
+
auth: "protected"
|
|
62561
|
+
}), method(object({
|
|
62562
|
+
deviceId: DeviceIdSchema,
|
|
62563
|
+
on: boolean()
|
|
62564
|
+
}), _void(), {
|
|
62565
|
+
kind: "mutation",
|
|
62566
|
+
auth: "protected"
|
|
62567
|
+
}), method(object({
|
|
62568
|
+
deviceId: DeviceIdSchema,
|
|
62569
|
+
minutes: MinutesSchema
|
|
62570
|
+
}), _void(), {
|
|
62571
|
+
kind: "mutation",
|
|
62572
|
+
auth: "protected"
|
|
62573
|
+
}), method(object({
|
|
62574
|
+
deviceId: DeviceIdSchema,
|
|
62575
|
+
minutes: MinutesSchema
|
|
62576
|
+
}), _void(), {
|
|
62577
|
+
kind: "mutation",
|
|
62578
|
+
auth: "protected"
|
|
62579
|
+
}), method(object({ deviceId: DeviceIdSchema }), _void(), {
|
|
62580
|
+
kind: "mutation",
|
|
62581
|
+
auth: "protected"
|
|
62582
|
+
});
|
|
62383
62583
|
var VehicleSchema = object({
|
|
62384
62584
|
id: string(),
|
|
62385
62585
|
name: string(),
|
|
@@ -67079,7 +67279,7 @@ discriminatedUnion("kind", [object({
|
|
|
67079
67279
|
})]);
|
|
67080
67280
|
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
67081
67281
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
67082
|
-
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;
|
|
67282
|
+
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;
|
|
67083
67283
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
67084
67284
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
67085
67285
|
new Set(CAP_NAMES);
|
|
@@ -67132,7 +67332,7 @@ var AccessoryKind = {
|
|
|
67132
67332
|
PrivacyMask: DeviceRole.PrivacyMask
|
|
67133
67333
|
};
|
|
67134
67334
|
AccessoryKind.Siren, AccessoryKind.Floodlight, AccessoryKind.Spotlight, AccessoryKind.PirSensor, AccessoryKind.Chime, AccessoryKind.Autotrack, AccessoryKind.Nightvision, AccessoryKind.PrivacyMask;
|
|
67135
|
-
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;
|
|
67335
|
+
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;
|
|
67136
67336
|
new Set(Object.values(DeviceType));
|
|
67137
67337
|
Object.freeze({
|
|
67138
67338
|
"accessories.getStatus": {
|
|
@@ -69067,6 +69267,13 @@ Object.freeze({
|
|
|
69067
69267
|
access: "create",
|
|
69068
69268
|
role: "admin"
|
|
69069
69269
|
},
|
|
69270
|
+
"deviceExport.exposeEntity": {
|
|
69271
|
+
capName: "device-export",
|
|
69272
|
+
capScope: "system",
|
|
69273
|
+
addonId: null,
|
|
69274
|
+
access: "create",
|
|
69275
|
+
role: "admin"
|
|
69276
|
+
},
|
|
69070
69277
|
"deviceExport.getDeviceLiveContribution": {
|
|
69071
69278
|
capName: "device-export",
|
|
69072
69279
|
capScope: "system",
|
|
@@ -69095,6 +69302,13 @@ Object.freeze({
|
|
|
69095
69302
|
access: "view",
|
|
69096
69303
|
role: "admin"
|
|
69097
69304
|
},
|
|
69305
|
+
"deviceExport.listExposedEntities": {
|
|
69306
|
+
capName: "device-export",
|
|
69307
|
+
capScope: "system",
|
|
69308
|
+
addonId: null,
|
|
69309
|
+
access: "view",
|
|
69310
|
+
role: "admin"
|
|
69311
|
+
},
|
|
69098
69312
|
"deviceExport.listSupportedDeviceKinds": {
|
|
69099
69313
|
capName: "device-export",
|
|
69100
69314
|
capScope: "system",
|
|
@@ -69102,6 +69316,13 @@ Object.freeze({
|
|
|
69102
69316
|
access: "view",
|
|
69103
69317
|
role: "admin"
|
|
69104
69318
|
},
|
|
69319
|
+
"deviceExport.listSupportedEntityKinds": {
|
|
69320
|
+
capName: "device-export",
|
|
69321
|
+
capScope: "system",
|
|
69322
|
+
addonId: null,
|
|
69323
|
+
access: "view",
|
|
69324
|
+
role: "admin"
|
|
69325
|
+
},
|
|
69105
69326
|
"deviceExport.unexposeDevice": {
|
|
69106
69327
|
capName: "device-export",
|
|
69107
69328
|
capScope: "system",
|
|
@@ -69109,6 +69330,13 @@ Object.freeze({
|
|
|
69109
69330
|
access: "create",
|
|
69110
69331
|
role: "admin"
|
|
69111
69332
|
},
|
|
69333
|
+
"deviceExport.unexposeEntity": {
|
|
69334
|
+
capName: "device-export",
|
|
69335
|
+
capScope: "system",
|
|
69336
|
+
addonId: null,
|
|
69337
|
+
access: "create",
|
|
69338
|
+
role: "admin"
|
|
69339
|
+
},
|
|
69112
69340
|
"deviceExtension.listCandidates": {
|
|
69113
69341
|
capName: "device-extension",
|
|
69114
69342
|
capScope: "device",
|
|
@@ -72574,6 +72802,48 @@ Object.freeze({
|
|
|
72574
72802
|
access: "create",
|
|
72575
72803
|
role: "viewer"
|
|
72576
72804
|
},
|
|
72805
|
+
"petFountain.getStatus": {
|
|
72806
|
+
capName: "pet-fountain",
|
|
72807
|
+
capScope: "device",
|
|
72808
|
+
addonId: null,
|
|
72809
|
+
access: "view",
|
|
72810
|
+
role: "viewer"
|
|
72811
|
+
},
|
|
72812
|
+
"petFountain.resetDailyConsumption": {
|
|
72813
|
+
capName: "pet-fountain",
|
|
72814
|
+
capScope: "device",
|
|
72815
|
+
addonId: null,
|
|
72816
|
+
access: "delete",
|
|
72817
|
+
role: "viewer"
|
|
72818
|
+
},
|
|
72819
|
+
"petFountain.setPump": {
|
|
72820
|
+
capName: "pet-fountain",
|
|
72821
|
+
capScope: "device",
|
|
72822
|
+
addonId: null,
|
|
72823
|
+
access: "create",
|
|
72824
|
+
role: "viewer"
|
|
72825
|
+
},
|
|
72826
|
+
"petFountain.setPumpInterval": {
|
|
72827
|
+
capName: "pet-fountain",
|
|
72828
|
+
capScope: "device",
|
|
72829
|
+
addonId: null,
|
|
72830
|
+
access: "create",
|
|
72831
|
+
role: "viewer"
|
|
72832
|
+
},
|
|
72833
|
+
"petFountain.setPumpOffMinutes": {
|
|
72834
|
+
capName: "pet-fountain",
|
|
72835
|
+
capScope: "device",
|
|
72836
|
+
addonId: null,
|
|
72837
|
+
access: "create",
|
|
72838
|
+
role: "viewer"
|
|
72839
|
+
},
|
|
72840
|
+
"petFountain.setPumpOnMinutes": {
|
|
72841
|
+
capName: "pet-fountain",
|
|
72842
|
+
capScope: "device",
|
|
72843
|
+
addonId: null,
|
|
72844
|
+
access: "create",
|
|
72845
|
+
role: "viewer"
|
|
72846
|
+
},
|
|
72577
72847
|
"pipelineAnalytics.addRetrainFrameFromRecording": {
|
|
72578
72848
|
capName: "pipeline-analytics",
|
|
72579
72849
|
capScope: "device",
|
|
@@ -79056,6 +79326,100 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
79056
79326
|
}
|
|
79057
79327
|
]
|
|
79058
79328
|
},
|
|
79329
|
+
"pet-fountain": {
|
|
79330
|
+
scope: "device",
|
|
79331
|
+
noun: t("Pet fountain", "Fontana per animali"),
|
|
79332
|
+
actions: [
|
|
79333
|
+
{
|
|
79334
|
+
id: "petFountain.pumpOn",
|
|
79335
|
+
method: "setPump",
|
|
79336
|
+
label: t("Pump on", "Pompa accesa"),
|
|
79337
|
+
phrase: t("Start the pump of {device}", "Avvia la pompa di {device}"),
|
|
79338
|
+
icon: "play",
|
|
79339
|
+
args: { on: true }
|
|
79340
|
+
},
|
|
79341
|
+
{
|
|
79342
|
+
id: "petFountain.pumpOff",
|
|
79343
|
+
method: "setPump",
|
|
79344
|
+
label: t("Pump off", "Pompa spenta"),
|
|
79345
|
+
phrase: t("Stop the pump of {device}", "Ferma la pompa di {device}"),
|
|
79346
|
+
icon: "square",
|
|
79347
|
+
args: { on: false }
|
|
79348
|
+
},
|
|
79349
|
+
{
|
|
79350
|
+
id: "petFountain.intervalOn",
|
|
79351
|
+
method: "setPumpInterval",
|
|
79352
|
+
label: t("Pump cycle on", "Ciclo pompa attivo"),
|
|
79353
|
+
phrase: t("Run the pump of {device} on its on/off cycle", "Fai lavorare la pompa di {device} a ciclo acceso/spento"),
|
|
79354
|
+
icon: "timer",
|
|
79355
|
+
args: { on: true }
|
|
79356
|
+
},
|
|
79357
|
+
{
|
|
79358
|
+
id: "petFountain.intervalOff",
|
|
79359
|
+
method: "setPumpInterval",
|
|
79360
|
+
label: t("Pump cycle off", "Ciclo pompa spento"),
|
|
79361
|
+
phrase: t("Run the pump of {device} continuously", "Fai lavorare la pompa di {device} in continuo"),
|
|
79362
|
+
icon: "timer-off",
|
|
79363
|
+
args: { on: false }
|
|
79364
|
+
},
|
|
79365
|
+
{
|
|
79366
|
+
id: "petFountain.pumpOnMinutes",
|
|
79367
|
+
method: "setPumpOnMinutes",
|
|
79368
|
+
label: t("Set pump run time", "Imposta il tempo di lavoro della pompa"),
|
|
79369
|
+
phrase: t("Set the pump of {device} to run {minutes} minutes per cycle", "Imposta la pompa di {device} a lavorare {minutes} minuti per ciclo"),
|
|
79370
|
+
icon: "timer",
|
|
79371
|
+
openArgs: [{
|
|
79372
|
+
key: "minutes",
|
|
79373
|
+
label: t("Minutes", "Minuti"),
|
|
79374
|
+
offer: {
|
|
79375
|
+
kind: "number",
|
|
79376
|
+
min: 0,
|
|
79377
|
+
step: 1,
|
|
79378
|
+
unit: "min"
|
|
79379
|
+
}
|
|
79380
|
+
}]
|
|
79381
|
+
},
|
|
79382
|
+
{
|
|
79383
|
+
id: "petFountain.pumpOffMinutes",
|
|
79384
|
+
method: "setPumpOffMinutes",
|
|
79385
|
+
label: t("Set pump rest time", "Imposta il tempo di riposo della pompa"),
|
|
79386
|
+
phrase: t("Set the pump of {device} to rest {minutes} minutes per cycle", "Imposta la pompa di {device} a riposare {minutes} minuti per ciclo"),
|
|
79387
|
+
icon: "timer-off",
|
|
79388
|
+
openArgs: [{
|
|
79389
|
+
key: "minutes",
|
|
79390
|
+
label: t("Minutes", "Minuti"),
|
|
79391
|
+
offer: {
|
|
79392
|
+
kind: "number",
|
|
79393
|
+
min: 0,
|
|
79394
|
+
step: 1,
|
|
79395
|
+
unit: "min"
|
|
79396
|
+
}
|
|
79397
|
+
}]
|
|
79398
|
+
},
|
|
79399
|
+
{
|
|
79400
|
+
id: "petFountain.resetDailyConsumption",
|
|
79401
|
+
method: "resetDailyConsumption",
|
|
79402
|
+
label: t("Clear daily consumption", "Azzera il consumo giornaliero"),
|
|
79403
|
+
phrase: t("Clear the daily water consumption of {device}", "Azzera il consumo giornaliero di acqua di {device}"),
|
|
79404
|
+
icon: "rotate-ccw"
|
|
79405
|
+
}
|
|
79406
|
+
],
|
|
79407
|
+
state: [{
|
|
79408
|
+
kind: "boolean",
|
|
79409
|
+
field: "empty",
|
|
79410
|
+
label: t("Tank empty", "Serbatoio vuoto"),
|
|
79411
|
+
whenTrue: t("When the tank of {device} is empty", "Quando il serbatoio di {device} è vuoto"),
|
|
79412
|
+
whenFalse: t("When the tank of {device} is refilled", "Quando il serbatoio di {device} viene riempito"),
|
|
79413
|
+
icon: "droplet"
|
|
79414
|
+
}, {
|
|
79415
|
+
kind: "numeric",
|
|
79416
|
+
field: "waterLevel",
|
|
79417
|
+
quantity: t("the water level", "il livello dell’acqua"),
|
|
79418
|
+
label: t("Water level", "Livello dell’acqua"),
|
|
79419
|
+
unit: "%",
|
|
79420
|
+
icon: "droplets"
|
|
79421
|
+
}]
|
|
79422
|
+
},
|
|
79059
79423
|
"media-player": {
|
|
79060
79424
|
scope: "device",
|
|
79061
79425
|
noun: t("Media player", "Lettore multimediale"),
|
|
@@ -80993,7 +81357,7 @@ function projectAction(cap, action) {
|
|
|
80993
81357
|
};
|
|
80994
81358
|
}
|
|
80995
81359
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
80996
|
-
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;
|
|
81360
|
+
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;
|
|
80997
81361
|
DeviceFeature.BatteryOperated;
|
|
80998
81362
|
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
80999
81363
|
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.";
|
|
@@ -82544,6 +82908,36 @@ Object.freeze({
|
|
|
82544
82908
|
form: "single",
|
|
82545
82909
|
optional: false
|
|
82546
82910
|
}],
|
|
82911
|
+
"petFountain.getStatus": [{
|
|
82912
|
+
name: "deviceId",
|
|
82913
|
+
form: "single",
|
|
82914
|
+
optional: false
|
|
82915
|
+
}],
|
|
82916
|
+
"petFountain.resetDailyConsumption": [{
|
|
82917
|
+
name: "deviceId",
|
|
82918
|
+
form: "single",
|
|
82919
|
+
optional: false
|
|
82920
|
+
}],
|
|
82921
|
+
"petFountain.setPump": [{
|
|
82922
|
+
name: "deviceId",
|
|
82923
|
+
form: "single",
|
|
82924
|
+
optional: false
|
|
82925
|
+
}],
|
|
82926
|
+
"petFountain.setPumpInterval": [{
|
|
82927
|
+
name: "deviceId",
|
|
82928
|
+
form: "single",
|
|
82929
|
+
optional: false
|
|
82930
|
+
}],
|
|
82931
|
+
"petFountain.setPumpOffMinutes": [{
|
|
82932
|
+
name: "deviceId",
|
|
82933
|
+
form: "single",
|
|
82934
|
+
optional: false
|
|
82935
|
+
}],
|
|
82936
|
+
"petFountain.setPumpOnMinutes": [{
|
|
82937
|
+
name: "deviceId",
|
|
82938
|
+
form: "single",
|
|
82939
|
+
optional: false
|
|
82940
|
+
}],
|
|
82547
82941
|
"pipelineAnalytics.addRetrainFrameFromRecording": [{
|
|
82548
82942
|
name: "deviceId",
|
|
82549
82943
|
form: "single",
|
|
@@ -85202,4 +85596,4 @@ object({
|
|
|
85202
85596
|
commands: record(string(), unknown())
|
|
85203
85597
|
});
|
|
85204
85598
|
//#endregion
|
|
85205
|
-
export { record as C, object as S, isSecretClear as _,
|
|
85599
|
+
export { record as C, object as S, isSecretClear as _, parseTrainingEventLine as a, boolean as b, BaseAddon as c, addonPagesSourceCapability as d, arrayItemFieldPath as f, globalSecretScope as g, entryBody as h, TrainingResultSchema as i, RECORD_MAX_DATA_BYTES as l, defineRecordKinds as m, TrainingJobSchema as n, trainingCapability as o, defineEntryKind as p, TrainingJobSpecSchema as r, trainingProviderCapability as s, TRAINING_JOB_SCHEMA as t, SECRET_CLEAR as u, isSecretMarker as v, string as w, number as x, toSecretFieldView as y };
|