@camstack/addon-auth 1.2.19 → 1.2.20

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.
@@ -10967,6 +10967,8 @@ var QueryFilterSchema = object({
10967
10967
  where: record(string(), unknown()).optional(),
10968
10968
  whereIn: record(string(), array(unknown())).optional(),
10969
10969
  whereBetween: record(string(), tuple([unknown(), unknown()])).optional(),
10970
+ /** NULL-safe exclusion: matches rows whose field is NULL OR != the value. */
10971
+ whereNot: record(string(), unknown()).optional(),
10970
10972
  orderBy: object({
10971
10973
  field: string(),
10972
10974
  direction: _enum(["asc", "desc"])
@@ -10986,7 +10988,8 @@ var QueryFilterSchema = object({
10986
10988
  var MutationFilterSchema = object({
10987
10989
  where: record(string(), unknown()).optional(),
10988
10990
  whereIn: record(string(), array(unknown())).optional(),
10989
- whereBetween: record(string(), tuple([unknown(), unknown()])).optional()
10991
+ whereBetween: record(string(), tuple([unknown(), unknown()])).optional(),
10992
+ whereNot: record(string(), unknown()).optional()
10990
10993
  });
10991
10994
  /** A single stored record: `{ id, data }`. */
10992
10995
  var SettingsRecordSchema = object({
@@ -12402,6 +12405,18 @@ var LlmGenerateBaseInputSchema = object({
12402
12405
  * Resource ceiling = llama-server flags + idleStopMinutes ONLY (no RSS
12403
12406
  * watchdog — operator decision #3).
12404
12407
  */
12408
+ /**
12409
+ * A companion artifact that MUST land beside the main GGUF: the `mmproj`
12410
+ * projector of a vision model, or shards 2..N of a split GGUF. Carried on the
12411
+ * REF rather than looked up at install time, so what the operator approved in
12412
+ * the preview is exactly what the node downloads.
12413
+ */
12414
+ var ManagedModelExtraFileSchema = object({
12415
+ url: string(),
12416
+ filename: string(),
12417
+ sizeBytes: number(),
12418
+ sha256: string().optional()
12419
+ });
12405
12420
  var ManagedModelRefSchema = discriminatedUnion("kind", [
12406
12421
  object({
12407
12422
  kind: literal("catalog"),
@@ -12410,7 +12425,11 @@ var ManagedModelRefSchema = discriminatedUnion("kind", [
12410
12425
  object({
12411
12426
  kind: literal("url"),
12412
12427
  url: string(),
12413
- sha256: string().optional()
12428
+ sha256: string().optional(),
12429
+ /** Picker/status label; the file basename when absent. */
12430
+ label: string().optional(),
12431
+ sizeBytes: number().optional(),
12432
+ extraFiles: array(ManagedModelExtraFileSchema).optional()
12414
12433
  }),
12415
12434
  object({
12416
12435
  kind: literal("path"),
@@ -12471,11 +12490,39 @@ var ManagedRuntimeConfigSchema = object({
12471
12490
  "q4_1",
12472
12491
  "q4_0"
12473
12492
  ]).optional(),
12493
+ /**
12494
+ * Escape hatch for llama-server flags this schema does NOT model — `--jinja`
12495
+ * (which most vision chat templates need and some language-only models
12496
+ * dislike), `--cont-batching`, `--rope-scaling`, …
12497
+ *
12498
+ * It is NOT a second place to set the flags above. A token that collides
12499
+ * with a typed field is REJECTED at start, naming the field that owns it
12500
+ * (`assertNoOwnedFlags`), because two knobs writing the same argv is exactly
12501
+ * the "two switches that disagree" failure this repo has already shipped
12502
+ * twice (D62).
12503
+ */
12504
+ extraArgs: array(string()).default([]),
12474
12505
  /** Else lazy: first generate boots it. */
12475
12506
  autoStart: boolean().default(false),
12476
12507
  /** 0 = never; frees RAM after quiet periods. */
12477
12508
  idleStopMinutes: number().int().default(30)
12478
12509
  });
12510
+ /**
12511
+ * Where a multi-GB install currently is. A single 0..1 fraction cannot answer
12512
+ * "is it stuck?" for an install that is three files (shards + mmproj) followed
12513
+ * by a sha256 pass over 22 GB — during which the fraction sat at 1.0 and the
12514
+ * node looked hung. Phase + file + bytes is the smallest shape that does.
12515
+ */
12516
+ var LlmDownloadProgressSchema = object({
12517
+ phase: _enum(["downloading", "verifying"]),
12518
+ /** The artifact currently moving, e.g. `mmproj-F16.gguf`. */
12519
+ file: string(),
12520
+ fileIndex: number().int(),
12521
+ fileCount: number().int(),
12522
+ /** Across the WHOLE install, not the current file. */
12523
+ downloadedBytes: number(),
12524
+ totalBytes: number().optional()
12525
+ });
12479
12526
  var LlmRuntimeStatusSchema = object({
12480
12527
  /** Status is ALWAYS node-qualified. */
12481
12528
  nodeId: string(),
@@ -12492,6 +12539,8 @@ var LlmRuntimeStatusSchema = object({
12492
12539
  modelPath: string().optional(),
12493
12540
  modelId: string().optional(),
12494
12541
  downloadProgress: number().min(0).max(1).optional(),
12542
+ /** Detail behind `downloadProgress`; present for the same lifetime. */
12543
+ download: LlmDownloadProgressSchema.optional(),
12495
12544
  lastError: string().optional(),
12496
12545
  crashesInWindow: number(),
12497
12546
  /** Child RSS (sampled best-effort). */
@@ -12502,7 +12551,14 @@ var LlmNodeModelSchema = object({
12502
12551
  file: string(),
12503
12552
  sizeBytes: number(),
12504
12553
  catalogId: string().optional(),
12505
- installedAt: number().optional()
12554
+ installedAt: number().optional(),
12555
+ /**
12556
+ * Absolute path on the node. Present so a file that is on disk but matches
12557
+ * no catalog entry — a custom Hugging Face install, or a GGUF the operator
12558
+ * copied in by hand — is still SELECTABLE, as a `{kind:'path'}` ref. Without
12559
+ * it the picker could list such a file and do nothing with it.
12560
+ */
12561
+ path: string().optional()
12506
12562
  });
12507
12563
  var LlmRuntimeDiskUsageSchema = object({
12508
12564
  nodeId: string(),
@@ -12580,9 +12636,12 @@ var LlmProfileSchema = object({
12580
12636
  systemPrompt: string().optional(),
12581
12637
  /** Total generation bound — the only one a unary call has. */
12582
12638
  timeoutMs: number().int().positive().default(6e4),
12583
- /** Wait for response headers only. */
12639
+ /** The TCP handshake only — "is the port even open". NOT the wait for
12640
+ * response headers: on the LM Studio / llama-server wire those are written
12641
+ * once the model has finished loading, so they belong to the bound below. */
12584
12642
  connectTimeoutMs: number().int().positive().default(1e4),
12585
- /** Accepted, but no output yet — a cold GPU load lives here. */
12643
+ /** Accepted, but no output yet — response headers included, because a cold
12644
+ * GPU load is exactly what happens before them. */
12586
12645
  firstTokenTimeoutMs: number().int().positive().default(12e4),
12587
12646
  /** Output started then stopped. */
12588
12647
  idleTimeoutMs: number().int().positive().default(6e4),
@@ -12645,6 +12704,36 @@ var ManagedModelCatalogEntrySchema = object({
12645
12704
  /** Vision models: companion projector file. */
12646
12705
  mmprojUrl: string().optional()
12647
12706
  });
12707
+ /**
12708
+ * The outcome of turning one operator-typed Hugging Face reference into a
12709
+ * download plan. A RESULT, never a throw: "this repo has 24 quantizations and
12710
+ * I will not pick for you" is a normal answer the UI has to render, not an
12711
+ * exception.
12712
+ *
12713
+ * `candidates` is the whole reason the refusal is usable — every string in it
12714
+ * is a tag that resolves when pasted back as `<org>/<repo>:<TAG>`.
12715
+ */
12716
+ var HfModelResolutionSchema = discriminatedUnion("ok", [object({
12717
+ ok: literal(true),
12718
+ /** Ready to hand to `installModel` unchanged. */
12719
+ model: ManagedModelRefSchema,
12720
+ label: string(),
12721
+ repo: string(),
12722
+ quantization: string(),
12723
+ purpose: _enum(["text", "vision"]),
12724
+ totalBytes: number(),
12725
+ /** mmproj + shards, for the preview: an operator approving 23 GB should
12726
+ * see that 0.9 GB of it is a projector they did not name. */
12727
+ extraFilenames: array(string())
12728
+ }), object({
12729
+ ok: literal(false),
12730
+ code: string(),
12731
+ message: string(),
12732
+ candidates: array(string()).optional(),
12733
+ /** Set when the refusal was only the ceiling: re-calling with
12734
+ * `maxBytes: requiredBytes` is the operator's explicit override. */
12735
+ requiredBytes: number().optional()
12736
+ })]);
12648
12737
  var LlmRuntimeNodeSchema = object({
12649
12738
  nodeId: string(),
12650
12739
  reachable: boolean(),
@@ -12681,6 +12770,15 @@ method(LlmGenerateBaseInputSchema, LlmGenerateResultSchema, { kind: "mutation" }
12681
12770
  consumer: string().optional(),
12682
12771
  profileId: string().optional()
12683
12772
  }), array(LlmUsageRollupSchema)), method(object({}), array(ManagedModelCatalogEntrySchema)), method(object({}), array(LlmRuntimeNodeSchema)), method(object({ nodeId: string() }), array(LlmNodeModelSchema)), method(object({
12773
+ /** `https://huggingface.co/<org>/<repo>/resolve/main/<f>.gguf`,
12774
+ * `<org>/<repo>/<f>.gguf`, `<org>/<repo>` or `<org>/<repo>:<QUANT>`. */
12775
+ ref: string(),
12776
+ /** Explicit ceiling override, in bytes. Absent = the built-in ceiling. */
12777
+ maxBytes: number().positive().optional()
12778
+ }), HfModelResolutionSchema, {
12779
+ kind: "mutation",
12780
+ auth: "admin"
12781
+ }), method(object({
12684
12782
  nodeId: string(),
12685
12783
  model: ManagedModelRefSchema
12686
12784
  }), _void(), {
@@ -14585,13 +14683,81 @@ var NcRuleActionsSchema = object({
14585
14683
  */
14586
14684
  buttons: array(NcRuleNotificationButtonSchema).max(8).optional()
14587
14685
  });
14686
+ /**
14687
+ * "This rule applies only while `deviceId` is in one of `states`."
14688
+ *
14689
+ * The states are the DEVICE's own vocabulary — `AlarmState` for a panel,
14690
+ * `on`/`off` for a switch — not a normalised set, because normalising would
14691
+ * make the condition lie about devices whose states have no equivalent.
14692
+ *
14693
+ * An unreadable state does NOT match: see the engine's fail-closed gate. A
14694
+ * condition that fired on "I could not read it" would be worse than no gate.
14695
+ */
14696
+ var NcDeviceStateConditionSchema = object({
14697
+ deviceId: number().int(),
14698
+ /** Any of these matches. */
14699
+ states: array(string().min(1)).min(1)
14700
+ });
14701
+ /**
14702
+ * "This rule applies only while scene `sceneId` is `matched` / `diverged`."
14703
+ *
14704
+ * A GATE, not a trigger. `occupancy` and `audio` each DISCRIMINATE their rule —
14705
+ * carrying one makes the rule fire on that subject and nothing else. Scene is
14706
+ * the other shape entirely, the `deviceState` shape: it narrows a rule that
14707
+ * already has a trigger ("tell me about a person at the front door, but only
14708
+ * while the bin is still out"). That is why it composes with every delivery
14709
+ * instead of owning one, and why no new `NcDelivery` member and no new subject
14710
+ * kind exist for it — see D159.
14711
+ *
14712
+ * ── Identity ───────────────────────────────────────────────────────────────
14713
+ * `sceneId` is `SceneMonitor.id`, a `randomUUID()` minted by `createScene` —
14714
+ * globally unique, so it needs no device to disambiguate it. `deviceId` is
14715
+ * carried as a HINT for the editor and for the log line, never as part of the
14716
+ * lookup key: a rule whose hint drifted must still gate correctly.
14717
+ *
14718
+ * ── Which boolean ──────────────────────────────────────────────────────────
14719
+ * `latched` ABSENT means "whatever the scene itself says" — `SceneMonitor.emit`
14720
+ * already declares which boolean drives notification rules, and a second knob
14721
+ * that could disagree with it is exactly the D62 failure. Set it only to
14722
+ * override one rule against the scene's own default.
14723
+ *
14724
+ * - LIVE reading (`emit`/`latched` resolve to live): passes iff
14725
+ * `verdict === requiredState`. `unknown` — no reference for this light, view
14726
+ * shifted, no snapshot — passes NEITHER. A scene that cannot judge is not
14727
+ * evidence, in either direction.
14728
+ * - LATCHED reading: passes iff `latched === (requiredState === 'diverged')`.
14729
+ * The latch is a durable fact about the past ("it has diverged since I armed
14730
+ * it"), so a camera that has gone dark does not clear it — that is the whole
14731
+ * reason the operator asked for a latch.
14732
+ *
14733
+ * The gate reads an in-memory mirror (`NcSceneStateCache`) refreshed OFF the
14734
+ * event path, never the cap: D49. A mirror that has never loaded, or a scene it
14735
+ * does not carry, reads absent and the rule does NOT fire — fail closed, and
14736
+ * said out loud in the log rather than dropped in silence.
14737
+ */
14738
+ var NcSceneConditionSchema = object({
14739
+ /** `SceneMonitor.id` — the uuid the cap mints. The whole lookup key. */
14740
+ sceneId: string().min(1),
14741
+ /** The camera the scene lives on. A hint for the editor and the log line. */
14742
+ deviceId: number().int().optional(),
14743
+ /** The state the scene must be in for the rule to fire. */
14744
+ requiredState: _enum(["matched", "diverged"]),
14745
+ /**
14746
+ * Read the LATCH (`true`) or the LIVE verdict (`false`). Absent = follow the
14747
+ * scene's own `emit` field, which is the only place that decision belongs.
14748
+ */
14749
+ latched: boolean().optional()
14750
+ });
14588
14751
  var NcConditionsSchema = object({
14589
14752
  /** Gate on ANOTHER device's current state (the alarm armed, a switch on). */
14590
- deviceState: object({
14591
- deviceId: number().int(),
14592
- /** Any of these matches. */
14593
- states: array(string().min(1)).min(1)
14594
- }).optional(),
14753
+ deviceState: NcDeviceStateConditionSchema.optional(),
14754
+ /**
14755
+ * Gate on a SCENE's state — "only while the bin is still out". Composes with
14756
+ * every trigger (detection, occupancy, audio, sensor, package, track-end);
14757
+ * unlike `occupancy`/`audio` it discriminates nothing. See
14758
+ * {@link NcSceneCondition} and D159.
14759
+ */
14760
+ scene: NcSceneConditionSchema.optional(),
14595
14761
  /** Device scope — absent = all devices. */
14596
14762
  devices: array(number()).optional(),
14597
14763
  /** Detector class names (any overlap with the record's class set). */
@@ -15229,6 +15395,7 @@ var NcConditionDescriptorSchema = object({
15229
15395
  "occupancy",
15230
15396
  "audio",
15231
15397
  "deviceState",
15398
+ "scene",
15232
15399
  "systemEvent"
15233
15400
  ]),
15234
15401
  operator: _enum([
@@ -16706,7 +16873,10 @@ var RecentTracksQueryInput = object({
16706
16873
  * Encodes the (lastSeen, trackId) sort position — treat as opaque. */
16707
16874
  cursor: string().optional(),
16708
16875
  /** See {@link TrackProjectionSchema}. Default `full`. */
16709
- projection: TrackProjectionSchema.optional()
16876
+ projection: TrackProjectionSchema.optional(),
16877
+ /** Include stationary-promoted rows (parked objects). Default false: the
16878
+ * feed lists passages; parking records live on the stationary registry. */
16879
+ includeStationary: boolean().optional()
16710
16880
  });
16711
16881
  var RecentTracksPageSchema = object({
16712
16882
  /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
@@ -16924,7 +17094,11 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
16924
17094
  zone: TrackZoneFilterSchema.optional(),
16925
17095
  /** See {@link TrackProjectionSchema}. Default `full` (backward
16926
17096
  * compatible — omitting the field keeps today's exact behaviour). */
16927
- projection: TrackProjectionSchema.optional()
17097
+ projection: TrackProjectionSchema.optional(),
17098
+ /** Include stationary-promoted rows (parked objects handed to the
17099
+ * stationary registry). Default false: the timeline lists passages,
17100
+ * not parking records (operator decision, 2026-08-15). */
17101
+ includeStationary: boolean().optional()
16928
17102
  }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
16929
17103
  kind: "mutation",
16930
17104
  auth: "admin"
@@ -17088,11 +17262,16 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17088
17262
  auth: "admin"
17089
17263
  }), method(object({
17090
17264
  eventId: string(),
17091
- kind: MediaFileKindEnum.optional()
17265
+ kind: MediaFileKindEnum.optional(),
17266
+ deviceId: number()
17267
+ }), array(MediaFileSchema).readonly()), method(object({
17268
+ trackId: string(),
17269
+ kinds: array(MediaFileKindEnum).optional(),
17270
+ deviceId: number()
17092
17271
  }), array(MediaFileSchema).readonly()), method(object({
17093
17272
  trackId: string(),
17094
- kinds: array(MediaFileKindEnum).optional()
17095
- }), array(MediaFileSchema).readonly()), method(object({ trackId: string() }), array(MediaFileInfoSchema).readonly()), method(SearchObjectEventsInput, array(ScoredObjectEventSchema).readonly()), method(object({}), WipeObjectEmbeddingsResultSchema, {
17273
+ deviceId: number()
17274
+ }), array(MediaFileInfoSchema).readonly()), method(SearchObjectEventsInput, array(ScoredObjectEventSchema).readonly()), method(object({}), WipeObjectEmbeddingsResultSchema, {
17096
17275
  kind: "mutation",
17097
17276
  auth: "admin"
17098
17277
  }), method(RebuildObjectEmbeddingsInput, RebuildObjectEmbeddingsResultSchema, {
@@ -17752,6 +17931,17 @@ var maxSessionHoldMsField = {
17752
17931
  default: 12e4,
17753
17932
  step: 5e3
17754
17933
  };
17934
+ /**
17935
+ * Quiet period that closes an `audioMode: 'on-motion'` audio window. Floor of
17936
+ * 5s so a rearm can never degenerate into per-event stream churn; default 90s
17937
+ * comfortably outlives the gap between two PIR wakes on a battery camera.
17938
+ */
17939
+ var audioMotionWindowMsField = {
17940
+ min: 5e3,
17941
+ max: 6e5,
17942
+ default: 9e4,
17943
+ step: 5e3
17944
+ };
17755
17945
  var motionFpsField = {
17756
17946
  min: 1,
17757
17947
  max: 30,
@@ -17928,6 +18118,27 @@ var RunnerCameraConfigSchema = object({
17928
18118
  * resolved `CameraDetectionConfig`.
17929
18119
  */
17930
18120
  maxSessionHoldMs: number().min(maxSessionHoldMsField.min).max(maxSessionHoldMsField.max).optional(),
18121
+ /**
18122
+ * Orchestrator-side quiet period (ms) that closes an `audioMode:
18123
+ * 'on-motion'` audio window, measured from the LAST motion event.
18124
+ *
18125
+ * This exists because the falling edge cannot be relied on. Camera-native
18126
+ * providers emit motion as a RISING EDGE ONLY (Reolink's Baichuan push and
18127
+ * its email-push SMTP path both emit `detected: true` and never the
18128
+ * counterpart); only the frame-diff analyzer emits falls. So on an
18129
+ * onboard-only camera a window that closed only on `detected: false` never
18130
+ * closed at all, and `on-motion` silently behaved as `always-on` — on a
18131
+ * battery camera, the one failure mode the mode exists to prevent.
18132
+ *
18133
+ * Every motion event rearms this timer WITHOUT restarting the stream, so a
18134
+ * burst of re-fires costs nothing. A falling edge, when one does arrive,
18135
+ * still closes earlier via `motionCooldownMs` — whichever comes first wins.
18136
+ *
18137
+ * Not consumed by the runner: carried here so it shares the per-camera
18138
+ * device-settings surface with `motionCooldownMs`, exactly like
18139
+ * `maxSessionHoldMs`.
18140
+ */
18141
+ audioMotionWindowMs: number().min(audioMotionWindowMsField.min).max(audioMotionWindowMsField.max).optional(),
17931
18142
  motionFps: number().min(motionFpsField.min).max(motionFpsField.max).default(motionFpsField.default),
17932
18143
  detectionFps: number().min(detectionFpsField.min).max(detectionFpsField.max).default(detectionFpsField.default),
17933
18144
  motionStreamId: string(),
@@ -18023,7 +18234,7 @@ var RunnerCameraConfigSchema = object({
18023
18234
  */
18024
18235
  inferenceDevices: array(RunnerInferenceDeviceSchema).readonly().optional()
18025
18236
  });
18026
- motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, maxSessionHoldMsField.min, maxSessionHoldMsField.max, maxSessionHoldMsField.step, maxSessionHoldMsField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
18237
+ motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, maxSessionHoldMsField.min, maxSessionHoldMsField.max, maxSessionHoldMsField.step, maxSessionHoldMsField.default, audioMotionWindowMsField.min, audioMotionWindowMsField.max, audioMotionWindowMsField.step, audioMotionWindowMsField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
18027
18238
  /**
18028
18239
  * Runtime load summary returned by `getLocalLoad`. Used by the orchestrator's
18029
18240
  * load-balancing levels (L2 capacity-based, L3 hardware-aware) to decide
@@ -19039,7 +19250,16 @@ targets: array(object({
19039
19250
  /** A sleeping battery camera: the frame is deliberately stale and will
19040
19251
  * NOT refresh in the background. A surface should say so rather than
19041
19252
  * present it as current. */
19042
- sleeping: boolean()
19253
+ sleeping: boolean(),
19254
+ /** Current device state rendered over the cached frame. State images
19255
+ * remain authoritative even when their photographic background is
19256
+ * old; null means the link must carry a current camera frame. */
19257
+ stateReason: _enum([
19258
+ "disabled",
19259
+ "sleeping",
19260
+ "unreachable",
19261
+ "waking"
19262
+ ]).nullable()
19043
19263
  })));
19044
19264
  /**
19045
19265
  * `sso-bridge` — internal hub-only cap that lets SSO-style auth
@@ -20578,6 +20798,25 @@ var BatteryStatusSchema = object({
20578
20798
  /** Ms epoch of the last observation. Lets consumers reason about freshness. */
20579
20799
  lastUpdated: number(),
20580
20800
  /**
20801
+ * Ms epoch of the last time the device PROVED it was reachable — a
20802
+ * completed firmware round-trip, an observed wake, or an inbound push
20803
+ * (firmware event, email). `0`/absent = never since this slice was born.
20804
+ *
20805
+ * This is the ONLY input that separates "asleep" from "gone", and it is
20806
+ * fed exclusively by PASSIVE signals: nothing may write it by reaching
20807
+ * for the radio, because a poll that confirms reachability is the same
20808
+ * poll that drains the battery. See {@link deriveBatteryPresence} — the
20809
+ * single derivation every consumer must use; no surface computes its own.
20810
+ *
20811
+ * It is deliberately NOT a clock in the
20812
+ * `scripts/check-runtime-state-durability.ts` sense: it is the
20813
+ * observation itself, and it is the only thing a 30-hour silence is
20814
+ * visible in. Writers quantise it (see `CONTACT_WRITE_QUANTUM_MS` in the
20815
+ * Reolink provider) so a value that means "recently" cannot cost a
20816
+ * SQLite commit per round-trip.
20817
+ */
20818
+ lastContactAt: number().optional(),
20819
+ /**
20581
20820
  * True when the source is a BINARY low-battery indicator (HA
20582
20821
  * `binary_sensor` device_class=battery / `LOW_BAT`) that has no real
20583
20822
  * charge level — `percentage` is then a coarse stand-in (100 = normal,
@@ -24446,6 +24685,33 @@ method(object({
24446
24685
  * as `unknown`, never guessed. A day reference scored against an IR frame
24447
24686
  * collapses the cosine and would latch a false alarm every single night. */
24448
24687
  var SceneConditionSchema = string();
24688
+ /**
24689
+ * What a scene does when the CURRENT light has no reference of its own.
24690
+ *
24691
+ * The lighting variants are not equally likely to exist. Almost every operator
24692
+ * captures daylight and then never stands outside at 22:00 to capture IR, and a
24693
+ * scene that is only ever going to be asked about a daytime question ("is the
24694
+ * bin still on the kerb at 08:00") does not need a night reference at all. The
24695
+ * night half must therefore be OPTIONAL, and optional means the scene keeps
24696
+ * working without it rather than degrading into a permanent complaint.
24697
+ *
24698
+ * - `skip` (default) — the check in that light is not made. Not a verdict, not
24699
+ * an alarm, not even an `unknown`: the live state simply stays whatever the
24700
+ * last covered light left it at, the latch is untouched, and the hysteresis
24701
+ * run is neither spent nor cleared. The scene resumes by itself at first
24702
+ * light. This is the only behaviour under which "I never captured IR" is a
24703
+ * configuration choice instead of a nightly fault.
24704
+ * - `judge-anyway` — score against the OTHER conditions' references. Available
24705
+ * for cameras whose IR frame is close enough to daylight (a floodlit
24706
+ * driveway, an always-white-light doorbell), and wrong for everything else:
24707
+ * cross-condition cosines are not comparable, so a day reference against a
24708
+ * true IR frame collapses and the scene reports a theft at 21:40.
24709
+ *
24710
+ * Never applies when the scene has NO comparable reference at all — that is
24711
+ * "not armed yet", it is reported as `no-reference-for-condition`, and silence
24712
+ * there would hide a scene the operator never finished setting up.
24713
+ */
24714
+ var SceneUncoveredPolicySchema = _enum(["skip", "judge-anyway"]);
24449
24715
  /** `matched` = the baseline is what we see; `diverged` = it demonstrably is not;
24450
24716
  * `unknown` = we cannot judge (no reference for this condition, encoder model
24451
24717
  * changed, view shifted, no snapshot). `unknown` is a real value, not a null,
@@ -24501,6 +24767,9 @@ var SceneCheckSchema = discriminatedUnion("mode", [object({
24501
24767
  hysteresisCount: number().int().positive()
24502
24768
  })]);
24503
24769
  var SCENE_DEFAULT_ANCHOR_THRESHOLD = .85;
24770
+ /** Night is OPTIONAL. A scene with only a daylight reference sits the IR hours
24771
+ * out in silence rather than reporting a fault every night. */
24772
+ var SCENE_DEFAULT_UNCOVERED_POLICY = "skip";
24504
24773
  /**
24505
24774
  * Vision-model adjudication of a candidate flip. Field names deliberately
24506
24775
  * mirror `NcConfirmSchema` so an operator meets one vocabulary, not two.
@@ -24567,6 +24836,21 @@ var SceneMonitorSchema = object({
24567
24836
  * automation can react to the bin coming back without the operator's own
24568
24837
  * alarm silently clearing itself. */
24569
24838
  autoRestore: boolean().default(false),
24839
+ /** What to do when the current light has no reference of its own. See
24840
+ * {@link SceneUncoveredPolicySchema} — the default makes night OPTIONAL. */
24841
+ onUncoveredCondition: SceneUncoveredPolicySchema.default(SCENE_DEFAULT_UNCOVERED_POLICY),
24842
+ /**
24843
+ * The light whose checks are currently being SAT OUT under
24844
+ * `onUncoveredCondition: 'skip'` — `null` when the scene is checking normally.
24845
+ *
24846
+ * Engine-reported and advisory only: it moves no verdict, no latch and no
24847
+ * hysteresis. It exists so the card can say *"night (IR) — checks paused,
24848
+ * nothing captured in this light"* in the same calm voice as the coverage
24849
+ * line, because the alternative is a scene that silently stops answering
24850
+ * after sunset with nothing anywhere saying why. A skipped check must never
24851
+ * read as a broken one.
24852
+ */
24853
+ suspendedCondition: SceneConditionSchema.nullable().default(null),
24570
24854
  /** Named cause when `verdict === 'unknown'`. */
24571
24855
  unavailable: SceneUnavailableSchema.nullable(),
24572
24856
  /** Conditions that have at least one comparable reference — the coverage line
@@ -24610,6 +24894,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), SceneMonitorStatusSche
24610
24894
  minObservationSpacingSec: number().int().min(0).max(3600).optional(),
24611
24895
  anchorThreshold: number().min(0).max(1).optional(),
24612
24896
  autoRestore: boolean().optional(),
24897
+ onUncoveredCondition: SceneUncoveredPolicySchema.optional(),
24613
24898
  /** `null` clears the vision-model adjudicator. */
24614
24899
  confirm: SceneConfirmSchema.nullable().optional()
24615
24900
  })
@@ -24809,6 +25094,16 @@ var CamStreamDescriptorSchema = object({
24809
25094
  /** Transport-specific opaque metadata (e.g. rfc4571 SDP). */
24810
25095
  metadata: record(string(), unknown()).optional()
24811
25096
  });
25097
+ object({
25098
+ /** The descriptors as last built from a real camera response. Never a guess:
25099
+ * a failed or refused build writes NOTHING, so a restored catalog is always
25100
+ * one the camera itself once produced. */
25101
+ descriptors: array(CamStreamDescriptorSchema),
25102
+ /** Ms epoch of the build that produced {@link descriptors}. Lets the wake
25103
+ * path decide whether the camera's own awake window is worth spending on a
25104
+ * re-read. */
25105
+ lastFetchedAt: number()
25106
+ });
24812
25107
  DeviceType.Camera, method(object({ deviceId: number().int().nonnegative() }), array(CamStreamDescriptorSchema).readonly());
24813
25108
  /** One of the camera's stream profiles. */
24814
25109
  var StreamProfileSchema = _enum([
@@ -27841,6 +28136,12 @@ Object.freeze({
27841
28136
  addonId: null,
27842
28137
  access: "view"
27843
28138
  },
28139
+ "llm.resolveModelRef": {
28140
+ capName: "llm",
28141
+ capScope: "system",
28142
+ addonId: null,
28143
+ access: "create"
28144
+ },
27844
28145
  "llm.setDefault": {
27845
28146
  capName: "llm",
27846
28147
  capScope: "system",
@@ -32233,6 +32534,11 @@ Object.freeze({
32233
32534
  form: "single",
32234
32535
  optional: false
32235
32536
  }],
32537
+ "pipelineAnalytics.getEventMedia": [{
32538
+ name: "deviceId",
32539
+ form: "single",
32540
+ optional: false
32541
+ }],
32236
32542
  "pipelineAnalytics.getKeyEvents": [{
32237
32543
  name: "deviceId",
32238
32544
  form: "single",
@@ -32263,6 +32569,11 @@ Object.freeze({
32263
32569
  form: "single",
32264
32570
  optional: false
32265
32571
  }],
32572
+ "pipelineAnalytics.getTrackMedia": [{
32573
+ name: "deviceId",
32574
+ form: "single",
32575
+ optional: false
32576
+ }],
32266
32577
  "pipelineAnalytics.getTrainingExportSummary": [{
32267
32578
  name: "deviceIds",
32268
32579
  form: "array",
@@ -32298,6 +32609,11 @@ Object.freeze({
32298
32609
  form: "array",
32299
32610
  optional: true
32300
32611
  }],
32612
+ "pipelineAnalytics.listTrackMedia": [{
32613
+ name: "deviceId",
32614
+ form: "single",
32615
+ optional: false
32616
+ }],
32301
32617
  "pipelineAnalytics.listTracks": [{
32302
32618
  name: "deviceId",
32303
32619
  form: "single",
@@ -32738,6 +33054,12 @@ Object.freeze({
32738
33054
  form: "single",
32739
33055
  optional: false
32740
33056
  }],
33057
+ "snapshot.getSnapshotLinks": [{
33058
+ name: "targets",
33059
+ form: "object-array",
33060
+ optional: false,
33061
+ itemField: "deviceId"
33062
+ }],
32741
33063
  "snapshot.getSnapshotOverview": [{
32742
33064
  name: "deviceIds",
32743
33065
  form: "array",
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../chunk-Cek0wNdY.js");
6
- const require_dist = require("../dist-CIER3syF.js");
6
+ const require_dist = require("../dist-DMouzlMU.js");
7
7
  //#region src/magic-link/auth-magic-link.addon.ts
8
8
  /**
9
9
  * Magic-link authentication addon.
@@ -1,4 +1,4 @@
1
- import { a as loginMethodCapability, c as BaseAddon, i as buildAddonRouteProvider, r as authProviderCapability, s as errMsg, t as addonRoutesCapability } from "../dist-BPw7MIhF.mjs";
1
+ import { a as loginMethodCapability, c as BaseAddon, i as buildAddonRouteProvider, r as authProviderCapability, s as errMsg, t as addonRoutesCapability } from "../dist-c2S490eb.mjs";
2
2
  //#region src/magic-link/auth-magic-link.addon.ts
3
3
  /**
4
4
  * Magic-link authentication addon.
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-Cek0wNdY.js");
6
- const require_dist = require("../dist-CIER3syF.js");
6
+ const require_dist = require("../dist-DMouzlMU.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  node_crypto = require_chunk.__toESM(node_crypto);
9
9
  //#region node_modules/jose/dist/webapi/lib/buffer_utils.js
@@ -1,4 +1,4 @@
1
- import { a as loginMethodCapability, c as BaseAddon, i as buildAddonRouteProvider, r as authProviderCapability, s as errMsg, t as addonRoutesCapability } from "../dist-BPw7MIhF.mjs";
1
+ import { a as loginMethodCapability, c as BaseAddon, i as buildAddonRouteProvider, r as authProviderCapability, s as errMsg, t as addonRoutesCapability } from "../dist-c2S490eb.mjs";
2
2
  import * as crypto$1 from "node:crypto";
3
3
  //#region node_modules/jose/dist/webapi/lib/buffer_utils.js
4
4
  var encoder = new TextEncoder();
@@ -1,6 +1,6 @@
1
1
  import { n as e, r as t, t as n } from "./_virtual_mf___mfe_internal__addon_auth_webauthn_widgets__loadShare__react__loadShare__.js-BIIa6vDX.mjs";
2
2
  import { n as r, t as i } from "./_virtual_mf___mfe_internal__addon_auth_webauthn_widgets__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-CQ-aEQ9b.mjs";
3
- import { t as a } from "./_virtual_mf___mfe_internal__addon_auth_webauthn_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-ALMi5go0.mjs";
3
+ import { t as a } from "./_virtual_mf___mfe_internal__addon_auth_webauthn_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-k1jCpzO3.mjs";
4
4
  import { n as o, r as s, t as c } from "./_virtual_mf___mfe_internal__addon_auth_webauthn_widgets__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-BL2etuqg.mjs";
5
5
  //#region ../../node_modules/lucide-react/dist/esm/shared/src/utils.js
6
6
  var l = (e) => e.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(), u = (e) => e.replace(/^([A-Z])|[\s-_]+(\w)/g, (e, t, n) => n ? n.toUpperCase() : t.toLowerCase()), d = (e) => {
@@ -3,7 +3,7 @@ import "./dist-CYZr2fwk.mjs";
3
3
  var e = {
4
4
  "@camstack/sdk": {
5
5
  name: "@camstack/sdk",
6
- version: "1.2.19",
6
+ version: "1.2.20",
7
7
  scope: ["default"],
8
8
  loaded: !1,
9
9
  from: "addon_auth_webauthn_widgets",
@@ -18,7 +18,7 @@ var e = {
18
18
  },
19
19
  "@camstack/types": {
20
20
  name: "@camstack/types",
21
- version: "1.2.73",
21
+ version: "1.2.80",
22
22
  scope: ["default"],
23
23
  loaded: !1,
24
24
  from: "addon_auth_webauthn_widgets",
@@ -33,7 +33,7 @@ var e = {
33
33
  },
34
34
  "@camstack/ui-library": {
35
35
  name: "@camstack/ui-library",
36
- version: "1.2.51",
36
+ version: "1.2.55",
37
37
  scope: ["default"],
38
38
  loaded: !1,
39
39
  from: "addon_auth_webauthn_widgets",