@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
|
@@ -7421,8 +7421,31 @@ var AdoptionJobSchema = object({
|
|
|
7421
7421
|
error: string().nullable()
|
|
7422
7422
|
});
|
|
7423
7423
|
/**
|
|
7424
|
-
* Per-camera FUNCTION SWITCHES
|
|
7425
|
-
*
|
|
7424
|
+
* Per-camera FUNCTION SWITCHES.
|
|
7425
|
+
*
|
|
7426
|
+
* ## The aggregate group is being withdrawn — the BADGE is not (D113)
|
|
7427
|
+
*
|
|
7428
|
+
* This file shipped as "the one coherent on/off surface over the pipeline
|
|
7429
|
+
* functions an operator thinks in terms of". The operator's verdict on
|
|
7430
|
+
* 2026-08-12 was that the coherent surface bought complexity and no clarity:
|
|
7431
|
+
* every function already had a settings page of its own, and a second place to
|
|
7432
|
+
* turn it off is a second place to look. Each switch is going back to its own
|
|
7433
|
+
* component's original options — detection to the detection-pipeline wrapper
|
|
7434
|
+
* binding, audio analysis to its own, recording to `RecordingConfig.enabled`
|
|
7435
|
+
* (which was always first-class; the switch was a veneer over
|
|
7436
|
+
* `recording.setDeviceConfig`), notifications to a notification-center
|
|
7437
|
+
* per-device setting, the two camera planes to their own components.
|
|
7438
|
+
*
|
|
7439
|
+
* What survives is {@link composeSwitchedOff}: `CameraStatus.switchedOff`, the
|
|
7440
|
+
* thing that lets a status surface say DISABLED instead of BROKEN, recomposed
|
|
7441
|
+
* straight from the authorities with no group in the middle. That rule was
|
|
7442
|
+
* never about a control panel.
|
|
7443
|
+
*
|
|
7444
|
+
* Everything else here — {@link CAMERA_SWITCH_CATALOG}, {@link CameraSwitch},
|
|
7445
|
+
* {@link deriveCameraSwitches}, the `pipelineOrchestrator.getCameraSwitches` /
|
|
7446
|
+
* `setCameraSwitch` pair — is a COMPATIBILITY surface for as long as deployed
|
|
7447
|
+
* viewers (v1.0.305) and the admin UI still call it. It is deleted when they
|
|
7448
|
+
* stop; nothing new may be built on it.
|
|
7426
7449
|
*
|
|
7427
7450
|
* ## This file adds no state
|
|
7428
7451
|
*
|
|
@@ -7784,14 +7807,29 @@ var RecordingConfigSchema = object({
|
|
|
7784
7807
|
scrubThumbnails: ScrubThumbnailPresetSchema.optional()
|
|
7785
7808
|
}).strict();
|
|
7786
7809
|
/**
|
|
7810
|
+
* Derive the {@link RecordingStorageModeSchema} summary from the authoritative
|
|
7811
|
+
* bands: `continuous` when any band records continuously, `events` when a band
|
|
7812
|
+
* exists at all, else `off`. Pure.
|
|
7813
|
+
*
|
|
7814
|
+
* THE one definition: the recorder stamps `config.mode` with it on save and
|
|
7815
|
+
* reports it as the cap's `activeMode`, and the settings UI reads it back to
|
|
7816
|
+
* decide which authoring tab a config opens in. Two copies would drift, and the
|
|
7817
|
+
* symptom (a status dot disagreeing with what is being recorded) is exactly the
|
|
7818
|
+
* bug this field was added to fix.
|
|
7819
|
+
*/
|
|
7820
|
+
function deriveRecordingMode(config) {
|
|
7821
|
+
if (!config.enabled || config.bands.length === 0) return "off";
|
|
7822
|
+
if (config.bands.some((band) => band.mode === "continuous")) return "continuous";
|
|
7823
|
+
return "events";
|
|
7824
|
+
}
|
|
7825
|
+
/**
|
|
7787
7826
|
* Entity-relocation job state (storage entity-routing spec, Phase 4).
|
|
7788
7827
|
*
|
|
7789
|
-
* One shape shared by the recorder
|
|
7790
|
-
*
|
|
7791
|
-
*
|
|
7792
|
-
*
|
|
7793
|
-
*
|
|
7794
|
-
* row on the owning addon's surface.
|
|
7828
|
+
* One shape shared by the recorder and pipeline-analytics internal movers.
|
|
7829
|
+
* The public admin surface is `storage-migration`; child jobs remain in RAM
|
|
7830
|
+
* because copy-if-absent, verify, delete and index/row repoint are resumable.
|
|
7831
|
+
* Each completed/failed run also lands one durable ops-log row on its owning
|
|
7832
|
+
* addon surface.
|
|
7795
7833
|
*/
|
|
7796
7834
|
var RelocateJobStateSchema = _enum([
|
|
7797
7835
|
"running",
|
|
@@ -7818,19 +7856,100 @@ var RelocateJobSchema = object({
|
|
|
7818
7856
|
finishedAt: number().nullable(),
|
|
7819
7857
|
error: string().nullable()
|
|
7820
7858
|
});
|
|
7859
|
+
/** Profile-derived footage selection used only by the migration coordinator:
|
|
7860
|
+
* `recordings` owns high+mid; `recordingsLow` owns low. */
|
|
7861
|
+
var RelocateFootageClassSchema = _enum(["recordings", "recordingsLow"]);
|
|
7821
7862
|
var RelocateFootageInputSchema = object({
|
|
7822
|
-
deviceId: number().optional(),
|
|
7823
7863
|
fromLocationId: string(),
|
|
7824
7864
|
toLocationId: string(),
|
|
7825
7865
|
entities: array(_enum(["segments"])).optional(),
|
|
7866
|
+
/** Limits relocation to the logical profile class. Omit only for the
|
|
7867
|
+
* pre-orchestration compatibility path. */
|
|
7868
|
+
footageClass: RelocateFootageClassSchema.optional(),
|
|
7826
7869
|
/** Copy throttle in MB/s (default 40) — the drain is a background chore,
|
|
7827
7870
|
* never allowed to starve live writers. */
|
|
7828
7871
|
throttleMbps: number().min(1).max(1e3).optional()
|
|
7829
7872
|
});
|
|
7830
|
-
|
|
7831
|
-
|
|
7873
|
+
/** Internal, lease-scoped participant operation. It is intentionally separate
|
|
7874
|
+
* from persistent recording settings: a migration never changes
|
|
7875
|
+
* `RecordingConfig.enabled` or camera wrapper bindings. */
|
|
7876
|
+
var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
|
|
7877
|
+
var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
|
|
7878
|
+
var StorageMigrationMediaMoveInputSchema = object({
|
|
7832
7879
|
toLocationId: string(),
|
|
7833
7880
|
throttleMbps: number().min(1).max(1e3).optional()
|
|
7881
|
+
}).extend({ leaseId: string().min(1) });
|
|
7882
|
+
/** The independently selectable logical storage classes. `recordings`
|
|
7883
|
+
* encompasses the high and mid segment profiles; `recordingsLow` is low
|
|
7884
|
+
* segments; `eventMedia` is post-analysis blobs. */
|
|
7885
|
+
var StorageMigrationClassSchema = _enum([
|
|
7886
|
+
"recordings",
|
|
7887
|
+
"recordingsLow",
|
|
7888
|
+
"eventMedia"
|
|
7889
|
+
]);
|
|
7890
|
+
/** A destination is always an existing, fully-qualified location id. The
|
|
7891
|
+
* migration API intentionally never changes a source location's `basePath`:
|
|
7892
|
+
* callers create a new `<type>:<slug>` location, then select it here. */
|
|
7893
|
+
var StorageMigrationDestinationsSchema = object({
|
|
7894
|
+
recordings: string().min(1).optional(),
|
|
7895
|
+
recordingsLow: string().min(1).optional(),
|
|
7896
|
+
eventMedia: string().min(1).optional()
|
|
7897
|
+
}).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
|
|
7898
|
+
/** Shared input for planning and starting an orchestrated storage migration. */
|
|
7899
|
+
var StorageMigrationInputSchema = object({
|
|
7900
|
+
destinations: StorageMigrationDestinationsSchema,
|
|
7901
|
+
throttleMbps: number().min(1).max(1e3).optional()
|
|
7902
|
+
});
|
|
7903
|
+
/** The durable coordinator state machine. The only phase that changes default
|
|
7904
|
+
* locations is `repointing`, after every selected mover has completed and been
|
|
7905
|
+
* verified. */
|
|
7906
|
+
var StorageMigrationPhaseSchema = _enum([
|
|
7907
|
+
"planning",
|
|
7908
|
+
"pausing",
|
|
7909
|
+
"moving",
|
|
7910
|
+
"verifying",
|
|
7911
|
+
"repointing",
|
|
7912
|
+
"refreshing",
|
|
7913
|
+
"resuming",
|
|
7914
|
+
"done",
|
|
7915
|
+
"failed",
|
|
7916
|
+
"cancelled"
|
|
7917
|
+
]);
|
|
7918
|
+
var StorageMigrationParticipantSchema = _enum([
|
|
7919
|
+
"pipeline",
|
|
7920
|
+
"recorder",
|
|
7921
|
+
"analytics"
|
|
7922
|
+
]);
|
|
7923
|
+
var StorageMigrationMoveSchema = object({
|
|
7924
|
+
storageClass: StorageMigrationClassSchema,
|
|
7925
|
+
fromLocationId: string(),
|
|
7926
|
+
toLocationId: string(),
|
|
7927
|
+
moverJobId: string().nullable(),
|
|
7928
|
+
state: RelocateJobStateSchema.nullable(),
|
|
7929
|
+
error: string().nullable()
|
|
7930
|
+
});
|
|
7931
|
+
var StorageMigrationJobSchema = object({
|
|
7932
|
+
jobId: string(),
|
|
7933
|
+
phase: StorageMigrationPhaseSchema,
|
|
7934
|
+
destinations: StorageMigrationDestinationsSchema,
|
|
7935
|
+
throttleMbps: number(),
|
|
7936
|
+
moves: array(StorageMigrationMoveSchema),
|
|
7937
|
+
pauseLeaseId: string().nullable(),
|
|
7938
|
+
pausedParticipants: array(StorageMigrationParticipantSchema),
|
|
7939
|
+
repointed: boolean(),
|
|
7940
|
+
cancelRequested: boolean(),
|
|
7941
|
+
startedAt: number(),
|
|
7942
|
+
updatedAt: number(),
|
|
7943
|
+
finishedAt: number().nullable(),
|
|
7944
|
+
error: string().nullable()
|
|
7945
|
+
});
|
|
7946
|
+
var StorageMigrationPlanSchema = object({
|
|
7947
|
+
destinations: StorageMigrationDestinationsSchema,
|
|
7948
|
+
moves: array(object({
|
|
7949
|
+
storageClass: StorageMigrationClassSchema,
|
|
7950
|
+
fromLocationId: string(),
|
|
7951
|
+
toLocationId: string()
|
|
7952
|
+
}))
|
|
7834
7953
|
});
|
|
7835
7954
|
/**
|
|
7836
7955
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
@@ -17149,20 +17268,28 @@ var pipelineAnalyticsCapability = {
|
|
|
17149
17268
|
}),
|
|
17150
17269
|
/** The events ops-log rows (newest-first), optionally scoped to one camera.
|
|
17151
17270
|
* Backed by a declared pipeline-analytics SQLite collection. */
|
|
17152
|
-
/**
|
|
17153
|
-
*
|
|
17154
|
-
|
|
17155
|
-
* at the target are skipped, so a re-run resumes. Single-flight.
|
|
17156
|
-
*/
|
|
17157
|
-
relocateMedia: method(RelocateMediaInputSchema, object({ jobId: string() }), {
|
|
17271
|
+
/** Internal migration-participant lease. It drains active MediaStore
|
|
17272
|
+
* writes and refuses new ones without changing analytics bindings. */
|
|
17273
|
+
pauseForStorageMigration: method(StorageMigrationLeaseInputSchema, object({ paused: literal(true) }), {
|
|
17158
17274
|
kind: "mutation",
|
|
17159
17275
|
auth: "admin"
|
|
17160
17276
|
}),
|
|
17161
|
-
|
|
17162
|
-
kind: "
|
|
17277
|
+
resumeForStorageMigration: method(StorageMigrationLeaseInputSchema, object({ resumed: literal(true) }), {
|
|
17278
|
+
kind: "mutation",
|
|
17163
17279
|
auth: "admin"
|
|
17164
17280
|
}),
|
|
17165
|
-
|
|
17281
|
+
/** Drops cached location roots after the storage coordinator repoints a
|
|
17282
|
+
* default so future event-media writes use the new root. */
|
|
17283
|
+
refreshStorageLocationsForMigration: method(StorageMigrationLeaseInputSchema, object({ refreshed: literal(true) }), {
|
|
17284
|
+
kind: "mutation",
|
|
17285
|
+
auth: "admin"
|
|
17286
|
+
}),
|
|
17287
|
+
startStorageMigrationMove: method(StorageMigrationMediaMoveInputSchema, object({ jobId: string() }), {
|
|
17288
|
+
kind: "mutation",
|
|
17289
|
+
auth: "admin"
|
|
17290
|
+
}),
|
|
17291
|
+
getStorageMigrationMoveStatus: method(object({ jobId: string() }), RelocateJobSchema.nullable(), { auth: "admin" }),
|
|
17292
|
+
cancelStorageMigrationMove: method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
17166
17293
|
kind: "mutation",
|
|
17167
17294
|
auth: "admin"
|
|
17168
17295
|
}),
|
|
@@ -18825,9 +18952,16 @@ var CameraStatusSchema = object({
|
|
|
18825
18952
|
audio: CameraAudioStatusSchema.nullable(),
|
|
18826
18953
|
recording: CameraRecordingStatusSchema.nullable(),
|
|
18827
18954
|
/**
|
|
18828
|
-
* Per-camera
|
|
18955
|
+
* Per-camera functions an OPERATOR has turned off
|
|
18829
18956
|
* ([D61](../../../../docs/decisions/adr-0067.md)).
|
|
18830
18957
|
*
|
|
18958
|
+
* Composed from the AUTHORITIES themselves — the wrapper bindings,
|
|
18959
|
+
* `RecordingConfig.enabled`, the notification mute, the broker's audio
|
|
18960
|
+
* policy, the camera's own microphone — via `composeSwitchedOff`, not from
|
|
18961
|
+
* the deprecated `getCameraSwitches` group ([D113](../../../../docs/decisions/adr-0113.md)).
|
|
18962
|
+
* The badge outlives the control panel: the panel was a convenience, this is
|
|
18963
|
+
* the difference between a camera being off and a camera being dead.
|
|
18964
|
+
*
|
|
18831
18965
|
* This is the difference between DISABLED and BROKEN. A camera whose
|
|
18832
18966
|
* `detection` block reports zero fps and whose `switchedOff` contains
|
|
18833
18967
|
* `'object-detection'` was switched off by a person; the same camera with an
|
|
@@ -18898,7 +19032,13 @@ var NodeInferenceDevicesSchema = object({
|
|
|
18898
19032
|
reachable: boolean(),
|
|
18899
19033
|
devices: array(NodeInferenceDeviceSchema).readonly()
|
|
18900
19034
|
});
|
|
18901
|
-
method(object({
|
|
19035
|
+
method(StorageMigrationLeaseInputSchema, object({ paused: literal(true) }), {
|
|
19036
|
+
kind: "mutation",
|
|
19037
|
+
auth: "admin"
|
|
19038
|
+
}), method(StorageMigrationLeaseInputSchema, object({ resumed: literal(true) }), {
|
|
19039
|
+
kind: "mutation",
|
|
19040
|
+
auth: "admin"
|
|
19041
|
+
}), method(object({
|
|
18902
19042
|
deviceId: number(),
|
|
18903
19043
|
agentNodeId: string()
|
|
18904
19044
|
}), object({ success: literal(true) }), {
|
|
@@ -19602,6 +19742,13 @@ method(object({ locationId: string() }), EvictableUsageSchema), method(object({
|
|
|
19602
19742
|
locationId: string(),
|
|
19603
19743
|
targetBytes: number().int().positive()
|
|
19604
19744
|
}), EvictResultSchema, { kind: "mutation" });
|
|
19745
|
+
method(StorageMigrationInputSchema, StorageMigrationPlanSchema, { auth: "admin" }), method(StorageMigrationInputSchema, object({ jobId: string() }), {
|
|
19746
|
+
kind: "mutation",
|
|
19747
|
+
auth: "admin"
|
|
19748
|
+
}), method(object({ jobId: string().optional() }), StorageMigrationJobSchema.nullable(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
19749
|
+
kind: "mutation",
|
|
19750
|
+
auth: "admin"
|
|
19751
|
+
});
|
|
19605
19752
|
var ProviderInfoSchema = discriminatedUnion("shouldSaveDiskSpace", [object({
|
|
19606
19753
|
providerId: string().min(1),
|
|
19607
19754
|
displayName: string().min(1),
|
|
@@ -19705,6 +19852,28 @@ var TerminalProfileInfoSchema = object({
|
|
|
19705
19852
|
label: string(),
|
|
19706
19853
|
description: string().optional()
|
|
19707
19854
|
});
|
|
19855
|
+
/**
|
|
19856
|
+
* A durable operator-created Terminal instance. Profiles are templates; only
|
|
19857
|
+
* an instance declares a camera.
|
|
19858
|
+
*/
|
|
19859
|
+
var TerminalInstanceInfoSchema = object({
|
|
19860
|
+
instanceId: string(),
|
|
19861
|
+
cameraStableId: string(),
|
|
19862
|
+
nodeId: string(),
|
|
19863
|
+
profileId: string(),
|
|
19864
|
+
profileLabel: string(),
|
|
19865
|
+
name: string(),
|
|
19866
|
+
enabled: boolean()
|
|
19867
|
+
});
|
|
19868
|
+
var TerminalLegacyCameraSchema = object({
|
|
19869
|
+
stableId: string(),
|
|
19870
|
+
nodeId: string(),
|
|
19871
|
+
profileId: string(),
|
|
19872
|
+
profileLabel: string(),
|
|
19873
|
+
name: string(),
|
|
19874
|
+
/** Only legacy monitor cameras can retain their historic stable identity. */
|
|
19875
|
+
adoptable: boolean()
|
|
19876
|
+
});
|
|
19708
19877
|
var TerminalOutputEventSchema = discriminatedUnion("kind", [object({
|
|
19709
19878
|
seq: number().int().positive(),
|
|
19710
19879
|
kind: literal("data"),
|
|
@@ -19721,7 +19890,29 @@ var TerminalOutputBatchSchema = object({
|
|
|
19721
19890
|
snapshot: string().optional(),
|
|
19722
19891
|
events: array(TerminalOutputEventSchema).readonly()
|
|
19723
19892
|
});
|
|
19724
|
-
method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(
|
|
19893
|
+
method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalInstanceInfoSchema).readonly(), { auth: "admin" }), method(object({
|
|
19894
|
+
targetNodeId: string().min(1),
|
|
19895
|
+
profileId: string().min(1),
|
|
19896
|
+
name: string().trim().min(1).max(160).optional()
|
|
19897
|
+
}), TerminalInstanceInfoSchema, {
|
|
19898
|
+
kind: "mutation",
|
|
19899
|
+
auth: "admin"
|
|
19900
|
+
}), method(object({ instanceId: string().min(1) }), _void(), {
|
|
19901
|
+
kind: "mutation",
|
|
19902
|
+
auth: "admin"
|
|
19903
|
+
}), method(object({
|
|
19904
|
+
instanceId: string().min(1),
|
|
19905
|
+
enabled: boolean()
|
|
19906
|
+
}), TerminalInstanceInfoSchema, {
|
|
19907
|
+
kind: "mutation",
|
|
19908
|
+
auth: "admin"
|
|
19909
|
+
}), method(_void(), array(TerminalLegacyCameraSchema).readonly(), { auth: "admin" }), method(object({
|
|
19910
|
+
stableId: string().min(1),
|
|
19911
|
+
name: string().trim().min(1).max(160).optional()
|
|
19912
|
+
}), TerminalInstanceInfoSchema, {
|
|
19913
|
+
kind: "mutation",
|
|
19914
|
+
auth: "admin"
|
|
19915
|
+
}), method(_void(), array(TerminalSessionInfoSchema).readonly(), { auth: "admin" }), method(object({
|
|
19725
19916
|
profileId: string(),
|
|
19726
19917
|
cols: number().int().positive(),
|
|
19727
19918
|
rows: number().int().positive()
|
|
@@ -19738,7 +19929,13 @@ method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }),
|
|
|
19738
19929
|
}), method(object({
|
|
19739
19930
|
sessionId: string(),
|
|
19740
19931
|
afterSeq: number().int().nonnegative(),
|
|
19741
|
-
waitMs: number().int().min(0).max(2e3).default(0)
|
|
19932
|
+
waitMs: number().int().min(0).max(2e3).default(0),
|
|
19933
|
+
/**
|
|
19934
|
+
* Wait when a just-opened session has no output yet. Kept opt-in so a
|
|
19935
|
+
* browser's initial repaint remains immediate; the camera snapshot
|
|
19936
|
+
* relay uses it to avoid encoding a blank startup frame.
|
|
19937
|
+
*/
|
|
19938
|
+
waitForOutput: boolean().optional()
|
|
19742
19939
|
}), TerminalOutputBatchSchema, {
|
|
19743
19940
|
kind: "mutation",
|
|
19744
19941
|
auth: "admin",
|
|
@@ -25785,13 +25982,19 @@ method(object({
|
|
|
25785
25982
|
}), {
|
|
25786
25983
|
kind: "mutation",
|
|
25787
25984
|
auth: "admin"
|
|
25788
|
-
}), method(
|
|
25985
|
+
}), method(StorageMigrationLeaseInputSchema, object({ paused: literal(true) }), {
|
|
25789
25986
|
kind: "mutation",
|
|
25790
25987
|
auth: "admin"
|
|
25791
|
-
}), method(object({
|
|
25792
|
-
kind: "
|
|
25988
|
+
}), method(StorageMigrationLeaseInputSchema, object({ resumed: literal(true) }), {
|
|
25989
|
+
kind: "mutation",
|
|
25990
|
+
auth: "admin"
|
|
25991
|
+
}), method(StorageMigrationLeaseInputSchema, object({ refreshed: literal(true) }), {
|
|
25992
|
+
kind: "mutation",
|
|
25793
25993
|
auth: "admin"
|
|
25794
|
-
}), method(object({ jobId: string() }),
|
|
25994
|
+
}), method(StorageMigrationFootageMoveInputSchema, object({ jobId: string() }), {
|
|
25995
|
+
kind: "mutation",
|
|
25996
|
+
auth: "admin"
|
|
25997
|
+
}), method(object({ jobId: string() }), RelocateJobSchema.nullable(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
25795
25998
|
kind: "mutation",
|
|
25796
25999
|
auth: "admin"
|
|
25797
26000
|
});
|
|
@@ -25811,10 +26014,42 @@ method(object({
|
|
|
25811
26014
|
*/
|
|
25812
26015
|
/** Playback-speed multiplier for the render (1 = realtime). */
|
|
25813
26016
|
var ExportSpeedSchema = number().min(.25).max(32);
|
|
26017
|
+
/**
|
|
26018
|
+
* One dense interval, in SECONDS FROM THE EXPORT'S OWN `fromMs`.
|
|
26019
|
+
*
|
|
26020
|
+
* Relative and not absolute epoch on purpose: the renderer's frame-select
|
|
26021
|
+
* expression sees ffmpeg's `t`, which starts at 0 for the export's source
|
|
26022
|
+
* playlist. Handing it absolute epochs would make every call site responsible
|
|
26023
|
+
* for the same subtraction, and the one that forgot would emit a filter that
|
|
26024
|
+
* selects nothing — silently, as a uniform timelapse.
|
|
26025
|
+
*/
|
|
26026
|
+
var ExportDenseRangeSchema = object({
|
|
26027
|
+
fromSec: number().nonnegative(),
|
|
26028
|
+
toSec: number().nonnegative()
|
|
26029
|
+
}).refine((r) => r.toSec > r.fromSec, { message: "dense range must have toSec > fromSec" });
|
|
26030
|
+
/**
|
|
26031
|
+
* Dense-interval overlay for a timelapse: sample at `dense.everyMs` INSIDE the
|
|
26032
|
+
* listed ranges and at the base `everyMs` everywhere else.
|
|
26033
|
+
*
|
|
26034
|
+
* `everyMs` must be strictly smaller than the base cadence — a dense rate that
|
|
26035
|
+
* is not denser renders a uniform timelapse the operator believes is two-rate.
|
|
26036
|
+
*/
|
|
26037
|
+
var ExportDenseSchema = object({
|
|
26038
|
+
everyMs: number().int().positive(),
|
|
26039
|
+
ranges: array(ExportDenseRangeSchema).min(1).max(200)
|
|
26040
|
+
});
|
|
25814
26041
|
/** Timelapse cadence — sample one source frame per `everyMs`, output at `outputFps`. */
|
|
25815
26042
|
var ExportTimelapseSchema = object({
|
|
25816
26043
|
everyMs: number().int().positive(),
|
|
25817
|
-
outputFps: number().int().min(1).max(60).optional()
|
|
26044
|
+
outputFps: number().int().min(1).max(60).optional(),
|
|
26045
|
+
/** Optional second, FASTER rate over the intervals that matter. */
|
|
26046
|
+
dense: ExportDenseSchema.optional()
|
|
26047
|
+
}).superRefine((v, ctx) => {
|
|
26048
|
+
if (v.dense !== void 0 && v.dense.everyMs >= v.everyMs) ctx.addIssue({
|
|
26049
|
+
code: ZodIssueCode.custom,
|
|
26050
|
+
message: "dense.everyMs must be strictly smaller than the base everyMs",
|
|
26051
|
+
path: ["dense", "everyMs"]
|
|
26052
|
+
});
|
|
25818
26053
|
});
|
|
25819
26054
|
/**
|
|
25820
26055
|
* Render options. `speed` and `timelapse` are mutually exclusive. `includeAudio`
|
|
@@ -25872,6 +26107,38 @@ var ExportDownloadSchema = object({
|
|
|
25872
26107
|
url: string(),
|
|
25873
26108
|
endpoints: array(string())
|
|
25874
26109
|
});
|
|
26110
|
+
/**
|
|
26111
|
+
* Hard ceiling on ONE {@link recordingExportCapability} byte read — 50 MiB.
|
|
26112
|
+
*
|
|
26113
|
+
* Two independent reasons land on the same number, which is why it is this one
|
|
26114
|
+
* and not a rounder guess:
|
|
26115
|
+
*
|
|
26116
|
+
* - **Nobody would accept more.** The roomiest byte cap any notifier backend
|
|
26117
|
+
* declares is telegram's 50 MiB, and the degrade engine DROPS an over-cap
|
|
26118
|
+
* attachment outright rather than degrading it to a link. Bytes above this
|
|
26119
|
+
* are read, encoded and moved to be thrown away at the last step.
|
|
26120
|
+
* - **The envelope is unary.** A base64 payload is held whole, ~1.33× its
|
|
26121
|
+
* size, in the provider AND in the caller — on a hub this repo has already
|
|
26122
|
+
* OOM'd once (D9/D18). A bounded on-demand read at human speed is the shape
|
|
26123
|
+
* those records permit; an unbounded one is the shape they forbid.
|
|
26124
|
+
*
|
|
26125
|
+
* Above it the provider REFUSES with a log line rather than truncating: half a
|
|
26126
|
+
* video is worse than a notification that says there is no attachment.
|
|
26127
|
+
*/
|
|
26128
|
+
var RECORDING_EXPORT_MAX_READ_BYTES = 50 * 1024 * 1024;
|
|
26129
|
+
/**
|
|
26130
|
+
* A finished export's bytes, inline.
|
|
26131
|
+
*
|
|
26132
|
+
* `bytes` is the DECODED length — the number the caller bounds and logs
|
|
26133
|
+
* against, so nobody has to infer it from the base64 length.
|
|
26134
|
+
*/
|
|
26135
|
+
var ExportBytesSchema = object({
|
|
26136
|
+
base64: string(),
|
|
26137
|
+
contentType: string(),
|
|
26138
|
+
/** Suggested filename, extension included. */
|
|
26139
|
+
name: string(),
|
|
26140
|
+
bytes: number().int().nonnegative()
|
|
26141
|
+
});
|
|
25875
26142
|
method(object({
|
|
25876
26143
|
deviceId: number(),
|
|
25877
26144
|
profile: string(),
|
|
@@ -25896,6 +26163,9 @@ method(object({
|
|
|
25896
26163
|
}), method(object({ exportId: string() }), ExportDownloadSchema, {
|
|
25897
26164
|
kind: "query",
|
|
25898
26165
|
auth: "protected"
|
|
26166
|
+
}), method(object({ exportId: string() }), ExportBytesSchema, {
|
|
26167
|
+
kind: "query",
|
|
26168
|
+
auth: "protected"
|
|
25899
26169
|
});
|
|
25900
26170
|
/**
|
|
25901
26171
|
* scene-monitor — device-scoped reference-region state cap. An operator marks
|
|
@@ -28362,9 +28632,10 @@ var DeclaredDevices = class {
|
|
|
28362
28632
|
}
|
|
28363
28633
|
const integrationId = spec.integrationId ?? await this.ensureIntegration(spec.integrationName);
|
|
28364
28634
|
const index = await this.readIndex();
|
|
28635
|
+
const live = await this.readLiveByStableId();
|
|
28365
28636
|
const outcomes = [];
|
|
28366
28637
|
for (const declaration of spec.devices) {
|
|
28367
|
-
const outcome = await this.applyDeclaration(declaration, integrationId, index);
|
|
28638
|
+
const outcome = await this.applyDeclaration(declaration, integrationId, index, live);
|
|
28368
28639
|
if (outcome !== null) outcomes.push(outcome);
|
|
28369
28640
|
}
|
|
28370
28641
|
return {
|
|
@@ -28410,6 +28681,26 @@ var DeclaredDevices = class {
|
|
|
28410
28681
|
return new Map(rows.map((row) => [row.stableId, row]));
|
|
28411
28682
|
}
|
|
28412
28683
|
/**
|
|
28684
|
+
* Devices this kernel already has CONSTRUCTED, by stableId.
|
|
28685
|
+
*
|
|
28686
|
+
* Distinct from {@link readIndex}, and the distinction is the bug: the index
|
|
28687
|
+
* is persisted rows, this is live objects. A row without an object must be
|
|
28688
|
+
* adopted; an object must be left exactly as it is.
|
|
28689
|
+
*
|
|
28690
|
+
* Failure is non-fatal and deliberately so — an empty map degrades to the
|
|
28691
|
+
* previous behaviour (attempt the adopt) rather than skipping a device that
|
|
28692
|
+
* genuinely needs bringing up.
|
|
28693
|
+
*/
|
|
28694
|
+
async readLiveByStableId() {
|
|
28695
|
+
try {
|
|
28696
|
+
const devices = await this.ports.devices.getAll();
|
|
28697
|
+
return new Map(devices.map((device) => [device.stableId, device]));
|
|
28698
|
+
} catch (err) {
|
|
28699
|
+
this.ports.logger.warn("could not read live devices — falling back to adopt-by-row", { meta: { error: err instanceof Error ? err.message : String(err) } });
|
|
28700
|
+
return /* @__PURE__ */ new Map();
|
|
28701
|
+
}
|
|
28702
|
+
}
|
|
28703
|
+
/**
|
|
28413
28704
|
* One declaration: adopt what exists, create what does not.
|
|
28414
28705
|
*
|
|
28415
28706
|
* The create branch is the destructive one — it seeds `initialMeta`, and
|
|
@@ -28418,8 +28709,15 @@ var DeclaredDevices = class {
|
|
|
28418
28709
|
* the declared name over the operator's rename. D49: that branch needs a
|
|
28419
28710
|
* second read to agree.
|
|
28420
28711
|
*/
|
|
28421
|
-
async applyDeclaration(declaration, integrationId, index) {
|
|
28712
|
+
async applyDeclaration(declaration, integrationId, index, live) {
|
|
28422
28713
|
try {
|
|
28714
|
+
const alreadyLive = live.get(declaration.stableId);
|
|
28715
|
+
if (alreadyLive !== void 0) return {
|
|
28716
|
+
stableId: declaration.stableId,
|
|
28717
|
+
deviceId: alreadyLive.id,
|
|
28718
|
+
device: alreadyLive,
|
|
28719
|
+
created: false
|
|
28720
|
+
};
|
|
28423
28721
|
let existing = index.get(declaration.stableId);
|
|
28424
28722
|
if (existing === void 0) {
|
|
28425
28723
|
existing = (await this.readIndex()).get(declaration.stableId);
|
|
@@ -31524,7 +31822,7 @@ Object.freeze({
|
|
|
31524
31822
|
addonId: null,
|
|
31525
31823
|
access: "create"
|
|
31526
31824
|
},
|
|
31527
|
-
"pipelineAnalytics.
|
|
31825
|
+
"pipelineAnalytics.cancelStorageMigrationMove": {
|
|
31528
31826
|
capName: "pipeline-analytics",
|
|
31529
31827
|
capScope: "device",
|
|
31530
31828
|
addonId: null,
|
|
@@ -31596,12 +31894,6 @@ Object.freeze({
|
|
|
31596
31894
|
addonId: null,
|
|
31597
31895
|
access: "view"
|
|
31598
31896
|
},
|
|
31599
|
-
"pipelineAnalytics.getMediaRelocateStatus": {
|
|
31600
|
-
capName: "pipeline-analytics",
|
|
31601
|
-
capScope: "device",
|
|
31602
|
-
addonId: null,
|
|
31603
|
-
access: "view"
|
|
31604
|
-
},
|
|
31605
31897
|
"pipelineAnalytics.getMotionEvents": {
|
|
31606
31898
|
capName: "pipeline-analytics",
|
|
31607
31899
|
capScope: "device",
|
|
@@ -31638,6 +31930,12 @@ Object.freeze({
|
|
|
31638
31930
|
addonId: null,
|
|
31639
31931
|
access: "view"
|
|
31640
31932
|
},
|
|
31933
|
+
"pipelineAnalytics.getStorageMigrationMoveStatus": {
|
|
31934
|
+
capName: "pipeline-analytics",
|
|
31935
|
+
capScope: "device",
|
|
31936
|
+
addonId: null,
|
|
31937
|
+
access: "view"
|
|
31938
|
+
},
|
|
31641
31939
|
"pipelineAnalytics.getTrack": {
|
|
31642
31940
|
capName: "pipeline-analytics",
|
|
31643
31941
|
capScope: "device",
|
|
@@ -31716,6 +32014,12 @@ Object.freeze({
|
|
|
31716
32014
|
addonId: null,
|
|
31717
32015
|
access: "view"
|
|
31718
32016
|
},
|
|
32017
|
+
"pipelineAnalytics.pauseForStorageMigration": {
|
|
32018
|
+
capName: "pipeline-analytics",
|
|
32019
|
+
capScope: "device",
|
|
32020
|
+
addonId: null,
|
|
32021
|
+
access: "create"
|
|
32022
|
+
},
|
|
31719
32023
|
"pipelineAnalytics.proposeRetrainAnnotations": {
|
|
31720
32024
|
capName: "pipeline-analytics",
|
|
31721
32025
|
capScope: "device",
|
|
@@ -31746,7 +32050,7 @@ Object.freeze({
|
|
|
31746
32050
|
addonId: null,
|
|
31747
32051
|
access: "create"
|
|
31748
32052
|
},
|
|
31749
|
-
"pipelineAnalytics.
|
|
32053
|
+
"pipelineAnalytics.refreshStorageLocationsForMigration": {
|
|
31750
32054
|
capName: "pipeline-analytics",
|
|
31751
32055
|
capScope: "device",
|
|
31752
32056
|
addonId: null,
|
|
@@ -31758,6 +32062,12 @@ Object.freeze({
|
|
|
31758
32062
|
addonId: null,
|
|
31759
32063
|
access: "create"
|
|
31760
32064
|
},
|
|
32065
|
+
"pipelineAnalytics.resumeForStorageMigration": {
|
|
32066
|
+
capName: "pipeline-analytics",
|
|
32067
|
+
capScope: "device",
|
|
32068
|
+
addonId: null,
|
|
32069
|
+
access: "create"
|
|
32070
|
+
},
|
|
31761
32071
|
"pipelineAnalytics.saveRetrainAnnotations": {
|
|
31762
32072
|
capName: "pipeline-analytics",
|
|
31763
32073
|
capScope: "device",
|
|
@@ -31782,6 +32092,12 @@ Object.freeze({
|
|
|
31782
32092
|
addonId: null,
|
|
31783
32093
|
access: "create"
|
|
31784
32094
|
},
|
|
32095
|
+
"pipelineAnalytics.startStorageMigrationMove": {
|
|
32096
|
+
capName: "pipeline-analytics",
|
|
32097
|
+
capScope: "device",
|
|
32098
|
+
addonId: null,
|
|
32099
|
+
access: "create"
|
|
32100
|
+
},
|
|
31785
32101
|
"pipelineAnalytics.wipeAllAnalytics": {
|
|
31786
32102
|
capName: "pipeline-analytics",
|
|
31787
32103
|
capScope: "device",
|
|
@@ -32148,6 +32464,12 @@ Object.freeze({
|
|
|
32148
32464
|
addonId: null,
|
|
32149
32465
|
access: "view"
|
|
32150
32466
|
},
|
|
32467
|
+
"pipelineOrchestrator.pauseForStorageMigration": {
|
|
32468
|
+
capName: "pipeline-orchestrator",
|
|
32469
|
+
capScope: "system",
|
|
32470
|
+
addonId: null,
|
|
32471
|
+
access: "create"
|
|
32472
|
+
},
|
|
32151
32473
|
"pipelineOrchestrator.rebalance": {
|
|
32152
32474
|
capName: "pipeline-orchestrator",
|
|
32153
32475
|
capScope: "system",
|
|
@@ -32172,6 +32494,12 @@ Object.freeze({
|
|
|
32172
32494
|
addonId: null,
|
|
32173
32495
|
access: "view"
|
|
32174
32496
|
},
|
|
32497
|
+
"pipelineOrchestrator.resumeForStorageMigration": {
|
|
32498
|
+
capName: "pipeline-orchestrator",
|
|
32499
|
+
capScope: "system",
|
|
32500
|
+
addonId: null,
|
|
32501
|
+
access: "create"
|
|
32502
|
+
},
|
|
32175
32503
|
"pipelineOrchestrator.saveTemplate": {
|
|
32176
32504
|
capName: "pipeline-orchestrator",
|
|
32177
32505
|
capScope: "system",
|
|
@@ -32568,7 +32896,7 @@ Object.freeze({
|
|
|
32568
32896
|
addonId: null,
|
|
32569
32897
|
access: "create"
|
|
32570
32898
|
},
|
|
32571
|
-
"recording.
|
|
32899
|
+
"recording.cancelStorageMigrationMove": {
|
|
32572
32900
|
capName: "recording",
|
|
32573
32901
|
capScope: "system",
|
|
32574
32902
|
addonId: null,
|
|
@@ -32604,7 +32932,7 @@ Object.freeze({
|
|
|
32604
32932
|
addonId: null,
|
|
32605
32933
|
access: "view"
|
|
32606
32934
|
},
|
|
32607
|
-
"recording.
|
|
32935
|
+
"recording.getStorageMigrationMoveStatus": {
|
|
32608
32936
|
capName: "recording",
|
|
32609
32937
|
capScope: "system",
|
|
32610
32938
|
addonId: null,
|
|
@@ -32628,6 +32956,12 @@ Object.freeze({
|
|
|
32628
32956
|
addonId: null,
|
|
32629
32957
|
access: "view"
|
|
32630
32958
|
},
|
|
32959
|
+
"recording.pauseForStorageMigration": {
|
|
32960
|
+
capName: "recording",
|
|
32961
|
+
capScope: "system",
|
|
32962
|
+
addonId: null,
|
|
32963
|
+
access: "create"
|
|
32964
|
+
},
|
|
32631
32965
|
"recording.pruneFootage": {
|
|
32632
32966
|
capName: "recording",
|
|
32633
32967
|
capScope: "system",
|
|
@@ -32646,7 +32980,7 @@ Object.freeze({
|
|
|
32646
32980
|
addonId: null,
|
|
32647
32981
|
access: "view"
|
|
32648
32982
|
},
|
|
32649
|
-
"recording.
|
|
32983
|
+
"recording.refreshStorageLocationsForMigration": {
|
|
32650
32984
|
capName: "recording",
|
|
32651
32985
|
capScope: "system",
|
|
32652
32986
|
addonId: null,
|
|
@@ -32670,12 +33004,24 @@ Object.freeze({
|
|
|
32670
33004
|
addonId: null,
|
|
32671
33005
|
access: "create"
|
|
32672
33006
|
},
|
|
33007
|
+
"recording.resumeForStorageMigration": {
|
|
33008
|
+
capName: "recording",
|
|
33009
|
+
capScope: "system",
|
|
33010
|
+
addonId: null,
|
|
33011
|
+
access: "create"
|
|
33012
|
+
},
|
|
32673
33013
|
"recording.setDeviceConfig": {
|
|
32674
33014
|
capName: "recording",
|
|
32675
33015
|
capScope: "system",
|
|
32676
33016
|
addonId: null,
|
|
32677
33017
|
access: "create"
|
|
32678
33018
|
},
|
|
33019
|
+
"recording.startStorageMigrationMove": {
|
|
33020
|
+
capName: "recording",
|
|
33021
|
+
capScope: "system",
|
|
33022
|
+
addonId: null,
|
|
33023
|
+
access: "create"
|
|
33024
|
+
},
|
|
32679
33025
|
"recordingExport.cancelExport": {
|
|
32680
33026
|
capName: "recordingExport",
|
|
32681
33027
|
capScope: "system",
|
|
@@ -32712,6 +33058,12 @@ Object.freeze({
|
|
|
32712
33058
|
addonId: null,
|
|
32713
33059
|
access: "view"
|
|
32714
33060
|
},
|
|
33061
|
+
"recordingExport.readExportBytes": {
|
|
33062
|
+
capName: "recordingExport",
|
|
33063
|
+
capScope: "system",
|
|
33064
|
+
addonId: null,
|
|
33065
|
+
access: "view"
|
|
33066
|
+
},
|
|
32715
33067
|
"sceneMonitor.captureReference": {
|
|
32716
33068
|
capName: "scene-monitor",
|
|
32717
33069
|
capScope: "device",
|
|
@@ -33066,6 +33418,30 @@ Object.freeze({
|
|
|
33066
33418
|
addonId: null,
|
|
33067
33419
|
access: "view"
|
|
33068
33420
|
},
|
|
33421
|
+
"storageMigration.cancel": {
|
|
33422
|
+
capName: "storage-migration",
|
|
33423
|
+
capScope: "system",
|
|
33424
|
+
addonId: null,
|
|
33425
|
+
access: "create"
|
|
33426
|
+
},
|
|
33427
|
+
"storageMigration.plan": {
|
|
33428
|
+
capName: "storage-migration",
|
|
33429
|
+
capScope: "system",
|
|
33430
|
+
addonId: null,
|
|
33431
|
+
access: "view"
|
|
33432
|
+
},
|
|
33433
|
+
"storageMigration.start": {
|
|
33434
|
+
capName: "storage-migration",
|
|
33435
|
+
capScope: "system",
|
|
33436
|
+
addonId: null,
|
|
33437
|
+
access: "create"
|
|
33438
|
+
},
|
|
33439
|
+
"storageMigration.status": {
|
|
33440
|
+
capName: "storage-migration",
|
|
33441
|
+
capScope: "system",
|
|
33442
|
+
addonId: null,
|
|
33443
|
+
access: "view"
|
|
33444
|
+
},
|
|
33069
33445
|
"storageProvider.abortUpload": {
|
|
33070
33446
|
capName: "storage-provider",
|
|
33071
33447
|
capScope: "system",
|
|
@@ -33444,12 +33820,42 @@ Object.freeze({
|
|
|
33444
33820
|
addonId: null,
|
|
33445
33821
|
access: "create"
|
|
33446
33822
|
},
|
|
33823
|
+
"terminalSession.adoptLegacyMonitor": {
|
|
33824
|
+
capName: "terminal-session",
|
|
33825
|
+
capScope: "system",
|
|
33826
|
+
addonId: null,
|
|
33827
|
+
access: "create"
|
|
33828
|
+
},
|
|
33447
33829
|
"terminalSession.close": {
|
|
33448
33830
|
capName: "terminal-session",
|
|
33449
33831
|
capScope: "system",
|
|
33450
33832
|
addonId: null,
|
|
33451
33833
|
access: "create"
|
|
33452
33834
|
},
|
|
33835
|
+
"terminalSession.createInstance": {
|
|
33836
|
+
capName: "terminal-session",
|
|
33837
|
+
capScope: "system",
|
|
33838
|
+
addonId: null,
|
|
33839
|
+
access: "create"
|
|
33840
|
+
},
|
|
33841
|
+
"terminalSession.deleteInstance": {
|
|
33842
|
+
capName: "terminal-session",
|
|
33843
|
+
capScope: "system",
|
|
33844
|
+
addonId: null,
|
|
33845
|
+
access: "delete"
|
|
33846
|
+
},
|
|
33847
|
+
"terminalSession.listInstances": {
|
|
33848
|
+
capName: "terminal-session",
|
|
33849
|
+
capScope: "system",
|
|
33850
|
+
addonId: null,
|
|
33851
|
+
access: "view"
|
|
33852
|
+
},
|
|
33853
|
+
"terminalSession.listLegacyCameras": {
|
|
33854
|
+
capName: "terminal-session",
|
|
33855
|
+
capScope: "system",
|
|
33856
|
+
addonId: null,
|
|
33857
|
+
access: "view"
|
|
33858
|
+
},
|
|
33453
33859
|
"terminalSession.listProfiles": {
|
|
33454
33860
|
capName: "terminal-session",
|
|
33455
33861
|
capScope: "system",
|
|
@@ -33480,6 +33886,12 @@ Object.freeze({
|
|
|
33480
33886
|
addonId: null,
|
|
33481
33887
|
access: "create"
|
|
33482
33888
|
},
|
|
33889
|
+
"terminalSession.setInstanceEnabled": {
|
|
33890
|
+
capName: "terminal-session",
|
|
33891
|
+
capScope: "system",
|
|
33892
|
+
addonId: null,
|
|
33893
|
+
access: "create"
|
|
33894
|
+
},
|
|
33483
33895
|
"terminalSession.writeInput": {
|
|
33484
33896
|
capName: "terminal-session",
|
|
33485
33897
|
capScope: "system",
|
|
@@ -34109,7 +34521,23 @@ var TimelapseRuleInputSchema = object({
|
|
|
34109
34521
|
/** Canonical notification priority ordinal (1..5); per-target overridable. */
|
|
34110
34522
|
priority: PriorityField.default(3)
|
|
34111
34523
|
});
|
|
34112
|
-
|
|
34524
|
+
/**
|
|
34525
|
+
* Partial patch for an update — any subset of the INPUT fields, with NO
|
|
34526
|
+
* defaults (an absent key means "leave unchanged", never "reset to default").
|
|
34527
|
+
* Provenance and ownership are absent by construction: a patch can rename or
|
|
34528
|
+
* retune a rule, never re-own it or forge its generation state.
|
|
34529
|
+
*
|
|
34530
|
+
* CLEAR SIGNAL: `template` is the one OPTIONAL field an editor can REMOVE, so
|
|
34531
|
+
* it is `.nullable()` here and NOWHERE else. Wire representation:
|
|
34532
|
+
* - key absent → leave the template unchanged
|
|
34533
|
+
* - `"template": null` → CLEAR it (the persisted rule loses the key)
|
|
34534
|
+
* - `"template": {...}` → replace it
|
|
34535
|
+
* `undefined` is deliberately NOT the clear signal: it does not survive
|
|
34536
|
+
* `JSON.stringify`, so a viewer editor could not express "remove". The
|
|
34537
|
+
* PERSISTED rule never carries `null` — the store drops the key (see
|
|
34538
|
+
* `TimelapseStore.update`).
|
|
34539
|
+
*/
|
|
34540
|
+
var TimelapseRulePatchSchema = object({
|
|
34113
34541
|
name: NameField.optional(),
|
|
34114
34542
|
enabled: boolean().optional(),
|
|
34115
34543
|
deviceIds: DeviceIdsField.optional(),
|
|
@@ -34130,15 +34558,50 @@ var TimelapseRuleSchema = TimelapseRuleInputSchema.extend({
|
|
|
34130
34558
|
*/
|
|
34131
34559
|
ownerUserId: string().optional(),
|
|
34132
34560
|
/**
|
|
34133
|
-
* Epoch-ms of the
|
|
34134
|
-
*
|
|
34561
|
+
* Epoch-ms of the NEWEST successful generation across every camera of this
|
|
34562
|
+
* rule. What a UI shows, and the compatibility floor for
|
|
34563
|
+
* {@link readTimelapseGeneratedAt}. Absent = never generated.
|
|
34135
34564
|
*/
|
|
34136
34565
|
lastGeneratedAt: number().optional(),
|
|
34566
|
+
/**
|
|
34567
|
+
* PER-CAMERA generation state, keyed by `String(deviceId)` — the
|
|
34568
|
+
* re-generation guard's real durable state.
|
|
34569
|
+
*
|
|
34570
|
+
* One rule covers several cameras and each renders its own video, so a rule
|
|
34571
|
+
* -wide stamp is wrong in the direction that DESTROYS work: camera A
|
|
34572
|
+
* succeeding at 06:05 tells camera B, whose render failed, that it is
|
|
34573
|
+
* already done — and B's night is gone for good, because the window will not
|
|
34574
|
+
* come back.
|
|
34575
|
+
*
|
|
34576
|
+
* ADDITIVE, so the migration is free: a row written before this field simply
|
|
34577
|
+
* has no map, and {@link readTimelapseGeneratedAt} falls back to
|
|
34578
|
+
* {@link TimelapseRuleSchema.shape.lastGeneratedAt}. Reading an old row as
|
|
34579
|
+
* "never generated" would re-render and re-notify every camera of every rule
|
|
34580
|
+
* once, on the deploy that shipped the map.
|
|
34581
|
+
*/
|
|
34582
|
+
generatedByDevice: record(string(), number()).optional(),
|
|
34137
34583
|
/** userId of the caller who created the rule (server-stamped). */
|
|
34138
34584
|
createdBy: string(),
|
|
34139
34585
|
createdAt: number(),
|
|
34140
34586
|
updatedAt: number()
|
|
34141
34587
|
});
|
|
34588
|
+
/**
|
|
34589
|
+
* The last successful generation for ONE camera of a rule, epoch-ms.
|
|
34590
|
+
*
|
|
34591
|
+
* The per-device map wins; a rule with no map falls back to the rule-wide
|
|
34592
|
+
* `lastGeneratedAt` (the compatible-migration path — see
|
|
34593
|
+
* {@link TimelapseRuleSchema}); a rule with neither returns 0, which every
|
|
34594
|
+
* guard reads as "never generated".
|
|
34595
|
+
*
|
|
34596
|
+
* Read through this helper and never off the field directly: the fallback is
|
|
34597
|
+
* the whole migration, and a call site that forgot it would re-render an
|
|
34598
|
+
* entire rule set once.
|
|
34599
|
+
*/
|
|
34600
|
+
function readTimelapseGeneratedAt(rule, deviceId) {
|
|
34601
|
+
const map = rule.generatedByDevice;
|
|
34602
|
+
if (map !== void 0) return map[String(deviceId)] ?? 0;
|
|
34603
|
+
return rule.lastGeneratedAt ?? 0;
|
|
34604
|
+
}
|
|
34142
34605
|
object({
|
|
34143
34606
|
/**
|
|
34144
34607
|
* Fraction of the box's own size added on EACH side before cutting.
|
|
@@ -34417,6 +34880,12 @@ Object.defineProperty(exports, "OpsLogEntrySchema", {
|
|
|
34417
34880
|
return OpsLogEntrySchema;
|
|
34418
34881
|
}
|
|
34419
34882
|
});
|
|
34883
|
+
Object.defineProperty(exports, "RECORDING_EXPORT_MAX_READ_BYTES", {
|
|
34884
|
+
enumerable: true,
|
|
34885
|
+
get: function() {
|
|
34886
|
+
return RECORDING_EXPORT_MAX_READ_BYTES;
|
|
34887
|
+
}
|
|
34888
|
+
});
|
|
34420
34889
|
Object.defineProperty(exports, "RetrainStatusSchema", {
|
|
34421
34890
|
enumerable: true,
|
|
34422
34891
|
get: function() {
|
|
@@ -34429,6 +34898,12 @@ Object.defineProperty(exports, "TimelapseRuleInputSchema", {
|
|
|
34429
34898
|
return TimelapseRuleInputSchema;
|
|
34430
34899
|
}
|
|
34431
34900
|
});
|
|
34901
|
+
Object.defineProperty(exports, "TimelapseRulePatchSchema", {
|
|
34902
|
+
enumerable: true,
|
|
34903
|
+
get: function() {
|
|
34904
|
+
return TimelapseRulePatchSchema;
|
|
34905
|
+
}
|
|
34906
|
+
});
|
|
34432
34907
|
Object.defineProperty(exports, "TimelapseRuleSchema", {
|
|
34433
34908
|
enumerable: true,
|
|
34434
34909
|
get: function() {
|
|
@@ -34519,6 +34994,12 @@ Object.defineProperty(exports, "defineCustomActions", {
|
|
|
34519
34994
|
return defineCustomActions;
|
|
34520
34995
|
}
|
|
34521
34996
|
});
|
|
34997
|
+
Object.defineProperty(exports, "deriveRecordingMode", {
|
|
34998
|
+
enumerable: true,
|
|
34999
|
+
get: function() {
|
|
35000
|
+
return deriveRecordingMode;
|
|
35001
|
+
}
|
|
35002
|
+
});
|
|
34522
35003
|
Object.defineProperty(exports, "embeddingEncoderCapability", {
|
|
34523
35004
|
enumerable: true,
|
|
34524
35005
|
get: function() {
|
|
@@ -34621,6 +35102,12 @@ Object.defineProperty(exports, "readDeviceStateFrom", {
|
|
|
34621
35102
|
return readDeviceStateFrom;
|
|
34622
35103
|
}
|
|
34623
35104
|
});
|
|
35105
|
+
Object.defineProperty(exports, "readTimelapseGeneratedAt", {
|
|
35106
|
+
enumerable: true,
|
|
35107
|
+
get: function() {
|
|
35108
|
+
return readTimelapseGeneratedAt;
|
|
35109
|
+
}
|
|
35110
|
+
});
|
|
34624
35111
|
Object.defineProperty(exports, "record", {
|
|
34625
35112
|
enumerable: true,
|
|
34626
35113
|
get: function() {
|