@camstack/addon-mqtt-broker 1.2.78 → 1.2.79

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.
@@ -7644,111 +7644,6 @@ var CameraSwitchGroupSchema = object({
7644
7644
  fetchedAt: number()
7645
7645
  });
7646
7646
  /**
7647
- * Per-component log CHANNELS — the gate a hot path consults, and the registry
7648
- * an addon declares its channels in.
7649
- *
7650
- * ## Two axes, deliberately separated
7651
- *
7652
- * - **DECLARATION** — which channels exist. Only the addon knows:
7653
- * `stream-broker` knows webrtc/ICE/RTP, `provider-reolink` knows
7654
- * baichuan/handshake. A hand-wired central list rots at the first addition,
7655
- * and rots silently. So a channel is declared where it is consulted, and the
7656
- * `log-channels` capability enumerates the declarations.
7657
- * - **VALUE** — at which level, for which scope, until when. That stays ONE
7658
- * thing: the logging settings document on the `system` cap. Two authorities
7659
- * over the values is the exact defect
7660
- * `docs/design/plans/2026-08-26-logging-per-componente.md` was written to
7661
- * remove; re-introducing it from the cure side would be grotesque.
7662
- *
7663
- * Nothing in this file reads a clock, an env var or a store. The registry is
7664
- * a MIRROR: it is moved only by {@link LogChannelRegistry.apply}, called off
7665
- * the hot path with a value somebody actually read, and by
7666
- * {@link LogChannelRegistry.tick}, called on a timer. A store read that fails
7667
- * never reaches here, so it can neither disarm an armed channel nor arm a
7668
- * disarmed one (D49).
7669
- *
7670
- * ## The canonical call shape
7671
- *
7672
- * ```ts
7673
- * if (CH_RTP.on && CH_RTP.wants(deviceId)) {
7674
- * CH_RTP.log(logger, 'rtp subscriber added', { tags: { deviceId }, meta: { ssrc } })
7675
- * }
7676
- * ```
7677
- *
7678
- * `on` is a plain boolean FIELD — never a getter — and it is the FIRST thing
7679
- * read. Disarmed, a call site costs one load and one branch, and the `extras`
7680
- * object literal is never constructed because it lives inside the branch. It
7681
- * is the same shape already proven in production at `stream-broker.ts:1650`,
7682
- * and the same discipline `LoggingGate.allowsDestination` uses for the
7683
- * destination floor (measured at 1.93 ns/call when off).
7684
- *
7685
- * ## Why a channel emits at `info`
7686
- *
7687
- * `loki-logging.addon.ts` pins the destination default at `info` and
7688
- * `loki-destination.ts` drops everything below it, so a line emitted at
7689
- * `debug` never reaches Loki and the hub's in-memory ring only holds ~35
7690
- * minutes. A diagnostic that cannot be read an hour later is worse than no
7691
- * diagnostic, because it looks done. {@link LogChannelGate.log} therefore
7692
- * emits at the channel's declared level, whose schema floor is `info`.
7693
- */
7694
- /**
7695
- * The level a channel writes at once armed.
7696
- *
7697
- * `debug` is absent ON PURPOSE and not by omission: below `info` the line does
7698
- * not leave the process for Loki, and the whole point of arming a channel is
7699
- * to read it later.
7700
- */
7701
- var LogChannelLevelSchema = _enum([
7702
- "info",
7703
- "warn",
7704
- "error"
7705
- ]);
7706
- /**
7707
- * What an addon declares about one channel. No value, no state — a
7708
- * declaration is inert.
7709
- */
7710
- var LogChannelDescriptorSchema = object({
7711
- /**
7712
- * Dotted `area.thing`, unique across the workspace. `area` is conventionally
7713
- * the addon's short name so an operator reading a channel list can tell who
7714
- * owns it without a second lookup.
7715
- */
7716
- name: string().min(3).regex(/^[a-z0-9-]+(\.[a-z0-9-]+)+$/, "a channel name is dotted lower-kebab, e.g. area.thing"),
7717
- /** One sentence: what the operator will SEE after arming it. */
7718
- description: string().min(1),
7719
- /** The level its lines are emitted at. Never below `info`. */
7720
- defaultLevel: LogChannelLevelSchema,
7721
- /**
7722
- * Whether this channel can be narrowed to a camera.
7723
- *
7724
- * `true` is a PROMISE with two halves, and both must hold: the gate is
7725
- * consulted with the numeric device id, AND every line the channel admits
7726
- * carries `tags: { deviceId }` with that same numeric id. The second half is
7727
- * what makes `| json | deviceId="617"` work in Loki — `loki-payload.ts`
7728
- * keeps `deviceId` out of the stream labels for cardinality, so the tag in
7729
- * the body is the only way to filter.
7730
- *
7731
- * A channel whose lines carry the device only in `meta` (or not at all) is
7732
- * declared `false`. Declaring it `true` anyway would be a lie the UI repeats:
7733
- * the operator narrows to one camera, sees nothing, and concludes the code
7734
- * path was never taken.
7735
- */
7736
- perDevice: boolean()
7737
- });
7738
- /**
7739
- * An armed window over one channel, as the document hands it to a mirror.
7740
- *
7741
- * A window is a DEADLINE, never a flag (ADR-0244): a channel somebody forgot
7742
- * expires by itself, which is the one failure a boolean cannot avoid.
7743
- */
7744
- var LogChannelWindowSchema = object({
7745
- channel: string().min(1),
7746
- /** Epoch ms the window closes at. */
7747
- armedUntilMs: number(),
7748
- /** `null` = every camera. A non-empty list narrows to those numeric ids. */
7749
- deviceIds: array(number().int()).readonly().nullable()
7750
- });
7751
- /**
7752
7647
  * Ops-log — the durable, append-only operations audit shared by the
7753
7648
  * recordings and events management surfaces.
7754
7649
  *
@@ -8694,8 +8589,11 @@ var StorageLocationTypeSchema = string().regex(/^[a-z][a-zA-Z0-9-]*$/);
8694
8589
  * `STORAGE_LOCATION_CARDINALITY` map has been removed.
8695
8590
  *
8696
8591
  * `id` is a stable namespaced string of the form `<type>:<slug>`.
8697
- * The default location for a type uses `id === <type>:default` by
8698
- * convention (the bare type ref like `'backups'` resolves to it).
8592
+ * The seed names its first instance `<type>:default` — a NAME, not a flag.
8593
+ * There is no default location any more (D383): `enabled` is the whole write
8594
+ * model, and a bare type ref resolves to the sole location of the type, or —
8595
+ * transitionally, only while legacy NULL-stamped rows exist — to the row whose
8596
+ * slug is `default`.
8699
8597
  *
8700
8598
  * `isSystem` is a legacy persisted flag. Seed still creates the initial
8701
8599
  * `<type>:default` locations; the flag is no longer a lock, a badge, or a
@@ -8716,21 +8614,20 @@ var StorageLocationSchema = object({
8716
8614
  * flag at upsert time, not here (the schema is provider-agnostic).
8717
8615
  */
