@camstack/addon-auth 1.2.171 → 1.2.173
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/{dist-CAPIgbvM.mjs → dist-Czu2V8Ha.mjs} +909 -115
- package/dist/{dist-BCzztoSM.js → dist-DZD7NMtO.js} +909 -115
- package/dist/oidc/auth-oidc.addon.js +76 -130
- package/dist/oidc/auth-oidc.addon.mjs +76 -130
- package/dist/webauthn/_stub.js +1 -1
- package/dist/webauthn/{_virtual_mf-localSharedImportMap___mfe_internal__addon_auth_webauthn_widgets-cmM4lkBD.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_auth_webauthn_widgets-CPEjaa2U.mjs} +2 -2
- package/dist/webauthn/_virtual_mf___mfe_internal__addon_auth_webauthn_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DDAXLfIp.mjs +26 -0
- package/dist/webauthn/auth-webauthn.addon.js +1 -1
- package/dist/webauthn/auth-webauthn.addon.mjs +1 -1
- package/dist/webauthn/{hostInit-hRFE010M.mjs → hostInit-gERoQwbG.mjs} +2 -2
- package/dist/webauthn/remoteEntry.js +1 -1
- package/package.json +3 -1
- package/dist/webauthn/_virtual_mf___mfe_internal__addon_auth_webauthn_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-Di6YsQxe.mjs +0 -26
|
@@ -5621,7 +5621,7 @@ var ZodIssueCode = {
|
|
|
5621
5621
|
var ZodFirstPartyTypeKind;
|
|
5622
5622
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5623
5623
|
//#endregion
|
|
5624
|
-
//#region ../types/dist/sleep-
|
|
5624
|
+
//#region ../types/dist/sleep-CeyhrcOk.mjs
|
|
5625
5625
|
/**
|
|
5626
5626
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5627
5627
|
* window to float samples (D455).
|
|
@@ -7688,6 +7688,7 @@ var BaseAddon = class {
|
|
|
7688
7688
|
* a warning and falls back rather than crashing boot.
|
|
7689
7689
|
*/
|
|
7690
7690
|
state(key, schema, fallback) {
|
|
7691
|
+
this._declaredStateKeys.add(key);
|
|
7691
7692
|
return createDurableState({
|
|
7692
7693
|
key,
|
|
7693
7694
|
schema,
|
|
@@ -7703,6 +7704,96 @@ var BaseAddon = class {
|
|
|
7703
7704
|
} })
|
|
7704
7705
|
});
|
|
7705
7706
|
}
|
|
7707
|
+
/** Durable-state keys this process registered through {@link state}. */
|
|
7708
|
+
_declaredStateKeys = /* @__PURE__ */ new Set();
|
|
7709
|
+
/**
|
|
7710
|
+
* Stale-data audit: every global-settings key this addon still declares —
|
|
7711
|
+
* constructor defaults, settings-schema fields (layout containers included),
|
|
7712
|
+
* durable-state keys and the root of each `secretStatePaths` entry. Answered
|
|
7713
|
+
* here, in the addon's own process, so the hub keeps no copy of it.
|
|
7714
|
+
*/
|
|
7715
|
+
async getDeclaredSettingsKeys() {
|
|
7716
|
+
return { keys: [...this.declaredKeySet()].toSorted() };
|
|
7717
|
+
}
|
|
7718
|
+
declaredKeySet() {
|
|
7719
|
+
const keys = new Set(Object.keys(this.defaults));
|
|
7720
|
+
const schema = this.globalSettingsSchema();
|
|
7721
|
+
if (schema) for (const section of schema.sections) for (const key of collectFieldKeys(section.fields)) keys.add(key);
|
|
7722
|
+
for (const key of this._declaredStateKeys) keys.add(key);
|
|
7723
|
+
for (const path of this.secretStatePaths) {
|
|
7724
|
+
const root = path.split(/[.[]/, 1)[0];
|
|
7725
|
+
if (root) keys.add(root);
|
|
7726
|
+
}
|
|
7727
|
+
return keys;
|
|
7728
|
+
}
|
|
7729
|
+
/**
|
|
7730
|
+
* Stale-data audit: remove stored global-settings keys the addon no longer
|
|
7731
|
+
* declares, and clear the keychain values their markers held — except a value
|
|
7732
|
+
* a surviving key still points at. A declared or absent key is refused.
|
|
7733
|
+
*/
|
|
7734
|
+
async unsetStoredSettingsKeys(keys) {
|
|
7735
|
+
const settings = this._ctx?.settings;
|
|
7736
|
+
const raw = this.rawSettings();
|
|
7737
|
+
if (!settings || !raw) return {
|
|
7738
|
+
removed: [],
|
|
7739
|
+
refused: keys.map((key) => ({
|
|
7740
|
+
key,
|
|
7741
|
+
reason: "no settings store"
|
|
7742
|
+
})),
|
|
7743
|
+
secretsCleared: 0
|
|
7744
|
+
};
|
|
7745
|
+
let stored;
|
|
7746
|
+
try {
|
|
7747
|
+
stored = await raw.readAddonStore();
|
|
7748
|
+
} catch (error) {
|
|
7749
|
+
const reason = `store unreadable: ${error instanceof Error ? error.message : "unknown"}`;
|
|
7750
|
+
return {
|
|
7751
|
+
removed: [],
|
|
7752
|
+
refused: keys.map((key) => ({
|
|
7753
|
+
key,
|
|
7754
|
+
reason
|
|
7755
|
+
})),
|
|
7756
|
+
secretsCleared: 0
|
|
7757
|
+
};
|
|
7758
|
+
}
|
|
7759
|
+
const declared = this.declaredKeySet();
|
|
7760
|
+
const removed = [];
|
|
7761
|
+
const refused = [];
|
|
7762
|
+
for (const key of keys) {
|
|
7763
|
+
const base = key.split("@", 1)[0] ?? key;
|
|
7764
|
+
if (declared.has(base)) refused.push({
|
|
7765
|
+
key,
|
|
7766
|
+
reason: "still declared by the addon"
|
|
7767
|
+
});
|
|
7768
|
+
else if (!(key in stored)) refused.push({
|
|
7769
|
+
key,
|
|
7770
|
+
reason: "not stored"
|
|
7771
|
+
});
|
|
7772
|
+
else removed.push(key);
|
|
7773
|
+
}
|
|
7774
|
+
if (removed.length === 0) return {
|
|
7775
|
+
removed,
|
|
7776
|
+
refused,
|
|
7777
|
+
secretsCleared: 0
|
|
7778
|
+
};
|
|
7779
|
+
const kept = /* @__PURE__ */ new Set();
|
|
7780
|
+
const held = /* @__PURE__ */ new Set();
|
|
7781
|
+
for (const [key, value] of Object.entries(stored)) {
|
|
7782
|
+
const target = removed.includes(key) ? held : kept;
|
|
7783
|
+
for (const ref of collectSecretMarkerRefs(value)) target.add(ref);
|
|
7784
|
+
}
|
|
7785
|
+
const refsToClear = [...held].filter((ref) => !kept.has(ref));
|
|
7786
|
+
const patch = {};
|
|
7787
|
+
for (const key of removed) patch[key] = void 0;
|
|
7788
|
+
await settings.writeAddonStore(patch);
|
|
7789
|
+
const secretsCleared = refsToClear.length > 0 && this._ctx?.secrets ? await this._ctx.secrets.delete(refsToClear) : 0;
|
|
7790
|
+
await this.resolveConfig();
|
|
7791
|
+
return {
|
|
7792
|
+
removed,
|
|
7793
|
+
refused,
|
|
7794
|
+
secretsCleared
|
|
7795
|
+
};
|
|
7796
|
+
}
|
|
7706
7797
|
/** Per-device variant of {@link state}, backed by the per-device store. */
|
|
7707
7798
|
deviceState(deviceId, key, schema, fallback) {
|
|
7708
7799
|
return createDurableState({
|
|
@@ -7973,6 +8064,21 @@ function dropPerNodeFields(fields) {
|
|
|
7973
8064
|
}
|
|
7974
8065
|
return kept;
|
|
7975
8066
|
}
|
|
8067
|
+
function collectFieldKeys(fields) {
|
|
8068
|
+
const collected = [];
|
|
8069
|
+
for (const field of fields) {
|
|
8070
|
+
if (field.type === "group") {
|
|
8071
|
+
collected.push(...collectFieldKeys(field.fields));
|
|
8072
|
+
continue;
|
|
8073
|
+
}
|
|
8074
|
+
if (field.type === "sub-tabs") {
|
|
8075
|
+
for (const tab of field.tabs) collected.push(...collectFieldKeys(tab.fields));
|
|
8076
|
+
continue;
|
|
8077
|
+
}
|
|
8078
|
+
if ("key" in field && typeof field.key === "string") collected.push(field.key);
|
|
8079
|
+
}
|
|
8080
|
+
return collected;
|
|
8081
|
+
}
|
|
7976
8082
|
function collectPerNodeFieldKeys(fields) {
|
|
7977
8083
|
const collected = [];
|
|
7978
8084
|
for (const field of fields) {
|
|
@@ -16657,8 +16763,172 @@ object({
|
|
|
16657
16763
|
quantity: ReadingQuantitySchema,
|
|
16658
16764
|
unit: string().min(1)
|
|
16659
16765
|
});
|
|
16660
|
-
|
|
16661
|
-
|
|
16766
|
+
new Set([
|
|
16767
|
+
{
|
|
16768
|
+
id: "person",
|
|
16769
|
+
name: "Person"
|
|
16770
|
+
},
|
|
16771
|
+
{
|
|
16772
|
+
id: "vehicle",
|
|
16773
|
+
name: "Vehicle"
|
|
16774
|
+
},
|
|
16775
|
+
{
|
|
16776
|
+
id: "animal",
|
|
16777
|
+
name: "Animal"
|
|
16778
|
+
},
|
|
16779
|
+
{
|
|
16780
|
+
id: "package",
|
|
16781
|
+
name: "Package"
|
|
16782
|
+
}
|
|
16783
|
+
].map((l) => l.id));
|
|
16784
|
+
var COCO_TO_MACRO = {
|
|
16785
|
+
mapping: {
|
|
16786
|
+
person: "person",
|
|
16787
|
+
bicycle: "vehicle",
|
|
16788
|
+
car: "vehicle",
|
|
16789
|
+
motorcycle: "vehicle",
|
|
16790
|
+
airplane: "vehicle",
|
|
16791
|
+
bus: "vehicle",
|
|
16792
|
+
train: "vehicle",
|
|
16793
|
+
truck: "vehicle",
|
|
16794
|
+
boat: "vehicle",
|
|
16795
|
+
bird: "animal",
|
|
16796
|
+
cat: "animal",
|
|
16797
|
+
dog: "animal",
|
|
16798
|
+
horse: "animal",
|
|
16799
|
+
sheep: "animal",
|
|
16800
|
+
cow: "animal",
|
|
16801
|
+
elephant: "animal",
|
|
16802
|
+
bear: "animal",
|
|
16803
|
+
zebra: "animal",
|
|
16804
|
+
giraffe: "animal",
|
|
16805
|
+
suitcase: "package",
|
|
16806
|
+
backpack: "package",
|
|
16807
|
+
handbag: "package"
|
|
16808
|
+
},
|
|
16809
|
+
preserveOriginal: false
|
|
16810
|
+
};
|
|
16811
|
+
/**
|
|
16812
|
+
* WHAT a detection-shaped leaf is about: one MACRO class (person, vehicle,
|
|
16813
|
+
* animal, package) plus an OPTIONAL label that narrows it.
|
|
16814
|
+
*
|
|
16815
|
+
* The taxonomy is `COCO_TO_MACRO` (and `CLASS_MAP_MACRO_TARGETS`) — never a
|
|
16816
|
+
* second list. The label that fits depends on the macro class:
|
|
16817
|
+
*
|
|
16818
|
+
* - `animal` → a sub-class (`dog`, `cat`, …);
|
|
16819
|
+
* - `person` → a known face (an identity of the `face-gallery`);
|
|
16820
|
+
* - `vehicle` → a plate (its text) or a sub-class (`car`, `truck`, …);
|
|
16821
|
+
* - `package` → a sub-class.
|
|
16822
|
+
*
|
|
16823
|
+
* `other` exists only so a class the taxonomy does not know (a custom model's
|
|
16824
|
+
* `forklift`) survives the conversion of a stored recipe without widening.
|
|
16825
|
+
*
|
|
16826
|
+
* A label is decided LATE (D683): face recognition and LPR land after the
|
|
16827
|
+
* detection starts. The track-lifecycle `update` event carries the newly
|
|
16828
|
+
* resolved `label` / `plateText`, which is why a leaf with a label fires when
|
|
16829
|
+
* the subject GETS it — not at the first detection.
|
|
16830
|
+
*/
|
|
16831
|
+
var SubClassLabelSchema = object({
|
|
16832
|
+
kind: literal("sub-class"),
|
|
16833
|
+
className: string().min(1)
|
|
16834
|
+
});
|
|
16835
|
+
var IdentityLabelSchema = object({
|
|
16836
|
+
kind: literal("identity"),
|
|
16837
|
+
/** The `face-gallery` identity id (stable across a rename). */
|
|
16838
|
+
identityId: string().min(1),
|
|
16839
|
+
/** The identity's name — what a track-lifecycle event carries as `label`. */
|
|
16840
|
+
name: string().min(1)
|
|
16841
|
+
});
|
|
16842
|
+
var PlateLabelSchema = object({
|
|
16843
|
+
kind: literal("plate"),
|
|
16844
|
+
text: string().min(1)
|
|
16845
|
+
});
|
|
16846
|
+
function macroOf$1(className) {
|
|
16847
|
+
return COCO_TO_MACRO.mapping[className.toLowerCase()] ?? className.toLowerCase();
|
|
16848
|
+
}
|
|
16849
|
+
/** A sub-class label must belong to the macro it is under. */
|
|
16850
|
+
function subClassBelongs(macro, label) {
|
|
16851
|
+
return label === void 0 || macroOf$1(label.className) === macro;
|
|
16852
|
+
}
|
|
16853
|
+
var subClassOf = (macro) => SubClassLabelSchema.refine((l) => subClassBelongs(macro, l), { message: `that class is not a kind of ${macro} in the detection taxonomy` });
|
|
16854
|
+
var DetectionSubjectSchema = discriminatedUnion("macro", [
|
|
16855
|
+
object({
|
|
16856
|
+
macro: literal("animal"),
|
|
16857
|
+
label: subClassOf("animal").optional()
|
|
16858
|
+
}),
|
|
16859
|
+
object({
|
|
16860
|
+
macro: literal("person"),
|
|
16861
|
+
label: IdentityLabelSchema.optional()
|
|
16862
|
+
}),
|
|
16863
|
+
object({
|
|
16864
|
+
macro: literal("vehicle"),
|
|
16865
|
+
label: discriminatedUnion("kind", [SubClassLabelSchema.refine((l) => subClassBelongs("vehicle", l), { message: "that class is not a kind of vehicle in the detection taxonomy" }), PlateLabelSchema]).optional()
|
|
16866
|
+
}),
|
|
16867
|
+
object({
|
|
16868
|
+
macro: literal("package"),
|
|
16869
|
+
label: subClassOf("package").optional()
|
|
16870
|
+
}),
|
|
16871
|
+
object({
|
|
16872
|
+
macro: literal("other"),
|
|
16873
|
+
className: string().min(1)
|
|
16874
|
+
})
|
|
16875
|
+
]);
|
|
16876
|
+
/**
|
|
16877
|
+
* The subject of a PARKED object. The stationary registry's event carries a
|
|
16878
|
+
* class and a zone, no face and no plate — an identity or plate label there
|
|
16879
|
+
* could never match, so the schema refuses it instead of letting it sit dead.
|
|
16880
|
+
*/
|
|
16881
|
+
var StationarySubjectSchema = DetectionSubjectSchema.refine((s) => s.macro === "other" || s.label === void 0 || s.label.kind === "sub-class", { message: "a parked object carries no face or plate — only a class can narrow it" });
|
|
16882
|
+
/**
|
|
16883
|
+
* A stored class string as a subject: a macro name stays a macro; a raw class
|
|
16884
|
+
* the taxonomy files under a macro becomes that macro plus the sub-class label
|
|
16885
|
+
* (`dog` → animal / dog); anything else is `other`, kept verbatim.
|
|
16886
|
+
*/
|
|
16887
|
+
function subjectFromClassName(className) {
|
|
16888
|
+
const name = className.trim().toLowerCase();
|
|
16889
|
+
const macro = COCO_TO_MACRO.mapping[name];
|
|
16890
|
+
if (new Set(Object.values(COCO_TO_MACRO.mapping)).has(name)) return macroOnly(name);
|
|
16891
|
+
if (macro === void 0) return {
|
|
16892
|
+
macro: "other",
|
|
16893
|
+
className
|
|
16894
|
+
};
|
|
16895
|
+
const label = {
|
|
16896
|
+
kind: "sub-class",
|
|
16897
|
+
className: name
|
|
16898
|
+
};
|
|
16899
|
+
switch (macro) {
|
|
16900
|
+
case "animal": return {
|
|
16901
|
+
macro: "animal",
|
|
16902
|
+
label
|
|
16903
|
+
};
|
|
16904
|
+
case "vehicle": return {
|
|
16905
|
+
macro: "vehicle",
|
|
16906
|
+
label
|
|
16907
|
+
};
|
|
16908
|
+
case "package": return {
|
|
16909
|
+
macro: "package",
|
|
16910
|
+
label
|
|
16911
|
+
};
|
|
16912
|
+
default: return {
|
|
16913
|
+
macro: "other",
|
|
16914
|
+
className
|
|
16915
|
+
};
|
|
16916
|
+
}
|
|
16917
|
+
}
|
|
16918
|
+
function macroOnly(macro) {
|
|
16919
|
+
switch (macro) {
|
|
16920
|
+
case "animal": return { macro: "animal" };
|
|
16921
|
+
case "person": return { macro: "person" };
|
|
16922
|
+
case "vehicle": return { macro: "vehicle" };
|
|
16923
|
+
case "package": return { macro: "package" };
|
|
16924
|
+
default: return {
|
|
16925
|
+
macro: "other",
|
|
16926
|
+
className: macro
|
|
16927
|
+
};
|
|
16928
|
+
}
|
|
16929
|
+
}
|
|
16930
|
+
/** How a state leaf compares a device field to a value. Derived from the
|
|
16931
|
+
* field's `kind` in `deviceManager.getWireableFields`, never hand-maintained. */
|
|
16662
16932
|
var AutomationConditionOperatorSchema = _enum([
|
|
16663
16933
|
"eq",
|
|
16664
16934
|
"ne",
|
|
@@ -16669,12 +16939,76 @@ var AutomationConditionOperatorSchema = _enum([
|
|
|
16669
16939
|
"contains",
|
|
16670
16940
|
"in"
|
|
16671
16941
|
]);
|
|
16672
|
-
|
|
16673
|
-
|
|
16942
|
+
/**
|
|
16943
|
+
* D8 compliance, and it is the reason a "becomes" leaf is not merely an event
|
|
16944
|
+
* subscription: it evaluates against the **state mirror**, which is reconciled,
|
|
16945
|
+
* and an event only WAKES the evaluation. A dropped event therefore DELAYS a
|
|
16946
|
+
* fire; it does not lose it.
|
|
16947
|
+
*/
|
|
16948
|
+
var DeviceBecomesLeafSchema = object({
|
|
16949
|
+
kind: literal("device-becomes"),
|
|
16950
|
+
deviceId: number().int().nonnegative(),
|
|
16951
|
+
cap: string().min(1),
|
|
16952
|
+
fieldPath: string().min(1),
|
|
16953
|
+
/** Fire when the field takes this value. Omit to fire on any change. */
|
|
16954
|
+
becomes: union([
|
|
16955
|
+
string(),
|
|
16956
|
+
number(),
|
|
16957
|
+
boolean()
|
|
16958
|
+
]).optional(),
|
|
16959
|
+
/** Only on a CHANGE of value, not on every re-report. */
|
|
16960
|
+
edge: boolean().optional(),
|
|
16961
|
+
/** The new value must hold this long before it counts. */
|
|
16962
|
+
forMs: number().int().min(0).max(864e5).optional(),
|
|
16963
|
+
/** Collapse a burst into one occurrence. */
|
|
16964
|
+
debounceMs: number().int().min(0).max(6e5).optional()
|
|
16965
|
+
});
|
|
16966
|
+
var DeviceEventLeafSchema = object({
|
|
16967
|
+
kind: literal("device-event"),
|
|
16968
|
+
/** An `EventCategory` value. */
|
|
16969
|
+
category: string().min(1),
|
|
16970
|
+
deviceId: number().int().nonnegative().optional()
|
|
16971
|
+
});
|
|
16972
|
+
var ScheduleLeafSchema = object({
|
|
16973
|
+
kind: literal("schedule"),
|
|
16974
|
+
cron: string().min(1).max(120)
|
|
16975
|
+
});
|
|
16976
|
+
var ManualLeafSchema = object({ kind: literal("manual") });
|
|
16977
|
+
var IntervalLeafSchema = object({
|
|
16978
|
+
kind: literal("interval"),
|
|
16979
|
+
minutes: number().int().min(1).max(1440)
|
|
16980
|
+
});
|
|
16981
|
+
var DetectionLeafSchema = object({
|
|
16982
|
+
kind: literal("detection"),
|
|
16983
|
+
/** One macro class each, optionally narrowed by a label; a track of any listed subject fires. */
|
|
16984
|
+
subjects: array(DetectionSubjectSchema).min(1),
|
|
16985
|
+
deviceIds: array(number().int().nonnegative()).min(1),
|
|
16986
|
+
/** The track must have visited at least one of these zones. */
|
|
16987
|
+
zones: array(string().min(1)).min(1).optional(),
|
|
16988
|
+
/** Best-so-far confidence the track must reach. */
|
|
16989
|
+
minScore: number().min(0).max(1).optional()
|
|
16990
|
+
});
|
|
16991
|
+
var StationaryLeafSchema = object({
|
|
16992
|
+
kind: literal("stationary"),
|
|
16993
|
+
deviceIds: array(number().int().nonnegative()).min(1),
|
|
16994
|
+
subjects: array(StationarySubjectSchema).min(1).optional(),
|
|
16995
|
+
zones: array(string().min(1)).min(1).optional(),
|
|
16996
|
+
/** `appeared`: it became parked. `departed`: the registry retired it. */
|
|
16997
|
+
phase: _enum(["appeared", "departed"])
|
|
16998
|
+
});
|
|
16999
|
+
/** "is": one device field compared to one value, NOW. */
|
|
17000
|
+
var DeviceIsLeafSchema = object({
|
|
17001
|
+
kind: literal("device-is"),
|
|
16674
17002
|
deviceId: number().int().nonnegative(),
|
|
16675
17003
|
cap: string().min(1),
|
|
16676
17004
|
fieldPath: string().min(1),
|
|
16677
17005
|
operator: AutomationConditionOperatorSchema,
|
|
17006
|
+
/**
|
|
17007
|
+
* The value. A number on a quantity field is stored in the field's base unit
|
|
17008
|
+
* (D944); a quantity value is the WRITE form, which the save boundary
|
|
17009
|
+
* replaces with the converted number and `unit`. A leaf that still carries
|
|
17010
|
+
* one is never evaluated (it fails).
|
|
17011
|
+
*/
|
|
16678
17012
|
value: union([
|
|
16679
17013
|
string(),
|
|
16680
17014
|
number(),
|
|
@@ -16682,24 +17016,26 @@ var AutomationConditionLeafSchema = object({
|
|
|
16682
17016
|
array(union([string(), number()])),
|
|
16683
17017
|
QuantityValueSchema
|
|
16684
17018
|
]),
|
|
17019
|
+
/** The unit the person picked for `value` (display only; `value` is in the base unit). */
|
|
16685
17020
|
unit: string().min(1).optional()
|
|
16686
17021
|
});
|
|
16687
|
-
|
|
17022
|
+
/**
|
|
17023
|
+
* True when the camera currently has a PARKED object matching `subjects` in at
|
|
17024
|
+
* least one of `zones`. Reads the zone-analytics snapshot through the same
|
|
17025
|
+
* mirror as every other state leaf, so a dropped event never decides it (D49).
|
|
17026
|
+
*/
|
|
17027
|
+
var StationaryPresentLeafSchema = object({
|
|
16688
17028
|
kind: literal("stationary-present"),
|
|
16689
17029
|
deviceId: number().int().nonnegative(),
|
|
16690
|
-
|
|
16691
|
-
classes: array(string().min(1)).min(1).optional(),
|
|
16692
|
-
/** The parked object must be in at least one of these zones. */
|
|
17030
|
+
subjects: array(StationarySubjectSchema).min(1).optional(),
|
|
16693
17031
|
zones: array(string().min(1)).min(1).optional()
|
|
16694
17032
|
});
|
|
16695
17033
|
/**
|
|
16696
|
-
* The
|
|
16697
|
-
*
|
|
16698
|
-
*
|
|
16699
|
-
* validation is the SAME function `ExpressionSourceSchema` runs, so the two
|
|
16700
|
-
* cannot drift — an expression that one accepts, the other accepts.
|
|
17034
|
+
* The escape hatch: the bounded expression engine over named device bindings.
|
|
17035
|
+
* Declared as a plain object so a discriminated union can read `kind`; the
|
|
17036
|
+
* author-time validation is the SAME function `ExpressionSourceSchema` runs.
|
|
16701
17037
|
*/
|
|
16702
|
-
var
|
|
17038
|
+
var ExpressionLeafSchema = object({
|
|
16703
17039
|
kind: literal("expression"),
|
|
16704
17040
|
expr: string().min(1).max(MAX_EXPRESSION_SOURCE_LENGTH),
|
|
16705
17041
|
bindings: record(string().regex(EXPRESSION_IDENTIFIER_RE), ExpressionBindingSourceSchema)
|
|
@@ -16711,55 +17047,62 @@ var AutomationConditionExpressionSchema = object({
|
|
|
16711
17047
|
path: ["expr"]
|
|
16712
17048
|
});
|
|
16713
17049
|
});
|
|
16714
|
-
var
|
|
17050
|
+
var AutomationWhenSchema = lazy(() => discriminatedUnion("kind", [
|
|
16715
17051
|
object({
|
|
16716
17052
|
kind: literal("all"),
|
|
16717
|
-
children: array(
|
|
17053
|
+
children: array(AutomationWhenSchema)
|
|
16718
17054
|
}),
|
|
16719
17055
|
object({
|
|
16720
17056
|
kind: literal("any"),
|
|
16721
|
-
children: array(
|
|
17057
|
+
children: array(AutomationWhenSchema)
|
|
16722
17058
|
}),
|
|
16723
17059
|
object({
|
|
16724
17060
|
kind: literal("not"),
|
|
16725
|
-
child:
|
|
17061
|
+
child: AutomationWhenSchema
|
|
16726
17062
|
}),
|
|
16727
|
-
|
|
16728
|
-
|
|
16729
|
-
|
|
17063
|
+
DeviceBecomesLeafSchema,
|
|
17064
|
+
DeviceEventLeafSchema,
|
|
17065
|
+
ScheduleLeafSchema,
|
|
17066
|
+
ManualLeafSchema,
|
|
17067
|
+
IntervalLeafSchema,
|
|
17068
|
+
DetectionLeafSchema,
|
|
17069
|
+
StationaryLeafSchema,
|
|
17070
|
+
DeviceIsLeafSchema,
|
|
17071
|
+
StationaryPresentLeafSchema,
|
|
17072
|
+
ExpressionLeafSchema
|
|
16730
17073
|
]));
|
|
16731
17074
|
/**
|
|
16732
|
-
*
|
|
16733
|
-
*
|
|
16734
|
-
*
|
|
16735
|
-
*
|
|
16736
|
-
*
|
|
16737
|
-
*
|
|
16738
|
-
*
|
|
16739
|
-
*
|
|
16740
|
-
|
|
16741
|
-
|
|
17075
|
+
* The recipe shape before the single `when` tree: a flat list of triggers
|
|
17076
|
+
* (OR'd, each an instant) and an optional condition tree. Stored recipes —
|
|
17077
|
+
* the `AUTOMATION_RECIPE` literal of every block saved so far, and whatever an
|
|
17078
|
+
* older client still posts — are in this shape, so it stays READABLE here, and
|
|
17079
|
+
* {@link convertLegacyRecipe} turns it into the new one, losslessly and one
|
|
17080
|
+
* way. Nothing writes this shape any more.
|
|
17081
|
+
*
|
|
17082
|
+
* `{ triggers: [t1…tn], conditions?: C }`
|
|
17083
|
+
* → `when = all(any(t1…tn), C)`, or `any(t1…tn)` without `C`;
|
|
17084
|
+
* a single trigger is not wrapped in `any`.
|
|
17085
|
+
* a `condition` leaf → a `device-is` leaf (the "is" verb);
|
|
17086
|
+
* a `device-state` trigger → a `device-becomes` leaf (the "becomes" verb);
|
|
17087
|
+
* `classes: ['dog']` → the macro `animal` with the label `dog`.
|
|
17088
|
+
*/
|
|
17089
|
+
var LegacyTriggerSchema = discriminatedUnion("kind", [
|
|
16742
17090
|
object({
|
|
16743
17091
|
kind: literal("device-state"),
|
|
16744
17092
|
deviceId: number().int().nonnegative(),
|
|
16745
17093
|
cap: string().min(1),
|
|
16746
17094
|
fieldPath: string().min(1),
|
|
16747
|
-
/** Fire when the field takes this value. Omit to fire on any change. */
|
|
16748
17095
|
becomes: union([
|
|
16749
17096
|
string(),
|
|
16750
17097
|
number(),
|
|
16751
17098
|
boolean()
|
|
16752
17099
|
]).optional(),
|
|
16753
|
-
/** Only on a CHANGE of value, not on every re-report. */
|
|
16754
17100
|
edge: boolean().optional(),
|
|
16755
|
-
/** The condition must hold this long before the run starts. */
|
|
16756
17101
|
forMs: number().int().min(0).max(864e5).optional(),
|
|
16757
|
-
/** Collapse a burst into one run. */
|
|
16758
17102
|
debounceMs: number().int().min(0).max(6e5).optional()
|
|
16759
17103
|
}),
|
|
16760
17104
|
object({
|
|
16761
17105
|
kind: literal("device-event"),
|
|
16762
|
-
/** An `EventCategory` value. */
|
|
16763
17106
|
category: string().min(1),
|
|
16764
17107
|
deviceId: number().int().nonnegative().optional()
|
|
16765
17108
|
}),
|
|
@@ -16770,25 +17113,16 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
|
|
|
16770
17113
|
object({ kind: literal("manual") }),
|
|
16771
17114
|
object({
|
|
16772
17115
|
kind: literal("detection"),
|
|
16773
|
-
/** Class names. A macro class (`animal`, `vehicle`, `person`, `package`)
|
|
16774
|
-
* matches every raw class that maps to it; any other name matches
|
|
16775
|
-
* exactly. */
|
|
16776
17116
|
classes: array(string().min(1)).min(1),
|
|
16777
17117
|
deviceIds: array(number().int().nonnegative()).min(1),
|
|
16778
|
-
/** The track must have visited at least one of these zones. */
|
|
16779
17118
|
zones: array(string().min(1)).min(1).optional(),
|
|
16780
|
-
/** Best-so-far confidence the track must reach. */
|
|
16781
17119
|
minScore: number().min(0).max(1).optional()
|
|
16782
17120
|
}),
|
|
16783
17121
|
object({
|
|
16784
17122
|
kind: literal("stationary"),
|
|
16785
17123
|
deviceIds: array(number().int().nonnegative()).min(1),
|
|
16786
|
-
/** Class names; a macro class matches like the detection trigger. */
|
|
16787
17124
|
classes: array(string().min(1)).min(1).optional(),
|
|
16788
|
-
/** The parked object must be in at least one of these zones. */
|
|
16789
17125
|
zones: array(string().min(1)).min(1).optional(),
|
|
16790
|
-
/** `appeared`: it became parked. `departed`: the registry retired it.
|
|
16791
|
-
* The vocabulary of `PipelineAnalyticsStationaryChanged`. */
|
|
16792
17126
|
phase: _enum(["appeared", "departed"])
|
|
16793
17127
|
}),
|
|
16794
17128
|
object({
|
|
@@ -16796,6 +17130,143 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
|
|
|
16796
17130
|
minutes: number().int().min(1).max(1440)
|
|
16797
17131
|
})
|
|
16798
17132
|
]);
|
|
17133
|
+
var LegacyConditionLeafSchema = object({
|
|
17134
|
+
kind: literal("condition"),
|
|
17135
|
+
deviceId: number().int().nonnegative(),
|
|
17136
|
+
cap: string().min(1),
|
|
17137
|
+
fieldPath: string().min(1),
|
|
17138
|
+
operator: AutomationConditionOperatorSchema,
|
|
17139
|
+
value: union([
|
|
17140
|
+
string(),
|
|
17141
|
+
number(),
|
|
17142
|
+
boolean(),
|
|
17143
|
+
array(union([string(), number()])),
|
|
17144
|
+
QuantityValueSchema
|
|
17145
|
+
]),
|
|
17146
|
+
unit: string().min(1).optional()
|
|
17147
|
+
});
|
|
17148
|
+
var LegacyStationaryPresentSchema = object({
|
|
17149
|
+
kind: literal("stationary-present"),
|
|
17150
|
+
deviceId: number().int().nonnegative(),
|
|
17151
|
+
classes: array(string().min(1)).min(1).optional(),
|
|
17152
|
+
zones: array(string().min(1)).min(1).optional()
|
|
17153
|
+
});
|
|
17154
|
+
var LegacyExpressionSchema = object({
|
|
17155
|
+
kind: literal("expression"),
|
|
17156
|
+
expr: string().min(1).max(MAX_EXPRESSION_SOURCE_LENGTH),
|
|
17157
|
+
bindings: record(string().regex(EXPRESSION_IDENTIFIER_RE), ExpressionBindingSourceSchema)
|
|
17158
|
+
}).superRefine((src, ctx) => {
|
|
17159
|
+
const err = validateExpressionSource(src);
|
|
17160
|
+
if (err !== null) ctx.addIssue({
|
|
17161
|
+
code: "custom",
|
|
17162
|
+
message: err,
|
|
17163
|
+
path: ["expr"]
|
|
17164
|
+
});
|
|
17165
|
+
});
|
|
17166
|
+
var LegacyConditionSchema = lazy(() => discriminatedUnion("kind", [
|
|
17167
|
+
object({
|
|
17168
|
+
kind: literal("all"),
|
|
17169
|
+
children: array(LegacyConditionSchema)
|
|
17170
|
+
}),
|
|
17171
|
+
object({
|
|
17172
|
+
kind: literal("any"),
|
|
17173
|
+
children: array(LegacyConditionSchema)
|
|
17174
|
+
}),
|
|
17175
|
+
object({
|
|
17176
|
+
kind: literal("not"),
|
|
17177
|
+
child: LegacyConditionSchema
|
|
17178
|
+
}),
|
|
17179
|
+
LegacyConditionLeafSchema,
|
|
17180
|
+
LegacyExpressionSchema,
|
|
17181
|
+
LegacyStationaryPresentSchema
|
|
17182
|
+
]));
|
|
17183
|
+
function convertTrigger(trigger) {
|
|
17184
|
+
switch (trigger.kind) {
|
|
17185
|
+
case "device-state": return {
|
|
17186
|
+
...trigger,
|
|
17187
|
+
kind: "device-becomes"
|
|
17188
|
+
};
|
|
17189
|
+
case "detection": {
|
|
17190
|
+
const { classes, ...rest } = trigger;
|
|
17191
|
+
return {
|
|
17192
|
+
...rest,
|
|
17193
|
+
subjects: classes.map(subjectFromClassName)
|
|
17194
|
+
};
|
|
17195
|
+
}
|
|
17196
|
+
case "stationary": {
|
|
17197
|
+
const { classes, ...rest } = trigger;
|
|
17198
|
+
return {
|
|
17199
|
+
...rest,
|
|
17200
|
+
...classes === void 0 ? {} : { subjects: classes.map(subjectFromClassName) }
|
|
17201
|
+
};
|
|
17202
|
+
}
|
|
17203
|
+
default: return trigger;
|
|
17204
|
+
}
|
|
17205
|
+
}
|
|
17206
|
+
/** An old condition tree as a `when` subtree: `condition` → "is", classes → subjects. */
|
|
17207
|
+
function convertLegacyCondition(condition) {
|
|
17208
|
+
switch (condition.kind) {
|
|
17209
|
+
case "condition": return {
|
|
17210
|
+
...condition,
|
|
17211
|
+
kind: "device-is"
|
|
17212
|
+
};
|
|
17213
|
+
case "stationary-present": {
|
|
17214
|
+
const { classes, ...rest } = condition;
|
|
17215
|
+
return {
|
|
17216
|
+
...rest,
|
|
17217
|
+
...classes === void 0 ? {} : { subjects: classes.map(subjectFromClassName) }
|
|
17218
|
+
};
|
|
17219
|
+
}
|
|
17220
|
+
case "expression": return condition;
|
|
17221
|
+
case "not": return {
|
|
17222
|
+
kind: "not",
|
|
17223
|
+
child: convertLegacyCondition(condition.child)
|
|
17224
|
+
};
|
|
17225
|
+
case "all":
|
|
17226
|
+
case "any": return {
|
|
17227
|
+
kind: condition.kind,
|
|
17228
|
+
children: condition.children.map(convertLegacyCondition)
|
|
17229
|
+
};
|
|
17230
|
+
}
|
|
17231
|
+
}
|
|
17232
|
+
/** `all(any(t1…tn), C)`, or `any(t1…tn)`; a single trigger is not wrapped in `any`. */
|
|
17233
|
+
function convertLegacyWhen(half) {
|
|
17234
|
+
const leaves = half.triggers.map(convertTrigger);
|
|
17235
|
+
const first = leaves[0];
|
|
17236
|
+
const triggers = leaves.length === 1 && first !== void 0 ? first : {
|
|
17237
|
+
kind: "any",
|
|
17238
|
+
children: leaves
|
|
17239
|
+
};
|
|
17240
|
+
if (half.conditions === void 0) return triggers;
|
|
17241
|
+
return {
|
|
17242
|
+
kind: "all",
|
|
17243
|
+
children: [triggers, convertLegacyCondition(half.conditions)]
|
|
17244
|
+
};
|
|
17245
|
+
}
|
|
17246
|
+
/**
|
|
17247
|
+
* The automation RECIPE — what a visually-authored automation is, before it
|
|
17248
|
+
* becomes code.
|
|
17249
|
+
*
|
|
17250
|
+
* This is the data half of `docs/design/2026-08-08-automation-scripts-custom-devices.md`
|
|
17251
|
+
* Phase 6. A recipe is not an engine and never evaluates anything: it is a
|
|
17252
|
+
* declarative description that {@link generateAutomationBlock} compiles to the
|
|
17253
|
+
* TypeScript of an ordinary core block. There is therefore no second rule
|
|
17254
|
+
* engine, no second store and no second runtime — the block runner is the
|
|
17255
|
+
* runtime, `core_blocks` is the store (§2.1).
|
|
17256
|
+
*
|
|
17257
|
+
* Two parts:
|
|
17258
|
+
*
|
|
17259
|
+
* - **`when`** — ONE tree (`./when.ts`) of all/any/not over event leaves
|
|
17260
|
+
* (instants) and state leaves (durations). It replaces the flat trigger list
|
|
17261
|
+
* plus the separate condition tree; the firing rule is in that file and in
|
|
17262
|
+
* ADR "one tree".
|
|
17263
|
+
* - **Actions** — `NcRuleActionSchema`'s two steps, plus the `{kind:'code'}`
|
|
17264
|
+
* fragment of §3.2.2. See {@link AutomationActionSchema} for the ONE place
|
|
17265
|
+
* this had to diverge from "verbatim", and why.
|
|
17266
|
+
*
|
|
17267
|
+
* A recipe stored in the old shape (`triggers` + `conditions`) still LOADS:
|
|
17268
|
+
* {@link AutomationRecipeSchema} (the parse-anywhere schema) converts it on parse. Nothing writes it.
|
|
17269
|
+
*/
|
|
16799
17270
|
/**
|
|
16800
17271
|
* One action step.
|
|
16801
17272
|
*
|
|
@@ -16898,69 +17369,49 @@ var AutomationRunModeSchema = discriminatedUnion("mode", [
|
|
|
16898
17369
|
minutes: number().int().min(1).max(1440)
|
|
16899
17370
|
})
|
|
16900
17371
|
]);
|
|
16901
|
-
var
|
|
16902
|
-
|
|
16903
|
-
conditions: AutomationConditionSchema.optional(),
|
|
17372
|
+
var CurrentAutomationRecipeSchema = object({
|
|
17373
|
+
when: AutomationWhenSchema,
|
|
16904
17374
|
actions: array(AutomationActionSchema),
|
|
16905
17375
|
runMode: AutomationRunModeSchema.optional(),
|
|
16906
17376
|
/** How many run traces the automation keeps (default {@link DEFAULT_TRACE_KEEP}). */
|
|
16907
17377
|
keepTraces: number().int().min(1).max(100).optional()
|
|
16908
17378
|
});
|
|
16909
|
-
|
|
16910
|
-
|
|
16911
|
-
|
|
16912
|
-
|
|
16913
|
-
|
|
16914
|
-
|
|
16915
|
-
|
|
16916
|
-
|
|
16917
|
-
|
|
16918
|
-
|
|
16919
|
-
|
|
16920
|
-
|
|
16921
|
-
|
|
16922
|
-
|
|
16923
|
-
|
|
16924
|
-
|
|
16925
|
-
|
|
16926
|
-
|
|
16927
|
-
|
|
16928
|
-
|
|
16929
|
-
|
|
16930
|
-
|
|
16931
|
-
|
|
16932
|
-
|
|
16933
|
-
|
|
16934
|
-
bus: "vehicle",
|
|
16935
|
-
train: "vehicle",
|
|
16936
|
-
truck: "vehicle",
|
|
16937
|
-
boat: "vehicle",
|
|
16938
|
-
bird: "animal",
|
|
16939
|
-
cat: "animal",
|
|
16940
|
-
dog: "animal",
|
|
16941
|
-
horse: "animal",
|
|
16942
|
-
sheep: "animal",
|
|
16943
|
-
cow: "animal",
|
|
16944
|
-
elephant: "animal",
|
|
16945
|
-
bear: "animal",
|
|
16946
|
-
zebra: "animal",
|
|
16947
|
-
giraffe: "animal",
|
|
16948
|
-
suitcase: "package",
|
|
16949
|
-
backpack: "package",
|
|
16950
|
-
handbag: "package"
|
|
16951
|
-
},
|
|
16952
|
-
preserveOriginal: false
|
|
16953
|
-
};
|
|
17379
|
+
/** A recipe as it was stored before the single tree. Read-only: nothing writes this. */
|
|
17380
|
+
var LegacyAutomationRecipeSchema = object({
|
|
17381
|
+
triggers: array(LegacyTriggerSchema),
|
|
17382
|
+
conditions: LegacyConditionSchema.optional(),
|
|
17383
|
+
actions: array(AutomationActionSchema),
|
|
17384
|
+
runMode: AutomationRunModeSchema.optional(),
|
|
17385
|
+
keepTraces: number().int().min(1).max(100).optional()
|
|
17386
|
+
});
|
|
17387
|
+
/** The old shape as the new one, lossless. */
|
|
17388
|
+
function convertLegacyRecipe(legacy) {
|
|
17389
|
+
const { triggers, conditions, ...rest } = legacy;
|
|
17390
|
+
return {
|
|
17391
|
+
when: convertLegacyWhen({
|
|
17392
|
+
triggers,
|
|
17393
|
+
conditions
|
|
17394
|
+
}),
|
|
17395
|
+
...rest
|
|
17396
|
+
};
|
|
17397
|
+
}
|
|
17398
|
+
/**
|
|
17399
|
+
* Where recipes are PARSED (the core-blocks cap, the MCP tool, the literal a
|
|
17400
|
+
* saved block carries): the new shape as it is, or the old shape converted to
|
|
17401
|
+
* it. The output type is always the new one.
|
|
17402
|
+
*/
|
|
17403
|
+
var AutomationRecipeSchema = union([CurrentAutomationRecipeSchema, LegacyAutomationRecipeSchema.transform(convertLegacyRecipe)]);
|
|
16954
17404
|
new Set(Object.values(COCO_TO_MACRO.mapping));
|
|
16955
17405
|
/**
|
|
16956
17406
|
* Run traces — what an automation (or, later, an Action run) DID, node by node,
|
|
16957
17407
|
* so the editor can paint every block green or red with its reason.
|
|
16958
17408
|
*
|
|
16959
|
-
* A trace is data, not a log: it covers the WHOLE tree — the
|
|
16960
|
-
* every
|
|
16961
|
-
* short-circuit never reached), the run-mode verdict and every action
|
|
16962
|
-
* each addressed by a stable path (`
|
|
16963
|
-
* for an Action run).
|
|
17409
|
+
* A trace is data, not a log: it covers the WHOLE tree — the event leaf that
|
|
17410
|
+
* fired, every node of the `when` tree (containers and leaves, including the
|
|
17411
|
+
* ones a short-circuit never reached), the run-mode verdict and every action
|
|
17412
|
+
* step — each addressed by a stable path (`when.0.1`, `actions.2`, or `steps.N`
|
|
17413
|
+
* for an Action run). Traces written before the single tree carry
|
|
17414
|
+
* `conditions.*` paths and still parse. Skipped
|
|
16964
17415
|
* evaluations are traced too, and identical consecutive skips collapse into a
|
|
16965
17416
|
* repeat count so a trigger that fails every 5 minutes cannot flush real runs.
|
|
16966
17417
|
*
|
|
@@ -16992,6 +17443,8 @@ var TraceNodeOutcomeSchema = _enum([
|
|
|
16992
17443
|
]);
|
|
16993
17444
|
var AutomationTriggerTraceSchema = object({
|
|
16994
17445
|
kind: string().min(1),
|
|
17446
|
+
/** The event leaf that fired (`when`, `when.0.1`); absent on traces written before the single tree. */
|
|
17447
|
+
path: string().min(1).optional(),
|
|
16995
17448
|
outcome: _enum(["pass", "fail"]),
|
|
16996
17449
|
/** Why an event was rejected ("class person not in [dog]") or what fired. */
|
|
16997
17450
|
reason: string(),
|
|
@@ -16999,15 +17452,23 @@ var AutomationTriggerTraceSchema = object({
|
|
|
16999
17452
|
vars: record(string(), TraceValueSchema)
|
|
17000
17453
|
});
|
|
17001
17454
|
var AutomationConditionTraceNodeSchema = object({
|
|
17002
|
-
/** `
|
|
17455
|
+
/** `when` for the root, `when.<i>` for its i-th child, … (`conditions…` on an old trace). */
|
|
17003
17456
|
path: string().min(1),
|
|
17004
17457
|
kind: _enum([
|
|
17005
17458
|
"all",
|
|
17006
17459
|
"any",
|
|
17007
17460
|
"not",
|
|
17008
17461
|
"condition",
|
|
17462
|
+
"device-is",
|
|
17009
17463
|
"expression",
|
|
17010
|
-
"stationary-present"
|
|
17464
|
+
"stationary-present",
|
|
17465
|
+
"device-becomes",
|
|
17466
|
+
"device-event",
|
|
17467
|
+
"schedule",
|
|
17468
|
+
"interval",
|
|
17469
|
+
"manual",
|
|
17470
|
+
"detection",
|
|
17471
|
+
"stationary"
|
|
17011
17472
|
]),
|
|
17012
17473
|
outcome: TraceNodeOutcomeSchema,
|
|
17013
17474
|
reason: string(),
|
|
@@ -17041,6 +17502,12 @@ var AutomationStepTraceSchema = object({
|
|
|
17041
17502
|
deviceId: number().int().optional(),
|
|
17042
17503
|
startedAt: number().optional(),
|
|
17043
17504
|
endedAt: number().optional(),
|
|
17505
|
+
/**
|
|
17506
|
+
* The parameters the step SENT, after `{{vars.x}}` substitution — what the
|
|
17507
|
+
* device was actually asked. Bounded like trigger `vars`; a secret parameter
|
|
17508
|
+
* is shown as {@link REDACTED_ARG}. Absent on traces written before it existed.
|
|
17509
|
+
*/
|
|
17510
|
+
args: record(string(), TraceValueSchema).optional(),
|
|
17044
17511
|
outcome: _enum([
|
|
17045
17512
|
"ok",
|
|
17046
17513
|
"error",
|
|
@@ -17809,6 +18276,23 @@ method(object({
|
|
|
17809
18276
|
addonId: string(),
|
|
17810
18277
|
nodeId: string().optional()
|
|
17811
18278
|
}), SettingsSchemaWithValuesSchema.nullable()), method(object({
|
|
18279
|
+
addonId: string(),
|
|
18280
|
+
nodeId: string().optional()
|
|
18281
|
+
}), object({ keys: array(string()) }).nullable(), { auth: "admin" }), method(object({
|
|
18282
|
+
addonId: string(),
|
|
18283
|
+
nodeId: string().optional(),
|
|
18284
|
+
keys: array(string())
|
|
18285
|
+
}), object({
|
|
18286
|
+
removed: array(string()),
|
|
18287
|
+
refused: array(object({
|
|
18288
|
+
key: string(),
|
|
18289
|
+
reason: string()
|
|
18290
|
+
})),
|
|
18291
|
+
secretsCleared: number()
|
|
18292
|
+
}), {
|
|
18293
|
+
kind: "mutation",
|
|
18294
|
+
auth: "admin"
|
|
18295
|
+
}), method(object({
|
|
17812
18296
|
addonId: string(),
|
|
17813
18297
|
deviceId: number(),
|
|
17814
18298
|
nodeId: string().optional()
|
|
@@ -21764,6 +22248,8 @@ var StorageKindSchema = object({
|
|
|
21764
22248
|
"orphaned",
|
|
21765
22249
|
"dropped"
|
|
21766
22250
|
]),
|
|
22251
|
+
/** An owner declared this kind since the engine started. */
|
|
22252
|
+
declaredThisBoot: boolean(),
|
|
21767
22253
|
/** `null` when the caller asked for no counts (`counts: false`). */
|
|
21768
22254
|
rows: number().int().nonnegative().nullable(),
|
|
21769
22255
|
/** Rows x the average size of a sample; null for an empty kind. */
|
|
@@ -21775,6 +22261,51 @@ var StorageKindSchema = object({
|
|
|
21775
22261
|
/** The whole declaration, secret paths and entry descriptor included (the entries service builds its handle from it). */
|
|
21776
22262
|
declaration: RecordKindDeclarationSchema
|
|
21777
22263
|
});
|
|
22264
|
+
_enum([
|
|
22265
|
+
"orphaned",
|
|
22266
|
+
"stale",
|
|
22267
|
+
"unknown"
|
|
22268
|
+
]);
|
|
22269
|
+
/** A record kind nobody declared since its owner started, or whose owner is gone. */
|
|
22270
|
+
var StaleKindFindingSchema = object({
|
|
22271
|
+
owner: string(),
|
|
22272
|
+
kind: string(),
|
|
22273
|
+
/** `unknown`: the owner could not be judged (not running, or its state unreadable) - never dropped. */
|
|
22274
|
+
verdict: _enum(["orphaned", "unknown"]),
|
|
22275
|
+
reason: string(),
|
|
22276
|
+
rows: number().int().nonnegative().nullable(),
|
|
22277
|
+
/** local-auth's tables are never dropped by this audit. */
|
|
22278
|
+
protected: boolean()
|
|
22279
|
+
});
|
|
22280
|
+
/** A stored global-settings key the running addon no longer declares. */
|
|
22281
|
+
var StaleSettingsKeyFindingSchema = object({
|
|
22282
|
+
addonId: string(),
|
|
22283
|
+
/** The stored key as written, a per-node `<key>@<nodeId>` suffix included. */
|
|
22284
|
+
key: string(),
|
|
22285
|
+
/**
|
|
22286
|
+
* Keychain refs whose ONLY marker sits under this key: in use by stale data,
|
|
22287
|
+
* not orphans yet. Removing the key releases them.
|
|
22288
|
+
*/
|
|
22289
|
+
secretRefs: array(string())
|
|
22290
|
+
});
|
|
22291
|
+
/** An addon the audit could not judge, with the reason. Never reported as stale. */
|
|
22292
|
+
var StaleUnknownSchema = object({
|
|
22293
|
+
subject: string(),
|
|
22294
|
+
reason: string()
|
|
22295
|
+
});
|
|
22296
|
+
var StaleDataReportSchema = object({
|
|
22297
|
+
/** Epoch ms of the last finished scan; `null` before the first. */
|
|
22298
|
+
scannedAt: number().nullable(),
|
|
22299
|
+
scanning: boolean(),
|
|
22300
|
+
trigger: _enum([
|
|
22301
|
+
"boot",
|
|
22302
|
+
"interval",
|
|
22303
|
+
"manual"
|
|
22304
|
+
]).nullable(),
|
|
22305
|
+
kinds: array(StaleKindFindingSchema),
|
|
22306
|
+
settingsKeys: array(StaleSettingsKeyFindingSchema),
|
|
22307
|
+
unknown: array(StaleUnknownSchema)
|
|
22308
|
+
});
|
|
21778
22309
|
method(object({ ownerPrefix: string().min(1).optional() }), object({ tables: array(StorageTableSchema) }), { auth: "admin" }), method(object({
|
|
21779
22310
|
owner: string().min(1).optional(),
|
|
21780
22311
|
/** `false` skips the per-kind row count (a catalog read only). Default true. */
|
|
@@ -21782,7 +22313,30 @@ method(object({ ownerPrefix: string().min(1).optional() }), object({ tables: arr
|
|
|
21782
22313
|
}), object({ kinds: array(StorageKindSchema) }), { auth: "admin" }), method(RecordQueryInputSchema.extend({
|
|
21783
22314
|
owner: string().min(1),
|
|
21784
22315
|
kind: RecordKindNameSchema
|
|
21785
|
-
}), RecordQueryResultSchema, { auth: "admin" })
|
|
22316
|
+
}), RecordQueryResultSchema, { auth: "admin" }), method(object({}), StaleDataReportSchema, { auth: "admin" }), method(object({}), StaleDataReportSchema, {
|
|
22317
|
+
kind: "mutation",
|
|
22318
|
+
auth: "admin"
|
|
22319
|
+
}), method(object({
|
|
22320
|
+
owner: string().min(1),
|
|
22321
|
+
kind: RecordKindNameSchema
|
|
22322
|
+
}), object({
|
|
22323
|
+
deleted: number().int().nonnegative(),
|
|
22324
|
+
secretsReleased: number().int().nonnegative()
|
|
22325
|
+
}), {
|
|
22326
|
+
kind: "mutation",
|
|
22327
|
+
auth: "admin",
|
|
22328
|
+
caller: "required"
|
|
22329
|
+
}), method(object({
|
|
22330
|
+
addonId: string().min(1),
|
|
22331
|
+
key: string().min(1)
|
|
22332
|
+
}), object({
|
|
22333
|
+
removed: boolean(),
|
|
22334
|
+
secretsCleared: number().int().nonnegative()
|
|
22335
|
+
}), {
|
|
22336
|
+
kind: "mutation",
|
|
22337
|
+
auth: "admin",
|
|
22338
|
+
caller: "required"
|
|
22339
|
+
});
|
|
21786
22340
|
/**
|
|
21787
22341
|
* record-entries - the ONE admin surface for every list of user-created entries
|
|
21788
22342
|
* (D881): notification targets, brokers, LLM profiles, anything an addon
|
|
@@ -21921,6 +22475,12 @@ method(object({
|
|
|
21921
22475
|
}), method(object({ deviceId: number().int() }), object({ refs: array(string()).readonly() }), {
|
|
21922
22476
|
kind: "mutation",
|
|
21923
22477
|
auth: "admin"
|
|
22478
|
+
}), method(object({
|
|
22479
|
+
refs: RefListSchema,
|
|
22480
|
+
onBehalfOf: string().min(1)
|
|
22481
|
+
}), object({ released: number().int() }), {
|
|
22482
|
+
kind: "mutation",
|
|
22483
|
+
auth: "admin"
|
|
21924
22484
|
}), method(object({}), array(KeychainSecretMetaSchema).readonly(), { auth: "admin" }), method(object({}), KeychainStateSchema, { auth: "admin" });
|
|
21925
22485
|
/**
|
|
21926
22486
|
* device-history — the ONE mechanism for numeric history (D850).
|
|
@@ -22710,7 +23270,9 @@ var DiscoveredChildDeviceSchema = lazy(() => object({
|
|
|
22710
23270
|
/** Upstream-system identity + rendering hints for the candidate. */
|
|
22711
23271
|
sourceInfo: SourceInfoSchema.optional(),
|
|
22712
23272
|
/** Nested entity-children for accordion preview — integrations populate, Hubs omit. */
|
|
22713
|
-
children: array(DiscoveredChildDeviceSchema).readonly().optional()
|
|
23273
|
+
children: array(DiscoveredChildDeviceSchema).readonly().optional(),
|
|
23274
|
+
/** `childNativeId` of the gateway candidate in the same list this device sits behind. */
|
|
23275
|
+
parentStableId: string().optional()
|
|
22714
23276
|
}));
|
|
22715
23277
|
/**
|
|
22716
23278
|
* Status block — populated by the integration after each
|
|
@@ -43043,6 +43605,79 @@ object({
|
|
|
43043
43605
|
metadata: record(string(), unknown()).optional()
|
|
43044
43606
|
});
|
|
43045
43607
|
/**
|
|
43608
|
+
* HOW a provider can be found on the network. The provider only DECLARES the
|
|
43609
|
+
* mode; the `local-network` scan engine runs it once for every provider that
|
|
43610
|
+
* asked (one multicast browse, one host sweep) and hands the raw hits back to
|
|
43611
|
+
* `classifyDiscoveryHits`. A provider never opens a discovery socket itself,
|
|
43612
|
+
* except through a `custom` mode.
|
|
43613
|
+
*/
|
|
43614
|
+
var DiscoveryModeSchema = discriminatedUnion("kind", [
|
|
43615
|
+
object({
|
|
43616
|
+
kind: literal("mdns"),
|
|
43617
|
+
/** DNS-SD service type, e.g. `_esphomelib._tcp`. */
|
|
43618
|
+
serviceType: string().min(1),
|
|
43619
|
+
/** Regular expression an instance name must match (case-insensitive). */
|
|
43620
|
+
instancePattern: string().optional()
|
|
43621
|
+
}),
|
|
43622
|
+
object({
|
|
43623
|
+
kind: literal("ws-discovery"),
|
|
43624
|
+
/** Probe types (e.g. `dn:NetworkVideoTransmitter`); omitted = any device. */
|
|
43625
|
+
types: array(string()).optional()
|
|
43626
|
+
}),
|
|
43627
|
+
object({
|
|
43628
|
+
kind: literal("ssdp"),
|
|
43629
|
+
searchTarget: string().min(1)
|
|
43630
|
+
}),
|
|
43631
|
+
object({
|
|
43632
|
+
kind: literal("udp-broadcast"),
|
|
43633
|
+
port: number().int().min(1).max(65535),
|
|
43634
|
+
payloadHex: string().regex(/^([0-9a-fA-F]{2})*$/),
|
|
43635
|
+
/** Port replies arrive on, when the device answers somewhere other than the source port. */
|
|
43636
|
+
listenPort: number().int().min(1).max(65535).optional()
|
|
43637
|
+
}),
|
|
43638
|
+
object({
|
|
43639
|
+
kind: literal("http-probe"),
|
|
43640
|
+
port: number().int().min(1).max(65535),
|
|
43641
|
+
path: string().startsWith("/"),
|
|
43642
|
+
method: _enum(["GET", "POST"]).default("GET"),
|
|
43643
|
+
bodyText: string().optional(),
|
|
43644
|
+
contentType: string().optional(),
|
|
43645
|
+
tls: boolean().default(false),
|
|
43646
|
+
/** Status codes that count as a hit. Omitted = any HTTP answer. */
|
|
43647
|
+
acceptStatus: array(number().int()).optional()
|
|
43648
|
+
}),
|
|
43649
|
+
object({
|
|
43650
|
+
kind: literal("custom"),
|
|
43651
|
+
/** Why the engine cannot do it (an allowlisted exception, e.g. a vendor UDP protocol). */
|
|
43652
|
+
reason: string().min(1)
|
|
43653
|
+
})
|
|
43654
|
+
]);
|
|
43655
|
+
/** What the engine saw on the wire for ONE declared mode; the provider classifies it. */
|
|
43656
|
+
var DiscoveryHitSchema = object({
|
|
43657
|
+
/** Index into the provider's own `getDiscoveryModes()` array. */
|
|
43658
|
+
modeIndex: number().int().min(0),
|
|
43659
|
+
host: string(),
|
|
43660
|
+
port: number().int(),
|
|
43661
|
+
http: object({
|
|
43662
|
+
status: number().int(),
|
|
43663
|
+
headers: record(string(), string()),
|
|
43664
|
+
/** At most 16 KiB. */
|
|
43665
|
+
bodyText: string()
|
|
43666
|
+
}).optional(),
|
|
43667
|
+
mdns: object({
|
|
43668
|
+
instance: string(),
|
|
43669
|
+
host: string(),
|
|
43670
|
+
port: number().int(),
|
|
43671
|
+
txt: record(string(), string())
|
|
43672
|
+
}).optional(),
|
|
43673
|
+
udp: object({ payloadHex: string() }).optional(),
|
|
43674
|
+
wsd: object({
|
|
43675
|
+
xaddrs: array(string()),
|
|
43676
|
+
types: array(string()),
|
|
43677
|
+
scopes: array(string())
|
|
43678
|
+
}).optional()
|
|
43679
|
+
});
|
|
43680
|
+
/**
|
|
43046
43681
|
* Candidate handed back from discovery and accepted by
|
|
43047
43682
|
* `adoptDiscoveredDevice`. Shape mirrors the in-process
|
|
43048
43683
|
* `DiscoveredDevice` interface used by `DeviceDiscovery`.
|
|
@@ -43077,7 +43712,17 @@ var DiscoveryCandidateSchema = object({
|
|
|
43077
43712
|
/** Numeric id of the device this candidate was matched to. Set with `alreadyOnboarded`. */
|
|
43078
43713
|
onboardedDeviceId: number().optional(),
|
|
43079
43714
|
/** Operator-facing name of the matched device, so the UI can say WHICH one it is. */
|
|
43080
|
-
onboardedName: string().optional()
|
|
43715
|
+
onboardedName: string().optional(),
|
|
43716
|
+
/**
|
|
43717
|
+
* This candidate is an INTEGRATION to set up (a gateway, a hub, a controller),
|
|
43718
|
+
* not a device to adopt. Replaces the `prefilledConfig.setupIntegration` marker,
|
|
43719
|
+
* which is still read for one release.
|
|
43720
|
+
*/
|
|
43721
|
+
setupIntegration: boolean().optional(),
|
|
43722
|
+
/** `stableId` of the gateway candidate this device was found BEHIND. */
|
|
43723
|
+
parentStableId: string().optional(),
|
|
43724
|
+
/** `false` = shown for context but not pickable. Default true. */
|
|
43725
|
+
selectable: boolean().optional()
|
|
43081
43726
|
});
|
|
43082
43727
|
/**
|
|
43083
43728
|
* Flat device summary returned by `createDevice` / `adoptDiscoveredDevice`.
|
|
@@ -43130,6 +43775,12 @@ method(_void(), _void(), { kind: "mutation" }), method(_void(), _void(), { kind:
|
|
|
43130
43775
|
}), method(object({}), boolean()), method(object({ params: record(string(), unknown()).optional() }), array(DiscoveryCandidateSchema), {
|
|
43131
43776
|
kind: "mutation",
|
|
43132
43777
|
auth: "admin"
|
|
43778
|
+
}), method(object({}), array(DiscoveryModeSchema)), method(object({
|
|
43779
|
+
hits: array(DiscoveryHitSchema),
|
|
43780
|
+
params: record(string(), unknown()).optional()
|
|
43781
|
+
}), array(DiscoveryCandidateSchema), {
|
|
43782
|
+
kind: "mutation",
|
|
43783
|
+
auth: "admin"
|
|
43133
43784
|
}), method(object({}), CreationSchemaOutputSchema), method(object({}), object({ deviceType: _enum(DeviceType).nullable() })), method(object({ candidate: DiscoveryCandidateSchema }), DeviceSummarySchema, {
|
|
43134
43785
|
kind: "mutation",
|
|
43135
43786
|
auth: "admin"
|
|
@@ -43857,17 +44508,23 @@ method(object({
|
|
|
43857
44508
|
}), method(object({}), object({ providers: array(object({
|
|
43858
44509
|
addonId: string(),
|
|
43859
44510
|
label: string()
|
|
43860
|
-
})).readonly() }), { auth: "admin" }), method(
|
|
43861
|
-
|
|
43862
|
-
|
|
43863
|
-
|
|
43864
|
-
|
|
43865
|
-
|
|
43866
|
-
|
|
43867
|
-
|
|
43868
|
-
}),
|
|
44511
|
+
})).readonly() }), { auth: "admin" }), method(
|
|
44512
|
+
/** `subnets`: extra CIDRs for THIS scan, on top of the hub's own and the saved list. */
|
|
44513
|
+
object({ subnets: array(string()).optional() }),
|
|
44514
|
+
object({ groups: array(object({
|
|
44515
|
+
addonId: string(),
|
|
44516
|
+
label: string(),
|
|
44517
|
+
candidates: array(DiscoveryCandidateSchema).readonly(),
|
|
44518
|
+
error: string().nullable()
|
|
44519
|
+
})).readonly() }),
|
|
44520
|
+
{
|
|
44521
|
+
kind: "mutation",
|
|
44522
|
+
auth: "admin"
|
|
44523
|
+
}
|
|
44524
|
+
), method(object({
|
|
43869
44525
|
addonId: string(),
|
|
43870
|
-
params: record(string(), unknown()).optional()
|
|
44526
|
+
params: record(string(), unknown()).optional(),
|
|
44527
|
+
subnets: array(string()).optional()
|
|
43871
44528
|
}), object({ candidates: array(DiscoveryCandidateSchema).readonly() }), {
|
|
43872
44529
|
kind: "mutation",
|
|
43873
44530
|
auth: "admin"
|
|
@@ -56437,6 +57094,12 @@ var TerminalInstanceInfoSchema = object({
|
|
|
56437
57094
|
instanceId: string(),
|
|
56438
57095
|
cameraStableId: string(),
|
|
56439
57096
|
nodeId: string(),
|
|
57097
|
+
/**
|
|
57098
|
+
* False while the node the instance is bound to is not in the cluster
|
|
57099
|
+
* topology (forgotten, renamed, re-paired). The instance is kept; the
|
|
57100
|
+
* operator re-points it with `updateInstance({ targetNodeId })`.
|
|
57101
|
+
*/
|
|
57102
|
+
nodeInCluster: boolean(),
|
|
56440
57103
|
profileId: string(),
|
|
56441
57104
|
profileLabel: string(),
|
|
56442
57105
|
name: string(),
|
|
@@ -56486,6 +57149,8 @@ method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }),
|
|
|
56486
57149
|
auth: "admin"
|
|
56487
57150
|
}), method(object({
|
|
56488
57151
|
instanceId: string().min(1),
|
|
57152
|
+
/** Re-point the instance to another node; the profile must exist there. */
|
|
57153
|
+
targetNodeId: string().min(1).max(256).optional(),
|
|
56489
57154
|
name: string().trim().min(1).max(160).optional(),
|
|
56490
57155
|
executable: string().max(1024).optional(),
|
|
56491
57156
|
args: array(string().max(2048)).max(64).optional(),
|
|
@@ -61546,7 +62211,9 @@ method(_void(), array(IntegrationWithStateSchema)), method(object({ id: string()
|
|
|
61546
62211
|
id: string(),
|
|
61547
62212
|
settings: record(string(), unknown()),
|
|
61548
62213
|
/** Keys the form's schema declares secret (by type) — keychain-stored (D787). */
|
|
61549
|
-
secretKeys: array(string()).optional()
|
|
62214
|
+
secretKeys: array(string()).optional(),
|
|
62215
|
+
/** The integration's own addon applies the change in-process and asks the hub not to respawn it. */
|
|
62216
|
+
skipRestart: boolean().optional()
|
|
61550
62217
|
}), object({ success: boolean() }), {
|
|
61551
62218
|
kind: "mutation",
|
|
61552
62219
|
auth: "admin"
|
|
@@ -62023,6 +62690,39 @@ var TlsStatusSchema = object({
|
|
|
62023
62690
|
hasCa: boolean()
|
|
62024
62691
|
}).nullable()
|
|
62025
62692
|
});
|
|
62693
|
+
/** One provider's ask of the scan engine: the modes it declared. */
|
|
62694
|
+
var ScanRequestSchema = object({
|
|
62695
|
+
providerId: string().min(1),
|
|
62696
|
+
modes: array(DiscoveryModeSchema)
|
|
62697
|
+
});
|
|
62698
|
+
var ScanErrorSchema = object({
|
|
62699
|
+
/** Absent for a failure that is the scan's own (a bad subnet, a socket that would not open). */
|
|
62700
|
+
providerId: string().optional(),
|
|
62701
|
+
/** The mode family that failed (`mdns`, `http-probe`, …). */
|
|
62702
|
+
mode: string().optional(),
|
|
62703
|
+
message: string()
|
|
62704
|
+
});
|
|
62705
|
+
/** What one scan did, per mode family; the engine logs the same numbers once. */
|
|
62706
|
+
var ScanStatsSchema = object({
|
|
62707
|
+
hostsProbed: number().int(),
|
|
62708
|
+
hits: number().int(),
|
|
62709
|
+
timeouts: number().int(),
|
|
62710
|
+
byMode: record(string(), object({
|
|
62711
|
+
probed: number().int(),
|
|
62712
|
+
hits: number().int(),
|
|
62713
|
+
timeouts: number().int()
|
|
62714
|
+
}))
|
|
62715
|
+
});
|
|
62716
|
+
var ScanNetworkResultSchema = object({
|
|
62717
|
+
hits: array(object({
|
|
62718
|
+
providerId: string(),
|
|
62719
|
+
hit: DiscoveryHitSchema
|
|
62720
|
+
})),
|
|
62721
|
+
/** CIDRs actually covered: the hub's own /24s, the saved list and the per-call list. */
|
|
62722
|
+
subnetsScanned: array(string()),
|
|
62723
|
+
errors: array(ScanErrorSchema),
|
|
62724
|
+
stats: ScanStatsSchema
|
|
62725
|
+
});
|
|
62026
62726
|
method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
|
|
62027
62727
|
/**
|
|
62028
62728
|
* LEGACY HINT — do not send from new code. Kept optional so clients
|
|
@@ -62077,6 +62777,16 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
|
|
|
62077
62777
|
}), method(_void(), object({ pem: string() })), method(_void(), TlsStatusSchema, {
|
|
62078
62778
|
kind: "mutation",
|
|
62079
62779
|
auth: "admin"
|
|
62780
|
+
}), method(object({
|
|
62781
|
+
requests: array(ScanRequestSchema),
|
|
62782
|
+
subnets: array(string()).optional()
|
|
62783
|
+
}), ScanNetworkResultSchema, {
|
|
62784
|
+
kind: "mutation",
|
|
62785
|
+
auth: "admin",
|
|
62786
|
+
timeoutMs: 9e4
|
|
62787
|
+
}), method(_void(), object({ subnets: array(string()) }), { auth: "admin" }), method(object({ subnets: array(string()) }), object({ subnets: array(string()) }), {
|
|
62788
|
+
kind: "mutation",
|
|
62789
|
+
auth: "admin"
|
|
62080
62790
|
}), method(_void(), TlsStatusSchema, {
|
|
62081
62791
|
kind: "mutation",
|
|
62082
62792
|
auth: "admin"
|
|
@@ -68918,6 +69628,13 @@ Object.freeze({
|
|
|
68918
69628
|
access: "create",
|
|
68919
69629
|
role: "admin"
|
|
68920
69630
|
},
|
|
69631
|
+
"addonSettings.getDeclaredSettingsKeys": {
|
|
69632
|
+
capName: "addon-settings",
|
|
69633
|
+
capScope: "system",
|
|
69634
|
+
addonId: null,
|
|
69635
|
+
access: "view",
|
|
69636
|
+
role: "admin"
|
|
69637
|
+
},
|
|
68921
69638
|
"addonSettings.getDeviceSettings": {
|
|
68922
69639
|
capName: "addon-settings",
|
|
68923
69640
|
capScope: "system",
|
|
@@ -68939,6 +69656,13 @@ Object.freeze({
|
|
|
68939
69656
|
access: "view",
|
|
68940
69657
|
role: "admin"
|
|
68941
69658
|
},
|
|
69659
|
+
"addonSettings.unsetStoredSettingsKeys": {
|
|
69660
|
+
capName: "addon-settings",
|
|
69661
|
+
capScope: "system",
|
|
69662
|
+
addonId: null,
|
|
69663
|
+
access: "create",
|
|
69664
|
+
role: "admin"
|
|
69665
|
+
},
|
|
68942
69666
|
"addonSettings.updateDeviceSettings": {
|
|
68943
69667
|
capName: "addon-settings",
|
|
68944
69668
|
capScope: "system",
|
|
@@ -71354,6 +72078,13 @@ Object.freeze({
|
|
|
71354
72078
|
access: "create",
|
|
71355
72079
|
role: "admin"
|
|
71356
72080
|
},
|
|
72081
|
+
"deviceProvider.classifyDiscoveryHits": {
|
|
72082
|
+
capName: "device-provider",
|
|
72083
|
+
capScope: "system",
|
|
72084
|
+
addonId: null,
|
|
72085
|
+
access: "create",
|
|
72086
|
+
role: "admin"
|
|
72087
|
+
},
|
|
71357
72088
|
"deviceProvider.createDevice": {
|
|
71358
72089
|
capName: "device-provider",
|
|
71359
72090
|
capScope: "system",
|
|
@@ -71382,6 +72113,13 @@ Object.freeze({
|
|
|
71382
72113
|
access: "view",
|
|
71383
72114
|
role: "admin"
|
|
71384
72115
|
},
|
|
72116
|
+
"deviceProvider.getDiscoveryModes": {
|
|
72117
|
+
capName: "device-provider",
|
|
72118
|
+
capScope: "system",
|
|
72119
|
+
addonId: null,
|
|
72120
|
+
access: "view",
|
|
72121
|
+
role: "admin"
|
|
72122
|
+
},
|
|
71385
72123
|
"deviceProvider.getDiscoveryParamsSchema": {
|
|
71386
72124
|
capName: "device-provider",
|
|
71387
72125
|
capScope: "system",
|
|
@@ -72159,6 +72897,13 @@ Object.freeze({
|
|
|
72159
72897
|
access: "create",
|
|
72160
72898
|
role: "admin"
|
|
72161
72899
|
},
|
|
72900
|
+
"keychain.releaseRecordRefs": {
|
|
72901
|
+
capName: "keychain",
|
|
72902
|
+
capScope: "system",
|
|
72903
|
+
addonId: null,
|
|
72904
|
+
access: "create",
|
|
72905
|
+
role: "admin"
|
|
72906
|
+
},
|
|
72162
72907
|
"keychain.resolve": {
|
|
72163
72908
|
capName: "keychain",
|
|
72164
72909
|
capScope: "system",
|
|
@@ -72579,6 +73324,13 @@ Object.freeze({
|
|
|
72579
73324
|
access: "view",
|
|
72580
73325
|
role: "admin"
|
|
72581
73326
|
},
|
|
73327
|
+
"localNetwork.getScanSubnets": {
|
|
73328
|
+
capName: "local-network",
|
|
73329
|
+
capScope: "system",
|
|
73330
|
+
addonId: null,
|
|
73331
|
+
access: "view",
|
|
73332
|
+
role: "admin"
|
|
73333
|
+
},
|
|
72582
73334
|
"localNetwork.getTlsStatus": {
|
|
72583
73335
|
capName: "local-network",
|
|
72584
73336
|
capScope: "system",
|
|
@@ -72628,6 +73380,13 @@ Object.freeze({
|
|
|
72628
73380
|
access: "create",
|
|
72629
73381
|
role: "admin"
|
|
72630
73382
|
},
|
|
73383
|
+
"localNetwork.scanNetwork": {
|
|
73384
|
+
capName: "local-network",
|
|
73385
|
+
capScope: "system",
|
|
73386
|
+
addonId: null,
|
|
73387
|
+
access: "create",
|
|
73388
|
+
role: "admin"
|
|
73389
|
+
},
|
|
72631
73390
|
"localNetwork.setAddressRole": {
|
|
72632
73391
|
capName: "local-network",
|
|
72633
73392
|
capScope: "system",
|
|
@@ -72649,6 +73408,13 @@ Object.freeze({
|
|
|
72649
73408
|
access: "create",
|
|
72650
73409
|
role: "admin"
|
|
72651
73410
|
},
|
|
73411
|
+
"localNetwork.setScanSubnets": {
|
|
73412
|
+
capName: "local-network",
|
|
73413
|
+
capScope: "system",
|
|
73414
|
+
addonId: null,
|
|
73415
|
+
access: "create",
|
|
73416
|
+
role: "admin"
|
|
73417
|
+
},
|
|
72652
73418
|
"localNetwork.setViewerEndpoints": {
|
|
72653
73419
|
capName: "local-network",
|
|
72654
73420
|
capScope: "system",
|
|
@@ -76870,6 +77636,13 @@ Object.freeze({
|
|
|
76870
77636
|
access: "create",
|
|
76871
77637
|
role: "admin"
|
|
76872
77638
|
},
|
|
77639
|
+
"storageAdmin.dropOrphanedKind": {
|
|
77640
|
+
capName: "storage-admin",
|
|
77641
|
+
capScope: "system",
|
|
77642
|
+
addonId: null,
|
|
77643
|
+
access: "delete",
|
|
77644
|
+
role: "admin"
|
|
77645
|
+
},
|
|
76873
77646
|
"storageAdmin.listKinds": {
|
|
76874
77647
|
capName: "storage-admin",
|
|
76875
77648
|
capScope: "system",
|
|
@@ -76891,6 +77664,27 @@ Object.freeze({
|
|
|
76891
77664
|
access: "view",
|
|
76892
77665
|
role: "admin"
|
|
76893
77666
|
},
|
|
77667
|
+
"storageAdmin.scanStaleData": {
|
|
77668
|
+
capName: "storage-admin",
|
|
77669
|
+
capScope: "system",
|
|
77670
|
+
addonId: null,
|
|
77671
|
+
access: "create",
|
|
77672
|
+
role: "admin"
|
|
77673
|
+
},
|
|
77674
|
+
"storageAdmin.staleDataReport": {
|
|
77675
|
+
capName: "storage-admin",
|
|
77676
|
+
capScope: "system",
|
|
77677
|
+
addonId: null,
|
|
77678
|
+
access: "view",
|
|
77679
|
+
role: "admin"
|
|
77680
|
+
},
|
|
77681
|
+
"storageAdmin.unsetStaleSettingsKey": {
|
|
77682
|
+
capName: "storage-admin",
|
|
77683
|
+
capScope: "system",
|
|
77684
|
+
addonId: null,
|
|
77685
|
+
access: "create",
|
|
77686
|
+
role: "admin"
|
|
77687
|
+
},
|
|
76894
77688
|
"storageEvictable.evict": {
|
|
76895
77689
|
capName: "storage-evictable",
|
|
76896
77690
|
capScope: "system",
|