@camstack/addon-post-analysis 1.2.63 → 1.2.65
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/{dist-CdqESw05.mjs → dist-4dhFDogy.mjs} +509 -46
- package/dist/{dist-D4fGaA71.js → dist-DTClXZLm.js} +532 -45
- 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-DrgptocJ.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-Ck9Z2cZR.mjs} +3 -3
- package/dist/pipeline-analytics/{_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DJwl-swi.mjs → _virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DO3ZGk1V.mjs} +1 -1
- package/dist/pipeline-analytics/{hostInit-C8v4WVLy.mjs → hostInit-DvCGVFX8.mjs} +3 -3
- package/dist/pipeline-analytics/index.js +1383 -65
- package/dist/pipeline-analytics/index.mjs +1383 -65
- package/dist/pipeline-analytics/remoteEntry.js +1 -1
- package/package.json +2 -2
|
@@ -7390,8 +7390,31 @@ var AdoptionJobSchema = object({
|
|
|
7390
7390
|
error: string().nullable()
|
|
7391
7391
|
});
|
|
7392
7392
|
/**
|
|
7393
|
-
* Per-camera FUNCTION SWITCHES
|
|
7394
|
-
*
|
|
7393
|
+
* Per-camera FUNCTION SWITCHES.
|
|
7394
|
+
*
|
|
7395
|
+
* ## The aggregate group is being withdrawn — the BADGE is not (D113)
|
|
7396
|
+
*
|
|
7397
|
+
* This file shipped as "the one coherent on/off surface over the pipeline
|
|
7398
|
+
* functions an operator thinks in terms of". The operator's verdict on
|
|
7399
|
+
* 2026-08-12 was that the coherent surface bought complexity and no clarity:
|
|
7400
|
+
* every function already had a settings page of its own, and a second place to
|
|
7401
|
+
* turn it off is a second place to look. Each switch is going back to its own
|
|
7402
|
+
* component's original options — detection to the detection-pipeline wrapper
|
|
7403
|
+
* binding, audio analysis to its own, recording to `RecordingConfig.enabled`
|
|
7404
|
+
* (which was always first-class; the switch was a veneer over
|
|
7405
|
+
* `recording.setDeviceConfig`), notifications to a notification-center
|
|
7406
|
+
* per-device setting, the two camera planes to their own components.
|
|
7407
|
+
*
|
|
7408
|
+
* What survives is {@link composeSwitchedOff}: `CameraStatus.switchedOff`, the
|
|
7409
|
+
* thing that lets a status surface say DISABLED instead of BROKEN, recomposed
|
|
7410
|
+
* straight from the authorities with no group in the middle. That rule was
|
|
7411
|
+
* never about a control panel.
|
|
7412
|
+
*
|
|
7413
|
+
* Everything else here — {@link CAMERA_SWITCH_CATALOG}, {@link CameraSwitch},
|
|
7414
|
+
* {@link deriveCameraSwitches}, the `pipelineOrchestrator.getCameraSwitches` /
|
|
7415
|
+
* `setCameraSwitch` pair — is a COMPATIBILITY surface for as long as deployed
|
|
7416
|
+
* viewers (v1.0.305) and the admin UI still call it. It is deleted when they
|
|
7417
|
+
* stop; nothing new may be built on it.
|
|
7395
7418
|
*
|
|
7396
7419
|
* ## This file adds no state
|
|
7397
7420
|
*
|
|
@@ -7753,14 +7776,29 @@ var RecordingConfigSchema = object({
|
|
|
7753
7776
|
scrubThumbnails: ScrubThumbnailPresetSchema.optional()
|
|
7754
7777
|
}).strict();
|
|
7755
7778
|
/**
|
|
7779
|
+
* Derive the {@link RecordingStorageModeSchema} summary from the authoritative
|
|
7780
|
+
* bands: `continuous` when any band records continuously, `events` when a band
|
|
7781
|
+
* exists at all, else `off`. Pure.
|
|
7782
|
+
*
|
|
7783
|
+
* THE one definition: the recorder stamps `config.mode` with it on save and
|
|
7784
|
+
* reports it as the cap's `activeMode`, and the settings UI reads it back to
|
|
7785
|
+
* decide which authoring tab a config opens in. Two copies would drift, and the
|
|
7786
|
+
* symptom (a status dot disagreeing with what is being recorded) is exactly the
|
|
7787
|
+
* bug this field was added to fix.
|
|
7788
|
+
*/
|
|
7789
|
+
function deriveRecordingMode(config) {
|
|
7790
|
+
if (!config.enabled || config.bands.length === 0) return "off";
|
|
7791
|
+
if (config.bands.some((band) => band.mode === "continuous")) return "continuous";
|
|
7792
|
+
return "events";
|
|
7793
|
+
}
|
|
7794
|
+
/**
|
|
7756
7795
|
* Entity-relocation job state (storage entity-routing spec, Phase 4).
|
|
7757
7796
|
*
|
|
7758
|
-
* One shape shared by the recorder
|
|
7759
|
-
*
|
|
7760
|
-
*
|
|
7761
|
-
*
|
|
7762
|
-
*
|
|
7763
|
-
* row on the owning addon's surface.
|
|
7797
|
+
* One shape shared by the recorder and pipeline-analytics internal movers.
|
|
7798
|
+
* The public admin surface is `storage-migration`; child jobs remain in RAM
|
|
7799
|
+
* because copy-if-absent, verify, delete and index/row repoint are resumable.
|
|
7800
|
+
* Each completed/failed run also lands one durable ops-log row on its owning
|
|
7801
|
+
* addon surface.
|
|
7764
7802
|
*/
|
|
7765
7803
|
var RelocateJobStateSchema = _enum([
|
|
7766
7804
|
"running",
|
|
@@ -7787,19 +7825,100 @@ var RelocateJobSchema = object({
|
|
|
7787
7825
|
finishedAt: number().nullable(),
|
|
7788
7826
|
error: string().nullable()
|
|
7789
7827
|
});
|
|
7828
|
+
/** Profile-derived footage selection used only by the migration coordinator:
|
|
7829
|
+
* `recordings` owns high+mid; `recordingsLow` owns low. */
|
|
7830
|
+
var RelocateFootageClassSchema = _enum(["recordings", "recordingsLow"]);
|
|
7790
7831
|
var RelocateFootageInputSchema = object({
|
|
7791
|
-
deviceId: number().optional(),
|
|
7792
7832
|
fromLocationId: string(),
|
|
7793
7833
|
toLocationId: string(),
|
|
7794
7834
|
entities: array(_enum(["segments"])).optional(),
|
|
7835
|
+
/** Limits relocation to the logical profile class. Omit only for the
|
|
7836
|
+
* pre-orchestration compatibility path. */
|
|
7837
|
+
footageClass: RelocateFootageClassSchema.optional(),
|
|
7795
7838
|
/** Copy throttle in MB/s (default 40) — the drain is a background chore,
|
|
7796
7839
|
* never allowed to starve live writers. */
|
|
7797
7840
|
throttleMbps: number().min(1).max(1e3).optional()
|
|
7798
7841
|
});
|
|
7799
|
-
|
|
7800
|
-
|
|
7842
|
+
/** Internal, lease-scoped participant operation. It is intentionally separate
|
|
7843
|
+
* from persistent recording settings: a migration never changes
|
|
7844
|
+
* `RecordingConfig.enabled` or camera wrapper bindings. */
|
|
7845
|
+
var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
|
|
7846
|
+
var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
|
|
7847
|
+
var StorageMigrationMediaMoveInputSchema = object({
|
|
7801
7848
|
toLocationId: string(),
|
|
7802
7849
|
throttleMbps: number().min(1).max(1e3).optional()
|
|
7850
|
+
}).extend({ leaseId: string().min(1) });
|
|
7851
|
+
/** The independently selectable logical storage classes. `recordings`
|
|
7852
|
+
* encompasses the high and mid segment profiles; `recordingsLow` is low
|
|
7853
|
+
* segments; `eventMedia` is post-analysis blobs. */
|
|
7854
|
+
var StorageMigrationClassSchema = _enum([
|
|
7855
|
+
"recordings",
|
|
7856
|
+
"recordingsLow",
|
|
7857
|
+
"eventMedia"
|
|
7858
|
+
]);
|
|
7859
|
+
/** A destination is always an existing, fully-qualified location id. The
|
|
7860
|
+
* migration API intentionally never changes a source location's `basePath`:
|
|
7861
|
+
* callers create a new `<type>:<slug>` location, then select it here. */
|
|
7862
|
+
var StorageMigrationDestinationsSchema = object({
|
|
7863
|
+
recordings: string().min(1).optional(),
|
|
7864
|
+
recordingsLow: string().min(1).optional(),
|
|
7865
|
+
eventMedia: string().min(1).optional()
|
|
7866
|
+
}).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
|
|
7867
|
+
/** Shared input for planning and starting an orchestrated storage migration. */
|
|
7868
|
+
var StorageMigrationInputSchema = object({
|
|
7869
|
+
destinations: StorageMigrationDestinationsSchema,
|
|
7870
|
+
throttleMbps: number().min(1).max(1e3).optional()
|
|
7871
|
+
});
|
|
7872
|
+
/** The durable coordinator state machine. The only phase that changes default
|
|
7873
|
+
* locations is `repointing`, after every selected mover has completed and been
|
|
7874
|
+
* verified. */
|
|
7875
|
+
var StorageMigrationPhaseSchema = _enum([
|
|
7876
|
+
"planning",
|
|
7877
|
+
"pausing",
|
|
7878
|
+
"moving",
|
|
7879
|
+
"verifying",
|
|
7880
|
+
"repointing",
|
|
7881
|
+
"refreshing",
|
|
7882
|
+
"resuming",
|
|
7883
|
+
"done",
|
|
7884
|
+
"failed",
|
|
7885
|
+
"cancelled"
|
|
7886
|
+
]);
|
|
7887
|
+
var StorageMigrationParticipantSchema = _enum([
|
|
7888
|
+
"pipeline",
|
|
7889
|
+
"recorder",
|
|
7890
|
+
"analytics"
|
|
7891
|
+
]);
|
|
7892
|
+
var StorageMigrationMoveSchema = object({
|
|
7893
|
+
storageClass: StorageMigrationClassSchema,
|
|
7894
|
+
fromLocationId: string(),
|
|
7895
|
+
toLocationId: string(),
|
|
7896
|
+
moverJobId: string().nullable(),
|
|
7897
|
+
state: RelocateJobStateSchema.nullable(),
|
|
7898
|
+
error: string().nullable()
|
|
7899
|
+
});
|
|
7900
|
+
var StorageMigrationJobSchema = object({
|
|
7901
|
+
jobId: string(),
|
|
7902
|
+
phase: StorageMigrationPhaseSchema,
|
|
7903
|
+
destinations: StorageMigrationDestinationsSchema,
|
|
7904
|
+
throttleMbps: number(),
|
|
7905
|
+
moves: array(StorageMigrationMoveSchema),
|
|
7906
|
+
pauseLeaseId: string().nullable(),
|
|
7907
|
+
pausedParticipants: array(StorageMigrationParticipantSchema),
|
|
7908
|
+
repointed: boolean(),
|
|
7909
|
+
cancelRequested: boolean(),
|
|
7910
|
+
startedAt: number(),
|
|
7911
|
+
updatedAt: number(),
|
|
7912
|
+
finishedAt: number().nullable(),
|
|
7913
|
+
error: string().nullable()
|
|
7914
|
+
});
|
|
7915
|
+
var StorageMigrationPlanSchema = object({
|
|
7916
|
+
destinations: StorageMigrationDestinationsSchema,
|
|
7917
|
+
moves: array(object({
|
|
7918
|
+
storageClass: StorageMigrationClassSchema,
|
|
7919
|
+
fromLocationId: string(),
|
|
7920
|
+
toLocationId: string()
|
|
7921
|
+
}))
|
|
7803
7922
|
});
|
|
7804
7923
|
/**
|
|
7805
7924
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
@@ -17118,20 +17237,28 @@ var pipelineAnalyticsCapability = {
|
|
|
17118
17237
|
}),
|
|
17119
17238
|
/** The events ops-log rows (newest-first), optionally scoped to one camera.
|
|
17120
17239
|
* Backed by a declared pipeline-analytics SQLite collection. */
|
|
17121
|
-
/**
|
|
17122
|
-
*
|
|
17123
|
-
|
|
17124
|
-
* at the target are skipped, so a re-run resumes. Single-flight.
|
|
17125
|
-
*/
|
|
17126
|
-
relocateMedia: method(RelocateMediaInputSchema, object({ jobId: string() }), {
|
|
17240
|
+
/** Internal migration-participant lease. It drains active MediaStore
|
|
17241
|
+
* writes and refuses new ones without changing analytics bindings. */
|
|
17242
|
+
pauseForStorageMigration: method(StorageMigrationLeaseInputSchema, object({ paused: literal(true) }), {
|
|
17127
17243
|
kind: "mutation",
|
|
17128
17244
|
auth: "admin"
|
|
17129
17245
|
}),
|
|
17130
|
-
|
|
17131
|
-
kind: "
|
|
17246
|
+
resumeForStorageMigration: method(StorageMigrationLeaseInputSchema, object({ resumed: literal(true) }), {
|
|
17247
|
+
kind: "mutation",
|
|
17248
|
+
auth: "admin"
|
|
17249
|
+
}),
|
|
17250
|
+
/** Drops cached location roots after the storage coordinator repoints a
|
|
17251
|
+
* default so future event-media writes use the new root. */
|
|
17252
|
+
refreshStorageLocationsForMigration: method(StorageMigrationLeaseInputSchema, object({ refreshed: literal(true) }), {
|
|
17253
|
+
kind: "mutation",
|
|
17254
|
+
auth: "admin"
|
|
17255
|
+
}),
|
|
17256
|
+
startStorageMigrationMove: method(StorageMigrationMediaMoveInputSchema, object({ jobId: string() }), {
|
|
17257
|
+
kind: "mutation",
|
|
17132
17258
|
auth: "admin"
|
|
17133
17259
|
}),
|
|
17134
|
-
|
|
17260
|
+
getStorageMigrationMoveStatus: method(object({ jobId: string() }), RelocateJobSchema.nullable(), { auth: "admin" }),
|
|
17261
|
+
cancelStorageMigrationMove: method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
17135
17262
|
kind: "mutation",
|
|
17136
17263
|
auth: "admin"
|
|
17137
17264
|
}),
|
|
@@ -18794,9 +18921,16 @@ var CameraStatusSchema = object({
|
|
|
18794
18921
|
audio: CameraAudioStatusSchema.nullable(),
|
|
18795
18922
|
recording: CameraRecordingStatusSchema.nullable(),
|
|
18796
18923
|
/**
|
|
18797
|
-
* Per-camera
|
|
18924
|
+
* Per-camera functions an OPERATOR has turned off
|
|
18798
18925
|
* ([D61](../../../../docs/decisions/adr-0067.md)).
|
|
18799
18926
|
*
|
|
18927
|
+
* Composed from the AUTHORITIES themselves — the wrapper bindings,
|
|
18928
|
+
* `RecordingConfig.enabled`, the notification mute, the broker's audio
|
|
18929
|
+
* policy, the camera's own microphone — via `composeSwitchedOff`, not from
|
|
18930
|
+
* the deprecated `getCameraSwitches` group ([D113](../../../../docs/decisions/adr-0113.md)).
|
|
18931
|
+
* The badge outlives the control panel: the panel was a convenience, this is
|
|
18932
|
+
* the difference between a camera being off and a camera being dead.
|
|
18933
|
+
*
|
|
18800
18934
|
* This is the difference between DISABLED and BROKEN. A camera whose
|
|
18801
18935
|
* `detection` block reports zero fps and whose `switchedOff` contains
|
|
18802
18936
|
* `'object-detection'` was switched off by a person; the same camera with an
|
|
@@ -18867,7 +19001,13 @@ var NodeInferenceDevicesSchema = object({
|
|
|
18867
19001
|
reachable: boolean(),
|
|
18868
19002
|
devices: array(NodeInferenceDeviceSchema).readonly()
|
|
18869
19003
|
});
|
|
18870
|
-
method(object({
|
|
19004
|
+
method(StorageMigrationLeaseInputSchema, object({ paused: literal(true) }), {
|
|
19005
|
+
kind: "mutation",
|
|
19006
|
+
auth: "admin"
|
|
19007
|
+
}), method(StorageMigrationLeaseInputSchema, object({ resumed: literal(true) }), {
|
|
19008
|
+
kind: "mutation",
|
|
19009
|
+
auth: "admin"
|
|
19010
|
+
}), method(object({
|
|
18871
19011
|
deviceId: number(),
|
|
18872
19012
|
agentNodeId: string()
|
|
18873
19013
|
}), object({ success: literal(true) }), {
|
|
@@ -19571,6 +19711,13 @@ method(object({ locationId: string() }), EvictableUsageSchema), method(object({
|
|
|
19571
19711
|
locationId: string(),
|
|
19572
19712
|
targetBytes: number().int().positive()
|
|
19573
19713
|
}), EvictResultSchema, { kind: "mutation" });
|
|
19714
|
+
method(StorageMigrationInputSchema, StorageMigrationPlanSchema, { auth: "admin" }), method(StorageMigrationInputSchema, object({ jobId: string() }), {
|
|
19715
|
+
kind: "mutation",
|
|
19716
|
+
auth: "admin"
|
|
19717
|
+
}), method(object({ jobId: string().optional() }), StorageMigrationJobSchema.nullable(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
19718
|
+
kind: "mutation",
|
|
19719
|
+
auth: "admin"
|
|
19720
|
+
});
|
|
19574
19721
|
var ProviderInfoSchema = discriminatedUnion("shouldSaveDiskSpace", [object({
|
|
19575
19722
|
providerId: string().min(1),
|
|
19576
19723
|
displayName: string().min(1),
|
|
@@ -19674,6 +19821,28 @@ var TerminalProfileInfoSchema = object({
|
|
|
19674
19821
|
label: string(),
|
|
19675
19822
|
description: string().optional()
|
|
19676
19823
|
});
|
|
19824
|
+
/**
|
|
19825
|
+
* A durable operator-created Terminal instance. Profiles are templates; only
|
|
19826
|
+
* an instance declares a camera.
|
|
19827
|
+
*/
|
|
19828
|
+
var TerminalInstanceInfoSchema = object({
|
|
19829
|
+
instanceId: string(),
|
|
19830
|
+
cameraStableId: string(),
|
|
19831
|
+
nodeId: string(),
|
|
19832
|
+
profileId: string(),
|
|
19833
|
+
profileLabel: string(),
|
|
19834
|
+
name: string(),
|
|
19835
|
+
enabled: boolean()
|
|
19836
|
+
});
|
|
19837
|
+
var TerminalLegacyCameraSchema = object({
|
|
19838
|
+
stableId: string(),
|
|
19839
|
+
nodeId: string(),
|
|
19840
|
+
profileId: string(),
|
|
19841
|
+
profileLabel: string(),
|
|
19842
|
+
name: string(),
|
|
19843
|
+
/** Only legacy monitor cameras can retain their historic stable identity. */
|
|
19844
|
+
adoptable: boolean()
|
|
19845
|
+
});
|
|
19677
19846
|
var TerminalOutputEventSchema = discriminatedUnion("kind", [object({
|
|
19678
19847
|
seq: number().int().positive(),
|
|
19679
19848
|
kind: literal("data"),
|
|
@@ -19690,7 +19859,29 @@ var TerminalOutputBatchSchema = object({
|
|
|
19690
19859
|
snapshot: string().optional(),
|
|
19691
19860
|
events: array(TerminalOutputEventSchema).readonly()
|
|
19692
19861
|
});
|
|
19693
|
-
method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(
|
|
19862
|
+
method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalInstanceInfoSchema).readonly(), { auth: "admin" }), method(object({
|
|
19863
|
+
targetNodeId: string().min(1),
|
|
19864
|
+
profileId: string().min(1),
|
|
19865
|
+
name: string().trim().min(1).max(160).optional()
|
|
19866
|
+
}), TerminalInstanceInfoSchema, {
|
|
19867
|
+
kind: "mutation",
|
|
19868
|
+
auth: "admin"
|
|
19869
|
+
}), method(object({ instanceId: string().min(1) }), _void(), {
|
|
19870
|
+
kind: "mutation",
|
|
19871
|
+
auth: "admin"
|
|
19872
|
+
}), method(object({
|
|
19873
|
+
instanceId: string().min(1),
|
|
19874
|
+
enabled: boolean()
|
|
19875
|
+
}), TerminalInstanceInfoSchema, {
|
|
19876
|
+
kind: "mutation",
|
|
19877
|
+
auth: "admin"
|
|
19878
|
+
}), method(_void(), array(TerminalLegacyCameraSchema).readonly(), { auth: "admin" }), method(object({
|
|
19879
|
+
stableId: string().min(1),
|
|
19880
|
+
name: string().trim().min(1).max(160).optional()
|
|
19881
|
+
}), TerminalInstanceInfoSchema, {
|
|
19882
|
+
kind: "mutation",
|
|
19883
|
+
auth: "admin"
|
|
19884
|
+
}), method(_void(), array(TerminalSessionInfoSchema).readonly(), { auth: "admin" }), method(object({
|
|
19694
19885
|
profileId: string(),
|
|
19695
19886
|
cols: number().int().positive(),
|
|
19696
19887
|
rows: number().int().positive()
|
|
@@ -19707,7 +19898,13 @@ method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }),
|
|
|
19707
19898
|
}), method(object({
|
|
19708
19899
|
sessionId: string(),
|
|
19709
19900
|
afterSeq: number().int().nonnegative(),
|
|
19710
|
-
waitMs: number().int().min(0).max(2e3).default(0)
|
|
19901
|
+
waitMs: number().int().min(0).max(2e3).default(0),
|
|
19902
|
+
/**
|
|
19903
|
+
* Wait when a just-opened session has no output yet. Kept opt-in so a
|
|
19904
|
+
* browser's initial repaint remains immediate; the camera snapshot
|
|
19905
|
+
* relay uses it to avoid encoding a blank startup frame.
|
|
19906
|
+
*/
|
|
19907
|
+
waitForOutput: boolean().optional()
|
|
19711
19908
|
}), TerminalOutputBatchSchema, {
|
|
19712
19909
|
kind: "mutation",
|
|
19713
19910
|
auth: "admin",
|
|
@@ -25754,13 +25951,19 @@ method(object({
|
|
|
25754
25951
|
}), {
|
|
25755
25952
|
kind: "mutation",
|
|
25756
25953
|
auth: "admin"
|
|
25757
|
-
}), method(
|
|
25954
|
+
}), method(StorageMigrationLeaseInputSchema, object({ paused: literal(true) }), {
|
|
25758
25955
|
kind: "mutation",
|
|
25759
25956
|
auth: "admin"
|
|
25760
|
-
}), method(object({
|
|
25761
|
-
kind: "
|
|
25957
|
+
}), method(StorageMigrationLeaseInputSchema, object({ resumed: literal(true) }), {
|
|
25958
|
+
kind: "mutation",
|
|
25959
|
+
auth: "admin"
|
|
25960
|
+
}), method(StorageMigrationLeaseInputSchema, object({ refreshed: literal(true) }), {
|
|
25961
|
+
kind: "mutation",
|
|
25962
|
+
auth: "admin"
|
|
25963
|
+
}), method(StorageMigrationFootageMoveInputSchema, object({ jobId: string() }), {
|
|
25964
|
+
kind: "mutation",
|
|
25762
25965
|
auth: "admin"
|
|
25763
|
-
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
25966
|
+
}), method(object({ jobId: string() }), RelocateJobSchema.nullable(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
25764
25967
|
kind: "mutation",
|
|
25765
25968
|
auth: "admin"
|
|
25766
25969
|
});
|
|
@@ -25780,10 +25983,42 @@ method(object({
|
|
|
25780
25983
|
*/
|
|
25781
25984
|
/** Playback-speed multiplier for the render (1 = realtime). */
|
|
25782
25985
|
var ExportSpeedSchema = number().min(.25).max(32);
|
|
25986
|
+
/**
|
|
25987
|
+
* One dense interval, in SECONDS FROM THE EXPORT'S OWN `fromMs`.
|
|
25988
|
+
*
|
|
25989
|
+
* Relative and not absolute epoch on purpose: the renderer's frame-select
|
|
25990
|
+
* expression sees ffmpeg's `t`, which starts at 0 for the export's source
|
|
25991
|
+
* playlist. Handing it absolute epochs would make every call site responsible
|
|
25992
|
+
* for the same subtraction, and the one that forgot would emit a filter that
|
|
25993
|
+
* selects nothing — silently, as a uniform timelapse.
|
|
25994
|
+
*/
|
|
25995
|
+
var ExportDenseRangeSchema = object({
|
|
25996
|
+
fromSec: number().nonnegative(),
|
|
25997
|
+
toSec: number().nonnegative()
|
|
25998
|
+
}).refine((r) => r.toSec > r.fromSec, { message: "dense range must have toSec > fromSec" });
|
|
25999
|
+
/**
|
|
26000
|
+
* Dense-interval overlay for a timelapse: sample at `dense.everyMs` INSIDE the
|
|
26001
|
+
* listed ranges and at the base `everyMs` everywhere else.
|
|
26002
|
+
*
|
|
26003
|
+
* `everyMs` must be strictly smaller than the base cadence — a dense rate that
|
|
26004
|
+
* is not denser renders a uniform timelapse the operator believes is two-rate.
|
|
26005
|
+
*/
|
|
26006
|
+
var ExportDenseSchema = object({
|
|
26007
|
+
everyMs: number().int().positive(),
|
|
26008
|
+
ranges: array(ExportDenseRangeSchema).min(1).max(200)
|
|
26009
|
+
});
|
|
25783
26010
|
/** Timelapse cadence — sample one source frame per `everyMs`, output at `outputFps`. */
|
|
25784
26011
|
var ExportTimelapseSchema = object({
|
|
25785
26012
|
everyMs: number().int().positive(),
|
|
25786
|
-
outputFps: number().int().min(1).max(60).optional()
|
|
26013
|
+
outputFps: number().int().min(1).max(60).optional(),
|
|
26014
|
+
/** Optional second, FASTER rate over the intervals that matter. */
|
|
26015
|
+
dense: ExportDenseSchema.optional()
|
|
26016
|
+
}).superRefine((v, ctx) => {
|
|
26017
|
+
if (v.dense !== void 0 && v.dense.everyMs >= v.everyMs) ctx.addIssue({
|
|
26018
|
+
code: ZodIssueCode.custom,
|
|
26019
|
+
message: "dense.everyMs must be strictly smaller than the base everyMs",
|
|
26020
|
+
path: ["dense", "everyMs"]
|
|
26021
|
+
});
|
|
25787
26022
|
});
|
|
25788
26023
|
/**
|
|
25789
26024
|
* Render options. `speed` and `timelapse` are mutually exclusive. `includeAudio`
|
|
@@ -25841,6 +26076,38 @@ var ExportDownloadSchema = object({
|
|
|
25841
26076
|
url: string(),
|
|
25842
26077
|
endpoints: array(string())
|
|
25843
26078
|
});
|
|
26079
|
+
/**
|
|
26080
|
+
* Hard ceiling on ONE {@link recordingExportCapability} byte read — 50 MiB.
|
|
26081
|
+
*
|
|
26082
|
+
* Two independent reasons land on the same number, which is why it is this one
|
|
26083
|
+
* and not a rounder guess:
|
|
26084
|
+
*
|
|
26085
|
+
* - **Nobody would accept more.** The roomiest byte cap any notifier backend
|
|
26086
|
+
* declares is telegram's 50 MiB, and the degrade engine DROPS an over-cap
|
|
26087
|
+
* attachment outright rather than degrading it to a link. Bytes above this
|
|
26088
|
+
* are read, encoded and moved to be thrown away at the last step.
|
|
26089
|
+
* - **The envelope is unary.** A base64 payload is held whole, ~1.33× its
|
|
26090
|
+
* size, in the provider AND in the caller — on a hub this repo has already
|
|
26091
|
+
* OOM'd once (D9/D18). A bounded on-demand read at human speed is the shape
|
|
26092
|
+
* those records permit; an unbounded one is the shape they forbid.
|
|
26093
|
+
*
|
|
26094
|
+
* Above it the provider REFUSES with a log line rather than truncating: half a
|
|
26095
|
+
* video is worse than a notification that says there is no attachment.
|
|
26096
|
+
*/
|
|
26097
|
+
var RECORDING_EXPORT_MAX_READ_BYTES = 50 * 1024 * 1024;
|
|
26098
|
+
/**
|
|
26099
|
+
* A finished export's bytes, inline.
|
|
26100
|
+
*
|
|
26101
|
+
* `bytes` is the DECODED length — the number the caller bounds and logs
|
|
26102
|
+
* against, so nobody has to infer it from the base64 length.
|
|
26103
|
+
*/
|
|
26104
|
+
var ExportBytesSchema = object({
|
|
26105
|
+
base64: string(),
|
|
26106
|
+
contentType: string(),
|
|
26107
|
+
/** Suggested filename, extension included. */
|
|
26108
|
+
name: string(),
|
|
26109
|
+
bytes: number().int().nonnegative()
|
|
26110
|
+
});
|
|
25844
26111
|
method(object({
|
|
25845
26112
|
deviceId: number(),
|
|
25846
26113
|
profile: string(),
|
|
@@ -25865,6 +26132,9 @@ method(object({
|
|
|
25865
26132
|
}), method(object({ exportId: string() }), ExportDownloadSchema, {
|
|
25866
26133
|
kind: "query",
|
|
25867
26134
|
auth: "protected"
|
|
26135
|
+
}), method(object({ exportId: string() }), ExportBytesSchema, {
|
|
26136
|
+
kind: "query",
|
|
26137
|
+
auth: "protected"
|
|
25868
26138
|
});
|
|
25869
26139
|
/**
|
|
25870
26140
|
* scene-monitor — device-scoped reference-region state cap. An operator marks
|
|
@@ -28331,9 +28601,10 @@ var DeclaredDevices = class {
|
|
|
28331
28601
|
}
|
|
28332
28602
|
const integrationId = spec.integrationId ?? await this.ensureIntegration(spec.integrationName);
|
|
28333
28603
|
const index = await this.readIndex();
|
|
28604
|
+
const live = await this.readLiveByStableId();
|
|
28334
28605
|
const outcomes = [];
|
|
28335
28606
|
for (const declaration of spec.devices) {
|
|
28336
|
-
const outcome = await this.applyDeclaration(declaration, integrationId, index);
|
|
28607
|
+
const outcome = await this.applyDeclaration(declaration, integrationId, index, live);
|
|
28337
28608
|
if (outcome !== null) outcomes.push(outcome);
|
|
28338
28609
|
}
|
|
28339
28610
|
return {
|
|
@@ -28379,6 +28650,26 @@ var DeclaredDevices = class {
|
|
|
28379
28650
|
return new Map(rows.map((row) => [row.stableId, row]));
|
|
28380
28651
|
}
|
|
28381
28652
|
/**
|
|
28653
|
+
* Devices this kernel already has CONSTRUCTED, by stableId.
|
|
28654
|
+
*
|
|
28655
|
+
* Distinct from {@link readIndex}, and the distinction is the bug: the index
|
|
28656
|
+
* is persisted rows, this is live objects. A row without an object must be
|
|
28657
|
+
* adopted; an object must be left exactly as it is.
|
|
28658
|
+
*
|
|
28659
|
+
* Failure is non-fatal and deliberately so — an empty map degrades to the
|
|
28660
|
+
* previous behaviour (attempt the adopt) rather than skipping a device that
|
|
28661
|
+
* genuinely needs bringing up.
|
|
28662
|
+
*/
|
|
28663
|
+
async readLiveByStableId() {
|
|
28664
|
+
try {
|
|
28665
|
+
const devices = await this.ports.devices.getAll();
|
|
28666
|
+
return new Map(devices.map((device) => [device.stableId, device]));
|
|
28667
|
+
} catch (err) {
|
|
28668
|
+
this.ports.logger.warn("could not read live devices — falling back to adopt-by-row", { meta: { error: err instanceof Error ? err.message : String(err) } });
|
|
28669
|
+
return /* @__PURE__ */ new Map();
|
|
28670
|
+
}
|
|
28671
|
+
}
|
|
28672
|
+
/**
|
|
28382
28673
|
* One declaration: adopt what exists, create what does not.
|
|
28383
28674
|
*
|
|
28384
28675
|
* The create branch is the destructive one — it seeds `initialMeta`, and
|
|
@@ -28387,8 +28678,15 @@ var DeclaredDevices = class {
|
|
|
28387
28678
|
* the declared name over the operator's rename. D49: that branch needs a
|
|
28388
28679
|
* second read to agree.
|
|
28389
28680
|
*/
|
|
28390
|
-
async applyDeclaration(declaration, integrationId, index) {
|
|
28681
|
+
async applyDeclaration(declaration, integrationId, index, live) {
|
|
28391
28682
|
try {
|
|
28683
|
+
const alreadyLive = live.get(declaration.stableId);
|
|
28684
|
+
if (alreadyLive !== void 0) return {
|
|
28685
|
+
stableId: declaration.stableId,
|
|
28686
|
+
deviceId: alreadyLive.id,
|
|
28687
|
+
device: alreadyLive,
|
|
28688
|
+
created: false
|
|
28689
|
+
};
|
|
28392
28690
|
let existing = index.get(declaration.stableId);
|
|
28393
28691
|
if (existing === void 0) {
|
|
28394
28692
|
existing = (await this.readIndex()).get(declaration.stableId);
|
|
@@ -31493,7 +31791,7 @@ Object.freeze({
|
|
|
31493
31791
|
addonId: null,
|
|
31494
31792
|
access: "create"
|
|
31495
31793
|
},
|
|
31496
|
-
"pipelineAnalytics.
|
|
31794
|
+
"pipelineAnalytics.cancelStorageMigrationMove": {
|
|
31497
31795
|
capName: "pipeline-analytics",
|
|
31498
31796
|
capScope: "device",
|
|
31499
31797
|
addonId: null,
|
|
@@ -31565,12 +31863,6 @@ Object.freeze({
|
|
|
31565
31863
|
addonId: null,
|
|
31566
31864
|
access: "view"
|
|
31567
31865
|
},
|
|
31568
|
-
"pipelineAnalytics.getMediaRelocateStatus": {
|
|
31569
|
-
capName: "pipeline-analytics",
|
|
31570
|
-
capScope: "device",
|
|
31571
|
-
addonId: null,
|
|
31572
|
-
access: "view"
|
|
31573
|
-
},
|
|
31574
31866
|
"pipelineAnalytics.getMotionEvents": {
|
|
31575
31867
|
capName: "pipeline-analytics",
|
|
31576
31868
|
capScope: "device",
|
|
@@ -31607,6 +31899,12 @@ Object.freeze({
|
|
|
31607
31899
|
addonId: null,
|
|
31608
31900
|
access: "view"
|
|
31609
31901
|
},
|
|
31902
|
+
"pipelineAnalytics.getStorageMigrationMoveStatus": {
|
|
31903
|
+
capName: "pipeline-analytics",
|
|
31904
|
+
capScope: "device",
|
|
31905
|
+
addonId: null,
|
|
31906
|
+
access: "view"
|
|
31907
|
+
},
|
|
31610
31908
|
"pipelineAnalytics.getTrack": {
|
|
31611
31909
|
capName: "pipeline-analytics",
|
|
31612
31910
|
capScope: "device",
|
|
@@ -31685,6 +31983,12 @@ Object.freeze({
|
|
|
31685
31983
|
addonId: null,
|
|
31686
31984
|
access: "view"
|
|
31687
31985
|
},
|
|
31986
|
+
"pipelineAnalytics.pauseForStorageMigration": {
|
|
31987
|
+
capName: "pipeline-analytics",
|
|
31988
|
+
capScope: "device",
|
|
31989
|
+
addonId: null,
|
|
31990
|
+
access: "create"
|
|
31991
|
+
},
|
|
31688
31992
|
"pipelineAnalytics.proposeRetrainAnnotations": {
|
|
31689
31993
|
capName: "pipeline-analytics",
|
|
31690
31994
|
capScope: "device",
|
|
@@ -31715,7 +32019,7 @@ Object.freeze({
|
|
|
31715
32019
|
addonId: null,
|
|
31716
32020
|
access: "create"
|
|
31717
32021
|
},
|
|
31718
|
-
"pipelineAnalytics.
|
|
32022
|
+
"pipelineAnalytics.refreshStorageLocationsForMigration": {
|
|
31719
32023
|
capName: "pipeline-analytics",
|
|
31720
32024
|
capScope: "device",
|
|
31721
32025
|
addonId: null,
|
|
@@ -31727,6 +32031,12 @@ Object.freeze({
|
|
|
31727
32031
|
addonId: null,
|
|
31728
32032
|
access: "create"
|
|
31729
32033
|
},
|
|
32034
|
+
"pipelineAnalytics.resumeForStorageMigration": {
|
|
32035
|
+
capName: "pipeline-analytics",
|
|
32036
|
+
capScope: "device",
|
|
32037
|
+
addonId: null,
|
|
32038
|
+
access: "create"
|
|
32039
|
+
},
|
|
31730
32040
|
"pipelineAnalytics.saveRetrainAnnotations": {
|
|
31731
32041
|
capName: "pipeline-analytics",
|
|
31732
32042
|
capScope: "device",
|
|
@@ -31751,6 +32061,12 @@ Object.freeze({
|
|
|
31751
32061
|
addonId: null,
|
|
31752
32062
|
access: "create"
|
|
31753
32063
|
},
|
|
32064
|
+
"pipelineAnalytics.startStorageMigrationMove": {
|
|
32065
|
+
capName: "pipeline-analytics",
|
|
32066
|
+
capScope: "device",
|
|
32067
|
+
addonId: null,
|
|
32068
|
+
access: "create"
|
|
32069
|
+
},
|
|
31754
32070
|
"pipelineAnalytics.wipeAllAnalytics": {
|
|
31755
32071
|
capName: "pipeline-analytics",
|
|
31756
32072
|
capScope: "device",
|
|
@@ -32117,6 +32433,12 @@ Object.freeze({
|
|
|
32117
32433
|
addonId: null,
|
|
32118
32434
|
access: "view"
|
|
32119
32435
|
},
|
|
32436
|
+
"pipelineOrchestrator.pauseForStorageMigration": {
|
|
32437
|
+
capName: "pipeline-orchestrator",
|
|
32438
|
+
capScope: "system",
|
|
32439
|
+
addonId: null,
|
|
32440
|
+
access: "create"
|
|
32441
|
+
},
|
|
32120
32442
|
"pipelineOrchestrator.rebalance": {
|
|
32121
32443
|
capName: "pipeline-orchestrator",
|
|
32122
32444
|
capScope: "system",
|
|
@@ -32141,6 +32463,12 @@ Object.freeze({
|
|
|
32141
32463
|
addonId: null,
|
|
32142
32464
|
access: "view"
|
|
32143
32465
|
},
|
|
32466
|
+
"pipelineOrchestrator.resumeForStorageMigration": {
|
|
32467
|
+
capName: "pipeline-orchestrator",
|
|
32468
|
+
capScope: "system",
|
|
32469
|
+
addonId: null,
|
|
32470
|
+
access: "create"
|
|
32471
|
+
},
|
|
32144
32472
|
"pipelineOrchestrator.saveTemplate": {
|
|
32145
32473
|
capName: "pipeline-orchestrator",
|
|
32146
32474
|
capScope: "system",
|
|
@@ -32537,7 +32865,7 @@ Object.freeze({
|
|
|
32537
32865
|
addonId: null,
|
|
32538
32866
|
access: "create"
|
|
32539
32867
|
},
|
|
32540
|
-
"recording.
|
|
32868
|
+
"recording.cancelStorageMigrationMove": {
|
|
32541
32869
|
capName: "recording",
|
|
32542
32870
|
capScope: "system",
|
|
32543
32871
|
addonId: null,
|
|
@@ -32573,7 +32901,7 @@ Object.freeze({
|
|
|
32573
32901
|
addonId: null,
|
|
32574
32902
|
access: "view"
|
|
32575
32903
|
},
|
|
32576
|
-
"recording.
|
|
32904
|
+
"recording.getStorageMigrationMoveStatus": {
|
|
32577
32905
|
capName: "recording",
|
|
32578
32906
|
capScope: "system",
|
|
32579
32907
|
addonId: null,
|
|
@@ -32597,6 +32925,12 @@ Object.freeze({
|
|
|
32597
32925
|
addonId: null,
|
|
32598
32926
|
access: "view"
|
|
32599
32927
|
},
|
|
32928
|
+
"recording.pauseForStorageMigration": {
|
|
32929
|
+
capName: "recording",
|
|
32930
|
+
capScope: "system",
|
|
32931
|
+
addonId: null,
|
|
32932
|
+
access: "create"
|
|
32933
|
+
},
|
|
32600
32934
|
"recording.pruneFootage": {
|
|
32601
32935
|
capName: "recording",
|
|
32602
32936
|
capScope: "system",
|
|
@@ -32615,7 +32949,7 @@ Object.freeze({
|
|
|
32615
32949
|
addonId: null,
|
|
32616
32950
|
access: "view"
|
|
32617
32951
|
},
|
|
32618
|
-
"recording.
|
|
32952
|
+
"recording.refreshStorageLocationsForMigration": {
|
|
32619
32953
|
capName: "recording",
|
|
32620
32954
|
capScope: "system",
|
|
32621
32955
|
addonId: null,
|
|
@@ -32639,12 +32973,24 @@ Object.freeze({
|
|
|
32639
32973
|
addonId: null,
|
|
32640
32974
|
access: "create"
|
|
32641
32975
|
},
|
|
32976
|
+
"recording.resumeForStorageMigration": {
|
|
32977
|
+
capName: "recording",
|
|
32978
|
+
capScope: "system",
|
|
32979
|
+
addonId: null,
|
|
32980
|
+
access: "create"
|
|
32981
|
+
},
|
|
32642
32982
|
"recording.setDeviceConfig": {
|
|
32643
32983
|
capName: "recording",
|
|
32644
32984
|
capScope: "system",
|
|
32645
32985
|
addonId: null,
|
|
32646
32986
|
access: "create"
|
|
32647
32987
|
},
|
|
32988
|
+
"recording.startStorageMigrationMove": {
|
|
32989
|
+
capName: "recording",
|
|
32990
|
+
capScope: "system",
|
|
32991
|
+
addonId: null,
|
|
32992
|
+
access: "create"
|
|
32993
|
+
},
|
|
32648
32994
|
"recordingExport.cancelExport": {
|
|
32649
32995
|
capName: "recordingExport",
|
|
32650
32996
|
capScope: "system",
|
|
@@ -32681,6 +33027,12 @@ Object.freeze({
|
|
|
32681
33027
|
addonId: null,
|
|
32682
33028
|
access: "view"
|
|
32683
33029
|
},
|
|
33030
|
+
"recordingExport.readExportBytes": {
|
|
33031
|
+
capName: "recordingExport",
|
|
33032
|
+
capScope: "system",
|
|
33033
|
+
addonId: null,
|
|
33034
|
+
access: "view"
|
|
33035
|
+
},
|
|
32684
33036
|
"sceneMonitor.captureReference": {
|
|
32685
33037
|
capName: "scene-monitor",
|
|
32686
33038
|
capScope: "device",
|
|
@@ -33035,6 +33387,30 @@ Object.freeze({
|
|
|
33035
33387
|
addonId: null,
|
|
33036
33388
|
access: "view"
|
|
33037
33389
|
},
|
|
33390
|
+
"storageMigration.cancel": {
|
|
33391
|
+
capName: "storage-migration",
|
|
33392
|
+
capScope: "system",
|
|
33393
|
+
addonId: null,
|
|
33394
|
+
access: "create"
|
|
33395
|
+
},
|
|
33396
|
+
"storageMigration.plan": {
|
|
33397
|
+
capName: "storage-migration",
|
|
33398
|
+
capScope: "system",
|
|
33399
|
+
addonId: null,
|
|
33400
|
+
access: "view"
|
|
33401
|
+
},
|
|
33402
|
+
"storageMigration.start": {
|
|
33403
|
+
capName: "storage-migration",
|
|
33404
|
+
capScope: "system",
|
|
33405
|
+
addonId: null,
|
|
33406
|
+
access: "create"
|
|
33407
|
+
},
|
|
33408
|
+
"storageMigration.status": {
|
|
33409
|
+
capName: "storage-migration",
|
|
33410
|
+
capScope: "system",
|
|
33411
|
+
addonId: null,
|
|
33412
|
+
access: "view"
|
|
33413
|
+
},
|
|
33038
33414
|
"storageProvider.abortUpload": {
|
|
33039
33415
|
capName: "storage-provider",
|
|
33040
33416
|
capScope: "system",
|
|
@@ -33413,12 +33789,42 @@ Object.freeze({
|
|
|
33413
33789
|
addonId: null,
|
|
33414
33790
|
access: "create"
|
|
33415
33791
|
},
|
|
33792
|
+
"terminalSession.adoptLegacyMonitor": {
|
|
33793
|
+
capName: "terminal-session",
|
|
33794
|
+
capScope: "system",
|
|
33795
|
+
addonId: null,
|
|
33796
|
+
access: "create"
|
|
33797
|
+
},
|
|
33416
33798
|
"terminalSession.close": {
|
|
33417
33799
|
capName: "terminal-session",
|
|
33418
33800
|
capScope: "system",
|
|
33419
33801
|
addonId: null,
|
|
33420
33802
|
access: "create"
|
|
33421
33803
|
},
|
|
33804
|
+
"terminalSession.createInstance": {
|
|
33805
|
+
capName: "terminal-session",
|
|
33806
|
+
capScope: "system",
|
|
33807
|
+
addonId: null,
|
|
33808
|
+
access: "create"
|
|
33809
|
+
},
|
|
33810
|
+
"terminalSession.deleteInstance": {
|
|
33811
|
+
capName: "terminal-session",
|
|
33812
|
+
capScope: "system",
|
|
33813
|
+
addonId: null,
|
|
33814
|
+
access: "delete"
|
|
33815
|
+
},
|
|
33816
|
+
"terminalSession.listInstances": {
|
|
33817
|
+
capName: "terminal-session",
|
|
33818
|
+
capScope: "system",
|
|
33819
|
+
addonId: null,
|
|
33820
|
+
access: "view"
|
|
33821
|
+
},
|
|
33822
|
+
"terminalSession.listLegacyCameras": {
|
|
33823
|
+
capName: "terminal-session",
|
|
33824
|
+
capScope: "system",
|
|
33825
|
+
addonId: null,
|
|
33826
|
+
access: "view"
|
|
33827
|
+
},
|
|
33422
33828
|
"terminalSession.listProfiles": {
|
|
33423
33829
|
capName: "terminal-session",
|
|
33424
33830
|
capScope: "system",
|
|
@@ -33449,6 +33855,12 @@ Object.freeze({
|
|
|
33449
33855
|
addonId: null,
|
|
33450
33856
|
access: "create"
|
|
33451
33857
|
},
|
|
33858
|
+
"terminalSession.setInstanceEnabled": {
|
|
33859
|
+
capName: "terminal-session",
|
|
33860
|
+
capScope: "system",
|
|
33861
|
+
addonId: null,
|
|
33862
|
+
access: "create"
|
|
33863
|
+
},
|
|
33452
33864
|
"terminalSession.writeInput": {
|
|
33453
33865
|
capName: "terminal-session",
|
|
33454
33866
|
capScope: "system",
|
|
@@ -34078,7 +34490,23 @@ var TimelapseRuleInputSchema = object({
|
|
|
34078
34490
|
/** Canonical notification priority ordinal (1..5); per-target overridable. */
|
|
34079
34491
|
priority: PriorityField.default(3)
|
|
34080
34492
|
});
|
|
34081
|
-
|
|
34493
|
+
/**
|
|
34494
|
+
* Partial patch for an update — any subset of the INPUT fields, with NO
|
|
34495
|
+
* defaults (an absent key means "leave unchanged", never "reset to default").
|
|
34496
|
+
* Provenance and ownership are absent by construction: a patch can rename or
|
|
34497
|
+
* retune a rule, never re-own it or forge its generation state.
|
|
34498
|
+
*
|
|
34499
|
+
* CLEAR SIGNAL: `template` is the one OPTIONAL field an editor can REMOVE, so
|
|
34500
|
+
* it is `.nullable()` here and NOWHERE else. Wire representation:
|
|
34501
|
+
* - key absent → leave the template unchanged
|
|
34502
|
+
* - `"template": null` → CLEAR it (the persisted rule loses the key)
|
|
34503
|
+
* - `"template": {...}` → replace it
|
|
34504
|
+
* `undefined` is deliberately NOT the clear signal: it does not survive
|
|
34505
|
+
* `JSON.stringify`, so a viewer editor could not express "remove". The
|
|
34506
|
+
* PERSISTED rule never carries `null` — the store drops the key (see
|
|
34507
|
+
* `TimelapseStore.update`).
|
|
34508
|
+
*/
|
|
34509
|
+
var TimelapseRulePatchSchema = object({
|
|
34082
34510
|
name: NameField.optional(),
|
|
34083
34511
|
enabled: boolean().optional(),
|
|
34084
34512
|
deviceIds: DeviceIdsField.optional(),
|
|
@@ -34099,15 +34527,50 @@ var TimelapseRuleSchema = TimelapseRuleInputSchema.extend({
|
|
|
34099
34527
|
*/
|
|
34100
34528
|
ownerUserId: string().optional(),
|
|
34101
34529
|
/**
|
|
34102
|
-
* Epoch-ms of the
|
|
34103
|
-
*
|
|
34530
|
+
* Epoch-ms of the NEWEST successful generation across every camera of this
|
|
34531
|
+
* rule. What a UI shows, and the compatibility floor for
|
|
34532
|
+
* {@link readTimelapseGeneratedAt}. Absent = never generated.
|
|
34104
34533
|
*/
|
|
34105
34534
|
lastGeneratedAt: number().optional(),
|
|
34535
|
+
/**
|
|
34536
|
+
* PER-CAMERA generation state, keyed by `String(deviceId)` — the
|
|
34537
|
+
* re-generation guard's real durable state.
|
|
34538
|
+
*
|
|
34539
|
+
* One rule covers several cameras and each renders its own video, so a rule
|
|
34540
|
+
* -wide stamp is wrong in the direction that DESTROYS work: camera A
|
|
34541
|
+
* succeeding at 06:05 tells camera B, whose render failed, that it is
|
|
34542
|
+
* already done — and B's night is gone for good, because the window will not
|
|
34543
|
+
* come back.
|
|
34544
|
+
*
|
|
34545
|
+
* ADDITIVE, so the migration is free: a row written before this field simply
|
|
34546
|
+
* has no map, and {@link readTimelapseGeneratedAt} falls back to
|
|
34547
|
+
* {@link TimelapseRuleSchema.shape.lastGeneratedAt}. Reading an old row as
|
|
34548
|
+
* "never generated" would re-render and re-notify every camera of every rule
|
|
34549
|
+
* once, on the deploy that shipped the map.
|
|
34550
|
+
*/
|
|
34551
|
+
generatedByDevice: record(string(), number()).optional(),
|
|
34106
34552
|
/** userId of the caller who created the rule (server-stamped). */
|
|
34107
34553
|
createdBy: string(),
|
|
34108
34554
|
createdAt: number(),
|
|
34109
34555
|
updatedAt: number()
|
|
34110
34556
|
});
|
|
34557
|
+
/**
|
|
34558
|
+
* The last successful generation for ONE camera of a rule, epoch-ms.
|
|
34559
|
+
*
|
|
34560
|
+
* The per-device map wins; a rule with no map falls back to the rule-wide
|
|
34561
|
+
* `lastGeneratedAt` (the compatible-migration path — see
|
|
34562
|
+
* {@link TimelapseRuleSchema}); a rule with neither returns 0, which every
|
|
34563
|
+
* guard reads as "never generated".
|
|
34564
|
+
*
|
|
34565
|
+
* Read through this helper and never off the field directly: the fallback is
|
|
34566
|
+
* the whole migration, and a call site that forgot it would re-render an
|
|
34567
|
+
* entire rule set once.
|
|
34568
|
+
*/
|
|
34569
|
+
function readTimelapseGeneratedAt(rule, deviceId) {
|
|
34570
|
+
const map = rule.generatedByDevice;
|
|
34571
|
+
if (map !== void 0) return map[String(deviceId)] ?? 0;
|
|
34572
|
+
return rule.lastGeneratedAt ?? 0;
|
|
34573
|
+
}
|
|
34111
34574
|
object({
|
|
34112
34575
|
/**
|
|
34113
34576
|
* Fraction of the box's own size added on EACH side before cutting.
|
|
@@ -34260,4 +34723,4 @@ function vectorDimFromBase64(encoded) {
|
|
|
34260
34723
|
return Math.floor(Buffer.from(encoded, "base64").byteLength / 4);
|
|
34261
34724
|
}
|
|
34262
34725
|
//#endregion
|
|
34263
|
-
export {
|
|
34726
|
+
export { isDeviceScopedCap as $, customAction as A, pipelineAnalyticsCapability as B, TimelapseRuleSchema as C, audioMetricsCapability as D, alarmPanelCapability as E, faceGalleryCapability as F, vectorDimFromBase64 as G, readDeviceStateFrom as H, hfModelUrl as I, errMsg as J, videoclipsCapability as K, isScheduleActive as L, deriveRecordingMode as M, embeddingEncoderCapability as N, buildEventKindDescriptor as O, encodeVectorBase64 as P, hydrateSchema as Q, kebabToCamel as R, TimelapseRulePatchSchema as S, addonWidgetsSourceCapability as T, readTimelapseGeneratedAt as U, plateGalleryCapability as V, subKindsOf as W, DeviceType as X, BaseAddon as Y, createEvent as Z, NcTaxonomySchema as _, EVENT_PAD_MS as a, literal as at, RetrainStatusSchema as b, NC_CONDITION_CATALOG as c, record as ct, NcRuleInputSchema as d, EventCategory as dt, nodePin as et, NcRulePatchSchema as f, NcSnoozeSuppressedSchema as g, NcSnoozeSchema as h, EVENT_KIND_BY_CAP as i, boolean as it, defineCustomActions as j, cosineSimilarity as k, NC_TAXONOMY as l, string as lt, NcSnoozeInputSchema as m, DEFAULT_EVENT_COLOR as n, _enum as nt, LabelAttributionSchema as o, number as ot, NcRuleSchema as p, zoneAnalyticsCapability as q, DeclaredDevices as r, array as rt, MACRO_LABELS as s, object as st, BaseDevice as t, sleep as tt, NcConditionDescriptorSchema as u, unknown as ut, OpsLogEntrySchema as v, TrackSourceSchema as w, TimelapseRuleInputSchema as x, RECORDING_EXPORT_MAX_READ_BYTES as y, notificationRulesCapability as z };
|