8718
8616
  nodeId: string().optional(),
8719
- isDefault: boolean().default(false),
8720
8617
  isSystem: boolean().default(false),
8721
8618
  /**
8722
- * Operator opt-in: whether consumers that BALANCE across several locations
8723
- * of a type may write here. Recordings reads it today; event media and
8724
- * backups are the next consumers, which is why the flag lives on the
8725
- * location rather than in any one addon's store — nothing has to be
8726
- * extended to add the next consumer.
8619
+ * THE write switch, and the only one (D383). `enabled: true` means every
8620
+ * consumer that chooses a write target for this type may write here, and all
8621
+ * enabled locations of a type are used TOGETHER; `false` means read-only —
8622
+ * still read, still played back, still age-swept, still drained, never
8623
+ * written.
8727
8624
  *
8728
- * OPTIONAL, and ABSENT MEANS ACTIVE. Every location persisted before the
8729
- * flag existed reads back with no flag and keeps working exactly as before;
8730
- * that is the whole compat story, and it is why no migration ships with it.
8731
- * A newly CREATED sibling is stamped `false` by the orchestrator (creating a
8732
- * disk must not silently start writing to it); the default of a type is
8733
- * always stamped `true`.
8625
+ * OPTIONAL only for the wire: an upsert that omits it means "leave what is
8626
+ * stored" on an update and "born inert unless it is the first location of its
8627
+ * type" on a create. On a PERSISTED row absence is legacy and it means
8628
+ * enabled — {@link isLocationEnabled} is the one place that says so, and the
8629
+ * orchestrator stamps every flagless row `true` once at hydrate so absence
8630
+ * stops existing rather than being re-derived on every read.
8734
8631
  */
