@camstack/types 1.2.50 → 1.2.52
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/dist/addon.js +1 -1
- package/dist/addon.mjs +1 -1
- package/dist/automation/codegen.d.ts +39 -0
- package/dist/automation/index.d.ts +14 -0
- package/dist/automation/recipe.d.ts +194 -0
- package/dist/capabilities/core-blocks.cap.d.ts +17 -0
- package/dist/capabilities/index.d.ts +1 -1
- package/dist/capabilities/mqtt-broker.cap.d.ts +1 -1
- package/dist/capabilities/pipeline-analytics.cap.d.ts +6 -0
- package/dist/capabilities/snapshot.cap.d.ts +56 -0
- package/dist/device/declared-device.d.ts +22 -1
- package/dist/generated/addon-api.d.ts +7 -0
- package/dist/generated/method-access-map.d.ts +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +8493 -7756
- package/dist/index.mjs +8482 -7757
- package/dist/node.d.ts +2 -0
- package/dist/node.js +57 -0
- package/dist/node.mjs +57 -2
- package/dist/{sleep-7WqNZVcL.mjs → sleep-CT4lN1ij.mjs} +1 -0
- package/dist/{sleep-ocMLM2o5.js → sleep-DfF6vKCf.js} +1 -0
- package/dist/utils/expiring-url-signature.d.ts +27 -0
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_event_category = require("./event-category-BE4PDZ_3.js");
|
|
3
|
-
const require_sleep = require("./sleep-
|
|
3
|
+
const require_sleep = require("./sleep-DfF6vKCf.js");
|
|
4
4
|
const require_err_msg = require("./err-msg-COpsHMw2.js");
|
|
5
5
|
//#region src/generated/collection-array-methods.ts
|
|
6
6
|
/**
|
package/dist/addon.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as EventCategory } from "./event-category-41fKf-q9.mjs";
|
|
2
|
-
import { C as DeviceType, F as readNodePin, L as ReadinessRegistry, O as expandCapMethods, P as nodePin, R as ReadinessTimeoutError, V as scopeKey, a as asJsonObject, d as DEVICE_SCOPED_CAPS, f as isDeviceScopedCap, gt as normalizeAddonInitResult, ht as BaseAddon, mt as DisposerChain, p as createDeviceProxy, pt as DATAPLANE_SECRET_HEADER, s as asString, t as sleep, u as parseJsonUnknown, v as deviceOpsCapability, w as adminUiCapability, y as viewerUiCapability, yt as emitReadiness } from "./sleep-
|
|
2
|
+
import { C as DeviceType, F as readNodePin, L as ReadinessRegistry, O as expandCapMethods, P as nodePin, R as ReadinessTimeoutError, V as scopeKey, a as asJsonObject, d as DEVICE_SCOPED_CAPS, f as isDeviceScopedCap, gt as normalizeAddonInitResult, ht as BaseAddon, mt as DisposerChain, p as createDeviceProxy, pt as DATAPLANE_SECRET_HEADER, s as asString, t as sleep, u as parseJsonUnknown, v as deviceOpsCapability, w as adminUiCapability, y as viewerUiCapability, yt as emitReadiness } from "./sleep-CT4lN1ij.mjs";
|
|
3
3
|
import { t as errMsg } from "./err-msg-IQTHeDzc.mjs";
|
|
4
4
|
//#region src/generated/collection-array-methods.ts
|
|
5
5
|
/**
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recipe → TypeScript. The half that makes "a visual automation compiles to a
|
|
3
|
+
* block; it does not get an engine" true rather than aspirational
|
|
4
|
+
* (design decision 4, `docs/design/2026-08-08-automation-scripts-custom-devices.md`).
|
|
5
|
+
*
|
|
6
|
+
* **The generated source is derived, never authoritative.** It is regenerated on
|
|
7
|
+
* every compile and shown read-only; the RECIPE is what the operator edited.
|
|
8
|
+
* That resolves the open question §8.2 left to this phase ("is the generated
|
|
9
|
+
* code stored for audit, or regenerated?"): storing it creates a second copy
|
|
10
|
+
* that can disagree with the recipe, and a second copy that can disagree is the
|
|
11
|
+
* failure this whole chapter exists to avoid.
|
|
12
|
+
*
|
|
13
|
+
* The recipe travels INSIDE the generated file as `AUTOMATION_RECIPE`, a frozen
|
|
14
|
+
* JSON literal. That is deliberate and it is not a second store: there is still
|
|
15
|
+
* exactly one row in `core_blocks`, and the recipe is part of the one artefact
|
|
16
|
+
* that row holds. It is what lets the editor re-open a visually-authored
|
|
17
|
+
* automation without `CoreBlock.source` having shipped yet — and when the
|
|
18
|
+
* `source` union does ship, this literal becomes redundant and is dropped in the
|
|
19
|
+
* same change that starts persisting the recipe properly.
|
|
20
|
+
*
|
|
21
|
+
* Nothing here evaluates anything. The generated code is compiled by esbuild
|
|
22
|
+
* inside the block pipeline exactly like hand-written code — no `eval`, no
|
|
23
|
+
* `new Function`, no `vm`, which `scripts/check-no-dynamic-eval.ts` enforces
|
|
24
|
+
* repo-wide.
|
|
25
|
+
*/
|
|
26
|
+
import type { AutomationRecipe } from './recipe.js';
|
|
27
|
+
export interface GenerateAutomationBlockInput {
|
|
28
|
+
/** The block's name — the ONE name for the artefact (§2.1). */
|
|
29
|
+
readonly name: string;
|
|
30
|
+
readonly recipe: AutomationRecipe;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Compile a recipe to the TypeScript of a core block.
|
|
34
|
+
*
|
|
35
|
+
* Throws when the recipe is out of bounds — generation is not the place to
|
|
36
|
+
* discover that, but it is the last place it can still be caught before code
|
|
37
|
+
* that the operator did not author starts running.
|
|
38
|
+
*/
|
|
39
|
+
export declare function generateAutomationBlock(input: GenerateAutomationBlockInput): string;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Automation recipes — the declarative half of a visually-authored automation,
|
|
3
|
+
* and the generator that turns one into the TypeScript of an ordinary core
|
|
4
|
+
* block. There is no engine here and there must never be one: the block runner
|
|
5
|
+
* is the runtime and `core_blocks` is the store.
|
|
6
|
+
*
|
|
7
|
+
* This is the module barrel; leaf files inside @camstack/types MUST import from
|
|
8
|
+
* the deep modules (e.g. `../automation/recipe.js`), never through this file OR
|
|
9
|
+
* the root barrel (see biome-plugins/no-types-barrel-leaf-import.grit).
|
|
10
|
+
*/
|
|
11
|
+
export type { GenerateAutomationBlockInput } from './codegen.js';
|
|
12
|
+
export { generateAutomationBlock } from './codegen.js';
|
|
13
|
+
export type { AutomationAction, AutomationCondition, AutomationConditionAll, AutomationConditionAny, AutomationConditionExpression, AutomationConditionLeaf, AutomationConditionNot, AutomationConditionOperator, AutomationRecipe, AutomationTrigger, } from './recipe.js';
|
|
14
|
+
export { AutomationActionSchema, AutomationConditionOperatorSchema, AutomationConditionSchema, AutomationRecipeSchema, AutomationTriggerSchema, conditionDepth, countConditionLeaves, MAX_CONDITION_DEPTH, MAX_CONDITION_LEAVES, validateRecipeBounds, } from './recipe.js';
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The automation RECIPE — what a visually-authored automation is, before it
|
|
3
|
+
* becomes code.
|
|
4
|
+
*
|
|
5
|
+
* This is the data half of `docs/design/2026-08-08-automation-scripts-custom-devices.md`
|
|
6
|
+
* Phase 6. A recipe is not an engine and never evaluates anything: it is a
|
|
7
|
+
* declarative description that {@link generateAutomationBlock} compiles to the
|
|
8
|
+
* TypeScript of an ordinary core block. There is therefore no second rule
|
|
9
|
+
* engine, no second store and no second runtime — the block runner is the
|
|
10
|
+
* runtime, `core_blocks` is the store (§2.1).
|
|
11
|
+
*
|
|
12
|
+
* Three vocabularies, each salvaged rather than invented:
|
|
13
|
+
*
|
|
14
|
+
* - **Triggers** — the only genuinely new surface. Four members, none of which
|
|
15
|
+
* touches notification delivery. The NC keeps its four *pipeline* triggers;
|
|
16
|
+
* these are device/time triggers and the two sets do not overlap.
|
|
17
|
+
* - **Conditions** — `ALL`/`ANY`/`NOT` over two leaf kinds, bounded. The
|
|
18
|
+
* expression leaf is the bounded engine at `../expression/`, which is where
|
|
19
|
+
* arithmetic between two device fields lives and the only place it lives.
|
|
20
|
+
* - **Actions** — `NcRuleActionSchema`'s two steps, plus the `{kind:'code'}`
|
|
21
|
+
* fragment of §3.2.2. See {@link AutomationActionSchema} for the ONE place
|
|
22
|
+
* this had to diverge from "verbatim", and why.
|
|
23
|
+
*
|
|
24
|
+
* Bounds are a guard, not a paragraph (§3.2.1): depth ≤ 3, ≤ 32 leaves. They are
|
|
25
|
+
* enforced by {@link validateRecipeBounds} AND by the schema, so a recipe that
|
|
26
|
+
* arrives over the wire cannot skip the check that the editor applies.
|
|
27
|
+
*/
|
|
28
|
+
import { z } from 'zod';
|
|
29
|
+
import { type ExpressionBindingSource } from '../expression/binding-source.js';
|
|
30
|
+
/**
|
|
31
|
+
* Depth of a condition tree, counting the root container as level 1.
|
|
32
|
+
*
|
|
33
|
+
* Three is enough and is not arbitrary: `NOT` over a group is always rewritable
|
|
34
|
+
* by De Morgan (`not(any(a,b))` ≡ `all(not a, not b)`), so the shapes that would
|
|
35
|
+
* need a fourth level have an equivalent at three. An editor that refuses depth
|
|
36
|
+
* 4 should offer that rewrite rather than refusing blankly.
|
|
37
|
+
*/
|
|
38
|
+
export declare const MAX_CONDITION_DEPTH = 3;
|
|
39
|
+
/** Leaves per automation. A UI that grows without a bound becomes a language. */
|
|
40
|
+
export declare const MAX_CONDITION_LEAVES = 32;
|
|
41
|
+
/** How a leaf compares a device field to a value. Derived from the field's
|
|
42
|
+
* `kind` in `deviceManager.getWireableFields`, never hand-maintained. */
|
|
43
|
+
export declare const AutomationConditionOperatorSchema: z.ZodEnum<{
|
|
44
|
+
in: "in";
|
|
45
|
+
gte: "gte";
|
|
46
|
+
eq: "eq";
|
|
47
|
+
ne: "ne";
|
|
48
|
+
gt: "gt";
|
|
49
|
+
lt: "lt";
|
|
50
|
+
lte: "lte";
|
|
51
|
+
contains: "contains";
|
|
52
|
+
}>;
|
|
53
|
+
export type AutomationConditionOperator = z.infer<typeof AutomationConditionOperatorSchema>;
|
|
54
|
+
/** A catalog leaf: one device field compared to one value. */
|
|
55
|
+
export interface AutomationConditionLeaf {
|
|
56
|
+
readonly kind: 'condition';
|
|
57
|
+
readonly deviceId: number;
|
|
58
|
+
readonly cap: string;
|
|
59
|
+
readonly fieldPath: string;
|
|
60
|
+
readonly operator: AutomationConditionOperator;
|
|
61
|
+
readonly value: string | number | boolean | readonly (string | number)[];
|
|
62
|
+
}
|
|
63
|
+
/** The escape hatch: the bounded expression engine over named device bindings. */
|
|
64
|
+
export interface AutomationConditionExpression {
|
|
65
|
+
readonly kind: 'expression';
|
|
66
|
+
readonly expr: string;
|
|
67
|
+
readonly bindings: Readonly<Record<string, ExpressionBindingSource>>;
|
|
68
|
+
}
|
|
69
|
+
export interface AutomationConditionAll {
|
|
70
|
+
readonly kind: 'all';
|
|
71
|
+
readonly children: readonly AutomationCondition[];
|
|
72
|
+
}
|
|
73
|
+
export interface AutomationConditionAny {
|
|
74
|
+
readonly kind: 'any';
|
|
75
|
+
readonly children: readonly AutomationCondition[];
|
|
76
|
+
}
|
|
77
|
+
export interface AutomationConditionNot {
|
|
78
|
+
readonly kind: 'not';
|
|
79
|
+
readonly child: AutomationCondition;
|
|
80
|
+
}
|
|
81
|
+
export type AutomationCondition = AutomationConditionAll | AutomationConditionAny | AutomationConditionNot | AutomationConditionLeaf | AutomationConditionExpression;
|
|
82
|
+
export declare const AutomationConditionSchema: z.ZodType<AutomationCondition>;
|
|
83
|
+
/**
|
|
84
|
+
* What starts a run.
|
|
85
|
+
*
|
|
86
|
+
* D8 compliance, and it is the reason `device-state` is not merely an event
|
|
87
|
+
* subscription: the trigger evaluates against the **state mirror**, which is
|
|
88
|
+
* reconciled, and an event only WAKES the evaluation. A dropped event therefore
|
|
89
|
+
* DELAYS a trigger; it does not lose it. `schedule` uses `croner` — the one
|
|
90
|
+
* already in the repo — because `setInterval(24h)` drifts and "at 23:30" does
|
|
91
|
+
* not.
|
|
92
|
+
*/
|
|
93
|
+
export declare const AutomationTriggerSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
94
|
+
kind: z.ZodLiteral<"device-state">;
|
|
95
|
+
deviceId: z.ZodNumber;
|
|
96
|
+
cap: z.ZodString;
|
|
97
|
+
fieldPath: z.ZodString;
|
|
98
|
+
becomes: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>;
|
|
99
|
+
edge: z.ZodOptional<z.ZodBoolean>;
|
|
100
|
+
forMs: z.ZodOptional<z.ZodNumber>;
|
|
101
|
+
debounceMs: z.ZodOptional<z.ZodNumber>;
|
|
102
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
103
|
+
kind: z.ZodLiteral<"device-event">;
|
|
104
|
+
category: z.ZodString;
|
|
105
|
+
deviceId: z.ZodOptional<z.ZodNumber>;
|
|
106
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
107
|
+
kind: z.ZodLiteral<"schedule">;
|
|
108
|
+
cron: z.ZodString;
|
|
109
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
110
|
+
kind: z.ZodLiteral<"manual">;
|
|
111
|
+
}, z.core.$strip>], "kind">;
|
|
112
|
+
export type AutomationTrigger = z.infer<typeof AutomationTriggerSchema>;
|
|
113
|
+
/**
|
|
114
|
+
* One action step.
|
|
115
|
+
*
|
|
116
|
+
* `wait` and `cap` are `NcRuleActionSchema`'s two members, kept structurally
|
|
117
|
+
* identical so `NcRuleActionRunner` runs them unchanged — its device-scope
|
|
118
|
+
* check, stop-at-first-failure and per-sequence throttle are the whole reason
|
|
119
|
+
* to reuse it, and none of them are re-implemented here.
|
|
120
|
+
*
|
|
121
|
+
* **The one divergence, and it is forced.** `NcRuleActionSchema.cap.deviceId` is
|
|
122
|
+
* a literal `z.number().int()`, and the NC runner's own `RunSequencesInput`
|
|
123
|
+
* documents its subject device as *"for the log tag, never for routing"*. So an
|
|
124
|
+
* NC action can never target the device that triggered it — which is fine for
|
|
125
|
+
* the NC (its rules already scope to a device) and fatal for an automation
|
|
126
|
+
* ("sound the siren of the camera that saw the person"). `deviceId` therefore
|
|
127
|
+
* also accepts `{ $var }`, resolved from the run's `vars` bag BEFORE the runner
|
|
128
|
+
* is called. The runner still receives a number and is untouched; the
|
|
129
|
+
* resolution is the recipe's job, not the runner's.
|
|
130
|
+
*/
|
|
131
|
+
export declare const AutomationActionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
132
|
+
kind: z.ZodLiteral<"wait">;
|
|
133
|
+
seconds: z.ZodNumber;
|
|
134
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
135
|
+
kind: z.ZodLiteral<"cap">;
|
|
136
|
+
deviceId: z.ZodUnion<readonly [z.ZodNumber, z.ZodObject<{
|
|
137
|
+
$var: z.ZodString;
|
|
138
|
+
}, z.core.$strip>]>;
|
|
139
|
+
cap: z.ZodString;
|
|
140
|
+
method: z.ZodString;
|
|
141
|
+
args: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
142
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
143
|
+
kind: z.ZodLiteral<"code">;
|
|
144
|
+
code: z.ZodString;
|
|
145
|
+
}, z.core.$strip>], "kind">;
|
|
146
|
+
export type AutomationAction = z.infer<typeof AutomationActionSchema>;
|
|
147
|
+
export declare const AutomationRecipeSchema: z.ZodObject<{
|
|
148
|
+
triggers: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
149
|
+
kind: z.ZodLiteral<"device-state">;
|
|
150
|
+
deviceId: z.ZodNumber;
|
|
151
|
+
cap: z.ZodString;
|
|
152
|
+
fieldPath: z.ZodString;
|
|
153
|
+
becomes: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>;
|
|
154
|
+
edge: z.ZodOptional<z.ZodBoolean>;
|
|
155
|
+
forMs: z.ZodOptional<z.ZodNumber>;
|
|
156
|
+
debounceMs: z.ZodOptional<z.ZodNumber>;
|
|
157
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
158
|
+
kind: z.ZodLiteral<"device-event">;
|
|
159
|
+
category: z.ZodString;
|
|
160
|
+
deviceId: z.ZodOptional<z.ZodNumber>;
|
|
161
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
162
|
+
kind: z.ZodLiteral<"schedule">;
|
|
163
|
+
cron: z.ZodString;
|
|
164
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
165
|
+
kind: z.ZodLiteral<"manual">;
|
|
166
|
+
}, z.core.$strip>], "kind">>;
|
|
167
|
+
conditions: z.ZodOptional<z.ZodType<AutomationCondition, unknown, z.core.$ZodTypeInternals<AutomationCondition, unknown>>>;
|
|
168
|
+
actions: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
169
|
+
kind: z.ZodLiteral<"wait">;
|
|
170
|
+
seconds: z.ZodNumber;
|
|
171
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
172
|
+
kind: z.ZodLiteral<"cap">;
|
|
173
|
+
deviceId: z.ZodUnion<readonly [z.ZodNumber, z.ZodObject<{
|
|
174
|
+
$var: z.ZodString;
|
|
175
|
+
}, z.core.$strip>]>;
|
|
176
|
+
cap: z.ZodString;
|
|
177
|
+
method: z.ZodString;
|
|
178
|
+
args: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
179
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
180
|
+
kind: z.ZodLiteral<"code">;
|
|
181
|
+
code: z.ZodString;
|
|
182
|
+
}, z.core.$strip>], "kind">>;
|
|
183
|
+
}, z.core.$strip>;
|
|
184
|
+
export type AutomationRecipe = z.infer<typeof AutomationRecipeSchema>;
|
|
185
|
+
/** Depth of a tree, root container = 1. A bare leaf is depth 1. */
|
|
186
|
+
export declare function conditionDepth(cond: AutomationCondition): number;
|
|
187
|
+
/** Leaves only — containers do not count toward the leaf budget. */
|
|
188
|
+
export declare function countConditionLeaves(cond: AutomationCondition): number;
|
|
189
|
+
/**
|
|
190
|
+
* Author-time bounds check. Returns `null` when the recipe is legal, else a
|
|
191
|
+
* message naming the bound it broke — the editor shows it verbatim, so it has
|
|
192
|
+
* to read like something an operator can act on.
|
|
193
|
+
*/
|
|
194
|
+
export declare function validateRecipeBounds(recipe: AutomationRecipe): string | null;
|
|
@@ -30,6 +30,23 @@ import { type InferProvider } from './capability-definition.js';
|
|
|
30
30
|
* too many — a drift would show as a logs pane that is simply always empty.
|
|
31
31
|
*/
|
|
32
32
|
export declare const CORE_BLOCK_ADDON_PREFIX = "core-block-";
|
|
33
|
+
/**
|
|
34
|
+
* The builtin's own addon id — and, because of that, the OWNER of the
|
|
35
|
+
* integration every block's devices hang from.
|
|
36
|
+
*
|
|
37
|
+
* A block cannot own one. Every integration read is gated on the installed-addon
|
|
38
|
+
* set (`addon-registry.service.ts` → `createFilteredRegistry`) and a block's
|
|
39
|
+
* `core-block-<uuid>` is never in it, so its `getIntegrationByAddonId` answers
|
|
40
|
+
* null forever while the write succeeds — one invisible, undeletable row per
|
|
41
|
+
* start. `core-blocks` IS installed, so it reconciles one shared integration and
|
|
42
|
+
* a block names it by id (`DeclaredDevicesSpec.integrationId`), minting nothing.
|
|
43
|
+
*
|
|
44
|
+
* Exported from the contract, next to the runner prefix and for the same reason:
|
|
45
|
+
* a block reads it as
|
|
46
|
+
* `ctx.api.integrations.getByAddonId.query({ addonId: CORE_BLOCKS_ADDON_ID })`,
|
|
47
|
+
* so a second copy of the string is a block that silently declares into nowhere.
|
|
48
|
+
*/
|
|
49
|
+
export declare const CORE_BLOCKS_ADDON_ID = "core-blocks";
|
|
33
50
|
/** The addon/runner id a block's process runs under. */
|
|
34
51
|
export declare function coreBlockAddonId(blockId: string): string;
|
|
35
52
|
/** The block id behind a generated addon/runner id, or null when the id belongs
|
|
@@ -38,7 +38,7 @@ export { cameraStreamsCapability, type ICameraStreamsProvider, type PickedCamStr
|
|
|
38
38
|
export { extractNestedAddonId, isArrayOutputSchema, isCollectionArrayMethod, isObjectInput, isVoidInput, kebabToCamel, looseSchema, objectInputDeclaresAddonId, procedureAuthKey, } from './cap-router-predicates.js';
|
|
39
39
|
export type { CapabilityDefinition, CapabilityEventSchema, CapabilityMethodAuth, CapabilityMethodCaller, CapabilityMethodKind, CapabilityMethodOptions, CapabilityMethodSchema, CapabilityMountHint, CapabilityMountKind, CapabilityStatusItemArray, CapabilityStatusKind, CapabilityStatusSchema, CapCaller, DeviceConfigDerivedFormUi, DeviceConfigSpec, DeviceConfigUiSpec, DeviceConfigWidgetUi, DeviceSettingsContribution, InferDeviceProxyCap, InferEvents, InferName, InferNativeProvider, InferProvider, InferRuntimeState, ProviderKind, UiContribution, UiContributionKind, UiContributionRemote, } from './capability-definition.js';
|
|
40
40
|
export { DEVICE_SETTINGS_CONTRIBUTION_METHODS, DEVICE_STATUS_METHOD, event, expandCapMethods, isDeviceConfigCap, method, resolveCapMount, } from './capability-definition.js';
|
|
41
|
-
export { CORE_BLOCK_ADDON_PREFIX, type CoreBlock, type CoreBlockCompileResult, CoreBlockCompileResultSchema, type CoreBlockInput, CoreBlockInputSchema, type CoreBlockPlacement, CoreBlockPlacementSchema, CoreBlockSchema, type CoreBlockStatus, CoreBlockStatusSchema, coreBlockAddonId, coreBlockIdFromAddonId, coreBlocksCapability, type ICoreBlocksProvider, } from './core-blocks.cap.js';
|
|
41
|
+
export { CORE_BLOCK_ADDON_PREFIX, CORE_BLOCKS_ADDON_ID, type CoreBlock, type CoreBlockCompileResult, CoreBlockCompileResultSchema, type CoreBlockInput, CoreBlockInputSchema, type CoreBlockPlacement, CoreBlockPlacementSchema, CoreBlockSchema, type CoreBlockStatus, CoreBlockStatusSchema, coreBlockAddonId, coreBlockIdFromAddonId, coreBlocksCapability, type ICoreBlocksProvider, } from './core-blocks.cap.js';
|
|
42
42
|
export * from './custom-actions.js';
|
|
43
43
|
export type { CustomModelDescriptor, ICustomModelRegistryProvider, } from './custom-model-registry.cap.js';
|
|
44
44
|
export { CustomModelDescriptorSchema, customModelRegistryCapability, } from './custom-model-registry.cap.js';
|
|
@@ -149,4 +149,4 @@ export declare const mqttBrokerCapability: {
|
|
|
149
149
|
};
|
|
150
150
|
};
|
|
151
151
|
export type IMqttBrokerProvider = InferProvider<typeof mqttBrokerCapability>;
|
|
152
|
-
export {
|
|
152
|
+
export { AddBrokerInputSchema, BrokerConnectionDetailsSchema, BrokerInfoSchema, StartEmbeddedInputSchema, StatusSchema as MqttBrokerStatusSchema, };
|
|
@@ -403,6 +403,7 @@ declare const TrackSchema: z.ZodObject<{
|
|
|
403
403
|
mediaKey: z.ZodString;
|
|
404
404
|
}, z.core.$strip>>>;
|
|
405
405
|
zonesVisited: z.ZodReadonly<z.ZodArray<z.ZodString>>;
|
|
406
|
+
zoneNames: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
|
|
406
407
|
classes: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
|
|
407
408
|
totalDistance: z.ZodNumber;
|
|
408
409
|
state: z.ZodEnum<{
|
|
@@ -1047,6 +1048,7 @@ declare const RecentTracksPageSchema: z.ZodObject<{
|
|
|
1047
1048
|
mediaKey: z.ZodString;
|
|
1048
1049
|
}, z.core.$strip>>>;
|
|
1049
1050
|
zonesVisited: z.ZodReadonly<z.ZodArray<z.ZodString>>;
|
|
1051
|
+
zoneNames: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
|
|
1050
1052
|
classes: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
|
|
1051
1053
|
totalDistance: z.ZodNumber;
|
|
1052
1054
|
state: z.ZodEnum<{
|
|
@@ -1291,6 +1293,7 @@ export declare const pipelineAnalyticsCapability: {
|
|
|
1291
1293
|
mediaKey: z.ZodString;
|
|
1292
1294
|
}, z.core.$strip>>>;
|
|
1293
1295
|
zonesVisited: z.ZodReadonly<z.ZodArray<z.ZodString>>;
|
|
1296
|
+
zoneNames: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
|
|
1294
1297
|
classes: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
|
|
1295
1298
|
totalDistance: z.ZodNumber;
|
|
1296
1299
|
state: z.ZodEnum<{
|
|
@@ -1382,6 +1385,7 @@ export declare const pipelineAnalyticsCapability: {
|
|
|
1382
1385
|
mediaKey: z.ZodString;
|
|
1383
1386
|
}, z.core.$strip>>>;
|
|
1384
1387
|
zonesVisited: z.ZodReadonly<z.ZodArray<z.ZodString>>;
|
|
1388
|
+
zoneNames: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
|
|
1385
1389
|
classes: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
|
|
1386
1390
|
totalDistance: z.ZodNumber;
|
|
1387
1391
|
state: z.ZodEnum<{
|
|
@@ -1495,6 +1499,7 @@ export declare const pipelineAnalyticsCapability: {
|
|
|
1495
1499
|
mediaKey: z.ZodString;
|
|
1496
1500
|
}, z.core.$strip>>>;
|
|
1497
1501
|
zonesVisited: z.ZodReadonly<z.ZodArray<z.ZodString>>;
|
|
1502
|
+
zoneNames: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
|
|
1498
1503
|
classes: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
|
|
1499
1504
|
totalDistance: z.ZodNumber;
|
|
1500
1505
|
state: z.ZodEnum<{
|
|
@@ -1604,6 +1609,7 @@ export declare const pipelineAnalyticsCapability: {
|
|
|
1604
1609
|
mediaKey: z.ZodString;
|
|
1605
1610
|
}, z.core.$strip>>>;
|
|
1606
1611
|
zonesVisited: z.ZodReadonly<z.ZodArray<z.ZodString>>;
|
|
1612
|
+
zoneNames: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
|
|
1607
1613
|
classes: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
|
|
1608
1614
|
totalDistance: z.ZodNumber;
|
|
1609
1615
|
state: z.ZodEnum<{
|
|
@@ -82,6 +82,62 @@ export declare const snapshotCapability: {
|
|
|
82
82
|
}, z.core.$strip>>, import("./capability-definition.js").CapabilityMethodKind> & {
|
|
83
83
|
readonly systemOnly: true;
|
|
84
84
|
};
|
|
85
|
+
/**
|
|
86
|
+
* Signed, expiring links to a CLIENT-SIZED frame — and the demand signal
|
|
87
|
+
* that makes those frames current.
|
|
88
|
+
*
|
|
89
|
+
* ## The problem it replaces
|
|
90
|
+
*
|
|
91
|
+
* `getSnapshotOverview` is cache-only by contract: it answers from whatever
|
|
92
|
+
* the wrapper happens to hold and never captures. Under D93 the client
|
|
93
|
+
* versions its image URL on that answer, and an image REQUEST is what enrols
|
|
94
|
+
* a camera in the keep-warm loop. Both of those are satisfiable by the
|
|
95
|
+
* client's own image cache — `expo-image` is URL-keyed and never revalidates
|
|
96
|
+
* — so a URL painted in a previous session comes off disk with no network,
|
|
97
|
+
* no enrolment, and nothing warming. Measured on the live hub: reopening
|
|
98
|
+
* after two minutes idle painted 15 of 16 tiles at **168 s old** with zero
|
|
99
|
+
* HTTP requests, and the fleet only recovered because a later poll happened
|
|
100
|
+
* to observe a different identity.
|
|
101
|
+
*
|
|
102
|
+
* ## The two properties that fix it
|
|
103
|
+
*
|
|
104
|
+
* **It is an RPC, so no client cache can answer it.** The demand signal
|
|
105
|
+
* always reaches the wrapper. This method therefore MAY create keep-warm
|
|
106
|
+
* subscriptions, where `getSnapshotOverview` must never (D93) — the
|
|
107
|
+
* distinction is not "one is newer" but that the overview poll is app-wide
|
|
108
|
+
* (a creating overview would warm every camera on the install) while this is
|
|
109
|
+
* called by a rendered surface naming the tiles it is actually painting, at
|
|
110
|
+
* the width it is painting them.
|
|
111
|
+
*
|
|
112
|
+
* **It waits, briefly and boundedly, for the capture it triggered.** The
|
|
113
|
+
* returned `capturedAt` is the frame the link will serve, not the frame the
|
|
114
|
+
* cache held when the client asked, so a first paint is honest and current
|
|
115
|
+
* instead of a generation behind. A device that does not settle inside the
|
|
116
|
+
* bound still gets a link and its real (older) `capturedAt` — the next poll
|
|
117
|
+
* carries it forward.
|
|
118
|
+
*
|
|
119
|
+
* `force` is never set on behalf of a client here. A sleeping battery camera
|
|
120
|
+
* is reported with `sleeping: true` and the last frame it produced, however
|
|
121
|
+
* old; the wrapper's existing sleep gate owns that decision and this method
|
|
122
|
+
* adds no second one.
|
|
123
|
+
*/
|
|
124
|
+
readonly getSnapshotLinks: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
|
|
125
|
+
targets: z.ZodArray<z.ZodObject<{
|
|
126
|
+
deviceId: z.ZodNumber;
|
|
127
|
+
width: z.ZodOptional<z.ZodNumber>;
|
|
128
|
+
}, z.core.$strip>>;
|
|
129
|
+
}, z.core.$strip>, z.ZodArray<z.ZodObject<{
|
|
130
|
+
deviceId: z.ZodNumber;
|
|
131
|
+
url: z.ZodNullable<z.ZodString>;
|
|
132
|
+
capturedAt: z.ZodNullable<z.ZodNumber>;
|
|
133
|
+
ageMs: z.ZodNullable<z.ZodNumber>;
|
|
134
|
+
expiresAt: z.ZodNullable<z.ZodNumber>;
|
|
135
|
+
width: z.ZodNullable<z.ZodNumber>;
|
|
136
|
+
neverCaptured: z.ZodBoolean;
|
|
137
|
+
sleeping: z.ZodBoolean;
|
|
138
|
+
}, z.core.$strip>>, import("./capability-definition.js").CapabilityMethodKind> & {
|
|
139
|
+
readonly systemOnly: true;
|
|
140
|
+
};
|
|
85
141
|
};
|
|
86
142
|
readonly status: {
|
|
87
143
|
readonly schema: z.ZodObject<{
|
|
@@ -109,8 +109,29 @@ export interface DeviceDeclaration<T extends IDevice = IDevice> {
|
|
|
109
109
|
/** Where the declaration is owned. */
|
|
110
110
|
export type DeclarationPlacement = 'hub' | 'this-node';
|
|
111
111
|
export interface DeclaredDevicesSpec {
|
|
112
|
-
/** Display name of the FIXED integration the devices hang from.
|
|
112
|
+
/** Display name of the FIXED integration the devices hang from. Unused when
|
|
113
|
+
* {@link integrationId} names an existing one. */
|
|
113
114
|
readonly integrationName: string;
|
|
115
|
+
/**
|
|
116
|
+
* Hang the devices off an integration that ALREADY EXISTS, owned by somebody
|
|
117
|
+
* else. When set, nothing is minted and `fixed` is not re-asserted — the
|
|
118
|
+
* owner of that integration is responsible for both.
|
|
119
|
+
*
|
|
120
|
+
* This exists because a declarer is not always an installed addon. Every
|
|
121
|
+
* integration READ is filtered by `installedAddonIds`
|
|
122
|
+
* (`addon-registry.service.ts` → `createFilteredRegistry`), and a core
|
|
123
|
+
* block's addon id (`core-block-<uuid>`) is never in that set: its
|
|
124
|
+
* `getIntegration` answers null forever, so the mint branch runs on every
|
|
125
|
+
* start and leaks a row `listIntegrations` hides and `deleteIntegration`
|
|
126
|
+
* refuses to delete. Measured on the live hub, 2026-08-09 — two starts of one
|
|
127
|
+
* block left `int_0021` and `int_0022` orphaned and unreachable.
|
|
128
|
+
*
|
|
129
|
+
* A block therefore hangs its devices off the integration the `core-blocks`
|
|
130
|
+
* builtin owns. Ownership of the DEVICE is unaffected: that is
|
|
131
|
+
* `(addonId, stableId)`, and `listOwnDevices` stays addon-scoped, which is
|
|
132
|
+
* what keeps one block's withdrawal sweep away from another's devices.
|
|
133
|
+
*/
|
|
134
|
+
readonly integrationId?: string;
|
|
114
135
|
readonly devices: readonly DeviceDeclaration[];
|
|
115
136
|
/**
|
|
116
137
|
* Default `'hub'`: a declaration is cluster state and belongs to the node
|
|
@@ -6575,6 +6575,13 @@ export type AppRouter = TrpcCoreRouter<{
|
|
|
6575
6575
|
output: z.infer<typeof snapshotCapability.methods.getSnapshotOverview.output>;
|
|
6576
6576
|
meta: object;
|
|
6577
6577
|
}>;
|
|
6578
|
+
getSnapshotLinks: TRPCQueryProcedure<{
|
|
6579
|
+
input: {
|
|
6580
|
+
[x: string]: unknown;
|
|
6581
|
+
} & z.input<typeof snapshotCapability.methods.getSnapshotLinks.input>;
|
|
6582
|
+
output: z.infer<typeof snapshotCapability.methods.getSnapshotLinks.output>;
|
|
6583
|
+
meta: object;
|
|
6584
|
+
}>;
|
|
6578
6585
|
}>>;
|
|
6579
6586
|
ssoBridge: TRPCBuiltRouter<{
|
|
6580
6587
|
ctx: TrpcContext;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* scope+access check inside `protectedProcedure` (see
|
|
7
7
|
* `server/backend/src/api/trpc/trpc.middleware.ts`).
|
|
8
8
|
*
|
|
9
|
-
* Coverage:
|
|
9
|
+
* Coverage: 901 method paths across 121 capabilities.
|
|
10
10
|
*/
|
|
11
11
|
import type { CapabilityMethodAccess } from '../capabilities/capability-definition.js';
|
|
12
12
|
export interface MethodAccessRecord {
|
package/dist/index.d.ts
CHANGED
|
@@ -112,6 +112,8 @@ export * from './types/pipeline.js';
|
|
|
112
112
|
export type { AvailableEngine, PipelineAddonSchema, PipelineDefaultStep, PipelineModelOption, PipelineSchema, PipelineSlotSchema, PipelineTemplate, PipelineTemplateStep, TemplateValidationResult, } from './types/pipeline-schema.js';
|
|
113
113
|
export * from './types/pipeline-step.js';
|
|
114
114
|
export * from './types/tracked.js';
|
|
115
|
+
export type { AutomationAction, AutomationCondition, AutomationConditionAll, AutomationConditionAny, AutomationConditionExpression, AutomationConditionLeaf, AutomationConditionNot, AutomationConditionOperator, AutomationRecipe, AutomationTrigger, GenerateAutomationBlockInput, } from './automation/index.js';
|
|
116
|
+
export { AutomationActionSchema, AutomationConditionOperatorSchema, AutomationConditionSchema, AutomationRecipeSchema, AutomationTriggerSchema, conditionDepth, countConditionLeaves, generateAutomationBlock, MAX_CONDITION_DEPTH, MAX_CONDITION_LEAVES, validateRecipeBounds, } from './automation/index.js';
|
|
115
117
|
export * from './cap-call-context.js';
|
|
116
118
|
export * from './capabilities/index.js';
|
|
117
119
|
export { APPLE_SA_TO_MACRO, AUDIO_MACRO_LABELS, getAudioMacroClassIds, mapAudioLabelToMacro, YAMNET_TO_MACRO, } from './catalogs/audio-classmap.js';
|