@camstack/addon-training 0.1.105 → 0.1.107
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/{MotionZonesSettings-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 +6454 -6115
- package/dist/{_virtual_mf-localSharedImportMap___mfe_internal__addon_training_page-1sr2B1A2.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_training_page-BRcFqfn3.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-BzQ67_ca.js} +1261 -844
- package/dist/{dist-CCRzGEk1.mjs → dist-CJWYZwLF.mjs} +1262 -845
- package/dist/{hostInit-Cxx4Eh3M.mjs → hostInit-B2Q4U9vQ.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-CWBMcDrQ.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
|
@@ -5234,6 +5234,14 @@ function object(shape, params) {
|
|
|
5234
5234
|
...normalizeParams(params)
|
|
5235
5235
|
});
|
|
5236
5236
|
}
|
|
5237
|
+
function strictObject(shape, params) {
|
|
5238
|
+
return new ZodObject({
|
|
5239
|
+
type: "object",
|
|
5240
|
+
shape,
|
|
5241
|
+
catchall: never(),
|
|
5242
|
+
...normalizeParams(params)
|
|
5243
|
+
});
|
|
5244
|
+
}
|
|
5237
5245
|
function looseObject(shape, params) {
|
|
5238
5246
|
return new ZodObject({
|
|
5239
5247
|
type: "object",
|
|
@@ -5613,7 +5621,7 @@ var ZodIssueCode = {
|
|
|
5613
5621
|
var ZodFirstPartyTypeKind;
|
|
5614
5622
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5615
5623
|
//#endregion
|
|
5616
|
-
//#region ../types/dist/sleep-
|
|
5624
|
+
//#region ../types/dist/sleep-6eG9C8Xl.mjs
|
|
5617
5625
|
/**
|
|
5618
5626
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5619
5627
|
* window to float samples (D455).
|
|
@@ -8837,9 +8845,93 @@ function optionalMethod(input, output, options) {
|
|
|
8837
8845
|
providerOptional: true
|
|
8838
8846
|
};
|
|
8839
8847
|
}
|
|
8848
|
+
/**
|
|
8849
|
+
* `addon-pages-source` — collection cap exposing per-provider raw page
|
|
8850
|
+
* declarations. Every addon that contributes a UI page registers a
|
|
8851
|
+
* provider here. The hub-side singleton aggregator (`addon-pages` cap,
|
|
8852
|
+
* see `addon-pages.cap.ts`) walks this collection, stamps versioned
|
|
8853
|
+
* `bundleUrl` values, and returns the enriched `AddonPageInfo[]` list
|
|
8854
|
+
* that admin-ui consumes.
|
|
8855
|
+
*
|
|
8856
|
+
* The split exists because the public listing has a different output
|
|
8857
|
+
* shape than the per-provider raw declarations, and we want both ends
|
|
8858
|
+
* to flow through codegen instead of relying on a hand-written wrapper.
|
|
8859
|
+
*/
|
|
8860
|
+
var AddonPageDeclarationSchema = object({
|
|
8861
|
+
id: string(),
|
|
8862
|
+
label: string(),
|
|
8863
|
+
icon: string(),
|
|
8864
|
+
path: string(),
|
|
8865
|
+
/**
|
|
8866
|
+
* Module Federation remote name — must match the `name` field on the
|
|
8867
|
+
* page addon's `federation()` plugin config. Used by admin-ui's
|
|
8868
|
+
* `<AddonPageLoader>` to call `loadRemote('<remoteName>/page')`.
|
|
8869
|
+
* Conventionally `addon_<id>_page` (snake_case; MF names cannot
|
|
8870
|
+
* contain hyphens).
|
|
8871
|
+
*/
|
|
8872
|
+
remoteName: string(),
|
|
8873
|
+
/**
|
|
8874
|
+
* Bundle filename inside the addon's `dist/` dir served at
|
|
8875
|
+
* `/api/addon-pages/<addonId>/<bundle>`. With Module Federation this
|
|
8876
|
+
* is always `'remoteEntry.js'`; the value is kept on the metadata so
|
|
8877
|
+
* the static-file route can compute an mtime-based cache-buster URL
|
|
8878
|
+
* without a separate filesystem stat.
|
|
8879
|
+
*/
|
|
8880
|
+
bundle: string(),
|
|
8881
|
+
/**
|
|
8882
|
+
* Sidebar section this page docks into. Well-known ids: `'detection'`,
|
|
8883
|
+
* `'cluster'`, `'administration'` — the page renders inside that group.
|
|
8884
|
+
* Any OTHER string creates (or joins) a custom section rendered after
|
|
8885
|
+
* the built-in groups; its label comes from `sectionLabel` (first
|
|
8886
|
+
* declaration wins), falling back to the id. Absent → the legacy
|
|
8887
|
+
* "Addon Pages" group.
|
|
8888
|
+
*/
|
|
8889
|
+
section: string().optional(),
|
|
8890
|
+
/** Display label for a CUSTOM `section` id (ignored for well-known ids). */
|
|
8891
|
+
sectionLabel: string().optional()
|
|
8892
|
+
});
|
|
8893
|
+
var addonPagesSourceCapability = {
|
|
8894
|
+
name: "addon-pages-source",
|
|
8895
|
+
scope: "system",
|
|
8896
|
+
mode: "collection",
|
|
8897
|
+
internal: true,
|
|
8898
|
+
methods: {
|
|
8899
|
+
/**
|
|
8900
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
8901
|
+
* `data-store-provider`) — this was reachable on the AppRouter by ANY
|
|
8902
|
+
* authenticated session at the default `auth: 'protected'`. The only
|
|
8903
|
+
* consumer, the `addon-pages-aggregator` builtin, reads it via
|
|
8904
|
+
* `ctx.capabilities.getCollection('addon-pages-source')` — LOCAL-PROCESS
|
|
8905
|
+
* only, never tRPC (per `ctx.capabilities` seeing only the local
|
|
8906
|
+
* process). The public, enriched listing admin-ui actually consumes is
|
|
8907
|
+
* the separate `addon-pages` cap, unaffected by this change.
|
|
8908
|
+
*/
|
|
8909
|
+
listPages: method(_void(), array(AddonPageDeclarationSchema).readonly(), { auth: "admin" }) }
|
|
8910
|
+
};
|
|
8840
8911
|
var StaticDirOutputSchema$1 = object({ staticDir: string() });
|
|
8841
8912
|
var VersionOutputSchema$1 = object({ version: string() });
|
|
8842
8913
|
method(_void(), StaticDirOutputSchema$1, { auth: "admin" }), method(_void(), VersionOutputSchema$1, { auth: "admin" });
|
|
8914
|
+
/**
|
|
8915
|
+
* The pipeline step-input shape and the run-result bridge, in a module that
|
|
8916
|
+
* imports nothing but zod and types.
|
|
8917
|
+
*
|
|
8918
|
+
* WHY A SEPARATE FILE (addon footprint, D28): both were declared in
|
|
8919
|
+
* `pipeline-executor.cap.ts`, whose import evaluates the whole executor schema
|
|
8920
|
+
* graph. An addon that only needs these two (the benchmark's `runPipelineTest`
|
|
8921
|
+
* action) paid ~130 MB of heap at load. `pipeline-executor.cap.ts` re-exports
|
|
8922
|
+
* them, so every existing import keeps working; addon server code takes them
|
|
8923
|
+
* from `@camstack/types/addon`.
|
|
8924
|
+
*/
|
|
8925
|
+
var PipelineStepInputSchema = lazy(() => object({
|
|
8926
|
+
addonId: string(),
|
|
8927
|
+
modelId: string().optional(),
|
|
8928
|
+
enabled: boolean().default(true),
|
|
8929
|
+
children: array(PipelineStepInputSchema).optional(),
|
|
8930
|
+
settings: record(string(), unknown()).optional(),
|
|
8931
|
+
jumpDeviceKey: string().optional()
|
|
8932
|
+
}));
|
|
8933
|
+
/** Typed bridge to the recursive `FrameResult` graph; validation is structural. */
|
|
8934
|
+
var PipelineRunResultBridge = custom();
|
|
8843
8935
|
var StaticDirOutputSchema = object({ staticDir: string() });
|
|
8844
8936
|
var VersionOutputSchema = object({ version: string() });
|
|
8845
8937
|
method(_void(), StaticDirOutputSchema, { auth: "admin" }), method(_void(), VersionOutputSchema, { auth: "admin" });
|
|
@@ -9035,6 +9127,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
9035
9127
|
"osd",
|
|
9036
9128
|
"osd-manager",
|
|
9037
9129
|
"pet-feeder",
|
|
9130
|
+
"pet-fountain",
|
|
9038
9131
|
"pipeline-analytics",
|
|
9039
9132
|
"pipeline-executor",
|
|
9040
9133
|
"pipeline-orchestrator",
|
|
@@ -10314,6 +10407,56 @@ Object.freeze({
|
|
|
10314
10407
|
"valueType": "number"
|
|
10315
10408
|
}
|
|
10316
10409
|
],
|
|
10410
|
+
"pet-fountain": [
|
|
10411
|
+
{
|
|
10412
|
+
"path": "waterLevel",
|
|
10413
|
+
"valueType": "number"
|
|
10414
|
+
},
|
|
10415
|
+
{
|
|
10416
|
+
"path": "waterVolume",
|
|
10417
|
+
"valueType": "number"
|
|
10418
|
+
},
|
|
10419
|
+
{
|
|
10420
|
+
"path": "empty",
|
|
10421
|
+
"valueType": "boolean"
|
|
10422
|
+
},
|
|
10423
|
+
{
|
|
10424
|
+
"path": "pumpRunning",
|
|
10425
|
+
"valueType": "boolean"
|
|
10426
|
+
},
|
|
10427
|
+
{
|
|
10428
|
+
"path": "pumpIntervalEnabled",
|
|
10429
|
+
"valueType": "boolean"
|
|
10430
|
+
},
|
|
10431
|
+
{
|
|
10432
|
+
"path": "pumpOnTime",
|
|
10433
|
+
"valueType": "number"
|
|
10434
|
+
},
|
|
10435
|
+
{
|
|
10436
|
+
"path": "pumpOffTime",
|
|
10437
|
+
"valueType": "number"
|
|
10438
|
+
},
|
|
10439
|
+
{
|
|
10440
|
+
"path": "lastDrink",
|
|
10441
|
+
"valueType": "number"
|
|
10442
|
+
},
|
|
10443
|
+
{
|
|
10444
|
+
"path": "currentHourDrink",
|
|
10445
|
+
"valueType": "number"
|
|
10446
|
+
},
|
|
10447
|
+
{
|
|
10448
|
+
"path": "last24hDrink",
|
|
10449
|
+
"valueType": "number"
|
|
10450
|
+
},
|
|
10451
|
+
{
|
|
10452
|
+
"path": "todayDrink",
|
|
10453
|
+
"valueType": "number"
|
|
10454
|
+
},
|
|
10455
|
+
{
|
|
10456
|
+
"path": "error",
|
|
10457
|
+
"valueType": "string"
|
|
10458
|
+
}
|
|
10459
|
+
],
|
|
10317
10460
|
"power-meter": [
|
|
10318
10461
|
{
|
|
10319
10462
|
"path": "power",
|
|
@@ -10851,7 +10994,7 @@ object({
|
|
|
10851
10994
|
params: record(string(), union([string(), number()])).optional()
|
|
10852
10995
|
});
|
|
10853
10996
|
//#endregion
|
|
10854
|
-
//#region ../types/dist/err-msg-
|
|
10997
|
+
//#region ../types/dist/err-msg-DWXWc0Di.mjs
|
|
10855
10998
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
10856
10999
|
DeviceType["Camera"] = "camera";
|
|
10857
11000
|
DeviceType["Hub"] = "hub";
|
|
@@ -10943,6 +11086,10 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
10943
11086
|
* native PetKit (`nodepetkit` `FeederDevice`), reusable by other feeder
|
|
10944
11087
|
* integrations sharing the same food/desiccant/hopper surface. */
|
|
10945
11088
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
11089
|
+
/** Pet water fountain — tank level, water drunk, pump and its duty cycle.
|
|
11090
|
+
* Installed with the `pet-fountain` cap. Reaches CamStack as loose entities
|
|
11091
|
+
* of a container and is BUILT as a composed device (D967). */
|
|
11092
|
+
DeviceType["PetFountain"] = "pet-fountain";
|
|
10946
11093
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
10947
11094
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
10948
11095
|
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
@@ -11203,7 +11350,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
11203
11350
|
return DeviceRole;
|
|
11204
11351
|
}({});
|
|
11205
11352
|
//#endregion
|
|
11206
|
-
//#region ../types/dist/composition-
|
|
11353
|
+
//#region ../types/dist/composition-kSuOifuG.mjs
|
|
11207
11354
|
/**
|
|
11208
11355
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11209
11356
|
*
|
|
@@ -12288,12 +12435,28 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
|
12288
12435
|
])
|
|
12289
12436
|
})
|
|
12290
12437
|
]);
|
|
12291
|
-
var
|
|
12438
|
+
var forwardArgUnion = union([
|
|
12439
|
+
string(),
|
|
12440
|
+
number(),
|
|
12441
|
+
boolean(),
|
|
12442
|
+
strictObject({ ["$input"]: string().min(1) }),
|
|
12443
|
+
record(string().min(1), lazy(() => forwardArgUnion))
|
|
12444
|
+
]);
|
|
12445
|
+
var CompositionForwardArgSchema = forwardArgUnion;
|
|
12446
|
+
/**
|
|
12447
|
+
* `forward` (D659, amended by D967): one method of a BUILT capability is one
|
|
12448
|
+
* call of `cap.method` on `source`. Without `args` the built method's input
|
|
12449
|
+
* passes through minus `deviceId`; with `args` the template IS the source's
|
|
12450
|
+
* whole input. `deviceId` is always the source's own, never an argument.
|
|
12451
|
+
*/
|
|
12452
|
+
var CompositionForwardCommandSchema = object({
|
|
12292
12453
|
kind: literal("forward"),
|
|
12293
12454
|
source: CompositionSourceRefSchema,
|
|
12294
12455
|
cap: string().min(1),
|
|
12295
|
-
method: string().min(1)
|
|
12296
|
-
|
|
12456
|
+
method: string().min(1),
|
|
12457
|
+
args: record(string().min(1), CompositionForwardArgSchema).optional()
|
|
12458
|
+
});
|
|
12459
|
+
var CompositionCommandTargetSchema = discriminatedUnion("kind", [CompositionForwardCommandSchema, CompositionCodeSourceSchema]);
|
|
12297
12460
|
/** An item key inside an item-array cap (`consumables.items[<key>]`). */
|
|
12298
12461
|
var COMPOSITION_ITEM_KEY_RE = /^[a-z0-9][a-z0-9-]{0,47}$/;
|
|
12299
12462
|
/**
|
|
@@ -12303,7 +12466,13 @@ var COMPOSITION_ITEM_KEY_RE = /^[a-z0-9][a-z0-9-]{0,47}$/;
|
|
|
12303
12466
|
*/
|
|
12304
12467
|
var CompositionItemEntrySchema = object({
|
|
12305
12468
|
label: string().min(1).max(80),
|
|
12306
|
-
fields: record(string().min(1), CompositionFieldSourceSchema)
|
|
12469
|
+
fields: record(string().min(1), CompositionFieldSourceSchema),
|
|
12470
|
+
/**
|
|
12471
|
+
* What the cap's `reset` does for THIS item (consumables). Present = the item
|
|
12472
|
+
* is resettable and a `reset` call naming its key forwards here. The item key
|
|
12473
|
+
* selects the command, so it is never an argument: there is no pass-through.
|
|
12474
|
+
*/
|
|
12475
|
+
reset: CompositionForwardCommandSchema.optional()
|
|
12307
12476
|
});
|
|
12308
12477
|
var CompositionFeatureSchema = discriminatedUnion("kind", [object({
|
|
12309
12478
|
kind: literal("fields"),
|
|
@@ -12315,7 +12484,7 @@ var CompositionFeatureSchema = discriminatedUnion("kind", [object({
|
|
|
12315
12484
|
* owns the WHOLE array field: the composed value holds exactly these items.
|
|
12316
12485
|
*/
|
|
12317
12486
|
items: record(string().regex(COMPOSITION_ITEM_KEY_RE), CompositionItemEntrySchema).refine((items) => Object.keys(items).length <= 16, { message: `at most 16 items` }).optional(),
|
|
12318
|
-
/**
|
|
12487
|
+
/** Method name → what serves it. Only a BUILT capability takes commands (D967). */
|
|
12319
12488
|
commands: record(string().min(1), CompositionCommandTargetSchema).optional()
|
|
12320
12489
|
}), object({
|
|
12321
12490
|
kind: literal("passthrough"),
|
|
@@ -16273,163 +16442,521 @@ object({
|
|
|
16273
16442
|
lastError: string().nullable()
|
|
16274
16443
|
});
|
|
16275
16444
|
/**
|
|
16276
|
-
*
|
|
16277
|
-
* surface that admin-ui consumes through `useAddonPagesListPages()`.
|
|
16445
|
+
* notification-output — canonical, capability-gated notification delivery.
|
|
16278
16446
|
*
|
|
16279
|
-
*
|
|
16280
|
-
*
|
|
16281
|
-
*
|
|
16282
|
-
*
|
|
16283
|
-
*
|
|
16447
|
+
* Apprise-derived model (see
|
|
16448
|
+
* `docs/superpowers/specs/2026-07-03-notification-output-notifier-matrix.md`):
|
|
16449
|
+
* callers emit ONE canonical `Notification`; each provider declares a
|
|
16450
|
+
* per-kind capability descriptor (`TargetKind`), and the pure degrade
|
|
16451
|
+
* engine (`@camstack/types` `prepareNotification`) transcodes / degrades the
|
|
16452
|
+
* message to what the kind supports — callers never special-case a service.
|
|
16284
16453
|
*
|
|
16285
|
-
*
|
|
16286
|
-
*
|
|
16287
|
-
* provider
|
|
16288
|
-
*
|
|
16289
|
-
*
|
|
16454
|
+
* DESIGN DECISIONS (locked):
|
|
16455
|
+
* - Target CRUD lives on THIS cap (`upsertTarget` / `deleteTarget` /
|
|
16456
|
+
* `setTargetEnabled`), each provider persisting via the `settings-store`
|
|
16457
|
+
* cap. Rationale: the admin UI needs one uniform surface across the
|
|
16458
|
+
* notifiers addon AND the HA addon; the addon-`globalSettingsSchema`-array
|
|
16459
|
+
* alternative would fork the UI per addon and cannot host the
|
|
16460
|
+
* discovery→adopt flow.
|
|
16461
|
+
* - `listTargetKinds` / `listTargets` / `discoverTargets` return arrays →
|
|
16462
|
+
* the generated cap-mount auto-`concatCollection`-fans them across every
|
|
16463
|
+
* registered provider (notifiers addon + HA addon) so one catalog is
|
|
16464
|
+
* routable. `send` / `testTarget` / CRUD route to ONE provider by the
|
|
16465
|
+
* `addonId` the generated collection router extracts from the call input.
|
|
16466
|
+
* - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
|
|
16467
|
+
* transformer) + UDS MsgPack both round-trip typed arrays — already used by
|
|
16468
|
+
* `storage` / `storage-provider` / `recording` caps over the same path. No
|
|
16469
|
+
* base64 fallback needed.
|
|
16470
|
+
*
|
|
16471
|
+
* TODO (deferred, closed-set change — separate decision): add
|
|
16472
|
+
* `providerKind: 'notify'` so notification providers surface on the unified
|
|
16473
|
+
* admin "Integrations" page.
|
|
16290
16474
|
*/
|
|
16291
|
-
var AddonPageDeclarationSchema$1 = object({
|
|
16292
|
-
id: string(),
|
|
16293
|
-
label: string(),
|
|
16294
|
-
icon: string(),
|
|
16295
|
-
path: string(),
|
|
16296
|
-
remoteName: string(),
|
|
16297
|
-
bundle: string(),
|
|
16298
|
-
section: string().optional(),
|
|
16299
|
-
sectionLabel: string().optional()
|
|
16300
|
-
});
|
|
16301
|
-
var AddonPageInfoSchema = object({
|
|
16302
|
-
addonId: string(),
|
|
16303
|
-
page: AddonPageDeclarationSchema$1,
|
|
16304
|
-
bundleUrl: string()
|
|
16305
|
-
});
|
|
16306
|
-
method(_void(), array(AddonPageInfoSchema).readonly());
|
|
16307
16475
|
/**
|
|
16308
|
-
*
|
|
16309
|
-
*
|
|
16310
|
-
|
|
16311
|
-
|
|
16312
|
-
|
|
16313
|
-
|
|
16476
|
+
* Zentik-derived typed-media enum — the superset across every kind. Each
|
|
16477
|
+
* adapter picks what it supports and the degrade engine filters the rest.
|
|
16478
|
+
*/
|
|
16479
|
+
var AttachmentMediaTypeSchema = _enum([
|
|
16480
|
+
"image",
|
|
16481
|
+
"video",
|
|
16482
|
+
"gif",
|
|
16483
|
+
"audio",
|
|
16484
|
+
"icon"
|
|
16485
|
+
]);
|
|
16486
|
+
/**
|
|
16487
|
+
* A single attachment. Exactly one of `url` (remote source, most adapters
|
|
16488
|
+
* prefer this) or `bytes` (inline source; required for Pushover-style
|
|
16489
|
+
* bytes-only kinds) MUST be present — the degrade engine expresses a
|
|
16490
|
+
* url→bytes fetch as a `needsFetch` directive the adapter executes.
|
|
16491
|
+
*/
|
|
16492
|
+
var AttachmentSchema = object({
|
|
16493
|
+
mediaType: AttachmentMediaTypeSchema,
|
|
16494
|
+
url: string().optional(),
|
|
16495
|
+
bytes: _instanceof(Uint8Array).optional(),
|
|
16496
|
+
mime: string().optional(),
|
|
16497
|
+
name: string().optional()
|
|
16498
|
+
}).refine((a) => a.url !== void 0 || a.bytes !== void 0, { message: "Attachment requires either `url` or `bytes`" });
|
|
16499
|
+
var NotificationFormatSchema = _enum([
|
|
16500
|
+
"text",
|
|
16501
|
+
"markdown",
|
|
16502
|
+
"html"
|
|
16503
|
+
]);
|
|
16504
|
+
/**
|
|
16505
|
+
* The CLOSED icon vocabulary an action button may use.
|
|
16314
16506
|
*
|
|
16315
|
-
*
|
|
16316
|
-
*
|
|
16317
|
-
*
|
|
16507
|
+
* A closed set, not a free string, and that is the whole point: an arbitrary
|
|
16508
|
+
* icon name is one that ntfy renders, zentik silently drops, and nobody
|
|
16509
|
+
* notices — the same class of gap as a zone vocabulary nothing produced
|
|
16510
|
+
* ([D35](../../../docs/decisions/adr-0035.md)). Every adapter maps this set or
|
|
16511
|
+
* declares `actionIcons: false` and the degrade engine strips the field.
|
|
16512
|
+
*
|
|
16513
|
+
* Named by INTENT, never by glyph. "check" would tie the vocabulary to one
|
|
16514
|
+
* renderer's icon set; "acknowledge" survives an adapter that draws it
|
|
16515
|
+
* differently.
|
|
16516
|
+
*
|
|
16517
|
+
* ── A TOKEN IS NOT A WIRE VALUE ─────────────────────────────────────
|
|
16518
|
+
*
|
|
16519
|
+
* These names are for US. **No adapter may forward one verbatim.** Each maps
|
|
16520
|
+
* the whole set onto its own renderer's vocabulary through a
|
|
16521
|
+
* `Record<NotificationActionIcon, string>` — a Record, never a lookup with a
|
|
16522
|
+
* fallback, so adding a member here fails every adapter's build until someone
|
|
16523
|
+
* decides its glyph, which is the only place that decision can be made
|
|
16524
|
+
* honestly.
|
|
16525
|
+
*
|
|
16526
|
+
* This paragraph is the bug. Zentik declared `actionIcons: true` and passed
|
|
16527
|
+
* `disarm` straight through; iOS feeds that string to
|
|
16528
|
+
* `UNNotificationActionIcon(systemImageName:)`, `disarm` is not an SF Symbol,
|
|
16529
|
+
* and every snooze and alarm button arrived BLANK. A pass-through is not a
|
|
16530
|
+
* mapping, and "the field is documented" is not "the value renders".
|
|
16531
|
+
*
|
|
16532
|
+
* Adding a member is TRAIN-BOUND. The enum lives in the published
|
|
16533
|
+
* `@camstack/server` closure and the cap seam validates against the HUB's copy,
|
|
16534
|
+
* so an addon that emits a token the running hub does not know does not lose an
|
|
16535
|
+
* icon — its whole `send` fails Zod validation and the notification never
|
|
16536
|
+
* arrives. Never emit a new token from an addon before the train carrying it.
|
|
16318
16537
|
*/
|
|
16319
|
-
var
|
|
16538
|
+
var NotificationActionIconSchema = _enum([
|
|
16539
|
+
"acknowledge",
|
|
16540
|
+
"dismiss",
|
|
16541
|
+
"silence",
|
|
16542
|
+
"snooze",
|
|
16543
|
+
"view",
|
|
16544
|
+
"play",
|
|
16545
|
+
"open",
|
|
16546
|
+
"close",
|
|
16547
|
+
"lock",
|
|
16548
|
+
"unlock",
|
|
16549
|
+
"arm",
|
|
16550
|
+
"arm-home",
|
|
16551
|
+
"arm-away",
|
|
16552
|
+
"arm-night",
|
|
16553
|
+
"disarm",
|
|
16554
|
+
"light",
|
|
16555
|
+
"alert",
|
|
16556
|
+
"camera"
|
|
16557
|
+
]);
|
|
16558
|
+
/** A single tap-through action button. */
|
|
16559
|
+
var NotificationActionSchema = object({
|
|
16320
16560
|
id: string(),
|
|
16321
16561
|
label: string(),
|
|
16322
|
-
|
|
16323
|
-
|
|
16324
|
-
|
|
16325
|
-
* Module Federation remote name — must match the `name` field on the
|
|
16326
|
-
* page addon's `federation()` plugin config. Used by admin-ui's
|
|
16327
|
-
* `<AddonPageLoader>` to call `loadRemote('<remoteName>/page')`.
|
|
16328
|
-
* Conventionally `addon_<id>_page` (snake_case; MF names cannot
|
|
16329
|
-
* contain hyphens).
|
|
16330
|
-
*/
|
|
16331
|
-
remoteName: string(),
|
|
16562
|
+
url: string().optional(),
|
|
16563
|
+
/** Dropped by the degrade engine for a kind with `caps.actionIcons: false`. */
|
|
16564
|
+
icon: NotificationActionIconSchema.optional(),
|
|
16332
16565
|
/**
|
|
16333
|
-
*
|
|
16334
|
-
*
|
|
16335
|
-
*
|
|
16336
|
-
*
|
|
16337
|
-
*
|
|
16566
|
+
* Renders in a warning style where the notifier supports it.
|
|
16567
|
+
*
|
|
16568
|
+
* A HINT, never a gate. The callback's authority is its token and nothing
|
|
16569
|
+
* else — see `notification-center/action-token.ts` for what that does and
|
|
16570
|
+
* does not buy.
|
|
16338
16571
|
*/
|
|
16339
|
-
|
|
16572
|
+
destructive: boolean().optional(),
|
|
16340
16573
|
/**
|
|
16341
|
-
*
|
|
16342
|
-
*
|
|
16343
|
-
*
|
|
16344
|
-
* the
|
|
16345
|
-
*
|
|
16346
|
-
*
|
|
16574
|
+
* How the tap should REACH the url.
|
|
16575
|
+
*
|
|
16576
|
+
* `navigate` (absent, and every button authored before this field) opens it:
|
|
16577
|
+
* the phone leaves the notification and shows whatever the callback returns.
|
|
16578
|
+
* That is right for a button whose answer the operator wants to read.
|
|
16579
|
+
*
|
|
16580
|
+
* `background` fires it as a POST and stays put. It exists for the buttons
|
|
16581
|
+
* whose whole point is not to interrupt — "silence this for 30 minutes" is
|
|
16582
|
+
* an answer to the notification, and being thrown into a browser tab to
|
|
16583
|
+
* confirm it costs more attention than the notification did. A backend that
|
|
16584
|
+
* cannot do a background call renders it as an ordinary link (the adapters
|
|
16585
|
+
* fall back rather than dropping the button), so this is a preference, never
|
|
16586
|
+
* a requirement.
|
|
16347
16587
|
*/
|
|
16348
|
-
|
|
16349
|
-
/** Display label for a CUSTOM `section` id (ignored for well-known ids). */
|
|
16350
|
-
sectionLabel: string().optional()
|
|
16588
|
+
mode: _enum(["navigate", "background"]).optional()
|
|
16351
16589
|
});
|
|
16352
|
-
|
|
16353
|
-
|
|
16354
|
-
|
|
16355
|
-
|
|
16356
|
-
|
|
16357
|
-
|
|
16358
|
-
|
|
16359
|
-
|
|
16360
|
-
|
|
16361
|
-
|
|
16362
|
-
|
|
16363
|
-
|
|
16364
|
-
|
|
16365
|
-
|
|
16366
|
-
|
|
16367
|
-
|
|
16368
|
-
|
|
16369
|
-
|
|
16370
|
-
|
|
16371
|
-
|
|
16372
|
-
|
|
16373
|
-
"
|
|
16374
|
-
"
|
|
16375
|
-
"
|
|
16376
|
-
"
|
|
16590
|
+
/** A delivery parameter value: what a notifier declared it takes. */
|
|
16591
|
+
var DeliveryParamValueSchema = union([
|
|
16592
|
+
string(),
|
|
16593
|
+
number(),
|
|
16594
|
+
boolean()
|
|
16595
|
+
]);
|
|
16596
|
+
/**
|
|
16597
|
+
* One extra delivery parameter a notifier KIND declares (D938). A rule that
|
|
16598
|
+
* addresses a target of that kind may set it; a kind that declares nothing is
|
|
16599
|
+
* never handed one. The admin UI derives its control from this descriptor —
|
|
16600
|
+
* no editor knows a service by name.
|
|
16601
|
+
*
|
|
16602
|
+
* Optional fields are `.optional()`, never `.default()` (a Zod default does not
|
|
16603
|
+
* run on the addon cap path).
|
|
16604
|
+
*/
|
|
16605
|
+
var DeliveryParamSchema = object({
|
|
16606
|
+
key: string().min(1),
|
|
16607
|
+
label: string(),
|
|
16608
|
+
/** i18n key of the label, resolved by the declaring addon's namespace. */
|
|
16609
|
+
labelKey: string().optional(),
|
|
16610
|
+
type: _enum([
|
|
16611
|
+
"enum",
|
|
16612
|
+
"number",
|
|
16613
|
+
"boolean",
|
|
16614
|
+
"string"
|
|
16377
16615
|
]),
|
|
16378
|
-
|
|
16379
|
-
|
|
16380
|
-
|
|
16381
|
-
|
|
16382
|
-
|
|
16383
|
-
|
|
16384
|
-
|
|
16385
|
-
|
|
16386
|
-
|
|
16616
|
+
/** `enum` only: the closed set of accepted values. */
|
|
16617
|
+
options: array(object({
|
|
16618
|
+
value: string(),
|
|
16619
|
+
label: string()
|
|
16620
|
+
})).optional(),
|
|
16621
|
+
/** `number` only. */
|
|
16622
|
+
min: number().optional(),
|
|
16623
|
+
max: number().optional(),
|
|
16624
|
+
/** What the notifier does when the rule sets nothing; shown as the placeholder. */
|
|
16625
|
+
default: DeliveryParamValueSchema.optional()
|
|
16387
16626
|
});
|
|
16388
16627
|
/**
|
|
16389
|
-
*
|
|
16390
|
-
*
|
|
16391
|
-
*
|
|
16392
|
-
*
|
|
16393
|
-
*
|
|
16394
|
-
*
|
|
16628
|
+
* The canonical notification. `body` is the only hard field (Apprise model).
|
|
16629
|
+
* `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
|
|
16630
|
+
* NOT a fixed severity enum — each kind declares its own `caps.levels` and
|
|
16631
|
+
* the adapter maps this ordinal onto its native level. `level?` is an
|
|
16632
|
+
* optional kind-native level id (`emergency`, `silent`, …) that overrides
|
|
16633
|
+
* `priority` for that one target.
|
|
16395
16634
|
*/
|
|
16396
|
-
var
|
|
16397
|
-
|
|
16398
|
-
|
|
16399
|
-
|
|
16400
|
-
|
|
16401
|
-
|
|
16402
|
-
|
|
16403
|
-
|
|
16404
|
-
|
|
16405
|
-
|
|
16406
|
-
|
|
16635
|
+
var NotificationSchema = object({
|
|
16636
|
+
body: string(),
|
|
16637
|
+
title: string().optional(),
|
|
16638
|
+
format: NotificationFormatSchema.default("text"),
|
|
16639
|
+
priority: number().int().min(1).max(5).default(3),
|
|
16640
|
+
level: string().optional(),
|
|
16641
|
+
attachments: array(AttachmentSchema).optional(),
|
|
16642
|
+
clickUrl: string().optional(),
|
|
16643
|
+
actions: array(NotificationActionSchema).optional(),
|
|
16644
|
+
sound: string().optional(),
|
|
16645
|
+
ttl: number().optional(),
|
|
16646
|
+
tag: string().optional(),
|
|
16647
|
+
deviceId: number().optional(),
|
|
16648
|
+
eventId: string().optional(),
|
|
16649
|
+
metadata: record(string(), unknown()).optional(),
|
|
16650
|
+
/**
|
|
16651
|
+
* Values for the parameters the target's kind DECLARES in
|
|
16652
|
+
* {@link TargetKindSchema} `deliveryParams`. Already validated against the
|
|
16653
|
+
* declaration by the sender; a notifier reads only the keys it declared.
|
|
16654
|
+
*/
|
|
16655
|
+
delivery: record(string(), DeliveryParamValueSchema).optional()
|
|
16656
|
+
});
|
|
16657
|
+
/** One declared native severity/priority level for a kind. */
|
|
16658
|
+
var TargetKindLevelSchema = object({
|
|
16659
|
+
id: string(),
|
|
16660
|
+
label: string(),
|
|
16661
|
+
/** Which canonical priority (1..5) this level maps to. `null` = qualitative-only. */
|
|
16662
|
+
ordinal: number().int().min(1).max(5).nullable(),
|
|
16663
|
+
flags: object({
|
|
16664
|
+
critical: boolean().optional(),
|
|
16665
|
+
silent: boolean().optional(),
|
|
16666
|
+
noPush: boolean().optional()
|
|
16407
16667
|
}).optional(),
|
|
16408
|
-
|
|
16668
|
+
/** e.g. Pushover `emergency` requires `retry` / `expire`. */
|
|
16669
|
+
requires: array(string()).optional(),
|
|
16670
|
+
description: string().optional()
|
|
16409
16671
|
});
|
|
16410
|
-
|
|
16411
|
-
|
|
16412
|
-
|
|
16413
|
-
|
|
16414
|
-
|
|
16415
|
-
|
|
16416
|
-
|
|
16417
|
-
|
|
16418
|
-
|
|
16419
|
-
|
|
16420
|
-
|
|
16672
|
+
/** The full capability block consulted before dispatch. */
|
|
16673
|
+
var TargetKindCapsSchema = object({
|
|
16674
|
+
attachments: object({
|
|
16675
|
+
mediaTypes: array(AttachmentMediaTypeSchema),
|
|
16676
|
+
mode: _enum([
|
|
16677
|
+
"url",
|
|
16678
|
+
"bytes",
|
|
16679
|
+
"both"
|
|
16680
|
+
]),
|
|
16681
|
+
max: number().int().nonnegative(),
|
|
16682
|
+
maxBytes: number().int().positive().optional()
|
|
16683
|
+
}),
|
|
16684
|
+
/** Max action buttons (0 = none). */
|
|
16685
|
+
actions: number().int().nonnegative(),
|
|
16686
|
+
/**
|
|
16687
|
+
* Whether this kind renders a per-action ICON.
|
|
16688
|
+
*
|
|
16689
|
+
* `.optional()`, deliberately NOT `.default(false)`: a Zod default does not
|
|
16690
|
+
* run on the addon cap path — three production failures in one day taught
|
|
16691
|
+
* this repo that once. Absent is read as false by the degrade engine, which
|
|
16692
|
+
* is the safe direction: an icon that is not rendered costs nothing, an icon
|
|
16693
|
+
* assumed and dropped costs the operator's trust in the field.
|
|
16694
|
+
*/
|
|
16695
|
+
actionIcons: boolean().optional(),
|
|
16696
|
+
levels: array(TargetKindLevelSchema),
|
|
16697
|
+
format: array(NotificationFormatSchema),
|
|
16698
|
+
clickUrl: boolean(),
|
|
16699
|
+
sound: boolean(),
|
|
16700
|
+
ttl: boolean(),
|
|
16701
|
+
bodyMaxLen: number().int().positive()
|
|
16421
16702
|
});
|
|
16422
|
-
|
|
16423
|
-
|
|
16424
|
-
|
|
16703
|
+
/**
|
|
16704
|
+
* `configSchema` is a `ConfigUISchema` tree passed through to the admin
|
|
16705
|
+
* FormBuilder. Stored as `z.unknown()` at the cap seam (mirrors
|
|
16706
|
+
* `device-provider.getChildCreationSchema` `CreationSchemaOutputSchema`) —
|
|
16707
|
+
* the union is large and not meant for runtime validation here; the exported
|
|
16708
|
+
* `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
|
|
16709
|
+
*/
|
|
16710
|
+
var ConfigSchemaPassthrough$3 = unknown();
|
|
16711
|
+
var TargetKindSchema = object({
|
|
16712
|
+
kind: string(),
|
|
16425
16713
|
label: string(),
|
|
16426
16714
|
icon: string(),
|
|
16427
|
-
|
|
16428
|
-
|
|
16429
|
-
|
|
16430
|
-
|
|
16431
|
-
|
|
16432
|
-
|
|
16715
|
+
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
16716
|
+
addonId: string(),
|
|
16717
|
+
/**
|
|
16718
|
+
* URL of the kind's bundled BRAND icon, served by the providing addon over
|
|
16719
|
+
* its own `addon-routes` surface (`/addon/<addonId>/icons/<kind>`). Absent
|
|
16720
|
+
* when the addon bundles no icon for that kind — the client then falls back
|
|
16721
|
+
* to a neutral glyph rather than rendering the raw `icon` NAME as text.
|
|
16722
|
+
*
|
|
16723
|
+
* Root-relative on purpose: it resolves against whatever origin serves a web
|
|
16724
|
+
* client, and a native client joins it onto its own hub base.
|
|
16725
|
+
*
|
|
16726
|
+
* DECLARED here deliberately. It used to travel as an undeclared passthrough
|
|
16727
|
+
* field that survived only because the runtime cap-router forwards provider
|
|
16728
|
+
* output verbatim — so every consumer had to re-declare it by hand to stop
|
|
16729
|
+
* its own Zod parse from stripping it, and the whole arrangement would have
|
|
16730
|
+
* broken silently the moment output validation was tightened anywhere.
|
|
16731
|
+
*/
|
|
16732
|
+
iconUrl: string().optional(),
|
|
16733
|
+
/**
|
|
16734
|
+
* Media type of {@link iconUrl} (`image/svg+xml`, `image/png`, …).
|
|
16735
|
+
*
|
|
16736
|
+
* The server knows this and therefore says it, because the client cannot
|
|
16737
|
+
* safely guess: a React-Native client renders SVG and raster through two
|
|
16738
|
+
* DIFFERENT components (`react-native-svg` vs `expo-image` — expo-image does
|
|
16739
|
+
* not decode SVG on iOS/Android), so without this it silently fell back to a
|
|
16740
|
+
* placeholder glyph for every vector icon while the web build looked fine.
|
|
16741
|
+
*
|
|
16742
|
+
* Absent when {@link iconUrl} is absent, or for a legacy provider that has
|
|
16743
|
+
* not been updated — a client that cannot determine the type should prefer
|
|
16744
|
+
* its raster path, which is the safe default for an unknown image.
|
|
16745
|
+
*/
|
|
16746
|
+
iconMediaType: string().optional(),
|
|
16747
|
+
configSchema: ConfigSchemaPassthrough$3,
|
|
16748
|
+
/**
|
|
16749
|
+
* The config keys that decide WHERE this kind's secrets are sent (server,
|
|
16750
|
+
* base URL, instance, chat, recipient). A save that changes any of them
|
|
16751
|
+
* while leaving a secret redacted is refused by the provider (D634), so an
|
|
16752
|
+
* editor uses this to ask for the secret on exactly those edits instead of
|
|
16753
|
+
* on every edit.
|
|
16754
|
+
*
|
|
16755
|
+
* Optional: absent from a provider that holds no secret (the Home Assistant
|
|
16756
|
+
* kinds) and from a provider older than this field — an editor that finds
|
|
16757
|
+
* it absent must assume ANY edit may need the secret.
|
|
16758
|
+
*/
|
|
16759
|
+
destinationKeys: array(string()).optional(),
|
|
16760
|
+
supportsDiscovery: boolean(),
|
|
16761
|
+
/**
|
|
16762
|
+
* Extra delivery parameters a rule may set for a target of this kind (D938).
|
|
16763
|
+
* Absent = none; the rule editor then offers nothing.
|
|
16764
|
+
*/
|
|
16765
|
+
deliveryParams: array(DeliveryParamSchema).optional(),
|
|
16766
|
+
caps: TargetKindCapsSchema
|
|
16767
|
+
});
|
|
16768
|
+
/**
|
|
16769
|
+
* A persisted target. `config` holds secrets; providers REDACT secret fields
|
|
16770
|
+
* (return a presence marker only) when serving `listTargets` — never
|
|
16771
|
+
* round-trip a stored secret to the UI.
|
|
16772
|
+
*/
|
|
16773
|
+
var TargetSchema = object({
|
|
16774
|
+
id: string(),
|
|
16775
|
+
name: string(),
|
|
16776
|
+
kind: string(),
|
|
16777
|
+
addonId: string(),
|
|
16778
|
+
enabled: boolean(),
|
|
16779
|
+
config: record(string(), unknown())
|
|
16780
|
+
});
|
|
16781
|
+
/** A discovery-surfaced candidate (config is partial + non-secret). */
|
|
16782
|
+
var DiscoveredTargetSchema = object({
|
|
16783
|
+
kind: string(),
|
|
16784
|
+
suggestedName: string(),
|
|
16785
|
+
config: record(string(), unknown())
|
|
16786
|
+
});
|
|
16787
|
+
/** The degrade engine's report — what was resolved / dropped / degraded. */
|
|
16788
|
+
var RenderedAsSchema = object({
|
|
16789
|
+
level: string(),
|
|
16790
|
+
format: NotificationFormatSchema,
|
|
16791
|
+
attachmentsSent: number().int().nonnegative(),
|
|
16792
|
+
actionsSent: number().int().nonnegative(),
|
|
16793
|
+
truncated: boolean(),
|
|
16794
|
+
dropped: array(string())
|
|
16795
|
+
});
|
|
16796
|
+
var SendResultSchema = object({
|
|
16797
|
+
success: boolean(),
|
|
16798
|
+
error: string().optional(),
|
|
16799
|
+
renderedAs: RenderedAsSchema.optional()
|
|
16800
|
+
});
|
|
16801
|
+
/** Same shape as SendResult — kept as a distinct name for the test panel. */
|
|
16802
|
+
var TestResultSchema = SendResultSchema;
|
|
16803
|
+
/**
|
|
16804
|
+
* Pre-save credential probe against a partial (unsaved) target config.
|
|
16805
|
+
* `resolvedUrl` never includes secrets (token stripped from path).
|
|
16806
|
+
*/
|
|
16807
|
+
var ProbeTargetConfigResultSchema = object({
|
|
16808
|
+
ok: boolean(),
|
|
16809
|
+
resolvedUrl: string(),
|
|
16810
|
+
httpStatus: number().int().optional(),
|
|
16811
|
+
stateInstance: string().optional(),
|
|
16812
|
+
error: string().optional()
|
|
16813
|
+
});
|
|
16814
|
+
method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSchema), { auth: "admin" }), method(object({ targetId: string() }), TargetSchema, { auth: "admin" }), method(object({
|
|
16815
|
+
kind: string(),
|
|
16816
|
+
config: record(string(), unknown()).optional(),
|
|
16817
|
+
/**
|
|
16818
|
+
* When editing / duplicating, the blank password field never round-trips
|
|
16819
|
+
* the stored token. Pass the source target id so the provider can restore
|
|
16820
|
+
* secrets server-side before dialling (same merge as upsert).
|
|
16821
|
+
*/
|
|
16822
|
+
targetId: string().optional()
|
|
16823
|
+
}), array(DiscoveredTargetSchema), { auth: "admin" }), method(object({
|
|
16824
|
+
kind: string(),
|
|
16825
|
+
config: record(string(), unknown()),
|
|
16826
|
+
/** See `discoverTargets.targetId` — restore stored secrets for a blank password. */
|
|
16827
|
+
targetId: string().optional()
|
|
16828
|
+
}), ProbeTargetConfigResultSchema, {
|
|
16829
|
+
kind: "mutation",
|
|
16830
|
+
auth: "admin"
|
|
16831
|
+
}), method(object({
|
|
16832
|
+
targetId: string(),
|
|
16833
|
+
notification: NotificationSchema
|
|
16834
|
+
}), SendResultSchema, {
|
|
16835
|
+
kind: "mutation",
|
|
16836
|
+
auth: "admin"
|
|
16837
|
+
}), method(object({
|
|
16838
|
+
targetId: string(),
|
|
16839
|
+
sample: NotificationSchema.optional()
|
|
16840
|
+
}), TestResultSchema, {
|
|
16841
|
+
kind: "mutation",
|
|
16842
|
+
auth: "admin"
|
|
16843
|
+
}), method(object({
|
|
16844
|
+
target: TargetSchema,
|
|
16845
|
+
/**
|
|
16846
|
+
* Duplicate flow: create a NEW target id while copying secrets from an
|
|
16847
|
+
* existing row. The UI never holds the stored token; blank / redacted
|
|
16848
|
+
* password fields are restored from this source (D634 still applies if
|
|
16849
|
+
* destinations diverge without a re-typed secret).
|
|
16850
|
+
*/
|
|
16851
|
+
cloneSecretsFrom: string().optional()
|
|
16852
|
+
}), TargetSchema, {
|
|
16853
|
+
kind: "mutation",
|
|
16854
|
+
auth: "admin"
|
|
16855
|
+
}), method(object({ targetId: string() }), _void(), {
|
|
16856
|
+
kind: "mutation",
|
|
16857
|
+
auth: "admin"
|
|
16858
|
+
}), method(object({
|
|
16859
|
+
targetId: string(),
|
|
16860
|
+
enabled: boolean()
|
|
16861
|
+
}), _void(), {
|
|
16862
|
+
kind: "mutation",
|
|
16863
|
+
auth: "admin"
|
|
16864
|
+
});
|
|
16865
|
+
/**
|
|
16866
|
+
* `addon-pages` — system-scoped singleton aggregator cap. Public-facing
|
|
16867
|
+
* surface that admin-ui consumes through `useAddonPagesListPages()`.
|
|
16868
|
+
*
|
|
16869
|
+
* The provider iterates every `addon-pages-source` (collection) provider
|
|
16870
|
+
* and emits `AddonPageInfo[]` enriched with versioned `bundleUrl` strings
|
|
16871
|
+
* pointing at `/api/addon-pages/<addonId>/<bundle>?v=<mtime>`. The
|
|
16872
|
+
* filesystem `mtime` cache-buster lets the browser pick up addon
|
|
16873
|
+
* rebuilds without manual reload.
|
|
16874
|
+
*
|
|
16875
|
+
* The hub-local builtin `addon-pages-aggregator` (see
|
|
16876
|
+
* `@camstack/system/builtins/addon-pages-aggregator`) registers the
|
|
16877
|
+
* provider. Splitting the public aggregator from the raw collection
|
|
16878
|
+
* keeps both ends in codegen — there's no hand-written
|
|
16879
|
+
* `addon-pages.router.ts` wrapper anymore.
|
|
16880
|
+
*/
|
|
16881
|
+
var AddonPageDeclarationSchema$1 = object({
|
|
16882
|
+
id: string(),
|
|
16883
|
+
label: string(),
|
|
16884
|
+
icon: string(),
|
|
16885
|
+
path: string(),
|
|
16886
|
+
remoteName: string(),
|
|
16887
|
+
bundle: string(),
|
|
16888
|
+
section: string().optional(),
|
|
16889
|
+
sectionLabel: string().optional()
|
|
16890
|
+
});
|
|
16891
|
+
var AddonPageInfoSchema = object({
|
|
16892
|
+
addonId: string(),
|
|
16893
|
+
page: AddonPageDeclarationSchema$1,
|
|
16894
|
+
bundleUrl: string()
|
|
16895
|
+
});
|
|
16896
|
+
method(_void(), array(AddonPageInfoSchema).readonly());
|
|
16897
|
+
var AddonHttpRouteSchema = object({
|
|
16898
|
+
method: _enum([
|
|
16899
|
+
"GET",
|
|
16900
|
+
"POST",
|
|
16901
|
+
"PUT",
|
|
16902
|
+
"DELETE",
|
|
16903
|
+
"PATCH"
|
|
16904
|
+
]),
|
|
16905
|
+
path: string(),
|
|
16906
|
+
access: _enum([
|
|
16907
|
+
"public",
|
|
16908
|
+
"authenticated",
|
|
16909
|
+
"admin"
|
|
16910
|
+
]).optional(),
|
|
16911
|
+
description: string().optional(),
|
|
16912
|
+
/** The hub limits this route per client address before the handler runs. */
|
|
16913
|
+
rateLimit: _enum(["auth"]).optional()
|
|
16914
|
+
});
|
|
16915
|
+
/**
|
|
16916
|
+
* Cross-process route invocation envelope. The hub captures the
|
|
16917
|
+
* request as plain data, ships it to the worker via Moleculer, and
|
|
16918
|
+
* the worker runs the local handler against a capturing reply. The
|
|
16919
|
+
* envelope returned describes what the handler intended (status,
|
|
16920
|
+
* headers, body, or a redirect) so the hub can translate it back to
|
|
16921
|
+
* the Fastify reply that's actually wired to the socket.
|
|
16922
|
+
*/
|
|
16923
|
+
var InvokeRequestSchema = object({
|
|
16924
|
+
method: string(),
|
|
16925
|
+
path: string(),
|
|
16926
|
+
params: record(string(), string()),
|
|
16927
|
+
query: record(string(), string()),
|
|
16928
|
+
body: unknown(),
|
|
16929
|
+
headers: record(string(), string()),
|
|
16930
|
+
user: object({
|
|
16931
|
+
id: string(),
|
|
16932
|
+
username: string(),
|
|
16933
|
+
isAdmin: boolean()
|
|
16934
|
+
}).optional(),
|
|
16935
|
+
scopedToken: unknown().optional()
|
|
16936
|
+
});
|
|
16937
|
+
var InvokeReplyEnvelopeSchema = object({
|
|
16938
|
+
status: number().int(),
|
|
16939
|
+
headers: record(string(), string()),
|
|
16940
|
+
/** When set, the hub MUST `reply.redirect(redirectUrl)` instead of
|
|
16941
|
+
* sending `body`. Status defaults to 302 when this is set unless
|
|
16942
|
+
* the handler called `reply.code(...)` explicitly. */
|
|
16943
|
+
redirectUrl: string().nullable(),
|
|
16944
|
+
/** JSON-serializable body. `undefined` is treated as "no body". */
|
|
16945
|
+
body: unknown().optional(),
|
|
16946
|
+
/** Set when the handler called `reply.type(mime)`. */
|
|
16947
|
+
contentType: string().optional()
|
|
16948
|
+
});
|
|
16949
|
+
method(_void(), array(AddonHttpRouteSchema)), method(InvokeRequestSchema, InvokeReplyEnvelopeSchema, { kind: "mutation" });
|
|
16950
|
+
var ConfigTabDeclarationSchema = object({
|
|
16951
|
+
id: string(),
|
|
16952
|
+
label: string(),
|
|
16953
|
+
icon: string(),
|
|
16954
|
+
order: number().optional()
|
|
16955
|
+
});
|
|
16956
|
+
var ConfigSectionWithValuesSchema = object({
|
|
16957
|
+
id: string(),
|
|
16958
|
+
title: string(),
|
|
16959
|
+
titleKey: string().optional(),
|
|
16433
16960
|
description: string().optional(),
|
|
16434
16961
|
descriptionKey: string().optional(),
|
|
16435
16962
|
style: _enum(["card", "accordion"]).optional(),
|
|
@@ -18909,7 +19436,11 @@ var CompositionProblemSchema = object({
|
|
|
18909
19436
|
"mixed-quantity",
|
|
18910
19437
|
"helper-mismatch",
|
|
18911
19438
|
"member-constraint",
|
|
18912
|
-
"retention"
|
|
19439
|
+
"retention",
|
|
19440
|
+
"command-method-unknown",
|
|
19441
|
+
"command-source-unknown",
|
|
19442
|
+
"command-input-unknown",
|
|
19443
|
+
"command-input-missing"
|
|
18913
19444
|
]),
|
|
18914
19445
|
path: string(),
|
|
18915
19446
|
message: string()
|
|
@@ -18948,7 +19479,9 @@ var CompositionFieldRoleSchema = _enum([
|
|
|
18948
19479
|
var CompositionFieldItemSchema = object({
|
|
18949
19480
|
arrayPath: string(),
|
|
18950
19481
|
key: string(),
|
|
18951
|
-
label: string()
|
|
19482
|
+
label: string(),
|
|
19483
|
+
/** True when the item carries a `reset` forward: the composer writes `resettable` from this (D967). */
|
|
19484
|
+
resettable: boolean().optional()
|
|
18952
19485
|
});
|
|
18953
19486
|
var CompositionFieldPlanSchema = object({
|
|
18954
19487
|
cap: string(),
|
|
@@ -19153,7 +19686,7 @@ Object.freeze({
|
|
|
19153
19686
|
* One catalog row per base reading a group helper can build (D944 §3).
|
|
19154
19687
|
* Data, not a form default written into the block.
|
|
19155
19688
|
*/
|
|
19156
|
-
var NOW$
|
|
19689
|
+
var NOW$3 = {
|
|
19157
19690
|
fieldPath: "lastFetchedAt",
|
|
19158
19691
|
expr: "now"
|
|
19159
19692
|
};
|
|
@@ -19205,7 +19738,7 @@ var GROUP_TEMPLATES = [
|
|
|
19205
19738
|
quantity: "temperature",
|
|
19206
19739
|
defaultAggregate: "mean",
|
|
19207
19740
|
empty: "null",
|
|
19208
|
-
companions: [NOW$
|
|
19741
|
+
companions: [NOW$3],
|
|
19209
19742
|
alsoFrom: {
|
|
19210
19743
|
deviceTypes: CLIMATE_DEVICES,
|
|
19211
19744
|
accept: {
|
|
@@ -19223,7 +19756,7 @@ var GROUP_TEMPLATES = [
|
|
|
19223
19756
|
quantity: "humidity",
|
|
19224
19757
|
defaultAggregate: "mean",
|
|
19225
19758
|
empty: "null",
|
|
19226
|
-
companions: [NOW$
|
|
19759
|
+
companions: [NOW$3],
|
|
19227
19760
|
alsoFrom: {
|
|
19228
19761
|
deviceTypes: CLIMATE_DEVICES,
|
|
19229
19762
|
accept: {
|
|
@@ -19241,7 +19774,7 @@ var GROUP_TEMPLATES = [
|
|
|
19241
19774
|
quantity: "pressure",
|
|
19242
19775
|
defaultAggregate: "mean",
|
|
19243
19776
|
empty: "null",
|
|
19244
|
-
companions: [NOW$
|
|
19777
|
+
companions: [NOW$3]
|
|
19245
19778
|
}),
|
|
19246
19779
|
numeric({
|
|
19247
19780
|
id: "illuminance",
|
|
@@ -19252,7 +19785,7 @@ var GROUP_TEMPLATES = [
|
|
|
19252
19785
|
quantity: "illuminance",
|
|
19253
19786
|
defaultAggregate: "mean",
|
|
19254
19787
|
empty: "null",
|
|
19255
|
-
companions: [NOW$
|
|
19788
|
+
companions: [NOW$3]
|
|
19256
19789
|
}),
|
|
19257
19790
|
numeric({
|
|
19258
19791
|
id: "power",
|
|
@@ -19263,7 +19796,7 @@ var GROUP_TEMPLATES = [
|
|
|
19263
19796
|
quantity: "power",
|
|
19264
19797
|
defaultAggregate: "sum",
|
|
19265
19798
|
empty: "omit",
|
|
19266
|
-
companions: [NOW$
|
|
19799
|
+
companions: [NOW$3]
|
|
19267
19800
|
}),
|
|
19268
19801
|
numeric({
|
|
19269
19802
|
id: "energy",
|
|
@@ -19274,7 +19807,7 @@ var GROUP_TEMPLATES = [
|
|
|
19274
19807
|
quantity: "energy",
|
|
19275
19808
|
defaultAggregate: "sum",
|
|
19276
19809
|
empty: "omit",
|
|
19277
|
-
companions: [NOW$
|
|
19810
|
+
companions: [NOW$3]
|
|
19278
19811
|
}),
|
|
19279
19812
|
numeric({
|
|
19280
19813
|
id: "battery",
|
|
@@ -19309,7 +19842,7 @@ var GROUP_TEMPLATES = [
|
|
|
19309
19842
|
quantity: "device",
|
|
19310
19843
|
defaultAggregate: "mean",
|
|
19311
19844
|
empty: "null",
|
|
19312
|
-
companions: [NOW$
|
|
19845
|
+
companions: [NOW$3]
|
|
19313
19846
|
}),
|
|
19314
19847
|
binary({
|
|
19315
19848
|
id: "motion",
|
|
@@ -21655,12 +22188,48 @@ var ExposeInputSchema = object({
|
|
|
21655
22188
|
capabilities: array(string()).optional()
|
|
21656
22189
|
});
|
|
21657
22190
|
var UnexposeInputSchema = object({ deviceId: string() });
|
|
22191
|
+
/**
|
|
22192
|
+
* What an exporter may expose besides devices (D968). An action and a
|
|
22193
|
+
* notification target are LIST ENTRIES, never devices (D954): they enter an
|
|
22194
|
+
* exporter's own selection, not the device registry.
|
|
22195
|
+
*/
|
|
22196
|
+
var ExportEntityKindSchema = _enum([
|
|
22197
|
+
"device",
|
|
22198
|
+
"action",
|
|
22199
|
+
"notifier"
|
|
22200
|
+
]);
|
|
22201
|
+
var ExportEntityRefSchema = discriminatedUnion("kind", [
|
|
22202
|
+
object({
|
|
22203
|
+
kind: literal("device"),
|
|
22204
|
+
deviceId: string()
|
|
22205
|
+
}),
|
|
22206
|
+
object({
|
|
22207
|
+
kind: literal("action"),
|
|
22208
|
+
actionId: string().min(1)
|
|
22209
|
+
}),
|
|
22210
|
+
object({
|
|
22211
|
+
kind: literal("notifier"),
|
|
22212
|
+
targetId: string().min(1)
|
|
22213
|
+
})
|
|
22214
|
+
]);
|
|
22215
|
+
var ExposedEntitySchema = object({
|
|
22216
|
+
entity: ExportEntityRefSchema,
|
|
22217
|
+
exposedAs: string().optional()
|
|
22218
|
+
});
|
|
22219
|
+
var ExposeEntityInputSchema = object({ entity: ExportEntityRefSchema });
|
|
22220
|
+
var UnexposeEntityInputSchema = object({ entity: ExportEntityRefSchema });
|
|
21658
22221
|
method(_void(), DeviceExportStatusSchema), method(_void(), array(DeviceKindSchema)), method(_void(), array(ExposedDeviceSchema)), method(ExposeInputSchema, _void(), {
|
|
21659
22222
|
kind: "mutation",
|
|
21660
22223
|
auth: "admin"
|
|
21661
22224
|
}), method(UnexposeInputSchema, _void(), {
|
|
21662
22225
|
kind: "mutation",
|
|
21663
22226
|
auth: "admin"
|
|
22227
|
+
}), optionalMethod(_void(), array(ExportEntityKindSchema)), optionalMethod(_void(), array(ExposedEntitySchema)), optionalMethod(ExposeEntityInputSchema, _void(), {
|
|
22228
|
+
kind: "mutation",
|
|
22229
|
+
auth: "admin"
|
|
22230
|
+
}), optionalMethod(UnexposeEntityInputSchema, _void(), {
|
|
22231
|
+
kind: "mutation",
|
|
22232
|
+
auth: "admin"
|
|
21664
22233
|
});
|
|
21665
22234
|
/** Lucide category ids, alphabetical. `ICON_META` indexes into this. */
|
|
21666
22235
|
var ICON_CATEGORY_IDS = [
|
|
@@ -43529,7 +44098,7 @@ var LlmProviderWidgetSchema = object({
|
|
|
43529
44098
|
/** ConfigUISchema tree passed through untyped on the wire (the
|
|
43530
44099
|
* notification-output `ConfigSchemaPassthrough` precedent at
|
|
43531
44100
|
* notification-output.cap.ts:151); the exported TS type re-tightens it. */
|
|
43532
|
-
var ConfigSchemaPassthrough$
|
|
44101
|
+
var ConfigSchemaPassthrough$2 = unknown();
|
|
43533
44102
|
var LlmProfileKindDescriptorSchema = object({
|
|
43534
44103
|
kind: LlmProfileKindSchema,
|
|
43535
44104
|
label: string(),
|
|
@@ -43538,9 +44107,9 @@ var LlmProfileKindDescriptorSchema = object({
|
|
|
43538
44107
|
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
43539
44108
|
addonId: string(),
|
|
43540
44109
|
/** The provider's own fields (`providerConfig`); `password` fields are keychain-held. */
|
|
43541
|
-
connectionSchema: ConfigSchemaPassthrough$
|
|
44110
|
+
connectionSchema: ConfigSchemaPassthrough$2,
|
|
43542
44111
|
/** Provider fields that belong under "Advanced" (extra headers, runtime tuning). */
|
|
43543
|
-
advancedSchema: ConfigSchemaPassthrough$
|
|
44112
|
+
advancedSchema: ConfigSchemaPassthrough$2.optional(),
|
|
43544
44113
|
/** The kind's defaults; a model from `listModels` may override any of them. */
|
|
43545
44114
|
features: LlmModelFeaturesSchema,
|
|
43546
44115
|
/** `false` = the provider stamps `supportsVision` itself (from what a node reports). */
|
|
@@ -44066,10 +44635,10 @@ var CpuBreakdownSchema = object({
|
|
|
44066
44635
|
cores: number()
|
|
44067
44636
|
});
|
|
44068
44637
|
var MemoryInfoSchema = object({
|
|
44069
|
-
percent: number(),
|
|
44638
|
+
percent: number().nullable(),
|
|
44070
44639
|
totalBytes: number(),
|
|
44071
|
-
usedBytes: number(),
|
|
44072
|
-
availableBytes: number(),
|
|
44640
|
+
usedBytes: number().nullable(),
|
|
44641
|
+
availableBytes: number().nullable(),
|
|
44073
44642
|
swapUsedBytes: number(),
|
|
44074
44643
|
swapTotalBytes: number()
|
|
44075
44644
|
});
|
|
@@ -44350,687 +44919,267 @@ var GetLoadSeriesInputSchema = object({
|
|
|
44350
44919
|
*
|
|
44351
44920
|
* NOT named `nodeId`: the generated cap router strips a top-level
|
|
44352
44921
|
* `nodeId` from every method input and uses it to ROUTE the call to
|
|
44353
|
-
* that node's provider (`generated-cap-routers.ts`). A series target
|
|
44354
|
-
* called `nodeId` would silently become a routing pin and never reach
|
|
44355
|
-
* the provider. The hub holds every node it hears from, so the
|
|
44356
|
-
* ordinary call is unpinned — answered by the hub, for any node.
|
|
44357
|
-
*/
|
|
44358
|
-
forNodeId: string(),
|
|
44359
|
-
/**
|
|
44360
|
-
* EXCLUSIVE lower bound. A caller passes the newest `atMs` it already
|
|
44361
|
-
* holds and receives only what it is missing, so seeding a live chart
|
|
44362
|
-
* from this method cannot double a point already drawn.
|
|
44363
|
-
*/
|
|
44364
|
-
sinceMs: number().optional(),
|
|
44365
|
-
/**
|
|
44366
|
-
* Most points the caller wants PER FUNCTION. The window is reduced to fit,
|
|
44367
|
-
* preserving min and max per bucket.
|
|
44368
|
-
*
|
|
44369
|
-
* Absent means NO reduction — legitimate for a short window and a trap for a
|
|
44370
|
-
* long one, which is why a chart passes its own pixel width.
|
|
44371
|
-
*/
|
|
44372
|
-
maxPoints: number().int().positive().optional()
|
|
44373
|
-
});
|
|
44374
|
-
var SystemMetricsSchema = object({
|
|
44375
|
-
cpuPercent: number(),
|
|
44376
|
-
memoryPercent: number(),
|
|
44377
|
-
memoryUsedMB: number(),
|
|
44378
|
-
memoryTotalMB: number(),
|
|
44379
|
-
diskPercent: number().optional(),
|
|
44380
|
-
temperature: number().optional(),
|
|
44381
|
-
gpuPercent: number().optional(),
|
|
44382
|
-
gpuMemoryPercent: number().optional()
|
|
44383
|
-
});
|
|
44384
|
-
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);
|
|
44385
|
-
method(object({
|
|
44386
|
-
sourceUrl: string(),
|
|
44387
|
-
metadata: ModelConvertMetadataSchema,
|
|
44388
|
-
targets: array(ConvertTargetSchema).min(1).readonly(),
|
|
44389
|
-
calibrationRef: string().optional(),
|
|
44390
|
-
sessionId: string().optional()
|
|
44391
|
-
}), ConvertResultSchema, {
|
|
44392
|
-
kind: "mutation",
|
|
44393
|
-
auth: "admin",
|
|
44394
|
-
timeoutMs: 6e5
|
|
44395
|
-
});
|
|
44396
|
-
method(object({
|
|
44397
|
-
targetNodeId: string(),
|
|
44398
|
-
modelId: string(),
|
|
44399
|
-
format: _enum(MODEL_FORMATS),
|
|
44400
|
-
entry: ModelCatalogEntrySchema
|
|
44401
|
-
}), object({
|
|
44402
|
-
ok: boolean(),
|
|
44403
|
-
/** sha256 of the staged tarball (empty for a hub-local no-op). */
|
|
44404
|
-
sha256: string(),
|
|
44405
|
-
bytes: number(),
|
|
44406
|
-
/** The target node's modelsDir the artifact landed in. */
|
|
44407
|
-
path: string()
|
|
44408
|
-
}), {
|
|
44409
|
-
kind: "mutation",
|
|
44410
|
-
auth: "admin"
|
|
44411
|
-
});
|
|
44412
|
-
var MotionRegionSchema = object({
|
|
44413
|
-
bbox: BoundingBoxSchema,
|
|
44414
|
-
pixelCount: number(),
|
|
44415
|
-
intensity: number()
|
|
44416
|
-
});
|
|
44417
|
-
var MotionAnalysisResultSchema = object({
|
|
44418
|
-
detected: boolean(),
|
|
44419
|
-
regionCount: number(),
|
|
44420
|
-
/** Regions passing minArea filter — used for pipeline triggering. */
|
|
44421
|
-
regions: array(MotionRegionSchema).readonly(),
|
|
44422
|
-
/** All raw regions from CCL before minArea filter — used for UI debug overlay. */
|
|
44423
|
-
rawRegions: array(MotionRegionSchema).readonly(),
|
|
44424
|
-
frameWidth: number(),
|
|
44425
|
-
frameHeight: number(),
|
|
44426
|
-
analysisMs: number()
|
|
44427
|
-
});
|
|
44428
|
-
DeviceType.Camera, method(object({
|
|
44429
|
-
deviceId: number(),
|
|
44430
|
-
frame: FrameInputSchema.optional(),
|
|
44431
|
-
frameHandle: FrameHandleSchema.optional()
|
|
44432
|
-
}), MotionAnalysisResultSchema, {
|
|
44433
|
-
role: "admin",
|
|
44434
|
-
kind: "mutation"
|
|
44435
|
-
}), method(object({ deviceId: number() }), _void(), {
|
|
44436
|
-
role: "admin",
|
|
44437
|
-
kind: "mutation"
|
|
44438
|
-
}), method(_void(), _void(), {
|
|
44439
|
-
role: "admin",
|
|
44440
|
-
kind: "mutation"
|
|
44441
|
-
}), object({
|
|
44442
|
-
deviceId: number(),
|
|
44443
|
-
detected: boolean(),
|
|
44444
|
-
regionCount: number()
|
|
44445
|
-
});
|
|
44446
|
-
/**
|
|
44447
|
-
* `mqtt-broker` — broker-registry cap.
|
|
44448
|
-
*
|
|
44449
|
-
* NOT a pub/sub proxy. The cap exposes (a) a registry of configured
|
|
44450
|
-
* MQTT brokers (external + optionally an embedded `aedes`-backed one)
|
|
44451
|
-
* and (b) the connection details a consumer addon needs to spin up
|
|
44452
|
-
* its OWN `mqtt.js` client.
|
|
44453
|
-
*
|
|
44454
|
-
* Why: pub/sub routing over the system event-bus loses fidelity
|
|
44455
|
-
* (callback shape, QoS guarantees, will/retain semantics) and adds
|
|
44456
|
-
* refcount bookkeeping that addons would rather own themselves. The
|
|
44457
|
-
* canonical consumer needs raw `mqtt.js`
|
|
44458
|
-
* features anyway — give it the connection config, get out of the way.
|
|
44459
|
-
*
|
|
44460
|
-
* Consumer flow:
|
|
44461
|
-
* const cfg = await ctx.api.mqttBroker.getBrokerConfig({ id })
|
|
44462
|
-
* const client = mqtt.connect(cfg.url, { username: cfg.username, … })
|
|
44463
|
-
* client.subscribe('zigbee2mqtt/+')
|
|
44464
|
-
*
|
|
44465
|
-
* Collection mode: multiple brokers (e.g. one local mosquitto + one
|
|
44466
|
-
* cloud bridge). The "embedded" entry (when present) is just another
|
|
44467
|
-
* broker in the registry — its lifecycle is owned by the addon that
|
|
44468
|
-
* spawned it.
|
|
44469
|
-
*/
|
|
44470
|
-
var BrokerKindSchema = _enum(["external", "embedded"]);
|
|
44471
|
-
/**
|
|
44472
|
-
* Broker live-probe status.
|
|
44473
|
-
*
|
|
44474
|
-
* - `connected` — last probe completed a clean CONNACK
|
|
44475
|
-
* - `disconnected` — no probe has run yet (cold cache)
|
|
44476
|
-
* - `auth-failed` — CONNACK refused with auth error (RC 4 / 5)
|
|
44477
|
-
* - `unreachable` — TCP connect timed out / refused
|
|
44478
|
-
* - `tls-error` — TLS handshake failed (cert / SNI / cipher)
|
|
44479
|
-
*/
|
|
44480
|
-
var BrokerStatusSchema$1 = _enum([
|
|
44481
|
-
"connected",
|
|
44482
|
-
"disconnected",
|
|
44483
|
-
"auth-failed",
|
|
44484
|
-
"unreachable",
|
|
44485
|
-
"tls-error"
|
|
44486
|
-
]);
|
|
44487
|
-
var BrokerInfoSchema$1 = object({
|
|
44488
|
-
id: string(),
|
|
44489
|
-
name: string(),
|
|
44490
|
-
url: string(),
|
|
44491
|
-
kind: BrokerKindSchema,
|
|
44492
|
-
status: BrokerStatusSchema$1,
|
|
44493
|
-
latencyMs: number().nullable(),
|
|
44494
|
-
error: string().optional(),
|
|
44495
|
-
/** Embedded brokers only: number of MQTT clients currently connected. */
|
|
44496
|
-
connectedClients: number().int().nonnegative().optional(),
|
|
44497
|
-
/** Epoch ms of the last live probe (external) or aedes snapshot (embedded). */
|
|
44498
|
-
lastCheckedAt: number().optional()
|
|
44499
|
-
});
|
|
44500
|
-
/**
|
|
44501
|
-
* Connection details — what a consumer needs to call
|
|
44502
|
-
* `mqtt.connect(url, options)`. We split URL + credentials so the
|
|
44503
|
-
* consumer can pass them as `mqtt.connect(url, { username, password })`
|
|
44504
|
-
* instead of stuffing creds into the URL (which leaks them into logs).
|
|
44505
|
-
*/
|
|
44506
|
-
var BrokerConnectionDetailsSchema = object({
|
|
44507
|
-
url: string(),
|
|
44508
|
-
username: string().optional(),
|
|
44509
|
-
password: string().optional(),
|
|
44510
|
-
/**
|
|
44511
|
-
* Suggested prefix for `clientId`. Each consumer should suffix this
|
|
44512
|
-
* with its own discriminator (addon id, instance id) so reconnects
|
|
44513
|
-
* don't kick each other off (MQTT spec: clientId must be unique per
|
|
44514
|
-
* broker).
|
|
44515
|
-
*/
|
|
44516
|
-
clientIdPrefix: string().optional()
|
|
44517
|
-
});
|
|
44518
|
-
var AddBrokerInputSchema = object({
|
|
44519
|
-
name: string().min(1),
|
|
44520
|
-
url: string().regex(/^(mqtt|mqtts|ws|wss):\/\//, "URL must start with mqtt(s):// or ws(s)://"),
|
|
44521
|
-
username: string().optional(),
|
|
44522
|
-
password: string().optional(),
|
|
44523
|
-
clientIdPrefix: string().optional()
|
|
44524
|
-
});
|
|
44525
|
-
var AddBrokerResultSchema = object({ id: string() });
|
|
44526
|
-
var IdInputSchema = object({ id: string() });
|
|
44527
|
-
var TestResultSchema$1 = discriminatedUnion("ok", [object({
|
|
44528
|
-
ok: literal(true),
|
|
44529
|
-
latencyMs: number()
|
|
44530
|
-
}), object({
|
|
44531
|
-
ok: literal(false),
|
|
44532
|
-
error: string()
|
|
44533
|
-
})]);
|
|
44534
|
-
var StartEmbeddedInputSchema = object({
|
|
44535
|
-
port: number().int().min(1).max(65535).default(1883),
|
|
44536
|
-
/** Allow anonymous connect (no username/password). Default: false. */
|
|
44537
|
-
allowAnonymous: boolean().default(false),
|
|
44538
|
-
/** Optional shared username/password for clients. */
|
|
44539
|
-
username: string().optional(),
|
|
44540
|
-
password: string().optional()
|
|
44541
|
-
});
|
|
44542
|
-
var StartEmbeddedResultSchema = object({
|
|
44543
|
-
id: string(),
|
|
44544
|
-
url: string()
|
|
44545
|
-
});
|
|
44546
|
-
var StatusSchema = object({
|
|
44547
|
-
brokerCount: number(),
|
|
44548
|
-
embeddedRunning: boolean()
|
|
44549
|
-
});
|
|
44550
|
-
method(_void(), array(BrokerInfoSchema$1)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
|
|
44551
|
-
kind: "mutation",
|
|
44552
|
-
auth: "admin"
|
|
44553
|
-
}), method(IdInputSchema, _void(), {
|
|
44554
|
-
kind: "mutation",
|
|
44555
|
-
auth: "admin"
|
|
44556
|
-
}), method(IdInputSchema, TestResultSchema$1, {
|
|
44557
|
-
kind: "mutation",
|
|
44558
|
-
auth: "admin"
|
|
44559
|
-
}), method(StartEmbeddedInputSchema, StartEmbeddedResultSchema, {
|
|
44560
|
-
kind: "mutation",
|
|
44561
|
-
auth: "admin"
|
|
44562
|
-
}), method(IdInputSchema, _void(), {
|
|
44563
|
-
kind: "mutation",
|
|
44564
|
-
auth: "admin"
|
|
44565
|
-
}), method(_void(), StatusSchema);
|
|
44566
|
-
var NetworkEndpointSchema = object({
|
|
44567
|
-
url: string(),
|
|
44568
|
-
hostname: string(),
|
|
44569
|
-
port: number(),
|
|
44570
|
-
protocol: _enum(["http", "https"]),
|
|
44571
|
-
/**
|
|
44572
|
-
* Whether this address survives a restart of its provider. `false` = it is
|
|
44573
|
-
* re-issued every time (a Quick tunnel's random `*.trycloudflare.com`); the
|
|
44574
|
-
* hub never selects such an address AUTOMATICALLY for a role (D860), though
|
|
44575
|
-
* it stays visible and an operator may still flag it. Absent = stable: every
|
|
44576
|
-
* provider except a Quick tunnel owns a name that does not change.
|
|
44577
|
-
*/
|
|
44578
|
-
stable: boolean().optional()
|
|
44579
|
-
});
|
|
44580
|
-
object({
|
|
44581
|
-
url: string(),
|
|
44582
|
-
/** Mirrors {@link NetworkEndpointSchema} `stable`; absent = stable. */
|
|
44583
|
-
stable: boolean().optional(),
|
|
44584
|
-
updated: boolean().optional()
|
|
44585
|
-
});
|
|
44586
|
-
var NetworkAccessStatusSchema = object({
|
|
44587
|
-
connected: boolean(),
|
|
44588
|
-
endpoint: NetworkEndpointSchema.nullable(),
|
|
44589
|
-
error: string().optional()
|
|
44590
|
-
});
|
|
44591
|
-
/**
|
|
44592
|
-
* Optional, richer endpoint shape returned by providers that expose
|
|
44593
|
-
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
44594
|
-
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
44595
|
-
* the originating provider config (mode + sourcePort) so the
|
|
44596
|
-
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
44597
|
-
* one endpoint just omit `listEndpoints` from their provider impl.
|
|
44598
|
-
*/
|
|
44599
|
-
var NetworkEndpointEntrySchema = NetworkEndpointSchema.extend({
|
|
44600
|
-
/**
|
|
44601
|
-
* Stable id within the provider — typically `<mode>-<sourcePort>` so
|
|
44602
|
-
* the orchestrator can dedupe across `listEndpoints` polls.
|
|
44603
|
-
*/
|
|
44604
|
-
id: string(),
|
|
44605
|
-
/** Operator-facing label (mirrors `MeshEndpoint.label`). */
|
|
44606
|
-
label: string(),
|
|
44607
|
-
/** Optional provider-specific mode tag, used for icon/colour in admin UI. */
|
|
44608
|
-
mode: string().optional(),
|
|
44609
|
-
/** Originating local port the ingress fronts (informational). */
|
|
44610
|
-
sourcePort: number().optional()
|
|
44611
|
-
});
|
|
44612
|
-
method(_void(), NetworkEndpointSchema, { kind: "mutation" }), method(_void(), _void(), { kind: "mutation" }), method(_void(), NetworkEndpointSchema.nullable()), method(_void(), NetworkAccessStatusSchema), method(_void(), array(NetworkEndpointEntrySchema).readonly());
|
|
44613
|
-
/**
|
|
44614
|
-
* notification-output — canonical, capability-gated notification delivery.
|
|
44615
|
-
*
|
|
44616
|
-
* Apprise-derived model (see
|
|
44617
|
-
* `docs/superpowers/specs/2026-07-03-notification-output-notifier-matrix.md`):
|
|
44618
|
-
* callers emit ONE canonical `Notification`; each provider declares a
|
|
44619
|
-
* per-kind capability descriptor (`TargetKind`), and the pure degrade
|
|
44620
|
-
* engine (`@camstack/types` `prepareNotification`) transcodes / degrades the
|
|
44621
|
-
* message to what the kind supports — callers never special-case a service.
|
|
44622
|
-
*
|
|
44623
|
-
* DESIGN DECISIONS (locked):
|
|
44624
|
-
* - Target CRUD lives on THIS cap (`upsertTarget` / `deleteTarget` /
|
|
44625
|
-
* `setTargetEnabled`), each provider persisting via the `settings-store`
|
|
44626
|
-
* cap. Rationale: the admin UI needs one uniform surface across the
|
|
44627
|
-
* notifiers addon AND the HA addon; the addon-`globalSettingsSchema`-array
|
|
44628
|
-
* alternative would fork the UI per addon and cannot host the
|
|
44629
|
-
* discovery→adopt flow.
|
|
44630
|
-
* - `listTargetKinds` / `listTargets` / `discoverTargets` return arrays →
|
|
44631
|
-
* the generated cap-mount auto-`concatCollection`-fans them across every
|
|
44632
|
-
* registered provider (notifiers addon + HA addon) so one catalog is
|
|
44633
|
-
* routable. `send` / `testTarget` / CRUD route to ONE provider by the
|
|
44634
|
-
* `addonId` the generated collection router extracts from the call input.
|
|
44635
|
-
* - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
|
|
44636
|
-
* transformer) + UDS MsgPack both round-trip typed arrays — already used by
|
|
44637
|
-
* `storage` / `storage-provider` / `recording` caps over the same path. No
|
|
44638
|
-
* base64 fallback needed.
|
|
44639
|
-
*
|
|
44640
|
-
* TODO (deferred, closed-set change — separate decision): add
|
|
44641
|
-
* `providerKind: 'notify'` so notification providers surface on the unified
|
|
44642
|
-
* admin "Integrations" page.
|
|
44643
|
-
*/
|
|
44644
|
-
/**
|
|
44645
|
-
* Zentik-derived typed-media enum — the superset across every kind. Each
|
|
44646
|
-
* adapter picks what it supports and the degrade engine filters the rest.
|
|
44647
|
-
*/
|
|
44648
|
-
var AttachmentMediaTypeSchema = _enum([
|
|
44649
|
-
"image",
|
|
44650
|
-
"video",
|
|
44651
|
-
"gif",
|
|
44652
|
-
"audio",
|
|
44653
|
-
"icon"
|
|
44654
|
-
]);
|
|
44655
|
-
/**
|
|
44656
|
-
* A single attachment. Exactly one of `url` (remote source, most adapters
|
|
44657
|
-
* prefer this) or `bytes` (inline source; required for Pushover-style
|
|
44658
|
-
* bytes-only kinds) MUST be present — the degrade engine expresses a
|
|
44659
|
-
* url→bytes fetch as a `needsFetch` directive the adapter executes.
|
|
44660
|
-
*/
|
|
44661
|
-
var AttachmentSchema = object({
|
|
44662
|
-
mediaType: AttachmentMediaTypeSchema,
|
|
44663
|
-
url: string().optional(),
|
|
44664
|
-
bytes: _instanceof(Uint8Array).optional(),
|
|
44665
|
-
mime: string().optional(),
|
|
44666
|
-
name: string().optional()
|
|
44667
|
-
}).refine((a) => a.url !== void 0 || a.bytes !== void 0, { message: "Attachment requires either `url` or `bytes`" });
|
|
44668
|
-
var NotificationFormatSchema = _enum([
|
|
44669
|
-
"text",
|
|
44670
|
-
"markdown",
|
|
44671
|
-
"html"
|
|
44672
|
-
]);
|
|
44673
|
-
/**
|
|
44674
|
-
* The CLOSED icon vocabulary an action button may use.
|
|
44675
|
-
*
|
|
44676
|
-
* A closed set, not a free string, and that is the whole point: an arbitrary
|
|
44677
|
-
* icon name is one that ntfy renders, zentik silently drops, and nobody
|
|
44678
|
-
* notices — the same class of gap as a zone vocabulary nothing produced
|
|
44679
|
-
* ([D35](../../../docs/decisions/adr-0035.md)). Every adapter maps this set or
|
|
44680
|
-
* declares `actionIcons: false` and the degrade engine strips the field.
|
|
44681
|
-
*
|
|
44682
|
-
* Named by INTENT, never by glyph. "check" would tie the vocabulary to one
|
|
44683
|
-
* renderer's icon set; "acknowledge" survives an adapter that draws it
|
|
44684
|
-
* differently.
|
|
44685
|
-
*
|
|
44686
|
-
* ── A TOKEN IS NOT A WIRE VALUE ─────────────────────────────────────
|
|
44687
|
-
*
|
|
44688
|
-
* These names are for US. **No adapter may forward one verbatim.** Each maps
|
|
44689
|
-
* the whole set onto its own renderer's vocabulary through a
|
|
44690
|
-
* `Record<NotificationActionIcon, string>` — a Record, never a lookup with a
|
|
44691
|
-
* fallback, so adding a member here fails every adapter's build until someone
|
|
44692
|
-
* decides its glyph, which is the only place that decision can be made
|
|
44693
|
-
* honestly.
|
|
44694
|
-
*
|
|
44695
|
-
* This paragraph is the bug. Zentik declared `actionIcons: true` and passed
|
|
44696
|
-
* `disarm` straight through; iOS feeds that string to
|
|
44697
|
-
* `UNNotificationActionIcon(systemImageName:)`, `disarm` is not an SF Symbol,
|
|
44698
|
-
* and every snooze and alarm button arrived BLANK. A pass-through is not a
|
|
44699
|
-
* mapping, and "the field is documented" is not "the value renders".
|
|
44700
|
-
*
|
|
44701
|
-
* Adding a member is TRAIN-BOUND. The enum lives in the published
|
|
44702
|
-
* `@camstack/server` closure and the cap seam validates against the HUB's copy,
|
|
44703
|
-
* so an addon that emits a token the running hub does not know does not lose an
|
|
44704
|
-
* icon — its whole `send` fails Zod validation and the notification never
|
|
44705
|
-
* arrives. Never emit a new token from an addon before the train carrying it.
|
|
44706
|
-
*/
|
|
44707
|
-
var NotificationActionIconSchema = _enum([
|
|
44708
|
-
"acknowledge",
|
|
44709
|
-
"dismiss",
|
|
44710
|
-
"silence",
|
|
44711
|
-
"snooze",
|
|
44712
|
-
"view",
|
|
44713
|
-
"play",
|
|
44714
|
-
"open",
|
|
44715
|
-
"close",
|
|
44716
|
-
"lock",
|
|
44717
|
-
"unlock",
|
|
44718
|
-
"arm",
|
|
44719
|
-
"arm-home",
|
|
44720
|
-
"arm-away",
|
|
44721
|
-
"arm-night",
|
|
44722
|
-
"disarm",
|
|
44723
|
-
"light",
|
|
44724
|
-
"alert",
|
|
44725
|
-
"camera"
|
|
44726
|
-
]);
|
|
44727
|
-
/** A single tap-through action button. */
|
|
44728
|
-
var NotificationActionSchema = object({
|
|
44729
|
-
id: string(),
|
|
44730
|
-
label: string(),
|
|
44731
|
-
url: string().optional(),
|
|
44732
|
-
/** Dropped by the degrade engine for a kind with `caps.actionIcons: false`. */
|
|
44733
|
-
icon: NotificationActionIconSchema.optional(),
|
|
44734
|
-
/**
|
|
44735
|
-
* Renders in a warning style where the notifier supports it.
|
|
44736
|
-
*
|
|
44737
|
-
* A HINT, never a gate. The callback's authority is its token and nothing
|
|
44738
|
-
* else — see `notification-center/action-token.ts` for what that does and
|
|
44739
|
-
* does not buy.
|
|
44740
|
-
*/
|
|
44741
|
-
destructive: boolean().optional(),
|
|
44742
|
-
/**
|
|
44743
|
-
* How the tap should REACH the url.
|
|
44744
|
-
*
|
|
44745
|
-
* `navigate` (absent, and every button authored before this field) opens it:
|
|
44746
|
-
* the phone leaves the notification and shows whatever the callback returns.
|
|
44747
|
-
* That is right for a button whose answer the operator wants to read.
|
|
44748
|
-
*
|
|
44749
|
-
* `background` fires it as a POST and stays put. It exists for the buttons
|
|
44750
|
-
* whose whole point is not to interrupt — "silence this for 30 minutes" is
|
|
44751
|
-
* an answer to the notification, and being thrown into a browser tab to
|
|
44752
|
-
* confirm it costs more attention than the notification did. A backend that
|
|
44753
|
-
* cannot do a background call renders it as an ordinary link (the adapters
|
|
44754
|
-
* fall back rather than dropping the button), so this is a preference, never
|
|
44755
|
-
* a requirement.
|
|
44756
|
-
*/
|
|
44757
|
-
mode: _enum(["navigate", "background"]).optional()
|
|
44758
|
-
});
|
|
44759
|
-
/** A delivery parameter value: what a notifier declared it takes. */
|
|
44760
|
-
var DeliveryParamValueSchema = union([
|
|
44761
|
-
string(),
|
|
44762
|
-
number(),
|
|
44763
|
-
boolean()
|
|
44764
|
-
]);
|
|
44765
|
-
/**
|
|
44766
|
-
* One extra delivery parameter a notifier KIND declares (D938). A rule that
|
|
44767
|
-
* addresses a target of that kind may set it; a kind that declares nothing is
|
|
44768
|
-
* never handed one. The admin UI derives its control from this descriptor —
|
|
44769
|
-
* no editor knows a service by name.
|
|
44770
|
-
*
|
|
44771
|
-
* Optional fields are `.optional()`, never `.default()` (a Zod default does not
|
|
44772
|
-
* run on the addon cap path).
|
|
44773
|
-
*/
|
|
44774
|
-
var DeliveryParamSchema = object({
|
|
44775
|
-
key: string().min(1),
|
|
44776
|
-
label: string(),
|
|
44777
|
-
/** i18n key of the label, resolved by the declaring addon's namespace. */
|
|
44778
|
-
labelKey: string().optional(),
|
|
44779
|
-
type: _enum([
|
|
44780
|
-
"enum",
|
|
44781
|
-
"number",
|
|
44782
|
-
"boolean",
|
|
44783
|
-
"string"
|
|
44784
|
-
]),
|
|
44785
|
-
/** `enum` only: the closed set of accepted values. */
|
|
44786
|
-
options: array(object({
|
|
44787
|
-
value: string(),
|
|
44788
|
-
label: string()
|
|
44789
|
-
})).optional(),
|
|
44790
|
-
/** `number` only. */
|
|
44791
|
-
min: number().optional(),
|
|
44792
|
-
max: number().optional(),
|
|
44793
|
-
/** What the notifier does when the rule sets nothing; shown as the placeholder. */
|
|
44794
|
-
default: DeliveryParamValueSchema.optional()
|
|
44795
|
-
});
|
|
44796
|
-
/**
|
|
44797
|
-
* The canonical notification. `body` is the only hard field (Apprise model).
|
|
44798
|
-
* `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
|
|
44799
|
-
* NOT a fixed severity enum — each kind declares its own `caps.levels` and
|
|
44800
|
-
* the adapter maps this ordinal onto its native level. `level?` is an
|
|
44801
|
-
* optional kind-native level id (`emergency`, `silent`, …) that overrides
|
|
44802
|
-
* `priority` for that one target.
|
|
44803
|
-
*/
|
|
44804
|
-
var NotificationSchema = object({
|
|
44805
|
-
body: string(),
|
|
44806
|
-
title: string().optional(),
|
|
44807
|
-
format: NotificationFormatSchema.default("text"),
|
|
44808
|
-
priority: number().int().min(1).max(5).default(3),
|
|
44809
|
-
level: string().optional(),
|
|
44810
|
-
attachments: array(AttachmentSchema).optional(),
|
|
44811
|
-
clickUrl: string().optional(),
|
|
44812
|
-
actions: array(NotificationActionSchema).optional(),
|
|
44813
|
-
sound: string().optional(),
|
|
44814
|
-
ttl: number().optional(),
|
|
44815
|
-
tag: string().optional(),
|
|
44816
|
-
deviceId: number().optional(),
|
|
44817
|
-
eventId: string().optional(),
|
|
44818
|
-
metadata: record(string(), unknown()).optional(),
|
|
44819
|
-
/**
|
|
44820
|
-
* Values for the parameters the target's kind DECLARES in
|
|
44821
|
-
* {@link TargetKindSchema} `deliveryParams`. Already validated against the
|
|
44822
|
-
* declaration by the sender; a notifier reads only the keys it declared.
|
|
44823
|
-
*/
|
|
44824
|
-
delivery: record(string(), DeliveryParamValueSchema).optional()
|
|
44825
|
-
});
|
|
44826
|
-
/** One declared native severity/priority level for a kind. */
|
|
44827
|
-
var TargetKindLevelSchema = object({
|
|
44828
|
-
id: string(),
|
|
44829
|
-
label: string(),
|
|
44830
|
-
/** Which canonical priority (1..5) this level maps to. `null` = qualitative-only. */
|
|
44831
|
-
ordinal: number().int().min(1).max(5).nullable(),
|
|
44832
|
-
flags: object({
|
|
44833
|
-
critical: boolean().optional(),
|
|
44834
|
-
silent: boolean().optional(),
|
|
44835
|
-
noPush: boolean().optional()
|
|
44836
|
-
}).optional(),
|
|
44837
|
-
/** e.g. Pushover `emergency` requires `retry` / `expire`. */
|
|
44838
|
-
requires: array(string()).optional(),
|
|
44839
|
-
description: string().optional()
|
|
44840
|
-
});
|
|
44841
|
-
/** The full capability block consulted before dispatch. */
|
|
44842
|
-
var TargetKindCapsSchema = object({
|
|
44843
|
-
attachments: object({
|
|
44844
|
-
mediaTypes: array(AttachmentMediaTypeSchema),
|
|
44845
|
-
mode: _enum([
|
|
44846
|
-
"url",
|
|
44847
|
-
"bytes",
|
|
44848
|
-
"both"
|
|
44849
|
-
]),
|
|
44850
|
-
max: number().int().nonnegative(),
|
|
44851
|
-
maxBytes: number().int().positive().optional()
|
|
44852
|
-
}),
|
|
44853
|
-
/** Max action buttons (0 = none). */
|
|
44854
|
-
actions: number().int().nonnegative(),
|
|
44855
|
-
/**
|
|
44856
|
-
* Whether this kind renders a per-action ICON.
|
|
44857
|
-
*
|
|
44858
|
-
* `.optional()`, deliberately NOT `.default(false)`: a Zod default does not
|
|
44859
|
-
* run on the addon cap path — three production failures in one day taught
|
|
44860
|
-
* this repo that once. Absent is read as false by the degrade engine, which
|
|
44861
|
-
* is the safe direction: an icon that is not rendered costs nothing, an icon
|
|
44862
|
-
* assumed and dropped costs the operator's trust in the field.
|
|
44863
|
-
*/
|
|
44864
|
-
actionIcons: boolean().optional(),
|
|
44865
|
-
levels: array(TargetKindLevelSchema),
|
|
44866
|
-
format: array(NotificationFormatSchema),
|
|
44867
|
-
clickUrl: boolean(),
|
|
44868
|
-
sound: boolean(),
|
|
44869
|
-
ttl: boolean(),
|
|
44870
|
-
bodyMaxLen: number().int().positive()
|
|
44871
|
-
});
|
|
44872
|
-
/**
|
|
44873
|
-
* `configSchema` is a `ConfigUISchema` tree passed through to the admin
|
|
44874
|
-
* FormBuilder. Stored as `z.unknown()` at the cap seam (mirrors
|
|
44875
|
-
* `device-provider.getChildCreationSchema` `CreationSchemaOutputSchema`) —
|
|
44876
|
-
* the union is large and not meant for runtime validation here; the exported
|
|
44877
|
-
* `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
|
|
44878
|
-
*/
|
|
44879
|
-
var ConfigSchemaPassthrough$2 = unknown();
|
|
44880
|
-
var TargetKindSchema = object({
|
|
44881
|
-
kind: string(),
|
|
44882
|
-
label: string(),
|
|
44883
|
-
icon: string(),
|
|
44884
|
-
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
44885
|
-
addonId: string(),
|
|
44886
|
-
/**
|
|
44887
|
-
* URL of the kind's bundled BRAND icon, served by the providing addon over
|
|
44888
|
-
* its own `addon-routes` surface (`/addon/<addonId>/icons/<kind>`). Absent
|
|
44889
|
-
* when the addon bundles no icon for that kind — the client then falls back
|
|
44890
|
-
* to a neutral glyph rather than rendering the raw `icon` NAME as text.
|
|
44891
|
-
*
|
|
44892
|
-
* Root-relative on purpose: it resolves against whatever origin serves a web
|
|
44893
|
-
* client, and a native client joins it onto its own hub base.
|
|
44894
|
-
*
|
|
44895
|
-
* DECLARED here deliberately. It used to travel as an undeclared passthrough
|
|
44896
|
-
* field that survived only because the runtime cap-router forwards provider
|
|
44897
|
-
* output verbatim — so every consumer had to re-declare it by hand to stop
|
|
44898
|
-
* its own Zod parse from stripping it, and the whole arrangement would have
|
|
44899
|
-
* broken silently the moment output validation was tightened anywhere.
|
|
44900
|
-
*/
|
|
44901
|
-
iconUrl: string().optional(),
|
|
44902
|
-
/**
|
|
44903
|
-
* Media type of {@link iconUrl} (`image/svg+xml`, `image/png`, …).
|
|
44904
|
-
*
|
|
44905
|
-
* The server knows this and therefore says it, because the client cannot
|
|
44906
|
-
* safely guess: a React-Native client renders SVG and raster through two
|
|
44907
|
-
* DIFFERENT components (`react-native-svg` vs `expo-image` — expo-image does
|
|
44908
|
-
* not decode SVG on iOS/Android), so without this it silently fell back to a
|
|
44909
|
-
* placeholder glyph for every vector icon while the web build looked fine.
|
|
44910
|
-
*
|
|
44911
|
-
* Absent when {@link iconUrl} is absent, or for a legacy provider that has
|
|
44912
|
-
* not been updated — a client that cannot determine the type should prefer
|
|
44913
|
-
* its raster path, which is the safe default for an unknown image.
|
|
44922
|
+
* that node's provider (`generated-cap-routers.ts`). A series target
|
|
44923
|
+
* called `nodeId` would silently become a routing pin and never reach
|
|
44924
|
+
* the provider. The hub holds every node it hears from, so the
|
|
44925
|
+
* ordinary call is unpinned — answered by the hub, for any node.
|
|
44914
44926
|
*/
|
|
44915
|
-
|
|
44916
|
-
configSchema: ConfigSchemaPassthrough$2,
|
|
44927
|
+
forNodeId: string(),
|
|
44917
44928
|
/**
|
|
44918
|
-
*
|
|
44919
|
-
*
|
|
44920
|
-
*
|
|
44921
|
-
* editor uses this to ask for the secret on exactly those edits instead of
|
|
44922
|
-
* on every edit.
|
|
44923
|
-
*
|
|
44924
|
-
* Optional: absent from a provider that holds no secret (the Home Assistant
|
|
44925
|
-
* kinds) and from a provider older than this field — an editor that finds
|
|
44926
|
-
* it absent must assume ANY edit may need the secret.
|
|
44929
|
+
* EXCLUSIVE lower bound. A caller passes the newest `atMs` it already
|
|
44930
|
+
* holds and receives only what it is missing, so seeding a live chart
|
|
44931
|
+
* from this method cannot double a point already drawn.
|
|
44927
44932
|
*/
|
|
44928
|
-
|
|
44929
|
-
supportsDiscovery: boolean(),
|
|
44933
|
+
sinceMs: number().optional(),
|
|
44930
44934
|
/**
|
|
44931
|
-
*
|
|
44932
|
-
*
|
|
44935
|
+
* Most points the caller wants PER FUNCTION. The window is reduced to fit,
|
|
44936
|
+
* preserving min and max per bucket.
|
|
44937
|
+
*
|
|
44938
|
+
* Absent means NO reduction — legitimate for a short window and a trap for a
|
|
44939
|
+
* long one, which is why a chart passes its own pixel width.
|
|
44933
44940
|
*/
|
|
44934
|
-
|
|
44935
|
-
|
|
44941
|
+
maxPoints: number().int().positive().optional()
|
|
44942
|
+
});
|
|
44943
|
+
var SystemMetricsSchema = object({
|
|
44944
|
+
cpuPercent: number(),
|
|
44945
|
+
/** `null` when the memory sample failed or was not taken yet (D393). */
|
|
44946
|
+
memoryPercent: number().nullable(),
|
|
44947
|
+
memoryUsedMB: number().nullable(),
|
|
44948
|
+
memoryTotalMB: number(),
|
|
44949
|
+
diskPercent: number().optional(),
|
|
44950
|
+
temperature: number().optional(),
|
|
44951
|
+
gpuPercent: number().optional(),
|
|
44952
|
+
gpuMemoryPercent: number().optional()
|
|
44953
|
+
});
|
|
44954
|
+
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);
|
|
44955
|
+
method(object({
|
|
44956
|
+
sourceUrl: string(),
|
|
44957
|
+
metadata: ModelConvertMetadataSchema,
|
|
44958
|
+
targets: array(ConvertTargetSchema).min(1).readonly(),
|
|
44959
|
+
calibrationRef: string().optional(),
|
|
44960
|
+
sessionId: string().optional()
|
|
44961
|
+
}), ConvertResultSchema, {
|
|
44962
|
+
kind: "mutation",
|
|
44963
|
+
auth: "admin",
|
|
44964
|
+
timeoutMs: 6e5
|
|
44965
|
+
});
|
|
44966
|
+
method(object({
|
|
44967
|
+
targetNodeId: string(),
|
|
44968
|
+
modelId: string(),
|
|
44969
|
+
format: _enum(MODEL_FORMATS),
|
|
44970
|
+
entry: ModelCatalogEntrySchema
|
|
44971
|
+
}), object({
|
|
44972
|
+
ok: boolean(),
|
|
44973
|
+
/** sha256 of the staged tarball (empty for a hub-local no-op). */
|
|
44974
|
+
sha256: string(),
|
|
44975
|
+
bytes: number(),
|
|
44976
|
+
/** The target node's modelsDir the artifact landed in. */
|
|
44977
|
+
path: string()
|
|
44978
|
+
}), {
|
|
44979
|
+
kind: "mutation",
|
|
44980
|
+
auth: "admin"
|
|
44981
|
+
});
|
|
44982
|
+
var MotionRegionSchema = object({
|
|
44983
|
+
bbox: BoundingBoxSchema,
|
|
44984
|
+
pixelCount: number(),
|
|
44985
|
+
intensity: number()
|
|
44986
|
+
});
|
|
44987
|
+
var MotionAnalysisResultSchema = object({
|
|
44988
|
+
detected: boolean(),
|
|
44989
|
+
regionCount: number(),
|
|
44990
|
+
/** Regions passing minArea filter — used for pipeline triggering. */
|
|
44991
|
+
regions: array(MotionRegionSchema).readonly(),
|
|
44992
|
+
/** All raw regions from CCL before minArea filter — used for UI debug overlay. */
|
|
44993
|
+
rawRegions: array(MotionRegionSchema).readonly(),
|
|
44994
|
+
frameWidth: number(),
|
|
44995
|
+
frameHeight: number(),
|
|
44996
|
+
analysisMs: number()
|
|
44997
|
+
});
|
|
44998
|
+
DeviceType.Camera, method(object({
|
|
44999
|
+
deviceId: number(),
|
|
45000
|
+
frame: FrameInputSchema.optional(),
|
|
45001
|
+
frameHandle: FrameHandleSchema.optional()
|
|
45002
|
+
}), MotionAnalysisResultSchema, {
|
|
45003
|
+
role: "admin",
|
|
45004
|
+
kind: "mutation"
|
|
45005
|
+
}), method(object({ deviceId: number() }), _void(), {
|
|
45006
|
+
role: "admin",
|
|
45007
|
+
kind: "mutation"
|
|
45008
|
+
}), method(_void(), _void(), {
|
|
45009
|
+
role: "admin",
|
|
45010
|
+
kind: "mutation"
|
|
45011
|
+
}), object({
|
|
45012
|
+
deviceId: number(),
|
|
45013
|
+
detected: boolean(),
|
|
45014
|
+
regionCount: number()
|
|
44936
45015
|
});
|
|
44937
45016
|
/**
|
|
44938
|
-
*
|
|
44939
|
-
*
|
|
44940
|
-
*
|
|
45017
|
+
* `mqtt-broker` — broker-registry cap.
|
|
45018
|
+
*
|
|
45019
|
+
* NOT a pub/sub proxy. The cap exposes (a) a registry of configured
|
|
45020
|
+
* MQTT brokers (external + optionally an embedded `aedes`-backed one)
|
|
45021
|
+
* and (b) the connection details a consumer addon needs to spin up
|
|
45022
|
+
* its OWN `mqtt.js` client.
|
|
45023
|
+
*
|
|
45024
|
+
* Why: pub/sub routing over the system event-bus loses fidelity
|
|
45025
|
+
* (callback shape, QoS guarantees, will/retain semantics) and adds
|
|
45026
|
+
* refcount bookkeeping that addons would rather own themselves. The
|
|
45027
|
+
* canonical consumer needs raw `mqtt.js`
|
|
45028
|
+
* features anyway — give it the connection config, get out of the way.
|
|
45029
|
+
*
|
|
45030
|
+
* Consumer flow:
|
|
45031
|
+
* const cfg = await ctx.api.mqttBroker.getBrokerConfig({ id })
|
|
45032
|
+
* const client = mqtt.connect(cfg.url, { username: cfg.username, … })
|
|
45033
|
+
* client.subscribe('zigbee2mqtt/+')
|
|
45034
|
+
*
|
|
45035
|
+
* Collection mode: multiple brokers (e.g. one local mosquitto + one
|
|
45036
|
+
* cloud bridge). The "embedded" entry (when present) is just another
|
|
45037
|
+
* broker in the registry — its lifecycle is owned by the addon that
|
|
45038
|
+
* spawned it.
|
|
44941
45039
|
*/
|
|
44942
|
-
var
|
|
45040
|
+
var BrokerKindSchema = _enum(["external", "embedded"]);
|
|
45041
|
+
/**
|
|
45042
|
+
* Broker live-probe status.
|
|
45043
|
+
*
|
|
45044
|
+
* - `connected` — last probe completed a clean CONNACK
|
|
45045
|
+
* - `disconnected` — no probe has run yet (cold cache)
|
|
45046
|
+
* - `auth-failed` — CONNACK refused with auth error (RC 4 / 5)
|
|
45047
|
+
* - `unreachable` — TCP connect timed out / refused
|
|
45048
|
+
* - `tls-error` — TLS handshake failed (cert / SNI / cipher)
|
|
45049
|
+
*/
|
|
45050
|
+
var BrokerStatusSchema$1 = _enum([
|
|
45051
|
+
"connected",
|
|
45052
|
+
"disconnected",
|
|
45053
|
+
"auth-failed",
|
|
45054
|
+
"unreachable",
|
|
45055
|
+
"tls-error"
|
|
45056
|
+
]);
|
|
45057
|
+
var BrokerInfoSchema$1 = object({
|
|
44943
45058
|
id: string(),
|
|
44944
45059
|
name: string(),
|
|
44945
|
-
|
|
44946
|
-
|
|
44947
|
-
|
|
44948
|
-
|
|
44949
|
-
});
|
|
44950
|
-
/** A discovery-surfaced candidate (config is partial + non-secret). */
|
|
44951
|
-
var DiscoveredTargetSchema = object({
|
|
44952
|
-
kind: string(),
|
|
44953
|
-
suggestedName: string(),
|
|
44954
|
-
config: record(string(), unknown())
|
|
44955
|
-
});
|
|
44956
|
-
/** The degrade engine's report — what was resolved / dropped / degraded. */
|
|
44957
|
-
var RenderedAsSchema = object({
|
|
44958
|
-
level: string(),
|
|
44959
|
-
format: NotificationFormatSchema,
|
|
44960
|
-
attachmentsSent: number().int().nonnegative(),
|
|
44961
|
-
actionsSent: number().int().nonnegative(),
|
|
44962
|
-
truncated: boolean(),
|
|
44963
|
-
dropped: array(string())
|
|
44964
|
-
});
|
|
44965
|
-
var SendResultSchema = object({
|
|
44966
|
-
success: boolean(),
|
|
45060
|
+
url: string(),
|
|
45061
|
+
kind: BrokerKindSchema,
|
|
45062
|
+
status: BrokerStatusSchema$1,
|
|
45063
|
+
latencyMs: number().nullable(),
|
|
44967
45064
|
error: string().optional(),
|
|
44968
|
-
|
|
45065
|
+
/** Embedded brokers only: number of MQTT clients currently connected. */
|
|
45066
|
+
connectedClients: number().int().nonnegative().optional(),
|
|
45067
|
+
/** Epoch ms of the last live probe (external) or aedes snapshot (embedded). */
|
|
45068
|
+
lastCheckedAt: number().optional()
|
|
44969
45069
|
});
|
|
44970
|
-
/** Same shape as SendResult — kept as a distinct name for the test panel. */
|
|
44971
|
-
var TestResultSchema = SendResultSchema;
|
|
44972
45070
|
/**
|
|
44973
|
-
*
|
|
44974
|
-
* `
|
|
45071
|
+
* Connection details — what a consumer needs to call
|
|
45072
|
+
* `mqtt.connect(url, options)`. We split URL + credentials so the
|
|
45073
|
+
* consumer can pass them as `mqtt.connect(url, { username, password })`
|
|
45074
|
+
* instead of stuffing creds into the URL (which leaks them into logs).
|
|
44975
45075
|
*/
|
|
44976
|
-
var
|
|
44977
|
-
|
|
44978
|
-
|
|
44979
|
-
|
|
44980
|
-
stateInstance: string().optional(),
|
|
44981
|
-
error: string().optional()
|
|
44982
|
-
});
|
|
44983
|
-
method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSchema), { auth: "admin" }), method(object({ targetId: string() }), TargetSchema, { auth: "admin" }), method(object({
|
|
44984
|
-
kind: string(),
|
|
44985
|
-
config: record(string(), unknown()).optional(),
|
|
45076
|
+
var BrokerConnectionDetailsSchema = object({
|
|
45077
|
+
url: string(),
|
|
45078
|
+
username: string().optional(),
|
|
45079
|
+
password: string().optional(),
|
|
44986
45080
|
/**
|
|
44987
|
-
*
|
|
44988
|
-
*
|
|
44989
|
-
*
|
|
45081
|
+
* Suggested prefix for `clientId`. Each consumer should suffix this
|
|
45082
|
+
* with its own discriminator (addon id, instance id) so reconnects
|
|
45083
|
+
* don't kick each other off (MQTT spec: clientId must be unique per
|
|
45084
|
+
* broker).
|
|
44990
45085
|
*/
|
|
44991
|
-
|
|
44992
|
-
})
|
|
44993
|
-
|
|
44994
|
-
|
|
44995
|
-
|
|
44996
|
-
|
|
44997
|
-
|
|
44998
|
-
|
|
44999
|
-
|
|
45000
|
-
|
|
45001
|
-
|
|
45002
|
-
|
|
45003
|
-
|
|
45086
|
+
clientIdPrefix: string().optional()
|
|
45087
|
+
});
|
|
45088
|
+
var AddBrokerInputSchema = object({
|
|
45089
|
+
name: string().min(1),
|
|
45090
|
+
url: string().regex(/^(mqtt|mqtts|ws|wss):\/\//, "URL must start with mqtt(s):// or ws(s)://"),
|
|
45091
|
+
username: string().optional(),
|
|
45092
|
+
password: string().optional(),
|
|
45093
|
+
clientIdPrefix: string().optional()
|
|
45094
|
+
});
|
|
45095
|
+
var AddBrokerResultSchema = object({ id: string() });
|
|
45096
|
+
var IdInputSchema = object({ id: string() });
|
|
45097
|
+
var TestResultSchema$1 = discriminatedUnion("ok", [object({
|
|
45098
|
+
ok: literal(true),
|
|
45099
|
+
latencyMs: number()
|
|
45100
|
+
}), object({
|
|
45101
|
+
ok: literal(false),
|
|
45102
|
+
error: string()
|
|
45103
|
+
})]);
|
|
45104
|
+
var StartEmbeddedInputSchema = object({
|
|
45105
|
+
port: number().int().min(1).max(65535).default(1883),
|
|
45106
|
+
/** Allow anonymous connect (no username/password). Default: false. */
|
|
45107
|
+
allowAnonymous: boolean().default(false),
|
|
45108
|
+
/** Optional shared username/password for clients. */
|
|
45109
|
+
username: string().optional(),
|
|
45110
|
+
password: string().optional()
|
|
45111
|
+
});
|
|
45112
|
+
var StartEmbeddedResultSchema = object({
|
|
45113
|
+
id: string(),
|
|
45114
|
+
url: string()
|
|
45115
|
+
});
|
|
45116
|
+
var StatusSchema = object({
|
|
45117
|
+
brokerCount: number(),
|
|
45118
|
+
embeddedRunning: boolean()
|
|
45119
|
+
});
|
|
45120
|
+
method(_void(), array(BrokerInfoSchema$1)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
|
|
45004
45121
|
kind: "mutation",
|
|
45005
45122
|
auth: "admin"
|
|
45006
|
-
}), method(
|
|
45007
|
-
targetId: string(),
|
|
45008
|
-
sample: NotificationSchema.optional()
|
|
45009
|
-
}), TestResultSchema, {
|
|
45123
|
+
}), method(IdInputSchema, _void(), {
|
|
45010
45124
|
kind: "mutation",
|
|
45011
45125
|
auth: "admin"
|
|
45012
|
-
}), method(
|
|
45013
|
-
target: TargetSchema,
|
|
45014
|
-
/**
|
|
45015
|
-
* Duplicate flow: create a NEW target id while copying secrets from an
|
|
45016
|
-
* existing row. The UI never holds the stored token; blank / redacted
|
|
45017
|
-
* password fields are restored from this source (D634 still applies if
|
|
45018
|
-
* destinations diverge without a re-typed secret).
|
|
45019
|
-
*/
|
|
45020
|
-
cloneSecretsFrom: string().optional()
|
|
45021
|
-
}), TargetSchema, {
|
|
45126
|
+
}), method(IdInputSchema, TestResultSchema$1, {
|
|
45022
45127
|
kind: "mutation",
|
|
45023
45128
|
auth: "admin"
|
|
45024
|
-
}), method(
|
|
45129
|
+
}), method(StartEmbeddedInputSchema, StartEmbeddedResultSchema, {
|
|
45025
45130
|
kind: "mutation",
|
|
45026
45131
|
auth: "admin"
|
|
45027
|
-
}), method(
|
|
45028
|
-
targetId: string(),
|
|
45029
|
-
enabled: boolean()
|
|
45030
|
-
}), _void(), {
|
|
45132
|
+
}), method(IdInputSchema, _void(), {
|
|
45031
45133
|
kind: "mutation",
|
|
45032
45134
|
auth: "admin"
|
|
45135
|
+
}), method(_void(), StatusSchema);
|
|
45136
|
+
var NetworkEndpointSchema = object({
|
|
45137
|
+
url: string(),
|
|
45138
|
+
hostname: string(),
|
|
45139
|
+
port: number(),
|
|
45140
|
+
protocol: _enum(["http", "https"]),
|
|
45141
|
+
/**
|
|
45142
|
+
* Whether this address survives a restart of its provider. `false` = it is
|
|
45143
|
+
* re-issued every time (a Quick tunnel's random `*.trycloudflare.com`); the
|
|
45144
|
+
* hub never selects such an address AUTOMATICALLY for a role (D860), though
|
|
45145
|
+
* it stays visible and an operator may still flag it. Absent = stable: every
|
|
45146
|
+
* provider except a Quick tunnel owns a name that does not change.
|
|
45147
|
+
*/
|
|
45148
|
+
stable: boolean().optional()
|
|
45149
|
+
});
|
|
45150
|
+
object({
|
|
45151
|
+
url: string(),
|
|
45152
|
+
/** Mirrors {@link NetworkEndpointSchema} `stable`; absent = stable. */
|
|
45153
|
+
stable: boolean().optional(),
|
|
45154
|
+
updated: boolean().optional()
|
|
45155
|
+
});
|
|
45156
|
+
var NetworkAccessStatusSchema = object({
|
|
45157
|
+
connected: boolean(),
|
|
45158
|
+
endpoint: NetworkEndpointSchema.nullable(),
|
|
45159
|
+
error: string().optional()
|
|
45160
|
+
});
|
|
45161
|
+
/**
|
|
45162
|
+
* Optional, richer endpoint shape returned by providers that expose
|
|
45163
|
+
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
45164
|
+
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
45165
|
+
* the originating provider config (mode + sourcePort) so the
|
|
45166
|
+
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
45167
|
+
* one endpoint just omit `listEndpoints` from their provider impl.
|
|
45168
|
+
*/
|
|
45169
|
+
var NetworkEndpointEntrySchema = NetworkEndpointSchema.extend({
|
|
45170
|
+
/**
|
|
45171
|
+
* Stable id within the provider — typically `<mode>-<sourcePort>` so
|
|
45172
|
+
* the orchestrator can dedupe across `listEndpoints` polls.
|
|
45173
|
+
*/
|
|
45174
|
+
id: string(),
|
|
45175
|
+
/** Operator-facing label (mirrors `MeshEndpoint.label`). */
|
|
45176
|
+
label: string(),
|
|
45177
|
+
/** Optional provider-specific mode tag, used for icon/colour in admin UI. */
|
|
45178
|
+
mode: string().optional(),
|
|
45179
|
+
/** Originating local port the ingress fronts (informational). */
|
|
45180
|
+
sourcePort: number().optional()
|
|
45033
45181
|
});
|
|
45182
|
+
method(_void(), NetworkEndpointSchema, { kind: "mutation" }), method(_void(), _void(), { kind: "mutation" }), method(_void(), NetworkEndpointSchema.nullable()), method(_void(), NetworkAccessStatusSchema), method(_void(), array(NetworkEndpointEntrySchema).readonly());
|
|
45034
45183
|
var AUDIO_MACRO_LABELS = [
|
|
45035
45184
|
{
|
|
45036
45185
|
id: "speech",
|
|
@@ -51431,14 +51580,6 @@ var EngineProvisioningSchema = object({
|
|
|
51431
51580
|
*/
|
|
51432
51581
|
configIssues: array(string()).optional()
|
|
51433
51582
|
});
|
|
51434
|
-
var PipelineStepInputSchema = lazy(() => object({
|
|
51435
|
-
addonId: string(),
|
|
51436
|
-
modelId: string().optional(),
|
|
51437
|
-
enabled: boolean().default(true),
|
|
51438
|
-
children: array(PipelineStepInputSchema).optional(),
|
|
51439
|
-
settings: record(string(), unknown()).optional(),
|
|
51440
|
-
jumpDeviceKey: string().optional()
|
|
51441
|
-
}));
|
|
51442
51583
|
var ModelSubstitutionSchema = object({
|
|
51443
51584
|
addonId: string(),
|
|
51444
51585
|
chosen: string(),
|
|
@@ -51517,7 +51658,6 @@ var ConfigUISchemaBridge = custom();
|
|
|
51517
51658
|
var ConfigUISchemaNullableBridge = custom();
|
|
51518
51659
|
var InferenceCapabilitiesBridge = custom();
|
|
51519
51660
|
var ModelAvailabilityListBridge = custom();
|
|
51520
|
-
var PipelineRunResultBridge = custom();
|
|
51521
51661
|
method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
|
|
51522
51662
|
modelId: string(),
|
|
51523
51663
|
settings: record(string(), unknown()).readonly()
|
|
@@ -54679,6 +54819,12 @@ var ServerUpdateActionResultSchema = object({
|
|
|
54679
54819
|
*/
|
|
54680
54820
|
blockers: array(UpdateBlockerSchema).optional()
|
|
54681
54821
|
});
|
|
54822
|
+
var LaunchOverridesSchema = object({
|
|
54823
|
+
/** The persisted heap ceiling in MB, or `null` when none is set. */
|
|
54824
|
+
heapMb: number().int().nullable() });
|
|
54825
|
+
var SetLaunchOverridesResultSchema = LaunchOverridesSchema.extend({
|
|
54826
|
+
/** Always true: the override is read at launch, not by the running process. */
|
|
54827
|
+
restartRequired: boolean() });
|
|
54682
54828
|
method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), ServerUpdateCheckResultSchema, {
|
|
54683
54829
|
kind: "mutation",
|
|
54684
54830
|
auth: "admin"
|
|
@@ -54701,6 +54847,9 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
|
|
|
54701
54847
|
}), method(_void(), ServerUpdateActionResultSchema, {
|
|
54702
54848
|
kind: "mutation",
|
|
54703
54849
|
auth: "admin"
|
|
54850
|
+
}), method(_void(), LaunchOverridesSchema, { auth: "admin" }), method(object({ heapMb: number().int().min(512).max(65536).nullable() }), SetLaunchOverridesResultSchema, {
|
|
54851
|
+
kind: "mutation",
|
|
54852
|
+
auth: "admin"
|
|
54704
54853
|
});
|
|
54705
54854
|
/**
|
|
54706
54855
|
* `smtp-provider` — pluggable email delivery surface.
|
|
@@ -59191,7 +59340,7 @@ object({
|
|
|
59191
59340
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
59192
59341
|
lastFetchedAt: number()
|
|
59193
59342
|
});
|
|
59194
|
-
var DeviceIdSchema = number().int().nonnegative();
|
|
59343
|
+
var DeviceIdSchema$1 = number().int().nonnegative();
|
|
59195
59344
|
/** A value a program option or setting can take. */
|
|
59196
59345
|
var DishwasherValueSchema = union([
|
|
59197
59346
|
boolean(),
|
|
@@ -59255,77 +59404,77 @@ var DishwasherOptionsSchema = object({
|
|
|
59255
59404
|
options: array(DishwasherOptionDescriptorSchema)
|
|
59256
59405
|
});
|
|
59257
59406
|
DeviceType.Dishwasher, method(object({
|
|
59258
|
-
deviceId: DeviceIdSchema,
|
|
59407
|
+
deviceId: DeviceIdSchema$1,
|
|
59259
59408
|
program: string().min(1).optional(),
|
|
59260
59409
|
options: record(string(), DishwasherValueSchema).optional()
|
|
59261
59410
|
}), _void(), {
|
|
59262
59411
|
kind: "mutation",
|
|
59263
59412
|
auth: "protected"
|
|
59264
|
-
}), method(object({ deviceId: DeviceIdSchema }), _void(), {
|
|
59413
|
+
}), method(object({ deviceId: DeviceIdSchema$1 }), _void(), {
|
|
59265
59414
|
kind: "mutation",
|
|
59266
59415
|
auth: "protected"
|
|
59267
|
-
}), method(object({ deviceId: DeviceIdSchema }), _void(), {
|
|
59416
|
+
}), method(object({ deviceId: DeviceIdSchema$1 }), _void(), {
|
|
59268
59417
|
kind: "mutation",
|
|
59269
59418
|
auth: "protected"
|
|
59270
|
-
}), method(object({ deviceId: DeviceIdSchema }), _void(), {
|
|
59419
|
+
}), method(object({ deviceId: DeviceIdSchema$1 }), _void(), {
|
|
59271
59420
|
kind: "mutation",
|
|
59272
59421
|
auth: "protected"
|
|
59273
59422
|
}), method(object({
|
|
59274
|
-
deviceId: DeviceIdSchema,
|
|
59423
|
+
deviceId: DeviceIdSchema$1,
|
|
59275
59424
|
program: string().min(1)
|
|
59276
59425
|
}), _void(), {
|
|
59277
59426
|
kind: "mutation",
|
|
59278
59427
|
auth: "protected"
|
|
59279
59428
|
}), method(object({
|
|
59280
|
-
deviceId: DeviceIdSchema,
|
|
59429
|
+
deviceId: DeviceIdSchema$1,
|
|
59281
59430
|
on: boolean()
|
|
59282
59431
|
}), _void(), {
|
|
59283
59432
|
kind: "mutation",
|
|
59284
59433
|
auth: "protected"
|
|
59285
59434
|
}), method(object({
|
|
59286
|
-
deviceId: DeviceIdSchema,
|
|
59435
|
+
deviceId: DeviceIdSchema$1,
|
|
59287
59436
|
on: boolean()
|
|
59288
59437
|
}), _void(), {
|
|
59289
59438
|
kind: "mutation",
|
|
59290
59439
|
auth: "protected"
|
|
59291
59440
|
}), method(object({
|
|
59292
|
-
deviceId: DeviceIdSchema,
|
|
59441
|
+
deviceId: DeviceIdSchema$1,
|
|
59293
59442
|
on: boolean()
|
|
59294
59443
|
}), _void(), {
|
|
59295
59444
|
kind: "mutation",
|
|
59296
59445
|
auth: "protected"
|
|
59297
59446
|
}), method(object({
|
|
59298
|
-
deviceId: DeviceIdSchema,
|
|
59447
|
+
deviceId: DeviceIdSchema$1,
|
|
59299
59448
|
on: boolean()
|
|
59300
59449
|
}), _void(), {
|
|
59301
59450
|
kind: "mutation",
|
|
59302
59451
|
auth: "protected"
|
|
59303
59452
|
}), method(object({
|
|
59304
|
-
deviceId: DeviceIdSchema,
|
|
59453
|
+
deviceId: DeviceIdSchema$1,
|
|
59305
59454
|
on: boolean()
|
|
59306
59455
|
}), _void(), {
|
|
59307
59456
|
kind: "mutation",
|
|
59308
59457
|
auth: "protected"
|
|
59309
59458
|
}), method(object({
|
|
59310
|
-
deviceId: DeviceIdSchema,
|
|
59459
|
+
deviceId: DeviceIdSchema$1,
|
|
59311
59460
|
on: boolean()
|
|
59312
59461
|
}), _void(), {
|
|
59313
59462
|
kind: "mutation",
|
|
59314
59463
|
auth: "protected"
|
|
59315
59464
|
}), method(object({
|
|
59316
|
-
deviceId: DeviceIdSchema,
|
|
59465
|
+
deviceId: DeviceIdSchema$1,
|
|
59317
59466
|
on: boolean()
|
|
59318
59467
|
}), _void(), {
|
|
59319
59468
|
kind: "mutation",
|
|
59320
59469
|
auth: "protected"
|
|
59321
59470
|
}), method(object({
|
|
59322
|
-
deviceId: DeviceIdSchema,
|
|
59471
|
+
deviceId: DeviceIdSchema$1,
|
|
59323
59472
|
key: string().min(1),
|
|
59324
59473
|
value: DishwasherValueSchema
|
|
59325
59474
|
}), _void(), {
|
|
59326
59475
|
kind: "mutation",
|
|
59327
59476
|
auth: "protected"
|
|
59328
|
-
}), method(object({ deviceId: DeviceIdSchema }), DishwasherOptionsSchema, { auth: "protected" });
|
|
59477
|
+
}), method(object({ deviceId: DeviceIdSchema$1 }), DishwasherOptionsSchema, { auth: "protected" });
|
|
59329
59478
|
DeviceType.Camera;
|
|
59330
59479
|
object({
|
|
59331
59480
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
@@ -61763,7 +61912,8 @@ var TopologyNodeSchema = object({
|
|
|
61763
61912
|
isHub: boolean(),
|
|
61764
61913
|
isOnline: boolean(),
|
|
61765
61914
|
cpuPercent: number(),
|
|
61766
|
-
|
|
61915
|
+
/** `null` when the node's memory read failed or it has not reported one (D393). */
|
|
61916
|
+
memoryPercent: number().nullable(),
|
|
61767
61917
|
uptime: number(),
|
|
61768
61918
|
lastSeen: string(),
|
|
61769
61919
|
localIps: array(string()).readonly(),
|
|
@@ -62298,9 +62448,10 @@ object({
|
|
|
62298
62448
|
* combined reading; per-hopper levels live in `food1`/`food2`. Null when
|
|
62299
62449
|
* the device has not reported yet. */
|
|
62300
62450
|
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
62301
|
-
/** Food in the BOWL
|
|
62302
|
-
* feeder
|
|
62303
|
-
|
|
62451
|
+
/** Food in the BOWL, a mass (stored in kilograms, D944). Reported only by a
|
|
62452
|
+
* feeder with a bowl scale; null when the model has none or its reading is
|
|
62453
|
+
* of an unproven unit. */
|
|
62454
|
+
bowlFood: number().nullable().meta(readingMeta("mass")),
|
|
62304
62455
|
/** True while the pet is eating (`state.eating`). */
|
|
62305
62456
|
eating: boolean(),
|
|
62306
62457
|
/** Whether `markFoodReplenished` does anything on this model. When false
|
|
@@ -62413,6 +62564,64 @@ DeviceType.PetFeeder, method(object({
|
|
|
62413
62564
|
kind: "mutation",
|
|
62414
62565
|
auth: "protected"
|
|
62415
62566
|
});
|
|
62567
|
+
object({
|
|
62568
|
+
/** Water in the tank, 0..100 (%). Null while the source has not reported. */
|
|
62569
|
+
waterLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
62570
|
+
/** Water in the tank, in litres. Null while the source has not reported. */
|
|
62571
|
+
waterVolume: number().min(0).nullable().meta(readingMeta("volume")),
|
|
62572
|
+
/** True when the tank is empty. Null while unknown. */
|
|
62573
|
+
empty: boolean().nullable(),
|
|
62574
|
+
/** True while the pump is running. Null while unknown. */
|
|
62575
|
+
pumpRunning: boolean().nullable(),
|
|
62576
|
+
/** True when the pump works on an on/off duty cycle rather than continuously. */
|
|
62577
|
+
pumpIntervalEnabled: boolean().nullable(),
|
|
62578
|
+
/** How long the pump runs per cycle, in seconds. */
|
|
62579
|
+
pumpOnTime: number().min(0).nullable().meta(readingMeta("duration")),
|
|
62580
|
+
/** How long the pump rests per cycle, in seconds. */
|
|
62581
|
+
pumpOffTime: number().min(0).nullable().meta(readingMeta("duration")),
|
|
62582
|
+
/** Water drunk in the last drink, in litres. */
|
|
62583
|
+
lastDrink: number().min(0).nullable().meta(readingMeta("volume")),
|
|
62584
|
+
/** Water drunk in the current hour, in litres. */
|
|
62585
|
+
currentHourDrink: number().min(0).nullable().meta(readingMeta("volume")),
|
|
62586
|
+
/** Water drunk over the last 24 hours (rolling), in litres. */
|
|
62587
|
+
last24hDrink: number().min(0).nullable().meta(readingMeta("volume")),
|
|
62588
|
+
/** Water drunk since local midnight, in litres. */
|
|
62589
|
+
todayDrink: number().min(0).nullable().meta(readingMeta("volume")),
|
|
62590
|
+
/** Decoded fault message. Null means healthy; a non-null string is an active fault. */
|
|
62591
|
+
error: string().nullable(),
|
|
62592
|
+
/** Ms epoch when the slice was last refreshed. */
|
|
62593
|
+
lastFetchedAt: number()
|
|
62594
|
+
});
|
|
62595
|
+
var DeviceIdSchema = number().int().nonnegative();
|
|
62596
|
+
var MinutesSchema = number().int().min(0);
|
|
62597
|
+
DeviceType.PetFountain, method(object({
|
|
62598
|
+
deviceId: DeviceIdSchema,
|
|
62599
|
+
on: boolean()
|
|
62600
|
+
}), _void(), {
|
|
62601
|
+
kind: "mutation",
|
|
62602
|
+
auth: "protected"
|
|
62603
|
+
}), method(object({
|
|
62604
|
+
deviceId: DeviceIdSchema,
|
|
62605
|
+
on: boolean()
|
|
62606
|
+
}), _void(), {
|
|
62607
|
+
kind: "mutation",
|
|
62608
|
+
auth: "protected"
|
|
62609
|
+
}), method(object({
|
|
62610
|
+
deviceId: DeviceIdSchema,
|
|
62611
|
+
minutes: MinutesSchema
|
|
62612
|
+
}), _void(), {
|
|
62613
|
+
kind: "mutation",
|
|
62614
|
+
auth: "protected"
|
|
62615
|
+
}), method(object({
|
|
62616
|
+
deviceId: DeviceIdSchema,
|
|
62617
|
+
minutes: MinutesSchema
|
|
62618
|
+
}), _void(), {
|
|
62619
|
+
kind: "mutation",
|
|
62620
|
+
auth: "protected"
|
|
62621
|
+
}), method(object({ deviceId: DeviceIdSchema }), _void(), {
|
|
62622
|
+
kind: "mutation",
|
|
62623
|
+
auth: "protected"
|
|
62624
|
+
});
|
|
62416
62625
|
var VehicleSchema = object({
|
|
62417
62626
|
id: string(),
|
|
62418
62627
|
name: string(),
|
|
@@ -67112,7 +67321,7 @@ discriminatedUnion("kind", [object({
|
|
|
67112
67321
|
})]);
|
|
67113
67322
|
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
67114
67323
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
67115
|
-
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;
|
|
67324
|
+
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;
|
|
67116
67325
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
67117
67326
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
67118
67327
|
new Set(CAP_NAMES);
|
|
@@ -67165,7 +67374,7 @@ var AccessoryKind = {
|
|
|
67165
67374
|
PrivacyMask: DeviceRole.PrivacyMask
|
|
67166
67375
|
};
|
|
67167
67376
|
AccessoryKind.Siren, AccessoryKind.Floodlight, AccessoryKind.Spotlight, AccessoryKind.PirSensor, AccessoryKind.Chime, AccessoryKind.Autotrack, AccessoryKind.Nightvision, AccessoryKind.PrivacyMask;
|
|
67168
|
-
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;
|
|
67377
|
+
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;
|
|
67169
67378
|
new Set(Object.values(DeviceType));
|
|
67170
67379
|
Object.freeze({
|
|
67171
67380
|
"accessories.getStatus": {
|
|
@@ -69100,6 +69309,13 @@ Object.freeze({
|
|
|
69100
69309
|
access: "create",
|
|
69101
69310
|
role: "admin"
|
|
69102
69311
|
},
|
|
69312
|
+
"deviceExport.exposeEntity": {
|
|
69313
|
+
capName: "device-export",
|
|
69314
|
+
capScope: "system",
|
|
69315
|
+
addonId: null,
|
|
69316
|
+
access: "create",
|
|
69317
|
+
role: "admin"
|
|
69318
|
+
},
|
|
69103
69319
|
"deviceExport.getDeviceLiveContribution": {
|
|
69104
69320
|
capName: "device-export",
|
|
69105
69321
|
capScope: "system",
|
|
@@ -69128,6 +69344,13 @@ Object.freeze({
|
|
|
69128
69344
|
access: "view",
|
|
69129
69345
|
role: "admin"
|
|
69130
69346
|
},
|
|
69347
|
+
"deviceExport.listExposedEntities": {
|
|
69348
|
+
capName: "device-export",
|
|
69349
|
+
capScope: "system",
|
|
69350
|
+
addonId: null,
|
|
69351
|
+
access: "view",
|
|
69352
|
+
role: "admin"
|
|
69353
|
+
},
|
|
69131
69354
|
"deviceExport.listSupportedDeviceKinds": {
|
|
69132
69355
|
capName: "device-export",
|
|
69133
69356
|
capScope: "system",
|
|
@@ -69135,6 +69358,13 @@ Object.freeze({
|
|
|
69135
69358
|
access: "view",
|
|
69136
69359
|
role: "admin"
|
|
69137
69360
|
},
|
|
69361
|
+
"deviceExport.listSupportedEntityKinds": {
|
|
69362
|
+
capName: "device-export",
|
|
69363
|
+
capScope: "system",
|
|
69364
|
+
addonId: null,
|
|
69365
|
+
access: "view",
|
|
69366
|
+
role: "admin"
|
|
69367
|
+
},
|
|
69138
69368
|
"deviceExport.unexposeDevice": {
|
|
69139
69369
|
capName: "device-export",
|
|
69140
69370
|
capScope: "system",
|
|
@@ -69142,6 +69372,13 @@ Object.freeze({
|
|
|
69142
69372
|
access: "create",
|
|
69143
69373
|
role: "admin"
|
|
69144
69374
|
},
|
|
69375
|
+
"deviceExport.unexposeEntity": {
|
|
69376
|
+
capName: "device-export",
|
|
69377
|
+
capScope: "system",
|
|
69378
|
+
addonId: null,
|
|
69379
|
+
access: "create",
|
|
69380
|
+
role: "admin"
|
|
69381
|
+
},
|
|
69145
69382
|
"deviceExtension.listCandidates": {
|
|
69146
69383
|
capName: "device-extension",
|
|
69147
69384
|
capScope: "device",
|
|
@@ -72607,6 +72844,48 @@ Object.freeze({
|
|
|
72607
72844
|
access: "create",
|
|
72608
72845
|
role: "viewer"
|
|
72609
72846
|
},
|
|
72847
|
+
"petFountain.getStatus": {
|
|
72848
|
+
capName: "pet-fountain",
|
|
72849
|
+
capScope: "device",
|
|
72850
|
+
addonId: null,
|
|
72851
|
+
access: "view",
|
|
72852
|
+
role: "viewer"
|
|
72853
|
+
},
|
|
72854
|
+
"petFountain.resetDailyConsumption": {
|
|
72855
|
+
capName: "pet-fountain",
|
|
72856
|
+
capScope: "device",
|
|
72857
|
+
addonId: null,
|
|
72858
|
+
access: "delete",
|
|
72859
|
+
role: "viewer"
|
|
72860
|
+
},
|
|
72861
|
+
"petFountain.setPump": {
|
|
72862
|
+
capName: "pet-fountain",
|
|
72863
|
+
capScope: "device",
|
|
72864
|
+
addonId: null,
|
|
72865
|
+
access: "create",
|
|
72866
|
+
role: "viewer"
|
|
72867
|
+
},
|
|
72868
|
+
"petFountain.setPumpInterval": {
|
|
72869
|
+
capName: "pet-fountain",
|
|
72870
|
+
capScope: "device",
|
|
72871
|
+
addonId: null,
|
|
72872
|
+
access: "create",
|
|
72873
|
+
role: "viewer"
|
|
72874
|
+
},
|
|
72875
|
+
"petFountain.setPumpOffMinutes": {
|
|
72876
|
+
capName: "pet-fountain",
|
|
72877
|
+
capScope: "device",
|
|
72878
|
+
addonId: null,
|
|
72879
|
+
access: "create",
|
|
72880
|
+
role: "viewer"
|
|
72881
|
+
},
|
|
72882
|
+
"petFountain.setPumpOnMinutes": {
|
|
72883
|
+
capName: "pet-fountain",
|
|
72884
|
+
capScope: "device",
|
|
72885
|
+
addonId: null,
|
|
72886
|
+
access: "create",
|
|
72887
|
+
role: "viewer"
|
|
72888
|
+
},
|
|
72610
72889
|
"pipelineAnalytics.addRetrainFrameFromRecording": {
|
|
72611
72890
|
capName: "pipeline-analytics",
|
|
72612
72891
|
capScope: "device",
|
|
@@ -75008,6 +75287,13 @@ Object.freeze({
|
|
|
75008
75287
|
access: "create",
|
|
75009
75288
|
role: "admin"
|
|
75010
75289
|
},
|
|
75290
|
+
"serverManagement.getLaunchOverrides": {
|
|
75291
|
+
capName: "server-management",
|
|
75292
|
+
capScope: "system",
|
|
75293
|
+
addonId: null,
|
|
75294
|
+
access: "view",
|
|
75295
|
+
role: "admin"
|
|
75296
|
+
},
|
|
75011
75297
|
"serverManagement.getServerPackageStatus": {
|
|
75012
75298
|
capName: "server-management",
|
|
75013
75299
|
capScope: "system",
|
|
@@ -75029,6 +75315,13 @@ Object.freeze({
|
|
|
75029
75315
|
access: "create",
|
|
75030
75316
|
role: "admin"
|
|
75031
75317
|
},
|
|
75318
|
+
"serverManagement.setLaunchOverrides": {
|
|
75319
|
+
capName: "server-management",
|
|
75320
|
+
capScope: "system",
|
|
75321
|
+
addonId: null,
|
|
75322
|
+
access: "create",
|
|
75323
|
+
role: "admin"
|
|
75324
|
+
},
|
|
75032
75325
|
"settingsStore.aggregate": {
|
|
75033
75326
|
capName: "settings-store",
|
|
75034
75327
|
capScope: "system",
|
|
@@ -79089,6 +79382,100 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
79089
79382
|
}
|
|
79090
79383
|
]
|
|
79091
79384
|
},
|
|
79385
|
+
"pet-fountain": {
|
|
79386
|
+
scope: "device",
|
|
79387
|
+
noun: t("Pet fountain", "Fontana per animali"),
|
|
79388
|
+
actions: [
|
|
79389
|
+
{
|
|
79390
|
+
id: "petFountain.pumpOn",
|
|
79391
|
+
method: "setPump",
|
|
79392
|
+
label: t("Pump on", "Pompa accesa"),
|
|
79393
|
+
phrase: t("Start the pump of {device}", "Avvia la pompa di {device}"),
|
|
79394
|
+
icon: "play",
|
|
79395
|
+
args: { on: true }
|
|
79396
|
+
},
|
|
79397
|
+
{
|
|
79398
|
+
id: "petFountain.pumpOff",
|
|
79399
|
+
method: "setPump",
|
|
79400
|
+
label: t("Pump off", "Pompa spenta"),
|
|
79401
|
+
phrase: t("Stop the pump of {device}", "Ferma la pompa di {device}"),
|
|
79402
|
+
icon: "square",
|
|
79403
|
+
args: { on: false }
|
|
79404
|
+
},
|
|
79405
|
+
{
|
|
79406
|
+
id: "petFountain.intervalOn",
|
|
79407
|
+
method: "setPumpInterval",
|
|
79408
|
+
label: t("Pump cycle on", "Ciclo pompa attivo"),
|
|
79409
|
+
phrase: t("Run the pump of {device} on its on/off cycle", "Fai lavorare la pompa di {device} a ciclo acceso/spento"),
|
|
79410
|
+
icon: "timer",
|
|
79411
|
+
args: { on: true }
|
|
79412
|
+
},
|
|
79413
|
+
{
|
|
79414
|
+
id: "petFountain.intervalOff",
|
|
79415
|
+
method: "setPumpInterval",
|
|
79416
|
+
label: t("Pump cycle off", "Ciclo pompa spento"),
|
|
79417
|
+
phrase: t("Run the pump of {device} continuously", "Fai lavorare la pompa di {device} in continuo"),
|
|
79418
|
+
icon: "timer-off",
|
|
79419
|
+
args: { on: false }
|
|
79420
|
+
},
|
|
79421
|
+
{
|
|
79422
|
+
id: "petFountain.pumpOnMinutes",
|
|
79423
|
+
method: "setPumpOnMinutes",
|
|
79424
|
+
label: t("Set pump run time", "Imposta il tempo di lavoro della pompa"),
|
|
79425
|
+
phrase: t("Set the pump of {device} to run {minutes} minutes per cycle", "Imposta la pompa di {device} a lavorare {minutes} minuti per ciclo"),
|
|
79426
|
+
icon: "timer",
|
|
79427
|
+
openArgs: [{
|
|
79428
|
+
key: "minutes",
|
|
79429
|
+
label: t("Minutes", "Minuti"),
|
|
79430
|
+
offer: {
|
|
79431
|
+
kind: "number",
|
|
79432
|
+
min: 0,
|
|
79433
|
+
step: 1,
|
|
79434
|
+
unit: "min"
|
|
79435
|
+
}
|
|
79436
|
+
}]
|
|
79437
|
+
},
|
|
79438
|
+
{
|
|
79439
|
+
id: "petFountain.pumpOffMinutes",
|
|
79440
|
+
method: "setPumpOffMinutes",
|
|
79441
|
+
label: t("Set pump rest time", "Imposta il tempo di riposo della pompa"),
|
|
79442
|
+
phrase: t("Set the pump of {device} to rest {minutes} minutes per cycle", "Imposta la pompa di {device} a riposare {minutes} minuti per ciclo"),
|
|
79443
|
+
icon: "timer-off",
|
|
79444
|
+
openArgs: [{
|
|
79445
|
+
key: "minutes",
|
|
79446
|
+
label: t("Minutes", "Minuti"),
|
|
79447
|
+
offer: {
|
|
79448
|
+
kind: "number",
|
|
79449
|
+
min: 0,
|
|
79450
|
+
step: 1,
|
|
79451
|
+
unit: "min"
|
|
79452
|
+
}
|
|
79453
|
+
}]
|
|
79454
|
+
},
|
|
79455
|
+
{
|
|
79456
|
+
id: "petFountain.resetDailyConsumption",
|
|
79457
|
+
method: "resetDailyConsumption",
|
|
79458
|
+
label: t("Clear daily consumption", "Azzera il consumo giornaliero"),
|
|
79459
|
+
phrase: t("Clear the daily water consumption of {device}", "Azzera il consumo giornaliero di acqua di {device}"),
|
|
79460
|
+
icon: "rotate-ccw"
|
|
79461
|
+
}
|
|
79462
|
+
],
|
|
79463
|
+
state: [{
|
|
79464
|
+
kind: "boolean",
|
|
79465
|
+
field: "empty",
|
|
79466
|
+
label: t("Tank empty", "Serbatoio vuoto"),
|
|
79467
|
+
whenTrue: t("When the tank of {device} is empty", "Quando il serbatoio di {device} è vuoto"),
|
|
79468
|
+
whenFalse: t("When the tank of {device} is refilled", "Quando il serbatoio di {device} viene riempito"),
|
|
79469
|
+
icon: "droplet"
|
|
79470
|
+
}, {
|
|
79471
|
+
kind: "numeric",
|
|
79472
|
+
field: "waterLevel",
|
|
79473
|
+
quantity: t("the water level", "il livello dell’acqua"),
|
|
79474
|
+
label: t("Water level", "Livello dell’acqua"),
|
|
79475
|
+
unit: "%",
|
|
79476
|
+
icon: "droplets"
|
|
79477
|
+
}]
|
|
79478
|
+
},
|
|
79092
79479
|
"media-player": {
|
|
79093
79480
|
scope: "device",
|
|
79094
79481
|
noun: t("Media player", "Lettore multimediale"),
|
|
@@ -81026,7 +81413,7 @@ function projectAction(cap, action) {
|
|
|
81026
81413
|
};
|
|
81027
81414
|
}
|
|
81028
81415
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
81029
|
-
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;
|
|
81416
|
+
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;
|
|
81030
81417
|
DeviceFeature.BatteryOperated;
|
|
81031
81418
|
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
81032
81419
|
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.";
|
|
@@ -82577,6 +82964,36 @@ Object.freeze({
|
|
|
82577
82964
|
form: "single",
|
|
82578
82965
|
optional: false
|
|
82579
82966
|
}],
|
|
82967
|
+
"petFountain.getStatus": [{
|
|
82968
|
+
name: "deviceId",
|
|
82969
|
+
form: "single",
|
|
82970
|
+
optional: false
|
|
82971
|
+
}],
|
|
82972
|
+
"petFountain.resetDailyConsumption": [{
|
|
82973
|
+
name: "deviceId",
|
|
82974
|
+
form: "single",
|
|
82975
|
+
optional: false
|
|
82976
|
+
}],
|
|
82977
|
+
"petFountain.setPump": [{
|
|
82978
|
+
name: "deviceId",
|
|
82979
|
+
form: "single",
|
|
82980
|
+
optional: false
|
|
82981
|
+
}],
|
|
82982
|
+
"petFountain.setPumpInterval": [{
|
|
82983
|
+
name: "deviceId",
|
|
82984
|
+
form: "single",
|
|
82985
|
+
optional: false
|
|
82986
|
+
}],
|
|
82987
|
+
"petFountain.setPumpOffMinutes": [{
|
|
82988
|
+
name: "deviceId",
|
|
82989
|
+
form: "single",
|
|
82990
|
+
optional: false
|
|
82991
|
+
}],
|
|
82992
|
+
"petFountain.setPumpOnMinutes": [{
|
|
82993
|
+
name: "deviceId",
|
|
82994
|
+
form: "single",
|
|
82995
|
+
optional: false
|
|
82996
|
+
}],
|
|
82580
82997
|
"pipelineAnalytics.addRetrainFrameFromRecording": [{
|
|
82581
82998
|
name: "deviceId",
|
|
82582
82999
|
form: "single",
|