@camstack/system 1.2.21 → 1.2.23
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/addon-runner.js +1 -1
- package/dist/addon-runner.mjs +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
- package/dist/builtins/alerts/alerts.addon.js +1 -1
- package/dist/builtins/alerts/alerts.addon.mjs +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.d.ts +17 -13
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1319 -1097
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1319 -1097
- package/dist/builtins/backup-orchestrator/schedule-store.d.ts +33 -0
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.mjs +1 -1
- package/dist/builtins/device-manager/device-manager.addon.js +1 -1
- package/dist/builtins/device-manager/device-manager.addon.mjs +1 -1
- package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
- package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- package/dist/builtins/local-auth/local-auth.addon.js +1 -1
- package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
- package/dist/builtins/local-network/local-network.addon.d.ts +16 -0
- package/dist/builtins/local-network/local-network.addon.js +30 -2
- package/dist/builtins/local-network/local-network.addon.mjs +30 -2
- package/dist/builtins/loki-logging/index.js +34 -12
- package/dist/builtins/loki-logging/index.mjs +34 -12
- package/dist/builtins/loki-logging/loki-logging.addon.d.ts +19 -0
- package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
- package/dist/builtins/platform-probe/index.js +1 -1
- package/dist/builtins/platform-probe/index.mjs +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
- package/dist/builtins/snapshot/index.js +1 -1
- package/dist/builtins/snapshot/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +1 -1
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +1 -1
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.d.ts +7 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +112 -6
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +112 -6
- package/dist/builtins/storage-orchestrator/storage-orchestrator.service.d.ts +17 -1
- package/dist/builtins/storage-orchestrator/storage-pressure-manager.d.ts +5 -0
- package/dist/builtins/system-config/system-config.addon.js +1 -1
- package/dist/builtins/system-config/system-config.addon.mjs +1 -1
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{dist-DmQ6thmF.mjs → dist-CIek6F9X.mjs} +536 -76
- package/dist/{dist-OQ1yU92D.js → dist-CS0pdC8l.js} +536 -76
- package/dist/index.js +58 -8
- package/dist/index.mjs +58 -8
- package/dist/kernel/capability-registry.d.ts +9 -0
- package/dist/kernel/transport/local-child-registry.d.ts +18 -0
- package/dist/kernel/transport/parent-unowned-call.d.ts +22 -0
- package/dist/logging/log-manager.d.ts +32 -1
- package/dist/logging/partitioned-log-buffer.d.ts +15 -3
- package/dist/{manifest-python-deps-B30qVAuW.mjs → manifest-python-deps-57PA4rHm.mjs} +15 -6
- package/dist/{manifest-python-deps-CnRW2Utv.js → manifest-python-deps-CqDPWqEE.js} +14 -5
- package/package.json +3 -2
|
@@ -3228,35 +3228,22 @@ var ConvertResultSchema = zod.z.object({
|
|
|
3228
3228
|
*/
|
|
3229
3229
|
var RecordingWeekdaySchema = zod.z.number().int().min(0).max(6);
|
|
3230
3230
|
var HHMM = /^([01]\d|2[0-3]):[0-5]\d$/;
|
|
3231
|
-
var RecordingScheduleSchema = zod.z.discriminatedUnion("kind", [zod.z.object({ kind: zod.z.literal("always") }), zod.z.object({
|
|
3232
|
-
kind: zod.z.literal("timeOfDay"),
|
|
3233
|
-
start: zod.z.string().regex(HHMM),
|
|
3234
|
-
end: zod.z.string().regex(HHMM),
|
|
3235
|
-
/** Restrict to these weekdays; omit = every day. */
|
|
3236
|
-
days: zod.z.array(RecordingWeekdaySchema).optional()
|
|
3237
|
-
})]);
|
|
3238
|
-
var RecordingModeSchema = zod.z.enum([
|
|
3239
|
-
"continuous",
|
|
3240
|
-
"onMotion",
|
|
3241
|
-
"onAudioThreshold"
|
|
3242
|
-
]);
|
|
3243
3231
|
/**
|
|
3244
|
-
*
|
|
3245
|
-
*
|
|
3246
|
-
* - `off` —
|
|
3247
|
-
* - `events` —
|
|
3248
|
-
*
|
|
3249
|
-
* - `continuous` — record 24/7 within the schedule.
|
|
3232
|
+
* DERIVED per-camera storage summary — the single field cheap consumers read
|
|
3233
|
+
* (the viewer's status dot, the camera list) instead of walking `bands`:
|
|
3234
|
+
* - `off` — no band covers the camera (or it is disabled).
|
|
3235
|
+
* - `events` — every band records around triggers only.
|
|
3236
|
+
* - `continuous` — at least one band records continuously.
|
|
3250
3237
|
*
|
|
3251
|
-
*
|
|
3252
|
-
*
|
|
3238
|
+
* NEVER authored: the recorder stamps it from the authoritative `bands` on
|
|
3239
|
+
* every save (`activeModeForConfig`). Writing it has no effect.
|
|
3253
3240
|
*/
|
|
3254
3241
|
var RecordingStorageModeSchema = zod.z.enum([
|
|
3255
3242
|
"off",
|
|
3256
3243
|
"events",
|
|
3257
3244
|
"continuous"
|
|
3258
3245
|
]);
|
|
3259
|
-
/** Which detectors trigger an `events`-mode
|
|
3246
|
+
/** Which detectors trigger an `events`-mode band. */
|
|
3260
3247
|
var RecordingTriggersSchema = zod.z.object({
|
|
3261
3248
|
motion: zod.z.boolean().optional(),
|
|
3262
3249
|
audioThresholdDbfs: zod.z.number().optional()
|
|
@@ -3292,18 +3279,6 @@ var RecordingBandSchema = zod.z.object({
|
|
|
3292
3279
|
preBufferSec: zod.z.number().min(0).optional(),
|
|
3293
3280
|
postBufferSec: zod.z.number().min(0).optional()
|
|
3294
3281
|
});
|
|
3295
|
-
var RecordingRuleSchema = zod.z.object({
|
|
3296
|
-
schedule: RecordingScheduleSchema,
|
|
3297
|
-
mode: RecordingModeSchema,
|
|
3298
|
-
/** Seconds of footage to retain BEFORE a trigger (applied at keep/discard). */
|
|
3299
|
-
preBufferSec: zod.z.number().min(0).default(0),
|
|
3300
|
-
/** Keep recording until this many seconds after the last trigger. */
|
|
3301
|
-
postBufferSec: zod.z.number().min(0).default(0),
|
|
3302
|
-
/** Each new trigger restarts the post-buffer window. */
|
|
3303
|
-
resetTimeoutOnNewEvent: zod.z.boolean().default(true),
|
|
3304
|
-
/** onAudioThreshold only — dBFS level that counts as a trigger. */
|
|
3305
|
-
thresholdDbfs: zod.z.number().optional()
|
|
3306
|
-
});
|
|
3307
3282
|
/**
|
|
3308
3283
|
* Per-device retention overrides. Every field is optional; an unset or `0`
|
|
3309
3284
|
* value inherits the node-wide recorder default. Only footage-lifetime limits
|
|
@@ -3337,40 +3312,28 @@ var ScrubThumbnailPresetSchema = zod.z.enum([
|
|
|
3337
3312
|
/**
|
|
3338
3313
|
* The full per-camera recording intent — the wire shape of a RecordingTarget.
|
|
3339
3314
|
*
|
|
3340
|
-
* `
|
|
3341
|
-
*
|
|
3342
|
-
*
|
|
3343
|
-
*
|
|
3315
|
+
* `bands` is the ONLY authored recording intent: what to record, when, and on
|
|
3316
|
+
* which trigger. `mode` is a derived summary the recorder stamps on save; every
|
|
3317
|
+
* other field is a storage knob (profiles, segment length, retention, scrub).
|
|
3318
|
+
*
|
|
3319
|
+
* STRICT on purpose: the legacy authoring surface (`schedule`/`schedules`/
|
|
3320
|
+
* `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30.
|
|
3321
|
+
* A stale caller must fail loudly — silently stripping its legacy intent would
|
|
3322
|
+
* persist a band-less config, i.e. silently stop recording the camera.
|
|
3344
3323
|
*/
|
|
3345
3324
|
var RecordingConfigSchema = zod.z.object({
|
|
3346
3325
|
enabled: zod.z.boolean(),
|
|
3347
|
-
/**
|
|
3348
|
-
*
|
|
3326
|
+
/** DERIVED summary of `bands`, stamped by the recorder on every save.
|
|
3327
|
+
* Authoring it has no effect — see {@link RecordingStorageModeSchema}. */
|
|
3349
3328
|
mode: RecordingStorageModeSchema.optional(),
|
|
3350
3329
|
profiles: zod.z.array(CamProfileSchema).optional(),
|
|
3351
3330
|
segmentSeconds: zod.z.number().int().positive().optional(),
|
|
3352
|
-
/** Shared recording time-bands for `events` & `continuous` — record only when
|
|
3353
|
-
* the wall-clock falls inside one of these windows. Omit or empty = always.
|
|
3354
|
-
* `continuous` compiles to one rule per band; `events` to band × trigger. */
|
|
3355
|
-
schedules: zod.z.array(RecordingScheduleSchema).optional(),
|
|
3356
|
-
/** Legacy single-band predecessor of `schedules`. Read-compat only — it is
|
|
3357
|
-
* normalized into `schedules` on read and never written going forward. (Not
|
|
3358
|
-
* tagged `@deprecated`: the normalization paths must read it cast-free.) */
|
|
3359
|
-
schedule: RecordingScheduleSchema.optional(),
|
|
3360
|
-
/** `events`-mode only — which detectors trigger a recording. */
|
|
3361
|
-
triggers: RecordingTriggersSchema.optional(),
|
|
3362
|
-
/** `events`-mode only — seconds retained before / after a trigger. */
|
|
3363
|
-
preBufferSec: zod.z.number().min(0).optional(),
|
|
3364
|
-
postBufferSec: zod.z.number().min(0).optional(),
|
|
3365
|
-
/** DEPRECATED authoring input; retained for migration/transition. */
|
|
3366
|
-
rules: zod.z.array(RecordingRuleSchema).optional(),
|
|
3367
3331
|
/**
|
|
3368
|
-
* AUTHORITATIVE mode-per-band recording model
|
|
3369
|
-
*
|
|
3370
|
-
*
|
|
3371
|
-
* derived into bands once via `migrateConfigToBands`.
|
|
3332
|
+
* AUTHORITATIVE mode-per-band recording model — the single source of truth
|
|
3333
|
+
* the recorder's band engine consumes. An empty array = record nothing;
|
|
3334
|
+
* "off" is the absence of a covering band, never a band value.
|
|
3372
3335
|
*/
|
|
3373
|
-
bands: zod.z.array(RecordingBandSchema).
|
|
3336
|
+
bands: zod.z.array(RecordingBandSchema).default([]),
|
|
3374
3337
|
retention: RecordingRetentionSchema.optional(),
|
|
3375
3338
|
/**
|
|
3376
3339
|
* Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
|
|
@@ -3378,8 +3341,15 @@ var RecordingConfigSchema = zod.z.object({
|
|
|
3378
3341
|
* windows only — existing sheets are immutable, and each window's index
|
|
3379
3342
|
* carries its own tile dims so mixed-preset history renders correctly.
|
|
3380
3343
|
*/
|
|
3381
|
-
scrubThumbnails: ScrubThumbnailPresetSchema.optional()
|
|
3382
|
-
|
|
3344
|
+
scrubThumbnails: ScrubThumbnailPresetSchema.optional(),
|
|
3345
|
+
/**
|
|
3346
|
+
* OPT-IN thumbnail-strip generation for this camera: every keyframe of the
|
|
3347
|
+
* low recording saved as a JPEG (the fast-drag scrub depth), a derived
|
|
3348
|
+
* cache that eviction reclaims with the footage. Absent/false = no strips
|
|
3349
|
+
* are written and scrub reads exact keyframes at every velocity.
|
|
3350
|
+
*/
|
|
3351
|
+
stripsEnabled: zod.z.boolean().optional()
|
|
3352
|
+
}).strict();
|
|
3383
3353
|
/**
|
|
3384
3354
|
* Ops-log — the durable, append-only operations audit shared by the
|
|
3385
3355
|
* recordings and events management surfaces.
|
|
@@ -3398,7 +3368,8 @@ var OpsLogOpSchema = zod.z.enum([
|
|
|
3398
3368
|
"prune",
|
|
3399
3369
|
"manual-delete",
|
|
3400
3370
|
"rescan",
|
|
3401
|
-
"retention-run"
|
|
3371
|
+
"retention-run",
|
|
3372
|
+
"relocate"
|
|
3402
3373
|
]);
|
|
3403
3374
|
/** Why the operation ran. */
|
|
3404
3375
|
var OpsLogReasonSchema = zod.z.enum([
|
|
@@ -3437,6 +3408,55 @@ var OpsLogQueryInputSchema = zod.z.object({
|
|
|
3437
3408
|
limit: zod.z.number().int().min(1).max(1e3).optional()
|
|
3438
3409
|
});
|
|
3439
3410
|
/**
|
|
3411
|
+
* Entity-relocation job state (storage entity-routing spec, Phase 4).
|
|
3412
|
+
*
|
|
3413
|
+
* One shape shared by the recorder's `relocateFootage` (segments + strips) and
|
|
3414
|
+
* pipeline-analytics' `relocateMedia` (event media blobs) so the admin Data
|
|
3415
|
+
* page renders both movers with one component. Jobs are in-RAM (a restart
|
|
3416
|
+
* forgets them — re-running is safe by construction: copy-if-absent, delete
|
|
3417
|
+
* after verify) and each completed/failed run also lands one durable ops-log
|
|
3418
|
+
* row on the owning addon's surface.
|
|
3419
|
+
*/
|
|
3420
|
+
var RelocateJobStateSchema = zod.z.enum([
|
|
3421
|
+
"running",
|
|
3422
|
+
"done",
|
|
3423
|
+
"failed",
|
|
3424
|
+
"cancelled"
|
|
3425
|
+
]);
|
|
3426
|
+
var RelocateJobSchema = zod.z.object({
|
|
3427
|
+
jobId: zod.z.string(),
|
|
3428
|
+
state: RelocateJobStateSchema,
|
|
3429
|
+
/** Source location — for media relocation this is informational ('*': rows
|
|
3430
|
+
* move from wherever they are to the target). */
|
|
3431
|
+
fromLocationId: zod.z.string(),
|
|
3432
|
+
toLocationId: zod.z.string(),
|
|
3433
|
+
/** Scoped device, or null = every device. */
|
|
3434
|
+
deviceId: zod.z.number().nullable(),
|
|
3435
|
+
/** What the job moves (owner-addon specific: segments/strips or media). */
|
|
3436
|
+
entities: zod.z.array(zod.z.string()),
|
|
3437
|
+
filesMoved: zod.z.number().int(),
|
|
3438
|
+
bytesMoved: zod.z.number().int(),
|
|
3439
|
+
/** Total files discovered up front; null while (or when) unknown. */
|
|
3440
|
+
filesTotal: zod.z.number().int().nullable(),
|
|
3441
|
+
startedAt: zod.z.number(),
|
|
3442
|
+
finishedAt: zod.z.number().nullable(),
|
|
3443
|
+
error: zod.z.string().nullable()
|
|
3444
|
+
});
|
|
3445
|
+
var RelocateFootageInputSchema = zod.z.object({
|
|
3446
|
+
deviceId: zod.z.number().optional(),
|
|
3447
|
+
fromLocationId: zod.z.string(),
|
|
3448
|
+
toLocationId: zod.z.string(),
|
|
3449
|
+
entities: zod.z.array(zod.z.enum(["segments", "strips"])).optional(),
|
|
3450
|
+
/** Copy throttle in MB/s (default 40) — the drain is a background chore,
|
|
3451
|
+
* never allowed to starve live writers. */
|
|
3452
|
+
throttleMbps: zod.z.number().min(1).max(1e3).optional()
|
|
3453
|
+
});
|
|
3454
|
+
var RelocateMediaInputSchema = zod.z.object({
|
|
3455
|
+
deviceId: zod.z.number().optional(),
|
|
3456
|
+
toLocationId: zod.z.string(),
|
|
3457
|
+
throttleMbps: zod.z.number().min(1).max(1e3).optional()
|
|
3458
|
+
});
|
|
3459
|
+
/**
|
|
3440
3460
|
* Severity ordering. Declared once here because it had already been re-declared
|
|
3441
3461
|
* three times independently (`kernel/transport/uds-logger.ts`,
|
|
3442
3462
|
* `builtins/loki-logging/loki-destination.ts`, and the log buffer) — four copies
|
|
@@ -3506,6 +3526,13 @@ var StorageLocationSchema = zod.z.object({
|
|
|
3506
3526
|
nodeId: zod.z.string().optional(),
|
|
3507
3527
|
isDefault: zod.z.boolean().default(false),
|
|
3508
3528
|
isSystem: zod.z.boolean().default(false),
|
|
3529
|
+
/** COMPUTED at read time by the orchestrator (statfs of the backing volume
|
|
3530
|
+
* for node-local locations it can reach) — never persisted, absent when the
|
|
3531
|
+
* volume is remote/unreachable. The single capacity truth every UI reads. */
|
|
3532
|
+
capacity: zod.z.object({
|
|
3533
|
+
totalBytes: zod.z.number(),
|
|
3534
|
+
availableBytes: zod.z.number()
|
|
3535
|
+
}).nullable().optional(),
|
|
3509
3536
|
createdAt: zod.z.number(),
|
|
3510
3537
|
updatedAt: zod.z.number()
|
|
3511
3538
|
});
|
|
@@ -3567,16 +3594,23 @@ var StorageLocationDeclarationSchema = zod.z.object({
|
|
|
3567
3594
|
* Which node root the seeded `<id>:default` instance is placed under on a
|
|
3568
3595
|
* FRESH install:
|
|
3569
3596
|
* - `'data'` (default) — the node's data dir (`CAMSTACK_DATA` / boot dir),
|
|
3570
|
-
* the appData volume. Right for small/durable data (
|
|
3597
|
+
* the appData volume. Right for small/durable data (logs, models).
|
|
3571
3598
|
* - `'media'` — the dedicated media volume (`CAMSTACK_MEDIA_ROOT`) when that
|
|
3572
3599
|
* env is set, else falls back to the data root. Right for bulky, hot media
|
|
3573
3600
|
* (recordings, event media) that should stay off the appData disk.
|
|
3601
|
+
* - `'backup'` — the dedicated backup volume (`CAMSTACK_BACKUP_ROOT`, default
|
|
3602
|
+
* `/backups` in the image) so archives live on their own mount rather than
|
|
3603
|
+
* filling the appData disk. Falls back to the data root when unset.
|
|
3574
3604
|
*
|
|
3575
3605
|
* Only affects the seeded default's `basePath`; operators can repoint any
|
|
3576
3606
|
* location afterwards, and a `defaultsTo` slot inherits its parent's root
|
|
3577
3607
|
* regardless of this field. Absent (the common case) is treated as `'data'`.
|
|
3578
3608
|
*/
|
|
3579
|
-
defaultRoot: zod.z.enum([
|
|
3609
|
+
defaultRoot: zod.z.enum([
|
|
3610
|
+
"data",
|
|
3611
|
+
"media",
|
|
3612
|
+
"backup"
|
|
3613
|
+
]).optional()
|
|
3580
3614
|
});
|
|
3581
3615
|
/** Friendly display labels for stream quality IDs. */
|
|
3582
3616
|
var STREAM_QUALITY_LABELS = {
|
|
@@ -4327,7 +4361,8 @@ var NcTaxonomyEntrySchema = zod.z.object({
|
|
|
4327
4361
|
/** Macro/category parent for grouping ('car' → 'vehicle'); null for a top. */
|
|
4328
4362
|
parentKind: zod.z.string().nullable()
|
|
4329
4363
|
});
|
|
4330
|
-
|
|
4364
|
+
/** The complete NC picker taxonomy — three grouped buckets. */
|
|
4365
|
+
var NcTaxonomySchema = zod.z.object({
|
|
4331
4366
|
videoClasses: zod.z.array(NcTaxonomyEntrySchema),
|
|
4332
4367
|
audioKinds: zod.z.array(NcTaxonomyEntrySchema),
|
|
4333
4368
|
labels: zod.z.array(NcTaxonomyEntrySchema)
|
|
@@ -5128,6 +5163,7 @@ var AccessoryKind = {
|
|
|
5128
5163
|
};
|
|
5129
5164
|
AccessoryKind.Siren, AccessoryKind.Floodlight, AccessoryKind.Spotlight, AccessoryKind.PirSensor, AccessoryKind.Chime, AccessoryKind.Autotrack, AccessoryKind.Nightvision, AccessoryKind.PrivacyMask;
|
|
5130
5165
|
DeviceFeature.BatteryOperated;
|
|
5166
|
+
new Set(["devices", "classes"]);
|
|
5131
5167
|
/**
|
|
5132
5168
|
* Shared geometry vocabulary for on-frame shape caps — privacy-mask,
|
|
5133
5169
|
* motion-zones, and the detection zones/lines editor all speak this one
|
|
@@ -5448,12 +5484,60 @@ var NcRuleTargetSchema = zod.z.object({
|
|
|
5448
5484
|
* - `keyFrame` — the clean scene frame (no subject box).
|
|
5449
5485
|
* - `none` — no attachment.
|
|
5450
5486
|
*/
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5487
|
+
/**
|
|
5488
|
+
* WHAT THE PICTURE SHOWS — chosen explicitly, because the implicit ladders
|
|
5489
|
+
* conflate it with the selection strategy and betray the request: asking for
|
|
5490
|
+
* the clean scene frame on an object-event owner used to start at
|
|
5491
|
+
* `fullFrameBoxed`, i.e. the annotated frame (2026-07-30).
|
|
5492
|
+
* - `cropped` — the subject, tight. What "who is at the door" wants.
|
|
5493
|
+
* - `full` — the clean scene, no annotation. What "what is going on" wants.
|
|
5494
|
+
* - `boxed` — the scene WITH the detection boxes drawn, for verifying what
|
|
5495
|
+
* the pipeline actually saw.
|
|
5496
|
+
*/
|
|
5497
|
+
var NcMediaFrameSchema = zod.z.enum([
|
|
5498
|
+
"cropped",
|
|
5499
|
+
"full",
|
|
5500
|
+
"boxed"
|
|
5501
|
+
]);
|
|
5502
|
+
var NcMediaPolicySchema = zod.z.object({
|
|
5503
|
+
attach: zod.z.enum([
|
|
5504
|
+
"best",
|
|
5505
|
+
"best-matching",
|
|
5506
|
+
"keyFrame",
|
|
5507
|
+
"none"
|
|
5508
|
+
]).default("best"),
|
|
5509
|
+
/** What the still shows. Absent = `cropped` (the historical `best` shape). */
|
|
5510
|
+
frame: NcMediaFrameSchema.optional(),
|
|
5511
|
+
/** Crop the attached still to the rule's condition-zone bbox (padded) —
|
|
5512
|
+
* "show me the ZONE", not the whole scene or the subject crop. */
|
|
5513
|
+
zoneCrop: zod.z.boolean().optional(),
|
|
5514
|
+
/**
|
|
5515
|
+
* Also attach a short GIF cut from the stream broker's clip ring around the
|
|
5516
|
+
* event — NOT from the recording, so the camera does not have to be
|
|
5517
|
+
* recording, and the window sits AROUND the moment instead of a segment
|
|
5518
|
+
* behind it. Fail-closed: a window the ring does not cover contributes no
|
|
5519
|
+
* gif, never a failed notification.
|
|
5520
|
+
*/
|
|
5521
|
+
gif: zod.z.boolean().optional(),
|
|
5522
|
+
/**
|
|
5523
|
+
* Also attach a short MP4 CLIP of the same cut. Same source and the same
|
|
5524
|
+
* fail-closed rule as `gif`. Prefer it where the backend takes video
|
|
5525
|
+
* (telegram, discord, zentik, webhook); backends that do not are handled by
|
|
5526
|
+
* the degrade engine, which drops the video and keeps the still.
|
|
5527
|
+
*/
|
|
5528
|
+
clip: zod.z.boolean().optional(),
|
|
5529
|
+
/** Seconds of footage BEFORE / AFTER the event instant. Defaults 3 / 7. */
|
|
5530
|
+
clipPreRollSec: zod.z.number().int().min(0).max(30).optional(),
|
|
5531
|
+
clipPostRollSec: zod.z.number().int().min(0).max(30).optional(),
|
|
5532
|
+
/**
|
|
5533
|
+
* Which stream profile the footage is cut from. Absent = the CHEAPEST
|
|
5534
|
+
* assigned profile: a notification is watched on a phone, so the 4K
|
|
5535
|
+
* rendition would burn CPU to produce a file the client downscales anyway.
|
|
5536
|
+
* A profile that is not assigned falls back to the cheapest, and the render
|
|
5537
|
+
* reports which one actually ran.
|
|
5538
|
+
*/
|
|
5539
|
+
profile: CamProfileSchema.optional()
|
|
5540
|
+
});
|
|
5457
5541
|
/** Throttle — cooldown survives restarts (rebuilt from the outbox on boot). */
|
|
5458
5542
|
var NcThrottleSchema = zod.z.object({
|
|
5459
5543
|
cooldownSec: zod.z.number().int().min(0).max(86400).default(60),
|
|
@@ -5467,7 +5551,19 @@ var NcRuleInputSchema = zod.z.object({
|
|
|
5467
5551
|
delivery: NcDeliverySchema,
|
|
5468
5552
|
conditions: NcConditionsSchema.default({}),
|
|
5469
5553
|
schedule: NcScheduleSchema.optional(),
|
|
5470
|
-
|
|
5554
|
+
/** May be empty when `targetUsers` addresses at least one user — the
|
|
5555
|
+
* "at least one addressee" invariant is enforced by the provider, because
|
|
5556
|
+
* a cross-field refine here would break `NcRulePatchSchema.partial()`. */
|
|
5557
|
+
targets: zod.z.array(NcRuleTargetSchema),
|
|
5558
|
+
/**
|
|
5559
|
+
* USERS this rule addresses in addition to `targets` (Phase 4). At fire
|
|
5560
|
+
* time each user fans out to the personal targets they own
|
|
5561
|
+
* (`config.ownerUserId`), filtered by that user's `allowedDevices` for the
|
|
5562
|
+
* firing camera — a user is never notified about a device they cannot open.
|
|
5563
|
+
* Per-user opt-outs (`disabledTargetIds`) still apply to the fanned-out
|
|
5564
|
+
* targets.
|
|
5565
|
+
*/
|
|
5566
|
+
targetUsers: zod.z.array(zod.z.string()).optional(),
|
|
5471
5567
|
media: NcMediaPolicySchema.default({ attach: "best" }),
|
|
5472
5568
|
throttle: NcThrottleSchema.default({
|
|
5473
5569
|
cooldownSec: 60,
|
|
@@ -5697,7 +5793,20 @@ var notificationRulesCapability = {
|
|
|
5697
5793
|
kind: "mutation",
|
|
5698
5794
|
auth: "admin"
|
|
5699
5795
|
}),
|
|
5700
|
-
|
|
5796
|
+
/**
|
|
5797
|
+
* The machine-readable condition surface a rule editor renders from, plus
|
|
5798
|
+
* the picker VOCABULARY those conditions draw on.
|
|
5799
|
+
*
|
|
5800
|
+
* `taxonomy` is optional so an older provider that only returns `catalog`
|
|
5801
|
+
* still validates; a client that receives none keeps free-text inputs.
|
|
5802
|
+
* It was previously served ONLY on the `nc.getConditionCatalog` bridge
|
|
5803
|
+
* action, which is why the viewer had grouped pickers and the admin UI —
|
|
5804
|
+
* which reaches this cap — was stuck typing `person` from memory.
|
|
5805
|
+
*/
|
|
5806
|
+
getConditionCatalog: method(zod.z.object({}), zod.z.object({
|
|
5807
|
+
catalog: zod.z.array(NcConditionDescriptorSchema),
|
|
5808
|
+
taxonomy: NcTaxonomySchema.optional()
|
|
5809
|
+
})),
|
|
5701
5810
|
/**
|
|
5702
5811
|
* Queryable delivery history — a read-only view over the durable outbox
|
|
5703
5812
|
* (fired rule, subject summary, target, status, timestamps, error on a
|
|
@@ -6745,6 +6854,48 @@ var streamBrokerCapability = {
|
|
|
6745
6854
|
kind: "mutation",
|
|
6746
6855
|
auth: "admin"
|
|
6747
6856
|
}),
|
|
6857
|
+
/**
|
|
6858
|
+
* Render a short GIF or MP4 from the broker's PRE-BUFFER around an instant.
|
|
6859
|
+
*
|
|
6860
|
+
* The pre-buffer is the only source that already holds the seconds BEFORE
|
|
6861
|
+
* an event (it is what it exists for — "when an addon needs the last N
|
|
6862
|
+
* seconds of video for clip creation"). Cutting from recorded segments
|
|
6863
|
+
* cannot: only finalized segments are addressable and the one covering the
|
|
6864
|
+
* moment is still being written, so a segment-sourced clip is either
|
|
6865
|
+
* delayed or shows the approach instead of the event (operator,
|
|
6866
|
+
* 2026-07-30). It also means a camera does not have to be RECORDING to
|
|
6867
|
+
* produce a notification clip.
|
|
6868
|
+
*
|
|
6869
|
+
* Returns muxed BYTES, never packets: the frame plane never crosses a
|
|
6870
|
+
* process boundary at frame rate (D9/D18) — this is one compressed,
|
|
6871
|
+
* on-demand payload per notification.
|
|
6872
|
+
*
|
|
6873
|
+
* Waits up to `postRollSec` for the tail to accumulate, so the window is
|
|
6874
|
+
* CENTRED on `aroundMs`.
|
|
6875
|
+
*/
|
|
6876
|
+
renderPreBufferClip: method(zod.z.object({
|
|
6877
|
+
deviceId: zod.z.number(),
|
|
6878
|
+
/** Absent = the LOWEST assigned profile — a notification attachment is
|
|
6879
|
+
* watched on a phone, and the cheap rendition is the right default. */
|
|
6880
|
+
profile: CamProfileSchema.optional(),
|
|
6881
|
+
aroundMs: zod.z.number(),
|
|
6882
|
+
preRollSec: zod.z.number().min(0).max(20).default(3),
|
|
6883
|
+
postRollSec: zod.z.number().min(0).max(20).default(5),
|
|
6884
|
+
format: zod.z.enum(["gif", "mp4"]).default("gif"),
|
|
6885
|
+
maxWidth: zod.z.number().int().min(120).max(1920).default(480),
|
|
6886
|
+
/** GIF only — MP4 keeps the source cadence. */
|
|
6887
|
+
fps: zod.z.number().int().min(1).max(15).default(5)
|
|
6888
|
+
}), zod.z.object({
|
|
6889
|
+
base64: zod.z.string(),
|
|
6890
|
+
mime: zod.z.string(),
|
|
6891
|
+
bytes: zod.z.number().int(),
|
|
6892
|
+
/** The profile actually rendered (what the default resolved to). */
|
|
6893
|
+
profile: CamProfileSchema,
|
|
6894
|
+
durationMs: zod.z.number()
|
|
6895
|
+
}), {
|
|
6896
|
+
kind: "mutation",
|
|
6897
|
+
auth: "admin"
|
|
6898
|
+
}),
|
|
6748
6899
|
listAllCameraStreams: method(zod.z.void(), zod.z.array(CameraStreamSchema).readonly()),
|
|
6749
6900
|
listAllProfileSlots: method(zod.z.void(), zod.z.array(ProfileSlotSchema).readonly()),
|
|
6750
6901
|
getBrokerStats: method(zod.z.object({ brokerId: zod.z.string() }), BrokerStatsSchema),
|
|
@@ -13573,6 +13724,41 @@ var LocationStatSchema = zod.z.object({
|
|
|
13573
13724
|
present: zod.z.boolean()
|
|
13574
13725
|
});
|
|
13575
13726
|
/**
|
|
13727
|
+
* A backup schedule — the N:M "entry" that binds one cron cadence to a
|
|
13728
|
+
* SET of destination locations. Supersedes the per-location cron on
|
|
13729
|
+
* `BackupDestinationPolicy`: an operator creates a schedule, picks the
|
|
13730
|
+
* `backups` locations it should write to, and the orchestrator fans a
|
|
13731
|
+
* single archive out to all of them when the cron fires.
|
|
13732
|
+
*
|
|
13733
|
+
* `retentionCount` is per-schedule (D-decision 2026-07-28): every
|
|
13734
|
+
* location targeted by this schedule keeps this many archives from
|
|
13735
|
+
* this schedule's runs.
|
|
13736
|
+
*
|
|
13737
|
+
* `dataSources` optionally narrows which top-level state locations
|
|
13738
|
+
* (db, addons, tls, …) are archived; omitted = the orchestrator's
|
|
13739
|
+
* default full set.
|
|
13740
|
+
*/
|
|
13741
|
+
var BackupScheduleSchema = zod.z.object({
|
|
13742
|
+
/** Stable id. Generated by the orchestrator on first upsert if absent. */
|
|
13743
|
+
id: zod.z.string(),
|
|
13744
|
+
/** Operator-facing display name. */
|
|
13745
|
+
label: zod.z.string(),
|
|
13746
|
+
/** 5-field POSIX cron. Empty = disabled cadence (kept for editing). */
|
|
13747
|
+
cron: zod.z.string(),
|
|
13748
|
+
/** Master on/off toggle for the whole schedule. */
|
|
13749
|
+
enabled: zod.z.boolean(),
|
|
13750
|
+
/** `backups`-location ids this schedule writes to (fan-out set). */
|
|
13751
|
+
locationIds: zod.z.array(zod.z.string()).readonly(),
|
|
13752
|
+
/** Archives kept per targeted location for this schedule. */
|
|
13753
|
+
retentionCount: zod.z.number().int().min(1).max(1e3),
|
|
13754
|
+
/** Optional subset of source locations to include; omitted = all. */
|
|
13755
|
+
dataSources: zod.z.array(zod.z.string()).readonly().optional(),
|
|
13756
|
+
/** ms-epoch of last successful run. */
|
|
13757
|
+
lastRunAt: zod.z.number().optional(),
|
|
13758
|
+
/** ms-epoch of next computed firing (read-only, filled on list). */
|
|
13759
|
+
nextRunAt: zod.z.number().optional()
|
|
13760
|
+
});
|
|
13761
|
+
/**
|
|
13576
13762
|
* backup — singleton capability for backup management.
|
|
13577
13763
|
*
|
|
13578
13764
|
* Implemented by `local-backup` addon. Future providers (S3, rsync)
|
|
@@ -13599,7 +13785,14 @@ var backupCapability = {
|
|
|
13599
13785
|
/** Subset of registered `backup-destination` addon ids to write to. */
|
|
13600
13786
|
destinations: zod.z.array(zod.z.string()).optional(),
|
|
13601
13787
|
locations: zod.z.array(zod.z.string()).optional(),
|
|
13602
|
-
label: zod.z.string().optional()
|
|
13788
|
+
label: zod.z.string().optional(),
|
|
13789
|
+
/**
|
|
13790
|
+
* Per-run retention override applied to every targeted
|
|
13791
|
+
* destination. Used by schedule-driven runs (per-entry
|
|
13792
|
+
* retention). Omitted = each destination's own policy
|
|
13793
|
+
* retention (manual runs).
|
|
13794
|
+
*/
|
|
13795
|
+
retentionCount: zod.z.number().int().min(1).max(1e3).optional()
|
|
13603
13796
|
}).optional(), zod.z.array(BackupEntrySchema).readonly(), {
|
|
13604
13797
|
kind: "mutation",
|
|
13605
13798
|
auth: "admin"
|
|
@@ -13686,7 +13879,36 @@ var backupCapability = {
|
|
|
13686
13879
|
ok: zod.z.boolean(),
|
|
13687
13880
|
error: zod.z.string().optional(),
|
|
13688
13881
|
nextRuns: zod.z.array(zod.z.number()).readonly()
|
|
13689
|
-
}))
|
|
13882
|
+
})),
|
|
13883
|
+
/**
|
|
13884
|
+
* List every backup schedule (the N:M entries), each with its
|
|
13885
|
+
* computed `nextRunAt`. Powers the Schedules section of the
|
|
13886
|
+
* admin-UI Backups page.
|
|
13887
|
+
*/
|
|
13888
|
+
listSchedules: method(zod.z.void(), zod.z.array(BackupScheduleSchema).readonly(), { auth: "admin" }),
|
|
13889
|
+
/**
|
|
13890
|
+
* Create or replace a schedule. An empty / absent `id` mints a new
|
|
13891
|
+
* one; a present `id` replaces in place. `cron` is validated
|
|
13892
|
+
* server-side; `locationIds` must reference existing `backups`
|
|
13893
|
+
* locations (unknown ids are dropped with a warning).
|
|
13894
|
+
*/
|
|
13895
|
+
upsertSchedule: method(zod.z.object({
|
|
13896
|
+
id: zod.z.string().optional(),
|
|
13897
|
+
label: zod.z.string(),
|
|
13898
|
+
cron: zod.z.string(),
|
|
13899
|
+
enabled: zod.z.boolean(),
|
|
13900
|
+
locationIds: zod.z.array(zod.z.string()).readonly(),
|
|
13901
|
+
retentionCount: zod.z.number().int().min(1).max(1e3),
|
|
13902
|
+
dataSources: zod.z.array(zod.z.string()).readonly().optional()
|
|
13903
|
+
}), BackupScheduleSchema, {
|
|
13904
|
+
kind: "mutation",
|
|
13905
|
+
auth: "admin"
|
|
13906
|
+
}),
|
|
13907
|
+
/** Delete a schedule by id. Does not touch the target locations. */
|
|
13908
|
+
deleteSchedule: method(zod.z.object({ id: zod.z.string() }), zod.z.void(), {
|
|
13909
|
+
kind: "mutation",
|
|
13910
|
+
auth: "admin"
|
|
13911
|
+
})
|
|
13690
13912
|
}
|
|
13691
13913
|
};
|
|
13692
13914
|
/**
|
|
@@ -16680,6 +16902,36 @@ var TargetKindSchema = zod.z.object({
|
|
|
16680
16902
|
icon: zod.z.string(),
|
|
16681
16903
|
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
16682
16904
|
addonId: zod.z.string(),
|
|
16905
|
+
/**
|
|
16906
|
+
* URL of the kind's bundled BRAND icon, served by the providing addon over
|
|
16907
|
+
* its own `addon-routes` surface (`/addon/<addonId>/icons/<kind>`). Absent
|
|
16908
|
+
* when the addon bundles no icon for that kind — the client then falls back
|
|
16909
|
+
* to a neutral glyph rather than rendering the raw `icon` NAME as text.
|
|
16910
|
+
*
|
|
16911
|
+
* Root-relative on purpose: it resolves against whatever origin serves a web
|
|
16912
|
+
* client, and a native client joins it onto its own hub base.
|
|
16913
|
+
*
|
|
16914
|
+
* DECLARED here deliberately. It used to travel as an undeclared passthrough
|
|
16915
|
+
* field that survived only because the runtime cap-router forwards provider
|
|
16916
|
+
* output verbatim — so every consumer had to re-declare it by hand to stop
|
|
16917
|
+
* its own Zod parse from stripping it, and the whole arrangement would have
|
|
16918
|
+
* broken silently the moment output validation was tightened anywhere.
|
|
16919
|
+
*/
|
|
16920
|
+
iconUrl: zod.z.string().optional(),
|
|
16921
|
+
/**
|
|
16922
|
+
* Media type of {@link iconUrl} (`image/svg+xml`, `image/png`, …).
|
|
16923
|
+
*
|
|
16924
|
+
* The server knows this and therefore says it, because the client cannot
|
|
16925
|
+
* safely guess: a React-Native client renders SVG and raster through two
|
|
16926
|
+
* DIFFERENT components (`react-native-svg` vs `expo-image` — expo-image does
|
|
16927
|
+
* not decode SVG on iOS/Android), so without this it silently fell back to a
|
|
16928
|
+
* placeholder glyph for every vector icon while the web build looked fine.
|
|
16929
|
+
*
|
|
16930
|
+
* Absent when {@link iconUrl} is absent, or for a legacy provider that has
|
|
16931
|
+
* not been updated — a client that cannot determine the type should prefer
|
|
16932
|
+
* its raster path, which is the safe default for an unknown image.
|
|
16933
|
+
*/
|
|
16934
|
+
iconMediaType: zod.z.string().optional(),
|
|
16683
16935
|
configSchema: ConfigSchemaPassthrough,
|
|
16684
16936
|
supportsDiscovery: zod.z.boolean(),
|
|
16685
16937
|
caps: TargetKindCapsSchema
|
|
@@ -17552,6 +17804,23 @@ var pipelineAnalyticsCapability = {
|
|
|
17552
17804
|
}),
|
|
17553
17805
|
/** The events ops-log rows (newest-first), optionally scoped to one camera.
|
|
17554
17806
|
* Backed by a declared pipeline-analytics SQLite collection. */
|
|
17807
|
+
/**
|
|
17808
|
+
* Move event-media blobs onto `toLocationId` (entity-routing spec Phase
|
|
17809
|
+
* 4): per-row copy → stamp row.locationId → delete old blob. Rows already
|
|
17810
|
+
* at the target are skipped, so a re-run resumes. Single-flight.
|
|
17811
|
+
*/
|
|
17812
|
+
relocateMedia: method(RelocateMediaInputSchema, zod.z.object({ jobId: zod.z.string() }), {
|
|
17813
|
+
kind: "mutation",
|
|
17814
|
+
auth: "admin"
|
|
17815
|
+
}),
|
|
17816
|
+
getMediaRelocateStatus: method(zod.z.object({}), zod.z.array(RelocateJobSchema).readonly(), {
|
|
17817
|
+
kind: "query",
|
|
17818
|
+
auth: "admin"
|
|
17819
|
+
}),
|
|
17820
|
+
cancelMediaRelocate: method(zod.z.object({ jobId: zod.z.string() }), zod.z.object({ cancelled: zod.z.boolean() }), {
|
|
17821
|
+
kind: "mutation",
|
|
17822
|
+
auth: "admin"
|
|
17823
|
+
}),
|
|
17555
17824
|
listOpsLog: method(OpsLogQueryInputSchema, zod.z.array(OpsLogEntrySchema).readonly(), {
|
|
17556
17825
|
kind: "query",
|
|
17557
17826
|
auth: "admin"
|
|
@@ -21109,6 +21378,17 @@ var ConnectionEndpointSchema = zod.z.object({
|
|
|
21109
21378
|
priority: zod.z.number()
|
|
21110
21379
|
});
|
|
21111
21380
|
var GetConnectionEndpointsResultSchema = zod.z.object({ endpoints: zod.z.array(ConnectionEndpointSchema).readonly() });
|
|
21381
|
+
/**
|
|
21382
|
+
* The chosen outbound endpoint for notification artifacts. `baseUrl: null` =
|
|
21383
|
+
* AUTO (resolved from the candidate ranking at send time); `resolved` reports
|
|
21384
|
+
* what AUTO currently picks, so the UI can show the effective value either way.
|
|
21385
|
+
*/
|
|
21386
|
+
var NotificationEndpointSchema = zod.z.object({
|
|
21387
|
+
/** The operator's explicit choice, or null for AUTO. */
|
|
21388
|
+
baseUrl: zod.z.string().nullable(),
|
|
21389
|
+
/** What the ranking currently resolves to (null when nothing is reachable). */
|
|
21390
|
+
resolved: zod.z.string().nullable()
|
|
21391
|
+
});
|
|
21112
21392
|
var AllowedAddressesSchema = zod.z.object({
|
|
21113
21393
|
/**
|
|
21114
21394
|
* Allowlist of interface addresses operators have explicitly opted
|
|
@@ -21160,6 +21440,26 @@ var localNetworkCapability = {
|
|
|
21160
21440
|
scheme: zod.z.enum(["http", "https"]).optional()
|
|
21161
21441
|
}), GetConnectionEndpointsResultSchema),
|
|
21162
21442
|
/**
|
|
21443
|
+
* The endpoint OUTBOUND artifacts must be addressed by — notification
|
|
21444
|
+
* attachment links and deep links. `baseUrl: null` means AUTO: the first
|
|
21445
|
+
* public candidate (a configured origin, then a connected tunnel, then the
|
|
21446
|
+
* LAN), never loopback.
|
|
21447
|
+
*
|
|
21448
|
+
* Why an explicit marker: the automatic ranking cannot know which of
|
|
21449
|
+
* several reachable addresses the RECIPIENT can actually open. A link is
|
|
21450
|
+
* consumed on someone's phone, off the LAN, possibly hours later — and a
|
|
21451
|
+
* link nobody can open is worse than no link, because the notification
|
|
21452
|
+
* arrives advertising media that 404s.
|
|
21453
|
+
*/
|
|
21454
|
+
getNotificationEndpoint: method(zod.z.void(), NotificationEndpointSchema),
|
|
21455
|
+
/**
|
|
21456
|
+
* Mark which endpoint notification artifacts use. `baseUrl: null` restores
|
|
21457
|
+
* AUTO. The value is stored verbatim (not an index into the candidate
|
|
21458
|
+
* list): interfaces come and go, and an index would silently re-point at a
|
|
21459
|
+
* different address after a reboot.
|
|
21460
|
+
*/
|
|
21461
|
+
setNotificationEndpoint: method(zod.z.object({ baseUrl: zod.z.string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }),
|
|
21462
|
+
/**
|
|
21163
21463
|
* Read the operator's allowlist. Empty = "auto" (no filter). Used
|
|
21164
21464
|
* by the admin UI's address selector to seed its checkbox state.
|
|
21165
21465
|
*/
|
|
@@ -22253,7 +22553,12 @@ var RecordingDeviceUsageSchema = zod.z.object({
|
|
|
22253
22553
|
var RecordingLocationUsageSchema = zod.z.object({
|
|
22254
22554
|
/** StorageLocation id; null for the legacy/degraded single-root fallback. */
|
|
22255
22555
|
locationId: zod.z.string().nullable(),
|
|
22256
|
-
/**
|
|
22556
|
+
/** Every location id sharing this row's PHYSICAL volume (aliases). One row
|
|
22557
|
+
* is emitted per physical disk (2026-07-29): two locations on one root
|
|
22558
|
+
* previously rendered as two identical "disks" with a nonsensical used
|
|
22559
|
+
* split — hydrate attribution across aliases is arbitrary by nature. */
|
|
22560
|
+
locationIds: zod.z.array(zod.z.string()).optional(),
|
|
22561
|
+
/** Bytes of recordings stored on this PHYSICAL volume (all aliases). */
|
|
22257
22562
|
usedBytes: zod.z.number(),
|
|
22258
22563
|
/** Free bytes on the location's volume; null when capacity is unknown (remote). */
|
|
22259
22564
|
availableBytes: zod.z.number().nullable(),
|
|
@@ -22409,6 +22714,77 @@ var recordingCapability = {
|
|
|
22409
22714
|
listOpsLog: method(OpsLogQueryInputSchema, zod.z.array(OpsLogEntrySchema).readonly(), {
|
|
22410
22715
|
kind: "query",
|
|
22411
22716
|
auth: "admin"
|
|
22717
|
+
}),
|
|
22718
|
+
/**
|
|
22719
|
+
* Move footage (segments and/or strips) from one recordings location to
|
|
22720
|
+
* another — the drain workflow's mover (entity-routing spec Phase 4).
|
|
22721
|
+
* Throttled copy → size-verify → delete source → index refresh; resumable
|
|
22722
|
+
* by construction (copy-if-absent). Single-flight: one job at a time.
|
|
22723
|
+
*/
|
|
22724
|
+
/**
|
|
22725
|
+
* Render a short GIF from recorded footage around `aroundMs` (low profile,
|
|
22726
|
+
* palette-free ffmpeg gif). Synchronous — the window is a few seconds of
|
|
22727
|
+
* `low`, rendering in ~1-2s. Built for notification attachments: the
|
|
22728
|
+
* caller gets bytes, nothing persists. Fails when no footage covers the
|
|
22729
|
+
* window (camera not recording → caller skips the attachment).
|
|
22730
|
+
*/
|
|
22731
|
+
renderGif: method(zod.z.object({
|
|
22732
|
+
deviceId: zod.z.number(),
|
|
22733
|
+
aroundMs: zod.z.number(),
|
|
22734
|
+
preRollSec: zod.z.number().min(0).max(30).default(2),
|
|
22735
|
+
postRollSec: zod.z.number().min(0).max(30).default(5),
|
|
22736
|
+
maxWidth: zod.z.number().int().min(120).max(1280).default(480),
|
|
22737
|
+
fps: zod.z.number().int().min(1).max(15).default(5)
|
|
22738
|
+
}), zod.z.object({
|
|
22739
|
+
gifBase64: zod.z.string(),
|
|
22740
|
+
fromMs: zod.z.number(),
|
|
22741
|
+
toMs: zod.z.number()
|
|
22742
|
+
}), {
|
|
22743
|
+
kind: "mutation",
|
|
22744
|
+
auth: "admin"
|
|
22745
|
+
}),
|
|
22746
|
+
/**
|
|
22747
|
+
* Render a short MP4 clip from recorded footage around `aroundMs` — the
|
|
22748
|
+
* "send a clip, not a gif" notification attachment. Same window, source
|
|
22749
|
+
* and fail-closed contract as {@link renderGif}: no footage covering the
|
|
22750
|
+
* window ⇒ it throws and the caller ships no attachment. Re-encoded (never
|
|
22751
|
+
* stream-copied) so a concat across segments with different encoder
|
|
22752
|
+
* parameters still plays. Silent by contract.
|
|
22753
|
+
*
|
|
22754
|
+
* The returned window is SEGMENT-GRANULAR: the source playlist is built
|
|
22755
|
+
* from whole segments, so the clip starts at or before `fromMs` and ends
|
|
22756
|
+
* at or after `toMs` — overshoot bounded by one segment per side (an 8 s
|
|
22757
|
+
* ask over 4 s segments measured 12 s). `fromMs`/`toMs` report the window
|
|
22758
|
+
* ASKED for, not the encoded duration.
|
|
22759
|
+
*/
|
|
22760
|
+
renderClip: method(zod.z.object({
|
|
22761
|
+
deviceId: zod.z.number(),
|
|
22762
|
+
aroundMs: zod.z.number(),
|
|
22763
|
+
preRollSec: zod.z.number().min(0).max(30).default(3),
|
|
22764
|
+
postRollSec: zod.z.number().min(0).max(30).default(7),
|
|
22765
|
+
maxWidth: zod.z.number().int().min(160).max(1920).default(640)
|
|
22766
|
+
}), zod.z.object({
|
|
22767
|
+
clipBase64: zod.z.string(),
|
|
22768
|
+
mime: zod.z.string(),
|
|
22769
|
+
fromMs: zod.z.number(),
|
|
22770
|
+
toMs: zod.z.number(),
|
|
22771
|
+
bytes: zod.z.number().int()
|
|
22772
|
+
}), {
|
|
22773
|
+
kind: "mutation",
|
|
22774
|
+
auth: "admin"
|
|
22775
|
+
}),
|
|
22776
|
+
relocateFootage: method(RelocateFootageInputSchema, zod.z.object({ jobId: zod.z.string() }), {
|
|
22777
|
+
kind: "mutation",
|
|
22778
|
+
auth: "admin"
|
|
22779
|
+
}),
|
|
22780
|
+
/** Every known relocate job (in-RAM, newest-first). */
|
|
22781
|
+
getRelocateStatus: method(zod.z.object({}), zod.z.array(RelocateJobSchema).readonly(), {
|
|
22782
|
+
kind: "query",
|
|
22783
|
+
auth: "admin"
|
|
22784
|
+
}),
|
|
22785
|
+
cancelRelocate: method(zod.z.object({ jobId: zod.z.string() }), zod.z.object({ cancelled: zod.z.boolean() }), {
|
|
22786
|
+
kind: "mutation",
|
|
22787
|
+
auth: "admin"
|
|
22412
22788
|
})
|
|
22413
22789
|
}
|
|
22414
22790
|
};
|
|
@@ -23904,6 +24280,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
23904
24280
|
addonId: null,
|
|
23905
24281
|
access: "delete"
|
|
23906
24282
|
},
|
|
24283
|
+
"backup.deleteSchedule": {
|
|
24284
|
+
capName: "backup",
|
|
24285
|
+
capScope: "system",
|
|
24286
|
+
addonId: null,
|
|
24287
|
+
access: "delete"
|
|
24288
|
+
},
|
|
23907
24289
|
"backup.getEntries": {
|
|
23908
24290
|
capName: "backup",
|
|
23909
24291
|
capScope: "system",
|
|
@@ -23934,6 +24316,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
23934
24316
|
addonId: null,
|
|
23935
24317
|
access: "view"
|
|
23936
24318
|
},
|
|
24319
|
+
"backup.listSchedules": {
|
|
24320
|
+
capName: "backup",
|
|
24321
|
+
capScope: "system",
|
|
24322
|
+
addonId: null,
|
|
24323
|
+
access: "view"
|
|
24324
|
+
},
|
|
23937
24325
|
"backup.previewSchedule": {
|
|
23938
24326
|
capName: "backup",
|
|
23939
24327
|
capScope: "system",
|
|
@@ -23958,6 +24346,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
23958
24346
|
addonId: null,
|
|
23959
24347
|
access: "create"
|
|
23960
24348
|
},
|
|
24349
|
+
"backup.upsertSchedule": {
|
|
24350
|
+
capName: "backup",
|
|
24351
|
+
capScope: "system",
|
|
24352
|
+
addonId: null,
|
|
24353
|
+
access: "create"
|
|
24354
|
+
},
|
|
23961
24355
|
"battery.wakeForStream": {
|
|
23962
24356
|
capName: "battery",
|
|
23963
24357
|
capScope: "device",
|
|
@@ -25458,6 +25852,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
25458
25852
|
addonId: null,
|
|
25459
25853
|
access: "view"
|
|
25460
25854
|
},
|
|
25855
|
+
"localNetwork.getNotificationEndpoint": {
|
|
25856
|
+
capName: "local-network",
|
|
25857
|
+
capScope: "system",
|
|
25858
|
+
addonId: null,
|
|
25859
|
+
access: "view"
|
|
25860
|
+
},
|
|
25461
25861
|
"localNetwork.getPreferred": {
|
|
25462
25862
|
capName: "local-network",
|
|
25463
25863
|
capScope: "system",
|
|
@@ -25482,6 +25882,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
25482
25882
|
addonId: null,
|
|
25483
25883
|
access: "create"
|
|
25484
25884
|
},
|
|
25885
|
+
"localNetwork.setNotificationEndpoint": {
|
|
25886
|
+
capName: "local-network",
|
|
25887
|
+
capScope: "system",
|
|
25888
|
+
addonId: null,
|
|
25889
|
+
access: "create"
|
|
25890
|
+
},
|
|
25485
25891
|
"lockControl.lock": {
|
|
25486
25892
|
capName: "lock-control",
|
|
25487
25893
|
capScope: "device",
|
|
@@ -26124,6 +26530,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
26124
26530
|
addonId: null,
|
|
26125
26531
|
access: "create"
|
|
26126
26532
|
},
|
|
26533
|
+
"pipelineAnalytics.cancelMediaRelocate": {
|
|
26534
|
+
capName: "pipeline-analytics",
|
|
26535
|
+
capScope: "device",
|
|
26536
|
+
addonId: null,
|
|
26537
|
+
access: "create"
|
|
26538
|
+
},
|
|
26127
26539
|
"pipelineAnalytics.clearTracks": {
|
|
26128
26540
|
capName: "pipeline-analytics",
|
|
26129
26541
|
capScope: "device",
|
|
@@ -26178,6 +26590,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
26178
26590
|
addonId: null,
|
|
26179
26591
|
access: "view"
|
|
26180
26592
|
},
|
|
26593
|
+
"pipelineAnalytics.getMediaRelocateStatus": {
|
|
26594
|
+
capName: "pipeline-analytics",
|
|
26595
|
+
capScope: "device",
|
|
26596
|
+
addonId: null,
|
|
26597
|
+
access: "view"
|
|
26598
|
+
},
|
|
26181
26599
|
"pipelineAnalytics.getMotionEvents": {
|
|
26182
26600
|
capName: "pipeline-analytics",
|
|
26183
26601
|
capScope: "device",
|
|
@@ -26250,6 +26668,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
26250
26668
|
addonId: null,
|
|
26251
26669
|
access: "create"
|
|
26252
26670
|
},
|
|
26671
|
+
"pipelineAnalytics.relocateMedia": {
|
|
26672
|
+
capName: "pipeline-analytics",
|
|
26673
|
+
capScope: "device",
|
|
26674
|
+
addonId: null,
|
|
26675
|
+
access: "create"
|
|
26676
|
+
},
|
|
26253
26677
|
"pipelineAnalytics.searchObjectEvents": {
|
|
26254
26678
|
capName: "pipeline-analytics",
|
|
26255
26679
|
capScope: "device",
|
|
@@ -27012,6 +27436,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
27012
27436
|
addonId: null,
|
|
27013
27437
|
access: "create"
|
|
27014
27438
|
},
|
|
27439
|
+
"recording.cancelRelocate": {
|
|
27440
|
+
capName: "recording",
|
|
27441
|
+
capScope: "system",
|
|
27442
|
+
addonId: null,
|
|
27443
|
+
access: "create"
|
|
27444
|
+
},
|
|
27015
27445
|
"recording.deleteFootprint": {
|
|
27016
27446
|
capName: "recording",
|
|
27017
27447
|
capScope: "system",
|
|
@@ -27042,6 +27472,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
27042
27472
|
addonId: null,
|
|
27043
27473
|
access: "view"
|
|
27044
27474
|
},
|
|
27475
|
+
"recording.getRelocateStatus": {
|
|
27476
|
+
capName: "recording",
|
|
27477
|
+
capScope: "system",
|
|
27478
|
+
addonId: null,
|
|
27479
|
+
access: "view"
|
|
27480
|
+
},
|
|
27045
27481
|
"recording.getStorageUsage": {
|
|
27046
27482
|
capName: "recording",
|
|
27047
27483
|
capScope: "system",
|
|
@@ -27072,6 +27508,24 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
27072
27508
|
addonId: null,
|
|
27073
27509
|
access: "view"
|
|
27074
27510
|
},
|
|
27511
|
+
"recording.relocateFootage": {
|
|
27512
|
+
capName: "recording",
|
|
27513
|
+
capScope: "system",
|
|
27514
|
+
addonId: null,
|
|
27515
|
+
access: "create"
|
|
27516
|
+
},
|
|
27517
|
+
"recording.renderClip": {
|
|
27518
|
+
capName: "recording",
|
|
27519
|
+
capScope: "system",
|
|
27520
|
+
addonId: null,
|
|
27521
|
+
access: "create"
|
|
27522
|
+
},
|
|
27523
|
+
"recording.renderGif": {
|
|
27524
|
+
capName: "recording",
|
|
27525
|
+
capScope: "system",
|
|
27526
|
+
addonId: null,
|
|
27527
|
+
access: "create"
|
|
27528
|
+
},
|
|
27075
27529
|
"recording.rescanStorage": {
|
|
27076
27530
|
capName: "recording",
|
|
27077
27531
|
capScope: "system",
|
|
@@ -27666,6 +28120,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
27666
28120
|
addonId: null,
|
|
27667
28121
|
access: "create"
|
|
27668
28122
|
},
|
|
28123
|
+
"streamBroker.renderPreBufferClip": {
|
|
28124
|
+
capName: "stream-broker",
|
|
28125
|
+
capScope: "system",
|
|
28126
|
+
addonId: null,
|
|
28127
|
+
access: "create"
|
|
28128
|
+
},
|
|
27669
28129
|
"streamBroker.restartProfile": {
|
|
27670
28130
|
capName: "stream-broker",
|
|
27671
28131
|
capScope: "system",
|