@camstack/addon-import-alexa 0.2.166 → 0.2.167
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/addon.js +1211 -675
- package/dist/addon.mjs +1211 -675
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -5248,6 +5248,14 @@ function object(shape, params) {
|
|
|
5248
5248
|
...normalizeParams(params)
|
|
5249
5249
|
});
|
|
5250
5250
|
}
|
|
5251
|
+
function strictObject(shape, params) {
|
|
5252
|
+
return new ZodObject({
|
|
5253
|
+
type: "object",
|
|
5254
|
+
shape,
|
|
5255
|
+
catchall: never(),
|
|
5256
|
+
...normalizeParams(params)
|
|
5257
|
+
});
|
|
5258
|
+
}
|
|
5251
5259
|
function looseObject(shape, params) {
|
|
5252
5260
|
return new ZodObject({
|
|
5253
5261
|
type: "object",
|
|
@@ -5627,7 +5635,7 @@ var ZodIssueCode = {
|
|
|
5627
5635
|
var ZodFirstPartyTypeKind;
|
|
5628
5636
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5629
5637
|
//#endregion
|
|
5630
|
-
//#region ../types/dist/sleep-
|
|
5638
|
+
//#region ../types/dist/sleep-6eG9C8Xl.mjs
|
|
5631
5639
|
/**
|
|
5632
5640
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5633
5641
|
* window to float samples (D455).
|
|
@@ -8862,9 +8870,76 @@ function optionalMethod(input, output, options) {
|
|
|
8862
8870
|
function event(data) {
|
|
8863
8871
|
return { data };
|
|
8864
8872
|
}
|
|
8873
|
+
/**
|
|
8874
|
+
* `addon-pages-source` — collection cap exposing per-provider raw page
|
|
8875
|
+
* declarations. Every addon that contributes a UI page registers a
|
|
8876
|
+
* provider here. The hub-side singleton aggregator (`addon-pages` cap,
|
|
8877
|
+
* see `addon-pages.cap.ts`) walks this collection, stamps versioned
|
|
8878
|
+
* `bundleUrl` values, and returns the enriched `AddonPageInfo[]` list
|
|
8879
|
+
* that admin-ui consumes.
|
|
8880
|
+
*
|
|
8881
|
+
* The split exists because the public listing has a different output
|
|
8882
|
+
* shape than the per-provider raw declarations, and we want both ends
|
|
8883
|
+
* to flow through codegen instead of relying on a hand-written wrapper.
|
|
8884
|
+
*/
|
|
8885
|
+
var AddonPageDeclarationSchema = object({
|
|
8886
|
+
id: string(),
|
|
8887
|
+
label: string(),
|
|
8888
|
+
icon: string(),
|
|
8889
|
+
path: string(),
|
|
8890
|
+
/**
|
|
8891
|
+
* Module Federation remote name — must match the `name` field on the
|
|
8892
|
+
* page addon's `federation()` plugin config. Used by admin-ui's
|
|
8893
|
+
* `<AddonPageLoader>` to call `loadRemote('<remoteName>/page')`.
|
|
8894
|
+
* Conventionally `addon_<id>_page` (snake_case; MF names cannot
|
|
8895
|
+
* contain hyphens).
|
|
8896
|
+
*/
|
|
8897
|
+
remoteName: string(),
|
|
8898
|
+
/**
|
|
8899
|
+
* Bundle filename inside the addon's `dist/` dir served at
|
|
8900
|
+
* `/api/addon-pages/<addonId>/<bundle>`. With Module Federation this
|
|
8901
|
+
* is always `'remoteEntry.js'`; the value is kept on the metadata so
|
|
8902
|
+
* the static-file route can compute an mtime-based cache-buster URL
|
|
8903
|
+
* without a separate filesystem stat.
|
|
8904
|
+
*/
|
|
8905
|
+
bundle: string(),
|
|
8906
|
+
/**
|
|
8907
|
+
* Sidebar section this page docks into. Well-known ids: `'detection'`,
|
|
8908
|
+
* `'cluster'`, `'administration'` — the page renders inside that group.
|
|
8909
|
+
* Any OTHER string creates (or joins) a custom section rendered after
|
|
8910
|
+
* the built-in groups; its label comes from `sectionLabel` (first
|
|
8911
|
+
* declaration wins), falling back to the id. Absent → the legacy
|
|
8912
|
+
* "Addon Pages" group.
|
|
8913
|
+
*/
|
|
8914
|
+
section: string().optional(),
|
|
8915
|
+
/** Display label for a CUSTOM `section` id (ignored for well-known ids). */
|
|
8916
|
+
sectionLabel: string().optional()
|
|
8917
|
+
});
|
|
8918
|
+
method(_void(), array(AddonPageDeclarationSchema).readonly(), { auth: "admin" });
|
|
8865
8919
|
var StaticDirOutputSchema$1 = object({ staticDir: string() });
|
|
8866
8920
|
var VersionOutputSchema$1 = object({ version: string() });
|
|
8867
8921
|
method(_void(), StaticDirOutputSchema$1, { auth: "admin" }), method(_void(), VersionOutputSchema$1, { auth: "admin" });
|
|
8922
|
+
/**
|
|
8923
|
+
* The pipeline step-input shape and the run-result bridge, in a module that
|
|
8924
|
+
* imports nothing but zod and types.
|
|
8925
|
+
*
|
|
8926
|
+
* WHY A SEPARATE FILE (addon footprint, D28): both were declared in
|
|
8927
|
+
* `pipeline-executor.cap.ts`, whose import evaluates the whole executor schema
|
|
8928
|
+
* graph. An addon that only needs these two (the benchmark's `runPipelineTest`
|
|
8929
|
+
* action) paid ~130 MB of heap at load. `pipeline-executor.cap.ts` re-exports
|
|
8930
|
+
* them, so every existing import keeps working; addon server code takes them
|
|
8931
|
+
* from `@camstack/types/addon`.
|
|
8932
|
+
*/
|
|
8933
|
+
var PipelineStepInputSchema = lazy(() => object({
|
|
8934
|
+
addonId: string(),
|
|
8935
|
+
modelId: string().optional(),
|
|
8936
|
+
enabled: boolean().default(true),
|
|
8937
|
+
children: array(PipelineStepInputSchema).optional(),
|
|
8938
|
+
settings: record(string(), unknown()).optional(),
|
|
8939
|
+
jumpDeviceKey: string().optional()
|
|
8940
|
+
}));
|
|
8941
|
+
/** Typed bridge to the recursive `FrameResult` graph; validation is structural. */
|
|
8942
|
+
var PipelineRunResultBridge = custom();
|
|
8868
8943
|
var StaticDirOutputSchema = object({ staticDir: string() });
|
|
8869
8944
|
var VersionOutputSchema = object({ version: string() });
|
|
8870
8945
|
method(_void(), StaticDirOutputSchema, { auth: "admin" }), method(_void(), VersionOutputSchema, { auth: "admin" });
|
|
@@ -9060,6 +9135,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
9060
9135
|
"osd",
|
|
9061
9136
|
"osd-manager",
|
|
9062
9137
|
"pet-feeder",
|
|
9138
|
+
"pet-fountain",
|
|
9063
9139
|
"pipeline-analytics",
|
|
9064
9140
|
"pipeline-executor",
|
|
9065
9141
|
"pipeline-orchestrator",
|
|
@@ -10339,6 +10415,56 @@ Object.freeze({
|
|
|
10339
10415
|
"valueType": "number"
|
|
10340
10416
|
}
|
|
10341
10417
|
],
|
|
10418
|
+
"pet-fountain": [
|
|
10419
|
+
{
|
|
10420
|
+
"path": "waterLevel",
|
|
10421
|
+
"valueType": "number"
|
|
10422
|
+
},
|
|
10423
|
+
{
|
|
10424
|
+
"path": "waterVolume",
|
|
10425
|
+
"valueType": "number"
|
|
10426
|
+
},
|
|
10427
|
+
{
|
|
10428
|
+
"path": "empty",
|
|
10429
|
+
"valueType": "boolean"
|
|
10430
|
+
},
|
|
10431
|
+
{
|
|
10432
|
+
"path": "pumpRunning",
|
|
10433
|
+
"valueType": "boolean"
|
|
10434
|
+
},
|
|
10435
|
+
{
|
|
10436
|
+
"path": "pumpIntervalEnabled",
|
|
10437
|
+
"valueType": "boolean"
|
|
10438
|
+
},
|
|
10439
|
+
{
|
|
10440
|
+
"path": "pumpOnTime",
|
|
10441
|
+
"valueType": "number"
|
|
10442
|
+
},
|
|
10443
|
+
{
|
|
10444
|
+
"path": "pumpOffTime",
|
|
10445
|
+
"valueType": "number"
|
|
10446
|
+
},
|
|
10447
|
+
{
|
|
10448
|
+
"path": "lastDrink",
|
|
10449
|
+
"valueType": "number"
|
|
10450
|
+
},
|
|
10451
|
+
{
|
|
10452
|
+
"path": "currentHourDrink",
|
|
10453
|
+
"valueType": "number"
|
|
10454
|
+
},
|
|
10455
|
+
{
|
|
10456
|
+
"path": "last24hDrink",
|
|
10457
|
+
"valueType": "number"
|
|
10458
|
+
},
|
|
10459
|
+
{
|
|
10460
|
+
"path": "todayDrink",
|
|
10461
|
+
"valueType": "number"
|
|
10462
|
+
},
|
|
10463
|
+
{
|
|
10464
|
+
"path": "error",
|
|
10465
|
+
"valueType": "string"
|
|
10466
|
+
}
|
|
10467
|
+
],
|
|
10342
10468
|
"power-meter": [
|
|
10343
10469
|
{
|
|
10344
10470
|
"path": "power",
|
|
@@ -10876,7 +11002,7 @@ object({
|
|
|
10876
11002
|
params: record(string(), union([string(), number()])).optional()
|
|
10877
11003
|
});
|
|
10878
11004
|
//#endregion
|
|
10879
|
-
//#region ../types/dist/err-msg-
|
|
11005
|
+
//#region ../types/dist/err-msg-DWXWc0Di.mjs
|
|
10880
11006
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
10881
11007
|
DeviceType["Camera"] = "camera";
|
|
10882
11008
|
DeviceType["Hub"] = "hub";
|
|
@@ -10968,6 +11094,10 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
10968
11094
|
* native PetKit (`nodepetkit` `FeederDevice`), reusable by other feeder
|
|
10969
11095
|
* integrations sharing the same food/desiccant/hopper surface. */
|
|
10970
11096
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
11097
|
+
/** Pet water fountain — tank level, water drunk, pump and its duty cycle.
|
|
11098
|
+
* Installed with the `pet-fountain` cap. Reaches CamStack as loose entities
|
|
11099
|
+
* of a container and is BUILT as a composed device (D967). */
|
|
11100
|
+
DeviceType["PetFountain"] = "pet-fountain";
|
|
10971
11101
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
10972
11102
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
10973
11103
|
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
@@ -11238,7 +11368,7 @@ function errMsg(err) {
|
|
|
11238
11368
|
return String(err);
|
|
11239
11369
|
}
|
|
11240
11370
|
//#endregion
|
|
11241
|
-
//#region ../types/dist/composition-
|
|
11371
|
+
//#region ../types/dist/composition-kSuOifuG.mjs
|
|
11242
11372
|
/**
|
|
11243
11373
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11244
11374
|
*
|
|
@@ -11286,11 +11416,11 @@ function errMsg(err) {
|
|
|
11286
11416
|
*/
|
|
11287
11417
|
/** The pinned jellyfin-ffmpeg release. Changing this is the version change. */
|
|
11288
11418
|
var FFMPEG_RELEASE = "8.1.2-5";
|
|
11289
|
-
var BASE = `https://github.com/jellyfin/jellyfin-ffmpeg/releases/download/v${FFMPEG_RELEASE}`;
|
|
11419
|
+
var BASE$1 = `https://github.com/jellyfin/jellyfin-ffmpeg/releases/download/v${FFMPEG_RELEASE}`;
|
|
11290
11420
|
function portable(target) {
|
|
11291
|
-
return `${BASE}/jellyfin-ffmpeg_${FFMPEG_RELEASE}_portable_${target}-gpl.tar.xz`;
|
|
11421
|
+
return `${BASE$1}/jellyfin-ffmpeg_${FFMPEG_RELEASE}_portable_${target}-gpl.tar.xz`;
|
|
11292
11422
|
}
|
|
11293
|
-
portable("linux64"), portable("linuxarm64"), portable("macarm64"), portable("mac64"), `${BASE}${FFMPEG_RELEASE}`;
|
|
11423
|
+
portable("linux64"), portable("linuxarm64"), portable("macarm64"), portable("mac64"), `${BASE$1}${FFMPEG_RELEASE}`;
|
|
11294
11424
|
/**
|
|
11295
11425
|
* THE table "which boolean of this device type counts as HIGH", and the
|
|
11296
11426
|
* pure evaluator of its EDGE.
|
|
@@ -12323,12 +12453,28 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
|
12323
12453
|
])
|
|
12324
12454
|
})
|
|
12325
12455
|
]);
|
|
12326
|
-
var
|
|
12456
|
+
var forwardArgUnion = union([
|
|
12457
|
+
string(),
|
|
12458
|
+
number(),
|
|
12459
|
+
boolean(),
|
|
12460
|
+
strictObject({ ["$input"]: string().min(1) }),
|
|
12461
|
+
record(string().min(1), lazy(() => forwardArgUnion))
|
|
12462
|
+
]);
|
|
12463
|
+
var CompositionForwardArgSchema = forwardArgUnion;
|
|
12464
|
+
/**
|
|
12465
|
+
* `forward` (D659, amended by D967): one method of a BUILT capability is one
|
|
12466
|
+
* call of `cap.method` on `source`. Without `args` the built method's input
|
|
12467
|
+
* passes through minus `deviceId`; with `args` the template IS the source's
|
|
12468
|
+
* whole input. `deviceId` is always the source's own, never an argument.
|
|
12469
|
+
*/
|
|
12470
|
+
var CompositionForwardCommandSchema = object({
|
|
12327
12471
|
kind: literal("forward"),
|
|
12328
12472
|
source: CompositionSourceRefSchema,
|
|
12329
12473
|
cap: string().min(1),
|
|
12330
|
-
method: string().min(1)
|
|
12331
|
-
|
|
12474
|
+
method: string().min(1),
|
|
12475
|
+
args: record(string().min(1), CompositionForwardArgSchema).optional()
|
|
12476
|
+
});
|
|
12477
|
+
var CompositionCommandTargetSchema = discriminatedUnion("kind", [CompositionForwardCommandSchema, CompositionCodeSourceSchema]);
|
|
12332
12478
|
/** An item key inside an item-array cap (`consumables.items[<key>]`). */
|
|
12333
12479
|
var COMPOSITION_ITEM_KEY_RE = /^[a-z0-9][a-z0-9-]{0,47}$/;
|
|
12334
12480
|
/**
|
|
@@ -12338,7 +12484,13 @@ var COMPOSITION_ITEM_KEY_RE = /^[a-z0-9][a-z0-9-]{0,47}$/;
|
|
|
12338
12484
|
*/
|
|
12339
12485
|
var CompositionItemEntrySchema = object({
|
|
12340
12486
|
label: string().min(1).max(80),
|
|
12341
|
-
fields: record(string().min(1), CompositionFieldSourceSchema)
|
|
12487
|
+
fields: record(string().min(1), CompositionFieldSourceSchema),
|
|
12488
|
+
/**
|
|
12489
|
+
* What the cap's `reset` does for THIS item (consumables). Present = the item
|
|
12490
|
+
* is resettable and a `reset` call naming its key forwards here. The item key
|
|
12491
|
+
* selects the command, so it is never an argument: there is no pass-through.
|
|
12492
|
+
*/
|
|
12493
|
+
reset: CompositionForwardCommandSchema.optional()
|
|
12342
12494
|
});
|
|
12343
12495
|
var CompositionFeatureSchema = discriminatedUnion("kind", [object({
|
|
12344
12496
|
kind: literal("fields"),
|
|
@@ -12350,7 +12502,7 @@ var CompositionFeatureSchema = discriminatedUnion("kind", [object({
|
|
|
12350
12502
|
* owns the WHOLE array field: the composed value holds exactly these items.
|
|
12351
12503
|
*/
|
|
12352
12504
|
items: record(string().regex(COMPOSITION_ITEM_KEY_RE), CompositionItemEntrySchema).refine((items) => Object.keys(items).length <= 16, { message: `at most 16 items` }).optional(),
|
|
12353
|
-
/**
|
|
12505
|
+
/** Method name → what serves it. Only a BUILT capability takes commands (D967). */
|
|
12354
12506
|
commands: record(string().min(1), CompositionCommandTargetSchema).optional()
|
|
12355
12507
|
}), object({
|
|
12356
12508
|
kind: literal("passthrough"),
|
|
@@ -16407,6 +16559,449 @@ object({
|
|
|
16407
16559
|
lastError: string().nullable()
|
|
16408
16560
|
});
|
|
16409
16561
|
/**
|
|
16562
|
+
* notification-output — canonical, capability-gated notification delivery.
|
|
16563
|
+
*
|
|
16564
|
+
* Apprise-derived model (see
|
|
16565
|
+
* `docs/superpowers/specs/2026-07-03-notification-output-notifier-matrix.md`):
|
|
16566
|
+
* callers emit ONE canonical `Notification`; each provider declares a
|
|
16567
|
+
* per-kind capability descriptor (`TargetKind`), and the pure degrade
|
|
16568
|
+
* engine (`@camstack/types` `prepareNotification`) transcodes / degrades the
|
|
16569
|
+
* message to what the kind supports — callers never special-case a service.
|
|
16570
|
+
*
|
|
16571
|
+
* DESIGN DECISIONS (locked):
|
|
16572
|
+
* - Target CRUD lives on THIS cap (`upsertTarget` / `deleteTarget` /
|
|
16573
|
+
* `setTargetEnabled`), each provider persisting via the `settings-store`
|
|
16574
|
+
* cap. Rationale: the admin UI needs one uniform surface across the
|
|
16575
|
+
* notifiers addon AND the HA addon; the addon-`globalSettingsSchema`-array
|
|
16576
|
+
* alternative would fork the UI per addon and cannot host the
|
|
16577
|
+
* discovery→adopt flow.
|
|
16578
|
+
* - `listTargetKinds` / `listTargets` / `discoverTargets` return arrays →
|
|
16579
|
+
* the generated cap-mount auto-`concatCollection`-fans them across every
|
|
16580
|
+
* registered provider (notifiers addon + HA addon) so one catalog is
|
|
16581
|
+
* routable. `send` / `testTarget` / CRUD route to ONE provider by the
|
|
16582
|
+
* `addonId` the generated collection router extracts from the call input.
|
|
16583
|
+
* - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
|
|
16584
|
+
* transformer) + UDS MsgPack both round-trip typed arrays — already used by
|
|
16585
|
+
* `storage` / `storage-provider` / `recording` caps over the same path. No
|
|
16586
|
+
* base64 fallback needed.
|
|
16587
|
+
*
|
|
16588
|
+
* TODO (deferred, closed-set change — separate decision): add
|
|
16589
|
+
* `providerKind: 'notify'` so notification providers surface on the unified
|
|
16590
|
+
* admin "Integrations" page.
|
|
16591
|
+
*/
|
|
16592
|
+
/**
|
|
16593
|
+
* Zentik-derived typed-media enum — the superset across every kind. Each
|
|
16594
|
+
* adapter picks what it supports and the degrade engine filters the rest.
|
|
16595
|
+
*/
|
|
16596
|
+
var AttachmentMediaTypeSchema = _enum([
|
|
16597
|
+
"image",
|
|
16598
|
+
"video",
|
|
16599
|
+
"gif",
|
|
16600
|
+
"audio",
|
|
16601
|
+
"icon"
|
|
16602
|
+
]);
|
|
16603
|
+
/**
|
|
16604
|
+
* A single attachment. Exactly one of `url` (remote source, most adapters
|
|
16605
|
+
* prefer this) or `bytes` (inline source; required for Pushover-style
|
|
16606
|
+
* bytes-only kinds) MUST be present — the degrade engine expresses a
|
|
16607
|
+
* url→bytes fetch as a `needsFetch` directive the adapter executes.
|
|
16608
|
+
*/
|
|
16609
|
+
var AttachmentSchema = object({
|
|
16610
|
+
mediaType: AttachmentMediaTypeSchema,
|
|
16611
|
+
url: string().optional(),
|
|
16612
|
+
bytes: _instanceof(Uint8Array).optional(),
|
|
16613
|
+
mime: string().optional(),
|
|
16614
|
+
name: string().optional()
|
|
16615
|
+
}).refine((a) => a.url !== void 0 || a.bytes !== void 0, { message: "Attachment requires either `url` or `bytes`" });
|
|
16616
|
+
var NotificationFormatSchema = _enum([
|
|
16617
|
+
"text",
|
|
16618
|
+
"markdown",
|
|
16619
|
+
"html"
|
|
16620
|
+
]);
|
|
16621
|
+
/**
|
|
16622
|
+
* The CLOSED icon vocabulary an action button may use.
|
|
16623
|
+
*
|
|
16624
|
+
* A closed set, not a free string, and that is the whole point: an arbitrary
|
|
16625
|
+
* icon name is one that ntfy renders, zentik silently drops, and nobody
|
|
16626
|
+
* notices — the same class of gap as a zone vocabulary nothing produced
|
|
16627
|
+
* ([D35](../../../docs/decisions/adr-0035.md)). Every adapter maps this set or
|
|
16628
|
+
* declares `actionIcons: false` and the degrade engine strips the field.
|
|
16629
|
+
*
|
|
16630
|
+
* Named by INTENT, never by glyph. "check" would tie the vocabulary to one
|
|
16631
|
+
* renderer's icon set; "acknowledge" survives an adapter that draws it
|
|
16632
|
+
* differently.
|
|
16633
|
+
*
|
|
16634
|
+
* ── A TOKEN IS NOT A WIRE VALUE ─────────────────────────────────────
|
|
16635
|
+
*
|
|
16636
|
+
* These names are for US. **No adapter may forward one verbatim.** Each maps
|
|
16637
|
+
* the whole set onto its own renderer's vocabulary through a
|
|
16638
|
+
* `Record<NotificationActionIcon, string>` — a Record, never a lookup with a
|
|
16639
|
+
* fallback, so adding a member here fails every adapter's build until someone
|
|
16640
|
+
* decides its glyph, which is the only place that decision can be made
|
|
16641
|
+
* honestly.
|
|
16642
|
+
*
|
|
16643
|
+
* This paragraph is the bug. Zentik declared `actionIcons: true` and passed
|
|
16644
|
+
* `disarm` straight through; iOS feeds that string to
|
|
16645
|
+
* `UNNotificationActionIcon(systemImageName:)`, `disarm` is not an SF Symbol,
|
|
16646
|
+
* and every snooze and alarm button arrived BLANK. A pass-through is not a
|
|
16647
|
+
* mapping, and "the field is documented" is not "the value renders".
|
|
16648
|
+
*
|
|
16649
|
+
* Adding a member is TRAIN-BOUND. The enum lives in the published
|
|
16650
|
+
* `@camstack/server` closure and the cap seam validates against the HUB's copy,
|
|
16651
|
+
* so an addon that emits a token the running hub does not know does not lose an
|
|
16652
|
+
* icon — its whole `send` fails Zod validation and the notification never
|
|
16653
|
+
* arrives. Never emit a new token from an addon before the train carrying it.
|
|
16654
|
+
*/
|
|
16655
|
+
var NotificationActionIconSchema = _enum([
|
|
16656
|
+
"acknowledge",
|
|
16657
|
+
"dismiss",
|
|
16658
|
+
"silence",
|
|
16659
|
+
"snooze",
|
|
16660
|
+
"view",
|
|
16661
|
+
"play",
|
|
16662
|
+
"open",
|
|
16663
|
+
"close",
|
|
16664
|
+
"lock",
|
|
16665
|
+
"unlock",
|
|
16666
|
+
"arm",
|
|
16667
|
+
"arm-home",
|
|
16668
|
+
"arm-away",
|
|
16669
|
+
"arm-night",
|
|
16670
|
+
"disarm",
|
|
16671
|
+
"light",
|
|
16672
|
+
"alert",
|
|
16673
|
+
"camera"
|
|
16674
|
+
]);
|
|
16675
|
+
/** A single tap-through action button. */
|
|
16676
|
+
var NotificationActionSchema = object({
|
|
16677
|
+
id: string(),
|
|
16678
|
+
label: string(),
|
|
16679
|
+
url: string().optional(),
|
|
16680
|
+
/** Dropped by the degrade engine for a kind with `caps.actionIcons: false`. */
|
|
16681
|
+
icon: NotificationActionIconSchema.optional(),
|
|
16682
|
+
/**
|
|
16683
|
+
* Renders in a warning style where the notifier supports it.
|
|
16684
|
+
*
|
|
16685
|
+
* A HINT, never a gate. The callback's authority is its token and nothing
|
|
16686
|
+
* else — see `notification-center/action-token.ts` for what that does and
|
|
16687
|
+
* does not buy.
|
|
16688
|
+
*/
|
|
16689
|
+
destructive: boolean().optional(),
|
|
16690
|
+
/**
|
|
16691
|
+
* How the tap should REACH the url.
|
|
16692
|
+
*
|
|
16693
|
+
* `navigate` (absent, and every button authored before this field) opens it:
|
|
16694
|
+
* the phone leaves the notification and shows whatever the callback returns.
|
|
16695
|
+
* That is right for a button whose answer the operator wants to read.
|
|
16696
|
+
*
|
|
16697
|
+
* `background` fires it as a POST and stays put. It exists for the buttons
|
|
16698
|
+
* whose whole point is not to interrupt — "silence this for 30 minutes" is
|
|
16699
|
+
* an answer to the notification, and being thrown into a browser tab to
|
|
16700
|
+
* confirm it costs more attention than the notification did. A backend that
|
|
16701
|
+
* cannot do a background call renders it as an ordinary link (the adapters
|
|
16702
|
+
* fall back rather than dropping the button), so this is a preference, never
|
|
16703
|
+
* a requirement.
|
|
16704
|
+
*/
|
|
16705
|
+
mode: _enum(["navigate", "background"]).optional()
|
|
16706
|
+
});
|
|
16707
|
+
/** A delivery parameter value: what a notifier declared it takes. */
|
|
16708
|
+
var DeliveryParamValueSchema = union([
|
|
16709
|
+
string(),
|
|
16710
|
+
number(),
|
|
16711
|
+
boolean()
|
|
16712
|
+
]);
|
|
16713
|
+
/**
|
|
16714
|
+
* One extra delivery parameter a notifier KIND declares (D938). A rule that
|
|
16715
|
+
* addresses a target of that kind may set it; a kind that declares nothing is
|
|
16716
|
+
* never handed one. The admin UI derives its control from this descriptor —
|
|
16717
|
+
* no editor knows a service by name.
|
|
16718
|
+
*
|
|
16719
|
+
* Optional fields are `.optional()`, never `.default()` (a Zod default does not
|
|
16720
|
+
* run on the addon cap path).
|
|
16721
|
+
*/
|
|
16722
|
+
var DeliveryParamSchema = object({
|
|
16723
|
+
key: string().min(1),
|
|
16724
|
+
label: string(),
|
|
16725
|
+
/** i18n key of the label, resolved by the declaring addon's namespace. */
|
|
16726
|
+
labelKey: string().optional(),
|
|
16727
|
+
type: _enum([
|
|
16728
|
+
"enum",
|
|
16729
|
+
"number",
|
|
16730
|
+
"boolean",
|
|
16731
|
+
"string"
|
|
16732
|
+
]),
|
|
16733
|
+
/** `enum` only: the closed set of accepted values. */
|
|
16734
|
+
options: array(object({
|
|
16735
|
+
value: string(),
|
|
16736
|
+
label: string()
|
|
16737
|
+
})).optional(),
|
|
16738
|
+
/** `number` only. */
|
|
16739
|
+
min: number().optional(),
|
|
16740
|
+
max: number().optional(),
|
|
16741
|
+
/** What the notifier does when the rule sets nothing; shown as the placeholder. */
|
|
16742
|
+
default: DeliveryParamValueSchema.optional()
|
|
16743
|
+
});
|
|
16744
|
+
/**
|
|
16745
|
+
* The canonical notification. `body` is the only hard field (Apprise model).
|
|
16746
|
+
* `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
|
|
16747
|
+
* NOT a fixed severity enum — each kind declares its own `caps.levels` and
|
|
16748
|
+
* the adapter maps this ordinal onto its native level. `level?` is an
|
|
16749
|
+
* optional kind-native level id (`emergency`, `silent`, …) that overrides
|
|
16750
|
+
* `priority` for that one target.
|
|
16751
|
+
*/
|
|
16752
|
+
var NotificationSchema = object({
|
|
16753
|
+
body: string(),
|
|
16754
|
+
title: string().optional(),
|
|
16755
|
+
format: NotificationFormatSchema.default("text"),
|
|
16756
|
+
priority: number().int().min(1).max(5).default(3),
|
|
16757
|
+
level: string().optional(),
|
|
16758
|
+
attachments: array(AttachmentSchema).optional(),
|
|
16759
|
+
clickUrl: string().optional(),
|
|
16760
|
+
actions: array(NotificationActionSchema).optional(),
|
|
16761
|
+
sound: string().optional(),
|
|
16762
|
+
ttl: number().optional(),
|
|
16763
|
+
tag: string().optional(),
|
|
16764
|
+
deviceId: number().optional(),
|
|
16765
|
+
eventId: string().optional(),
|
|
16766
|
+
metadata: record(string(), unknown()).optional(),
|
|
16767
|
+
/**
|
|
16768
|
+
* Values for the parameters the target's kind DECLARES in
|
|
16769
|
+
* {@link TargetKindSchema} `deliveryParams`. Already validated against the
|
|
16770
|
+
* declaration by the sender; a notifier reads only the keys it declared.
|
|
16771
|
+
*/
|
|
16772
|
+
delivery: record(string(), DeliveryParamValueSchema).optional()
|
|
16773
|
+
});
|
|
16774
|
+
/** One declared native severity/priority level for a kind. */
|
|
16775
|
+
var TargetKindLevelSchema = object({
|
|
16776
|
+
id: string(),
|
|
16777
|
+
label: string(),
|
|
16778
|
+
/** Which canonical priority (1..5) this level maps to. `null` = qualitative-only. */
|
|
16779
|
+
ordinal: number().int().min(1).max(5).nullable(),
|
|
16780
|
+
flags: object({
|
|
16781
|
+
critical: boolean().optional(),
|
|
16782
|
+
silent: boolean().optional(),
|
|
16783
|
+
noPush: boolean().optional()
|
|
16784
|
+
}).optional(),
|
|
16785
|
+
/** e.g. Pushover `emergency` requires `retry` / `expire`. */
|
|
16786
|
+
requires: array(string()).optional(),
|
|
16787
|
+
description: string().optional()
|
|
16788
|
+
});
|
|
16789
|
+
/** The full capability block consulted before dispatch. */
|
|
16790
|
+
var TargetKindCapsSchema = object({
|
|
16791
|
+
attachments: object({
|
|
16792
|
+
mediaTypes: array(AttachmentMediaTypeSchema),
|
|
16793
|
+
mode: _enum([
|
|
16794
|
+
"url",
|
|
16795
|
+
"bytes",
|
|
16796
|
+
"both"
|
|
16797
|
+
]),
|
|
16798
|
+
max: number().int().nonnegative(),
|
|
16799
|
+
maxBytes: number().int().positive().optional()
|
|
16800
|
+
}),
|
|
16801
|
+
/** Max action buttons (0 = none). */
|
|
16802
|
+
actions: number().int().nonnegative(),
|
|
16803
|
+
/**
|
|
16804
|
+
* Whether this kind renders a per-action ICON.
|
|
16805
|
+
*
|
|
16806
|
+
* `.optional()`, deliberately NOT `.default(false)`: a Zod default does not
|
|
16807
|
+
* run on the addon cap path — three production failures in one day taught
|
|
16808
|
+
* this repo that once. Absent is read as false by the degrade engine, which
|
|
16809
|
+
* is the safe direction: an icon that is not rendered costs nothing, an icon
|
|
16810
|
+
* assumed and dropped costs the operator's trust in the field.
|
|
16811
|
+
*/
|
|
16812
|
+
actionIcons: boolean().optional(),
|
|
16813
|
+
levels: array(TargetKindLevelSchema),
|
|
16814
|
+
format: array(NotificationFormatSchema),
|
|
16815
|
+
clickUrl: boolean(),
|
|
16816
|
+
sound: boolean(),
|
|
16817
|
+
ttl: boolean(),
|
|
16818
|
+
bodyMaxLen: number().int().positive()
|
|
16819
|
+
});
|
|
16820
|
+
/**
|
|
16821
|
+
* `configSchema` is a `ConfigUISchema` tree passed through to the admin
|
|
16822
|
+
* FormBuilder. Stored as `z.unknown()` at the cap seam (mirrors
|
|
16823
|
+
* `device-provider.getChildCreationSchema` `CreationSchemaOutputSchema`) —
|
|
16824
|
+
* the union is large and not meant for runtime validation here; the exported
|
|
16825
|
+
* `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
|
|
16826
|
+
*/
|
|
16827
|
+
var ConfigSchemaPassthrough$3 = unknown();
|
|
16828
|
+
var TargetKindSchema = object({
|
|
16829
|
+
kind: string(),
|
|
16830
|
+
label: string(),
|
|
16831
|
+
icon: string(),
|
|
16832
|
+
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
16833
|
+
addonId: string(),
|
|
16834
|
+
/**
|
|
16835
|
+
* URL of the kind's bundled BRAND icon, served by the providing addon over
|
|
16836
|
+
* its own `addon-routes` surface (`/addon/<addonId>/icons/<kind>`). Absent
|
|
16837
|
+
* when the addon bundles no icon for that kind — the client then falls back
|
|
16838
|
+
* to a neutral glyph rather than rendering the raw `icon` NAME as text.
|
|
16839
|
+
*
|
|
16840
|
+
* Root-relative on purpose: it resolves against whatever origin serves a web
|
|
16841
|
+
* client, and a native client joins it onto its own hub base.
|
|
16842
|
+
*
|
|
16843
|
+
* DECLARED here deliberately. It used to travel as an undeclared passthrough
|
|
16844
|
+
* field that survived only because the runtime cap-router forwards provider
|
|
16845
|
+
* output verbatim — so every consumer had to re-declare it by hand to stop
|
|
16846
|
+
* its own Zod parse from stripping it, and the whole arrangement would have
|
|
16847
|
+
* broken silently the moment output validation was tightened anywhere.
|
|
16848
|
+
*/
|
|
16849
|
+
iconUrl: string().optional(),
|
|
16850
|
+
/**
|
|
16851
|
+
* Media type of {@link iconUrl} (`image/svg+xml`, `image/png`, …).
|
|
16852
|
+
*
|
|
16853
|
+
* The server knows this and therefore says it, because the client cannot
|
|
16854
|
+
* safely guess: a React-Native client renders SVG and raster through two
|
|
16855
|
+
* DIFFERENT components (`react-native-svg` vs `expo-image` — expo-image does
|
|
16856
|
+
* not decode SVG on iOS/Android), so without this it silently fell back to a
|
|
16857
|
+
* placeholder glyph for every vector icon while the web build looked fine.
|
|
16858
|
+
*
|
|
16859
|
+
* Absent when {@link iconUrl} is absent, or for a legacy provider that has
|
|
16860
|
+
* not been updated — a client that cannot determine the type should prefer
|
|
16861
|
+
* its raster path, which is the safe default for an unknown image.
|
|
16862
|
+
*/
|
|
16863
|
+
iconMediaType: string().optional(),
|
|
16864
|
+
configSchema: ConfigSchemaPassthrough$3,
|
|
16865
|
+
/**
|
|
16866
|
+
* The config keys that decide WHERE this kind's secrets are sent (server,
|
|
16867
|
+
* base URL, instance, chat, recipient). A save that changes any of them
|
|
16868
|
+
* while leaving a secret redacted is refused by the provider (D634), so an
|
|
16869
|
+
* editor uses this to ask for the secret on exactly those edits instead of
|
|
16870
|
+
* on every edit.
|
|
16871
|
+
*
|
|
16872
|
+
* Optional: absent from a provider that holds no secret (the Home Assistant
|
|
16873
|
+
* kinds) and from a provider older than this field — an editor that finds
|
|
16874
|
+
* it absent must assume ANY edit may need the secret.
|
|
16875
|
+
*/
|
|
16876
|
+
destinationKeys: array(string()).optional(),
|
|
16877
|
+
supportsDiscovery: boolean(),
|
|
16878
|
+
/**
|
|
16879
|
+
* Extra delivery parameters a rule may set for a target of this kind (D938).
|
|
16880
|
+
* Absent = none; the rule editor then offers nothing.
|
|
16881
|
+
*/
|
|
16882
|
+
deliveryParams: array(DeliveryParamSchema).optional(),
|
|
16883
|
+
caps: TargetKindCapsSchema
|
|
16884
|
+
});
|
|
16885
|
+
/**
|
|
16886
|
+
* A persisted target. `config` holds secrets; providers REDACT secret fields
|
|
16887
|
+
* (return a presence marker only) when serving `listTargets` — never
|
|
16888
|
+
* round-trip a stored secret to the UI.
|
|
16889
|
+
*/
|
|
16890
|
+
var TargetSchema = object({
|
|
16891
|
+
id: string(),
|
|
16892
|
+
name: string(),
|
|
16893
|
+
kind: string(),
|
|
16894
|
+
addonId: string(),
|
|
16895
|
+
enabled: boolean(),
|
|
16896
|
+
config: record(string(), unknown())
|
|
16897
|
+
});
|
|
16898
|
+
/** A discovery-surfaced candidate (config is partial + non-secret). */
|
|
16899
|
+
var DiscoveredTargetSchema = object({
|
|
16900
|
+
kind: string(),
|
|
16901
|
+
suggestedName: string(),
|
|
16902
|
+
config: record(string(), unknown())
|
|
16903
|
+
});
|
|
16904
|
+
/** The degrade engine's report — what was resolved / dropped / degraded. */
|
|
16905
|
+
var RenderedAsSchema = object({
|
|
16906
|
+
level: string(),
|
|
16907
|
+
format: NotificationFormatSchema,
|
|
16908
|
+
attachmentsSent: number().int().nonnegative(),
|
|
16909
|
+
actionsSent: number().int().nonnegative(),
|
|
16910
|
+
truncated: boolean(),
|
|
16911
|
+
dropped: array(string())
|
|
16912
|
+
});
|
|
16913
|
+
var SendResultSchema = object({
|
|
16914
|
+
success: boolean(),
|
|
16915
|
+
error: string().optional(),
|
|
16916
|
+
renderedAs: RenderedAsSchema.optional()
|
|
16917
|
+
});
|
|
16918
|
+
/** Same shape as SendResult — kept as a distinct name for the test panel. */
|
|
16919
|
+
var TestResultSchema = SendResultSchema;
|
|
16920
|
+
/**
|
|
16921
|
+
* Pre-save credential probe against a partial (unsaved) target config.
|
|
16922
|
+
* `resolvedUrl` never includes secrets (token stripped from path).
|
|
16923
|
+
*/
|
|
16924
|
+
var ProbeTargetConfigResultSchema = object({
|
|
16925
|
+
ok: boolean(),
|
|
16926
|
+
resolvedUrl: string(),
|
|
16927
|
+
httpStatus: number().int().optional(),
|
|
16928
|
+
stateInstance: string().optional(),
|
|
16929
|
+
error: string().optional()
|
|
16930
|
+
});
|
|
16931
|
+
var notificationOutputCapability = {
|
|
16932
|
+
name: "notification-output",
|
|
16933
|
+
scope: "system",
|
|
16934
|
+
mode: "collection",
|
|
16935
|
+
methods: {
|
|
16936
|
+
listTargetKinds: method(object({}), array(TargetKindSchema)),
|
|
16937
|
+
listTargets: method(object({}), array(TargetSchema), { auth: "admin" }),
|
|
16938
|
+
/**
|
|
16939
|
+
* One target WITH secrets — admin edit / duplicate hydration only.
|
|
16940
|
+
* `listTargets` stays redacted; the editor loads this so password fields
|
|
16941
|
+
* are filled (masked in the input) and a save can round-trip the token
|
|
16942
|
+
* when a destination changes (Duplicate with a new chatId, etc.).
|
|
16943
|
+
*/
|
|
16944
|
+
getTarget: method(object({ targetId: string() }), TargetSchema, { auth: "admin" }),
|
|
16945
|
+
discoverTargets: method(object({
|
|
16946
|
+
kind: string(),
|
|
16947
|
+
config: record(string(), unknown()).optional(),
|
|
16948
|
+
/**
|
|
16949
|
+
* When editing / duplicating, the blank password field never round-trips
|
|
16950
|
+
* the stored token. Pass the source target id so the provider can restore
|
|
16951
|
+
* secrets server-side before dialling (same merge as upsert).
|
|
16952
|
+
*/
|
|
16953
|
+
targetId: string().optional()
|
|
16954
|
+
}), array(DiscoveredTargetSchema), { auth: "admin" }),
|
|
16955
|
+
probeTargetConfig: method(object({
|
|
16956
|
+
kind: string(),
|
|
16957
|
+
config: record(string(), unknown()),
|
|
16958
|
+
/** See `discoverTargets.targetId` — restore stored secrets for a blank password. */
|
|
16959
|
+
targetId: string().optional()
|
|
16960
|
+
}), ProbeTargetConfigResultSchema, {
|
|
16961
|
+
kind: "mutation",
|
|
16962
|
+
auth: "admin"
|
|
16963
|
+
}),
|
|
16964
|
+
send: method(object({
|
|
16965
|
+
targetId: string(),
|
|
16966
|
+
notification: NotificationSchema
|
|
16967
|
+
}), SendResultSchema, {
|
|
16968
|
+
kind: "mutation",
|
|
16969
|
+
auth: "admin"
|
|
16970
|
+
}),
|
|
16971
|
+
testTarget: method(object({
|
|
16972
|
+
targetId: string(),
|
|
16973
|
+
sample: NotificationSchema.optional()
|
|
16974
|
+
}), TestResultSchema, {
|
|
16975
|
+
kind: "mutation",
|
|
16976
|
+
auth: "admin"
|
|
16977
|
+
}),
|
|
16978
|
+
upsertTarget: method(object({
|
|
16979
|
+
target: TargetSchema,
|
|
16980
|
+
/**
|
|
16981
|
+
* Duplicate flow: create a NEW target id while copying secrets from an
|
|
16982
|
+
* existing row. The UI never holds the stored token; blank / redacted
|
|
16983
|
+
* password fields are restored from this source (D634 still applies if
|
|
16984
|
+
* destinations diverge without a re-typed secret).
|
|
16985
|
+
*/
|
|
16986
|
+
cloneSecretsFrom: string().optional()
|
|
16987
|
+
}), TargetSchema, {
|
|
16988
|
+
kind: "mutation",
|
|
16989
|
+
auth: "admin"
|
|
16990
|
+
}),
|
|
16991
|
+
deleteTarget: method(object({ targetId: string() }), _void(), {
|
|
16992
|
+
kind: "mutation",
|
|
16993
|
+
auth: "admin"
|
|
16994
|
+
}),
|
|
16995
|
+
setTargetEnabled: method(object({
|
|
16996
|
+
targetId: string(),
|
|
16997
|
+
enabled: boolean()
|
|
16998
|
+
}), _void(), {
|
|
16999
|
+
kind: "mutation",
|
|
17000
|
+
auth: "admin"
|
|
17001
|
+
})
|
|
17002
|
+
}
|
|
17003
|
+
};
|
|
17004
|
+
/**
|
|
16410
17005
|
* `addon-pages` — system-scoped singleton aggregator cap. Public-facing
|
|
16411
17006
|
* surface that admin-ui consumes through `useAddonPagesListPages()`.
|
|
16412
17007
|
*
|
|
@@ -16438,52 +17033,6 @@ var AddonPageInfoSchema = object({
|
|
|
16438
17033
|
bundleUrl: string()
|
|
16439
17034
|
});
|
|
16440
17035
|
method(_void(), array(AddonPageInfoSchema).readonly());
|
|
16441
|
-
/**
|
|
16442
|
-
* `addon-pages-source` — collection cap exposing per-provider raw page
|
|
16443
|
-
* declarations. Every addon that contributes a UI page registers a
|
|
16444
|
-
* provider here. The hub-side singleton aggregator (`addon-pages` cap,
|
|
16445
|
-
* see `addon-pages.cap.ts`) walks this collection, stamps versioned
|
|
16446
|
-
* `bundleUrl` values, and returns the enriched `AddonPageInfo[]` list
|
|
16447
|
-
* that admin-ui consumes.
|
|
16448
|
-
*
|
|
16449
|
-
* The split exists because the public listing has a different output
|
|
16450
|
-
* shape than the per-provider raw declarations, and we want both ends
|
|
16451
|
-
* to flow through codegen instead of relying on a hand-written wrapper.
|
|
16452
|
-
*/
|
|
16453
|
-
var AddonPageDeclarationSchema = object({
|
|
16454
|
-
id: string(),
|
|
16455
|
-
label: string(),
|
|
16456
|
-
icon: string(),
|
|
16457
|
-
path: string(),
|
|
16458
|
-
/**
|
|
16459
|
-
* Module Federation remote name — must match the `name` field on the
|
|
16460
|
-
* page addon's `federation()` plugin config. Used by admin-ui's
|
|
16461
|
-
* `<AddonPageLoader>` to call `loadRemote('<remoteName>/page')`.
|
|
16462
|
-
* Conventionally `addon_<id>_page` (snake_case; MF names cannot
|
|
16463
|
-
* contain hyphens).
|
|
16464
|
-
*/
|
|
16465
|
-
remoteName: string(),
|
|
16466
|
-
/**
|
|
16467
|
-
* Bundle filename inside the addon's `dist/` dir served at
|
|
16468
|
-
* `/api/addon-pages/<addonId>/<bundle>`. With Module Federation this
|
|
16469
|
-
* is always `'remoteEntry.js'`; the value is kept on the metadata so
|
|
16470
|
-
* the static-file route can compute an mtime-based cache-buster URL
|
|
16471
|
-
* without a separate filesystem stat.
|
|
16472
|
-
*/
|
|
16473
|
-
bundle: string(),
|
|
16474
|
-
/**
|
|
16475
|
-
* Sidebar section this page docks into. Well-known ids: `'detection'`,
|
|
16476
|
-
* `'cluster'`, `'administration'` — the page renders inside that group.
|
|
16477
|
-
* Any OTHER string creates (or joins) a custom section rendered after
|
|
16478
|
-
* the built-in groups; its label comes from `sectionLabel` (first
|
|
16479
|
-
* declaration wins), falling back to the id. Absent → the legacy
|
|
16480
|
-
* "Addon Pages" group.
|
|
16481
|
-
*/
|
|
16482
|
-
section: string().optional(),
|
|
16483
|
-
/** Display label for a CUSTOM `section` id (ignored for well-known ids). */
|
|
16484
|
-
sectionLabel: string().optional()
|
|
16485
|
-
});
|
|
16486
|
-
method(_void(), array(AddonPageDeclarationSchema).readonly(), { auth: "admin" });
|
|
16487
17036
|
var AddonHttpRouteSchema = object({
|
|
16488
17037
|
method: _enum([
|
|
16489
17038
|
"GET",
|
|
@@ -19200,7 +19749,11 @@ var CompositionProblemSchema = object({
|
|
|
19200
19749
|
"mixed-quantity",
|
|
19201
19750
|
"helper-mismatch",
|
|
19202
19751
|
"member-constraint",
|
|
19203
|
-
"retention"
|
|
19752
|
+
"retention",
|
|
19753
|
+
"command-method-unknown",
|
|
19754
|
+
"command-source-unknown",
|
|
19755
|
+
"command-input-unknown",
|
|
19756
|
+
"command-input-missing"
|
|
19204
19757
|
]),
|
|
19205
19758
|
path: string(),
|
|
19206
19759
|
message: string()
|
|
@@ -19239,7 +19792,9 @@ var CompositionFieldRoleSchema = _enum([
|
|
|
19239
19792
|
var CompositionFieldItemSchema = object({
|
|
19240
19793
|
arrayPath: string(),
|
|
19241
19794
|
key: string(),
|
|
19242
|
-
label: string()
|
|
19795
|
+
label: string(),
|
|
19796
|
+
/** True when the item carries a `reset` forward: the composer writes `resettable` from this (D967). */
|
|
19797
|
+
resettable: boolean().optional()
|
|
19243
19798
|
});
|
|
19244
19799
|
var CompositionFieldPlanSchema = object({
|
|
19245
19800
|
cap: string(),
|
|
@@ -19444,7 +19999,7 @@ Object.freeze({
|
|
|
19444
19999
|
* One catalog row per base reading a group helper can build (D944 §3).
|
|
19445
20000
|
* Data, not a form default written into the block.
|
|
19446
20001
|
*/
|
|
19447
|
-
var NOW$
|
|
20002
|
+
var NOW$3 = {
|
|
19448
20003
|
fieldPath: "lastFetchedAt",
|
|
19449
20004
|
expr: "now"
|
|
19450
20005
|
};
|
|
@@ -19496,7 +20051,7 @@ var GROUP_TEMPLATES = [
|
|
|
19496
20051
|
quantity: "temperature",
|
|
19497
20052
|
defaultAggregate: "mean",
|
|
19498
20053
|
empty: "null",
|
|
19499
|
-
companions: [NOW$
|
|
20054
|
+
companions: [NOW$3],
|
|
19500
20055
|
alsoFrom: {
|
|
19501
20056
|
deviceTypes: CLIMATE_DEVICES,
|
|
19502
20057
|
accept: {
|
|
@@ -19514,7 +20069,7 @@ var GROUP_TEMPLATES = [
|
|
|
19514
20069
|
quantity: "humidity",
|
|
19515
20070
|
defaultAggregate: "mean",
|
|
19516
20071
|
empty: "null",
|
|
19517
|
-
companions: [NOW$
|
|
20072
|
+
companions: [NOW$3],
|
|
19518
20073
|
alsoFrom: {
|
|
19519
20074
|
deviceTypes: CLIMATE_DEVICES,
|
|
19520
20075
|
accept: {
|
|
@@ -19532,7 +20087,7 @@ var GROUP_TEMPLATES = [
|
|
|
19532
20087
|
quantity: "pressure",
|
|
19533
20088
|
defaultAggregate: "mean",
|
|
19534
20089
|
empty: "null",
|
|
19535
|
-
companions: [NOW$
|
|
20090
|
+
companions: [NOW$3]
|
|
19536
20091
|
}),
|
|
19537
20092
|
numeric({
|
|
19538
20093
|
id: "illuminance",
|
|
@@ -19543,7 +20098,7 @@ var GROUP_TEMPLATES = [
|
|
|
19543
20098
|
quantity: "illuminance",
|
|
19544
20099
|
defaultAggregate: "mean",
|
|
19545
20100
|
empty: "null",
|
|
19546
|
-
companions: [NOW$
|
|
20101
|
+
companions: [NOW$3]
|
|
19547
20102
|
}),
|
|
19548
20103
|
numeric({
|
|
19549
20104
|
id: "power",
|
|
@@ -19554,7 +20109,7 @@ var GROUP_TEMPLATES = [
|
|
|
19554
20109
|
quantity: "power",
|
|
19555
20110
|
defaultAggregate: "sum",
|
|
19556
20111
|
empty: "omit",
|
|
19557
|
-
companions: [NOW$
|
|
20112
|
+
companions: [NOW$3]
|
|
19558
20113
|
}),
|
|
19559
20114
|
numeric({
|
|
19560
20115
|
id: "energy",
|
|
@@ -19565,7 +20120,7 @@ var GROUP_TEMPLATES = [
|
|
|
19565
20120
|
quantity: "energy",
|
|
19566
20121
|
defaultAggregate: "sum",
|
|
19567
20122
|
empty: "omit",
|
|
19568
|
-
companions: [NOW$
|
|
20123
|
+
companions: [NOW$3]
|
|
19569
20124
|
}),
|
|
19570
20125
|
numeric({
|
|
19571
20126
|
id: "battery",
|
|
@@ -19600,7 +20155,7 @@ var GROUP_TEMPLATES = [
|
|
|
19600
20155
|
quantity: "device",
|
|
19601
20156
|
defaultAggregate: "mean",
|
|
19602
20157
|
empty: "null",
|
|
19603
|
-
companions: [NOW$
|
|
20158
|
+
companions: [NOW$3]
|
|
19604
20159
|
}),
|
|
19605
20160
|
binary({
|
|
19606
20161
|
id: "motion",
|
|
@@ -22074,12 +22629,48 @@ var ExposeInputSchema = object({
|
|
|
22074
22629
|
capabilities: array(string()).optional()
|
|
22075
22630
|
});
|
|
22076
22631
|
var UnexposeInputSchema = object({ deviceId: string() });
|
|
22632
|
+
/**
|
|
22633
|
+
* What an exporter may expose besides devices (D968). An action and a
|
|
22634
|
+
* notification target are LIST ENTRIES, never devices (D954): they enter an
|
|
22635
|
+
* exporter's own selection, not the device registry.
|
|
22636
|
+
*/
|
|
22637
|
+
var ExportEntityKindSchema = _enum([
|
|
22638
|
+
"device",
|
|
22639
|
+
"action",
|
|
22640
|
+
"notifier"
|
|
22641
|
+
]);
|
|
22642
|
+
var ExportEntityRefSchema = discriminatedUnion("kind", [
|
|
22643
|
+
object({
|
|
22644
|
+
kind: literal("device"),
|
|
22645
|
+
deviceId: string()
|
|
22646
|
+
}),
|
|
22647
|
+
object({
|
|
22648
|
+
kind: literal("action"),
|
|
22649
|
+
actionId: string().min(1)
|
|
22650
|
+
}),
|
|
22651
|
+
object({
|
|
22652
|
+
kind: literal("notifier"),
|
|
22653
|
+
targetId: string().min(1)
|
|
22654
|
+
})
|
|
22655
|
+
]);
|
|
22656
|
+
var ExposedEntitySchema = object({
|
|
22657
|
+
entity: ExportEntityRefSchema,
|
|
22658
|
+
exposedAs: string().optional()
|
|
22659
|
+
});
|
|
22660
|
+
var ExposeEntityInputSchema = object({ entity: ExportEntityRefSchema });
|
|
22661
|
+
var UnexposeEntityInputSchema = object({ entity: ExportEntityRefSchema });
|
|
22077
22662
|
method(_void(), DeviceExportStatusSchema), method(_void(), array(DeviceKindSchema)), method(_void(), array(ExposedDeviceSchema)), method(ExposeInputSchema, _void(), {
|
|
22078
22663
|
kind: "mutation",
|
|
22079
22664
|
auth: "admin"
|
|
22080
22665
|
}), method(UnexposeInputSchema, _void(), {
|
|
22081
22666
|
kind: "mutation",
|
|
22082
22667
|
auth: "admin"
|
|
22668
|
+
}), optionalMethod(_void(), array(ExportEntityKindSchema)), optionalMethod(_void(), array(ExposedEntitySchema)), optionalMethod(ExposeEntityInputSchema, _void(), {
|
|
22669
|
+
kind: "mutation",
|
|
22670
|
+
auth: "admin"
|
|
22671
|
+
}), optionalMethod(UnexposeEntityInputSchema, _void(), {
|
|
22672
|
+
kind: "mutation",
|
|
22673
|
+
auth: "admin"
|
|
22083
22674
|
});
|
|
22084
22675
|
/** Lucide category ids, alphabetical. `ICON_META` indexes into this. */
|
|
22085
22676
|
var ICON_CATEGORY_IDS = [
|
|
@@ -44029,7 +44620,7 @@ var LlmProviderWidgetSchema = object({
|
|
|
44029
44620
|
/** ConfigUISchema tree passed through untyped on the wire (the
|
|
44030
44621
|
* notification-output `ConfigSchemaPassthrough` precedent at
|
|
44031
44622
|
* notification-output.cap.ts:151); the exported TS type re-tightens it. */
|
|
44032
|
-
var ConfigSchemaPassthrough$
|
|
44623
|
+
var ConfigSchemaPassthrough$2 = unknown();
|
|
44033
44624
|
var LlmProfileKindDescriptorSchema = object({
|
|
44034
44625
|
kind: LlmProfileKindSchema,
|
|
44035
44626
|
label: string(),
|
|
@@ -44038,9 +44629,9 @@ var LlmProfileKindDescriptorSchema = object({
|
|
|
44038
44629
|
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
44039
44630
|
addonId: string(),
|
|
44040
44631
|
/** The provider's own fields (`providerConfig`); `password` fields are keychain-held. */
|
|
44041
|
-
connectionSchema: ConfigSchemaPassthrough$
|
|
44632
|
+
connectionSchema: ConfigSchemaPassthrough$2,
|
|
44042
44633
|
/** Provider fields that belong under "Advanced" (extra headers, runtime tuning). */
|
|
44043
|
-
advancedSchema: ConfigSchemaPassthrough$
|
|
44634
|
+
advancedSchema: ConfigSchemaPassthrough$2.optional(),
|
|
44044
44635
|
/** The kind's defaults; a model from `listModels` may override any of them. */
|
|
44045
44636
|
features: LlmModelFeaturesSchema,
|
|
44046
44637
|
/** `false` = the provider stamps `supportsVision` itself (from what a node reports). */
|
|
@@ -44566,10 +45157,10 @@ var CpuBreakdownSchema = object({
|
|
|
44566
45157
|
cores: number()
|
|
44567
45158
|
});
|
|
44568
45159
|
var MemoryInfoSchema = object({
|
|
44569
|
-
percent: number(),
|
|
45160
|
+
percent: number().nullable(),
|
|
44570
45161
|
totalBytes: number(),
|
|
44571
|
-
usedBytes: number(),
|
|
44572
|
-
availableBytes: number(),
|
|
45162
|
+
usedBytes: number().nullable(),
|
|
45163
|
+
availableBytes: number().nullable(),
|
|
44573
45164
|
swapUsedBytes: number(),
|
|
44574
45165
|
swapTotalBytes: number()
|
|
44575
45166
|
});
|
|
@@ -44873,8 +45464,9 @@ var GetLoadSeriesInputSchema = object({
|
|
|
44873
45464
|
});
|
|
44874
45465
|
var SystemMetricsSchema = object({
|
|
44875
45466
|
cpuPercent: number(),
|
|
44876
|
-
|
|
44877
|
-
|
|
45467
|
+
/** `null` when the memory sample failed or was not taken yet (D393). */
|
|
45468
|
+
memoryPercent: number().nullable(),
|
|
45469
|
+
memoryUsedMB: number().nullable(),
|
|
44878
45470
|
memoryTotalMB: number(),
|
|
44879
45471
|
diskPercent: number().optional(),
|
|
44880
45472
|
temperature: number().optional(),
|
|
@@ -44981,578 +45573,135 @@ var BrokerStatusSchema$1 = _enum([
|
|
|
44981
45573
|
"connected",
|
|
44982
45574
|
"disconnected",
|
|
44983
45575
|
"auth-failed",
|
|
44984
|
-
"unreachable",
|
|
44985
|
-
"tls-error"
|
|
44986
|
-
]);
|
|
44987
|
-
var BrokerInfoSchema$1 = object({
|
|
44988
|
-
id: string(),
|
|
44989
|
-
name: string(),
|
|
44990
|
-
url: string(),
|
|
44991
|
-
kind: BrokerKindSchema,
|
|
44992
|
-
status: BrokerStatusSchema$1,
|
|
44993
|
-
latencyMs: number().nullable(),
|
|
44994
|
-
error: string().optional(),
|
|
44995
|
-
/** Embedded brokers only: number of MQTT clients currently connected. */
|
|
44996
|
-
connectedClients: number().int().nonnegative().optional(),
|
|
44997
|
-
/** Epoch ms of the last live probe (external) or aedes snapshot (embedded). */
|
|
44998
|
-
lastCheckedAt: number().optional()
|
|
44999
|
-
});
|
|
45000
|
-
/**
|
|
45001
|
-
* Connection details — what a consumer needs to call
|
|
45002
|
-
* `mqtt.connect(url, options)`. We split URL + credentials so the
|
|
45003
|
-
* consumer can pass them as `mqtt.connect(url, { username, password })`
|
|
45004
|
-
* instead of stuffing creds into the URL (which leaks them into logs).
|
|
45005
|
-
*/
|
|
45006
|
-
var BrokerConnectionDetailsSchema = object({
|
|
45007
|
-
url: string(),
|
|
45008
|
-
username: string().optional(),
|
|
45009
|
-
password: string().optional(),
|
|
45010
|
-
/**
|
|
45011
|
-
* Suggested prefix for `clientId`. Each consumer should suffix this
|
|
45012
|
-
* with its own discriminator (addon id, instance id) so reconnects
|
|
45013
|
-
* don't kick each other off (MQTT spec: clientId must be unique per
|
|
45014
|
-
* broker).
|
|
45015
|
-
*/
|
|
45016
|
-
clientIdPrefix: string().optional()
|
|
45017
|
-
});
|
|
45018
|
-
var AddBrokerInputSchema = object({
|
|
45019
|
-
name: string().min(1),
|
|
45020
|
-
url: string().regex(/^(mqtt|mqtts|ws|wss):\/\//, "URL must start with mqtt(s):// or ws(s)://"),
|
|
45021
|
-
username: string().optional(),
|
|
45022
|
-
password: string().optional(),
|
|
45023
|
-
clientIdPrefix: string().optional()
|
|
45024
|
-
});
|
|
45025
|
-
var AddBrokerResultSchema = object({ id: string() });
|
|
45026
|
-
var IdInputSchema = object({ id: string() });
|
|
45027
|
-
var TestResultSchema$1 = discriminatedUnion("ok", [object({
|
|
45028
|
-
ok: literal(true),
|
|
45029
|
-
latencyMs: number()
|
|
45030
|
-
}), object({
|
|
45031
|
-
ok: literal(false),
|
|
45032
|
-
error: string()
|
|
45033
|
-
})]);
|
|
45034
|
-
var StartEmbeddedInputSchema = object({
|
|
45035
|
-
port: number().int().min(1).max(65535).default(1883),
|
|
45036
|
-
/** Allow anonymous connect (no username/password). Default: false. */
|
|
45037
|
-
allowAnonymous: boolean().default(false),
|
|
45038
|
-
/** Optional shared username/password for clients. */
|
|
45039
|
-
username: string().optional(),
|
|
45040
|
-
password: string().optional()
|
|
45041
|
-
});
|
|
45042
|
-
var StartEmbeddedResultSchema = object({
|
|
45043
|
-
id: string(),
|
|
45044
|
-
url: string()
|
|
45045
|
-
});
|
|
45046
|
-
var StatusSchema = object({
|
|
45047
|
-
brokerCount: number(),
|
|
45048
|
-
embeddedRunning: boolean()
|
|
45049
|
-
});
|
|
45050
|
-
method(_void(), array(BrokerInfoSchema$1)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
|
|
45051
|
-
kind: "mutation",
|
|
45052
|
-
auth: "admin"
|
|
45053
|
-
}), method(IdInputSchema, _void(), {
|
|
45054
|
-
kind: "mutation",
|
|
45055
|
-
auth: "admin"
|
|
45056
|
-
}), method(IdInputSchema, TestResultSchema$1, {
|
|
45057
|
-
kind: "mutation",
|
|
45058
|
-
auth: "admin"
|
|
45059
|
-
}), method(StartEmbeddedInputSchema, StartEmbeddedResultSchema, {
|
|
45060
|
-
kind: "mutation",
|
|
45061
|
-
auth: "admin"
|
|
45062
|
-
}), method(IdInputSchema, _void(), {
|
|
45063
|
-
kind: "mutation",
|
|
45064
|
-
auth: "admin"
|
|
45065
|
-
}), method(_void(), StatusSchema);
|
|
45066
|
-
var NetworkEndpointSchema = object({
|
|
45067
|
-
url: string(),
|
|
45068
|
-
hostname: string(),
|
|
45069
|
-
port: number(),
|
|
45070
|
-
protocol: _enum(["http", "https"]),
|
|
45071
|
-
/**
|
|
45072
|
-
* Whether this address survives a restart of its provider. `false` = it is
|
|
45073
|
-
* re-issued every time (a Quick tunnel's random `*.trycloudflare.com`); the
|
|
45074
|
-
* hub never selects such an address AUTOMATICALLY for a role (D860), though
|
|
45075
|
-
* it stays visible and an operator may still flag it. Absent = stable: every
|
|
45076
|
-
* provider except a Quick tunnel owns a name that does not change.
|
|
45077
|
-
*/
|
|
45078
|
-
stable: boolean().optional()
|
|
45079
|
-
});
|
|
45080
|
-
object({
|
|
45081
|
-
url: string(),
|
|
45082
|
-
/** Mirrors {@link NetworkEndpointSchema} `stable`; absent = stable. */
|
|
45083
|
-
stable: boolean().optional(),
|
|
45084
|
-
updated: boolean().optional()
|
|
45085
|
-
});
|
|
45086
|
-
var NetworkAccessStatusSchema = object({
|
|
45087
|
-
connected: boolean(),
|
|
45088
|
-
endpoint: NetworkEndpointSchema.nullable(),
|
|
45089
|
-
error: string().optional()
|
|
45090
|
-
});
|
|
45091
|
-
/**
|
|
45092
|
-
* Optional, richer endpoint shape returned by providers that expose
|
|
45093
|
-
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
45094
|
-
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
45095
|
-
* the originating provider config (mode + sourcePort) so the
|
|
45096
|
-
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
45097
|
-
* one endpoint just omit `listEndpoints` from their provider impl.
|
|
45098
|
-
*/
|
|
45099
|
-
var NetworkEndpointEntrySchema = NetworkEndpointSchema.extend({
|
|
45100
|
-
/**
|
|
45101
|
-
* Stable id within the provider — typically `<mode>-<sourcePort>` so
|
|
45102
|
-
* the orchestrator can dedupe across `listEndpoints` polls.
|
|
45103
|
-
*/
|
|
45104
|
-
id: string(),
|
|
45105
|
-
/** Operator-facing label (mirrors `MeshEndpoint.label`). */
|
|
45106
|
-
label: string(),
|
|
45107
|
-
/** Optional provider-specific mode tag, used for icon/colour in admin UI. */
|
|
45108
|
-
mode: string().optional(),
|
|
45109
|
-
/** Originating local port the ingress fronts (informational). */
|
|
45110
|
-
sourcePort: number().optional()
|
|
45111
|
-
});
|
|
45112
|
-
method(_void(), NetworkEndpointSchema, { kind: "mutation" }), method(_void(), _void(), { kind: "mutation" }), method(_void(), NetworkEndpointSchema.nullable()), method(_void(), NetworkAccessStatusSchema), method(_void(), array(NetworkEndpointEntrySchema).readonly());
|
|
45113
|
-
/**
|
|
45114
|
-
* notification-output — canonical, capability-gated notification delivery.
|
|
45115
|
-
*
|
|
45116
|
-
* Apprise-derived model (see
|
|
45117
|
-
* `docs/superpowers/specs/2026-07-03-notification-output-notifier-matrix.md`):
|
|
45118
|
-
* callers emit ONE canonical `Notification`; each provider declares a
|
|
45119
|
-
* per-kind capability descriptor (`TargetKind`), and the pure degrade
|
|
45120
|
-
* engine (`@camstack/types` `prepareNotification`) transcodes / degrades the
|
|
45121
|
-
* message to what the kind supports — callers never special-case a service.
|
|
45122
|
-
*
|
|
45123
|
-
* DESIGN DECISIONS (locked):
|
|
45124
|
-
* - Target CRUD lives on THIS cap (`upsertTarget` / `deleteTarget` /
|
|
45125
|
-
* `setTargetEnabled`), each provider persisting via the `settings-store`
|
|
45126
|
-
* cap. Rationale: the admin UI needs one uniform surface across the
|
|
45127
|
-
* notifiers addon AND the HA addon; the addon-`globalSettingsSchema`-array
|
|
45128
|
-
* alternative would fork the UI per addon and cannot host the
|
|
45129
|
-
* discovery→adopt flow.
|
|
45130
|
-
* - `listTargetKinds` / `listTargets` / `discoverTargets` return arrays →
|
|
45131
|
-
* the generated cap-mount auto-`concatCollection`-fans them across every
|
|
45132
|
-
* registered provider (notifiers addon + HA addon) so one catalog is
|
|
45133
|
-
* routable. `send` / `testTarget` / CRUD route to ONE provider by the
|
|
45134
|
-
* `addonId` the generated collection router extracts from the call input.
|
|
45135
|
-
* - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
|
|
45136
|
-
* transformer) + UDS MsgPack both round-trip typed arrays — already used by
|
|
45137
|
-
* `storage` / `storage-provider` / `recording` caps over the same path. No
|
|
45138
|
-
* base64 fallback needed.
|
|
45139
|
-
*
|
|
45140
|
-
* TODO (deferred, closed-set change — separate decision): add
|
|
45141
|
-
* `providerKind: 'notify'` so notification providers surface on the unified
|
|
45142
|
-
* admin "Integrations" page.
|
|
45143
|
-
*/
|
|
45144
|
-
/**
|
|
45145
|
-
* Zentik-derived typed-media enum — the superset across every kind. Each
|
|
45146
|
-
* adapter picks what it supports and the degrade engine filters the rest.
|
|
45147
|
-
*/
|
|
45148
|
-
var AttachmentMediaTypeSchema = _enum([
|
|
45149
|
-
"image",
|
|
45150
|
-
"video",
|
|
45151
|
-
"gif",
|
|
45152
|
-
"audio",
|
|
45153
|
-
"icon"
|
|
45154
|
-
]);
|
|
45155
|
-
/**
|
|
45156
|
-
* A single attachment. Exactly one of `url` (remote source, most adapters
|
|
45157
|
-
* prefer this) or `bytes` (inline source; required for Pushover-style
|
|
45158
|
-
* bytes-only kinds) MUST be present — the degrade engine expresses a
|
|
45159
|
-
* url→bytes fetch as a `needsFetch` directive the adapter executes.
|
|
45160
|
-
*/
|
|
45161
|
-
var AttachmentSchema = object({
|
|
45162
|
-
mediaType: AttachmentMediaTypeSchema,
|
|
45163
|
-
url: string().optional(),
|
|
45164
|
-
bytes: _instanceof(Uint8Array).optional(),
|
|
45165
|
-
mime: string().optional(),
|
|
45166
|
-
name: string().optional()
|
|
45167
|
-
}).refine((a) => a.url !== void 0 || a.bytes !== void 0, { message: "Attachment requires either `url` or `bytes`" });
|
|
45168
|
-
var NotificationFormatSchema = _enum([
|
|
45169
|
-
"text",
|
|
45170
|
-
"markdown",
|
|
45171
|
-
"html"
|
|
45172
|
-
]);
|
|
45173
|
-
/**
|
|
45174
|
-
* The CLOSED icon vocabulary an action button may use.
|
|
45175
|
-
*
|
|
45176
|
-
* A closed set, not a free string, and that is the whole point: an arbitrary
|
|
45177
|
-
* icon name is one that ntfy renders, zentik silently drops, and nobody
|
|
45178
|
-
* notices — the same class of gap as a zone vocabulary nothing produced
|
|
45179
|
-
* ([D35](../../../docs/decisions/adr-0035.md)). Every adapter maps this set or
|
|
45180
|
-
* declares `actionIcons: false` and the degrade engine strips the field.
|
|
45181
|
-
*
|
|
45182
|
-
* Named by INTENT, never by glyph. "check" would tie the vocabulary to one
|
|
45183
|
-
* renderer's icon set; "acknowledge" survives an adapter that draws it
|
|
45184
|
-
* differently.
|
|
45185
|
-
*
|
|
45186
|
-
* ── A TOKEN IS NOT A WIRE VALUE ─────────────────────────────────────
|
|
45187
|
-
*
|
|
45188
|
-
* These names are for US. **No adapter may forward one verbatim.** Each maps
|
|
45189
|
-
* the whole set onto its own renderer's vocabulary through a
|
|
45190
|
-
* `Record<NotificationActionIcon, string>` — a Record, never a lookup with a
|
|
45191
|
-
* fallback, so adding a member here fails every adapter's build until someone
|
|
45192
|
-
* decides its glyph, which is the only place that decision can be made
|
|
45193
|
-
* honestly.
|
|
45194
|
-
*
|
|
45195
|
-
* This paragraph is the bug. Zentik declared `actionIcons: true` and passed
|
|
45196
|
-
* `disarm` straight through; iOS feeds that string to
|
|
45197
|
-
* `UNNotificationActionIcon(systemImageName:)`, `disarm` is not an SF Symbol,
|
|
45198
|
-
* and every snooze and alarm button arrived BLANK. A pass-through is not a
|
|
45199
|
-
* mapping, and "the field is documented" is not "the value renders".
|
|
45200
|
-
*
|
|
45201
|
-
* Adding a member is TRAIN-BOUND. The enum lives in the published
|
|
45202
|
-
* `@camstack/server` closure and the cap seam validates against the HUB's copy,
|
|
45203
|
-
* so an addon that emits a token the running hub does not know does not lose an
|
|
45204
|
-
* icon — its whole `send` fails Zod validation and the notification never
|
|
45205
|
-
* arrives. Never emit a new token from an addon before the train carrying it.
|
|
45206
|
-
*/
|
|
45207
|
-
var NotificationActionIconSchema = _enum([
|
|
45208
|
-
"acknowledge",
|
|
45209
|
-
"dismiss",
|
|
45210
|
-
"silence",
|
|
45211
|
-
"snooze",
|
|
45212
|
-
"view",
|
|
45213
|
-
"play",
|
|
45214
|
-
"open",
|
|
45215
|
-
"close",
|
|
45216
|
-
"lock",
|
|
45217
|
-
"unlock",
|
|
45218
|
-
"arm",
|
|
45219
|
-
"arm-home",
|
|
45220
|
-
"arm-away",
|
|
45221
|
-
"arm-night",
|
|
45222
|
-
"disarm",
|
|
45223
|
-
"light",
|
|
45224
|
-
"alert",
|
|
45225
|
-
"camera"
|
|
45226
|
-
]);
|
|
45227
|
-
/** A single tap-through action button. */
|
|
45228
|
-
var NotificationActionSchema = object({
|
|
45229
|
-
id: string(),
|
|
45230
|
-
label: string(),
|
|
45231
|
-
url: string().optional(),
|
|
45232
|
-
/** Dropped by the degrade engine for a kind with `caps.actionIcons: false`. */
|
|
45233
|
-
icon: NotificationActionIconSchema.optional(),
|
|
45234
|
-
/**
|
|
45235
|
-
* Renders in a warning style where the notifier supports it.
|
|
45236
|
-
*
|
|
45237
|
-
* A HINT, never a gate. The callback's authority is its token and nothing
|
|
45238
|
-
* else — see `notification-center/action-token.ts` for what that does and
|
|
45239
|
-
* does not buy.
|
|
45240
|
-
*/
|
|
45241
|
-
destructive: boolean().optional(),
|
|
45242
|
-
/**
|
|
45243
|
-
* How the tap should REACH the url.
|
|
45244
|
-
*
|
|
45245
|
-
* `navigate` (absent, and every button authored before this field) opens it:
|
|
45246
|
-
* the phone leaves the notification and shows whatever the callback returns.
|
|
45247
|
-
* That is right for a button whose answer the operator wants to read.
|
|
45248
|
-
*
|
|
45249
|
-
* `background` fires it as a POST and stays put. It exists for the buttons
|
|
45250
|
-
* whose whole point is not to interrupt — "silence this for 30 minutes" is
|
|
45251
|
-
* an answer to the notification, and being thrown into a browser tab to
|
|
45252
|
-
* confirm it costs more attention than the notification did. A backend that
|
|
45253
|
-
* cannot do a background call renders it as an ordinary link (the adapters
|
|
45254
|
-
* fall back rather than dropping the button), so this is a preference, never
|
|
45255
|
-
* a requirement.
|
|
45256
|
-
*/
|
|
45257
|
-
mode: _enum(["navigate", "background"]).optional()
|
|
45258
|
-
});
|
|
45259
|
-
/** A delivery parameter value: what a notifier declared it takes. */
|
|
45260
|
-
var DeliveryParamValueSchema = union([
|
|
45261
|
-
string(),
|
|
45262
|
-
number(),
|
|
45263
|
-
boolean()
|
|
45264
|
-
]);
|
|
45265
|
-
/**
|
|
45266
|
-
* One extra delivery parameter a notifier KIND declares (D938). A rule that
|
|
45267
|
-
* addresses a target of that kind may set it; a kind that declares nothing is
|
|
45268
|
-
* never handed one. The admin UI derives its control from this descriptor —
|
|
45269
|
-
* no editor knows a service by name.
|
|
45270
|
-
*
|
|
45271
|
-
* Optional fields are `.optional()`, never `.default()` (a Zod default does not
|
|
45272
|
-
* run on the addon cap path).
|
|
45273
|
-
*/
|
|
45274
|
-
var DeliveryParamSchema = object({
|
|
45275
|
-
key: string().min(1),
|
|
45276
|
-
label: string(),
|
|
45277
|
-
/** i18n key of the label, resolved by the declaring addon's namespace. */
|
|
45278
|
-
labelKey: string().optional(),
|
|
45279
|
-
type: _enum([
|
|
45280
|
-
"enum",
|
|
45281
|
-
"number",
|
|
45282
|
-
"boolean",
|
|
45283
|
-
"string"
|
|
45284
|
-
]),
|
|
45285
|
-
/** `enum` only: the closed set of accepted values. */
|
|
45286
|
-
options: array(object({
|
|
45287
|
-
value: string(),
|
|
45288
|
-
label: string()
|
|
45289
|
-
})).optional(),
|
|
45290
|
-
/** `number` only. */
|
|
45291
|
-
min: number().optional(),
|
|
45292
|
-
max: number().optional(),
|
|
45293
|
-
/** What the notifier does when the rule sets nothing; shown as the placeholder. */
|
|
45294
|
-
default: DeliveryParamValueSchema.optional()
|
|
45295
|
-
});
|
|
45296
|
-
/**
|
|
45297
|
-
* The canonical notification. `body` is the only hard field (Apprise model).
|
|
45298
|
-
* `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
|
|
45299
|
-
* NOT a fixed severity enum — each kind declares its own `caps.levels` and
|
|
45300
|
-
* the adapter maps this ordinal onto its native level. `level?` is an
|
|
45301
|
-
* optional kind-native level id (`emergency`, `silent`, …) that overrides
|
|
45302
|
-
* `priority` for that one target.
|
|
45303
|
-
*/
|
|
45304
|
-
var NotificationSchema = object({
|
|
45305
|
-
body: string(),
|
|
45306
|
-
title: string().optional(),
|
|
45307
|
-
format: NotificationFormatSchema.default("text"),
|
|
45308
|
-
priority: number().int().min(1).max(5).default(3),
|
|
45309
|
-
level: string().optional(),
|
|
45310
|
-
attachments: array(AttachmentSchema).optional(),
|
|
45311
|
-
clickUrl: string().optional(),
|
|
45312
|
-
actions: array(NotificationActionSchema).optional(),
|
|
45313
|
-
sound: string().optional(),
|
|
45314
|
-
ttl: number().optional(),
|
|
45315
|
-
tag: string().optional(),
|
|
45316
|
-
deviceId: number().optional(),
|
|
45317
|
-
eventId: string().optional(),
|
|
45318
|
-
metadata: record(string(), unknown()).optional(),
|
|
45319
|
-
/**
|
|
45320
|
-
* Values for the parameters the target's kind DECLARES in
|
|
45321
|
-
* {@link TargetKindSchema} `deliveryParams`. Already validated against the
|
|
45322
|
-
* declaration by the sender; a notifier reads only the keys it declared.
|
|
45323
|
-
*/
|
|
45324
|
-
delivery: record(string(), DeliveryParamValueSchema).optional()
|
|
45325
|
-
});
|
|
45326
|
-
/** One declared native severity/priority level for a kind. */
|
|
45327
|
-
var TargetKindLevelSchema = object({
|
|
45328
|
-
id: string(),
|
|
45329
|
-
label: string(),
|
|
45330
|
-
/** Which canonical priority (1..5) this level maps to. `null` = qualitative-only. */
|
|
45331
|
-
ordinal: number().int().min(1).max(5).nullable(),
|
|
45332
|
-
flags: object({
|
|
45333
|
-
critical: boolean().optional(),
|
|
45334
|
-
silent: boolean().optional(),
|
|
45335
|
-
noPush: boolean().optional()
|
|
45336
|
-
}).optional(),
|
|
45337
|
-
/** e.g. Pushover `emergency` requires `retry` / `expire`. */
|
|
45338
|
-
requires: array(string()).optional(),
|
|
45339
|
-
description: string().optional()
|
|
45340
|
-
});
|
|
45341
|
-
/** The full capability block consulted before dispatch. */
|
|
45342
|
-
var TargetKindCapsSchema = object({
|
|
45343
|
-
attachments: object({
|
|
45344
|
-
mediaTypes: array(AttachmentMediaTypeSchema),
|
|
45345
|
-
mode: _enum([
|
|
45346
|
-
"url",
|
|
45347
|
-
"bytes",
|
|
45348
|
-
"both"
|
|
45349
|
-
]),
|
|
45350
|
-
max: number().int().nonnegative(),
|
|
45351
|
-
maxBytes: number().int().positive().optional()
|
|
45352
|
-
}),
|
|
45353
|
-
/** Max action buttons (0 = none). */
|
|
45354
|
-
actions: number().int().nonnegative(),
|
|
45355
|
-
/**
|
|
45356
|
-
* Whether this kind renders a per-action ICON.
|
|
45357
|
-
*
|
|
45358
|
-
* `.optional()`, deliberately NOT `.default(false)`: a Zod default does not
|
|
45359
|
-
* run on the addon cap path — three production failures in one day taught
|
|
45360
|
-
* this repo that once. Absent is read as false by the degrade engine, which
|
|
45361
|
-
* is the safe direction: an icon that is not rendered costs nothing, an icon
|
|
45362
|
-
* assumed and dropped costs the operator's trust in the field.
|
|
45363
|
-
*/
|
|
45364
|
-
actionIcons: boolean().optional(),
|
|
45365
|
-
levels: array(TargetKindLevelSchema),
|
|
45366
|
-
format: array(NotificationFormatSchema),
|
|
45367
|
-
clickUrl: boolean(),
|
|
45368
|
-
sound: boolean(),
|
|
45369
|
-
ttl: boolean(),
|
|
45370
|
-
bodyMaxLen: number().int().positive()
|
|
45576
|
+
"unreachable",
|
|
45577
|
+
"tls-error"
|
|
45578
|
+
]);
|
|
45579
|
+
var BrokerInfoSchema$1 = object({
|
|
45580
|
+
id: string(),
|
|
45581
|
+
name: string(),
|
|
45582
|
+
url: string(),
|
|
45583
|
+
kind: BrokerKindSchema,
|
|
45584
|
+
status: BrokerStatusSchema$1,
|
|
45585
|
+
latencyMs: number().nullable(),
|
|
45586
|
+
error: string().optional(),
|
|
45587
|
+
/** Embedded brokers only: number of MQTT clients currently connected. */
|
|
45588
|
+
connectedClients: number().int().nonnegative().optional(),
|
|
45589
|
+
/** Epoch ms of the last live probe (external) or aedes snapshot (embedded). */
|
|
45590
|
+
lastCheckedAt: number().optional()
|
|
45371
45591
|
});
|
|
45372
45592
|
/**
|
|
45373
|
-
*
|
|
45374
|
-
*
|
|
45375
|
-
* `
|
|
45376
|
-
*
|
|
45377
|
-
* `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
|
|
45593
|
+
* Connection details — what a consumer needs to call
|
|
45594
|
+
* `mqtt.connect(url, options)`. We split URL + credentials so the
|
|
45595
|
+
* consumer can pass them as `mqtt.connect(url, { username, password })`
|
|
45596
|
+
* instead of stuffing creds into the URL (which leaks them into logs).
|
|
45378
45597
|
*/
|
|
45379
|
-
var
|
|
45380
|
-
|
|
45381
|
-
|
|
45382
|
-
|
|
45383
|
-
icon: string(),
|
|
45384
|
-
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
45385
|
-
addonId: string(),
|
|
45386
|
-
/**
|
|
45387
|
-
* URL of the kind's bundled BRAND icon, served by the providing addon over
|
|
45388
|
-
* its own `addon-routes` surface (`/addon/<addonId>/icons/<kind>`). Absent
|
|
45389
|
-
* when the addon bundles no icon for that kind — the client then falls back
|
|
45390
|
-
* to a neutral glyph rather than rendering the raw `icon` NAME as text.
|
|
45391
|
-
*
|
|
45392
|
-
* Root-relative on purpose: it resolves against whatever origin serves a web
|
|
45393
|
-
* client, and a native client joins it onto its own hub base.
|
|
45394
|
-
*
|
|
45395
|
-
* DECLARED here deliberately. It used to travel as an undeclared passthrough
|
|
45396
|
-
* field that survived only because the runtime cap-router forwards provider
|
|
45397
|
-
* output verbatim — so every consumer had to re-declare it by hand to stop
|
|
45398
|
-
* its own Zod parse from stripping it, and the whole arrangement would have
|
|
45399
|
-
* broken silently the moment output validation was tightened anywhere.
|
|
45400
|
-
*/
|
|
45401
|
-
iconUrl: string().optional(),
|
|
45402
|
-
/**
|
|
45403
|
-
* Media type of {@link iconUrl} (`image/svg+xml`, `image/png`, …).
|
|
45404
|
-
*
|
|
45405
|
-
* The server knows this and therefore says it, because the client cannot
|
|
45406
|
-
* safely guess: a React-Native client renders SVG and raster through two
|
|
45407
|
-
* DIFFERENT components (`react-native-svg` vs `expo-image` — expo-image does
|
|
45408
|
-
* not decode SVG on iOS/Android), so without this it silently fell back to a
|
|
45409
|
-
* placeholder glyph for every vector icon while the web build looked fine.
|
|
45410
|
-
*
|
|
45411
|
-
* Absent when {@link iconUrl} is absent, or for a legacy provider that has
|
|
45412
|
-
* not been updated — a client that cannot determine the type should prefer
|
|
45413
|
-
* its raster path, which is the safe default for an unknown image.
|
|
45414
|
-
*/
|
|
45415
|
-
iconMediaType: string().optional(),
|
|
45416
|
-
configSchema: ConfigSchemaPassthrough$2,
|
|
45417
|
-
/**
|
|
45418
|
-
* The config keys that decide WHERE this kind's secrets are sent (server,
|
|
45419
|
-
* base URL, instance, chat, recipient). A save that changes any of them
|
|
45420
|
-
* while leaving a secret redacted is refused by the provider (D634), so an
|
|
45421
|
-
* editor uses this to ask for the secret on exactly those edits instead of
|
|
45422
|
-
* on every edit.
|
|
45423
|
-
*
|
|
45424
|
-
* Optional: absent from a provider that holds no secret (the Home Assistant
|
|
45425
|
-
* kinds) and from a provider older than this field — an editor that finds
|
|
45426
|
-
* it absent must assume ANY edit may need the secret.
|
|
45427
|
-
*/
|
|
45428
|
-
destinationKeys: array(string()).optional(),
|
|
45429
|
-
supportsDiscovery: boolean(),
|
|
45598
|
+
var BrokerConnectionDetailsSchema = object({
|
|
45599
|
+
url: string(),
|
|
45600
|
+
username: string().optional(),
|
|
45601
|
+
password: string().optional(),
|
|
45430
45602
|
/**
|
|
45431
|
-
*
|
|
45432
|
-
*
|
|
45603
|
+
* Suggested prefix for `clientId`. Each consumer should suffix this
|
|
45604
|
+
* with its own discriminator (addon id, instance id) so reconnects
|
|
45605
|
+
* don't kick each other off (MQTT spec: clientId must be unique per
|
|
45606
|
+
* broker).
|
|
45433
45607
|
*/
|
|
45434
|
-
|
|
45435
|
-
caps: TargetKindCapsSchema
|
|
45608
|
+
clientIdPrefix: string().optional()
|
|
45436
45609
|
});
|
|
45437
|
-
|
|
45438
|
-
|
|
45439
|
-
|
|
45440
|
-
|
|
45441
|
-
|
|
45442
|
-
|
|
45610
|
+
var AddBrokerInputSchema = object({
|
|
45611
|
+
name: string().min(1),
|
|
45612
|
+
url: string().regex(/^(mqtt|mqtts|ws|wss):\/\//, "URL must start with mqtt(s):// or ws(s)://"),
|
|
45613
|
+
username: string().optional(),
|
|
45614
|
+
password: string().optional(),
|
|
45615
|
+
clientIdPrefix: string().optional()
|
|
45616
|
+
});
|
|
45617
|
+
var AddBrokerResultSchema = object({ id: string() });
|
|
45618
|
+
var IdInputSchema = object({ id: string() });
|
|
45619
|
+
var TestResultSchema$1 = discriminatedUnion("ok", [object({
|
|
45620
|
+
ok: literal(true),
|
|
45621
|
+
latencyMs: number()
|
|
45622
|
+
}), object({
|
|
45623
|
+
ok: literal(false),
|
|
45624
|
+
error: string()
|
|
45625
|
+
})]);
|
|
45626
|
+
var StartEmbeddedInputSchema = object({
|
|
45627
|
+
port: number().int().min(1).max(65535).default(1883),
|
|
45628
|
+
/** Allow anonymous connect (no username/password). Default: false. */
|
|
45629
|
+
allowAnonymous: boolean().default(false),
|
|
45630
|
+
/** Optional shared username/password for clients. */
|
|
45631
|
+
username: string().optional(),
|
|
45632
|
+
password: string().optional()
|
|
45633
|
+
});
|
|
45634
|
+
var StartEmbeddedResultSchema = object({
|
|
45443
45635
|
id: string(),
|
|
45444
|
-
|
|
45445
|
-
kind: string(),
|
|
45446
|
-
addonId: string(),
|
|
45447
|
-
enabled: boolean(),
|
|
45448
|
-
config: record(string(), unknown())
|
|
45636
|
+
url: string()
|
|
45449
45637
|
});
|
|
45450
|
-
|
|
45451
|
-
|
|
45452
|
-
|
|
45453
|
-
suggestedName: string(),
|
|
45454
|
-
config: record(string(), unknown())
|
|
45638
|
+
var StatusSchema = object({
|
|
45639
|
+
brokerCount: number(),
|
|
45640
|
+
embeddedRunning: boolean()
|
|
45455
45641
|
});
|
|
45456
|
-
|
|
45457
|
-
|
|
45458
|
-
|
|
45459
|
-
|
|
45460
|
-
|
|
45461
|
-
|
|
45462
|
-
|
|
45463
|
-
|
|
45642
|
+
method(_void(), array(BrokerInfoSchema$1)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
|
|
45643
|
+
kind: "mutation",
|
|
45644
|
+
auth: "admin"
|
|
45645
|
+
}), method(IdInputSchema, _void(), {
|
|
45646
|
+
kind: "mutation",
|
|
45647
|
+
auth: "admin"
|
|
45648
|
+
}), method(IdInputSchema, TestResultSchema$1, {
|
|
45649
|
+
kind: "mutation",
|
|
45650
|
+
auth: "admin"
|
|
45651
|
+
}), method(StartEmbeddedInputSchema, StartEmbeddedResultSchema, {
|
|
45652
|
+
kind: "mutation",
|
|
45653
|
+
auth: "admin"
|
|
45654
|
+
}), method(IdInputSchema, _void(), {
|
|
45655
|
+
kind: "mutation",
|
|
45656
|
+
auth: "admin"
|
|
45657
|
+
}), method(_void(), StatusSchema);
|
|
45658
|
+
var NetworkEndpointSchema = object({
|
|
45659
|
+
url: string(),
|
|
45660
|
+
hostname: string(),
|
|
45661
|
+
port: number(),
|
|
45662
|
+
protocol: _enum(["http", "https"]),
|
|
45663
|
+
/**
|
|
45664
|
+
* Whether this address survives a restart of its provider. `false` = it is
|
|
45665
|
+
* re-issued every time (a Quick tunnel's random `*.trycloudflare.com`); the
|
|
45666
|
+
* hub never selects such an address AUTOMATICALLY for a role (D860), though
|
|
45667
|
+
* it stays visible and an operator may still flag it. Absent = stable: every
|
|
45668
|
+
* provider except a Quick tunnel owns a name that does not change.
|
|
45669
|
+
*/
|
|
45670
|
+
stable: boolean().optional()
|
|
45464
45671
|
});
|
|
45465
|
-
|
|
45466
|
-
|
|
45467
|
-
|
|
45468
|
-
|
|
45672
|
+
object({
|
|
45673
|
+
url: string(),
|
|
45674
|
+
/** Mirrors {@link NetworkEndpointSchema} `stable`; absent = stable. */
|
|
45675
|
+
stable: boolean().optional(),
|
|
45676
|
+
updated: boolean().optional()
|
|
45677
|
+
});
|
|
45678
|
+
var NetworkAccessStatusSchema = object({
|
|
45679
|
+
connected: boolean(),
|
|
45680
|
+
endpoint: NetworkEndpointSchema.nullable(),
|
|
45681
|
+
error: string().optional()
|
|
45469
45682
|
});
|
|
45470
|
-
/** Same shape as SendResult — kept as a distinct name for the test panel. */
|
|
45471
|
-
var TestResultSchema = SendResultSchema;
|
|
45472
45683
|
/**
|
|
45473
|
-
*
|
|
45474
|
-
*
|
|
45684
|
+
* Optional, richer endpoint shape returned by providers that expose
|
|
45685
|
+
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
45686
|
+
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
45687
|
+
* the originating provider config (mode + sourcePort) so the
|
|
45688
|
+
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
45689
|
+
* one endpoint just omit `listEndpoints` from their provider impl.
|
|
45475
45690
|
*/
|
|
45476
|
-
var
|
|
45477
|
-
|
|
45478
|
-
|
|
45479
|
-
|
|
45480
|
-
|
|
45481
|
-
|
|
45691
|
+
var NetworkEndpointEntrySchema = NetworkEndpointSchema.extend({
|
|
45692
|
+
/**
|
|
45693
|
+
* Stable id within the provider — typically `<mode>-<sourcePort>` so
|
|
45694
|
+
* the orchestrator can dedupe across `listEndpoints` polls.
|
|
45695
|
+
*/
|
|
45696
|
+
id: string(),
|
|
45697
|
+
/** Operator-facing label (mirrors `MeshEndpoint.label`). */
|
|
45698
|
+
label: string(),
|
|
45699
|
+
/** Optional provider-specific mode tag, used for icon/colour in admin UI. */
|
|
45700
|
+
mode: string().optional(),
|
|
45701
|
+
/** Originating local port the ingress fronts (informational). */
|
|
45702
|
+
sourcePort: number().optional()
|
|
45482
45703
|
});
|
|
45483
|
-
|
|
45484
|
-
name: "notification-output",
|
|
45485
|
-
scope: "system",
|
|
45486
|
-
mode: "collection",
|
|
45487
|
-
methods: {
|
|
45488
|
-
listTargetKinds: method(object({}), array(TargetKindSchema)),
|
|
45489
|
-
listTargets: method(object({}), array(TargetSchema), { auth: "admin" }),
|
|
45490
|
-
/**
|
|
45491
|
-
* One target WITH secrets — admin edit / duplicate hydration only.
|
|
45492
|
-
* `listTargets` stays redacted; the editor loads this so password fields
|
|
45493
|
-
* are filled (masked in the input) and a save can round-trip the token
|
|
45494
|
-
* when a destination changes (Duplicate with a new chatId, etc.).
|
|
45495
|
-
*/
|
|
45496
|
-
getTarget: method(object({ targetId: string() }), TargetSchema, { auth: "admin" }),
|
|
45497
|
-
discoverTargets: method(object({
|
|
45498
|
-
kind: string(),
|
|
45499
|
-
config: record(string(), unknown()).optional(),
|
|
45500
|
-
/**
|
|
45501
|
-
* When editing / duplicating, the blank password field never round-trips
|
|
45502
|
-
* the stored token. Pass the source target id so the provider can restore
|
|
45503
|
-
* secrets server-side before dialling (same merge as upsert).
|
|
45504
|
-
*/
|
|
45505
|
-
targetId: string().optional()
|
|
45506
|
-
}), array(DiscoveredTargetSchema), { auth: "admin" }),
|
|
45507
|
-
probeTargetConfig: method(object({
|
|
45508
|
-
kind: string(),
|
|
45509
|
-
config: record(string(), unknown()),
|
|
45510
|
-
/** See `discoverTargets.targetId` — restore stored secrets for a blank password. */
|
|
45511
|
-
targetId: string().optional()
|
|
45512
|
-
}), ProbeTargetConfigResultSchema, {
|
|
45513
|
-
kind: "mutation",
|
|
45514
|
-
auth: "admin"
|
|
45515
|
-
}),
|
|
45516
|
-
send: method(object({
|
|
45517
|
-
targetId: string(),
|
|
45518
|
-
notification: NotificationSchema
|
|
45519
|
-
}), SendResultSchema, {
|
|
45520
|
-
kind: "mutation",
|
|
45521
|
-
auth: "admin"
|
|
45522
|
-
}),
|
|
45523
|
-
testTarget: method(object({
|
|
45524
|
-
targetId: string(),
|
|
45525
|
-
sample: NotificationSchema.optional()
|
|
45526
|
-
}), TestResultSchema, {
|
|
45527
|
-
kind: "mutation",
|
|
45528
|
-
auth: "admin"
|
|
45529
|
-
}),
|
|
45530
|
-
upsertTarget: method(object({
|
|
45531
|
-
target: TargetSchema,
|
|
45532
|
-
/**
|
|
45533
|
-
* Duplicate flow: create a NEW target id while copying secrets from an
|
|
45534
|
-
* existing row. The UI never holds the stored token; blank / redacted
|
|
45535
|
-
* password fields are restored from this source (D634 still applies if
|
|
45536
|
-
* destinations diverge without a re-typed secret).
|
|
45537
|
-
*/
|
|
45538
|
-
cloneSecretsFrom: string().optional()
|
|
45539
|
-
}), TargetSchema, {
|
|
45540
|
-
kind: "mutation",
|
|
45541
|
-
auth: "admin"
|
|
45542
|
-
}),
|
|
45543
|
-
deleteTarget: method(object({ targetId: string() }), _void(), {
|
|
45544
|
-
kind: "mutation",
|
|
45545
|
-
auth: "admin"
|
|
45546
|
-
}),
|
|
45547
|
-
setTargetEnabled: method(object({
|
|
45548
|
-
targetId: string(),
|
|
45549
|
-
enabled: boolean()
|
|
45550
|
-
}), _void(), {
|
|
45551
|
-
kind: "mutation",
|
|
45552
|
-
auth: "admin"
|
|
45553
|
-
})
|
|
45554
|
-
}
|
|
45555
|
-
};
|
|
45704
|
+
method(_void(), NetworkEndpointSchema, { kind: "mutation" }), method(_void(), _void(), { kind: "mutation" }), method(_void(), NetworkEndpointSchema.nullable()), method(_void(), NetworkAccessStatusSchema), method(_void(), array(NetworkEndpointEntrySchema).readonly());
|
|
45556
45705
|
var AUDIO_MACRO_LABELS = [
|
|
45557
45706
|
{
|
|
45558
45707
|
id: "speech",
|
|
@@ -51997,14 +52146,6 @@ var EngineProvisioningSchema = object({
|
|
|
51997
52146
|
*/
|
|
51998
52147
|
configIssues: array(string()).optional()
|
|
51999
52148
|
});
|
|
52000
|
-
var PipelineStepInputSchema = lazy(() => object({
|
|
52001
|
-
addonId: string(),
|
|
52002
|
-
modelId: string().optional(),
|
|
52003
|
-
enabled: boolean().default(true),
|
|
52004
|
-
children: array(PipelineStepInputSchema).optional(),
|
|
52005
|
-
settings: record(string(), unknown()).optional(),
|
|
52006
|
-
jumpDeviceKey: string().optional()
|
|
52007
|
-
}));
|
|
52008
52149
|
var ModelSubstitutionSchema = object({
|
|
52009
52150
|
addonId: string(),
|
|
52010
52151
|
chosen: string(),
|
|
@@ -52083,7 +52224,6 @@ var ConfigUISchemaBridge = custom();
|
|
|
52083
52224
|
var ConfigUISchemaNullableBridge = custom();
|
|
52084
52225
|
var InferenceCapabilitiesBridge = custom();
|
|
52085
52226
|
var ModelAvailabilityListBridge = custom();
|
|
52086
|
-
var PipelineRunResultBridge = custom();
|
|
52087
52227
|
method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
|
|
52088
52228
|
modelId: string(),
|
|
52089
52229
|
settings: record(string(), unknown()).readonly()
|
|
@@ -55289,6 +55429,12 @@ var ServerUpdateActionResultSchema = object({
|
|
|
55289
55429
|
*/
|
|
55290
55430
|
blockers: array(UpdateBlockerSchema).optional()
|
|
55291
55431
|
});
|
|
55432
|
+
var LaunchOverridesSchema = object({
|
|
55433
|
+
/** The persisted heap ceiling in MB, or `null` when none is set. */
|
|
55434
|
+
heapMb: number().int().nullable() });
|
|
55435
|
+
var SetLaunchOverridesResultSchema = LaunchOverridesSchema.extend({
|
|
55436
|
+
/** Always true: the override is read at launch, not by the running process. */
|
|
55437
|
+
restartRequired: boolean() });
|
|
55292
55438
|
method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), ServerUpdateCheckResultSchema, {
|
|
55293
55439
|
kind: "mutation",
|
|
55294
55440
|
auth: "admin"
|
|
@@ -55311,6 +55457,9 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
|
|
|
55311
55457
|
}), method(_void(), ServerUpdateActionResultSchema, {
|
|
55312
55458
|
kind: "mutation",
|
|
55313
55459
|
auth: "admin"
|
|
55460
|
+
}), method(_void(), LaunchOverridesSchema, { auth: "admin" }), method(object({ heapMb: number().int().min(512).max(65536).nullable() }), SetLaunchOverridesResultSchema, {
|
|
55461
|
+
kind: "mutation",
|
|
55462
|
+
auth: "admin"
|
|
55314
55463
|
});
|
|
55315
55464
|
/**
|
|
55316
55465
|
* `smtp-provider` — pluggable email delivery surface.
|
|
@@ -60219,14 +60368,13 @@ reset: method(object({
|
|
|
60219
60368
|
auth: "admin"
|
|
60220
60369
|
}) },
|
|
60221
60370
|
/**
|
|
60222
|
-
* A
|
|
60223
|
-
*
|
|
60224
|
-
*
|
|
60225
|
-
* commands (`forward`) arrive in slice 3 (D663).
|
|
60371
|
+
* A consumable ADDED to an existing device (a graft) refuses `reset` by
|
|
60372
|
+
* name: only a composed device of a NEW type forwards an item's reset to a
|
|
60373
|
+
* source button, and marks that item `resettable` (D967).
|
|
60226
60374
|
*/
|
|
60227
60375
|
composedMethods: { reset: {
|
|
60228
60376
|
kind: "refuse",
|
|
60229
|
-
reason: "a
|
|
60377
|
+
reason: "a consumable added to an existing device is not resettable — only a new composed device forwards a reset"
|
|
60230
60378
|
} },
|
|
60231
60379
|
status: {
|
|
60232
60380
|
schema: ConsumablesStatusSchema,
|
|
@@ -60820,7 +60968,7 @@ var DishwasherStatusSchema = object({
|
|
|
60820
60968
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
60821
60969
|
lastFetchedAt: number()
|
|
60822
60970
|
});
|
|
60823
|
-
var DeviceIdSchema = number().int().nonnegative();
|
|
60971
|
+
var DeviceIdSchema$1 = number().int().nonnegative();
|
|
60824
60972
|
/** A value a program option or setting can take. */
|
|
60825
60973
|
var DishwasherValueSchema = union([
|
|
60826
60974
|
boolean(),
|
|
@@ -60895,77 +61043,77 @@ var dishwasherCapability = {
|
|
|
60895
61043
|
* option feature keys; each is checked against the program's constraints.
|
|
60896
61044
|
*/
|
|
60897
61045
|
start: method(object({
|
|
60898
|
-
deviceId: DeviceIdSchema,
|
|
61046
|
+
deviceId: DeviceIdSchema$1,
|
|
60899
61047
|
program: string().min(1).optional(),
|
|
60900
61048
|
options: record(string(), DishwasherValueSchema).optional()
|
|
60901
61049
|
}), _void(), {
|
|
60902
61050
|
kind: "mutation",
|
|
60903
61051
|
auth: "protected"
|
|
60904
61052
|
}),
|
|
60905
|
-
pause: method(object({ deviceId: DeviceIdSchema }), _void(), {
|
|
61053
|
+
pause: method(object({ deviceId: DeviceIdSchema$1 }), _void(), {
|
|
60906
61054
|
kind: "mutation",
|
|
60907
61055
|
auth: "protected"
|
|
60908
61056
|
}),
|
|
60909
|
-
resume: method(object({ deviceId: DeviceIdSchema }), _void(), {
|
|
61057
|
+
resume: method(object({ deviceId: DeviceIdSchema$1 }), _void(), {
|
|
60910
61058
|
kind: "mutation",
|
|
60911
61059
|
auth: "protected"
|
|
60912
61060
|
}),
|
|
60913
|
-
stop: method(object({ deviceId: DeviceIdSchema }), _void(), {
|
|
61061
|
+
stop: method(object({ deviceId: DeviceIdSchema$1 }), _void(), {
|
|
60914
61062
|
kind: "mutation",
|
|
60915
61063
|
auth: "protected"
|
|
60916
61064
|
}),
|
|
60917
61065
|
/** Select (not start) a program; refused when the appliance does not offer it. */
|
|
60918
61066
|
setProgram: method(object({
|
|
60919
|
-
deviceId: DeviceIdSchema,
|
|
61067
|
+
deviceId: DeviceIdSchema$1,
|
|
60920
61068
|
program: string().min(1)
|
|
60921
61069
|
}), _void(), {
|
|
60922
61070
|
kind: "mutation",
|
|
60923
61071
|
auth: "protected"
|
|
60924
61072
|
}),
|
|
60925
61073
|
setPower: method(object({
|
|
60926
|
-
deviceId: DeviceIdSchema,
|
|
61074
|
+
deviceId: DeviceIdSchema$1,
|
|
60927
61075
|
on: boolean()
|
|
60928
61076
|
}), _void(), {
|
|
60929
61077
|
kind: "mutation",
|
|
60930
61078
|
auth: "protected"
|
|
60931
61079
|
}),
|
|
60932
61080
|
setHalfLoad: method(object({
|
|
60933
|
-
deviceId: DeviceIdSchema,
|
|
61081
|
+
deviceId: DeviceIdSchema$1,
|
|
60934
61082
|
on: boolean()
|
|
60935
61083
|
}), _void(), {
|
|
60936
61084
|
kind: "mutation",
|
|
60937
61085
|
auth: "protected"
|
|
60938
61086
|
}),
|
|
60939
61087
|
setHygienePlus: method(object({
|
|
60940
|
-
deviceId: DeviceIdSchema,
|
|
61088
|
+
deviceId: DeviceIdSchema$1,
|
|
60941
61089
|
on: boolean()
|
|
60942
61090
|
}), _void(), {
|
|
60943
61091
|
kind: "mutation",
|
|
60944
61092
|
auth: "protected"
|
|
60945
61093
|
}),
|
|
60946
61094
|
setExtraDry: method(object({
|
|
60947
|
-
deviceId: DeviceIdSchema,
|
|
61095
|
+
deviceId: DeviceIdSchema$1,
|
|
60948
61096
|
on: boolean()
|
|
60949
61097
|
}), _void(), {
|
|
60950
61098
|
kind: "mutation",
|
|
60951
61099
|
auth: "protected"
|
|
60952
61100
|
}),
|
|
60953
61101
|
setIntensiveZone: method(object({
|
|
60954
|
-
deviceId: DeviceIdSchema,
|
|
61102
|
+
deviceId: DeviceIdSchema$1,
|
|
60955
61103
|
on: boolean()
|
|
60956
61104
|
}), _void(), {
|
|
60957
61105
|
kind: "mutation",
|
|
60958
61106
|
auth: "protected"
|
|
60959
61107
|
}),
|
|
60960
61108
|
setVarioSpeedPlus: method(object({
|
|
60961
|
-
deviceId: DeviceIdSchema,
|
|
61109
|
+
deviceId: DeviceIdSchema$1,
|
|
60962
61110
|
on: boolean()
|
|
60963
61111
|
}), _void(), {
|
|
60964
61112
|
kind: "mutation",
|
|
60965
61113
|
auth: "protected"
|
|
60966
61114
|
}),
|
|
60967
61115
|
setChildLock: method(object({
|
|
60968
|
-
deviceId: DeviceIdSchema,
|
|
61116
|
+
deviceId: DeviceIdSchema$1,
|
|
60969
61117
|
on: boolean()
|
|
60970
61118
|
}), _void(), {
|
|
60971
61119
|
kind: "mutation",
|
|
@@ -60977,7 +61125,7 @@ var dishwasherCapability = {
|
|
|
60977
61125
|
* its declared range / members.
|
|
60978
61126
|
*/
|
|
60979
61127
|
setOption: method(object({
|
|
60980
|
-
deviceId: DeviceIdSchema,
|
|
61128
|
+
deviceId: DeviceIdSchema$1,
|
|
60981
61129
|
key: string().min(1),
|
|
60982
61130
|
value: DishwasherValueSchema
|
|
60983
61131
|
}), _void(), {
|
|
@@ -60985,7 +61133,7 @@ var dishwasherCapability = {
|
|
|
60985
61133
|
auth: "protected"
|
|
60986
61134
|
}),
|
|
60987
61135
|
/** What this appliance can do, from its own description — the UI is derived from it. */
|
|
60988
|
-
getOptions: method(object({ deviceId: DeviceIdSchema }), DishwasherOptionsSchema, { auth: "protected" })
|
|
61136
|
+
getOptions: method(object({ deviceId: DeviceIdSchema$1 }), DishwasherOptionsSchema, { auth: "protected" })
|
|
60989
61137
|
},
|
|
60990
61138
|
status: {
|
|
60991
61139
|
schema: DishwasherStatusSchema,
|
|
@@ -64676,7 +64824,8 @@ var TopologyNodeSchema = object({
|
|
|
64676
64824
|
isHub: boolean(),
|
|
64677
64825
|
isOnline: boolean(),
|
|
64678
64826
|
cpuPercent: number(),
|
|
64679
|
-
|
|
64827
|
+
/** `null` when the node's memory read failed or it has not reported one (D393). */
|
|
64828
|
+
memoryPercent: number().nullable(),
|
|
64680
64829
|
uptime: number(),
|
|
64681
64830
|
lastSeen: string(),
|
|
64682
64831
|
localIps: array(string()).readonly(),
|
|
@@ -65294,9 +65443,10 @@ var PetFeederStatusSchema = object({
|
|
|
65294
65443
|
* combined reading; per-hopper levels live in `food1`/`food2`. Null when
|
|
65295
65444
|
* the device has not reported yet. */
|
|
65296
65445
|
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
65297
|
-
/** Food in the BOWL
|
|
65298
|
-
* feeder
|
|
65299
|
-
|
|
65446
|
+
/** Food in the BOWL, a mass (stored in kilograms, D944). Reported only by a
|
|
65447
|
+
* feeder with a bowl scale; null when the model has none or its reading is
|
|
65448
|
+
* of an unproven unit. */
|
|
65449
|
+
bowlFood: number().nullable().meta(readingMeta("mass")),
|
|
65300
65450
|
/** True while the pet is eating (`state.eating`). */
|
|
65301
65451
|
eating: boolean(),
|
|
65302
65452
|
/** Whether `markFoodReplenished` does anything on this model. When false
|
|
@@ -65480,6 +65630,137 @@ var petFeederCapability = {
|
|
|
65480
65630
|
}
|
|
65481
65631
|
} }
|
|
65482
65632
|
};
|
|
65633
|
+
/**
|
|
65634
|
+
* Pet water-fountain cap. Models the telemetry and the control surface of a
|
|
65635
|
+
* circulating drinking fountain: how much water is in the tank, how much the
|
|
65636
|
+
* pet drank, whether the pump runs and on what duty cycle.
|
|
65637
|
+
*
|
|
65638
|
+
* It has no native vendor provider of its own: a fountain reaches CamStack as
|
|
65639
|
+
* a container of loose entities (a pump switch, two number boxes, a "filter
|
|
65640
|
+
* changed" button), and an operator BUILDS the device from them — a composed
|
|
65641
|
+
* device of this type (D659, D967). Every method is therefore a forward to ONE
|
|
65642
|
+
* method of ONE source entity, and every reading is a field derived from a
|
|
65643
|
+
* source entity; the provider-shaped interface below exists so the composed
|
|
65644
|
+
* device and any future native provider answer the same contract.
|
|
65645
|
+
*
|
|
65646
|
+
* Quantities are stored in the base unit of their kind (D944): volumes in
|
|
65647
|
+
* LITRES, durations in SECONDS, the tank level in percent. A source that
|
|
65648
|
+
* reports millilitres or minutes is converted in the composition's expression,
|
|
65649
|
+
* never here. Every reading may be `null`: a source that is offline or does
|
|
65650
|
+
* not report is unknown, never zero.
|
|
65651
|
+
*
|
|
65652
|
+
* The filter is not a field of this cap: it is an item of the `consumables`
|
|
65653
|
+
* cap on the same device (kind `wear`), reset by the same forward mechanism.
|
|
65654
|
+
*/
|
|
65655
|
+
var PetFountainStatusSchema = object({
|
|
65656
|
+
/** Water in the tank, 0..100 (%). Null while the source has not reported. */
|
|
65657
|
+
waterLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
65658
|
+
/** Water in the tank, in litres. Null while the source has not reported. */
|
|
65659
|
+
waterVolume: number().min(0).nullable().meta(readingMeta("volume")),
|
|
65660
|
+
/** True when the tank is empty. Null while unknown. */
|
|
65661
|
+
empty: boolean().nullable(),
|
|
65662
|
+
/** True while the pump is running. Null while unknown. */
|
|
65663
|
+
pumpRunning: boolean().nullable(),
|
|
65664
|
+
/** True when the pump works on an on/off duty cycle rather than continuously. */
|
|
65665
|
+
pumpIntervalEnabled: boolean().nullable(),
|
|
65666
|
+
/** How long the pump runs per cycle, in seconds. */
|
|
65667
|
+
pumpOnTime: number().min(0).nullable().meta(readingMeta("duration")),
|
|
65668
|
+
/** How long the pump rests per cycle, in seconds. */
|
|
65669
|
+
pumpOffTime: number().min(0).nullable().meta(readingMeta("duration")),
|
|
65670
|
+
/** Water drunk in the last drink, in litres. */
|
|
65671
|
+
lastDrink: number().min(0).nullable().meta(readingMeta("volume")),
|
|
65672
|
+
/** Water drunk in the current hour, in litres. */
|
|
65673
|
+
currentHourDrink: number().min(0).nullable().meta(readingMeta("volume")),
|
|
65674
|
+
/** Water drunk over the last 24 hours (rolling), in litres. */
|
|
65675
|
+
last24hDrink: number().min(0).nullable().meta(readingMeta("volume")),
|
|
65676
|
+
/** Water drunk since local midnight, in litres. */
|
|
65677
|
+
todayDrink: number().min(0).nullable().meta(readingMeta("volume")),
|
|
65678
|
+
/** Decoded fault message. Null means healthy; a non-null string is an active fault. */
|
|
65679
|
+
error: string().nullable(),
|
|
65680
|
+
/** Ms epoch when the slice was last refreshed. */
|
|
65681
|
+
lastFetchedAt: number()
|
|
65682
|
+
});
|
|
65683
|
+
var DeviceIdSchema = number().int().nonnegative();
|
|
65684
|
+
var MinutesSchema = number().int().min(0);
|
|
65685
|
+
var petFountainCapability = {
|
|
65686
|
+
name: "pet-fountain",
|
|
65687
|
+
scope: "device",
|
|
65688
|
+
deviceNative: true,
|
|
65689
|
+
mode: "singleton",
|
|
65690
|
+
deviceTypes: [DeviceType.PetFountain],
|
|
65691
|
+
methods: {
|
|
65692
|
+
/** Start or stop the pump. */
|
|
65693
|
+
setPump: method(object({
|
|
65694
|
+
deviceId: DeviceIdSchema,
|
|
65695
|
+
on: boolean()
|
|
65696
|
+
}), _void(), {
|
|
65697
|
+
kind: "mutation",
|
|
65698
|
+
auth: "protected"
|
|
65699
|
+
}),
|
|
65700
|
+
/** Switch the on/off duty cycle on or off (off = the pump runs continuously). */
|
|
65701
|
+
setPumpInterval: method(object({
|
|
65702
|
+
deviceId: DeviceIdSchema,
|
|
65703
|
+
on: boolean()
|
|
65704
|
+
}), _void(), {
|
|
65705
|
+
kind: "mutation",
|
|
65706
|
+
auth: "protected"
|
|
65707
|
+
}),
|
|
65708
|
+
/** Set how many minutes the pump runs per cycle. */
|
|
65709
|
+
setPumpOnMinutes: method(object({
|
|
65710
|
+
deviceId: DeviceIdSchema,
|
|
65711
|
+
minutes: MinutesSchema
|
|
65712
|
+
}), _void(), {
|
|
65713
|
+
kind: "mutation",
|
|
65714
|
+
auth: "protected"
|
|
65715
|
+
}),
|
|
65716
|
+
/** Set how many minutes the pump rests per cycle. */
|
|
65717
|
+
setPumpOffMinutes: method(object({
|
|
65718
|
+
deviceId: DeviceIdSchema,
|
|
65719
|
+
minutes: MinutesSchema
|
|
65720
|
+
}), _void(), {
|
|
65721
|
+
kind: "mutation",
|
|
65722
|
+
auth: "protected"
|
|
65723
|
+
}),
|
|
65724
|
+
/** Clear the rolling daily consumption counters on the device. */
|
|
65725
|
+
resetDailyConsumption: method(object({ deviceId: DeviceIdSchema }), _void(), {
|
|
65726
|
+
kind: "mutation",
|
|
65727
|
+
auth: "protected"
|
|
65728
|
+
})
|
|
65729
|
+
},
|
|
65730
|
+
status: {
|
|
65731
|
+
schema: PetFountainStatusSchema,
|
|
65732
|
+
kind: "push"
|
|
65733
|
+
},
|
|
65734
|
+
/** Runtime-state slice — mirrored by the kernel; the hero card reads it whole. */
|
|
65735
|
+
runtimeState: PetFountainStatusSchema,
|
|
65736
|
+
/**
|
|
65737
|
+
* Runtime-state durability: **session** — live appliance state re-published on connect.
|
|
65738
|
+
*
|
|
65739
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
65740
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
65741
|
+
*/
|
|
65742
|
+
durability: "session",
|
|
65743
|
+
/** History (D850): recorded series. */
|
|
65744
|
+
history: { fields: {
|
|
65745
|
+
waterLevel: {
|
|
65746
|
+
kind: "gauge",
|
|
65747
|
+
unit: "%",
|
|
65748
|
+
deadband: 1
|
|
65749
|
+
},
|
|
65750
|
+
waterVolume: {
|
|
65751
|
+
kind: "gauge",
|
|
65752
|
+
unit: "L"
|
|
65753
|
+
},
|
|
65754
|
+
todayDrink: {
|
|
65755
|
+
kind: "gauge",
|
|
65756
|
+
unit: "L"
|
|
65757
|
+
},
|
|
65758
|
+
last24hDrink: {
|
|
65759
|
+
kind: "gauge",
|
|
65760
|
+
unit: "L"
|
|
65761
|
+
}
|
|
65762
|
+
} }
|
|
65763
|
+
};
|
|
65483
65764
|
var VehicleSchema = object({
|
|
65484
65765
|
id: string(),
|
|
65485
65766
|
name: string(),
|
|
@@ -71402,7 +71683,7 @@ discriminatedUnion("kind", [object({
|
|
|
71402
71683
|
})]);
|
|
71403
71684
|
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
71404
71685
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
71405
|
-
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;
|
|
71686
|
+
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;
|
|
71406
71687
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
71407
71688
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
71408
71689
|
new Set(CAP_NAMES);
|
|
@@ -71753,6 +72034,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
71753
72034
|
notifier: notifierCapability,
|
|
71754
72035
|
numericSensor: numericSensorCapability,
|
|
71755
72036
|
petFeeder: petFeederCapability,
|
|
72037
|
+
petFountain: petFountainCapability,
|
|
71756
72038
|
powerMeter: powerMeterCapability,
|
|
71757
72039
|
presence: presenceCapability,
|
|
71758
72040
|
pressureSensor: pressureSensorCapability,
|
|
@@ -73003,7 +73285,7 @@ var BaseDeviceProvider = class extends BaseAddon {
|
|
|
73003
73285
|
return toDeviceSummary(device, this.addonId);
|
|
73004
73286
|
}
|
|
73005
73287
|
};
|
|
73006
|
-
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;
|
|
73288
|
+
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;
|
|
73007
73289
|
new Set(Object.values(DeviceType));
|
|
73008
73290
|
Object.freeze({
|
|
73009
73291
|
"accessories.getStatus": {
|
|
@@ -74938,6 +75220,13 @@ Object.freeze({
|
|
|
74938
75220
|
access: "create",
|
|
74939
75221
|
role: "admin"
|
|
74940
75222
|
},
|
|
75223
|
+
"deviceExport.exposeEntity": {
|
|
75224
|
+
capName: "device-export",
|
|
75225
|
+
capScope: "system",
|
|
75226
|
+
addonId: null,
|
|
75227
|
+
access: "create",
|
|
75228
|
+
role: "admin"
|
|
75229
|
+
},
|
|
74941
75230
|
"deviceExport.getDeviceLiveContribution": {
|
|
74942
75231
|
capName: "device-export",
|
|
74943
75232
|
capScope: "system",
|
|
@@ -74966,6 +75255,13 @@ Object.freeze({
|
|
|
74966
75255
|
access: "view",
|
|
74967
75256
|
role: "admin"
|
|
74968
75257
|
},
|
|
75258
|
+
"deviceExport.listExposedEntities": {
|
|
75259
|
+
capName: "device-export",
|
|
75260
|
+
capScope: "system",
|
|
75261
|
+
addonId: null,
|
|
75262
|
+
access: "view",
|
|
75263
|
+
role: "admin"
|
|
75264
|
+
},
|
|
74969
75265
|
"deviceExport.listSupportedDeviceKinds": {
|
|
74970
75266
|
capName: "device-export",
|
|
74971
75267
|
capScope: "system",
|
|
@@ -74973,6 +75269,13 @@ Object.freeze({
|
|
|
74973
75269
|
access: "view",
|
|
74974
75270
|
role: "admin"
|
|
74975
75271
|
},
|
|
75272
|
+
"deviceExport.listSupportedEntityKinds": {
|
|
75273
|
+
capName: "device-export",
|
|
75274
|
+
capScope: "system",
|
|
75275
|
+
addonId: null,
|
|
75276
|
+
access: "view",
|
|
75277
|
+
role: "admin"
|
|
75278
|
+
},
|
|
74976
75279
|
"deviceExport.unexposeDevice": {
|
|
74977
75280
|
capName: "device-export",
|
|
74978
75281
|
capScope: "system",
|
|
@@ -74980,6 +75283,13 @@ Object.freeze({
|
|
|
74980
75283
|
access: "create",
|
|
74981
75284
|
role: "admin"
|
|
74982
75285
|
},
|
|
75286
|
+
"deviceExport.unexposeEntity": {
|
|
75287
|
+
capName: "device-export",
|
|
75288
|
+
capScope: "system",
|
|
75289
|
+
addonId: null,
|
|
75290
|
+
access: "create",
|
|
75291
|
+
role: "admin"
|
|
75292
|
+
},
|
|
74983
75293
|
"deviceExtension.listCandidates": {
|
|
74984
75294
|
capName: "device-extension",
|
|
74985
75295
|
capScope: "device",
|
|
@@ -78445,6 +78755,48 @@ Object.freeze({
|
|
|
78445
78755
|
access: "create",
|
|
78446
78756
|
role: "viewer"
|
|
78447
78757
|
},
|
|
78758
|
+
"petFountain.getStatus": {
|
|
78759
|
+
capName: "pet-fountain",
|
|
78760
|
+
capScope: "device",
|
|
78761
|
+
addonId: null,
|
|
78762
|
+
access: "view",
|
|
78763
|
+
role: "viewer"
|
|
78764
|
+
},
|
|
78765
|
+
"petFountain.resetDailyConsumption": {
|
|
78766
|
+
capName: "pet-fountain",
|
|
78767
|
+
capScope: "device",
|
|
78768
|
+
addonId: null,
|
|
78769
|
+
access: "delete",
|
|
78770
|
+
role: "viewer"
|
|
78771
|
+
},
|
|
78772
|
+
"petFountain.setPump": {
|
|
78773
|
+
capName: "pet-fountain",
|
|
78774
|
+
capScope: "device",
|
|
78775
|
+
addonId: null,
|
|
78776
|
+
access: "create",
|
|
78777
|
+
role: "viewer"
|
|
78778
|
+
},
|
|
78779
|
+
"petFountain.setPumpInterval": {
|
|
78780
|
+
capName: "pet-fountain",
|
|
78781
|
+
capScope: "device",
|
|
78782
|
+
addonId: null,
|
|
78783
|
+
access: "create",
|
|
78784
|
+
role: "viewer"
|
|
78785
|
+
},
|
|
78786
|
+
"petFountain.setPumpOffMinutes": {
|
|
78787
|
+
capName: "pet-fountain",
|
|
78788
|
+
capScope: "device",
|
|
78789
|
+
addonId: null,
|
|
78790
|
+
access: "create",
|
|
78791
|
+
role: "viewer"
|
|
78792
|
+
},
|
|
78793
|
+
"petFountain.setPumpOnMinutes": {
|
|
78794
|
+
capName: "pet-fountain",
|
|
78795
|
+
capScope: "device",
|
|
78796
|
+
addonId: null,
|
|
78797
|
+
access: "create",
|
|
78798
|
+
role: "viewer"
|
|
78799
|
+
},
|
|
78448
78800
|
"pipelineAnalytics.addRetrainFrameFromRecording": {
|
|
78449
78801
|
capName: "pipeline-analytics",
|
|
78450
78802
|
capScope: "device",
|
|
@@ -80846,6 +81198,13 @@ Object.freeze({
|
|
|
80846
81198
|
access: "create",
|
|
80847
81199
|
role: "admin"
|
|
80848
81200
|
},
|
|
81201
|
+
"serverManagement.getLaunchOverrides": {
|
|
81202
|
+
capName: "server-management",
|
|
81203
|
+
capScope: "system",
|
|
81204
|
+
addonId: null,
|
|
81205
|
+
access: "view",
|
|
81206
|
+
role: "admin"
|
|
81207
|
+
},
|
|
80849
81208
|
"serverManagement.getServerPackageStatus": {
|
|
80850
81209
|
capName: "server-management",
|
|
80851
81210
|
capScope: "system",
|
|
@@ -80867,6 +81226,13 @@ Object.freeze({
|
|
|
80867
81226
|
access: "create",
|
|
80868
81227
|
role: "admin"
|
|
80869
81228
|
},
|
|
81229
|
+
"serverManagement.setLaunchOverrides": {
|
|
81230
|
+
capName: "server-management",
|
|
81231
|
+
capScope: "system",
|
|
81232
|
+
addonId: null,
|
|
81233
|
+
access: "create",
|
|
81234
|
+
role: "admin"
|
|
81235
|
+
},
|
|
80870
81236
|
"settingsStore.aggregate": {
|
|
80871
81237
|
capName: "settings-store",
|
|
80872
81238
|
capScope: "system",
|
|
@@ -84927,6 +85293,100 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
84927
85293
|
}
|
|
84928
85294
|
]
|
|
84929
85295
|
},
|
|
85296
|
+
"pet-fountain": {
|
|
85297
|
+
scope: "device",
|
|
85298
|
+
noun: t("Pet fountain", "Fontana per animali"),
|
|
85299
|
+
actions: [
|
|
85300
|
+
{
|
|
85301
|
+
id: "petFountain.pumpOn",
|
|
85302
|
+
method: "setPump",
|
|
85303
|
+
label: t("Pump on", "Pompa accesa"),
|
|
85304
|
+
phrase: t("Start the pump of {device}", "Avvia la pompa di {device}"),
|
|
85305
|
+
icon: "play",
|
|
85306
|
+
args: { on: true }
|
|
85307
|
+
},
|
|
85308
|
+
{
|
|
85309
|
+
id: "petFountain.pumpOff",
|
|
85310
|
+
method: "setPump",
|
|
85311
|
+
label: t("Pump off", "Pompa spenta"),
|
|
85312
|
+
phrase: t("Stop the pump of {device}", "Ferma la pompa di {device}"),
|
|
85313
|
+
icon: "square",
|
|
85314
|
+
args: { on: false }
|
|
85315
|
+
},
|
|
85316
|
+
{
|
|
85317
|
+
id: "petFountain.intervalOn",
|
|
85318
|
+
method: "setPumpInterval",
|
|
85319
|
+
label: t("Pump cycle on", "Ciclo pompa attivo"),
|
|
85320
|
+
phrase: t("Run the pump of {device} on its on/off cycle", "Fai lavorare la pompa di {device} a ciclo acceso/spento"),
|
|
85321
|
+
icon: "timer",
|
|
85322
|
+
args: { on: true }
|
|
85323
|
+
},
|
|
85324
|
+
{
|
|
85325
|
+
id: "petFountain.intervalOff",
|
|
85326
|
+
method: "setPumpInterval",
|
|
85327
|
+
label: t("Pump cycle off", "Ciclo pompa spento"),
|
|
85328
|
+
phrase: t("Run the pump of {device} continuously", "Fai lavorare la pompa di {device} in continuo"),
|
|
85329
|
+
icon: "timer-off",
|
|
85330
|
+
args: { on: false }
|
|
85331
|
+
},
|
|
85332
|
+
{
|
|
85333
|
+
id: "petFountain.pumpOnMinutes",
|
|
85334
|
+
method: "setPumpOnMinutes",
|
|
85335
|
+
label: t("Set pump run time", "Imposta il tempo di lavoro della pompa"),
|
|
85336
|
+
phrase: t("Set the pump of {device} to run {minutes} minutes per cycle", "Imposta la pompa di {device} a lavorare {minutes} minuti per ciclo"),
|
|
85337
|
+
icon: "timer",
|
|
85338
|
+
openArgs: [{
|
|
85339
|
+
key: "minutes",
|
|
85340
|
+
label: t("Minutes", "Minuti"),
|
|
85341
|
+
offer: {
|
|
85342
|
+
kind: "number",
|
|
85343
|
+
min: 0,
|
|
85344
|
+
step: 1,
|
|
85345
|
+
unit: "min"
|
|
85346
|
+
}
|
|
85347
|
+
}]
|
|
85348
|
+
},
|
|
85349
|
+
{
|
|
85350
|
+
id: "petFountain.pumpOffMinutes",
|
|
85351
|
+
method: "setPumpOffMinutes",
|
|
85352
|
+
label: t("Set pump rest time", "Imposta il tempo di riposo della pompa"),
|
|
85353
|
+
phrase: t("Set the pump of {device} to rest {minutes} minutes per cycle", "Imposta la pompa di {device} a riposare {minutes} minuti per ciclo"),
|
|
85354
|
+
icon: "timer-off",
|
|
85355
|
+
openArgs: [{
|
|
85356
|
+
key: "minutes",
|
|
85357
|
+
label: t("Minutes", "Minuti"),
|
|
85358
|
+
offer: {
|
|
85359
|
+
kind: "number",
|
|
85360
|
+
min: 0,
|
|
85361
|
+
step: 1,
|
|
85362
|
+
unit: "min"
|
|
85363
|
+
}
|
|
85364
|
+
}]
|
|
85365
|
+
},
|
|
85366
|
+
{
|
|
85367
|
+
id: "petFountain.resetDailyConsumption",
|
|
85368
|
+
method: "resetDailyConsumption",
|
|
85369
|
+
label: t("Clear daily consumption", "Azzera il consumo giornaliero"),
|
|
85370
|
+
phrase: t("Clear the daily water consumption of {device}", "Azzera il consumo giornaliero di acqua di {device}"),
|
|
85371
|
+
icon: "rotate-ccw"
|
|
85372
|
+
}
|
|
85373
|
+
],
|
|
85374
|
+
state: [{
|
|
85375
|
+
kind: "boolean",
|
|
85376
|
+
field: "empty",
|
|
85377
|
+
label: t("Tank empty", "Serbatoio vuoto"),
|
|
85378
|
+
whenTrue: t("When the tank of {device} is empty", "Quando il serbatoio di {device} è vuoto"),
|
|
85379
|
+
whenFalse: t("When the tank of {device} is refilled", "Quando il serbatoio di {device} viene riempito"),
|
|
85380
|
+
icon: "droplet"
|
|
85381
|
+
}, {
|
|
85382
|
+
kind: "numeric",
|
|
85383
|
+
field: "waterLevel",
|
|
85384
|
+
quantity: t("the water level", "il livello dell’acqua"),
|
|
85385
|
+
label: t("Water level", "Livello dell’acqua"),
|
|
85386
|
+
unit: "%",
|
|
85387
|
+
icon: "droplets"
|
|
85388
|
+
}]
|
|
85389
|
+
},
|
|
84930
85390
|
"media-player": {
|
|
84931
85391
|
scope: "device",
|
|
84932
85392
|
noun: t("Media player", "Lettore multimediale"),
|
|
@@ -86864,7 +87324,7 @@ function projectAction(cap, action) {
|
|
|
86864
87324
|
};
|
|
86865
87325
|
}
|
|
86866
87326
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
86867
|
-
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;
|
|
87327
|
+
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;
|
|
86868
87328
|
DeviceFeature.BatteryOperated;
|
|
86869
87329
|
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
86870
87330
|
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.";
|
|
@@ -88415,6 +88875,36 @@ Object.freeze({
|
|
|
88415
88875
|
form: "single",
|
|
88416
88876
|
optional: false
|
|
88417
88877
|
}],
|
|
88878
|
+
"petFountain.getStatus": [{
|
|
88879
|
+
name: "deviceId",
|
|
88880
|
+
form: "single",
|
|
88881
|
+
optional: false
|
|
88882
|
+
}],
|
|
88883
|
+
"petFountain.resetDailyConsumption": [{
|
|
88884
|
+
name: "deviceId",
|
|
88885
|
+
form: "single",
|
|
88886
|
+
optional: false
|
|
88887
|
+
}],
|
|
88888
|
+
"petFountain.setPump": [{
|
|
88889
|
+
name: "deviceId",
|
|
88890
|
+
form: "single",
|
|
88891
|
+
optional: false
|
|
88892
|
+
}],
|
|
88893
|
+
"petFountain.setPumpInterval": [{
|
|
88894
|
+
name: "deviceId",
|
|
88895
|
+
form: "single",
|
|
88896
|
+
optional: false
|
|
88897
|
+
}],
|
|
88898
|
+
"petFountain.setPumpOffMinutes": [{
|
|
88899
|
+
name: "deviceId",
|
|
88900
|
+
form: "single",
|
|
88901
|
+
optional: false
|
|
88902
|
+
}],
|
|
88903
|
+
"petFountain.setPumpOnMinutes": [{
|
|
88904
|
+
name: "deviceId",
|
|
88905
|
+
form: "single",
|
|
88906
|
+
optional: false
|
|
88907
|
+
}],
|
|
88418
88908
|
"pipelineAnalytics.addRetrainFrameFromRecording": [{
|
|
88419
88909
|
name: "deviceId",
|
|
88420
88910
|
form: "single",
|
|
@@ -133568,6 +134058,38 @@ function alexaRegionOptions(amazonDomain) {
|
|
|
133568
134058
|
};
|
|
133569
134059
|
}
|
|
133570
134060
|
//#endregion
|
|
134061
|
+
//#region src/alexa-url-params.ts
|
|
134062
|
+
var BASE = "http://placeholder.invalid";
|
|
134063
|
+
function describeUrlParams(url) {
|
|
134064
|
+
let parsed;
|
|
134065
|
+
try {
|
|
134066
|
+
parsed = new URL(url, BASE);
|
|
134067
|
+
} catch {
|
|
134068
|
+
return {
|
|
134069
|
+
path: "",
|
|
134070
|
+
names: [],
|
|
134071
|
+
oa2: false,
|
|
134072
|
+
returnTo: false,
|
|
134073
|
+
assocHandle: false,
|
|
134074
|
+
mode: false
|
|
134075
|
+
};
|
|
134076
|
+
}
|
|
134077
|
+
const names = [...new Set(parsed.searchParams.keys())].sort();
|
|
134078
|
+
return {
|
|
134079
|
+
path: parsed.pathname,
|
|
134080
|
+
names,
|
|
134081
|
+
oa2: names.some((n) => n.startsWith("openid.oa2.")),
|
|
134082
|
+
returnTo: names.includes("openid.return_to"),
|
|
134083
|
+
assocHandle: names.includes("openid.assoc_handle"),
|
|
134084
|
+
mode: names.includes("openid.mode")
|
|
134085
|
+
};
|
|
134086
|
+
}
|
|
134087
|
+
/** One-line, value-free rendering of {@link describeUrlParams}. */
|
|
134088
|
+
function formatUrlParams(url) {
|
|
134089
|
+
const d = describeUrlParams(url);
|
|
134090
|
+
return `names=[${d.names.join(",")}] oa2=${d.oa2} return_to=${d.returnTo} assoc_handle=${d.assocHandle} mode=${d.mode}`;
|
|
134091
|
+
}
|
|
134092
|
+
//#endregion
|
|
133571
134093
|
//#region src/alexa-proxy-trace.ts
|
|
133572
134094
|
/**
|
|
133573
134095
|
* Sanitised one-line trace of the alexa-cookie2 proxy's own log lines.
|
|
@@ -133588,17 +134110,21 @@ function stripQuery(target) {
|
|
|
133588
134110
|
const cut = target.search(/[?#]/);
|
|
133589
134111
|
return cut === -1 ? target : target.slice(0, cut);
|
|
133590
134112
|
}
|
|
134113
|
+
/** The target without its query, plus the value-free parameter summary. */
|
|
134114
|
+
function withParams(target) {
|
|
134115
|
+
return `${stripQuery(target)} ${formatUrlParams(target)}`;
|
|
134116
|
+
}
|
|
133591
134117
|
function sanitizeProxyTraceLine(line) {
|
|
133592
134118
|
const router = ROUTER_RE.exec(line);
|
|
133593
|
-
if (router !== null) return `router ${router[2]} ${
|
|
134119
|
+
if (router !== null) return `router ${router[2]} ${withParams(router[1] ?? "")}`;
|
|
133594
134120
|
const request = PROXY_REQUEST_RE.exec(line);
|
|
133595
|
-
if (request !== null) return `proxy-request ${request[1]} ${
|
|
134121
|
+
if (request !== null) return `proxy-request ${request[1]} ${withParams(request[2] ?? "")}`;
|
|
133596
134122
|
const response = PROXY_RESPONSE_RE.exec(line);
|
|
133597
134123
|
if (response !== null) return `proxy-response host=${response[1]}`;
|
|
133598
134124
|
const original = REDIRECT_ORIGINAL_RE.exec(line);
|
|
133599
|
-
if (original !== null) return `redirect-original ${
|
|
134125
|
+
if (original !== null) return `redirect-original ${withParams(original[1] ?? "")}`;
|
|
133600
134126
|
const final = REDIRECT_FINAL_RE.exec(line);
|
|
133601
|
-
if (final !== null) return `redirect-final ${
|
|
134127
|
+
if (final !== null) return `redirect-final ${withParams(final[1] ?? "")}`;
|
|
133602
134128
|
return null;
|
|
133603
134129
|
}
|
|
133604
134130
|
//#endregion
|
|
@@ -133714,7 +134240,7 @@ var AlexaProxyLoginSession = class {
|
|
|
133714
134240
|
const line = args.map(String).join(" ");
|
|
133715
134241
|
const trace = sanitizeProxyTraceLine(line);
|
|
133716
134242
|
if (trace !== null) {
|
|
133717
|
-
this.#logger.info(`alexa
|
|
134243
|
+
this.#logger.info(`[alexa-login-trace] ${trace}`, { meta: { sessionId: this.#opts.sessionId } });
|
|
133718
134244
|
return;
|
|
133719
134245
|
}
|
|
133720
134246
|
if (SECRET_LINE_RE.test(line)) return;
|
|
@@ -133892,6 +134418,13 @@ var AlexaProxyLoginManager = class {
|
|
|
133892
134418
|
this.#getLoginProxy = deps.getLoginProxy;
|
|
133893
134419
|
this.#captureWaitMs = deps.captureWaitMs ?? CAPTURE_WAIT_MS;
|
|
133894
134420
|
}
|
|
134421
|
+
/** One value-free line per upstream hop the hub login proxy sees (names only). */
|
|
134422
|
+
#traceHop(sessionId, view) {
|
|
134423
|
+
const url = describeUrlParams(view.url);
|
|
134424
|
+
const landing = url.path.endsWith("/ap/maplanding") ? " maplanding" : "";
|
|
134425
|
+
const location = view.location === null ? "none" : `${describeUrlParams(view.location).path} ${formatUrlParams(view.location)}`;
|
|
134426
|
+
this.#logger.info(`[alexa-login-trace] hub-hop${landing} status=${view.status} url=${url.path} ${formatUrlParams(view.url)} location=${location}`, { meta: { sessionId } });
|
|
134427
|
+
}
|
|
133895
134428
|
/**
|
|
133896
134429
|
* Start a fresh proxy-login. Cancels any in-flight session first (single
|
|
133897
134430
|
* fixed port). Returns the `loginUrl` for the onboarding UI to open.
|
|
@@ -133910,7 +134443,10 @@ var AlexaProxyLoginManager = class {
|
|
|
133910
134443
|
host: upstreamHost,
|
|
133911
134444
|
scheme: "http"
|
|
133912
134445
|
}],
|
|
133913
|
-
terminal:
|
|
134446
|
+
terminal: (view) => {
|
|
134447
|
+
this.#traceHop(sessionId, view);
|
|
134448
|
+
return cookieSuccessTerminal(view);
|
|
134449
|
+
},
|
|
133914
134450
|
onDone: async (end) => {
|
|
133915
134451
|
if (end === "no_authorization_code") {
|
|
133916
134452
|
this.#logger.warn("alexa proxy-login: Amazon ended the login without an authorization code", { meta: { sessionId } });
|