8735
8632
  enabled: boolean().optional(),
8736
8633
  /** COMPUTED at read time by the orchestrator (statfs of the backing volume
@@ -8743,10 +8640,12 @@ var StorageLocationSchema = object({
8743
8640
  createdAt: number(),
8744
8641
  updatedAt: number()
8745
8642
  });
8643
+ object({ isDefault: boolean().optional() });
8746
8644
  /**
8747
8645
  * Reference accepted by consumer-facing `api.storage.*` calls.
8748
8646
  * Either:
8749
- * - a `StorageLocationType` (e.g. `'backups'`) → orchestrator resolves to the default of that type
8647
+ * - a `StorageLocationType` (e.g. `'backups'`) → the sole location of that type
8648
+ * (transitionally, the `<type>:default`-slugged row when several exist)
8750
8649
  * - a fully-qualified id (e.g. `'backups:nas-01'`) → addresses a specific instance
8751
8650
  *
8752
8651
  * The orchestrator's `resolveRef(ref)` handles both cases.
@@ -8922,6 +8821,111 @@ var DecoderSessionConfigSchema = object({
8922
8821
  */
8923
8822
  debug: boolean().optional()
8924
8823
  });
8824
+ /**
8825
+ * Per-component log CHANNELS — the gate a hot path consults, and the registry
8826
+ * an addon declares its channels in.
8827
+ *
8828
+ * ## Two axes, deliberately separated
8829
+ *
8830
+ * - **DECLARATION** — which channels exist. Only the addon knows:
8831
+ * `stream-broker` knows webrtc/ICE/RTP, `provider-reolink` knows
8832
+ * baichuan/handshake. A hand-wired central list rots at the first addition,
8833
+ * and rots silently. So a channel is declared where it is consulted, and the
8834
+ * `log-channels` capability enumerates the declarations.
8835
+ * - **VALUE** — at which level, for which scope, until when. That stays ONE
8836
+ * thing: the logging settings document on the `system` cap. Two authorities
8837
+ * over the values is the exact defect
8838
+ * `docs/design/plans/2026-08-26-logging-per-componente.md` was written to
8839
+ * remove; re-introducing it from the cure side would be grotesque.
8840
+ *
8841
+ * Nothing in this file reads a clock, an env var or a store. The registry is
8842
+ * a MIRROR: it is moved only by {@link LogChannelRegistry.apply}, called off
8843
+ * the hot path with a value somebody actually read, and by
8844
+ * {@link LogChannelRegistry.tick}, called on a timer. A store read that fails
8845
+ * never reaches here, so it can neither disarm an armed channel nor arm a
8846
+ * disarmed one (D49).
8847
+ *
8848
+ * ## The canonical call shape
8849
+ *
8850
+ * ```ts
8851
+ * if (CH_RTP.on && CH_RTP.wants(deviceId)) {
8852
+ * CH_RTP.log(logger, 'rtp subscriber added', { tags: { deviceId }, meta: { ssrc } })
8853
+ * }
8854
+ * ```
8855
+ *
8856
+ * `on` is a plain boolean FIELD — never a getter — and it is the FIRST thing
8857
+ * read. Disarmed, a call site costs one load and one branch, and the `extras`
8858
+ * object literal is never constructed because it lives inside the branch. It
8859
+ * is the same shape already proven in production at `stream-broker.ts:1650`,
8860
+ * and the same discipline `LoggingGate.allowsDestination` uses for the
8861
+ * destination floor (measured at 1.93 ns/call when off).
8862
+ *
8863
+ * ## Why a channel emits at `info`
8864
+ *
8865
+ * `loki-logging.addon.ts` pins the destination default at `info` and
8866
+ * `loki-destination.ts` drops everything below it, so a line emitted at
8867
+ * `debug` never reaches Loki and the hub's in-memory ring only holds ~35
8868
+ * minutes. A diagnostic that cannot be read an hour later is worse than no
8869
+ * diagnostic, because it looks done. {@link LogChannelGate.log} therefore
8870
+ * emits at the channel's declared level, whose schema floor is `info`.
8871
+ */
8872
+ /**
8873
+ * The level a channel writes at once armed.
8874
+ *
8875
+ * `debug` is absent ON PURPOSE and not by omission: below `info` the line does
8876
+ * not leave the process for Loki, and the whole point of arming a channel is
8877
+ * to read it later.
8878
+ */
8879
+ var LogChannelLevelSchema = _enum([
8880
+ "info",
8881
+ "warn",
8882
+ "error"
8883
+ ]);
8884
+ /**
8885
+ * What an addon declares about one channel. No value, no state — a
8886
+ * declaration is inert.
8887
+ */
8888
+ var LogChannelDescriptorSchema = object({
8889
+ /**
8890
+ * Dotted `area.thing`, unique across the workspace. `area` is conventionally
8891
+ * the addon's short name so an operator reading a channel list can tell who
8892
+ * owns it without a second lookup.
8893
+ */
8894
+ name: string().min(3).regex(/^[a-z0-9-]+(\.[a-z0-9-]+)+$/, "a channel name is dotted lower-kebab, e.g. area.thing"),
8895
+ /** One sentence: what the operator will SEE after arming it. */
8896
+ description: string().min(1),
8897
+ /** The level its lines are emitted at. Never below `info`. */
8898
+ defaultLevel: LogChannelLevelSchema,
8899
+ /**
8900
+ * Whether this channel can be narrowed to a camera.
8901
+ *
8902
+ * `true` is a PROMISE with two halves, and both must hold: the gate is
8903
+ * consulted with the numeric device id, AND every line the channel admits
8904
+ * carries `tags: { deviceId }` with that same numeric id. The second half is
8905
+ * what makes `| json | deviceId="617"` work in Loki — `loki-payload.ts`
8906
+ * keeps `deviceId` out of the stream labels for cardinality, so the tag in
8907
+ * the body is the only way to filter.
8908
+ *
8909
+ * A channel whose lines carry the device only in `meta` (or not at all) is
8910
+ * declared `false`. Declaring it `true` anyway would be a lie the UI repeats:
8911
+ * the operator narrows to one camera, sees nothing, and concludes the code
8912
+ * path was never taken.
8913
+ */
8914
+ perDevice: boolean()
8915
+ });
8916
+ /**
8917
+ * An armed window over one channel, as the document hands it to a mirror.
8918
+ *
8919
+ * A window is a DEADLINE, never a flag (ADR-0244): a channel somebody forgot
8920
+ * expires by itself, which is the one failure a boolean cannot avoid.
8921
+ */
8922
+ var LogChannelWindowSchema = object({
8923
+ channel: string().min(1),
8924
+ /** Epoch ms the window closes at. */
8925
+ armedUntilMs: number(),
8926
+ /** `null` = every camera. A non-empty list narrows to those numeric ids. */
8927
+ deviceIds: array(number().int()).readonly().nullable()
8928
+ });
8925
8929
  var MODEL_FORMATS = [
8926
8930
  "onnx",
8927
8931
  "coreml",
@@ -21654,7 +21658,7 @@ method(object({
21654
21658
  downloadId: string(),
21655
21659
  offset: number(),
21656
21660
  length: number()
21657
- }), _instanceof(Uint8Array)), method(object({ downloadId: string() }), _void(), { kind: "mutation" }), method(object({ type: StorageLocationTypeSchema.optional() }), array(StorageLocationSchema).readonly()), method(object({ type: StorageLocationTypeSchema }), StorageLocationSchema.nullable()), method(_void(), array(StorageLocationDeclarationSchema).readonly()), method(StorageLocationSchema.omit({
21661
+ }), _instanceof(Uint8Array)), method(object({ downloadId: string() }), _void(), { kind: "mutation" }), method(object({ type: StorageLocationTypeSchema.optional() }), array(StorageLocationSchema).readonly()), method(_void(), array(StorageLocationDeclarationSchema).readonly()), method(StorageLocationSchema.omit({
21658
21662
  createdAt: true,
21659
21663
  updatedAt: true
21660
21664
  }), StorageLocationSchema, {
@@ -34503,12 +34507,6 @@ Object.freeze({
34503
34507
  addonId: null,
34504
34508
  access: "view"
34505
34509
  },
34506
- "storage.getDefaultLocation": {
34507
- capName: "storage",
34508
- capScope: "system",
34509
- addonId: null,
34510
- access: "view"
34511
- },
34512
34510
  "storage.list": {
34513
34511
  capName: "storage",
34514
34512
  capScope: "system",
@@ -7639,111 +7639,6 @@ var CameraSwitchGroupSchema = object({
7639
7639
  fetchedAt: number()
7640
7640
  });
7641
7641
  /**
7642
- * Per-component log CHANNELS — the gate a hot path consults, and the registry
7643
- * an addon declares its channels in.
7644
- *
7645
- * ## Two axes, deliberately separated
7646
- *
7647
- * - **DECLARATION** — which channels exist. Only the addon knows:
7648
- * `stream-broker` knows webrtc/ICE/RTP, `provider-reolink` knows
7649
- * baichuan/handshake. A hand-wired central list rots at the first addition,
7650
- * and rots silently. So a channel is declared where it is consulted, and the
7651
- * `log-channels` capability enumerates the declarations.
7652
- * - **VALUE** — at which level, for which scope, until when. That stays ONE
7653
- * thing: the logging settings document on the `system` cap. Two authorities
7654
- * over the values is the exact defect
7655
- * `docs/design/plans/2026-08-26-logging-per-componente.md` was written to
7656
- * remove; re-introducing it from the cure side would be grotesque.
7657
- *
7658
- * Nothing in this file reads a clock, an env var or a store. The registry is
7659
- * a MIRROR: it is moved only by {@link LogChannelRegistry.apply}, called off
7660
- * the hot path with a value somebody actually read, and by
7661
- * {@link LogChannelRegistry.tick}, called on a timer. A store read that fails
7662
- * never reaches here, so it can neither disarm an armed channel nor arm a
7663
- * disarmed one (D49).
7664
- *
7665
- * ## The canonical call shape
7666
- *
7667
- * ```ts
7668
- * if (CH_RTP.on && CH_RTP.wants(deviceId)) {
7669
- * CH_RTP.log(logger, 'rtp subscriber added', { tags: { deviceId }, meta: { ssrc } })
7670
- * }
7671
- * ```
7672
- *
7673
- * `on` is a plain boolean FIELD — never a getter — and it is the FIRST thing
7674
- * read. Disarmed, a call site costs one load and one branch, and the `extras`
7675
- * object literal is never constructed because it lives inside the branch. It
7676
- * is the same shape already proven in production at `stream-broker.ts:1650`,
7677
- * and the same discipline `LoggingGate.allowsDestination` uses for the
7678
- * destination floor (measured at 1.93 ns/call when off).
7679
- *
7680
- * ## Why a channel emits at `info`
7681
- *
7682
- * `loki-logging.addon.ts` pins the destination default at `info` and
7683
- * `loki-destination.ts` drops everything below it, so a line emitted at
7684
- * `debug` never reaches Loki and the hub's in-memory ring only holds ~35
7685
- * minutes. A diagnostic that cannot be read an hour later is worse than no
7686
- * diagnostic, because it looks done. {@link LogChannelGate.log} therefore
7687
- * emits at the channel's declared level, whose schema floor is `info`.
7688
- */
7689
- /**
7690
- * The level a channel writes at once armed.
7691
- *
7692
- * `debug` is absent ON PURPOSE and not by omission: below `info` the line does
7693
- * not leave the process for Loki, and the whole point of arming a channel is
7694
- * to read it later.
7695
- */
7696
- var LogChannelLevelSchema = _enum([
7697
- "info",
7698
- "warn",
7699
- "error"
7700
- ]);
7701
- /**
7702
- * What an addon declares about one channel. No value, no state — a
7703
- * declaration is inert.
7704
- */
7705
- var LogChannelDescriptorSchema = object({
7706
- /**
7707
- * Dotted `area.thing`, unique across the workspace. `area` is conventionally
7708
- * the addon's short name so an operator reading a channel list can tell who
7709
- * owns it without a second lookup.
7710
- */
7711
- name: string().min(3).regex(/^[a-z0-9-]+(\.[a-z0-9-]+)+$/, "a channel name is dotted lower-kebab, e.g. area.thing"),
7712
- /** One sentence: what the operator will SEE after arming it. */
7713
- description: string().min(1),
7714
- /** The level its lines are emitted at. Never below `info`. */
7715
- defaultLevel: LogChannelLevelSchema,
7716
- /**
7717
- * Whether this channel can be narrowed to a camera.
7718
- *
7719
- * `true` is a PROMISE with two halves, and both must hold: the gate is
7720
- * consulted with the numeric device id, AND every line the channel admits
7721
- * carries `tags: { deviceId }` with that same numeric id. The second half is
7722
- * what makes `| json | deviceId="617"` work in Loki — `loki-payload.ts`
7723
- * keeps `deviceId` out of the stream labels for cardinality, so the tag in
7724
- * the body is the only way to filter.
7725
- *
7726
- * A channel whose lines carry the device only in `meta` (or not at all) is
7727
- * declared `false`. Declaring it `true` anyway would be a lie the UI repeats:
7728
- * the operator narrows to one camera, sees nothing, and concludes the code
7729
- * path was never taken.
7730
- */
7731
- perDevice: boolean()
7732
- });
7733
- /**
7734
- * An armed window over one channel, as the document hands it to a mirror.
7735
- *
7736
- * A window is a DEADLINE, never a flag (ADR-0244): a channel somebody forgot
7737
- * expires by itself, which is the one failure a boolean cannot avoid.
7738
- */
7739
- var LogChannelWindowSchema = object({
7740
- channel: string().min(1),
7741
- /** Epoch ms the window closes at. */
7742
- armedUntilMs: number(),
7743
- /** `null` = every camera. A non-empty list narrows to those numeric ids. */
7744
- deviceIds: array(number().int()).readonly().nullable()
7745
- });
7746
- /**
7747
7642
  * Ops-log — the durable, append-only operations audit shared by the
7748
7643
  * recordings and events management surfaces.
7749
7644
  *
@@ -8689,8 +8584,11 @@ var StorageLocationTypeSchema = string().regex(/^[a-z][a-zA-Z0-9-]*$/);
8689
8584
  * `STORAGE_LOCATION_CARDINALITY` map has been removed.
8690
8585
  *
8691
8586
  * `id` is a stable namespaced string of the form `<type>:<slug>`.
8692
- * The default location for a type uses `id === <type>:default` by
8693
- * convention (the bare type ref like `'backups'` resolves to it).
8587
+ * The seed names its first instance `<type>:default` — a NAME, not a flag.
8588
+ * There is no default location any more (D383): `enabled` is the whole write
8589
+ * model, and a bare type ref resolves to the sole location of the type, or —
8590
+ * transitionally, only while legacy NULL-stamped rows exist — to the row whose
8591
+ * slug is `default`.
8694
8592
  *
8695
8593
  * `isSystem` is a legacy persisted flag. Seed still creates the initial
8696
8594
  * `<type>:default` locations; the flag is no longer a lock, a badge, or a
@@ -8711,21 +8609,20 @@ var StorageLocationSchema = object({
8711
8609
  * flag at upsert time, not here (the schema is provider-agnostic).
8712
8610
  */
8713
8611
  nodeId: string().optional(),
8714
- isDefault: boolean().default(false),
8715
8612
  isSystem: boolean().default(false),
8716
8613
  /**
8717
- * Operator opt-in: whether consumers that BALANCE across several locations
8718
- * of a type may write here. Recordings reads it today; event media and
8719
- * backups are the next consumers, which is why the flag lives on the
8720
- * location rather than in any one addon's store — nothing has to be
8721
- * extended to add the next consumer.
8614
+ * THE write switch, and the only one (D383). `enabled: true` means every
8615
+ * consumer that chooses a write target for this type may write here, and all
8616
+ * enabled locations of a type are used TOGETHER; `false` means read-only —
8617
+ * still read, still played back, still age-swept, still drained, never
8618
+ * written.
8722
8619
  *
8723
- * OPTIONAL, and ABSENT MEANS ACTIVE. Every location persisted before the
8724
- * flag existed reads back with no flag and keeps working exactly as before;
8725
- * that is the whole compat story, and it is why no migration ships with it.
8726
- * A newly CREATED sibling is stamped `false` by the orchestrator (creating a
8727
- * disk must not silently start writing to it); the default of a type is
8728
- * always stamped `true`.
8620
+ * OPTIONAL only for the wire: an upsert that omits it means "leave what is
8621
+ * stored" on an update and "born inert unless it is the first location of its
8622
+ * type" on a create. On a PERSISTED row absence is legacy and it means
8623
+ * enabled — {@link isLocationEnabled} is the one place that says so, and the
8624
+ * orchestrator stamps every flagless row `true` once at hydrate so absence
8625
+ * stops existing rather than being re-derived on every read.
8729
8626
  */
8730
8627
  enabled: boolean().optional(),
8731
8628
  /** COMPUTED at read time by the orchestrator (statfs of the backing volume
@@ -8738,10 +8635,12 @@ var StorageLocationSchema = object({
8738
8635
  createdAt: number(),
8739
8636
  updatedAt: number()
8740
8637
  });
8638
+ object({ isDefault: boolean().optional() });
8741
8639
  /**
8742
8640
  * Reference accepted by consumer-facing `api.storage.*` calls.
8743
8641
  * Either:
8744
- * - a `StorageLocationType` (e.g. `'backups'`) → orchestrator resolves to the default of that type
8642
+ * - a `StorageLocationType` (e.g. `'backups'`) → the sole location of that type
8643
+ * (transitionally, the `<type>:default`-slugged row when several exist)
8745
8644
  * - a fully-qualified id (e.g. `'backups:nas-01'`) → addresses a specific instance
8746
8645
  *
8747
8646
  * The orchestrator's `resolveRef(ref)` handles both cases.
@@ -8917,6 +8816,111 @@ var DecoderSessionConfigSchema = object({
8917
8816
  */
8918
8817
  debug: boolean().optional()
8919
8818
  });
8819
+ /**
8820
+ * Per-component log CHANNELS — the gate a hot path consults, and the registry
8821
+ * an addon declares its channels in.
8822
+ *
8823
+ * ## Two axes, deliberately separated
8824
+ *
8825
+ * - **DECLARATION** — which channels exist. Only the addon knows:
8826
+ * `stream-broker` knows webrtc/ICE/RTP, `provider-reolink` knows
8827
+ * baichuan/handshake. A hand-wired central list rots at the first addition,
8828
+ * and rots silently. So a channel is declared where it is consulted, and the
8829
+ * `log-channels` capability enumerates the declarations.
8830
+ * - **VALUE** — at which level, for which scope, until when. That stays ONE
8831
+ * thing: the logging settings document on the `system` cap. Two authorities
8832
+ * over the values is the exact defect
8833
+ * `docs/design/plans/2026-08-26-logging-per-componente.md` was written to
8834
+ * remove; re-introducing it from the cure side would be grotesque.
8835
+ *
8836
+ * Nothing in this file reads a clock, an env var or a store. The registry is
8837
+ * a MIRROR: it is moved only by {@link LogChannelRegistry.apply}, called off
8838
+ * the hot path with a value somebody actually read, and by
8839
+ * {@link LogChannelRegistry.tick}, called on a timer. A store read that fails
8840
+ * never reaches here, so it can neither disarm an armed channel nor arm a
8841
+ * disarmed one (D49).
8842
+ *
8843
+ * ## The canonical call shape
8844
+ *
8845
+ * ```ts
8846
+ * if (CH_RTP.on && CH_RTP.wants(deviceId)) {
8847
+ * CH_RTP.log(logger, 'rtp subscriber added', { tags: { deviceId }, meta: { ssrc } })
8848
+ * }
8849
+ * ```
8850
+ *
8851
+ * `on` is a plain boolean FIELD — never a getter — and it is the FIRST thing
8852
+ * read. Disarmed, a call site costs one load and one branch, and the `extras`
8853
+ * object literal is never constructed because it lives inside the branch. It
8854
+ * is the same shape already proven in production at `stream-broker.ts:1650`,
8855
+ * and the same discipline `LoggingGate.allowsDestination` uses for the
8856
+ * destination floor (measured at 1.93 ns/call when off).
8857
+ *
8858
+ * ## Why a channel emits at `info`
8859
+ *
8860
+ * `loki-logging.addon.ts` pins the destination default at `info` and
8861
+ * `loki-destination.ts` drops everything below it, so a line emitted at
8862
+ * `debug` never reaches Loki and the hub's in-memory ring only holds ~35
8863
+ * minutes. A diagnostic that cannot be read an hour later is worse than no
8864
+ * diagnostic, because it looks done. {@link LogChannelGate.log} therefore
8865
+ * emits at the channel's declared level, whose schema floor is `info`.
8866
+ */
8867
+ /**
8868
+ * The level a channel writes at once armed.
8869
+ *
8870
+ * `debug` is absent ON PURPOSE and not by omission: below `info` the line does
8871
+ * not leave the process for Loki, and the whole point of arming a channel is
8872
+ * to read it later.
8873
+ */
8874
+ var LogChannelLevelSchema = _enum([
8875
+ "info",
8876
+ "warn",
8877
+ "error"
8878
+ ]);
8879
+ /**
8880
+ * What an addon declares about one channel. No value, no state — a
8881
+ * declaration is inert.
8882
+ */
8883
+ var LogChannelDescriptorSchema = object({
8884
+ /**
8885
+ * Dotted `area.thing`, unique across the workspace. `area` is conventionally
8886
+ * the addon's short name so an operator reading a channel list can tell who
8887
+ * owns it without a second lookup.
8888
+ */
8889
+ name: string().min(3).regex(/^[a-z0-9-]+(\.[a-z0-9-]+)+$/, "a channel name is dotted lower-kebab, e.g. area.thing"),
8890
+ /** One sentence: what the operator will SEE after arming it. */
8891
+ description: string().min(1),
8892
+ /** The level its lines are emitted at. Never below `info`. */
8893
+ defaultLevel: LogChannelLevelSchema,
8894
+ /**
8895
+ * Whether this channel can be narrowed to a camera.
8896
+ *
8897
+ * `true` is a PROMISE with two halves, and both must hold: the gate is
8898
+ * consulted with the numeric device id, AND every line the channel admits
8899
+ * carries `tags: { deviceId }` with that same numeric id. The second half is
8900
+ * what makes `| json | deviceId="617"` work in Loki — `loki-payload.ts`
8901
+ * keeps `deviceId` out of the stream labels for cardinality, so the tag in
8902
+ * the body is the only way to filter.
8903
+ *
8904
+ * A channel whose lines carry the device only in `meta` (or not at all) is
8905
+ * declared `false`. Declaring it `true` anyway would be a lie the UI repeats:
8906
+ * the operator narrows to one camera, sees nothing, and concludes the code
8907
+ * path was never taken.
8908
+ */
8909
+ perDevice: boolean()
8910
+ });
8911
+ /**
8912
+ * An armed window over one channel, as the document hands it to a mirror.
8913
+ *
8914
+ * A window is a DEADLINE, never a flag (ADR-0244): a channel somebody forgot
8915
+ * expires by itself, which is the one failure a boolean cannot avoid.
8916
+ */
8917
+ var LogChannelWindowSchema = object({
8918
+ channel: string().min(1),
8919
+ /** Epoch ms the window closes at. */
8920
+ armedUntilMs: number(),
8921
+ /** `null` = every camera. A non-empty list narrows to those numeric ids. */
8922
+ deviceIds: array(number().int()).readonly().nullable()
8923
+ });
8920
8924
  var MODEL_FORMATS = [
8921
8925
  "onnx",
8922
8926
  "coreml",
@@ -21649,7 +21653,7 @@ method(object({
21649
21653
  downloadId: string(),
21650
21654
  offset: number(),
21651
21655
  length: number()
21652
- }), _instanceof(Uint8Array)), method(object({ downloadId: string() }), _void(), { kind: "mutation" }), method(object({ type: StorageLocationTypeSchema.optional() }), array(StorageLocationSchema).readonly()), method(object({ type: StorageLocationTypeSchema }), StorageLocationSchema.nullable()), method(_void(), array(StorageLocationDeclarationSchema).readonly()), method(StorageLocationSchema.omit({
21656
+ }), _instanceof(Uint8Array)), method(object({ downloadId: string() }), _void(), { kind: "mutation" }), method(object({ type: StorageLocationTypeSchema.optional() }), array(StorageLocationSchema).readonly()), method(_void(), array(StorageLocationDeclarationSchema).readonly()), method(StorageLocationSchema.omit({
21653
21657
  createdAt: true,
21654
21658
  updatedAt: true
21655
21659
  }), StorageLocationSchema, {
@@ -34498,12 +34502,6 @@ Object.freeze({
34498
34502
  addonId: null,
34499
34503
  access: "view"
34500
34504
  },
34501
- "storage.getDefaultLocation": {
34502
- capName: "storage",
34503
- capScope: "system",
34504
- addonId: null,
34505
- access: "view"
34506
- },
34507
34505
  "storage.list": {
34508
34506
  capName: "storage",
34509
34507
  capScope: "system",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-mqtt-broker",
3
- "version": "1.2.78",
3
+ "version": "1.2.79",
4
4
  "description": "MQTT broker registry addon for CamStack — manages external broker entries + an optional embedded aedes broker. Consumers spin up their own `mqtt.js` clients via the `mqtt-broker` cap.",
5
5
  "keywords": [
6
6
  "camstack",