@camstack/types 1.2.263 → 1.2.265
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/automation/recipe.d.ts +1 -1
- package/dist/capabilities/composer.cap.d.ts +328 -0
- package/dist/capabilities/control.cap.d.ts +4 -4
- package/dist/capabilities/core-blocks.cap.d.ts +2339 -0
- package/dist/capabilities/custom-model-registry.cap.d.ts +44 -2
- package/dist/capabilities/day-night.cap.d.ts +8 -8
- package/dist/capabilities/device-extension.cap.d.ts +8 -8
- package/dist/capabilities/index.d.ts +4 -2
- package/dist/capabilities/model-convert.cap.d.ts +22 -1
- package/dist/capabilities/model-distributor.cap.d.ts +44 -2
- package/dist/capabilities/notification-rules.cap.d.ts +74 -74
- package/dist/capabilities/osd-manager.cap.d.ts +13 -13
- package/dist/composition/composition-graph.d.ts +36 -0
- package/dist/composition/composition-report.d.ts +264 -0
- package/dist/composition/composition.d.ts +362 -0
- package/dist/composition/evaluate-field.d.ts +63 -0
- package/dist/composition/examples.d.ts +10 -0
- package/dist/composition/expression-kinds.d.ts +36 -0
- package/dist/composition/index.d.ts +12 -0
- package/dist/composition/state-fields.d.ts +19 -0
- package/dist/composition/validate-composition.d.ts +46 -0
- package/dist/device/schema-fields.d.ts +3 -0
- package/dist/expression/builtins.d.ts +30 -2
- package/dist/generated/addon-api.d.ts +57 -0
- package/dist/generated/capability-router-map.d.ts +5 -2
- package/dist/generated/method-access-map.d.ts +1 -1
- package/dist/generated/system-proxy.d.ts +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1388 -83
- package/dist/index.mjs +1314 -84
- package/dist/notification/rule-kinds.d.ts +3 -2
- package/dist/types/models.d.ts +80 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5215,6 +5215,50 @@ function inferModelProvider(entry) {
|
|
|
5215
5215
|
if (/frigate/i.test(haystack)) return "frigate";
|
|
5216
5216
|
return "custom";
|
|
5217
5217
|
}
|
|
5218
|
+
var MODEL_HOSTING = [
|
|
5219
|
+
"camstack-hf",
|
|
5220
|
+
"third-party",
|
|
5221
|
+
"built-in"
|
|
5222
|
+
];
|
|
5223
|
+
var ModelLicenseRecordSchema = zod.z.object({
|
|
5224
|
+
/** SPDX id of the WEIGHTS' terms, a `LicenseRef-*` for non-SPDX terms, or `UNKNOWN`. */
|
|
5225
|
+
weights: zod.z.string().min(1),
|
|
5226
|
+
/** SPDX id of the upstream code that defines / trained the network. */
|
|
5227
|
+
code: zod.z.string().min(1).optional(),
|
|
5228
|
+
/** Training data whose terms add obligations (attribution, non-commercial). */
|
|
5229
|
+
data: zod.z.object({
|
|
5230
|
+
name: zod.z.string().min(1),
|
|
5231
|
+
terms: zod.z.string().min(1),
|
|
5232
|
+
url: zod.z.string().url().optional()
|
|
5233
|
+
}).optional(),
|
|
5234
|
+
/** The project the weights come from. Required on built-in entries (guard). */
|
|
5235
|
+
upstream: zod.z.object({
|
|
5236
|
+
name: zod.z.string().min(1),
|
|
5237
|
+
url: zod.z.string().url()
|
|
5238
|
+
}).optional(),
|
|
5239
|
+
/** Where the licence text governing the weights is published. */
|
|
5240
|
+
url: zod.z.string().url().optional(),
|
|
5241
|
+
/** Attribution the licence REQUIRES, verbatim. */
|
|
5242
|
+
attribution: zod.z.string().min(1).optional(),
|
|
5243
|
+
/** What CamStack changed. Required when `hosting` is `camstack-hf` (guard). */
|
|
5244
|
+
modifications: zod.z.string().min(1).optional(),
|
|
5245
|
+
/** Who serves the file a node downloads. */
|
|
5246
|
+
hosting: zod.z.enum(MODEL_HOSTING).optional(),
|
|
5247
|
+
/** True when the weights or their data forbid commercial use. */
|
|
5248
|
+
nonCommercial: zod.z.boolean().optional()
|
|
5249
|
+
});
|
|
5250
|
+
/**
|
|
5251
|
+
* The licence of a model, as a record rather than a bare SPDX string: a
|
|
5252
|
+
* permissive CODE licence routinely sits on top of restrictive WEIGHTS or
|
|
5253
|
+
* DATA, and the obligations (attribution, modification notices, source offers)
|
|
5254
|
+
* are per upstream. A persisted custom-model row written when this field was a
|
|
5255
|
+
* string still parses — the string is lifted into `{ weights }`.
|
|
5256
|
+
*
|
|
5257
|
+
* Every licence surface (the admin "Models and licenses" page,
|
|
5258
|
+
* `THIRD_PARTY_MODELS.md`, the Hugging Face model table) is GENERATED from
|
|
5259
|
+
* these records by `scripts/gen-model-licenses.ts` (D661).
|
|
5260
|
+
*/
|
|
5261
|
+
var ModelLicenseSchema = zod.z.preprocess((value) => typeof value === "string" ? { weights: value } : value, ModelLicenseRecordSchema);
|
|
5218
5262
|
var ModelCatalogEntrySchema = zod.z.object({
|
|
5219
5263
|
id: zod.z.string(),
|
|
5220
5264
|
name: zod.z.string(),
|
|
@@ -5303,11 +5347,11 @@ var ModelCatalogEntrySchema = zod.z.object({
|
|
|
5303
5347
|
p95LatencyMs: zod.z.record(zod.z.string(), zod.z.number()).optional()
|
|
5304
5348
|
}).optional(),
|
|
5305
5349
|
/**
|
|
5306
|
-
*
|
|
5307
|
-
*
|
|
5308
|
-
*
|
|
5350
|
+
* The model's licence record — see {@link ModelLicenseSchema}. Optional in
|
|
5351
|
+
* the schema (a custom model's author may state none); REQUIRED and complete
|
|
5352
|
+
* on every built-in catalog entry (`scripts/check-catalog-licence.ts`).
|
|
5309
5353
|
*/
|
|
5310
|
-
license:
|
|
5354
|
+
license: ModelLicenseSchema.optional(),
|
|
5311
5355
|
/**
|
|
5312
5356
|
* Variant-selector grouping. The UI groups models by `family` + `tier` and
|
|
5313
5357
|
* offers `precision` / `optimization` as variant axes WITHIN a tier — so all
|
|
@@ -5503,23 +5547,6 @@ var ExpressionEvalError = class extends Error {
|
|
|
5503
5547
|
};
|
|
5504
5548
|
//#endregion
|
|
5505
5549
|
//#region src/expression/builtins.ts
|
|
5506
|
-
/**
|
|
5507
|
-
* Frozen, null-prototype builtin function table for the expression engine
|
|
5508
|
-
* (spec §4 rule 4). The table is the SOLE surface of callable functions: the
|
|
5509
|
-
* parser rejects any callee not in it, and the evaluator gates each call on an
|
|
5510
|
-
* own-property check against it.
|
|
5511
|
-
*
|
|
5512
|
-
* Because the object has a NULL prototype AND is `Object.freeze`d:
|
|
5513
|
-
* - it cannot be polluted (no `__proto__` / `constructor` write reaches it);
|
|
5514
|
-
* - a lookup for `toString` / `hasOwnProperty` / `constructor` finds NOTHING
|
|
5515
|
-
* (there is no `Object.prototype` in the chain), so those names are not
|
|
5516
|
-
* callable — they are simply "unknown function" at parse time.
|
|
5517
|
-
*
|
|
5518
|
-
* Every numeric argument is validated as a finite number and every numeric
|
|
5519
|
-
* RESULT is re-checked finite, so `/0`, `sqrt(-1)` (→ NaN) and overflow
|
|
5520
|
-
* (`pow(10,400)` → Infinity) all raise `ExpressionEvalError` and fail the link
|
|
5521
|
-
* closed rather than emitting a garbage value.
|
|
5522
|
-
*/
|
|
5523
5550
|
function asFiniteNumber(value, name, index) {
|
|
5524
5551
|
if (typeof value !== "number" || !Number.isFinite(value)) throw new ExpressionEvalError(`${name}: argument ${index + 1} must be a finite number`);
|
|
5525
5552
|
return value;
|
|
@@ -5535,6 +5562,10 @@ function finiteResult(value, name) {
|
|
|
5535
5562
|
function allFiniteNumbers(args, name) {
|
|
5536
5563
|
return args.map((a, idx) => asFiniteNumber(a, name, idx));
|
|
5537
5564
|
}
|
|
5565
|
+
function asBoolean$1(value, name, index) {
|
|
5566
|
+
if (typeof value !== "boolean") throw new ExpressionEvalError(`${name}: argument ${index + 1} must be a boolean`);
|
|
5567
|
+
return value;
|
|
5568
|
+
}
|
|
5538
5569
|
var INF = Number.POSITIVE_INFINITY;
|
|
5539
5570
|
var table = {
|
|
5540
5571
|
min: {
|
|
@@ -5635,6 +5666,40 @@ var table = {
|
|
|
5635
5666
|
if (from === to) return x;
|
|
5636
5667
|
throw new ExpressionEvalError("convert: unit conversion table not installed");
|
|
5637
5668
|
}
|
|
5669
|
+
},
|
|
5670
|
+
any: {
|
|
5671
|
+
minArgs: 1,
|
|
5672
|
+
maxArgs: INF,
|
|
5673
|
+
apply: (args) => args.map((a, i) => asBoolean$1(a, "any", i)).some((b) => b)
|
|
5674
|
+
},
|
|
5675
|
+
all: {
|
|
5676
|
+
minArgs: 1,
|
|
5677
|
+
maxArgs: INF,
|
|
5678
|
+
apply: (args) => args.map((a, i) => asBoolean$1(a, "all", i)).every((b) => b)
|
|
5679
|
+
},
|
|
5680
|
+
within: {
|
|
5681
|
+
minArgs: 2,
|
|
5682
|
+
maxArgs: 2,
|
|
5683
|
+
apply: (args, hooks) => {
|
|
5684
|
+
const windowMs = asFiniteNumber(args[1], "within", 1);
|
|
5685
|
+
if (windowMs < 0) throw new ExpressionEvalError("within: the window must not be negative");
|
|
5686
|
+
const at = args[0];
|
|
5687
|
+
if (at === null) return false;
|
|
5688
|
+
const ts = asFiniteNumber(at, "within", 0);
|
|
5689
|
+
const now = hooks.now;
|
|
5690
|
+
if (now === void 0 || !Number.isFinite(now)) throw new ExpressionEvalError("within: no clock was supplied to this evaluation");
|
|
5691
|
+
const inside = now - ts <= windowMs;
|
|
5692
|
+
if (inside) hooks.noteDeadline?.(ts + windowMs + 1);
|
|
5693
|
+
return inside;
|
|
5694
|
+
}
|
|
5695
|
+
},
|
|
5696
|
+
latest: {
|
|
5697
|
+
minArgs: 1,
|
|
5698
|
+
maxArgs: INF,
|
|
5699
|
+
apply: (args) => {
|
|
5700
|
+
const present = args.flatMap((a, i) => a === null ? [] : [asFiniteNumber(a, "latest", i)]);
|
|
5701
|
+
return present.length === 0 ? null : finiteResult(Math.max(...present), "latest");
|
|
5702
|
+
}
|
|
5638
5703
|
}
|
|
5639
5704
|
};
|
|
5640
5705
|
/** Frozen, null-prototype builtin table. */
|
|
@@ -6239,10 +6304,17 @@ function evaluateExpressionSource(expr, bindingValues, now, opts) {
|
|
|
6239
6304
|
...bindingValues,
|
|
6240
6305
|
["now"]: now
|
|
6241
6306
|
});
|
|
6307
|
+
const hooks = {
|
|
6308
|
+
...opts?.hooks,
|
|
6309
|
+
now
|
|
6310
|
+
};
|
|
6242
6311
|
try {
|
|
6243
6312
|
return {
|
|
6244
6313
|
ok: true,
|
|
6245
|
-
value: evaluateAst(compiled.parsed.ast, scope,
|
|
6314
|
+
value: evaluateAst(compiled.parsed.ast, scope, {
|
|
6315
|
+
...opts,
|
|
6316
|
+
hooks
|
|
6317
|
+
})
|
|
6246
6318
|
};
|
|
6247
6319
|
} catch (err) {
|
|
6248
6320
|
return {
|
|
@@ -10054,6 +10126,277 @@ function kebabToCamel(s) {
|
|
|
10054
10126
|
return s.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
10055
10127
|
}
|
|
10056
10128
|
//#endregion
|
|
10129
|
+
//#region src/composition/composition.ts
|
|
10130
|
+
/**
|
|
10131
|
+
* A COMPOSITION: a device assembled from other devices' state (D659).
|
|
10132
|
+
*
|
|
10133
|
+
* The data half of the composed-devices spec §1. A composition is stored inside
|
|
10134
|
+
* a core block (`CoreBlock.source.kind === 'composition'`) and run by the shared
|
|
10135
|
+
* `composer` runner. It names a TARGET and, for each capability of the target, a
|
|
10136
|
+
* FIELD MAP: every state field has exactly one source.
|
|
10137
|
+
*
|
|
10138
|
+
* Sources are keyed by `(addonId, stableId)`, NEVER by numeric device id. A
|
|
10139
|
+
* resync reissues numeric ids, and a composition that stored them would be
|
|
10140
|
+
* orphaned by the first re-adoption (the linked-devices lesson). A `stableId` is
|
|
10141
|
+
* unique only within its owning addon, so the owner travels with it.
|
|
10142
|
+
*
|
|
10143
|
+
* Later slices EXTEND these unions and do not reshape them. The variants a later
|
|
10144
|
+
* slice implements are already in the wire shape, and `validateComposition`
|
|
10145
|
+
* refuses them BY NAME until then:
|
|
10146
|
+
* target `existing` → slice 2 · feature `passthrough` → slice 3 ·
|
|
10147
|
+
* `commands` (`forward`) → slice 3 · source `code` → slice 4.
|
|
10148
|
+
*/
|
|
10149
|
+
/** The owner of every composed device: the `composer` builtin. */
|
|
10150
|
+
var COMPOSER_ADDON_ID = "composer";
|
|
10151
|
+
/** A composed device's stableId is this prefix plus the block id. */
|
|
10152
|
+
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
10153
|
+
/** A device with more capabilities than this is two devices. */
|
|
10154
|
+
var MAX_COMPOSITION_FEATURES = 16;
|
|
10155
|
+
var MAX_COMPOSITION_FIELDS_PER_FEATURE = 32;
|
|
10156
|
+
/** Longest snippet a `code` source may carry (slice 4). */
|
|
10157
|
+
var MAX_COMPOSITION_CODE_LENGTH = 2e4;
|
|
10158
|
+
var CompositionSourceRefSchema = zod.z.object({
|
|
10159
|
+
/** The owning addon; `stableId` is unique only within it. */
|
|
10160
|
+
addonId: zod.z.string().min(1),
|
|
10161
|
+
stableId: zod.z.string().min(1)
|
|
10162
|
+
});
|
|
10163
|
+
/** One field of one capability of one source device. */
|
|
10164
|
+
var CompositionFieldReadSchema = zod.z.object({
|
|
10165
|
+
source: CompositionSourceRefSchema,
|
|
10166
|
+
cap: zod.z.string().min(1),
|
|
10167
|
+
/** Dotted path into the source cap's runtime-state slice. */
|
|
10168
|
+
fieldPath: zod.z.string().min(1)
|
|
10169
|
+
});
|
|
10170
|
+
/** `from`: copy one source field verbatim. It is also an expression's `from` binding. */
|
|
10171
|
+
var CompositionFromSourceSchema = CompositionFieldReadSchema.extend({ kind: zod.z.literal("from") });
|
|
10172
|
+
/** A constant binding. No device is read. */
|
|
10173
|
+
var CompositionLiteralBindingSchema = zod.z.object({
|
|
10174
|
+
kind: zod.z.literal("literal"),
|
|
10175
|
+
value: zod.z.union([
|
|
10176
|
+
zod.z.string(),
|
|
10177
|
+
zod.z.number(),
|
|
10178
|
+
zod.z.boolean(),
|
|
10179
|
+
zod.z.null()
|
|
10180
|
+
])
|
|
10181
|
+
});
|
|
10182
|
+
var CompositionBindingSchema = zod.z.discriminatedUnion("kind", [CompositionFromSourceSchema, CompositionLiteralBindingSchema]);
|
|
10183
|
+
/**
|
|
10184
|
+
* `expression`: a formula over named bindings, in the salvaged expression
|
|
10185
|
+
* engine. Validated at parse by the SAME function every other consumer runs,
|
|
10186
|
+
* so the editor and the store cannot disagree.
|
|
10187
|
+
*/
|
|
10188
|
+
var CompositionExpressionSourceSchema = zod.z.object({
|
|
10189
|
+
kind: zod.z.literal("expression"),
|
|
10190
|
+
expr: zod.z.string().min(1).max(MAX_EXPRESSION_SOURCE_LENGTH),
|
|
10191
|
+
bindings: zod.z.record(zod.z.string().regex(EXPRESSION_IDENTIFIER_RE), CompositionBindingSchema)
|
|
10192
|
+
}).superRefine((src, ctx) => {
|
|
10193
|
+
const err = validateExpressionSource(src);
|
|
10194
|
+
if (err !== null) ctx.addIssue({
|
|
10195
|
+
code: "custom",
|
|
10196
|
+
message: err,
|
|
10197
|
+
path: ["expr"]
|
|
10198
|
+
});
|
|
10199
|
+
});
|
|
10200
|
+
/** `code`: RESERVED for slice 4 (own runner, one-way eject). */
|
|
10201
|
+
var CompositionCodeSourceSchema = zod.z.object({
|
|
10202
|
+
kind: zod.z.literal("code"),
|
|
10203
|
+
code: zod.z.string().min(1).max(MAX_COMPOSITION_CODE_LENGTH)
|
|
10204
|
+
});
|
|
10205
|
+
var CompositionFieldSourceSchema = zod.z.discriminatedUnion("kind", [
|
|
10206
|
+
CompositionFromSourceSchema,
|
|
10207
|
+
CompositionExpressionSourceSchema,
|
|
10208
|
+
CompositionCodeSourceSchema
|
|
10209
|
+
]);
|
|
10210
|
+
/** `forward`: RESERVED for slice 3. Argument mapping arrives there as an additive optional `args`. */
|
|
10211
|
+
var CompositionForwardCommandSchema = zod.z.object({
|
|
10212
|
+
kind: zod.z.literal("forward"),
|
|
10213
|
+
source: CompositionSourceRefSchema,
|
|
10214
|
+
cap: zod.z.string().min(1),
|
|
10215
|
+
method: zod.z.string().min(1)
|
|
10216
|
+
});
|
|
10217
|
+
var CompositionCommandTargetSchema = zod.z.discriminatedUnion("kind", [CompositionForwardCommandSchema, CompositionCodeSourceSchema]);
|
|
10218
|
+
var CompositionFieldsFeatureSchema = zod.z.object({
|
|
10219
|
+
kind: zod.z.literal("fields"),
|
|
10220
|
+
cap: zod.z.string().min(1),
|
|
10221
|
+
fields: zod.z.record(zod.z.string().min(1), CompositionFieldSourceSchema).refine((fields) => Object.keys(fields).length <= 32, { message: `at most 32 fields per capability` }),
|
|
10222
|
+
/** RESERVED for slice 3; refused by the validator when non-empty. */
|
|
10223
|
+
commands: zod.z.record(zod.z.string().min(1), CompositionCommandTargetSchema).optional()
|
|
10224
|
+
});
|
|
10225
|
+
/** RESERVED for slice 3: a media / data-plane cap, whole, from one source. */
|
|
10226
|
+
var CompositionPassthroughFeatureSchema = zod.z.object({
|
|
10227
|
+
kind: zod.z.literal("passthrough"),
|
|
10228
|
+
cap: zod.z.string().min(1),
|
|
10229
|
+
source: CompositionSourceRefSchema
|
|
10230
|
+
});
|
|
10231
|
+
var CompositionFeatureSchema = zod.z.discriminatedUnion("kind", [CompositionFieldsFeatureSchema, CompositionPassthroughFeatureSchema]);
|
|
10232
|
+
/**
|
|
10233
|
+
* A NEW device. It has no `name` of its own: the block's name IS the device's
|
|
10234
|
+
* name (2026-08-08). A second copy here would be a second writer of one string (D62).
|
|
10235
|
+
*/
|
|
10236
|
+
var CompositionNewTargetSchema = zod.z.object({
|
|
10237
|
+
kind: zod.z.literal("new"),
|
|
10238
|
+
type: zod.z.enum(require_sleep.DeviceType),
|
|
10239
|
+
role: zod.z.enum(require_sleep.DeviceRole).optional()
|
|
10240
|
+
});
|
|
10241
|
+
/** RESERVED for slice 2: customize an existing device. */
|
|
10242
|
+
var CompositionExistingTargetSchema = zod.z.object({
|
|
10243
|
+
kind: zod.z.literal("existing"),
|
|
10244
|
+
device: CompositionSourceRefSchema
|
|
10245
|
+
});
|
|
10246
|
+
var CompositionTargetSchema = zod.z.discriminatedUnion("kind", [CompositionNewTargetSchema, CompositionExistingTargetSchema]);
|
|
10247
|
+
var CompositionSchema = zod.z.object({
|
|
10248
|
+
target: CompositionTargetSchema,
|
|
10249
|
+
features: zod.z.array(CompositionFeatureSchema).min(1).max(16)
|
|
10250
|
+
}).superRefine((composition, ctx) => {
|
|
10251
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10252
|
+
composition.features.forEach((feature, index) => {
|
|
10253
|
+
if (seen.has(feature.cap)) ctx.addIssue({
|
|
10254
|
+
code: "custom",
|
|
10255
|
+
message: `capability \`${feature.cap}\` is composed twice — one feature per capability`,
|
|
10256
|
+
path: [
|
|
10257
|
+
"features",
|
|
10258
|
+
index,
|
|
10259
|
+
"cap"
|
|
10260
|
+
]
|
|
10261
|
+
});
|
|
10262
|
+
seen.add(feature.cap);
|
|
10263
|
+
});
|
|
10264
|
+
});
|
|
10265
|
+
function compositionSourceKey(ref) {
|
|
10266
|
+
return `${ref.addonId}/${ref.stableId}`;
|
|
10267
|
+
}
|
|
10268
|
+
function compositionSliceKey(ref, cap) {
|
|
10269
|
+
return `${compositionSourceKey(ref)}#${cap}`;
|
|
10270
|
+
}
|
|
10271
|
+
function compositionReadKey(read) {
|
|
10272
|
+
return `${compositionSliceKey(read.source, read.cap)}.${read.fieldPath}`;
|
|
10273
|
+
}
|
|
10274
|
+
function composedDeviceStableId(blockId) {
|
|
10275
|
+
return `${COMPOSED_DEVICE_STABLE_ID_PREFIX}${blockId}`;
|
|
10276
|
+
}
|
|
10277
|
+
function composedDeviceRef(blockId) {
|
|
10278
|
+
return {
|
|
10279
|
+
addonId: COMPOSER_ADDON_ID,
|
|
10280
|
+
stableId: composedDeviceStableId(blockId)
|
|
10281
|
+
};
|
|
10282
|
+
}
|
|
10283
|
+
/** Every device field a source reads: `from` is one read, an expression is its `from` bindings. */
|
|
10284
|
+
function fieldReads(source) {
|
|
10285
|
+
switch (source.kind) {
|
|
10286
|
+
case "from": return [{
|
|
10287
|
+
source: source.source,
|
|
10288
|
+
cap: source.cap,
|
|
10289
|
+
fieldPath: source.fieldPath
|
|
10290
|
+
}];
|
|
10291
|
+
case "expression": return Object.values(source.bindings).flatMap((binding) => binding.kind === "from" ? [{
|
|
10292
|
+
source: binding.source,
|
|
10293
|
+
cap: binding.cap,
|
|
10294
|
+
fieldPath: binding.fieldPath
|
|
10295
|
+
}] : []);
|
|
10296
|
+
case "code": return [];
|
|
10297
|
+
}
|
|
10298
|
+
}
|
|
10299
|
+
//#endregion
|
|
10300
|
+
//#region src/composition/composition-report.ts
|
|
10301
|
+
/**
|
|
10302
|
+
* What the validator says about a composition and what the composer says about
|
|
10303
|
+
* a running one: the wire shapes the API returns (D659).
|
|
10304
|
+
*/
|
|
10305
|
+
var CompositionProblemCodeSchema = zod.z.enum([
|
|
10306
|
+
"reserved-variant",
|
|
10307
|
+
"unknown-capability",
|
|
10308
|
+
"not-composable",
|
|
10309
|
+
"wrong-device-type",
|
|
10310
|
+
"has-commands",
|
|
10311
|
+
"unknown-field",
|
|
10312
|
+
"nested-field",
|
|
10313
|
+
"missing-field",
|
|
10314
|
+
"kind-mismatch",
|
|
10315
|
+
"may-be-null",
|
|
10316
|
+
"source-missing",
|
|
10317
|
+
"source-unreadable",
|
|
10318
|
+
"source-capability-missing",
|
|
10319
|
+
"source-field-unknown",
|
|
10320
|
+
"expression-invalid",
|
|
10321
|
+
"cycle",
|
|
10322
|
+
"duplicate-target"
|
|
10323
|
+
]);
|
|
10324
|
+
/** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.celsius`. */
|
|
10325
|
+
var CompositionProblemSchema = zod.z.object({
|
|
10326
|
+
code: CompositionProblemCodeSchema,
|
|
10327
|
+
path: zod.z.string(),
|
|
10328
|
+
message: zod.z.string()
|
|
10329
|
+
});
|
|
10330
|
+
var CompositionFieldKindSchema = zod.z.enum([
|
|
10331
|
+
"string",
|
|
10332
|
+
"number",
|
|
10333
|
+
"boolean",
|
|
10334
|
+
"enum"
|
|
10335
|
+
]);
|
|
10336
|
+
/** How a field says "unavailable": `null` when its schema allows it, else the device goes offline (D393). */
|
|
10337
|
+
var CompositionUnavailableModeSchema = zod.z.enum(["null", "offline"]);
|
|
10338
|
+
/**
|
|
10339
|
+
* `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
|
|
10340
|
+
* field of its cap changes value · `constant` reads nothing, computed once.
|
|
10341
|
+
*/
|
|
10342
|
+
var CompositionFieldRoleSchema = zod.z.enum([
|
|
10343
|
+
"derived",
|
|
10344
|
+
"clock",
|
|
10345
|
+
"constant"
|
|
10346
|
+
]);
|
|
10347
|
+
var CompositionFieldPlanSchema = zod.z.object({
|
|
10348
|
+
cap: zod.z.string(),
|
|
10349
|
+
path: zod.z.string(),
|
|
10350
|
+
/** Index into `composition.features` this field's capability came from —
|
|
10351
|
+
* lets a source/cycle problem name its path as `features[N].fields.<path>`
|
|
10352
|
+
* (the same convention `planComposition`'s own problems already use). */
|
|
10353
|
+
featureIndex: zod.z.number().int().nonnegative(),
|
|
10354
|
+
kind: CompositionFieldKindSchema,
|
|
10355
|
+
nullable: zod.z.boolean(),
|
|
10356
|
+
required: zod.z.boolean(),
|
|
10357
|
+
unavailable: CompositionUnavailableModeSchema,
|
|
10358
|
+
role: CompositionFieldRoleSchema,
|
|
10359
|
+
source: CompositionFieldSourceSchema,
|
|
10360
|
+
reads: zod.z.array(CompositionFieldReadSchema)
|
|
10361
|
+
});
|
|
10362
|
+
var CompositionValidationSchema = zod.z.object({
|
|
10363
|
+
ok: zod.z.boolean(),
|
|
10364
|
+
problems: zod.z.array(CompositionProblemSchema),
|
|
10365
|
+
fields: zod.z.array(CompositionFieldPlanSchema)
|
|
10366
|
+
});
|
|
10367
|
+
/** Mirrors `CoreBlockStatus`, pinned by `core-blocks-source.spec.ts` (Task 11). */
|
|
10368
|
+
var CompositionRunStatusSchema = zod.z.enum([
|
|
10369
|
+
"stopped",
|
|
10370
|
+
"starting",
|
|
10371
|
+
"running",
|
|
10372
|
+
"failed"
|
|
10373
|
+
]);
|
|
10374
|
+
var CompositionFieldStateKindSchema = zod.z.enum([
|
|
10375
|
+
"fresh",
|
|
10376
|
+
"stale",
|
|
10377
|
+
"unavailable"
|
|
10378
|
+
]);
|
|
10379
|
+
var CompositionFieldStateSchema = zod.z.object({
|
|
10380
|
+
cap: zod.z.string(),
|
|
10381
|
+
path: zod.z.string(),
|
|
10382
|
+
state: CompositionFieldStateKindSchema,
|
|
10383
|
+
/** `null` whenever `state === 'unavailable'`; never a plausible stand-in (D393). */
|
|
10384
|
+
value: zod.z.union([
|
|
10385
|
+
zod.z.string(),
|
|
10386
|
+
zod.z.number(),
|
|
10387
|
+
zod.z.boolean(),
|
|
10388
|
+
zod.z.null()
|
|
10389
|
+
]),
|
|
10390
|
+
reason: zod.z.string().optional()
|
|
10391
|
+
});
|
|
10392
|
+
var CompositionBlockStateSchema = zod.z.object({
|
|
10393
|
+
blockId: zod.z.string(),
|
|
10394
|
+
deviceId: zod.z.number().nullable(),
|
|
10395
|
+
status: CompositionRunStatusSchema,
|
|
10396
|
+
reason: zod.z.string().optional(),
|
|
10397
|
+
fields: zod.z.array(CompositionFieldStateSchema)
|
|
10398
|
+
});
|
|
10399
|
+
//#endregion
|
|
10057
10400
|
//#region src/capabilities/core-blocks.cap.ts
|
|
10058
10401
|
/**
|
|
10059
10402
|
* core-blocks — user-authored TypeScript, stored in the kernel and executed in
|
|
@@ -10139,6 +10482,30 @@ var CoreBlockInputSchema = zod.z.object({
|
|
|
10139
10482
|
*/
|
|
10140
10483
|
integrationId: zod.z.string().optional()
|
|
10141
10484
|
});
|
|
10485
|
+
/**
|
|
10486
|
+
* What a block IS (D659). Absent means `code` — every row stored before this
|
|
10487
|
+
* union keeps working unchanged.
|
|
10488
|
+
* - `code`: the TypeScript in `code`, compiled and run in its own runner;
|
|
10489
|
+
* - `recipe`: RESERVED (automations), stored shape only; refused at run by name;
|
|
10490
|
+
* - `composition`: declarative, run by the shared `composer`; `code` is `''`.
|
|
10491
|
+
*/
|
|
10492
|
+
var CoreBlockSourceSchema = zod.z.discriminatedUnion("kind", [
|
|
10493
|
+
zod.z.object({ kind: zod.z.literal("code") }),
|
|
10494
|
+
zod.z.object({
|
|
10495
|
+
kind: zod.z.literal("recipe"),
|
|
10496
|
+
recipe: AutomationRecipeSchema
|
|
10497
|
+
}),
|
|
10498
|
+
zod.z.object({
|
|
10499
|
+
kind: zod.z.literal("composition"),
|
|
10500
|
+
composition: CompositionSchema
|
|
10501
|
+
})
|
|
10502
|
+
]);
|
|
10503
|
+
/** The client-authored half of a composition block. No `code`, no placement (hub-only; Phase 7). */
|
|
10504
|
+
var CompositionBlockInputSchema = zod.z.object({
|
|
10505
|
+
name: zod.z.string().min(1).max(120),
|
|
10506
|
+
enabled: zod.z.boolean(),
|
|
10507
|
+
composition: CompositionSchema
|
|
10508
|
+
});
|
|
10142
10509
|
/** A stored block. */
|
|
10143
10510
|
var CoreBlockSchema = CoreBlockInputSchema.extend({
|
|
10144
10511
|
id: zod.z.string(),
|
|
@@ -10154,8 +10521,46 @@ var CoreBlockSchema = CoreBlockInputSchema.extend({
|
|
|
10154
10521
|
*/
|
|
10155
10522
|
lastError: zod.z.string().optional(),
|
|
10156
10523
|
/** Ms epoch of the last state change. */
|
|
10157
|
-
lastChangedAt: zod.z.number()
|
|
10524
|
+
lastChangedAt: zod.z.number(),
|
|
10525
|
+
/** What the block is. Absent means `code` (D659). */
|
|
10526
|
+
source: CoreBlockSourceSchema.optional()
|
|
10527
|
+
});
|
|
10528
|
+
function coreBlockSourceKind(block) {
|
|
10529
|
+
return block.source?.kind ?? "code";
|
|
10530
|
+
}
|
|
10531
|
+
function coreBlockComposition(block) {
|
|
10532
|
+
return block.source?.kind === "composition" ? block.source.composition : null;
|
|
10533
|
+
}
|
|
10534
|
+
/** What the composer said, or that it could not be asked. Unknown never looks like absent (D315). */
|
|
10535
|
+
var CompositionStateReadSchema = zod.z.discriminatedUnion("kind", [zod.z.object({
|
|
10536
|
+
kind: zod.z.literal("answered"),
|
|
10537
|
+
state: CompositionBlockStateSchema.nullable()
|
|
10538
|
+
}), zod.z.object({
|
|
10539
|
+
kind: zod.z.literal("unreachable"),
|
|
10540
|
+
error: zod.z.string()
|
|
10541
|
+
})]);
|
|
10542
|
+
/** A stored composition block and what the composer says about it. */
|
|
10543
|
+
var CompositionViewSchema = zod.z.object({
|
|
10544
|
+
block: CoreBlockSchema,
|
|
10545
|
+
state: CompositionStateReadSchema
|
|
10158
10546
|
});
|
|
10547
|
+
/**
|
|
10548
|
+
* A read of the stored compositions. `not-loaded` while the `core_blocks`
|
|
10549
|
+
* table has not been READ: an empty answer then would make "not yet known"
|
|
10550
|
+
* look like "none", and invite the operator to recreate what exists (D315).
|
|
10551
|
+
*/
|
|
10552
|
+
var CompositionsNotLoadedSchema = zod.z.object({
|
|
10553
|
+
state: zod.z.literal("not-loaded"),
|
|
10554
|
+
reason: zod.z.string()
|
|
10555
|
+
});
|
|
10556
|
+
var CompositionListReadSchema = zod.z.discriminatedUnion("state", [zod.z.object({
|
|
10557
|
+
state: zod.z.literal("loaded"),
|
|
10558
|
+
views: zod.z.array(CompositionViewSchema)
|
|
10559
|
+
}), CompositionsNotLoadedSchema]);
|
|
10560
|
+
var CompositionGetReadSchema = zod.z.discriminatedUnion("state", [zod.z.object({
|
|
10561
|
+
state: zod.z.literal("loaded"),
|
|
10562
|
+
view: CompositionViewSchema.nullable()
|
|
10563
|
+
}), CompositionsNotLoadedSchema]);
|
|
10159
10564
|
/** What a compile attempt produced. */
|
|
10160
10565
|
var CoreBlockCompileResultSchema = zod.z.object({
|
|
10161
10566
|
ok: zod.z.boolean(),
|
|
@@ -10237,7 +10642,119 @@ var coreBlocksCapability = {
|
|
|
10237
10642
|
getTypeDefs: require_sleep.method(zod.z.object({}), zod.z.object({ libs: zod.z.array(zod.z.object({
|
|
10238
10643
|
filePath: zod.z.string(),
|
|
10239
10644
|
content: zod.z.string()
|
|
10240
|
-
})) }), { auth: "admin" })
|
|
10645
|
+
})) }), { auth: "admin" }),
|
|
10646
|
+
/**
|
|
10647
|
+
* Create a composition block (D659). VALIDATED first against the live
|
|
10648
|
+
* sources and every stored composition; a refusal names every problem by
|
|
10649
|
+
* path and reason (D391) and stores nothing.
|
|
10650
|
+
*/
|
|
10651
|
+
createComposition: require_sleep.method(zod.z.object({ block: CompositionBlockInputSchema }), zod.z.object({ block: CoreBlockSchema }), {
|
|
10652
|
+
kind: "mutation",
|
|
10653
|
+
auth: "admin",
|
|
10654
|
+
caller: "required"
|
|
10655
|
+
}),
|
|
10656
|
+
/**
|
|
10657
|
+
* Patch a composition block. A changed `composition` is validated exactly
|
|
10658
|
+
* as on create. `expectedUpdatedAt` is the `updatedAt` the caller READ: a
|
|
10659
|
+
* block changed since is refused by name, never silently overwritten.
|
|
10660
|
+
*/
|
|
10661
|
+
updateComposition: require_sleep.method(zod.z.object({
|
|
10662
|
+
blockId: zod.z.string(),
|
|
10663
|
+
expectedUpdatedAt: zod.z.number(),
|
|
10664
|
+
block: CompositionBlockInputSchema.partial()
|
|
10665
|
+
}), zod.z.object({ block: CoreBlockSchema }), {
|
|
10666
|
+
kind: "mutation",
|
|
10667
|
+
auth: "admin",
|
|
10668
|
+
caller: "required"
|
|
10669
|
+
}),
|
|
10670
|
+
/** One composition and the composer's state for it, or `not-loaded` (D315). */
|
|
10671
|
+
getComposition: require_sleep.method(zod.z.object({ blockId: zod.z.string() }), CompositionGetReadSchema, { auth: "admin" }),
|
|
10672
|
+
listCompositions: require_sleep.method(zod.z.object({}), CompositionListReadSchema, { auth: "admin" }),
|
|
10673
|
+
/**
|
|
10674
|
+
* Validate without saving — the same verdict the save reaches. A mutation
|
|
10675
|
+
* for its body size; it writes nothing, so its access is `view`.
|
|
10676
|
+
*/
|
|
10677
|
+
validateComposition: require_sleep.method(zod.z.object({
|
|
10678
|
+
composition: CompositionSchema,
|
|
10679
|
+
blockId: zod.z.string().optional()
|
|
10680
|
+
}), CompositionValidationSchema, {
|
|
10681
|
+
kind: "mutation",
|
|
10682
|
+
auth: "admin",
|
|
10683
|
+
access: "view"
|
|
10684
|
+
})
|
|
10685
|
+
}
|
|
10686
|
+
};
|
|
10687
|
+
//#endregion
|
|
10688
|
+
//#region src/capabilities/composer.cap.ts
|
|
10689
|
+
/**
|
|
10690
|
+
* composer — runs every DECLARATIVE composition (D659).
|
|
10691
|
+
*
|
|
10692
|
+
* Internal and admin-only: its one caller is `core-blocks`' supervisor, which
|
|
10693
|
+
* sends the WHOLE set of composition blocks on every converge (idempotent),
|
|
10694
|
+
* and reads their state for the API. Nothing else talks to it.
|
|
10695
|
+
*/
|
|
10696
|
+
/** The composer's runner id, `resolveRunnerId(decl, 'composer')`; pinned by `composer-manifest.spec.ts`. */
|
|
10697
|
+
var COMPOSER_RUNNER_ID = COMPOSER_ADDON_ID;
|
|
10698
|
+
var ComposerBlockSchema = zod.z.object({
|
|
10699
|
+
id: zod.z.string().min(1),
|
|
10700
|
+
name: zod.z.string().min(1).max(120),
|
|
10701
|
+
enabled: zod.z.boolean(),
|
|
10702
|
+
updatedAt: zod.z.number(),
|
|
10703
|
+
composition: CompositionSchema
|
|
10704
|
+
});
|
|
10705
|
+
/**
|
|
10706
|
+
* A stored composition row that no longer PARSES — a schema a release
|
|
10707
|
+
* tightened, a row written by a newer build. Sent by id so the composer keeps
|
|
10708
|
+
* its device as a placeholder and reports the block `failed` naming the parse
|
|
10709
|
+
* error. Leaving it out would read, twice, exactly like a delete (D49).
|
|
10710
|
+
*/
|
|
10711
|
+
var ComposerUnreadableBlockSchema = zod.z.object({
|
|
10712
|
+
id: zod.z.string().min(1),
|
|
10713
|
+
/** The row's stored name column; null when even that is unreadable (the device keeps the name it has). */
|
|
10714
|
+
name: zod.z.string().nullable(),
|
|
10715
|
+
/** The parse error, in the operator's words. */
|
|
10716
|
+
error: zod.z.string()
|
|
10717
|
+
});
|
|
10718
|
+
var ComposerApplyInputSchema = zod.z.object({
|
|
10719
|
+
/** The shared Blocks integration; null until `core-blocks` has reconciled it. */
|
|
10720
|
+
integrationId: zod.z.string().nullable(),
|
|
10721
|
+
/** False when the `core_blocks` read failed: then nothing may be withdrawn (D49). */
|
|
10722
|
+
storeLoaded: zod.z.boolean(),
|
|
10723
|
+
blocks: zod.z.array(ComposerBlockSchema),
|
|
10724
|
+
/** Operator restarts: rebuild these runtimes and re-resolve their sources. Stores nothing (D62). */
|
|
10725
|
+
restartBlockIds: zod.z.array(zod.z.string()),
|
|
10726
|
+
/** Composition rows that exist but do not parse: held, never withdrawn, reported failed. */
|
|
10727
|
+
unreadableBlocks: zod.z.array(ComposerUnreadableBlockSchema)
|
|
10728
|
+
});
|
|
10729
|
+
var ComposerBlockVerdictSchema = zod.z.object({
|
|
10730
|
+
blockId: zod.z.string(),
|
|
10731
|
+
status: CompositionRunStatusSchema,
|
|
10732
|
+
reason: zod.z.string().optional()
|
|
10733
|
+
});
|
|
10734
|
+
var ComposerApplyResultSchema = zod.z.object({
|
|
10735
|
+
blocks: zod.z.array(ComposerBlockVerdictSchema),
|
|
10736
|
+
/**
|
|
10737
|
+
* False when the composer declared and withdrew NOTHING (store not loaded,
|
|
10738
|
+
* integration unknown, its own rows unread or read empty once). An empty
|
|
10739
|
+
* apply the caller owes is paid off only by one the composer acted on (D49).
|
|
10740
|
+
*/
|
|
10741
|
+
acted: zod.z.boolean()
|
|
10742
|
+
});
|
|
10743
|
+
var composerCapability = {
|
|
10744
|
+
name: "composer",
|
|
10745
|
+
scope: "system",
|
|
10746
|
+
mode: "singleton",
|
|
10747
|
+
internal: true,
|
|
10748
|
+
methods: {
|
|
10749
|
+
/**
|
|
10750
|
+
* Not `apply`: tRPC reserves `apply`, `call` and `then` as router keys, and
|
|
10751
|
+
* `router({})` throws on one — every cap router is built at boot.
|
|
10752
|
+
*/
|
|
10753
|
+
applyBlocks: require_sleep.method(ComposerApplyInputSchema, ComposerApplyResultSchema, {
|
|
10754
|
+
kind: "mutation",
|
|
10755
|
+
auth: "admin"
|
|
10756
|
+
}),
|
|
10757
|
+
getStates: require_sleep.method(zod.z.object({ blockIds: zod.z.array(zod.z.string()) }), zod.z.object({ states: zod.z.array(CompositionBlockStateSchema) }), { auth: "admin" })
|
|
10241
10758
|
}
|
|
10242
10759
|
};
|
|
10243
10760
|
//#endregion
|
|
@@ -18807,8 +19324,8 @@ var NcTestResultSchema = zod.z.object({
|
|
|
18807
19324
|
className: zod.z.string().optional(),
|
|
18808
19325
|
label: zod.z.string().optional()
|
|
18809
19326
|
});
|
|
18810
|
-
/** The rule kinds, as data. `NcRuleKind` in `notification/rule-kinds.ts` is
|
|
18811
|
-
*
|
|
19327
|
+
/** The rule kinds, as data. `NcRuleKind` in `notification/rule-kinds.ts` is
|
|
19328
|
+
* `z.infer` of this schema — one shape, no twin. `mixed` is DERIVED
|
|
18812
19329
|
* (a stored system rule whose kinds span families, D637) and never authored. */
|
|
18813
19330
|
var NcRuleKindSchema = zod.z.enum([
|
|
18814
19331
|
"detection",
|
|
@@ -44659,6 +45176,720 @@ function createDeviceExtensionProvider(options) {
|
|
|
44659
45176
|
};
|
|
44660
45177
|
}
|
|
44661
45178
|
//#endregion
|
|
45179
|
+
//#region src/composition/composition-graph.ts
|
|
45180
|
+
/**
|
|
45181
|
+
* The field graph across every composition, and the cycles in it (D659).
|
|
45182
|
+
*
|
|
45183
|
+
* A node is ONE field of ONE device (`<addon>/<stableId>#<cap>.<field>`); an
|
|
45184
|
+
* edge points from a composed field to each field it reads. A cycle, direct or
|
|
45185
|
+
* through another composition, is refused at save by name (spec §2).
|
|
45186
|
+
*
|
|
45187
|
+
* The graph is built for ONE save: the CANDIDATE composition (the one being
|
|
45188
|
+
* validated) plus every STORED composition. The candidate ALWAYS replaces any
|
|
45189
|
+
* stored peer that targets the same device, regardless of where that stored
|
|
45190
|
+
* peer sits in `stored` — whether a save introduces or removes a cycle must
|
|
45191
|
+
* never depend on array order. Two DIFFERENT stored peers that (wrongly)
|
|
45192
|
+
* target the same device are corrupted state, not a cycle to resolve by
|
|
45193
|
+
* picking one silently; that is refused by name (D391).
|
|
45194
|
+
*
|
|
45195
|
+
* `findCompositionCycles` reports at least one cycle per cycle-SET (the DFS
|
|
45196
|
+
* marks a node `done` after its first expansion) — enough to refuse a save,
|
|
45197
|
+
* not to enumerate every elementary cycle through a shared node. A dotted
|
|
45198
|
+
* `fieldPath` is matched only as an exact string: a write to `state.value` and
|
|
45199
|
+
* a read of `state` would not connect (no nested field writes exist yet).
|
|
45200
|
+
*/
|
|
45201
|
+
/** Two stored compositions both target the same device — refused by name, never silently resolved. */
|
|
45202
|
+
var CompositionGraphError = class extends Error {};
|
|
45203
|
+
function peerEdges(peer) {
|
|
45204
|
+
return peer.composition.features.flatMap((feature) => feature.kind !== "fields" ? [] : Object.entries(feature.fields).map(([path, source]) => [compositionReadKey({
|
|
45205
|
+
source: peer.target,
|
|
45206
|
+
cap: feature.cap,
|
|
45207
|
+
fieldPath: path
|
|
45208
|
+
}), fieldReads(source).map(compositionReadKey)]));
|
|
45209
|
+
}
|
|
45210
|
+
/**
|
|
45211
|
+
* Every peer that actually takes part in the graph: each stored peer minus
|
|
45212
|
+
* whichever one targets the same device as the candidate (the candidate
|
|
45213
|
+
* replaces it — this drop happens before any edge is built, so the
|
|
45214
|
+
* candidate's old edges never enter the map to begin with), plus the
|
|
45215
|
+
* candidate itself, exactly once. Throws {@link CompositionGraphError} if two
|
|
45216
|
+
* DIFFERENT stored peers (neither of them the candidate's own old version)
|
|
45217
|
+
* target the same device.
|
|
45218
|
+
*/
|
|
45219
|
+
function resolvedPeers(candidate, stored) {
|
|
45220
|
+
const candidateKey = compositionSourceKey(candidate.target);
|
|
45221
|
+
const survivors = /* @__PURE__ */ new Map();
|
|
45222
|
+
for (const peer of stored) {
|
|
45223
|
+
const key = compositionSourceKey(peer.target);
|
|
45224
|
+
if (key === candidateKey) continue;
|
|
45225
|
+
if (survivors.has(key)) throw new CompositionGraphError(`two stored compositions both target device \`${key}\` — refusing to build the field graph`);
|
|
45226
|
+
survivors.set(key, peer);
|
|
45227
|
+
}
|
|
45228
|
+
return [...survivors.values(), candidate];
|
|
45229
|
+
}
|
|
45230
|
+
function compositionEdges(candidate, stored) {
|
|
45231
|
+
const edges = resolvedPeers(candidate, stored).flatMap(peerEdges);
|
|
45232
|
+
return new Map(edges);
|
|
45233
|
+
}
|
|
45234
|
+
function findCompositionCycles(candidate, stored) {
|
|
45235
|
+
const edges = compositionEdges(candidate, stored);
|
|
45236
|
+
const marks = /* @__PURE__ */ new Map();
|
|
45237
|
+
const found = /* @__PURE__ */ new Map();
|
|
45238
|
+
const visit = (node, stack) => {
|
|
45239
|
+
const mark = marks.get(node);
|
|
45240
|
+
if (mark === "done") return;
|
|
45241
|
+
if (mark === "visiting") {
|
|
45242
|
+
const path = [...stack.slice(stack.indexOf(node)), node];
|
|
45243
|
+
const id = [...new Set(path)].toSorted().join("|");
|
|
45244
|
+
if (!found.has(id)) found.set(id, { path });
|
|
45245
|
+
return;
|
|
45246
|
+
}
|
|
45247
|
+
marks.set(node, "visiting");
|
|
45248
|
+
for (const next of edges.get(node) ?? []) visit(next, [...stack, node]);
|
|
45249
|
+
marks.set(node, "done");
|
|
45250
|
+
};
|
|
45251
|
+
for (const node of edges.keys()) visit(node, []);
|
|
45252
|
+
return [...found.values()];
|
|
45253
|
+
}
|
|
45254
|
+
//#endregion
|
|
45255
|
+
//#region src/composition/evaluate-field.ts
|
|
45256
|
+
function describeRead(read) {
|
|
45257
|
+
return `${compositionSourceKey(read.source)} ${read.cap}.${read.fieldPath}`;
|
|
45258
|
+
}
|
|
45259
|
+
function fromReading(reading, read) {
|
|
45260
|
+
if (reading.state === "unavailable") return {
|
|
45261
|
+
state: "unavailable",
|
|
45262
|
+
value: null,
|
|
45263
|
+
reason: `${describeRead(read)}: ${reading.reason}`,
|
|
45264
|
+
fatal: reading.fatal
|
|
45265
|
+
};
|
|
45266
|
+
return {
|
|
45267
|
+
state: reading.state,
|
|
45268
|
+
value: reading.value,
|
|
45269
|
+
reason: reading.state === "stale" ? `${describeRead(read)}: ${reading.reason}` : null,
|
|
45270
|
+
deadline: null
|
|
45271
|
+
};
|
|
45272
|
+
}
|
|
45273
|
+
function expressionOutcome(source, read, now) {
|
|
45274
|
+
const values = {};
|
|
45275
|
+
const staleReasons = [];
|
|
45276
|
+
let fatalUnavailable = null;
|
|
45277
|
+
let nonFatalUnavailable = null;
|
|
45278
|
+
for (const [name, binding] of Object.entries(source.bindings)) {
|
|
45279
|
+
if (binding.kind === "literal") {
|
|
45280
|
+
values[name] = binding.value;
|
|
45281
|
+
continue;
|
|
45282
|
+
}
|
|
45283
|
+
const reading = read(binding);
|
|
45284
|
+
if (reading.state === "unavailable") {
|
|
45285
|
+
const outcome = {
|
|
45286
|
+
state: "unavailable",
|
|
45287
|
+
value: null,
|
|
45288
|
+
reason: `binding \`${name}\` (${describeRead(binding)}): ${reading.reason}`,
|
|
45289
|
+
fatal: reading.fatal
|
|
45290
|
+
};
|
|
45291
|
+
if (reading.fatal) {
|
|
45292
|
+
fatalUnavailable = outcome;
|
|
45293
|
+
break;
|
|
45294
|
+
}
|
|
45295
|
+
if (nonFatalUnavailable === null) nonFatalUnavailable = outcome;
|
|
45296
|
+
continue;
|
|
45297
|
+
}
|
|
45298
|
+
values[name] = reading.value;
|
|
45299
|
+
if (reading.state === "stale") staleReasons.push(`\`${name}\`: ${reading.reason}`);
|
|
45300
|
+
}
|
|
45301
|
+
if (fatalUnavailable !== null) return fatalUnavailable;
|
|
45302
|
+
if (nonFatalUnavailable !== null) return nonFatalUnavailable;
|
|
45303
|
+
const deadlines = [];
|
|
45304
|
+
const result = evaluateExpressionSource(source.expr, values, now, { hooks: { noteDeadline: (at) => deadlines.push(at) } });
|
|
45305
|
+
if (!result.ok) return {
|
|
45306
|
+
state: "unavailable",
|
|
45307
|
+
value: null,
|
|
45308
|
+
reason: `the expression failed: ${result.error}`,
|
|
45309
|
+
fatal: false
|
|
45310
|
+
};
|
|
45311
|
+
return {
|
|
45312
|
+
state: staleReasons.length > 0 ? "stale" : "fresh",
|
|
45313
|
+
value: result.value,
|
|
45314
|
+
reason: staleReasons.length > 0 ? staleReasons.join("; ") : null,
|
|
45315
|
+
deadline: deadlines.length > 0 ? Math.min(...deadlines) : null
|
|
45316
|
+
};
|
|
45317
|
+
}
|
|
45318
|
+
function evaluateCompositionField(input) {
|
|
45319
|
+
const { source } = input;
|
|
45320
|
+
switch (source.kind) {
|
|
45321
|
+
case "from": return fromReading(input.read(source), source);
|
|
45322
|
+
case "expression": return expressionOutcome(source, input.read, input.now);
|
|
45323
|
+
case "code": return {
|
|
45324
|
+
state: "unavailable",
|
|
45325
|
+
value: null,
|
|
45326
|
+
reason: "code fields are not runnable in the composer — they arrive in slice 4",
|
|
45327
|
+
fatal: true
|
|
45328
|
+
};
|
|
45329
|
+
}
|
|
45330
|
+
}
|
|
45331
|
+
//#endregion
|
|
45332
|
+
//#region src/composition/examples.ts
|
|
45333
|
+
/**
|
|
45334
|
+
* The worked composed-device example: a ROOM. Temperature is the average of N
|
|
45335
|
+
* sensors, and occupancy is any motion within the last five minutes. It is the
|
|
45336
|
+
* slice-1 acceptance case and the template an author starts from (Phase 4
|
|
45337
|
+
* §4 item 4 asked for one).
|
|
45338
|
+
*/
|
|
45339
|
+
var ROOM_OCCUPANCY_WINDOW_MS = 3e5;
|
|
45340
|
+
var ROOM_EXAMPLE_TEMPERATURE_SOURCES = [
|
|
45341
|
+
{
|
|
45342
|
+
addonId: "provider-homeassistant",
|
|
45343
|
+
stableId: "sensor.living_room_temperature"
|
|
45344
|
+
},
|
|
45345
|
+
{
|
|
45346
|
+
addonId: "provider-homeassistant",
|
|
45347
|
+
stableId: "sensor.sofa_temperature"
|
|
45348
|
+
},
|
|
45349
|
+
{
|
|
45350
|
+
addonId: "provider-homeassistant",
|
|
45351
|
+
stableId: "sensor.window_temperature"
|
|
45352
|
+
}
|
|
45353
|
+
];
|
|
45354
|
+
var ROOM_EXAMPLE_MOTION_SOURCES = [{
|
|
45355
|
+
addonId: "provider-homeassistant",
|
|
45356
|
+
stableId: "binary_sensor.living_room_motion"
|
|
45357
|
+
}, {
|
|
45358
|
+
addonId: "provider-homeassistant",
|
|
45359
|
+
stableId: "binary_sensor.living_room_presence"
|
|
45360
|
+
}];
|
|
45361
|
+
function from(source, cap, fieldPath) {
|
|
45362
|
+
return {
|
|
45363
|
+
kind: "from",
|
|
45364
|
+
source,
|
|
45365
|
+
cap,
|
|
45366
|
+
fieldPath
|
|
45367
|
+
};
|
|
45368
|
+
}
|
|
45369
|
+
function named(prefix, sources, cap, fieldPath) {
|
|
45370
|
+
return Object.fromEntries(sources.map((s, i) => [`${prefix}${i + 1}`, from(s, cap, fieldPath)]));
|
|
45371
|
+
}
|
|
45372
|
+
function roomCompositionExample(input) {
|
|
45373
|
+
const t = named("t", input.temperatureSources, "temperature-sensor", "celsius");
|
|
45374
|
+
const f = named("f", input.temperatureSources, "temperature-sensor", "lastFetchedAt");
|
|
45375
|
+
const d = named("d", input.motionSources, "motion", "detected");
|
|
45376
|
+
const m = named("m", input.motionSources, "motion", "lastDetectedAt");
|
|
45377
|
+
const windows = Object.keys(m).map((name) => `within(${name}, ${input.occupancyWindowMs})`);
|
|
45378
|
+
return CompositionSchema.parse({
|
|
45379
|
+
target: {
|
|
45380
|
+
kind: "new",
|
|
45381
|
+
type: require_sleep.DeviceType.Sensor
|
|
45382
|
+
},
|
|
45383
|
+
features: [{
|
|
45384
|
+
kind: "fields",
|
|
45385
|
+
cap: "temperature-sensor",
|
|
45386
|
+
fields: {
|
|
45387
|
+
celsius: {
|
|
45388
|
+
kind: "expression",
|
|
45389
|
+
expr: `round(avg(${Object.keys(t).join(", ")}), 1)`,
|
|
45390
|
+
bindings: t
|
|
45391
|
+
},
|
|
45392
|
+
lastFetchedAt: {
|
|
45393
|
+
kind: "expression",
|
|
45394
|
+
expr: `max(${Object.keys(f).join(", ")})`,
|
|
45395
|
+
bindings: f
|
|
45396
|
+
}
|
|
45397
|
+
}
|
|
45398
|
+
}, {
|
|
45399
|
+
kind: "fields",
|
|
45400
|
+
cap: "binary",
|
|
45401
|
+
fields: {
|
|
45402
|
+
on: {
|
|
45403
|
+
kind: "expression",
|
|
45404
|
+
expr: `any(${[...Object.keys(d), ...windows].join(", ")})`,
|
|
45405
|
+
bindings: {
|
|
45406
|
+
...d,
|
|
45407
|
+
...m
|
|
45408
|
+
}
|
|
45409
|
+
},
|
|
45410
|
+
lastChangedAt: {
|
|
45411
|
+
kind: "expression",
|
|
45412
|
+
expr: "now",
|
|
45413
|
+
bindings: {}
|
|
45414
|
+
}
|
|
45415
|
+
}
|
|
45416
|
+
}]
|
|
45417
|
+
});
|
|
45418
|
+
}
|
|
45419
|
+
//#endregion
|
|
45420
|
+
//#region src/composition/expression-kinds.ts
|
|
45421
|
+
var NUMBER = {
|
|
45422
|
+
kind: "fixed",
|
|
45423
|
+
result: ["number"]
|
|
45424
|
+
};
|
|
45425
|
+
var BOOLEAN = {
|
|
45426
|
+
kind: "fixed",
|
|
45427
|
+
result: ["boolean"]
|
|
45428
|
+
};
|
|
45429
|
+
/** One rule per builtin. `expression-kinds.spec.ts` fails for a builtin missing here. */
|
|
45430
|
+
var BUILTIN_RESULT_KINDS = Object.freeze({
|
|
45431
|
+
min: NUMBER,
|
|
45432
|
+
max: NUMBER,
|
|
45433
|
+
abs: NUMBER,
|
|
45434
|
+
floor: NUMBER,
|
|
45435
|
+
ceil: NUMBER,
|
|
45436
|
+
sqrt: NUMBER,
|
|
45437
|
+
round: NUMBER,
|
|
45438
|
+
pow: NUMBER,
|
|
45439
|
+
clamp: NUMBER,
|
|
45440
|
+
avg: NUMBER,
|
|
45441
|
+
sum: NUMBER,
|
|
45442
|
+
age: NUMBER,
|
|
45443
|
+
convert: NUMBER,
|
|
45444
|
+
coalesce: { kind: "coalesce" },
|
|
45445
|
+
any: BOOLEAN,
|
|
45446
|
+
all: BOOLEAN,
|
|
45447
|
+
within: BOOLEAN,
|
|
45448
|
+
latest: {
|
|
45449
|
+
kind: "fixed",
|
|
45450
|
+
result: ["number", "null"]
|
|
45451
|
+
}
|
|
45452
|
+
});
|
|
45453
|
+
var KindInferenceError = class extends Error {};
|
|
45454
|
+
function kindOfValue(value) {
|
|
45455
|
+
if (value === null) return "null";
|
|
45456
|
+
if (typeof value === "number") return "number";
|
|
45457
|
+
if (typeof value === "string") return "string";
|
|
45458
|
+
return "boolean";
|
|
45459
|
+
}
|
|
45460
|
+
function only(kind) {
|
|
45461
|
+
return new Set([kind]);
|
|
45462
|
+
}
|
|
45463
|
+
function union(...sets) {
|
|
45464
|
+
return new Set(sets.flatMap((s) => [...s]));
|
|
45465
|
+
}
|
|
45466
|
+
function withoutNull(set) {
|
|
45467
|
+
return new Set([...set].filter((k) => k !== "null"));
|
|
45468
|
+
}
|
|
45469
|
+
function binaryKinds(op, left, right) {
|
|
45470
|
+
if (op === "+") {
|
|
45471
|
+
const all = [...left, ...right];
|
|
45472
|
+
if (all.every((k) => k === "string")) return only("string");
|
|
45473
|
+
if (all.every((k) => k === "number")) return only("number");
|
|
45474
|
+
return new Set(["number", "string"]);
|
|
45475
|
+
}
|
|
45476
|
+
if (op === "-" || op === "*" || op === "/" || op === "%") return only("number");
|
|
45477
|
+
return only("boolean");
|
|
45478
|
+
}
|
|
45479
|
+
/** "exactly N" / "at least N" / "N–M", for an arity refusal that says what IS allowed. */
|
|
45480
|
+
function arityRange(builtin) {
|
|
45481
|
+
if (builtin.minArgs === builtin.maxArgs) return `exactly ${builtin.minArgs}`;
|
|
45482
|
+
if (builtin.maxArgs === Number.POSITIVE_INFINITY) return `at least ${builtin.minArgs}`;
|
|
45483
|
+
return `${builtin.minArgs}–${builtin.maxArgs}`;
|
|
45484
|
+
}
|
|
45485
|
+
function callKinds(callee, args) {
|
|
45486
|
+
const builtin = EXPRESSION_BUILTINS[callee];
|
|
45487
|
+
if (builtin !== void 0 && (args.length < builtin.minArgs || args.length > builtin.maxArgs)) throw new KindInferenceError(`${callee}: wrong number of arguments (${args.length}); expected ${arityRange(builtin)}`);
|
|
45488
|
+
const rule = BUILTIN_RESULT_KINDS[callee];
|
|
45489
|
+
if (rule === void 0) throw new KindInferenceError(`no result-kind rule for builtin '${callee}'`);
|
|
45490
|
+
if (rule.kind === "fixed") return new Set(rule.result);
|
|
45491
|
+
const nonNull = union(...args.map(withoutNull));
|
|
45492
|
+
return args.every((a) => a.has("null")) ? union(nonNull, only("null")) : nonNull;
|
|
45493
|
+
}
|
|
45494
|
+
function kindsOf(node, bindings) {
|
|
45495
|
+
switch (node.kind) {
|
|
45496
|
+
case "literal": return only(kindOfValue(node.value));
|
|
45497
|
+
case "identifier": {
|
|
45498
|
+
if (node.name === "now") return only("number");
|
|
45499
|
+
const bound = bindings.get(node.name);
|
|
45500
|
+
if (bound === void 0) throw new KindInferenceError(`unbound identifier '${node.name}'`);
|
|
45501
|
+
return bound;
|
|
45502
|
+
}
|
|
45503
|
+
case "unary": return only(node.op === "!" ? "boolean" : "number");
|
|
45504
|
+
case "binary": return binaryKinds(node.op, kindsOf(node.left, bindings), kindsOf(node.right, bindings));
|
|
45505
|
+
case "logical": return union(kindsOf(node.left, bindings), kindsOf(node.right, bindings));
|
|
45506
|
+
case "conditional": return union(kindsOf(node.consequent, bindings), kindsOf(node.alternate, bindings));
|
|
45507
|
+
case "call": return callKinds(node.callee, node.args.map((a) => kindsOf(a, bindings)));
|
|
45508
|
+
}
|
|
45509
|
+
}
|
|
45510
|
+
function inferExpressionKinds(input) {
|
|
45511
|
+
const compiled = compileExpressionSafe(input.expr);
|
|
45512
|
+
if (!compiled.ok) return {
|
|
45513
|
+
ok: false,
|
|
45514
|
+
error: compiled.error
|
|
45515
|
+
};
|
|
45516
|
+
try {
|
|
45517
|
+
return {
|
|
45518
|
+
ok: true,
|
|
45519
|
+
kinds: kindsOf(compiled.parsed.ast, input.bindingKinds)
|
|
45520
|
+
};
|
|
45521
|
+
} catch (err) {
|
|
45522
|
+
if (err instanceof KindInferenceError) return {
|
|
45523
|
+
ok: false,
|
|
45524
|
+
error: err.message
|
|
45525
|
+
};
|
|
45526
|
+
throw err;
|
|
45527
|
+
}
|
|
45528
|
+
}
|
|
45529
|
+
//#endregion
|
|
45530
|
+
//#region src/device/schema-fields.ts
|
|
45531
|
+
/** Unwrap ZodNullable / ZodOptional / ZodDefault wrappers to reach the inner type.
|
|
45532
|
+
* Zod v4 exposes `.unwrap()` on all three wrapper classes. */
|
|
45533
|
+
function unwrapSchema(schema) {
|
|
45534
|
+
let s = schema;
|
|
45535
|
+
while (s instanceof zod.z.ZodNullable || s instanceof zod.z.ZodOptional || s instanceof zod.z.ZodDefault) s = s.unwrap();
|
|
45536
|
+
return s;
|
|
45537
|
+
}
|
|
45538
|
+
function leafKind(schema) {
|
|
45539
|
+
const s = unwrapSchema(schema);
|
|
45540
|
+
if (s instanceof zod.z.ZodEnum) return {
|
|
45541
|
+
kind: "enum",
|
|
45542
|
+
enumValues: s.options
|
|
45543
|
+
};
|
|
45544
|
+
if (s instanceof zod.z.ZodNumber) return { kind: "number" };
|
|
45545
|
+
if (s instanceof zod.z.ZodString) return { kind: "string" };
|
|
45546
|
+
if (s instanceof zod.z.ZodBoolean) return { kind: "boolean" };
|
|
45547
|
+
return null;
|
|
45548
|
+
}
|
|
45549
|
+
/** Walk a cap status schema into flat wireable leaf fields (dotted paths).
|
|
45550
|
+
* Recurses into nested ZodObject (unwrapping nullable/optional/default first),
|
|
45551
|
+
* so fields with null live values are still offered. Arrays / unknown shapes
|
|
45552
|
+
* are skipped — never throws. */
|
|
45553
|
+
function enumerateSchemaFields(schema, prefix = "") {
|
|
45554
|
+
const root = unwrapSchema(schema);
|
|
45555
|
+
if (!(root instanceof zod.z.ZodObject)) return [];
|
|
45556
|
+
const out = [];
|
|
45557
|
+
const shape = root.shape;
|
|
45558
|
+
for (const [key, field] of Object.entries(shape)) {
|
|
45559
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
45560
|
+
const inner = unwrapSchema(field);
|
|
45561
|
+
if (inner instanceof zod.z.ZodObject) {
|
|
45562
|
+
out.push(...enumerateSchemaFields(inner, path));
|
|
45563
|
+
continue;
|
|
45564
|
+
}
|
|
45565
|
+
const leaf = leafKind(field);
|
|
45566
|
+
if (leaf) out.push({
|
|
45567
|
+
path,
|
|
45568
|
+
kind: leaf.kind,
|
|
45569
|
+
...leaf.enumValues ? { enumValues: leaf.enumValues } : {}
|
|
45570
|
+
});
|
|
45571
|
+
}
|
|
45572
|
+
return out;
|
|
45573
|
+
}
|
|
45574
|
+
/** Enumerate the per-item wireable fields of an item-array cap (see
|
|
45575
|
+
* `CapabilityStatusItemArray`): the item schema's leaf fields, minus the
|
|
45576
|
+
* `keyField` (the key comes from the link's `itemKey`, never from a wired
|
|
45577
|
+
* source), each tagged `item: true` so the authoring UI collects an
|
|
45578
|
+
* `itemKey` alongside the field. Never throws. */
|
|
45579
|
+
function enumerateItemArrayFields(itemArray) {
|
|
45580
|
+
return enumerateSchemaFields(itemArray.itemSchema).filter((f) => f.path !== itemArray.keyField).map((f) => ({
|
|
45581
|
+
...f,
|
|
45582
|
+
item: true
|
|
45583
|
+
}));
|
|
45584
|
+
}
|
|
45585
|
+
//#endregion
|
|
45586
|
+
//#region src/composition/state-fields.ts
|
|
45587
|
+
/**
|
|
45588
|
+
* What a capability's state field IS: kind, nullability, whether required. The
|
|
45589
|
+
* validator needs nullability, which `enumerateSchemaFields` does not report,
|
|
45590
|
+
* and that decides a field's unavailable mode (D393).
|
|
45591
|
+
*/
|
|
45592
|
+
function fieldAt(schema, path) {
|
|
45593
|
+
let current = schema;
|
|
45594
|
+
for (const segment of path.split(".")) {
|
|
45595
|
+
const container = unwrapSchema(current);
|
|
45596
|
+
if (!(container instanceof zod.z.ZodObject)) return null;
|
|
45597
|
+
const next = container.shape[segment];
|
|
45598
|
+
if (!(next instanceof zod.z.ZodType)) return null;
|
|
45599
|
+
current = next;
|
|
45600
|
+
}
|
|
45601
|
+
return current;
|
|
45602
|
+
}
|
|
45603
|
+
function describeStateField(schema, path) {
|
|
45604
|
+
const leaf = enumerateSchemaFields(schema).find((f) => f.path === path);
|
|
45605
|
+
if (leaf === void 0) return null;
|
|
45606
|
+
const field = fieldAt(schema, path);
|
|
45607
|
+
if (field === null) return null;
|
|
45608
|
+
return {
|
|
45609
|
+
path,
|
|
45610
|
+
kind: leaf.kind,
|
|
45611
|
+
nullable: field.safeParse(null).success,
|
|
45612
|
+
required: !field.safeParse(void 0).success,
|
|
45613
|
+
...leaf.enumValues === void 0 ? {} : { enumValues: leaf.enumValues }
|
|
45614
|
+
};
|
|
45615
|
+
}
|
|
45616
|
+
function describeTopLevelStateFields(schema) {
|
|
45617
|
+
return new Map(enumerateSchemaFields(schema).filter((f) => !f.path.includes(".")).flatMap((f) => {
|
|
45618
|
+
const described = describeStateField(schema, f.path);
|
|
45619
|
+
return described === null ? [] : [[f.path, described]];
|
|
45620
|
+
}));
|
|
45621
|
+
}
|
|
45622
|
+
/** Top-level keys a value MUST carry: those whose schema refuses `undefined`. */
|
|
45623
|
+
function requiredTopLevelKeys(schema) {
|
|
45624
|
+
const root = unwrapSchema(schema);
|
|
45625
|
+
if (!(root instanceof zod.z.ZodObject)) return [];
|
|
45626
|
+
return Object.entries(root.shape).flatMap(([key, field]) => field instanceof zod.z.ZodType && !field.safeParse(void 0).success ? [key] : []);
|
|
45627
|
+
}
|
|
45628
|
+
//#endregion
|
|
45629
|
+
//#region src/composition/validate-composition.ts
|
|
45630
|
+
function buildCapabilityLookup(defs) {
|
|
45631
|
+
const byName = new Map(defs.map((d) => [d.name, d]));
|
|
45632
|
+
return (capName) => byName.get(capName) ?? null;
|
|
45633
|
+
}
|
|
45634
|
+
/** Caps every `BaseDevice` registers on itself; a second registration throws. */
|
|
45635
|
+
var BASE_DEVICE_CAPS = new Set(["device-status", "feature-probe"]);
|
|
45636
|
+
var PENDING_SELF = {
|
|
45637
|
+
addonId: COMPOSER_ADDON_ID,
|
|
45638
|
+
stableId: `${COMPOSED_DEVICE_STABLE_ID_PREFIX}(unsaved)`
|
|
45639
|
+
};
|
|
45640
|
+
function problem(code, path, message) {
|
|
45641
|
+
return {
|
|
45642
|
+
code,
|
|
45643
|
+
path,
|
|
45644
|
+
message
|
|
45645
|
+
};
|
|
45646
|
+
}
|
|
45647
|
+
function refused(...problems) {
|
|
45648
|
+
return {
|
|
45649
|
+
problems,
|
|
45650
|
+
fields: []
|
|
45651
|
+
};
|
|
45652
|
+
}
|
|
45653
|
+
function readKinds(read, lookupCap) {
|
|
45654
|
+
const def = lookupCap(read.cap);
|
|
45655
|
+
const schema = def?.runtimeState ?? def?.status?.schema;
|
|
45656
|
+
if (def === null || schema === void 0) return {
|
|
45657
|
+
ok: false,
|
|
45658
|
+
code: "source-field-unknown",
|
|
45659
|
+
message: `no capability \`${read.cap}\` with state to read`
|
|
45660
|
+
};
|
|
45661
|
+
const field = describeStateField(schema, read.fieldPath);
|
|
45662
|
+
if (field === null) return {
|
|
45663
|
+
ok: false,
|
|
45664
|
+
code: "source-field-unknown",
|
|
45665
|
+
message: `\`${read.cap}\` has no field \`${read.fieldPath}\``
|
|
45666
|
+
};
|
|
45667
|
+
const base = field.kind === "enum" ? "string" : field.kind;
|
|
45668
|
+
return {
|
|
45669
|
+
ok: true,
|
|
45670
|
+
kinds: new Set(field.nullable ? [base, "null"] : [base])
|
|
45671
|
+
};
|
|
45672
|
+
}
|
|
45673
|
+
function sourceKinds(source, lookupCap) {
|
|
45674
|
+
if (source.kind === "from") return readKinds(source, lookupCap);
|
|
45675
|
+
if (source.kind === "code") return {
|
|
45676
|
+
ok: false,
|
|
45677
|
+
code: "reserved-variant",
|
|
45678
|
+
message: "code fields arrive in slice 4"
|
|
45679
|
+
};
|
|
45680
|
+
const bindingKinds = /* @__PURE__ */ new Map();
|
|
45681
|
+
for (const [name, binding] of Object.entries(source.bindings)) {
|
|
45682
|
+
if (binding.kind === "literal") {
|
|
45683
|
+
bindingKinds.set(name, new Set([kindOfValue(binding.value)]));
|
|
45684
|
+
continue;
|
|
45685
|
+
}
|
|
45686
|
+
const kinds = readKinds(binding, lookupCap);
|
|
45687
|
+
if (!kinds.ok) return {
|
|
45688
|
+
...kinds,
|
|
45689
|
+
message: `binding \`${name}\`: ${kinds.message}`
|
|
45690
|
+
};
|
|
45691
|
+
bindingKinds.set(name, kinds.kinds);
|
|
45692
|
+
}
|
|
45693
|
+
const inferred = inferExpressionKinds({
|
|
45694
|
+
expr: source.expr,
|
|
45695
|
+
bindingKinds
|
|
45696
|
+
});
|
|
45697
|
+
return inferred.ok ? {
|
|
45698
|
+
ok: true,
|
|
45699
|
+
kinds: inferred.kinds
|
|
45700
|
+
} : {
|
|
45701
|
+
ok: false,
|
|
45702
|
+
code: "expression-invalid",
|
|
45703
|
+
message: inferred.error
|
|
45704
|
+
};
|
|
45705
|
+
}
|
|
45706
|
+
function compatibility(cap, target, kinds, at) {
|
|
45707
|
+
const allowed = target.kind === "enum" ? "string" : target.kind;
|
|
45708
|
+
const offending = [...kinds].filter((k) => k !== "null" && k !== allowed);
|
|
45709
|
+
const problems = [];
|
|
45710
|
+
if (offending.length > 0) problems.push(problem("kind-mismatch", at, `\`${cap}.${target.path}\` is a ${target.kind}; this source can produce ${offending.join(" or ")}`));
|
|
45711
|
+
if (kinds.has("null") && !target.nullable) problems.push(problem("may-be-null", at, `\`${cap}.${target.path}\` cannot be null and this source can produce null — wrap it in coalesce(…) or pick a non-null source`));
|
|
45712
|
+
return problems;
|
|
45713
|
+
}
|
|
45714
|
+
/**
|
|
45715
|
+
* A string a source produces WITHOUT reading any device — a field-level
|
|
45716
|
+
* `expression` source whose compiled AST is a bare string literal (`"red"`,
|
|
45717
|
+
* never `a` or `a + "x"`). Anything else that can only produce `'string'` at
|
|
45718
|
+
* the kind level (a `from` read of an enum-typed source field, a computed
|
|
45719
|
+
* expression) is NOT checked against the target's `enumValues` here: the
|
|
45720
|
+
* kind inference already collapsed it to the coarse `'string'` kind, losing
|
|
45721
|
+
* whichever enum it actually came from, so membership can only be judged at
|
|
45722
|
+
* write time against the runtime-state schema. Known limitation — see the
|
|
45723
|
+
* fix report for Task 6 round 1.
|
|
45724
|
+
*/
|
|
45725
|
+
function literalStringValue(source) {
|
|
45726
|
+
if (source.kind !== "expression") return null;
|
|
45727
|
+
const compiled = compileExpressionSafe(source.expr);
|
|
45728
|
+
if (!compiled.ok) return null;
|
|
45729
|
+
const ast = compiled.parsed.ast;
|
|
45730
|
+
return ast.kind === "literal" && typeof ast.value === "string" ? ast.value : null;
|
|
45731
|
+
}
|
|
45732
|
+
/**
|
|
45733
|
+
* An enum target whose source is a save-time-KNOWN string literal outside its
|
|
45734
|
+
* `enumValues` is refused now rather than left to fail the write later. A
|
|
45735
|
+
* dynamic source (a `from` read, a non-literal expression) is left to
|
|
45736
|
+
* runtime — see {@link literalStringValue}.
|
|
45737
|
+
*/
|
|
45738
|
+
function enumLiteralProblem(cap, target, source, at) {
|
|
45739
|
+
if (target.kind !== "enum" || target.enumValues === void 0) return null;
|
|
45740
|
+
const value = literalStringValue(source);
|
|
45741
|
+
if (value === null || target.enumValues.includes(value)) return null;
|
|
45742
|
+
const allowed = target.enumValues.map((v) => `\`${v}\``).join(", ");
|
|
45743
|
+
return problem("kind-mismatch", at, `\`${cap}.${target.path}\` accepts only ${allowed}; this source is the literal \`${value}\``);
|
|
45744
|
+
}
|
|
45745
|
+
function roleOf(source) {
|
|
45746
|
+
if (source.kind !== "expression") return "derived";
|
|
45747
|
+
if (fieldReads(source).length > 0) return "derived";
|
|
45748
|
+
const compiled = compileExpressionSafe(source.expr);
|
|
45749
|
+
return compiled.ok && compiled.parsed.identifiers.has("now") ? "clock" : "constant";
|
|
45750
|
+
}
|
|
45751
|
+
function planFeature(feature, featureIndex, target, lookupCap) {
|
|
45752
|
+
const at = `features[${featureIndex}]`;
|
|
45753
|
+
const def = lookupCap(feature.cap);
|
|
45754
|
+
if (def === null) return refused(problem("unknown-capability", `${at}.cap`, `no capability is named \`${feature.cap}\``));
|
|
45755
|
+
if (BASE_DEVICE_CAPS.has(def.name)) return refused(problem("not-composable", `${at}.cap`, `\`${def.name}\` is registered by every device itself — it cannot be composed`));
|
|
45756
|
+
const state = def.runtimeState;
|
|
45757
|
+
if (def.scope !== "device" || state === void 0) return refused(problem("not-composable", `${at}.cap`, `\`${def.name}\` has no per-device state to compose`));
|
|
45758
|
+
const capProblems = [];
|
|
45759
|
+
if (def.deviceTypes !== void 0 && !def.deviceTypes.includes(target.type)) capProblems.push(problem("wrong-device-type", `${at}.cap`, `\`${def.name}\` is not offered on a \`${target.type}\` device (it allows ${def.deviceTypes.join(", ")})`));
|
|
45760
|
+
const served = Object.entries(def.methods).filter(([, m]) => m.systemOnly !== true).map(([name]) => `\`${name}\``);
|
|
45761
|
+
if (served.length > 0) capProblems.push(problem("has-commands", `${at}.cap`, `\`${def.name}\` has ${served.join(", ")}, which a composed device cannot serve until commands arrive (slice 3)`));
|
|
45762
|
+
if (feature.commands !== void 0 && Object.keys(feature.commands).length > 0) capProblems.push(problem("reserved-variant", `${at}.commands`, "commands (`forward`) arrive in slice 3"));
|
|
45763
|
+
const targetFields = describeTopLevelStateFields(state);
|
|
45764
|
+
for (const key of requiredTopLevelKeys(state)) if (!targetFields.has(key)) capProblems.push(problem("not-composable", `${at}.fields`, `\`${def.name}.${key}\` is not a scalar — nested fields arrive in a later slice`));
|
|
45765
|
+
else if (!(key in feature.fields)) capProblems.push(problem("missing-field", `${at}.fields.${key}`, `\`${def.name}.${key}\` is required and has no source`));
|
|
45766
|
+
const perField = Object.entries(feature.fields).map(([path, source]) => {
|
|
45767
|
+
const fieldAt = `${at}.fields.${path}`;
|
|
45768
|
+
if (path.includes(".")) return refused(problem("nested-field", fieldAt, `\`${path}\` is nested — nested fields arrive in a later slice`));
|
|
45769
|
+
const tf = targetFields.get(path);
|
|
45770
|
+
if (tf === void 0) return refused(problem("unknown-field", fieldAt, `\`${def.name}\` has no field \`${path}\``));
|
|
45771
|
+
const kinds = sourceKinds(source, lookupCap);
|
|
45772
|
+
if (!kinds.ok) return refused(problem(kinds.code, fieldAt, kinds.message));
|
|
45773
|
+
const plan = {
|
|
45774
|
+
cap: def.name,
|
|
45775
|
+
path,
|
|
45776
|
+
featureIndex,
|
|
45777
|
+
kind: tf.kind,
|
|
45778
|
+
nullable: tf.nullable,
|
|
45779
|
+
required: tf.required,
|
|
45780
|
+
unavailable: tf.nullable ? "null" : "offline",
|
|
45781
|
+
role: roleOf(source),
|
|
45782
|
+
source,
|
|
45783
|
+
reads: [...fieldReads(source)]
|
|
45784
|
+
};
|
|
45785
|
+
const enumProblem = enumLiteralProblem(def.name, tf, source, fieldAt);
|
|
45786
|
+
return {
|
|
45787
|
+
problems: [...compatibility(def.name, tf, kinds.kinds, fieldAt), ...enumProblem === null ? [] : [enumProblem]],
|
|
45788
|
+
fields: [plan]
|
|
45789
|
+
};
|
|
45790
|
+
});
|
|
45791
|
+
return {
|
|
45792
|
+
problems: [...capProblems, ...perField.flatMap((r) => r.problems)],
|
|
45793
|
+
fields: perField.flatMap((r) => r.fields)
|
|
45794
|
+
};
|
|
45795
|
+
}
|
|
45796
|
+
function planComposition(composition, lookupCap) {
|
|
45797
|
+
const target = composition.target;
|
|
45798
|
+
if (target.kind === "existing") return refused(problem("reserved-variant", "target", "an EXISTING device as the target arrives in slice 2 — this release composes new devices only"));
|
|
45799
|
+
const results = composition.features.map((feature, index) => {
|
|
45800
|
+
const at = `features[${index}]`;
|
|
45801
|
+
if (feature.kind === "passthrough") return refused(problem("reserved-variant", at, `whole-capability passthrough of \`${feature.cap}\` arrives in slice 3`));
|
|
45802
|
+
return planFeature(feature, index, target, lookupCap);
|
|
45803
|
+
});
|
|
45804
|
+
return {
|
|
45805
|
+
problems: results.flatMap((r) => r.problems),
|
|
45806
|
+
fields: results.flatMap((r) => r.fields)
|
|
45807
|
+
};
|
|
45808
|
+
}
|
|
45809
|
+
function compositionSourceRefs(composition) {
|
|
45810
|
+
const refs = composition.features.flatMap((f) => f.kind === "fields" ? Object.values(f.fields).flatMap(fieldReads).map((r) => r.source) : []);
|
|
45811
|
+
return [...new Map(refs.map((r) => [compositionSourceKey(r), r])).values()];
|
|
45812
|
+
}
|
|
45813
|
+
function sourceProblems(fields, ctx) {
|
|
45814
|
+
const selfKey = ctx.self === null ? null : compositionSourceKey(ctx.self);
|
|
45815
|
+
return fields.flatMap((field) => field.reads.flatMap((read) => {
|
|
45816
|
+
const at = `features[${field.featureIndex}].fields.${field.path}`;
|
|
45817
|
+
const key = compositionSourceKey(read.source);
|
|
45818
|
+
if (key === selfKey) return fields.some((f) => f.cap === read.cap && f.path === read.fieldPath) ? [] : [problem("source-field-unknown", at, `this device has no composed field \`${read.cap}.${read.fieldPath}\``)];
|
|
45819
|
+
const desc = ctx.sources.get(key);
|
|
45820
|
+
if (desc === void 0 || desc.kind === "unreadable") return [problem("source-unreadable", at, `could not read source \`${key}\` (${desc === void 0 ? "it was not read" : desc.error}) — the save is refused rather than stored unchecked`)];
|
|
45821
|
+
if (desc.kind === "absent") return [problem("source-missing", at, `source \`${key}\` does not exist`)];
|
|
45822
|
+
if (!desc.caps.has(read.cap)) return [problem("source-capability-missing", at, `source \`${key}\` (device ${desc.deviceId}) has no \`${read.cap}\``)];
|
|
45823
|
+
return [];
|
|
45824
|
+
}));
|
|
45825
|
+
}
|
|
45826
|
+
/**
|
|
45827
|
+
* A cycle's node keys are `compositionReadKey` strings:
|
|
45828
|
+
* `<addonId>/<stableId>#<cap>.<fieldPath>`. When a node belongs to the
|
|
45829
|
+
* CANDIDATE itself (this composition being saved), pull its `cap`/`fieldPath`
|
|
45830
|
+
* back out so the refusal can point at that exact field, matching the
|
|
45831
|
+
* documented `features[N].fields.<path>` convention — slice 1 has no nested
|
|
45832
|
+
* field writes, so splitting `rest` on the FIRST `.` is exact.
|
|
45833
|
+
*/
|
|
45834
|
+
function candidateFieldOfNode(nodeKey, candidateKey) {
|
|
45835
|
+
const prefix = `${candidateKey}#`;
|
|
45836
|
+
if (!nodeKey.startsWith(prefix)) return null;
|
|
45837
|
+
const rest = nodeKey.slice(prefix.length);
|
|
45838
|
+
const dot = rest.indexOf(".");
|
|
45839
|
+
if (dot === -1) return null;
|
|
45840
|
+
return {
|
|
45841
|
+
cap: rest.slice(0, dot),
|
|
45842
|
+
fieldPath: rest.slice(dot + 1)
|
|
45843
|
+
};
|
|
45844
|
+
}
|
|
45845
|
+
/** The first node of a cycle's path that is one of THIS composition's own
|
|
45846
|
+
* planned fields, as a documented-convention path; `'features'` when the
|
|
45847
|
+
* cycle runs entirely through other stored compositions. */
|
|
45848
|
+
function cyclePath(nodePath, candidateKey, fields) {
|
|
45849
|
+
for (const nodeKey of nodePath) {
|
|
45850
|
+
const hit = candidateFieldOfNode(nodeKey, candidateKey);
|
|
45851
|
+
if (hit === null) continue;
|
|
45852
|
+
const field = fields.find((f) => f.cap === hit.cap && f.path === hit.fieldPath);
|
|
45853
|
+
if (field !== void 0) return `features[${field.featureIndex}].fields.${field.path}`;
|
|
45854
|
+
}
|
|
45855
|
+
return "features";
|
|
45856
|
+
}
|
|
45857
|
+
/**
|
|
45858
|
+
* Cycle check runs against the CANDIDATE (this composition, targeting `self`
|
|
45859
|
+
* when it already exists, else a placeholder that cannot collide with a
|
|
45860
|
+
* stored target) plus every OTHER stored composition. Two stored peers that
|
|
45861
|
+
* (wrongly) share a target are corrupted state — `findCompositionCycles`
|
|
45862
|
+
* throws `CompositionGraphError` rather than silently picking one, and this
|
|
45863
|
+
* is refused BY NAME (D391) instead of escaping as an uncaught throw.
|
|
45864
|
+
*/
|
|
45865
|
+
function cycleProblems(composition, ctx, fields) {
|
|
45866
|
+
const candidate = {
|
|
45867
|
+
target: ctx.self ?? PENDING_SELF,
|
|
45868
|
+
composition
|
|
45869
|
+
};
|
|
45870
|
+
const candidateKey = compositionSourceKey(candidate.target);
|
|
45871
|
+
try {
|
|
45872
|
+
return findCompositionCycles(candidate, ctx.peers).map((c) => problem("cycle", cyclePath(c.path, candidateKey, fields), `a field reads itself: ${c.path.join(" → ")}`));
|
|
45873
|
+
} catch (err) {
|
|
45874
|
+
if (err instanceof CompositionGraphError) return [problem("duplicate-target", "features", err.message)];
|
|
45875
|
+
throw err;
|
|
45876
|
+
}
|
|
45877
|
+
}
|
|
45878
|
+
function validateComposition(composition, ctx) {
|
|
45879
|
+
const plan = planComposition(composition, ctx.lookupCap);
|
|
45880
|
+
const cycles = cycleProblems(composition, ctx, plan.fields);
|
|
45881
|
+
const problems = [
|
|
45882
|
+
...plan.problems,
|
|
45883
|
+
...sourceProblems(plan.fields, ctx),
|
|
45884
|
+
...cycles
|
|
45885
|
+
];
|
|
45886
|
+
return {
|
|
45887
|
+
ok: problems.length === 0,
|
|
45888
|
+
problems,
|
|
45889
|
+
fields: [...plan.fields]
|
|
45890
|
+
};
|
|
45891
|
+
}
|
|
45892
|
+
//#endregion
|
|
44662
45893
|
//#region src/catalogs/device-state-vocabulary.ts
|
|
44663
45894
|
/**
|
|
44664
45895
|
* Most specific first. Extending this list is how a new device kind becomes
|
|
@@ -48811,62 +50042,6 @@ function createRuntimeStateBridge(params) {
|
|
|
48811
50042
|
};
|
|
48812
50043
|
}
|
|
48813
50044
|
//#endregion
|
|
48814
|
-
//#region src/device/schema-fields.ts
|
|
48815
|
-
/** Unwrap ZodNullable / ZodOptional / ZodDefault wrappers to reach the inner type.
|
|
48816
|
-
* Zod v4 exposes `.unwrap()` on all three wrapper classes. */
|
|
48817
|
-
function unwrap(schema) {
|
|
48818
|
-
let s = schema;
|
|
48819
|
-
while (s instanceof zod.z.ZodNullable || s instanceof zod.z.ZodOptional || s instanceof zod.z.ZodDefault) s = s.unwrap();
|
|
48820
|
-
return s;
|
|
48821
|
-
}
|
|
48822
|
-
function leafKind(schema) {
|
|
48823
|
-
const s = unwrap(schema);
|
|
48824
|
-
if (s instanceof zod.z.ZodEnum) return {
|
|
48825
|
-
kind: "enum",
|
|
48826
|
-
enumValues: s.options
|
|
48827
|
-
};
|
|
48828
|
-
if (s instanceof zod.z.ZodNumber) return { kind: "number" };
|
|
48829
|
-
if (s instanceof zod.z.ZodString) return { kind: "string" };
|
|
48830
|
-
if (s instanceof zod.z.ZodBoolean) return { kind: "boolean" };
|
|
48831
|
-
return null;
|
|
48832
|
-
}
|
|
48833
|
-
/** Walk a cap status schema into flat wireable leaf fields (dotted paths).
|
|
48834
|
-
* Recurses into nested ZodObject (unwrapping nullable/optional/default first),
|
|
48835
|
-
* so fields with null live values are still offered. Arrays / unknown shapes
|
|
48836
|
-
* are skipped — never throws. */
|
|
48837
|
-
function enumerateSchemaFields(schema, prefix = "") {
|
|
48838
|
-
const root = unwrap(schema);
|
|
48839
|
-
if (!(root instanceof zod.z.ZodObject)) return [];
|
|
48840
|
-
const out = [];
|
|
48841
|
-
const shape = root.shape;
|
|
48842
|
-
for (const [key, field] of Object.entries(shape)) {
|
|
48843
|
-
const path = prefix ? `${prefix}.${key}` : key;
|
|
48844
|
-
const inner = unwrap(field);
|
|
48845
|
-
if (inner instanceof zod.z.ZodObject) {
|
|
48846
|
-
out.push(...enumerateSchemaFields(inner, path));
|
|
48847
|
-
continue;
|
|
48848
|
-
}
|
|
48849
|
-
const leaf = leafKind(field);
|
|
48850
|
-
if (leaf) out.push({
|
|
48851
|
-
path,
|
|
48852
|
-
kind: leaf.kind,
|
|
48853
|
-
...leaf.enumValues ? { enumValues: leaf.enumValues } : {}
|
|
48854
|
-
});
|
|
48855
|
-
}
|
|
48856
|
-
return out;
|
|
48857
|
-
}
|
|
48858
|
-
/** Enumerate the per-item wireable fields of an item-array cap (see
|
|
48859
|
-
* `CapabilityStatusItemArray`): the item schema's leaf fields, minus the
|
|
48860
|
-
* `keyField` (the key comes from the link's `itemKey`, never from a wired
|
|
48861
|
-
* source), each tagged `item: true` so the authoring UI collects an
|
|
48862
|
-
* `itemKey` alongside the field. Never throws. */
|
|
48863
|
-
function enumerateItemArrayFields(itemArray) {
|
|
48864
|
-
return enumerateSchemaFields(itemArray.itemSchema).filter((f) => f.path !== itemArray.keyField).map((f) => ({
|
|
48865
|
-
...f,
|
|
48866
|
-
item: true
|
|
48867
|
-
}));
|
|
48868
|
-
}
|
|
48869
|
-
//#endregion
|
|
48870
50045
|
//#region src/device/system-mirror.ts
|
|
48871
50046
|
var STATE_CHANGED_CATEGORY = "device.state-changed";
|
|
48872
50047
|
var BINDING_CHANGED_CATEGORY = "capability.binding-changed";
|
|
@@ -49759,6 +50934,7 @@ var CAPABILITY_NAMES = {
|
|
|
49759
50934
|
carbonMonoxide: "carbon-monoxide",
|
|
49760
50935
|
climateControl: "climate-control",
|
|
49761
50936
|
color: "color",
|
|
50937
|
+
composer: "composer",
|
|
49762
50938
|
connectionTest: "connection-test",
|
|
49763
50939
|
connectivity: "connectivity",
|
|
49764
50940
|
consumables: "consumables",
|
|
@@ -50019,6 +51195,10 @@ var CAPABILITY_ROUTER_KEYS = [
|
|
|
50019
51195
|
key: "color",
|
|
50020
51196
|
name: "color"
|
|
50021
51197
|
},
|
|
51198
|
+
{
|
|
51199
|
+
key: "composer",
|
|
51200
|
+
name: "composer"
|
|
51201
|
+
},
|
|
50022
51202
|
{
|
|
50023
51203
|
key: "connectionTest",
|
|
50024
51204
|
name: "connection-test"
|
|
@@ -50578,6 +51758,7 @@ var ALL_CAPABILITY_DEFINITIONS = [
|
|
|
50578
51758
|
carbonMonoxideCapability,
|
|
50579
51759
|
climateControlCapability,
|
|
50580
51760
|
colorCapability,
|
|
51761
|
+
composerCapability,
|
|
50581
51762
|
connectionTestCapability,
|
|
50582
51763
|
connectivityCapability,
|
|
50583
51764
|
consumablesCapability,
|
|
@@ -51653,6 +52834,18 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
51653
52834
|
addonId: null,
|
|
51654
52835
|
access: "create"
|
|
51655
52836
|
},
|
|
52837
|
+
"composer.applyBlocks": {
|
|
52838
|
+
capName: "composer",
|
|
52839
|
+
capScope: "system",
|
|
52840
|
+
addonId: null,
|
|
52841
|
+
access: "create"
|
|
52842
|
+
},
|
|
52843
|
+
"composer.getStates": {
|
|
52844
|
+
capName: "composer",
|
|
52845
|
+
capScope: "system",
|
|
52846
|
+
addonId: null,
|
|
52847
|
+
access: "view"
|
|
52848
|
+
},
|
|
51656
52849
|
"connectionTest.describeTest": {
|
|
51657
52850
|
capName: "connection-test",
|
|
51658
52851
|
capScope: "system",
|
|
@@ -51713,6 +52906,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
51713
52906
|
addonId: null,
|
|
51714
52907
|
access: "create"
|
|
51715
52908
|
},
|
|
52909
|
+
"coreBlocks.createComposition": {
|
|
52910
|
+
capName: "core-blocks",
|
|
52911
|
+
capScope: "system",
|
|
52912
|
+
addonId: null,
|
|
52913
|
+
access: "create"
|
|
52914
|
+
},
|
|
51716
52915
|
"coreBlocks.delete": {
|
|
51717
52916
|
capName: "core-blocks",
|
|
51718
52917
|
capScope: "system",
|
|
@@ -51725,6 +52924,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
51725
52924
|
addonId: null,
|
|
51726
52925
|
access: "view"
|
|
51727
52926
|
},
|
|
52927
|
+
"coreBlocks.getComposition": {
|
|
52928
|
+
capName: "core-blocks",
|
|
52929
|
+
capScope: "system",
|
|
52930
|
+
addonId: null,
|
|
52931
|
+
access: "view"
|
|
52932
|
+
},
|
|
51728
52933
|
"coreBlocks.getTypeDefs": {
|
|
51729
52934
|
capName: "core-blocks",
|
|
51730
52935
|
capScope: "system",
|
|
@@ -51737,6 +52942,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
51737
52942
|
addonId: null,
|
|
51738
52943
|
access: "view"
|
|
51739
52944
|
},
|
|
52945
|
+
"coreBlocks.listCompositions": {
|
|
52946
|
+
capName: "core-blocks",
|
|
52947
|
+
capScope: "system",
|
|
52948
|
+
addonId: null,
|
|
52949
|
+
access: "view"
|
|
52950
|
+
},
|
|
51740
52951
|
"coreBlocks.restart": {
|
|
51741
52952
|
capName: "core-blocks",
|
|
51742
52953
|
capScope: "system",
|
|
@@ -51755,6 +52966,18 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
51755
52966
|
addonId: null,
|
|
51756
52967
|
access: "create"
|
|
51757
52968
|
},
|
|
52969
|
+
"coreBlocks.updateComposition": {
|
|
52970
|
+
capName: "core-blocks",
|
|
52971
|
+
capScope: "system",
|
|
52972
|
+
addonId: null,
|
|
52973
|
+
access: "create"
|
|
52974
|
+
},
|
|
52975
|
+
"coreBlocks.validateComposition": {
|
|
52976
|
+
capName: "core-blocks",
|
|
52977
|
+
capScope: "system",
|
|
52978
|
+
addonId: null,
|
|
52979
|
+
access: "view"
|
|
52980
|
+
},
|
|
51758
52981
|
"cover.close": {
|
|
51759
52982
|
capName: "cover",
|
|
51760
52983
|
capScope: "device",
|
|
@@ -57814,6 +59037,7 @@ var KNOWN_CAP_NAMES = [
|
|
|
57814
59037
|
"carbon-monoxide",
|
|
57815
59038
|
"climate-control",
|
|
57816
59039
|
"color",
|
|
59040
|
+
"composer",
|
|
57817
59041
|
"connection-test",
|
|
57818
59042
|
"connectivity",
|
|
57819
59043
|
"consumables",
|
|
@@ -58051,6 +59275,7 @@ var SYSTEM_CAP_NAMES = [
|
|
|
58051
59275
|
"auth-provider",
|
|
58052
59276
|
"backup",
|
|
58053
59277
|
"broker",
|
|
59278
|
+
"composer",
|
|
58054
59279
|
"connection-test",
|
|
58055
59280
|
"core-blocks",
|
|
58056
59281
|
"custom-model-registry",
|
|
@@ -60876,7 +62101,12 @@ function createSystemProxy(api) {
|
|
|
60876
62101
|
setEnabled: (input) => dispatch("coreBlocks", "setEnabled", "mutation", input),
|
|
60877
62102
|
restart: (input) => dispatch("coreBlocks", "restart", "mutation", input),
|
|
60878
62103
|
compile: (input) => dispatch("coreBlocks", "compile", "mutation", input),
|
|
60879
|
-
getTypeDefs: (input) => dispatch("coreBlocks", "getTypeDefs", "query", input)
|
|
62104
|
+
getTypeDefs: (input) => dispatch("coreBlocks", "getTypeDefs", "query", input),
|
|
62105
|
+
createComposition: (input) => dispatch("coreBlocks", "createComposition", "mutation", input),
|
|
62106
|
+
updateComposition: (input) => dispatch("coreBlocks", "updateComposition", "mutation", input),
|
|
62107
|
+
getComposition: (input) => dispatch("coreBlocks", "getComposition", "query", input),
|
|
62108
|
+
listCompositions: (input) => dispatch("coreBlocks", "listCompositions", "query", input),
|
|
62109
|
+
validateComposition: (input) => dispatch("coreBlocks", "validateComposition", "mutation", input)
|
|
60880
62110
|
},
|
|
60881
62111
|
decoder: {
|
|
60882
62112
|
supportsCodec: (input) => dispatch("decoder", "supportsCodec", "query", input),
|
|
@@ -67113,11 +68343,13 @@ exports.AutomationControlStatusSchema = AutomationControlStatusSchema;
|
|
|
67113
68343
|
exports.AutomationRecipeSchema = AutomationRecipeSchema;
|
|
67114
68344
|
exports.AutomationTriggerSchema = AutomationTriggerSchema;
|
|
67115
68345
|
exports.AvailableIntegrationTypeSchema = AvailableIntegrationTypeSchema;
|
|
68346
|
+
exports.BASE_DEVICE_CAPS = BASE_DEVICE_CAPS;
|
|
67116
68347
|
exports.BASE_LIVE_EGRESS_PROFILE = BASE_LIVE_EGRESS_PROFILE;
|
|
67117
68348
|
exports.BATTERY_DEVICE_PROFILE = BATTERY_DEVICE_PROFILE;
|
|
67118
68349
|
exports.BATTERY_UNREACHABLE_AFTER_MS = BATTERY_UNREACHABLE_AFTER_MS;
|
|
67119
68350
|
exports.BIRTH_DECISION_DEFAULT_LIMIT = BIRTH_DECISION_DEFAULT_LIMIT;
|
|
67120
68351
|
exports.BOOT_RECOVERY_BACKOFF_MS = require_sleep.BOOT_RECOVERY_BACKOFF_MS;
|
|
68352
|
+
exports.BUILTIN_RESULT_KINDS = BUILTIN_RESULT_KINDS;
|
|
67121
68353
|
exports.BackgroundRunRegistry = BackgroundRunRegistry;
|
|
67122
68354
|
exports.BacklightModeSchema = BacklightModeSchema;
|
|
67123
68355
|
exports.BackupDestinationInfoSchema = BackupDestinationInfoSchema;
|
|
@@ -67185,6 +68417,9 @@ exports.CLUSTER_MODEL_SECTION_ID = CLUSTER_MODEL_SECTION_ID;
|
|
|
67185
68417
|
exports.CLUSTER_STEP_SETTING_FIELDS = CLUSTER_STEP_SETTING_FIELDS;
|
|
67186
68418
|
exports.COCO_80_LABELS = COCO_80_LABELS;
|
|
67187
68419
|
exports.COCO_TO_MACRO = COCO_TO_MACRO;
|
|
68420
|
+
exports.COMPOSED_DEVICE_STABLE_ID_PREFIX = COMPOSED_DEVICE_STABLE_ID_PREFIX;
|
|
68421
|
+
exports.COMPOSER_ADDON_ID = COMPOSER_ADDON_ID;
|
|
68422
|
+
exports.COMPOSER_RUNNER_ID = COMPOSER_RUNNER_ID;
|
|
67188
68423
|
exports.CONNECTION_TEST_TIMEOUT_MS = CONNECTION_TEST_TIMEOUT_MS;
|
|
67189
68424
|
exports.CONTAINER_CHILD_PRIORITY = CONTAINER_CHILD_PRIORITY;
|
|
67190
68425
|
exports.CORE_BLOCKS_ADDON_ID = CORE_BLOCKS_ADDON_ID;
|
|
@@ -67253,6 +68488,45 @@ exports.ClusterModelChoiceSchema = ClusterModelChoiceSchema;
|
|
|
67253
68488
|
exports.CollectionColumnSchema = CollectionColumnSchema;
|
|
67254
68489
|
exports.CollectionIndexSchema = CollectionIndexSchema;
|
|
67255
68490
|
exports.ColorStatusSchema = ColorStatusSchema;
|
|
68491
|
+
exports.ComposerApplyInputSchema = ComposerApplyInputSchema;
|
|
68492
|
+
exports.ComposerApplyResultSchema = ComposerApplyResultSchema;
|
|
68493
|
+
exports.ComposerBlockSchema = ComposerBlockSchema;
|
|
68494
|
+
exports.ComposerBlockVerdictSchema = ComposerBlockVerdictSchema;
|
|
68495
|
+
exports.ComposerUnreadableBlockSchema = ComposerUnreadableBlockSchema;
|
|
68496
|
+
exports.CompositionBindingSchema = CompositionBindingSchema;
|
|
68497
|
+
exports.CompositionBlockInputSchema = CompositionBlockInputSchema;
|
|
68498
|
+
exports.CompositionBlockStateSchema = CompositionBlockStateSchema;
|
|
68499
|
+
exports.CompositionCodeSourceSchema = CompositionCodeSourceSchema;
|
|
68500
|
+
exports.CompositionCommandTargetSchema = CompositionCommandTargetSchema;
|
|
68501
|
+
exports.CompositionExistingTargetSchema = CompositionExistingTargetSchema;
|
|
68502
|
+
exports.CompositionExpressionSourceSchema = CompositionExpressionSourceSchema;
|
|
68503
|
+
exports.CompositionFeatureSchema = CompositionFeatureSchema;
|
|
68504
|
+
exports.CompositionFieldKindSchema = CompositionFieldKindSchema;
|
|
68505
|
+
exports.CompositionFieldPlanSchema = CompositionFieldPlanSchema;
|
|
68506
|
+
exports.CompositionFieldReadSchema = CompositionFieldReadSchema;
|
|
68507
|
+
exports.CompositionFieldRoleSchema = CompositionFieldRoleSchema;
|
|
68508
|
+
exports.CompositionFieldSourceSchema = CompositionFieldSourceSchema;
|
|
68509
|
+
exports.CompositionFieldStateKindSchema = CompositionFieldStateKindSchema;
|
|
68510
|
+
exports.CompositionFieldStateSchema = CompositionFieldStateSchema;
|
|
68511
|
+
exports.CompositionFieldsFeatureSchema = CompositionFieldsFeatureSchema;
|
|
68512
|
+
exports.CompositionForwardCommandSchema = CompositionForwardCommandSchema;
|
|
68513
|
+
exports.CompositionFromSourceSchema = CompositionFromSourceSchema;
|
|
68514
|
+
exports.CompositionGetReadSchema = CompositionGetReadSchema;
|
|
68515
|
+
exports.CompositionGraphError = CompositionGraphError;
|
|
68516
|
+
exports.CompositionListReadSchema = CompositionListReadSchema;
|
|
68517
|
+
exports.CompositionLiteralBindingSchema = CompositionLiteralBindingSchema;
|
|
68518
|
+
exports.CompositionNewTargetSchema = CompositionNewTargetSchema;
|
|
68519
|
+
exports.CompositionPassthroughFeatureSchema = CompositionPassthroughFeatureSchema;
|
|
68520
|
+
exports.CompositionProblemCodeSchema = CompositionProblemCodeSchema;
|
|
68521
|
+
exports.CompositionProblemSchema = CompositionProblemSchema;
|
|
68522
|
+
exports.CompositionRunStatusSchema = CompositionRunStatusSchema;
|
|
68523
|
+
exports.CompositionSchema = CompositionSchema;
|
|
68524
|
+
exports.CompositionSourceRefSchema = CompositionSourceRefSchema;
|
|
68525
|
+
exports.CompositionStateReadSchema = CompositionStateReadSchema;
|
|
68526
|
+
exports.CompositionTargetSchema = CompositionTargetSchema;
|
|
68527
|
+
exports.CompositionUnavailableModeSchema = CompositionUnavailableModeSchema;
|
|
68528
|
+
exports.CompositionValidationSchema = CompositionValidationSchema;
|
|
68529
|
+
exports.CompositionViewSchema = CompositionViewSchema;
|
|
67256
68530
|
exports.ConfigEntrySchema = ConfigEntrySchema;
|
|
67257
68531
|
exports.ConfigSectionWithValuesSchema = ConfigSectionWithValuesSchema;
|
|
67258
68532
|
exports.ConfigTabDeclarationSchema = ConfigTabDeclarationSchema;
|
|
@@ -67272,6 +68546,7 @@ exports.CoreBlockCompileResultSchema = CoreBlockCompileResultSchema;
|
|
|
67272
68546
|
exports.CoreBlockInputSchema = CoreBlockInputSchema;
|
|
67273
68547
|
exports.CoreBlockPlacementSchema = CoreBlockPlacementSchema;
|
|
67274
68548
|
exports.CoreBlockSchema = CoreBlockSchema;
|
|
68549
|
+
exports.CoreBlockSourceSchema = CoreBlockSourceSchema;
|
|
67275
68550
|
exports.CoreBlockStatusSchema = CoreBlockStatusSchema;
|
|
67276
68551
|
exports.CoverStateSchema = CoverStateSchema;
|
|
67277
68552
|
exports.CoverStatusSchema = CoverStatusSchema;
|
|
@@ -67604,6 +68879,9 @@ exports.MAX_BIRTH_DECISION_RECORDS = MAX_BIRTH_DECISION_RECORDS;
|
|
|
67604
68879
|
exports.MAX_BIRTH_LATENCY_PROXY_MS = MAX_BIRTH_LATENCY_PROXY_MS;
|
|
67605
68880
|
exports.MAX_CLIP_EVENT_IDS = MAX_CLIP_EVENT_IDS;
|
|
67606
68881
|
exports.MAX_CLIP_LABELS = MAX_CLIP_LABELS;
|
|
68882
|
+
exports.MAX_COMPOSITION_CODE_LENGTH = MAX_COMPOSITION_CODE_LENGTH;
|
|
68883
|
+
exports.MAX_COMPOSITION_FEATURES = MAX_COMPOSITION_FEATURES;
|
|
68884
|
+
exports.MAX_COMPOSITION_FIELDS_PER_FEATURE = MAX_COMPOSITION_FIELDS_PER_FEATURE;
|
|
67607
68885
|
exports.MAX_CONDITION_DEPTH = MAX_CONDITION_DEPTH;
|
|
67608
68886
|
exports.MAX_CONDITION_LEAVES = MAX_CONDITION_LEAVES;
|
|
67609
68887
|
exports.MAX_EXPRESSION_AST_NODES = MAX_EXPRESSION_AST_NODES;
|
|
@@ -67621,6 +68899,7 @@ exports.METHOD_ACCESS_MAP = METHOD_ACCESS_MAP;
|
|
|
67621
68899
|
exports.METHOD_DEVICE_SELECTORS = METHOD_DEVICE_SELECTORS;
|
|
67622
68900
|
exports.MINUTES_PER_DAY = MINUTES_PER_DAY;
|
|
67623
68901
|
exports.MODEL_FORMATS = MODEL_FORMATS;
|
|
68902
|
+
exports.MODEL_HOSTING = MODEL_HOSTING;
|
|
67624
68903
|
exports.MODEL_PROVIDER_IDS = MODEL_PROVIDER_IDS;
|
|
67625
68904
|
exports.MOTION_CLOSE_AFTER_MS = MOTION_CLOSE_AFTER_MS;
|
|
67626
68905
|
exports.MOTION_TRIGGER_FEATURE = MOTION_TRIGGER_FEATURE;
|
|
@@ -67660,6 +68939,7 @@ exports.ModelDistributeResultSchema = ModelDistributeResultSchema;
|
|
|
67660
68939
|
exports.ModelExtraFileSchema = ModelExtraFileSchema;
|
|
67661
68940
|
exports.ModelFormatEntrySchema = ModelFormatEntrySchema;
|
|
67662
68941
|
exports.ModelFormatsSchema = ModelFormatsSchema;
|
|
68942
|
+
exports.ModelLicenseSchema = ModelLicenseSchema;
|
|
67663
68943
|
exports.ModelProviderIdSchema = ModelProviderIdSchema;
|
|
67664
68944
|
exports.ModelSubstitutionSchema = ModelSubstitutionSchema;
|
|
67665
68945
|
exports.ModelVariantGroupSchema = ModelVariantGroupSchema;
|
|
@@ -67968,6 +69248,9 @@ exports.REDACTED_SECRET = REDACTED_SECRET;
|
|
|
67968
69248
|
exports.RESERVED_BINDING_NAMES = RESERVED_BINDING_NAMES;
|
|
67969
69249
|
exports.RESERVED_COLLECTION_SOURCES = RESERVED_COLLECTION_SOURCES;
|
|
67970
69250
|
exports.RESTORED_CAP_NAMES = RESTORED_CAP_NAMES;
|
|
69251
|
+
exports.ROOM_EXAMPLE_MOTION_SOURCES = ROOM_EXAMPLE_MOTION_SOURCES;
|
|
69252
|
+
exports.ROOM_EXAMPLE_TEMPERATURE_SOURCES = ROOM_EXAMPLE_TEMPERATURE_SOURCES;
|
|
69253
|
+
exports.ROOM_OCCUPANCY_WINDOW_MS = ROOM_OCCUPANCY_WINDOW_MS;
|
|
67971
69254
|
exports.ROOT_BUCKET_KEY = ROOT_BUCKET_KEY;
|
|
67972
69255
|
exports.RUNTIME_DEFAULTS = RUNTIME_DEFAULTS;
|
|
67973
69256
|
exports.RUNTIME_STATE_POLICY = RUNTIME_STATE_POLICY;
|
|
@@ -68365,6 +69648,7 @@ exports.brightnessCapability = brightnessCapability;
|
|
|
68365
69648
|
exports.brokerCapability = brokerCapability;
|
|
68366
69649
|
exports.buildAddonRouteProvider = buildAddonRouteProvider;
|
|
68367
69650
|
exports.buildAudioArgs = require_canonical_hash.buildAudioArgs;
|
|
69651
|
+
exports.buildCapabilityLookup = buildCapabilityLookup;
|
|
68368
69652
|
exports.buildDeviceAdminUrl = buildDeviceAdminUrl;
|
|
68369
69653
|
exports.buildEventKindDescriptor = buildEventKindDescriptor;
|
|
68370
69654
|
exports.buildFfmpegArgs = require_canonical_hash.buildFfmpegArgs;
|
|
@@ -68404,6 +69688,14 @@ exports.compareToTarget = compareToTarget;
|
|
|
68404
69688
|
exports.compileExpression = compileExpression;
|
|
68405
69689
|
exports.compileExpressionSafe = compileExpressionSafe;
|
|
68406
69690
|
exports.composeSwitchedOff = composeSwitchedOff;
|
|
69691
|
+
exports.composedDeviceRef = composedDeviceRef;
|
|
69692
|
+
exports.composedDeviceStableId = composedDeviceStableId;
|
|
69693
|
+
exports.composerCapability = composerCapability;
|
|
69694
|
+
exports.compositionEdges = compositionEdges;
|
|
69695
|
+
exports.compositionReadKey = compositionReadKey;
|
|
69696
|
+
exports.compositionSliceKey = compositionSliceKey;
|
|
69697
|
+
exports.compositionSourceKey = compositionSourceKey;
|
|
69698
|
+
exports.compositionSourceRefs = compositionSourceRefs;
|
|
68407
69699
|
exports.conditionDepth = conditionDepth;
|
|
68408
69700
|
exports.conditionExclusionReason = conditionExclusionReason;
|
|
68409
69701
|
exports.conditionVisibleForKind = conditionVisibleForKind;
|
|
@@ -68415,7 +69707,9 @@ exports.contactCapability = contactCapability;
|
|
|
68415
69707
|
exports.controlCapability = controlCapability;
|
|
68416
69708
|
exports.convertUnit = convertUnit;
|
|
68417
69709
|
exports.coreBlockAddonId = coreBlockAddonId;
|
|
69710
|
+
exports.coreBlockComposition = coreBlockComposition;
|
|
68418
69711
|
exports.coreBlockIdFromAddonId = coreBlockIdFromAddonId;
|
|
69712
|
+
exports.coreBlockSourceKind = coreBlockSourceKind;
|
|
68419
69713
|
exports.coreBlocksCapability = coreBlocksCapability;
|
|
68420
69714
|
exports.cosineSimilarity = cosineSimilarity;
|
|
68421
69715
|
exports.countConditionLeaves = countConditionLeaves;
|
|
@@ -68454,8 +69748,10 @@ exports.describeCustomActions = require_sleep.describeCustomActions;
|
|
|
68454
69748
|
exports.describeModelVariant = describeModelVariant;
|
|
68455
69749
|
exports.describeOnboardClamp = describeOnboardClamp;
|
|
68456
69750
|
exports.describeOnboardRefusal = describeOnboardRefusal;
|
|
69751
|
+
exports.describeStateField = describeStateField;
|
|
68457
69752
|
exports.describeSystemEventDeliveryProblem = describeSystemEventDeliveryProblem;
|
|
68458
69753
|
exports.describeSystemEventFamilyProblem = describeSystemEventFamilyProblem;
|
|
69754
|
+
exports.describeTopLevelStateFields = describeTopLevelStateFields;
|
|
68459
69755
|
exports.detectAccessRole = detectAccessRole;
|
|
68460
69756
|
exports.detectionPipelineCapability = detectionPipelineCapability;
|
|
68461
69757
|
exports.deviceAdminLinkCapability = deviceAdminLinkCapability;
|
|
@@ -68495,6 +69791,7 @@ exports.enumerateItemArrayFields = enumerateItemArrayFields;
|
|
|
68495
69791
|
exports.enumerateSchemaFields = enumerateSchemaFields;
|
|
68496
69792
|
exports.errMsg = require_err_msg.errMsg;
|
|
68497
69793
|
exports.evaluateAst = evaluateAst;
|
|
69794
|
+
exports.evaluateCompositionField = evaluateCompositionField;
|
|
68498
69795
|
exports.evaluateExpressionSource = evaluateExpressionSource;
|
|
68499
69796
|
exports.evaluatePoolMemory = evaluatePoolMemory;
|
|
68500
69797
|
exports.evaluateSensorEdge = evaluateSensorEdge;
|
|
@@ -68515,7 +69812,9 @@ exports.failureContributionCapability = failureContributionCapability;
|
|
|
68515
69812
|
exports.failureRate = failureRate;
|
|
68516
69813
|
exports.fanControlCapability = fanControlCapability;
|
|
68517
69814
|
exports.featureProbeCapability = featureProbeCapability;
|
|
69815
|
+
exports.fieldReads = fieldReads;
|
|
68518
69816
|
exports.filesystemBrowseCapability = filesystemBrowseCapability;
|
|
69817
|
+
exports.findCompositionCycles = findCompositionCycles;
|
|
68519
69818
|
exports.findTimezone = findTimezone;
|
|
68520
69819
|
exports.floodCapability = floodCapability;
|
|
68521
69820
|
exports.foldSnapshotByFunction = foldSnapshotByFunction;
|
|
@@ -68539,6 +69838,7 @@ exports.humiditySensorCapability = humiditySensorCapability;
|
|
|
68539
69838
|
exports.hydrateSchema = require_sleep.hydrateSchema;
|
|
68540
69839
|
exports.imageCapability = imageCapability;
|
|
68541
69840
|
exports.imageSettingsCapability = imageSettingsCapability;
|
|
69841
|
+
exports.inferExpressionKinds = inferExpressionKinds;
|
|
68542
69842
|
exports.inferModelProvider = inferModelProvider;
|
|
68543
69843
|
exports.initialPoolMemoryState = initialPoolMemoryState;
|
|
68544
69844
|
exports.integrationsCapability = integrationsCapability;
|
|
@@ -68588,6 +69888,7 @@ exports.isVoidInput = isVoidInput;
|
|
|
68588
69888
|
exports.ituDbfsFromPreEpoch = ituDbfsFromPreEpoch;
|
|
68589
69889
|
exports.jobKindSchema = jobKindSchema;
|
|
68590
69890
|
exports.kebabToCamel = kebabToCamel;
|
|
69891
|
+
exports.kindOfValue = kindOfValue;
|
|
68591
69892
|
exports.kindsForDiscriminator = kindsForDiscriminator;
|
|
68592
69893
|
exports.knownValues = knownValues;
|
|
68593
69894
|
exports.lawnMowerControlCapability = lawnMowerControlCapability;
|
|
@@ -68690,6 +69991,7 @@ exports.pipelineAnalyticsCapability = pipelineAnalyticsCapability;
|
|
|
68690
69991
|
exports.pipelineExecutorCapability = pipelineExecutorCapability;
|
|
68691
69992
|
exports.pipelineOrchestratorCapability = pipelineOrchestratorCapability;
|
|
68692
69993
|
exports.pipelineRunnerCapability = pipelineRunnerCapability;
|
|
69994
|
+
exports.planComposition = planComposition;
|
|
68693
69995
|
exports.plateGalleryCapability = plateGalleryCapability;
|
|
68694
69996
|
exports.platformProbeCapability = platformProbeCapability;
|
|
68695
69997
|
exports.poolMemoryThreshold = poolMemoryThreshold;
|
|
@@ -68720,6 +70022,7 @@ exports.recordingOnboardCapability = recordingOnboardCapability;
|
|
|
68720
70022
|
exports.recordingSignalCapability = recordingSignalCapability;
|
|
68721
70023
|
exports.rectsToCells = rectsToCells;
|
|
68722
70024
|
exports.reducePoints = reducePoints;
|
|
70025
|
+
exports.requiredTopLevelKeys = requiredTopLevelKeys;
|
|
68723
70026
|
exports.requiresPython = requiresPython;
|
|
68724
70027
|
exports.reservedSourceOwner = reservedSourceOwner;
|
|
68725
70028
|
exports.resetPoolBaseline = resetPoolBaseline;
|
|
@@ -68749,6 +70052,7 @@ exports.resolveStreamMaps = require_canonical_hash.resolveStreamMaps;
|
|
|
68749
70052
|
exports.resolveVariantModelId = resolveVariantModelId;
|
|
68750
70053
|
exports.resolveViewableDeviceIds = resolveViewableDeviceIds;
|
|
68751
70054
|
exports.roleSpec = roleSpec;
|
|
70055
|
+
exports.roomCompositionExample = roomCompositionExample;
|
|
68752
70056
|
exports.ruleBelongsToAlarm = ruleBelongsToAlarm;
|
|
68753
70057
|
exports.ruleEditorSectionsForKind = ruleEditorSectionsForKind;
|
|
68754
70058
|
exports.ruleKindOf = ruleKindOf;
|
|
@@ -68854,6 +70158,7 @@ exports.updateCapability = updateCapability;
|
|
|
68854
70158
|
exports.userManagementCapability = userManagementCapability;
|
|
68855
70159
|
exports.userPasskeysCapability = userPasskeysCapability;
|
|
68856
70160
|
exports.vacuumControlCapability = vacuumControlCapability;
|
|
70161
|
+
exports.validateComposition = validateComposition;
|
|
68857
70162
|
exports.validateExpressionSource = validateExpressionSource;
|
|
68858
70163
|
exports.validateRecipeBounds = validateRecipeBounds;
|
|
68859
70164
|
exports.valveCapability = valveCapability;
|