@camstack/addon-model-studio 1.1.20 → 1.1.22
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/{MotionZonesSettings-Cu3v84EK.mjs → MotionZonesSettings-DG6lbNZk.mjs} +1 -1
- package/dist/PrivacyMaskSettings-Ba_onhD4.mjs +368 -0
- package/dist/_stub.js +13 -32
- package/dist/{_virtual_mf-localSharedImportMap___mfe_internal__addon_model_studio_page-ChXR-SrT.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_model_studio_page-DLrVxdSd.mjs} +4 -4
- package/dist/_virtual_mf___mfe_internal__addon_model_studio_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CiO5eZYn.mjs +26 -0
- package/dist/{hostInit-DTLitKtO.mjs → hostInit-4ilKnbP0.mjs} +3 -3
- package/dist/model-studio.addon.js +139 -35
- package/dist/model-studio.addon.mjs +139 -35
- package/dist/{player-overlays-9g9Wl5lu.mjs → player-overlays-Djb228qI.mjs} +1 -1
- package/dist/remoteEntry.js +1 -1
- package/dist/{trash-2-CuBBH1-r.mjs → trash-2-B52D3CTz.mjs} +21 -4
- package/dist/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_model_studio_page__remoteEntry_js-CNbwY0Zt.mjs → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_model_studio_page__remoteEntry_js-C0lWeSYH.mjs} +1 -1
- package/package.json +1 -1
- package/dist/PrivacyMaskSettings-BXCBb85n.mjs +0 -290
- package/dist/_virtual_mf___mfe_internal__addon_model_studio_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DpvRwqsx.mjs +0 -26
|
@@ -13142,7 +13142,23 @@ var NotificationActionSchema = object({
|
|
|
13142
13142
|
* else — see `notification-center/action-token.ts` for what that does and
|
|
13143
13143
|
* does not buy.
|
|
13144
13144
|
*/
|
|
13145
|
-
destructive: boolean().optional()
|
|
13145
|
+
destructive: boolean().optional(),
|
|
13146
|
+
/**
|
|
13147
|
+
* How the tap should REACH the url.
|
|
13148
|
+
*
|
|
13149
|
+
* `navigate` (absent, and every button authored before this field) opens it:
|
|
13150
|
+
* the phone leaves the notification and shows whatever the callback returns.
|
|
13151
|
+
* That is right for a button whose answer the operator wants to read.
|
|
13152
|
+
*
|
|
13153
|
+
* `background` fires it as a POST and stays put. It exists for the buttons
|
|
13154
|
+
* whose whole point is not to interrupt — "silence this for 30 minutes" is
|
|
13155
|
+
* an answer to the notification, and being thrown into a browser tab to
|
|
13156
|
+
* confirm it costs more attention than the notification did. A backend that
|
|
13157
|
+
* cannot do a background call renders it as an ordinary link (the adapters
|
|
13158
|
+
* fall back rather than dropping the button), so this is a preference, never
|
|
13159
|
+
* a requirement.
|
|
13160
|
+
*/
|
|
13161
|
+
mode: _enum(["navigate", "background"]).optional()
|
|
13146
13162
|
});
|
|
13147
13163
|
/**
|
|
13148
13164
|
* The canonical notification. `body` is the only hard field (Apprise model).
|
|
@@ -14143,6 +14159,9 @@ var NcSystemEventConditionSchema = object({
|
|
|
14143
14159
|
nodeIds: array(string().min(1)).min(1).optional(),
|
|
14144
14160
|
packageNames: array(string().min(1)).min(1).optional()
|
|
14145
14161
|
});
|
|
14162
|
+
/** Hard ceiling on a window (24h). A snooze that could not expire would be an
|
|
14163
|
+
* outage the operator asked for once and forgot. */
|
|
14164
|
+
var NC_SNOOZE_MAX_MINUTES = 1440;
|
|
14146
14165
|
/** Weekly schedule — OR of windows; absence on the rule = always active. */
|
|
14147
14166
|
var NcScheduleSchema = object({
|
|
14148
14167
|
windows: array(object({
|
|
@@ -14519,15 +14538,15 @@ var NcConditionsSchema = object({
|
|
|
14519
14538
|
* (an `immediate` rule naming an `audio-*` class, one notification per
|
|
14520
14539
|
* classified sample) stays exactly as it was for rules that already use it.
|
|
14521
14540
|
*
|
|
14522
|
-
*
|
|
14523
|
-
* rather than an
|
|
14524
|
-
* (`camstack/src/data/notification-center.ts`, guarded by
|
|
14525
|
-
* `scripts/check-viewer-condition-mirror.ts`) and its rule editor
|
|
14541
|
+
* In {@link NC_CONDITION_CATALOG} since P2, and the ORDER it got there is the
|
|
14542
|
+
* rule rather than an accident: the viewer mirrors the descriptor enums BY
|
|
14543
|
+
* HAND (`camstack/src/data/notification-center.ts`, guarded by
|
|
14544
|
+
* `scripts/check-viewer-condition-mirror.ts`) and its rule editor strips the
|
|
14526
14545
|
* condition fields it does not know when a rule is saved from the phone.
|
|
14527
14546
|
* Publishing an editor for a condition the app cannot round-trip is how an
|
|
14528
|
-
* operator loses a rule's conditions by opening it — so the
|
|
14529
|
-
*
|
|
14530
|
-
*
|
|
14547
|
+
* operator loses a rule's conditions by opening it — so the viewer mirror
|
|
14548
|
+
* (P3, shipped) went FIRST, and the descriptor an editor renders from
|
|
14549
|
+
* follows here.
|
|
14531
14550
|
*/
|
|
14532
14551
|
audio: NcAudioConditionSchema.optional()
|
|
14533
14552
|
});
|
|
@@ -14763,6 +14782,30 @@ var NcRuleInputSchema = object({
|
|
|
14763
14782
|
*/
|
|
14764
14783
|
snoozeAllowGlobal: boolean().optional(),
|
|
14765
14784
|
/**
|
|
14785
|
+
* The snooze durations THIS rule's notification offers as buttons, in
|
|
14786
|
+
* minutes.
|
|
14787
|
+
*
|
|
14788
|
+
* Three states, and all three are distinct — which is exactly why this is
|
|
14789
|
+
* `.optional()` and never `.default()`. A Zod default does not run on the
|
|
14790
|
+
* addon cap path (three production failures in one day), so a schema default
|
|
14791
|
+
* would collapse the first two:
|
|
14792
|
+
*
|
|
14793
|
+
* | value | meaning |
|
|
14794
|
+
* | --- | --- |
|
|
14795
|
+
* | absent | the operator never said ⇒ {@link NC_DEFAULT_SNOOZE_MINUTES} |
|
|
14796
|
+
* | `[]` | **no snooze buttons on this rule** — the explicit override |
|
|
14797
|
+
* | a list | these choices, de-duplicated and sorted, at most four |
|
|
14798
|
+
*
|
|
14799
|
+
* `.max(4)` because the notifier's own action budget is small (ntfy allows
|
|
14800
|
+
* three buttons in total) and a rule that spent it all on snooze choices
|
|
14801
|
+
* would push its own tap-through actions off the notification.
|
|
14802
|
+
*
|
|
14803
|
+
* An empty list is NOT an alarm exemption: a rule the alarm is about, or
|
|
14804
|
+
* that arms the panel, is exempt automatically and cannot be silenced by a
|
|
14805
|
+
* window from anywhere (D133).
|
|
14806
|
+
*/
|
|
14807
|
+
snoozeOptions: array(number().int().min(1).max(NC_SNOOZE_MAX_MINUTES)).max(4).optional(),
|
|
14808
|
+
/**
|
|
14766
14809
|
* Devices this rule ACTUATES — arm the alarm, open a gate, turn on a light.
|
|
14767
14810
|
*
|
|
14768
14811
|
* This is what makes the rule set the alarm's trigger set without the alarm
|
|
@@ -14862,6 +14905,7 @@ var NcConditionDescriptorSchema = object({
|
|
|
14862
14905
|
"device",
|
|
14863
14906
|
"package",
|
|
14864
14907
|
"occupancy",
|
|
14908
|
+
"audio",
|
|
14865
14909
|
"system"
|
|
14866
14910
|
]),
|
|
14867
14911
|
label: string(),
|
|
@@ -14880,6 +14924,7 @@ var NcConditionDescriptorSchema = object({
|
|
|
14880
14924
|
"crossingSelect",
|
|
14881
14925
|
"polygonDraw",
|
|
14882
14926
|
"occupancy",
|
|
14927
|
+
"audio",
|
|
14883
14928
|
"deviceState",
|
|
14884
14929
|
"systemEvent"
|
|
14885
14930
|
]),
|
|
@@ -15031,7 +15076,20 @@ var NcSnoozeInputSchema = object({
|
|
|
15031
15076
|
ruleId: string().optional(),
|
|
15032
15077
|
/** Required when `scope: 'device'`. */
|
|
15033
15078
|
deviceId: number().int().optional(),
|
|
15034
|
-
|
|
15079
|
+
/**
|
|
15080
|
+
* Narrow the window to these subject classes — "the cat, not the person".
|
|
15081
|
+
*
|
|
15082
|
+
* ORTHOGONAL to `scope`, deliberately, and absent means EVERY class: that is
|
|
15083
|
+
* what every window authored before this field meant, so no persisted row
|
|
15084
|
+
* changes meaning and no client has to learn anything to keep working.
|
|
15085
|
+
*
|
|
15086
|
+
* It is what makes the window's real key `(deviceId, classes[])` and lets it
|
|
15087
|
+
* cross rules (D133): the operator points at a camera and a kind of thing,
|
|
15088
|
+
* not at whichever of their four rules happened to produce the notification
|
|
15089
|
+
* they are dismissing.
|
|
15090
|
+
*/
|
|
15091
|
+
classes: array(string().min(1)).min(1).optional(),
|
|
15092
|
+
durationMinutes: number().int().min(1).max(NC_SNOOZE_MAX_MINUTES),
|
|
15035
15093
|
/**
|
|
15036
15094
|
* Silence this for EVERY recipient, not just the caller. Permission is
|
|
15037
15095
|
* checked server-side (the rule's `snoozeAllowGlobal`, or admin for the
|
|
@@ -15056,6 +15114,10 @@ var NcSnoozeSchema = object({
|
|
|
15056
15114
|
scope: NcSnoozeScopeSchema,
|
|
15057
15115
|
ruleId: string().optional(),
|
|
15058
15116
|
deviceId: number().int().optional(),
|
|
15117
|
+
/** Subject classes this window covers. ABSENT = every class — see
|
|
15118
|
+
* {@link NcSnoozeInputSchema.shape.classes}. Lives in the JSON blob and has
|
|
15119
|
+
* no SQLite column: nothing queries a window by class. */
|
|
15120
|
+
classes: array(string().min(1)).min(1).optional(),
|
|
15059
15121
|
startedAt: number(),
|
|
15060
15122
|
/** Exclusive: at exactly this instant the snooze is over. Expiry is a
|
|
15061
15123
|
* COMPARISON, not a job — no sweeper can leave the operator silenced. */
|
|
@@ -23758,13 +23820,24 @@ method(object({
|
|
|
23758
23820
|
/** Playback-speed multiplier for the render (1 = realtime). */
|
|
23759
23821
|
var ExportSpeedSchema = number().min(.25).max(32);
|
|
23760
23822
|
/**
|
|
23761
|
-
* One dense interval, in SECONDS FROM THE EXPORT'S OWN `fromMs`.
|
|
23823
|
+
* One dense interval, in WALL-CLOCK SECONDS FROM THE EXPORT'S OWN `fromMs`.
|
|
23824
|
+
*
|
|
23825
|
+
* **Wall clock, not ffmpeg's `t`** — and the recorder translates. A caller
|
|
23826
|
+
* derives these bounds from things that happened at a TIME (a track's
|
|
23827
|
+
* `firstSeen`), while `t` runs over the source playlist: the concatenation of
|
|
23828
|
+
* every segment present for the range, with each recording GAP removed. The
|
|
23829
|
+
* two agree only on a window that recorded without one interruption, and only
|
|
23830
|
+
* the render side knows the segments, so the translation lives there
|
|
23831
|
+
* (`export-dense-map.ts`, addon-pipeline).
|
|
23832
|
+
*
|
|
23833
|
+
* It was not always so. These seconds were fed to `between(t,…)` verbatim, and
|
|
23834
|
+
* on a 10 h window holding 29,393 s of footage every range landed late by the
|
|
23835
|
+
* gap accumulated before it — up to 6,607 s, well past EOF. Nothing matched,
|
|
23836
|
+
* the video was a uniform timelapse, and the log line reported the five ranges
|
|
23837
|
+
* that had been ASKED for (2026-08-13, export `57d14363`, camera 615).
|
|
23762
23838
|
*
|
|
23763
|
-
* Relative and not absolute epoch
|
|
23764
|
-
*
|
|
23765
|
-
* playlist. Handing it absolute epochs would make every call site responsible
|
|
23766
|
-
* for the same subtraction, and the one that forgot would emit a filter that
|
|
23767
|
-
* selects nothing — silently, as a uniform timelapse.
|
|
23839
|
+
* Relative and not absolute epoch, because an absolute epoch would make every
|
|
23840
|
+
* call site responsible for the same subtraction.
|
|
23768
23841
|
*/
|
|
23769
23842
|
var ExportDenseRangeSchema = object({
|
|
23770
23843
|
fromSec: number().nonnegative(),
|
|
@@ -30617,6 +30690,7 @@ Object.freeze({
|
|
|
30617
30690
|
"network-access": "ingress",
|
|
30618
30691
|
"smtp-provider": "email"
|
|
30619
30692
|
});
|
|
30693
|
+
new Map(AUDIO_MACRO_LABELS.flatMap((macro) => macro.icon === void 0 ? [] : [[macro.id, macro.icon]]));
|
|
30620
30694
|
new Set(["devices", "classes"]);
|
|
30621
30695
|
/**
|
|
30622
30696
|
* TimelapseRule — the STANDALONE scheduled timelapse producer's rule model.
|
|
@@ -30894,25 +30968,32 @@ object({
|
|
|
30894
30968
|
var NativeLeaseAdmissionSchema = _enum(["all", "inferred"]);
|
|
30895
30969
|
object({
|
|
30896
30970
|
/**
|
|
30897
|
-
* How
|
|
30971
|
+
* How many delivered frames the worker HOLDS at once, waiting for each one's
|
|
30972
|
+
* detection result.
|
|
30898
30973
|
*
|
|
30899
|
-
*
|
|
30900
|
-
*
|
|
30901
|
-
*
|
|
30902
|
-
*
|
|
30903
|
-
*
|
|
30974
|
+
* This replaced a TTL on 2026-08-13, and the replacement is the whole point:
|
|
30975
|
+
* a time window was never related to the event the pixels were waiting for.
|
|
30976
|
+
* A held frame now lives from delivery until the runner has its `FrameResult`
|
|
30977
|
+
* — at which moment the runner cuts the subject tiles it actually wanted and
|
|
30978
|
+
* releases the frame. The bound exists only so a runner that stops answering
|
|
30979
|
+
* cannot pin RAM: above it the OLDEST held frame is dropped and counted.
|
|
30980
|
+
*
|
|
30981
|
+
* Sizing: the steady state is `inferenceLatency × deliveredFps`, measured at
|
|
30982
|
+
* 40-160 ms × ≤25 fps = 1-4 frames. The default leaves headroom for a hiccup
|
|
30983
|
+
* without ever approaching the old resident set (43 frames × 24.9 MB at 4K).
|
|
30984
|
+
* Raising it does not buy hit rate — it buys tolerance for a slow runner, and
|
|
30985
|
+
* `holdOverflow` on the metrics line is what says you need it.
|
|
30904
30986
|
*/
|
|
30905
|
-
|
|
30987
|
+
holdFrames: number().int().min(1).max(64),
|
|
30906
30988
|
/**
|
|
30907
30989
|
* Hard per-decode-worker RAM ceiling for retained native frames, in MB.
|
|
30908
30990
|
*
|
|
30909
|
-
*
|
|
30910
|
-
*
|
|
30911
|
-
*
|
|
30912
|
-
*
|
|
30913
|
-
*
|
|
30914
|
-
*
|
|
30915
|
-
* rather than giving RAM back — lower this knob if RAM is what you wanted.
|
|
30991
|
+
* Since 2026-08-13 this is a SAFETY ceiling and nothing else: `holdFrames`
|
|
30992
|
+
* is what decides how much is held, and the ceiling is the number above which
|
|
30993
|
+
* something is wrong. Before that it was the effective cap — at 1024 MB with
|
|
30994
|
+
* a 2 800 ms TTL a 4K camera sat pinned at `leaseMb:1020, leaseFrames:43`
|
|
30995
|
+
* with the TTL expiring nothing, which is exactly the confusion the hold
|
|
30996
|
+
* removes. `leaseMb` / `leaseFrames` still say what is resident.
|
|
30916
30997
|
* `0` DISABLES the lease entirely and falls the worker back to the tiny
|
|
30917
30998
|
* leak-prone GPU surface ring (~85% crop miss; that is what the lease exists
|
|
30918
30999
|
* to replace).
|
|
@@ -30938,22 +31019,45 @@ object({
|
|
|
30938
31019
|
* there is the signal that some caller names frames outside the inference set
|
|
30939
31020
|
* and that this must go back to `all`.
|
|
30940
31021
|
*/
|
|
30941
|
-
admission: NativeLeaseAdmissionSchema
|
|
31022
|
+
admission: NativeLeaseAdmissionSchema,
|
|
31023
|
+
/**
|
|
31024
|
+
* RAM ceiling per decode worker, in MB, for the SUBJECT TILES — the
|
|
31025
|
+
* compressed native crops the worker cuts at the moment a frame's detection
|
|
31026
|
+
* result arrives, and keeps long after the frame itself is freed.
|
|
31027
|
+
*
|
|
31028
|
+
* This is the knob that replaced the old retention window, and it buys about
|
|
31029
|
+
* three orders of magnitude more of it: a tile is one subject at native
|
|
31030
|
+
* resolution, JPEG-encoded (~60-120 KB on a 4K person), against ~24.9 MB for
|
|
31031
|
+
* the frame it was cut from. A frame on which nothing was detected costs
|
|
31032
|
+
* nothing at all, which is the real change — the old lease paid per FRAME and
|
|
31033
|
+
* was interrogated per SUBJECT.
|
|
31034
|
+
*
|
|
31035
|
+
* `0` DISABLES tiles, leaving only the hold window and the ≤640 RAM
|
|
31036
|
+
* fallback — i.e. the pre-2026-08-13 miss profile. Set it there only to
|
|
31037
|
+
* reproduce that.
|
|
31038
|
+
*/
|
|
31039
|
+
tileBudgetMb: number().int().min(0).max(1024)
|
|
30942
31040
|
});
|
|
30943
31041
|
/**
|
|
30944
|
-
* The values in force when the operator has set nothing
|
|
30945
|
-
*
|
|
30946
|
-
*
|
|
31042
|
+
* The values in force when the operator has set nothing.
|
|
31043
|
+
*
|
|
31044
|
+
* `budgetMb` stays at 1024 on the day the hold landed, deliberately: it stopped
|
|
31045
|
+
* being the retention window and became the OOM ceiling, and lowering a ceiling
|
|
31046
|
+
* in the same change that redefines it would make a regression and a retune
|
|
31047
|
+
* indistinguishable. Cut it once `tileHits` / `holdOverflow` have been read on
|
|
31048
|
+
* live traffic.
|
|
30947
31049
|
*/
|
|
30948
31050
|
var DEFAULT_NATIVE_LEASE_SETTINGS = {
|
|
30949
|
-
|
|
31051
|
+
holdFrames: 8,
|
|
30950
31052
|
budgetMb: 1024,
|
|
30951
31053
|
activityMs: 15e3,
|
|
31054
|
+
tileBudgetMb: 64,
|
|
30952
31055
|
admission: "inferred"
|
|
30953
31056
|
};
|
|
30954
|
-
DEFAULT_NATIVE_LEASE_SETTINGS.
|
|
31057
|
+
DEFAULT_NATIVE_LEASE_SETTINGS.holdFrames;
|
|
30955
31058
|
DEFAULT_NATIVE_LEASE_SETTINGS.budgetMb;
|
|
30956
31059
|
DEFAULT_NATIVE_LEASE_SETTINGS.activityMs;
|
|
31060
|
+
DEFAULT_NATIVE_LEASE_SETTINGS.tileBudgetMb;
|
|
30957
31061
|
DEFAULT_NATIVE_LEASE_SETTINGS.admission;
|
|
30958
31062
|
//#endregion
|
|
30959
31063
|
//#region src/convert-orchestrator.ts
|
|
@@ -13119,7 +13119,23 @@ var NotificationActionSchema = object({
|
|
|
13119
13119
|
* else — see `notification-center/action-token.ts` for what that does and
|
|
13120
13120
|
* does not buy.
|
|
13121
13121
|
*/
|
|
13122
|
-
destructive: boolean().optional()
|
|
13122
|
+
destructive: boolean().optional(),
|
|
13123
|
+
/**
|
|
13124
|
+
* How the tap should REACH the url.
|
|
13125
|
+
*
|
|
13126
|
+
* `navigate` (absent, and every button authored before this field) opens it:
|
|
13127
|
+
* the phone leaves the notification and shows whatever the callback returns.
|
|
13128
|
+
* That is right for a button whose answer the operator wants to read.
|
|
13129
|
+
*
|
|
13130
|
+
* `background` fires it as a POST and stays put. It exists for the buttons
|
|
13131
|
+
* whose whole point is not to interrupt — "silence this for 30 minutes" is
|
|
13132
|
+
* an answer to the notification, and being thrown into a browser tab to
|
|
13133
|
+
* confirm it costs more attention than the notification did. A backend that
|
|
13134
|
+
* cannot do a background call renders it as an ordinary link (the adapters
|
|
13135
|
+
* fall back rather than dropping the button), so this is a preference, never
|
|
13136
|
+
* a requirement.
|
|
13137
|
+
*/
|
|
13138
|
+
mode: _enum(["navigate", "background"]).optional()
|
|
13123
13139
|
});
|
|
13124
13140
|
/**
|
|
13125
13141
|
* The canonical notification. `body` is the only hard field (Apprise model).
|
|
@@ -14120,6 +14136,9 @@ var NcSystemEventConditionSchema = object({
|
|
|
14120
14136
|
nodeIds: array(string().min(1)).min(1).optional(),
|
|
14121
14137
|
packageNames: array(string().min(1)).min(1).optional()
|
|
14122
14138
|
});
|
|
14139
|
+
/** Hard ceiling on a window (24h). A snooze that could not expire would be an
|
|
14140
|
+
* outage the operator asked for once and forgot. */
|
|
14141
|
+
var NC_SNOOZE_MAX_MINUTES = 1440;
|
|
14123
14142
|
/** Weekly schedule — OR of windows; absence on the rule = always active. */
|
|
14124
14143
|
var NcScheduleSchema = object({
|
|
14125
14144
|
windows: array(object({
|
|
@@ -14496,15 +14515,15 @@ var NcConditionsSchema = object({
|
|
|
14496
14515
|
* (an `immediate` rule naming an `audio-*` class, one notification per
|
|
14497
14516
|
* classified sample) stays exactly as it was for rules that already use it.
|
|
14498
14517
|
*
|
|
14499
|
-
*
|
|
14500
|
-
* rather than an
|
|
14501
|
-
* (`camstack/src/data/notification-center.ts`, guarded by
|
|
14502
|
-
* `scripts/check-viewer-condition-mirror.ts`) and its rule editor
|
|
14518
|
+
* In {@link NC_CONDITION_CATALOG} since P2, and the ORDER it got there is the
|
|
14519
|
+
* rule rather than an accident: the viewer mirrors the descriptor enums BY
|
|
14520
|
+
* HAND (`camstack/src/data/notification-center.ts`, guarded by
|
|
14521
|
+
* `scripts/check-viewer-condition-mirror.ts`) and its rule editor strips the
|
|
14503
14522
|
* condition fields it does not know when a rule is saved from the phone.
|
|
14504
14523
|
* Publishing an editor for a condition the app cannot round-trip is how an
|
|
14505
|
-
* operator loses a rule's conditions by opening it — so the
|
|
14506
|
-
*
|
|
14507
|
-
*
|
|
14524
|
+
* operator loses a rule's conditions by opening it — so the viewer mirror
|
|
14525
|
+
* (P3, shipped) went FIRST, and the descriptor an editor renders from
|
|
14526
|
+
* follows here.
|
|
14508
14527
|
*/
|
|
14509
14528
|
audio: NcAudioConditionSchema.optional()
|
|
14510
14529
|
});
|
|
@@ -14740,6 +14759,30 @@ var NcRuleInputSchema = object({
|
|
|
14740
14759
|
*/
|
|
14741
14760
|
snoozeAllowGlobal: boolean().optional(),
|
|
14742
14761
|
/**
|
|
14762
|
+
* The snooze durations THIS rule's notification offers as buttons, in
|
|
14763
|
+
* minutes.
|
|
14764
|
+
*
|
|
14765
|
+
* Three states, and all three are distinct — which is exactly why this is
|
|
14766
|
+
* `.optional()` and never `.default()`. A Zod default does not run on the
|
|
14767
|
+
* addon cap path (three production failures in one day), so a schema default
|
|
14768
|
+
* would collapse the first two:
|
|
14769
|
+
*
|
|
14770
|
+
* | value | meaning |
|
|
14771
|
+
* | --- | --- |
|
|
14772
|
+
* | absent | the operator never said ⇒ {@link NC_DEFAULT_SNOOZE_MINUTES} |
|
|
14773
|
+
* | `[]` | **no snooze buttons on this rule** — the explicit override |
|
|
14774
|
+
* | a list | these choices, de-duplicated and sorted, at most four |
|
|
14775
|
+
*
|
|
14776
|
+
* `.max(4)` because the notifier's own action budget is small (ntfy allows
|
|
14777
|
+
* three buttons in total) and a rule that spent it all on snooze choices
|
|
14778
|
+
* would push its own tap-through actions off the notification.
|
|
14779
|
+
*
|
|
14780
|
+
* An empty list is NOT an alarm exemption: a rule the alarm is about, or
|
|
14781
|
+
* that arms the panel, is exempt automatically and cannot be silenced by a
|
|
14782
|
+
* window from anywhere (D133).
|
|
14783
|
+
*/
|
|
14784
|
+
snoozeOptions: array(number().int().min(1).max(NC_SNOOZE_MAX_MINUTES)).max(4).optional(),
|
|
14785
|
+
/**
|
|
14743
14786
|
* Devices this rule ACTUATES — arm the alarm, open a gate, turn on a light.
|
|
14744
14787
|
*
|
|
14745
14788
|
* This is what makes the rule set the alarm's trigger set without the alarm
|
|
@@ -14839,6 +14882,7 @@ var NcConditionDescriptorSchema = object({
|
|
|
14839
14882
|
"device",
|
|
14840
14883
|
"package",
|
|
14841
14884
|
"occupancy",
|
|
14885
|
+
"audio",
|
|
14842
14886
|
"system"
|
|
14843
14887
|
]),
|
|
14844
14888
|
label: string(),
|
|
@@ -14857,6 +14901,7 @@ var NcConditionDescriptorSchema = object({
|
|
|
14857
14901
|
"crossingSelect",
|
|
14858
14902
|
"polygonDraw",
|
|
14859
14903
|
"occupancy",
|
|
14904
|
+
"audio",
|
|
14860
14905
|
"deviceState",
|
|
14861
14906
|
"systemEvent"
|
|
14862
14907
|
]),
|
|
@@ -15008,7 +15053,20 @@ var NcSnoozeInputSchema = object({
|
|
|
15008
15053
|
ruleId: string().optional(),
|
|
15009
15054
|
/** Required when `scope: 'device'`. */
|
|
15010
15055
|
deviceId: number().int().optional(),
|
|
15011
|
-
|
|
15056
|
+
/**
|
|
15057
|
+
* Narrow the window to these subject classes — "the cat, not the person".
|
|
15058
|
+
*
|
|
15059
|
+
* ORTHOGONAL to `scope`, deliberately, and absent means EVERY class: that is
|
|
15060
|
+
* what every window authored before this field meant, so no persisted row
|
|
15061
|
+
* changes meaning and no client has to learn anything to keep working.
|
|
15062
|
+
*
|
|
15063
|
+
* It is what makes the window's real key `(deviceId, classes[])` and lets it
|
|
15064
|
+
* cross rules (D133): the operator points at a camera and a kind of thing,
|
|
15065
|
+
* not at whichever of their four rules happened to produce the notification
|
|
15066
|
+
* they are dismissing.
|
|
15067
|
+
*/
|
|
15068
|
+
classes: array(string().min(1)).min(1).optional(),
|
|
15069
|
+
durationMinutes: number().int().min(1).max(NC_SNOOZE_MAX_MINUTES),
|
|
15012
15070
|
/**
|
|
15013
15071
|
* Silence this for EVERY recipient, not just the caller. Permission is
|
|
15014
15072
|
* checked server-side (the rule's `snoozeAllowGlobal`, or admin for the
|
|
@@ -15033,6 +15091,10 @@ var NcSnoozeSchema = object({
|
|
|
15033
15091
|
scope: NcSnoozeScopeSchema,
|
|
15034
15092
|
ruleId: string().optional(),
|
|
15035
15093
|
deviceId: number().int().optional(),
|
|
15094
|
+
/** Subject classes this window covers. ABSENT = every class — see
|
|
15095
|
+
* {@link NcSnoozeInputSchema.shape.classes}. Lives in the JSON blob and has
|
|
15096
|
+
* no SQLite column: nothing queries a window by class. */
|
|
15097
|
+
classes: array(string().min(1)).min(1).optional(),
|
|
15036
15098
|
startedAt: number(),
|
|
15037
15099
|
/** Exclusive: at exactly this instant the snooze is over. Expiry is a
|
|
15038
15100
|
* COMPARISON, not a job — no sweeper can leave the operator silenced. */
|
|
@@ -23735,13 +23797,24 @@ method(object({
|
|
|
23735
23797
|
/** Playback-speed multiplier for the render (1 = realtime). */
|
|
23736
23798
|
var ExportSpeedSchema = number().min(.25).max(32);
|
|
23737
23799
|
/**
|
|
23738
|
-
* One dense interval, in SECONDS FROM THE EXPORT'S OWN `fromMs`.
|
|
23800
|
+
* One dense interval, in WALL-CLOCK SECONDS FROM THE EXPORT'S OWN `fromMs`.
|
|
23801
|
+
*
|
|
23802
|
+
* **Wall clock, not ffmpeg's `t`** — and the recorder translates. A caller
|
|
23803
|
+
* derives these bounds from things that happened at a TIME (a track's
|
|
23804
|
+
* `firstSeen`), while `t` runs over the source playlist: the concatenation of
|
|
23805
|
+
* every segment present for the range, with each recording GAP removed. The
|
|
23806
|
+
* two agree only on a window that recorded without one interruption, and only
|
|
23807
|
+
* the render side knows the segments, so the translation lives there
|
|
23808
|
+
* (`export-dense-map.ts`, addon-pipeline).
|
|
23809
|
+
*
|
|
23810
|
+
* It was not always so. These seconds were fed to `between(t,…)` verbatim, and
|
|
23811
|
+
* on a 10 h window holding 29,393 s of footage every range landed late by the
|
|
23812
|
+
* gap accumulated before it — up to 6,607 s, well past EOF. Nothing matched,
|
|
23813
|
+
* the video was a uniform timelapse, and the log line reported the five ranges
|
|
23814
|
+
* that had been ASKED for (2026-08-13, export `57d14363`, camera 615).
|
|
23739
23815
|
*
|
|
23740
|
-
* Relative and not absolute epoch
|
|
23741
|
-
*
|
|
23742
|
-
* playlist. Handing it absolute epochs would make every call site responsible
|
|
23743
|
-
* for the same subtraction, and the one that forgot would emit a filter that
|
|
23744
|
-
* selects nothing — silently, as a uniform timelapse.
|
|
23816
|
+
* Relative and not absolute epoch, because an absolute epoch would make every
|
|
23817
|
+
* call site responsible for the same subtraction.
|
|
23745
23818
|
*/
|
|
23746
23819
|
var ExportDenseRangeSchema = object({
|
|
23747
23820
|
fromSec: number().nonnegative(),
|
|
@@ -30594,6 +30667,7 @@ Object.freeze({
|
|
|
30594
30667
|
"network-access": "ingress",
|
|
30595
30668
|
"smtp-provider": "email"
|
|
30596
30669
|
});
|
|
30670
|
+
new Map(AUDIO_MACRO_LABELS.flatMap((macro) => macro.icon === void 0 ? [] : [[macro.id, macro.icon]]));
|
|
30597
30671
|
new Set(["devices", "classes"]);
|
|
30598
30672
|
/**
|
|
30599
30673
|
* TimelapseRule — the STANDALONE scheduled timelapse producer's rule model.
|
|
@@ -30871,25 +30945,32 @@ object({
|
|
|
30871
30945
|
var NativeLeaseAdmissionSchema = _enum(["all", "inferred"]);
|
|
30872
30946
|
object({
|
|
30873
30947
|
/**
|
|
30874
|
-
* How
|
|
30948
|
+
* How many delivered frames the worker HOLDS at once, waiting for each one's
|
|
30949
|
+
* detection result.
|
|
30875
30950
|
*
|
|
30876
|
-
*
|
|
30877
|
-
*
|
|
30878
|
-
*
|
|
30879
|
-
*
|
|
30880
|
-
*
|
|
30951
|
+
* This replaced a TTL on 2026-08-13, and the replacement is the whole point:
|
|
30952
|
+
* a time window was never related to the event the pixels were waiting for.
|
|
30953
|
+
* A held frame now lives from delivery until the runner has its `FrameResult`
|
|
30954
|
+
* — at which moment the runner cuts the subject tiles it actually wanted and
|
|
30955
|
+
* releases the frame. The bound exists only so a runner that stops answering
|
|
30956
|
+
* cannot pin RAM: above it the OLDEST held frame is dropped and counted.
|
|
30957
|
+
*
|
|
30958
|
+
* Sizing: the steady state is `inferenceLatency × deliveredFps`, measured at
|
|
30959
|
+
* 40-160 ms × ≤25 fps = 1-4 frames. The default leaves headroom for a hiccup
|
|
30960
|
+
* without ever approaching the old resident set (43 frames × 24.9 MB at 4K).
|
|
30961
|
+
* Raising it does not buy hit rate — it buys tolerance for a slow runner, and
|
|
30962
|
+
* `holdOverflow` on the metrics line is what says you need it.
|
|
30881
30963
|
*/
|
|
30882
|
-
|
|
30964
|
+
holdFrames: number().int().min(1).max(64),
|
|
30883
30965
|
/**
|
|
30884
30966
|
* Hard per-decode-worker RAM ceiling for retained native frames, in MB.
|
|
30885
30967
|
*
|
|
30886
|
-
*
|
|
30887
|
-
*
|
|
30888
|
-
*
|
|
30889
|
-
*
|
|
30890
|
-
*
|
|
30891
|
-
*
|
|
30892
|
-
* rather than giving RAM back — lower this knob if RAM is what you wanted.
|
|
30968
|
+
* Since 2026-08-13 this is a SAFETY ceiling and nothing else: `holdFrames`
|
|
30969
|
+
* is what decides how much is held, and the ceiling is the number above which
|
|
30970
|
+
* something is wrong. Before that it was the effective cap — at 1024 MB with
|
|
30971
|
+
* a 2 800 ms TTL a 4K camera sat pinned at `leaseMb:1020, leaseFrames:43`
|
|
30972
|
+
* with the TTL expiring nothing, which is exactly the confusion the hold
|
|
30973
|
+
* removes. `leaseMb` / `leaseFrames` still say what is resident.
|
|
30893
30974
|
* `0` DISABLES the lease entirely and falls the worker back to the tiny
|
|
30894
30975
|
* leak-prone GPU surface ring (~85% crop miss; that is what the lease exists
|
|
30895
30976
|
* to replace).
|
|
@@ -30915,22 +30996,45 @@ object({
|
|
|
30915
30996
|
* there is the signal that some caller names frames outside the inference set
|
|
30916
30997
|
* and that this must go back to `all`.
|
|
30917
30998
|
*/
|
|
30918
|
-
admission: NativeLeaseAdmissionSchema
|
|
30999
|
+
admission: NativeLeaseAdmissionSchema,
|
|
31000
|
+
/**
|
|
31001
|
+
* RAM ceiling per decode worker, in MB, for the SUBJECT TILES — the
|
|
31002
|
+
* compressed native crops the worker cuts at the moment a frame's detection
|
|
31003
|
+
* result arrives, and keeps long after the frame itself is freed.
|
|
31004
|
+
*
|
|
31005
|
+
* This is the knob that replaced the old retention window, and it buys about
|
|
31006
|
+
* three orders of magnitude more of it: a tile is one subject at native
|
|
31007
|
+
* resolution, JPEG-encoded (~60-120 KB on a 4K person), against ~24.9 MB for
|
|
31008
|
+
* the frame it was cut from. A frame on which nothing was detected costs
|
|
31009
|
+
* nothing at all, which is the real change — the old lease paid per FRAME and
|
|
31010
|
+
* was interrogated per SUBJECT.
|
|
31011
|
+
*
|
|
31012
|
+
* `0` DISABLES tiles, leaving only the hold window and the ≤640 RAM
|
|
31013
|
+
* fallback — i.e. the pre-2026-08-13 miss profile. Set it there only to
|
|
31014
|
+
* reproduce that.
|
|
31015
|
+
*/
|
|
31016
|
+
tileBudgetMb: number().int().min(0).max(1024)
|
|
30919
31017
|
});
|
|
30920
31018
|
/**
|
|
30921
|
-
* The values in force when the operator has set nothing
|
|
30922
|
-
*
|
|
30923
|
-
*
|
|
31019
|
+
* The values in force when the operator has set nothing.
|
|
31020
|
+
*
|
|
31021
|
+
* `budgetMb` stays at 1024 on the day the hold landed, deliberately: it stopped
|
|
31022
|
+
* being the retention window and became the OOM ceiling, and lowering a ceiling
|
|
31023
|
+
* in the same change that redefines it would make a regression and a retune
|
|
31024
|
+
* indistinguishable. Cut it once `tileHits` / `holdOverflow` have been read on
|
|
31025
|
+
* live traffic.
|
|
30924
31026
|
*/
|
|
30925
31027
|
var DEFAULT_NATIVE_LEASE_SETTINGS = {
|
|
30926
|
-
|
|
31028
|
+
holdFrames: 8,
|
|
30927
31029
|
budgetMb: 1024,
|
|
30928
31030
|
activityMs: 15e3,
|
|
31031
|
+
tileBudgetMb: 64,
|
|
30929
31032
|
admission: "inferred"
|
|
30930
31033
|
};
|
|
30931
|
-
DEFAULT_NATIVE_LEASE_SETTINGS.
|
|
31034
|
+
DEFAULT_NATIVE_LEASE_SETTINGS.holdFrames;
|
|
30932
31035
|
DEFAULT_NATIVE_LEASE_SETTINGS.budgetMb;
|
|
30933
31036
|
DEFAULT_NATIVE_LEASE_SETTINGS.activityMs;
|
|
31037
|
+
DEFAULT_NATIVE_LEASE_SETTINGS.tileBudgetMb;
|
|
30934
31038
|
DEFAULT_NATIVE_LEASE_SETTINGS.admission;
|
|
30935
31039
|
//#endregion
|
|
30936
31040
|
//#region src/convert-orchestrator.ts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { c as e, g as t, h as n, l as r, n as i, p as a, r as o, t as s, u as c, y as l } from "./_virtual_mf___mfe_internal__addon_model_studio_page__loadShare__react__loadShare__.js-DJDHChgO.mjs";
|
|
2
2
|
import { n as u, r as d, t as f } from "./_virtual_mf___mfe_internal__addon_model_studio_page__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-ds_Ehzaa.mjs";
|
|
3
|
-
import { m as p } from "./_virtual_mf___mfe_internal__addon_model_studio_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-
|
|
3
|
+
import { m as p } from "./_virtual_mf___mfe_internal__addon_model_studio_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CiO5eZYn.mjs";
|
|
4
4
|
//#region ../ui-library/src/lib/cap-error.ts
|
|
5
5
|
function m(e) {
|
|
6
6
|
if (typeof e != "object" || !e) return null;
|
package/dist/remoteEntry.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as e, t } from "./virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_model_studio_page__remoteEntry_js-
|
|
1
|
+
import { n as e, t } from "./virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_model_studio_page__remoteEntry_js-C0lWeSYH.mjs";
|
|
2
2
|
export { t as get, e as init };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { s as e } from "./player-overlays-
|
|
1
|
+
import { s as e } from "./player-overlays-Djb228qI.mjs";
|
|
2
2
|
var t = e("eye-off", [
|
|
3
3
|
["path", {
|
|
4
4
|
d: "M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49",
|
|
@@ -16,14 +16,31 @@ var t = e("eye-off", [
|
|
|
16
16
|
d: "m2 2 20 20",
|
|
17
17
|
key: "1ooewy"
|
|
18
18
|
}]
|
|
19
|
-
]), n = e("
|
|
19
|
+
]), n = e("mic", [
|
|
20
|
+
["path", {
|
|
21
|
+
d: "M12 19v3",
|
|
22
|
+
key: "npa21l"
|
|
23
|
+
}],
|
|
24
|
+
["path", {
|
|
25
|
+
d: "M19 10v2a7 7 0 0 1-14 0v-2",
|
|
26
|
+
key: "1vc78b"
|
|
27
|
+
}],
|
|
28
|
+
["rect", {
|
|
29
|
+
x: "9",
|
|
30
|
+
y: "2",
|
|
31
|
+
width: "6",
|
|
32
|
+
height: "13",
|
|
33
|
+
rx: "3",
|
|
34
|
+
key: "s6n7sd"
|
|
35
|
+
}]
|
|
36
|
+
]), r = e("square", [["rect", {
|
|
20
37
|
width: "18",
|
|
21
38
|
height: "18",
|
|
22
39
|
x: "3",
|
|
23
40
|
y: "3",
|
|
24
41
|
rx: "2",
|
|
25
42
|
key: "afitv7"
|
|
26
|
-
}]]),
|
|
43
|
+
}]]), i = e("trash-2", [
|
|
27
44
|
["path", {
|
|
28
45
|
d: "M10 11v6",
|
|
29
46
|
key: "nco0om"
|
|
@@ -46,4 +63,4 @@ var t = e("eye-off", [
|
|
|
46
63
|
}]
|
|
47
64
|
]);
|
|
48
65
|
//#endregion
|
|
49
|
-
export { n,
|
|
66
|
+
export { t as i, r as n, n as r, i as t };
|
|
@@ -2753,7 +2753,7 @@ async function rr(e) {
|
|
|
2753
2753
|
}
|
|
2754
2754
|
}
|
|
2755
2755
|
async function ir() {
|
|
2756
|
-
return tr ||= rr(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_model_studio_page-
|
|
2756
|
+
return tr ||= rr(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_model_studio_page-DLrVxdSd.mjs")).catch((e) => {
|
|
2757
2757
|
throw tr = void 0, e;
|
|
2758
2758
|
}), tr;
|
|
2759
2759
|
}
|