@camstack/addon-post-analysis 1.2.293 → 1.2.294
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/{clip-model-registry-BAuTHS_s.js → clip-model-registry-BVhju940.js} +232 -154
- package/dist/{clip-model-registry-D2zqXamW.mjs → clip-model-registry-Bz5BzfjI.mjs} +233 -155
- package/dist/embedding-encoder/index.js +1 -1
- package/dist/embedding-encoder/index.mjs +1 -1
- package/dist/pipeline-analytics/_stub.js +1 -1
- package/dist/pipeline-analytics/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-DW6-zerK.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-4K3NP0yl.mjs} +1 -1
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-T_INdcV8.mjs +26 -0
- package/dist/pipeline-analytics/{hostInit-CAJh3aX8.mjs → hostInit-B47ONgvZ.mjs} +1 -1
- package/dist/pipeline-analytics/index.js +268 -128
- package/dist/pipeline-analytics/index.mjs +268 -128
- package/dist/pipeline-analytics/remoteEntry.js +1 -1
- package/package.json +2 -1
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-Boh18P08.mjs +0 -26
|
@@ -5401,7 +5401,7 @@ var ZodIssueCode = {
|
|
|
5401
5401
|
var ZodFirstPartyTypeKind;
|
|
5402
5402
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5403
5403
|
//#endregion
|
|
5404
|
-
//#region ../types/dist/sleep-
|
|
5404
|
+
//#region ../types/dist/sleep-E6eD4yQS.mjs
|
|
5405
5405
|
/**
|
|
5406
5406
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5407
5407
|
* window to float samples (D455).
|
|
@@ -7016,6 +7016,10 @@ function toNodeId(idOrRunnerId) {
|
|
|
7016
7016
|
const head = idOrRunnerId.split("/")[0];
|
|
7017
7017
|
return head === void 0 || head.length === 0 ? idOrRunnerId : head;
|
|
7018
7018
|
}
|
|
7019
|
+
object({
|
|
7020
|
+
field: string().min(1),
|
|
7021
|
+
on: literal("advance")
|
|
7022
|
+
});
|
|
7019
7023
|
/**
|
|
7020
7024
|
* Output schema shared by the contribution + live methods.
|
|
7021
7025
|
*
|
|
@@ -7656,7 +7660,7 @@ function errMsg(err) {
|
|
|
7656
7660
|
return String(err);
|
|
7657
7661
|
}
|
|
7658
7662
|
//#endregion
|
|
7659
|
-
//#region ../types/dist/composition-
|
|
7663
|
+
//#region ../types/dist/composition-D5BQywfe.mjs
|
|
7660
7664
|
/**
|
|
7661
7665
|
* Deterministic SHA-256 hash of an arbitrary serialisable value. The
|
|
7662
7666
|
* canonical form sorts object keys alphabetically at every depth so two
|
|
@@ -7689,6 +7693,173 @@ function replaceWithSortedKeys(_key, value) {
|
|
|
7689
7693
|
return value;
|
|
7690
7694
|
}
|
|
7691
7695
|
/**
|
|
7696
|
+
* LA tabella "quale booleano di questo tipo di device conta come ALTO", e il
|
|
7697
|
+
* valutatore puro del suo FRONTE.
|
|
7698
|
+
*
|
|
7699
|
+
* Viveva dentro il builtin virtual-doorbell
|
|
7700
|
+
* (`@camstack/system` — `builtins/doorbell/trigger-engine.ts`) e i suoi
|
|
7701
|
+
* predicati erano privati al modulo. Il recorder ne ha bisogno per il trigger
|
|
7702
|
+
* `RecordingTriggers.sensorDeviceIds`: copiarla avrebbe creato la SECONDA
|
|
7703
|
+
* tabella, che diverge alla prima cap aggiunta e il cui sintomo — "il sensore
|
|
7704
|
+
* fa suonare il campanello ma non registra" — è esattamente D62. Quindi si
|
|
7705
|
+
* SPOSTA qui e il doorbell la ri-esporta.
|
|
7706
|
+
*
|
|
7707
|
+
* ⚠ NON è `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), e le
|
|
7708
|
+
* due non vanno unificate: quella risponde a "qual è la PAROLA di stato per una
|
|
7709
|
+
* regola" (e include `presence`, `cover`, `alarm-panel`), questa a "qual è il
|
|
7710
|
+
* booleano il cui FRONTE conta". Vocabolari deliberatamente diversi.
|
|
7711
|
+
*/
|
|
7712
|
+
/**
|
|
7713
|
+
* Known binary / switch source caps → the boolean slice field whose
|
|
7714
|
+
* false→true rise counts as ACTIVE. Every entry is "fire on active".
|
|
7715
|
+
* Sensors whose "active" reading is not a plain boolean (presence's string
|
|
7716
|
+
* state, connectivity's connected flag) are deliberately excluded — a
|
|
7717
|
+
* reconnect is not a doorbell press, and it is not a recording either.
|
|
7718
|
+
*/
|
|
7719
|
+
var SOURCE_CAP_ACTIVE_FIELD = {
|
|
7720
|
+
contact: "entryOpen",
|
|
7721
|
+
binary: "on",
|
|
7722
|
+
switch: "on",
|
|
7723
|
+
motion: "detected",
|
|
7724
|
+
flood: "flooded",
|
|
7725
|
+
gas: "detected",
|
|
7726
|
+
smoke: "detected",
|
|
7727
|
+
"carbon-monoxide": "detected",
|
|
7728
|
+
vibration: "detected",
|
|
7729
|
+
tamper: "tampered"
|
|
7730
|
+
};
|
|
7731
|
+
/**
|
|
7732
|
+
* The same caps → the slice field carrying the ms-epoch timestamp of the
|
|
7733
|
+
* last transition. Every source cap MUST appear here (guarded by a spec):
|
|
7734
|
+
* without a transition timestamp the evaluator cannot tell a genuine rise
|
|
7735
|
+
* from a boot-time hydration when the FIRST slice it ever sees is already
|
|
7736
|
+
* active, and errs towards silence — swallowing the rise.
|
|
7737
|
+
*
|
|
7738
|
+
* These timestamps are UPSTREAM ones, not ingest ones: the Home Assistant
|
|
7739
|
+
* provider derives them from `state.last_changed`, so they survive our own
|
|
7740
|
+
* restarts and correctly read as "hours ago" for a state that has been
|
|
7741
|
+
* active for hours. `motion` names its rise timestamp `lastDetectedAt`.
|
|
7742
|
+
*/
|
|
7743
|
+
var SOURCE_CAP_CHANGED_AT_FIELD = {
|
|
7744
|
+
contact: "lastChangedAt",
|
|
7745
|
+
binary: "lastChangedAt",
|
|
7746
|
+
switch: "lastChangedAt",
|
|
7747
|
+
motion: "lastDetectedAt",
|
|
7748
|
+
flood: "lastChangedAt",
|
|
7749
|
+
gas: "lastChangedAt",
|
|
7750
|
+
smoke: "lastChangedAt",
|
|
7751
|
+
"carbon-monoxide": "lastChangedAt",
|
|
7752
|
+
vibration: "lastChangedAt",
|
|
7753
|
+
tamper: "lastChangedAt"
|
|
7754
|
+
};
|
|
7755
|
+
/** Cap names whose presence in a device's bindings qualify it as a source. */
|
|
7756
|
+
var SOURCE_CAPS = Object.keys(SOURCE_CAP_ACTIVE_FIELD);
|
|
7757
|
+
/** True when a cap is a recognised binary/switch source. */
|
|
7758
|
+
function isSourceCap(capName) {
|
|
7759
|
+
return Object.prototype.hasOwnProperty.call(SOURCE_CAP_ACTIVE_FIELD, capName);
|
|
7760
|
+
}
|
|
7761
|
+
/** Extract the "active" boolean a source cap's slice carries, or null when
|
|
7762
|
+
* the cap is unknown or the field is missing / non-boolean. */
|
|
7763
|
+
function sliceActiveValue(capName, slice) {
|
|
7764
|
+
const field = SOURCE_CAP_ACTIVE_FIELD[capName];
|
|
7765
|
+
if (field === void 0) return null;
|
|
7766
|
+
const raw = slice[field];
|
|
7767
|
+
return typeof raw === "boolean" ? raw : null;
|
|
7768
|
+
}
|
|
7769
|
+
/** Ms-epoch transition timestamp a source cap's slice carries, or null when
|
|
7770
|
+
* it is absent, non-numeric or the zero "never observed" sentinel. */
|
|
7771
|
+
function sliceChangedAt(capName, slice) {
|
|
7772
|
+
const field = SOURCE_CAP_CHANGED_AT_FIELD[capName];
|
|
7773
|
+
if (field === void 0) return null;
|
|
7774
|
+
const raw = slice[field];
|
|
7775
|
+
if (typeof raw !== "number" || !Number.isFinite(raw) || raw <= 0) return null;
|
|
7776
|
+
return raw;
|
|
7777
|
+
}
|
|
7778
|
+
/**
|
|
7779
|
+
* How recent a source's own transition timestamp must be for a FIRST
|
|
7780
|
+
* sighting that is already active to count as a genuine rise rather than a
|
|
7781
|
+
* hydration of long-standing state.
|
|
7782
|
+
*/
|
|
7783
|
+
var DEFAULT_FIRST_SIGHTING_FRESHNESS_MS = 3e4;
|
|
7784
|
+
/**
|
|
7785
|
+
* The source-independent edge rule. The caller supplies an already extracted
|
|
7786
|
+
* boolean level and source timestamp; this function owns first-sighting
|
|
7787
|
+
* freshness and false-to-true detection.
|
|
7788
|
+
*/
|
|
7789
|
+
function evaluateSensorLevelEdge(input) {
|
|
7790
|
+
const timestamp = input.changedAt;
|
|
7791
|
+
const freshFloor = Math.max(input.startedAtMs, input.nowMs - input.firstSightingFreshnessMs);
|
|
7792
|
+
const firstRise = input.priorLevel === void 0 && input.level && timestamp !== null && Number.isFinite(timestamp) && timestamp >= freshFloor;
|
|
7793
|
+
const transitionRise = input.priorLevel === false && input.level && timestamp !== null && Number.isFinite(timestamp);
|
|
7794
|
+
if ((firstRise || transitionRise) && timestamp !== null) return {
|
|
7795
|
+
kind: "rise",
|
|
7796
|
+
timestamp
|
|
7797
|
+
};
|
|
7798
|
+
return {
|
|
7799
|
+
kind: "none",
|
|
7800
|
+
nextPriorLevel: input.level
|
|
7801
|
+
};
|
|
7802
|
+
}
|
|
7803
|
+
/**
|
|
7804
|
+
* IL fronte. Puro: nessun orologio proprio, nessuna memoria — il chiamante
|
|
7805
|
+
* porta `prior`, `nowMs` e il proprio `startedAtMs`.
|
|
7806
|
+
*
|
|
7807
|
+
* Il caso della PRIMA slice già attiva è trattato esplicitamente e vale come
|
|
7808
|
+
* fronte solo se il timestamp UPSTREAM della transizione è posteriore a
|
|
7809
|
+
* `startedAtMs` **e** entro `firstSightingFreshnessMs`. Entrambe le metà
|
|
7810
|
+
* servono: la sola freschezza scatterebbe su un'idratazione al boot di uno
|
|
7811
|
+
* stato flippato pochi secondi prima del riavvio, e il solo "dopo che abbiamo
|
|
7812
|
+
* iniziato" scatterebbe, su un processo di lunga vita, per una sorgente
|
|
7813
|
+
* adottata oggi il cui stato è cambiato ieri. Il caso ambiguo ERRA VERSO IL
|
|
7814
|
+
* SILENZIO e lo dichiara (`baseline-seeded-stale-active`).
|
|
7815
|
+
*/
|
|
7816
|
+
function evaluateSensorEdge(input) {
|
|
7817
|
+
const value = sliceActiveValue(input.capName, input.slice);
|
|
7818
|
+
if (value === null) return {
|
|
7819
|
+
edge: "none",
|
|
7820
|
+
value: null,
|
|
7821
|
+
reason: isSourceCap(input.capName) ? "non-boolean-value" : "unknown-cap"
|
|
7822
|
+
};
|
|
7823
|
+
if (evaluateSensorLevelEdge({
|
|
7824
|
+
level: value,
|
|
7825
|
+
changedAt: sliceChangedAt(input.capName, input.slice),
|
|
7826
|
+
priorLevel: input.prior,
|
|
7827
|
+
startedAtMs: input.startedAtMs,
|
|
7828
|
+
nowMs: input.nowMs,
|
|
7829
|
+
firstSightingFreshnessMs: input.firstSightingFreshnessMs
|
|
7830
|
+
}).kind === "rise") return {
|
|
7831
|
+
edge: "rising",
|
|
7832
|
+
value: true
|
|
7833
|
+
};
|
|
7834
|
+
if (input.prior === void 0) {
|
|
7835
|
+
if (!value) return {
|
|
7836
|
+
edge: "none",
|
|
7837
|
+
value,
|
|
7838
|
+
reason: "baseline-seeded-inactive"
|
|
7839
|
+
};
|
|
7840
|
+
return {
|
|
7841
|
+
edge: "none",
|
|
7842
|
+
value,
|
|
7843
|
+
reason: "baseline-seeded-stale-active"
|
|
7844
|
+
};
|
|
7845
|
+
}
|
|
7846
|
+
if (input.prior === value) return {
|
|
7847
|
+
edge: "none",
|
|
7848
|
+
value,
|
|
7849
|
+
reason: "no-change"
|
|
7850
|
+
};
|
|
7851
|
+
if (!value) return {
|
|
7852
|
+
edge: "none",
|
|
7853
|
+
value,
|
|
7854
|
+
reason: "falling-edge"
|
|
7855
|
+
};
|
|
7856
|
+
return {
|
|
7857
|
+
edge: "none",
|
|
7858
|
+
value,
|
|
7859
|
+
reason: "missing-timestamp"
|
|
7860
|
+
};
|
|
7861
|
+
}
|
|
7862
|
+
/**
|
|
7692
7863
|
* Error types for the safe expression engine. Two distinct classes so callers
|
|
7693
7864
|
* can tell a compile-time (grammar) failure from a runtime (evaluation)
|
|
7694
7865
|
* failure — both are non-fatal to the host: read paths degrade to "skip link".
|
|
@@ -7885,6 +8056,20 @@ var table = {
|
|
|
7885
8056
|
const present = args.flatMap((a, i) => a === null ? [] : [asFiniteNumber(a, "latest", i)]);
|
|
7886
8057
|
return present.length === 0 ? null : finiteResult(Math.max(...present), "latest");
|
|
7887
8058
|
}
|
|
8059
|
+
},
|
|
8060
|
+
rose: {
|
|
8061
|
+
minArgs: 2,
|
|
8062
|
+
maxArgs: 3,
|
|
8063
|
+
apply: () => {
|
|
8064
|
+
throw new ExpressionEvalError("rose: stateful evaluation context is required");
|
|
8065
|
+
}
|
|
8066
|
+
},
|
|
8067
|
+
count: {
|
|
8068
|
+
minArgs: 1,
|
|
8069
|
+
maxArgs: 1,
|
|
8070
|
+
apply: () => {
|
|
8071
|
+
throw new ExpressionEvalError("count: stateful evaluation context is required");
|
|
8072
|
+
}
|
|
7888
8073
|
}
|
|
7889
8074
|
};
|
|
7890
8075
|
Object.freeze(Object.assign(Object.create(null), table));
|
|
@@ -8399,6 +8584,7 @@ var CompositionItemEntrySchema = object({
|
|
|
8399
8584
|
var CompositionFeatureSchema = discriminatedUnion("kind", [object({
|
|
8400
8585
|
kind: literal("fields"),
|
|
8401
8586
|
cap: string().min(1),
|
|
8587
|
+
enabled: boolean().optional(),
|
|
8402
8588
|
fields: record(string().min(1), CompositionFieldSourceSchema).refine((fields) => Object.keys(fields).length <= 32, { message: `at most 32 fields per capability` }),
|
|
8403
8589
|
/**
|
|
8404
8590
|
* Items of the cap's item array, keyed by item key (D663). Naming `items`
|
|
@@ -8410,6 +8596,7 @@ var CompositionFeatureSchema = discriminatedUnion("kind", [object({
|
|
|
8410
8596
|
}), object({
|
|
8411
8597
|
kind: literal("passthrough"),
|
|
8412
8598
|
cap: string().min(1),
|
|
8599
|
+
enabled: boolean().optional(),
|
|
8413
8600
|
source: CompositionSourceRefSchema
|
|
8414
8601
|
})]);
|
|
8415
8602
|
var CompositionSchema = object({
|
|
@@ -13530,6 +13717,15 @@ var cameraStreamsCapability = {
|
|
|
13530
13717
|
function kebabToCamel(s) {
|
|
13531
13718
|
return s.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
13532
13719
|
}
|
|
13720
|
+
EventCategory.DoorbellOnPressed;
|
|
13721
|
+
var CompositionEventPlanSchema = object({
|
|
13722
|
+
featureIndex: number().int().nonnegative(),
|
|
13723
|
+
cap: string(),
|
|
13724
|
+
eventName: string(),
|
|
13725
|
+
category: _enum(EventCategory),
|
|
13726
|
+
stateField: string(),
|
|
13727
|
+
fieldKey: string()
|
|
13728
|
+
});
|
|
13533
13729
|
/** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.celsius`. */
|
|
13534
13730
|
var CompositionProblemSchema = object({
|
|
13535
13731
|
code: _enum([
|
|
@@ -13579,12 +13775,14 @@ var CompositionUnavailableModeSchema = _enum([
|
|
|
13579
13775
|
]);
|
|
13580
13776
|
/**
|
|
13581
13777
|
* `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
|
|
13582
|
-
* field of its cap changes value · `constant` reads nothing, computed once
|
|
13778
|
+
* field of its cap changes value · `constant` reads nothing, computed once ·
|
|
13779
|
+
* `accumulator` advances from the target's seed/current output.
|
|
13583
13780
|
*/
|
|
13584
13781
|
var CompositionFieldRoleSchema = _enum([
|
|
13585
13782
|
"derived",
|
|
13586
13783
|
"clock",
|
|
13587
|
-
"constant"
|
|
13784
|
+
"constant",
|
|
13785
|
+
"accumulator"
|
|
13588
13786
|
]);
|
|
13589
13787
|
/** The item a planned field belongs to; its `path` is then the dotted path INSIDE the item. */
|
|
13590
13788
|
var CompositionFieldItemSchema = object({
|
|
@@ -13620,6 +13818,7 @@ var CompositionFeatureModeSchema = _enum([
|
|
|
13620
13818
|
"replace"
|
|
13621
13819
|
]);
|
|
13622
13820
|
var CompositionFeaturePlanSchema = object({
|
|
13821
|
+
/** Index in the stored feature array; disabled features are omitted rather than re-indexed. */
|
|
13623
13822
|
featureIndex: number().int().nonnegative(),
|
|
13624
13823
|
cap: string(),
|
|
13625
13824
|
mode: CompositionFeatureModeSchema
|
|
@@ -13628,7 +13827,8 @@ var CompositionValidationSchema = object({
|
|
|
13628
13827
|
ok: boolean(),
|
|
13629
13828
|
problems: array(CompositionProblemSchema),
|
|
13630
13829
|
fields: array(CompositionFieldPlanSchema),
|
|
13631
|
-
features: array(CompositionFeaturePlanSchema)
|
|
13830
|
+
features: array(CompositionFeaturePlanSchema),
|
|
13831
|
+
events: array(CompositionEventPlanSchema)
|
|
13632
13832
|
});
|
|
13633
13833
|
/**
|
|
13634
13834
|
* Mirrors `CoreBlockStatus`, pinned by `core-blocks-source.spec.ts`. `degraded`:
|
|
@@ -28949,148 +29149,6 @@ DeviceType.Camera, method(object({
|
|
|
28949
29149
|
auth: "protected"
|
|
28950
29150
|
});
|
|
28951
29151
|
/**
|
|
28952
|
-
* LA tabella "quale booleano di questo tipo di device conta come ALTO", e il
|
|
28953
|
-
* valutatore puro del suo FRONTE.
|
|
28954
|
-
*
|
|
28955
|
-
* Viveva dentro il builtin virtual-doorbell
|
|
28956
|
-
* (`@camstack/system` — `builtins/doorbell/trigger-engine.ts`) e i suoi
|
|
28957
|
-
* predicati erano privati al modulo. Il recorder ne ha bisogno per il trigger
|
|
28958
|
-
* `RecordingTriggers.sensorDeviceIds`: copiarla avrebbe creato la SECONDA
|
|
28959
|
-
* tabella, che diverge alla prima cap aggiunta e il cui sintomo — "il sensore
|
|
28960
|
-
* fa suonare il campanello ma non registra" — è esattamente D62. Quindi si
|
|
28961
|
-
* SPOSTA qui e il doorbell la ri-esporta.
|
|
28962
|
-
*
|
|
28963
|
-
* ⚠ NON è `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), e le
|
|
28964
|
-
* due non vanno unificate: quella risponde a "qual è la PAROLA di stato per una
|
|
28965
|
-
* regola" (e include `presence`, `cover`, `alarm-panel`), questa a "qual è il
|
|
28966
|
-
* booleano il cui FRONTE conta". Vocabolari deliberatamente diversi.
|
|
28967
|
-
*/
|
|
28968
|
-
/**
|
|
28969
|
-
* Known binary / switch source caps → the boolean slice field whose
|
|
28970
|
-
* false→true rise counts as ACTIVE. Every entry is "fire on active".
|
|
28971
|
-
* Sensors whose "active" reading is not a plain boolean (presence's string
|
|
28972
|
-
* state, connectivity's connected flag) are deliberately excluded — a
|
|
28973
|
-
* reconnect is not a doorbell press, and it is not a recording either.
|
|
28974
|
-
*/
|
|
28975
|
-
var SOURCE_CAP_ACTIVE_FIELD = {
|
|
28976
|
-
contact: "entryOpen",
|
|
28977
|
-
binary: "on",
|
|
28978
|
-
switch: "on",
|
|
28979
|
-
motion: "detected",
|
|
28980
|
-
flood: "flooded",
|
|
28981
|
-
gas: "detected",
|
|
28982
|
-
smoke: "detected",
|
|
28983
|
-
"carbon-monoxide": "detected",
|
|
28984
|
-
vibration: "detected",
|
|
28985
|
-
tamper: "tampered"
|
|
28986
|
-
};
|
|
28987
|
-
/**
|
|
28988
|
-
* The same caps → the slice field carrying the ms-epoch timestamp of the
|
|
28989
|
-
* last transition. Every source cap MUST appear here (guarded by a spec):
|
|
28990
|
-
* without a transition timestamp the evaluator cannot tell a genuine rise
|
|
28991
|
-
* from a boot-time hydration when the FIRST slice it ever sees is already
|
|
28992
|
-
* active, and errs towards silence — swallowing the rise.
|
|
28993
|
-
*
|
|
28994
|
-
* These timestamps are UPSTREAM ones, not ingest ones: the Home Assistant
|
|
28995
|
-
* provider derives them from `state.last_changed`, so they survive our own
|
|
28996
|
-
* restarts and correctly read as "hours ago" for a state that has been
|
|
28997
|
-
* active for hours. `motion` names its rise timestamp `lastDetectedAt`.
|
|
28998
|
-
*/
|
|
28999
|
-
var SOURCE_CAP_CHANGED_AT_FIELD = {
|
|
29000
|
-
contact: "lastChangedAt",
|
|
29001
|
-
binary: "lastChangedAt",
|
|
29002
|
-
switch: "lastChangedAt",
|
|
29003
|
-
motion: "lastDetectedAt",
|
|
29004
|
-
flood: "lastChangedAt",
|
|
29005
|
-
gas: "lastChangedAt",
|
|
29006
|
-
smoke: "lastChangedAt",
|
|
29007
|
-
"carbon-monoxide": "lastChangedAt",
|
|
29008
|
-
vibration: "lastChangedAt",
|
|
29009
|
-
tamper: "lastChangedAt"
|
|
29010
|
-
};
|
|
29011
|
-
/** Cap names whose presence in a device's bindings qualify it as a source. */
|
|
29012
|
-
var SOURCE_CAPS = Object.keys(SOURCE_CAP_ACTIVE_FIELD);
|
|
29013
|
-
/** True when a cap is a recognised binary/switch source. */
|
|
29014
|
-
function isSourceCap(capName) {
|
|
29015
|
-
return Object.prototype.hasOwnProperty.call(SOURCE_CAP_ACTIVE_FIELD, capName);
|
|
29016
|
-
}
|
|
29017
|
-
/** Extract the "active" boolean a source cap's slice carries, or null when
|
|
29018
|
-
* the cap is unknown or the field is missing / non-boolean. */
|
|
29019
|
-
function sliceActiveValue(capName, slice) {
|
|
29020
|
-
const field = SOURCE_CAP_ACTIVE_FIELD[capName];
|
|
29021
|
-
if (field === void 0) return null;
|
|
29022
|
-
const raw = slice[field];
|
|
29023
|
-
return typeof raw === "boolean" ? raw : null;
|
|
29024
|
-
}
|
|
29025
|
-
/** Ms-epoch transition timestamp a source cap's slice carries, or null when
|
|
29026
|
-
* it is absent, non-numeric or the zero "never observed" sentinel. */
|
|
29027
|
-
function sliceChangedAt(capName, slice) {
|
|
29028
|
-
const field = SOURCE_CAP_CHANGED_AT_FIELD[capName];
|
|
29029
|
-
if (field === void 0) return null;
|
|
29030
|
-
const raw = slice[field];
|
|
29031
|
-
if (typeof raw !== "number" || !Number.isFinite(raw) || raw <= 0) return null;
|
|
29032
|
-
return raw;
|
|
29033
|
-
}
|
|
29034
|
-
/**
|
|
29035
|
-
* How recent a source's own transition timestamp must be for a FIRST
|
|
29036
|
-
* sighting that is already active to count as a genuine rise rather than a
|
|
29037
|
-
* hydration of long-standing state.
|
|
29038
|
-
*/
|
|
29039
|
-
var DEFAULT_FIRST_SIGHTING_FRESHNESS_MS = 3e4;
|
|
29040
|
-
/**
|
|
29041
|
-
* IL fronte. Puro: nessun orologio proprio, nessuna memoria — il chiamante
|
|
29042
|
-
* porta `prior`, `nowMs` e il proprio `startedAtMs`.
|
|
29043
|
-
*
|
|
29044
|
-
* Il caso della PRIMA slice già attiva è trattato esplicitamente e vale come
|
|
29045
|
-
* fronte solo se il timestamp UPSTREAM della transizione è posteriore a
|
|
29046
|
-
* `startedAtMs` **e** entro `firstSightingFreshnessMs`. Entrambe le metà
|
|
29047
|
-
* servono: la sola freschezza scatterebbe su un'idratazione al boot di uno
|
|
29048
|
-
* stato flippato pochi secondi prima del riavvio, e il solo "dopo che abbiamo
|
|
29049
|
-
* iniziato" scatterebbe, su un processo di lunga vita, per una sorgente
|
|
29050
|
-
* adottata oggi il cui stato è cambiato ieri. Il caso ambiguo ERRA VERSO IL
|
|
29051
|
-
* SILENZIO e lo dichiara (`baseline-seeded-stale-active`).
|
|
29052
|
-
*/
|
|
29053
|
-
function evaluateSensorEdge(input) {
|
|
29054
|
-
const value = sliceActiveValue(input.capName, input.slice);
|
|
29055
|
-
if (value === null) return {
|
|
29056
|
-
edge: "none",
|
|
29057
|
-
value: null,
|
|
29058
|
-
reason: isSourceCap(input.capName) ? "non-boolean-value" : "unknown-cap"
|
|
29059
|
-
};
|
|
29060
|
-
if (input.prior === void 0) {
|
|
29061
|
-
if (!value) return {
|
|
29062
|
-
edge: "none",
|
|
29063
|
-
value,
|
|
29064
|
-
reason: "baseline-seeded-inactive"
|
|
29065
|
-
};
|
|
29066
|
-
const changedAt = sliceChangedAt(input.capName, input.slice);
|
|
29067
|
-
const floor = Math.max(input.startedAtMs, input.nowMs - input.firstSightingFreshnessMs);
|
|
29068
|
-
if (changedAt === null || changedAt < floor) return {
|
|
29069
|
-
edge: "none",
|
|
29070
|
-
value,
|
|
29071
|
-
reason: "baseline-seeded-stale-active"
|
|
29072
|
-
};
|
|
29073
|
-
return {
|
|
29074
|
-
edge: "rising",
|
|
29075
|
-
value: true
|
|
29076
|
-
};
|
|
29077
|
-
}
|
|
29078
|
-
if (input.prior === value) return {
|
|
29079
|
-
edge: "none",
|
|
29080
|
-
value,
|
|
29081
|
-
reason: "no-change"
|
|
29082
|
-
};
|
|
29083
|
-
if (!value) return {
|
|
29084
|
-
edge: "none",
|
|
29085
|
-
value,
|
|
29086
|
-
reason: "falling-edge"
|
|
29087
|
-
};
|
|
29088
|
-
return {
|
|
29089
|
-
edge: "rising",
|
|
29090
|
-
value: true
|
|
29091
|
-
};
|
|
29092
|
-
}
|
|
29093
|
-
/**
|
|
29094
29152
|
* Doorbell button cap. Two kinds of providers coexist behind this cap
|
|
29095
29153
|
* name (same pattern as `snapshot`):
|
|
29096
29154
|
*
|
|
@@ -29163,7 +29221,13 @@ var doorbellCapability = {
|
|
|
29163
29221
|
* push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
|
|
29164
29222
|
* release/duration — it's a pulse.
|
|
29165
29223
|
*/
|
|
29166
|
-
onPressed: {
|
|
29224
|
+
onPressed: {
|
|
29225
|
+
data: DoorbellPressEventSchema,
|
|
29226
|
+
fromState: {
|
|
29227
|
+
field: "lastPressedAt",
|
|
29228
|
+
on: "advance"
|
|
29229
|
+
}
|
|
29230
|
+
} },
|
|
29167
29231
|
status: {
|
|
29168
29232
|
schema: DoorbellStatusSchema,
|
|
29169
29233
|
kind: "push"
|
|
@@ -37105,12 +37169,21 @@ var RecordingStorageUsageSchema = object({
|
|
|
37105
37169
|
*/
|
|
37106
37170
|
devicesRead: _enum(["archive", "unavailable"]).optional(),
|
|
37107
37171
|
/**
|
|
37172
|
+
* Is the `archive` answer WHOLE (D674): the hour ledger loaded without
|
|
37173
|
+
* hitting its row cap, and at least one location resolved? Only then may a
|
|
37174
|
+
* camera ABSENT from `devices[]` be read as "no footage" — and only then is a
|
|
37175
|
+
* row's `oldestMs` the archive's oldest rather than the oldest of a fraction.
|
|
37176
|
+
* OPTIONAL: a recorder predating D674 omits it, and a consumer must read the
|
|
37177
|
+
* absence as `false`. A retention floor is a delete; it never guesses.
|
|
37178
|
+
*/
|
|
37179
|
+
complete: boolean().optional(),
|
|
37180
|
+
/**
|
|
37108
37181
|
* Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
|
|
37109
|
-
* of the payload without it:
|
|
37110
|
-
*
|
|
37111
|
-
*
|
|
37112
|
-
*
|
|
37113
|
-
*
|
|
37182
|
+
* of the payload without it: a recorder that could not build it omits it. A
|
|
37183
|
+
* UI that dereferences it unconditionally crashes the whole Storage page over
|
|
37184
|
+
* a missing disk bar. (The hub's cap routers pass output through unvalidated
|
|
37185
|
+
* since 2026-07-11 — `cap-router-builder.ts` — so a newer recorder's fields
|
|
37186
|
+
* are not stripped by an older hub.)
|
|
37114
37187
|
*/
|
|
37115
37188
|
locations: array(RecordingLocationUsageSchema).optional()
|
|
37116
37189
|
});
|
|
@@ -40654,7 +40727,12 @@ Object.freeze({
|
|
|
40654
40727
|
number: {
|
|
40655
40728
|
kind: "fixed",
|
|
40656
40729
|
result: ["number", "null"]
|
|
40657
|
-
}
|
|
40730
|
+
},
|
|
40731
|
+
rose: {
|
|
40732
|
+
kind: "fixed",
|
|
40733
|
+
result: ["number", "null"]
|
|
40734
|
+
},
|
|
40735
|
+
count: NUMBER
|
|
40658
40736
|
});
|
|
40659
40737
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
40660
40738
|
/**
|