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