@camstack/addon-mqtt-broker 1.2.157 → 1.2.158

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/CHANGELOG.md CHANGED
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.2.158] - 2026-11-09
11
+
12
+ ### Changed
13
+
14
+ - Rebuilt against updated dependencies.
15
+
10
16
  ## [1.2.157] - 2026-11-08
11
17
 
12
18
  ### Changed
@@ -6059,7 +6059,7 @@ var ZodIssueCode = {
6059
6059
  var ZodFirstPartyTypeKind;
6060
6060
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
6061
6061
  //#endregion
6062
- //#region ../types/dist/sleep-CS5Xp1iQ.mjs
6062
+ //#region ../types/dist/sleep-CkinsFFb.mjs
6063
6063
  /**
6064
6064
  * The audio chunk plane's byte format, and the ONE expansion from a coded
6065
6065
  * window to float samples (D455).
@@ -8729,16 +8729,6 @@ var BaseAddon = class {
8729
8729
  return null;
8730
8730
  }
8731
8731
  /**
8732
- * The form schema of ONE integration instance, or `null` to use the scoped form.
8733
- *
8734
- * Override it only when an `instanceMode: multiple` addon's instances differ: an NVR integration
8735
- * needs its connection fields, the default integration the addon's own sections. It is the
8736
- * SHAPE of the form only — the values live on the instance record.
8737
- */
8738
- async integrationFormSchema(_instance) {
8739
- return null;
8740
- }
8741
- /**
8742
8732
  * D986 scoped settings: the form shape of the CLUSTER-wide settings one capability this addon
8743
8733
  * provides owns, or `null` when it has none. `cap` is a capability name the addon's manifest
8744
8734
  * declares. Stored as `addon-settings` rows `<addonId>.<field>`. The keys of this schema, of
@@ -8766,8 +8756,7 @@ var BaseAddon = class {
8766
8756
  }
8767
8757
  /**
8768
8758
  * The host's read of the scoped declarations: the schema one capability declares for `scope`,
8769
- * or `null`. Beside {@link getIntegrationFormSchema}, the same shape: the hook is protected, the
8770
- * host asks this method.
8759
+ * or `null`. The hook is protected, the host asks this method.
8771
8760
  */
8772
8761
  async getScopedSettingsSchema(scope, cap) {
8773
8762
  switch (scope) {
@@ -8935,22 +8924,6 @@ var BaseAddon = class {
8935
8924
  return Object.fromEntries([...collectHydratedFieldValues(form)].filter(([, value]) => value !== void 0));
8936
8925
  }
8937
8926
  /**
8938
- * What the create wizard and the integration edit page render for one instance: the addon's
8939
- * per-instance schema when it declares one, else its global schema (what they always showed).
8940
- */
8941
- async getIntegrationFormSchema(instance, nodeId) {
8942
- const scoped = await this.integrationFormSchema(instance);
8943
- if (scoped === null) return this.scopedForm(nodeId);
8944
- return hydrateSchema(scoped, {}, { inlineSecretsAsViews: true });
8945
- }
8946
- /** The form of the scoped schemas this addon declared, hydrated from its store. */
8947
- async scopedForm(nodeId) {
8948
- await this.loadScopedSchemas();
8949
- const schema = this.scopedFormSchema();
8950
- if (!schema) return { sections: [] };
8951
- return hydrateSchema(schema, await this.readRawProjectedStore(nodeId), { inlineSecretsAsViews: true });
8952
- }
8953
- /**
8954
8927
  * The raw addon store PROJECTED onto the target node's bare per-node keys:
8955
8928
  * every `perNode: true` field carries THAT node's scoped value on its bare
8956
8929
  * key (absent scoped key ⇒ key absent, so the schema `default` wins — no
@@ -9137,12 +9110,6 @@ var BaseAddon = class {
9137
9110
  this._nodeKeysByCap = /* @__PURE__ */ new Map();
9138
9111
  this._addonSecretTree = null;
9139
9112
  }
9140
- /** The form of an addon's scoped schemas: their sections, each shown once. */
9141
- scopedFormSchema(cap) {
9142
- const byId = /* @__PURE__ */ new Map();
9143
- for (const entry of this.loadedScopedSchemas(cap)) for (const section of entry.schema.sections) if (!byId.has(section.id)) byId.set(section.id, section);
9144
- return byId.size === 0 ? null : { sections: [...byId.values()] };
9145
- }
9146
9113
  /** Every loaded scoped schema of `cap`, or of every loaded capability. */
9147
9114
  loadedScopedSchemas(cap) {
9148
9115
  if (cap !== void 0) return this._scopedByCap.get(cap) ?? [];
@@ -9732,6 +9699,10 @@ function normalizeAddonInitResult(result) {
9732
9699
  if (Array.isArray(result)) return { providers: result };
9733
9700
  return result;
9734
9701
  }
9702
+ object({
9703
+ code: string().regex(/^[a-z][a-z0-9-]*(\.[a-z0-9-]+)+$/),
9704
+ params: record(string(), union([string(), number$1()])).optional()
9705
+ });
9735
9706
  object({
9736
9707
  field: string().min(1),
9737
9708
  on: literal("advance")
@@ -9808,12 +9779,6 @@ function systemMethod(input, output, options) {
9808
9779
  systemOnly: true
9809
9780
  };
9810
9781
  }
9811
- /**
9812
- * A method a SOURCE of a collection cap may legitimately not serve — OPTIONAL
9813
- * on `InferProvider`. The `providerOptional: true` literal is what
9814
- * `InferProvider` keys on; see {@link CapabilityMethodSchema.providerOptional}
9815
- * for when this is the honest answer and when it is a soft stub.
9816
- */
9817
9782
  function optionalMethod(input, output, options) {
9818
9783
  return {
9819
9784
  ...method(input, output, options),
@@ -17208,10 +17173,6 @@ Object.freeze({
17208
17173
  "uploadDataset": 72e5
17209
17174
  }
17210
17175
  });
17211
- object({
17212
- code: string().regex(/^[a-z][a-z0-9-]*(\.[a-z0-9-]+)+$/),
17213
- params: record(string(), union([string(), number$1()])).optional()
17214
- });
17215
17176
  //#endregion
17216
17177
  //#region ../types/dist/composition-CXCX78IR.mjs
17217
17178
  /**
@@ -18922,25 +18883,6 @@ var RequiredAddonUpdateSchema = object({
18922
18883
  /** What this node has; `null` when the addon is not installed. */
18923
18884
  installed: string().nullable()
18924
18885
  });
18925
- /**
18926
- * Which integration instance a settings form is for. An addon that serves several instances
18927
- * (`instanceMode: multiple`) can show a different form per instance — an NVR integration
18928
- * needs its connection, the default integration needs the addon's own sections.
18929
- *
18930
- * - `integrationId` is `null` in the create wizard: nothing exists yet, the operator is
18931
- * setting up a NEW instance.
18932
- * - `mode` is the wizard mode of the integration type (`getAvailableTypes`).
18933
- * - `candidateStableId` is the discovery candidate a wizard was seeded from, if any.
18934
- */
18935
- var IntegrationInstanceRefSchema = object({
18936
- integrationId: string().nullable(),
18937
- mode: _enum([
18938
- "standalone",
18939
- "account",
18940
- "broker"
18941
- ]),
18942
- candidateStableId: string().optional()
18943
- });
18944
18886
  /** No part holds the id a call named. */
18945
18887
  var UnknownInstanceError = class extends Error {
18946
18888
  instanceId;
@@ -19001,8 +18943,8 @@ function composeInstanceKinds(parts, base) {
19001
18943
  instanceFormSchema: async ({ id, kind }) => {
19002
18944
  return (id === null ? byKind(kind) : await holderOf(id)).provider.instanceFormSchema({ id });
19003
18945
  },
19004
- listInstances: async () => {
19005
- return (await Promise.all(parts.map(async (part) => (await part.provider.listInstances()).map((instance) => tagged(part, instance))))).flat();
18946
+ listInstances: async (input) => {
18947
+ return (await Promise.all(parts.map(async (part) => (await part.provider.listInstances(input)).map((instance) => tagged(part, instance))))).flat();
19006
18948
  },
19007
18949
  getInstance: async ({ id }) => {
19008
18950
  for (const part of parts) {
@@ -45128,10 +45070,6 @@ method(object({
45128
45070
  scope: ScopedSettingsScopeSchema,
45129
45071
  nodeId: string().optional()
45130
45072
  }), record(string(), unknown()).nullable()), method(object({
45131
- addonId: string(),
45132
- nodeId: string().optional(),
45133
- instance: IntegrationInstanceRefSchema
45134
- }), SettingsSchemaWithValuesSchema.nullable()), method(object({
45135
45073
  addonId: string(),
45136
45074
  nodeId: string().optional()
45137
45075
  }), object({ keys: array(string()) }).nullable(), { auth: "admin" }), method(object({
@@ -47167,7 +47105,14 @@ var CalendarInfoSchema = object({
47167
47105
  id: string().min(1),
47168
47106
  name: string().min(1),
47169
47107
  source: CalendarSourceKindSchema,
47170
- enabled: boolean()
47108
+ enabled: boolean(),
47109
+ /**
47110
+ * The `integration-instances` record that owns this calendar (the record the switch writes).
47111
+ * Every source stamps it from the record it read the calendar from, so a consumer joins on
47112
+ * it instead of rebuilding an id from form values. Optional on the wire so a source addon
47113
+ * that predates the field still lists its calendars: such a row simply has no switch.
47114
+ */
47115
+ instanceId: string().min(1).optional()
47171
47116
  });
47172
47117
  /**
47173
47118
  * Time contract of {@link CalendarEvent}.
@@ -49163,8 +49108,12 @@ var RemoteSourceSchema = discriminatedUnion("kind", [
49163
49108
  object({
49164
49109
  ...sourceBase,
49165
49110
  kind: literal("ir"),
49166
- /** The `ir-transmitter` device the code is sent through. */
49167
- transmitterId: number$1().int().nonnegative(),
49111
+ /**
49112
+ * The `ir-transmitter` device the code is sent through. Absent = the remote's
49113
+ * `defaultTransmitterId` at run time (a source stored before this field was
49114
+ * optional keeps the emitter it names).
49115
+ */
49116
+ transmitterId: number$1().int().nonnegative().optional(),
49168
49117
  /** The code itself; whether a transmitter could send it is `irSourceProblem`. */
49169
49118
  payload: IrPayloadSchema
49170
49119
  })
@@ -55515,6 +55464,12 @@ var IntegrationWithStateSchema = object({
55515
55464
  name: string(),
55516
55465
  /** A projection of the instance body's switch (`setInstanceEnabled` is the only writer). */
55517
55466
  enabled: boolean(),
55467
+ /**
55468
+ * True when the addon that holds the switch did not answer (down, failed, or keeps no record for
55469
+ * this row): `enabled` is then the stored registry flag, a stale value, not the state. A reader
55470
+ * must not draw it as on or off (D315).
55471
+ */
55472
+ switchUnknown: literal(true).optional(),
55518
55473
  info: record(string(), unknown()).readonly(),
55519
55474
  /** The discovery candidate this integration was set up from (D984). */
55520
55475
  originStableId: string().optional(),
@@ -55528,6 +55483,12 @@ var IntegrationLiteSchema = object({
55528
55483
  name: string(),
55529
55484
  /** A projection of the instance body's switch (`setInstanceEnabled` is the only writer). */
55530
55485
  enabled: boolean(),
55486
+ /**
55487
+ * True when the addon that holds the switch did not answer (down, failed, or keeps no record for
55488
+ * this row): `enabled` is then the stored registry flag, a stale value, not the state. A reader
55489
+ * must not draw it as on or off (D315).
55490
+ */
55491
+ switchUnknown: literal(true).optional(),
55531
55492
  info: record(string(), unknown()).readonly(),
55532
55493
  /** The discovery candidate this integration was set up from (D984). */
55533
55494
  originStableId: string().optional(),
@@ -55626,9 +55587,9 @@ var UpdateIntegrationInputSchema = object({
55626
55587
  id: string(),
55627
55588
  name: string().optional(),
55628
55589
  /**
55629
- * Accepted for a FIXED builtin only (`info.fixed`: alarm panel, camera grid, core blocks,
55630
- * terminal), which keeps no instance record: the registry flag is its one store. Any other
55631
- * integration is switched through `integration-instances.setInstanceEnabled`.
55590
+ * Honoured ONLY for a fixed builtin (`info.fixed`), whose switch is the hub's own registry flag
55591
+ * and works while its addon is down. Any other row is refused (a typed `BAD_REQUEST`): its
55592
+ * switch is `integration-instances.setInstanceEnabled`.
55632
55593
  */
55633
55594
  enabled: boolean().optional(),
55634
55595
  info: record(string(), unknown()).optional()
@@ -55662,6 +55623,12 @@ method(_void(), array(IntegrationWithStateSchema)), method(object({ id: string()
55662
55623
  * the form as a `SecretFieldView`, never text (D789). A patch value omitted, `''`
55663
55624
  * or the redaction token KEEPS the stored secret; `{ $secretClear: true }`
55664
55625
  * clears it.
55626
+ *
55627
+ * Who may call (epic #440): every method but `describe` and `instanceFormSchema` is open to any
55628
+ * session (`caller: 'scoped'`) and default-denies. An admin passes everywhere. A non-admin passes
55629
+ * only on a call pinned to one addon whose `describe().userScoped` is true, and that provider
55630
+ * filters every row on the `caller` the router injected (a notification target is somebody's
55631
+ * phone: a user sees and changes only their own). An addon that says nothing keeps the admin door.
55665
55632
  */
55666
55633
  var ConfigSchemaPassthrough$2 = custom();
55667
55634
  var IntegrationInstanceIdSchema = string().min(1);
@@ -55775,7 +55742,15 @@ var IntegrationInstanceDescriptionSchema = object({
55775
55742
  */
55776
55743
  mintsId: boolean().optional(),
55777
55744
  /** The links to other instances the provider's kinds declare; absent means none. */
55778
- links: array(IntegrationInstanceLinkSchema).optional()
55745
+ links: array(IntegrationInstanceLinkSchema).optional(),
55746
+ /**
55747
+ * The rows belong to individual users (a notification target is somebody's phone). The router
55748
+ * then opens `listInstances`, `getInstance`, `createInstance`, `updateInstance`,
55749
+ * `setInstanceEnabled`, `deleteInstance` and `testInstance` to a NON-admin session on a call
55750
+ * pinned to this addon, and hands the provider the `caller` so it keeps a user to their own rows.
55751
+ * Absent means admin only, as it always was.
55752
+ */
55753
+ userScoped: boolean().optional()
55779
55754
  });
55780
55755
  var IntegrationInstanceStatusSchema = object({
55781
55756
  state: _enum([
@@ -55833,8 +55808,14 @@ var integrationInstancesCapability = {
55833
55808
  /** The discovery candidate the wizard was seeded from (`stableId`), if any. */
55834
55809
  candidateStableId: string().min(1).optional()
55835
55810
  }), ConfigSchemaPassthrough$2, { auth: "admin" }),
55836
- listInstances: method(_void(), array(IntegrationInstanceSchema).readonly(), { auth: "admin" }),
55837
- getInstance: method(object({ id: IntegrationInstanceIdSchema }), IntegrationInstanceSchema.nullable(), { auth: "admin" }),
55811
+ listInstances: method(looseObject({}), array(IntegrationInstanceSchema).readonly(), {
55812
+ auth: "protected",
55813
+ caller: "scoped"
55814
+ }),
55815
+ getInstance: method(object({ id: IntegrationInstanceIdSchema }), IntegrationInstanceSchema.nullable(), {
55816
+ auth: "protected",
55817
+ caller: "scoped"
55818
+ }),
55838
55819
  /**
55839
55820
  * Insert the typed record. With `id` it is stored under that id (a duplicate id is refused);
55840
55821
  * without one the PROVIDER mints it and answers it. `kind` picks one of `describe().kinds`.
@@ -55867,11 +55848,13 @@ var integrationInstancesCapability = {
55867
55848
  seed: object({ info: record(string(), unknown()) }).optional()
55868
55849
  }), object({ id: string() }), {
55869
55850
  kind: "mutation",
55870
- auth: "admin"
55851
+ auth: "protected",
55852
+ caller: "scoped"
55871
55853
  }),
55872
55854
  updateInstance: method(IntegrationInstancePatchSchema, object({ ok: literal(true) }), {
55873
55855
  kind: "mutation",
55874
- auth: "admin"
55856
+ auth: "protected",
55857
+ caller: "scoped"
55875
55858
  }),
55876
55859
  /**
55877
55860
  * Switch ONE instance on or off, for every role; a missing record is created from the addon's
@@ -55883,7 +55866,8 @@ var integrationInstancesCapability = {
55883
55866
  enabled: boolean()
55884
55867
  }), object({ ok: literal(true) }), {
55885
55868
  kind: "mutation",
55886
- auth: "admin"
55869
+ auth: "protected",
55870
+ caller: "scoped"
55887
55871
  }),
55888
55872
  /**
55889
55873
  * Delete the record and its keychain refs together. For an instance that brings devices the hub
@@ -55892,7 +55876,8 @@ var integrationInstancesCapability = {
55892
55876
  */
55893
55877
  deleteInstance: method(object({ id: IntegrationInstanceIdSchema }), object({ ok: literal(true) }), {
55894
55878
  kind: "mutation",
55895
- auth: "admin"
55879
+ auth: "protected",
55880
+ caller: "scoped"
55896
55881
  }),
55897
55882
  testInstance: optionalMethod(object({
55898
55883
  id: IntegrationInstanceIdSchema.nullable(),
@@ -55901,7 +55886,8 @@ var integrationInstancesCapability = {
55901
55886
  kind: string().min(1).optional()
55902
55887
  }), TestConnectionResultSchema, {
55903
55888
  kind: "mutation",
55904
- auth: "admin"
55889
+ auth: "protected",
55890
+ caller: "scoped"
55905
55891
  })
55906
55892
  }
55907
55893
  };
@@ -72382,7 +72368,6 @@ var RemoteCustomButtonSchema = object({
72382
72368
  /** What the operator calls it, and what a voice command may name. */
72383
72369
  name: string().min(1).max(60)
72384
72370
  });
72385
- var RemotePowerModeSchema = _enum(["toggle", "discrete"]);
72386
72371
  /**
72387
72372
  * The source rules: every step role is bound, ids and names are unique, a
72388
72373
  * channel number belongs to one `digits` source, and no name or id is another
@@ -72463,7 +72448,6 @@ var RemoteConfigSchema = object({
72463
72448
  sources: array(RemoteSourceSchema).max(200).default([]),
72464
72449
  /** The pause between two steps of a source: the television's receiver, not a repeat. */
72465
72450
  stepDelayMs: number$1().int().min(100).max(REMOTE_STEP_DELAY_MAX_MS).default(500),
72466
- power: object({ mode: RemotePowerModeSchema }),
72467
72451
  /**
72468
72452
  * READ-ONLY: sources a stored configuration carries that no longer parse,
72469
72453
  * left out of `sources` with the reason (`readStoredRemoteConfig`). Never
@@ -72567,6 +72551,11 @@ var RemoteLayoutButtonSchema = object({
72567
72551
  /** Absent = the plain rendering every layout had before shapes existed. */
72568
72552
  shape: RemoteButtonShapeSchema.optional(),
72569
72553
  tone: RemoteButtonToneSchema.optional(),
72554
+ /**
72555
+ * Draw the label on a colour-toned key. A colour key shows only its colour
72556
+ * by default; a remote whose plastic prints letters on them (A B C D) sets it.
72557
+ */
72558
+ showLegend: boolean().optional(),
72570
72559
  /** The group this button belongs to; it must lie inside that group's rectangle. */
72571
72560
  groupId: string().min(1).max(40).optional()
72572
72561
  });
@@ -72704,7 +72693,6 @@ var RemoteBoundCommandSchema = object({
72704
72693
  });
72705
72694
  var RemoteCommandListSchema = object({
72706
72695
  layoutTemplateId: string().nullable(),
72707
- power: object({ mode: RemotePowerModeSchema }),
72708
72696
  /** Only the roles that are BOUND — the ones a press can reach. */
72709
72697
  commands: array(RemoteBoundCommandSchema),
72710
72698
  /** The sources the operator declared; empty when none (planning#460). */
@@ -72717,7 +72705,8 @@ var RemoteRefusalReasonSchema = _enum([
72717
72705
  "unknown-source",
72718
72706
  "unbound-step",
72719
72707
  "undeclared-channel",
72720
- "press-timeout"
72708
+ "press-timeout",
72709
+ "no-transmitter"
72721
72710
  ]);
72722
72711
  var RemoteSendResultSchema = discriminatedUnion("status", [
72723
72712
  object({
@@ -72810,7 +72799,8 @@ var RemoteComponentButtonSchema = object({
72810
72799
  icon: string().min(1).max(60).optional(),
72811
72800
  label: string().min(1).max(40).optional(),
72812
72801
  shape: RemoteButtonShapeSchema.optional(),
72813
- tone: RemoteButtonToneSchema.optional()
72802
+ tone: RemoteButtonToneSchema.optional(),
72803
+ showLegend: boolean().optional()
72814
72804
  });
72815
72805
  var RemoteLayoutComponentSchema = object({
72816
72806
  id: string().max(80).regex(COMPONENT_ID_RE, { message: "<namespace>:<name>, lowercase" }),
@@ -73765,6 +73755,11 @@ var SendEmailResultSchema = object({
73765
73755
  var SmtpStatusSchema = object({
73766
73756
  /** True iff the addon has successfully verified the relay. */
73767
73757
  ready: boolean(),
73758
+ /**
73759
+ * The tri-state behind `ready` (D315): true when the last send worked, false when it failed,
73760
+ * ABSENT when the relay has not sent yet (unknown, never "not verified").
73761
+ */
73762
+ verified: boolean().optional(),
73768
73763
  /** Operator-visible host string (no credentials). */
73769
73764
  host: string(),
73770
73765
  /** Last error message reported by the relay, when not ready. */
@@ -73776,10 +73771,6 @@ method(SendEmailInputSchema, SendEmailResultSchema, {
73776
73771
  kind: "mutation",
73777
73772
  auth: "admin",
73778
73773
  access: "create"
73779
- }), method(RelayPinSchema, SmtpStatusSchema, {
73780
- kind: "mutation",
73781
- auth: "admin",
73782
- access: "view"
73783
73774
  }), method(RelayPinSchema, SmtpStatusSchema, { auth: "admin" });
73784
73775
  /**
73785
73776
  * A single device snapshot returned as base64 JPEG/PNG.
@@ -80448,13 +80439,6 @@ Object.freeze({
80448
80439
  access: "view",
80449
80440
  role: "admin"
80450
80441
  },
80451
- "addonSettings.getIntegrationFormSchema": {
80452
- capName: "addon-settings",
80453
- capScope: "system",
80454
- addonId: null,
80455
- access: "view",
80456
- role: "admin"
80457
- },
80458
80442
  "addonSettings.getScopedSettings": {
80459
80443
  capName: "addon-settings",
80460
80444
  capScope: "system",
@@ -88477,13 +88461,6 @@ Object.freeze({
88477
88461
  access: "create",
88478
88462
  role: "admin"
88479
88463
  },
88480
- "smtpProvider.verify": {
88481
- capName: "smtp-provider",
88482
- capScope: "system",
88483
- addonId: null,
88484
- access: "view",
88485
- role: "admin"
88486
- },
88487
88464
  "snapshot.applyDeviceSettingsPatch": {
88488
88465
  capName: "snapshot",
88489
88466
  capScope: "device",
@@ -6052,7 +6052,7 @@ var ZodIssueCode = {
6052
6052
  var ZodFirstPartyTypeKind;
6053
6053
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
6054
6054
  //#endregion
6055
- //#region ../types/dist/sleep-CS5Xp1iQ.mjs
6055
+ //#region ../types/dist/sleep-CkinsFFb.mjs
6056
6056
  /**
6057
6057
  * The audio chunk plane's byte format, and the ONE expansion from a coded
6058
6058
  * window to float samples (D455).
@@ -8722,16 +8722,6 @@ var BaseAddon = class {
8722
8722
  return null;
8723
8723
  }
8724
8724
  /**
8725
- * The form schema of ONE integration instance, or `null` to use the scoped form.
8726
- *
8727
- * Override it only when an `instanceMode: multiple` addon's instances differ: an NVR integration
8728
- * needs its connection fields, the default integration the addon's own sections. It is the
8729
- * SHAPE of the form only — the values live on the instance record.
8730
- */
8731
- async integrationFormSchema(_instance) {
8732
- return null;
8733
- }
8734
- /**
8735
8725
  * D986 scoped settings: the form shape of the CLUSTER-wide settings one capability this addon
8736
8726
  * provides owns, or `null` when it has none. `cap` is a capability name the addon's manifest
8737
8727
  * declares. Stored as `addon-settings` rows `<addonId>.<field>`. The keys of this schema, of
@@ -8759,8 +8749,7 @@ var BaseAddon = class {
8759
8749
  }
8760
8750
  /**
8761
8751
  * The host's read of the scoped declarations: the schema one capability declares for `scope`,
8762
- * or `null`. Beside {@link getIntegrationFormSchema}, the same shape: the hook is protected, the
8763
- * host asks this method.
8752
+ * or `null`. The hook is protected, the host asks this method.
8764
8753
  */
8765
8754
  async getScopedSettingsSchema(scope, cap) {
8766
8755
  switch (scope) {
@@ -8928,22 +8917,6 @@ var BaseAddon = class {
8928
8917
  return Object.fromEntries([...collectHydratedFieldValues(form)].filter(([, value]) => value !== void 0));
8929
8918
  }
8930
8919
  /**
8931
- * What the create wizard and the integration edit page render for one instance: the addon's
8932
- * per-instance schema when it declares one, else its global schema (what they always showed).
8933
- */
8934
- async getIntegrationFormSchema(instance, nodeId) {
8935
- const scoped = await this.integrationFormSchema(instance);
8936
- if (scoped === null) return this.scopedForm(nodeId);
8937
- return hydrateSchema(scoped, {}, { inlineSecretsAsViews: true });
8938
- }
8939
- /** The form of the scoped schemas this addon declared, hydrated from its store. */
8940
- async scopedForm(nodeId) {
8941
- await this.loadScopedSchemas();
8942
- const schema = this.scopedFormSchema();
8943
- if (!schema) return { sections: [] };
8944
- return hydrateSchema(schema, await this.readRawProjectedStore(nodeId), { inlineSecretsAsViews: true });
8945
- }
8946
- /**
8947
8920
  * The raw addon store PROJECTED onto the target node's bare per-node keys:
8948
8921
  * every `perNode: true` field carries THAT node's scoped value on its bare
8949
8922
  * key (absent scoped key ⇒ key absent, so the schema `default` wins — no
@@ -9130,12 +9103,6 @@ var BaseAddon = class {
9130
9103
  this._nodeKeysByCap = /* @__PURE__ */ new Map();
9131
9104
  this._addonSecretTree = null;
9132
9105
  }
9133
- /** The form of an addon's scoped schemas: their sections, each shown once. */
9134
- scopedFormSchema(cap) {
9135
- const byId = /* @__PURE__ */ new Map();
9136
- for (const entry of this.loadedScopedSchemas(cap)) for (const section of entry.schema.sections) if (!byId.has(section.id)) byId.set(section.id, section);
9137
- return byId.size === 0 ? null : { sections: [...byId.values()] };
9138
- }
9139
9106
  /** Every loaded scoped schema of `cap`, or of every loaded capability. */
9140
9107
  loadedScopedSchemas(cap) {
9141
9108
  if (cap !== void 0) return this._scopedByCap.get(cap) ?? [];
@@ -9725,6 +9692,10 @@ function normalizeAddonInitResult(result) {
9725
9692
  if (Array.isArray(result)) return { providers: result };
9726
9693
  return result;
9727
9694
  }
9695
+ object({
9696
+ code: string().regex(/^[a-z][a-z0-9-]*(\.[a-z0-9-]+)+$/),
9697
+ params: record(string(), union([string(), number$1()])).optional()
9698
+ });
9728
9699
  object({
9729
9700
  field: string().min(1),
9730
9701
  on: literal("advance")
@@ -9801,12 +9772,6 @@ function systemMethod(input, output, options) {
9801
9772
  systemOnly: true
9802
9773
  };
9803
9774
  }
9804
- /**
9805
- * A method a SOURCE of a collection cap may legitimately not serve — OPTIONAL
9806
- * on `InferProvider`. The `providerOptional: true` literal is what
9807
- * `InferProvider` keys on; see {@link CapabilityMethodSchema.providerOptional}
9808
- * for when this is the honest answer and when it is a soft stub.
9809
- */
9810
9775
  function optionalMethod(input, output, options) {
9811
9776
  return {
9812
9777
  ...method(input, output, options),
@@ -17201,10 +17166,6 @@ Object.freeze({
17201
17166
  "uploadDataset": 72e5
17202
17167
  }
17203
17168
  });
17204
- object({
17205
- code: string().regex(/^[a-z][a-z0-9-]*(\.[a-z0-9-]+)+$/),
17206
- params: record(string(), union([string(), number$1()])).optional()
17207
- });
17208
17169
  //#endregion
17209
17170
  //#region ../types/dist/composition-CXCX78IR.mjs
17210
17171
  /**
@@ -18915,25 +18876,6 @@ var RequiredAddonUpdateSchema = object({
18915
18876
  /** What this node has; `null` when the addon is not installed. */
18916
18877
  installed: string().nullable()
18917
18878
  });
18918
- /**
18919
- * Which integration instance a settings form is for. An addon that serves several instances
18920
- * (`instanceMode: multiple`) can show a different form per instance — an NVR integration
18921
- * needs its connection, the default integration needs the addon's own sections.
18922
- *
18923
- * - `integrationId` is `null` in the create wizard: nothing exists yet, the operator is
18924
- * setting up a NEW instance.
18925
- * - `mode` is the wizard mode of the integration type (`getAvailableTypes`).
18926
- * - `candidateStableId` is the discovery candidate a wizard was seeded from, if any.
18927
- */
18928
- var IntegrationInstanceRefSchema = object({
18929
- integrationId: string().nullable(),
18930
- mode: _enum([
18931
- "standalone",
18932
- "account",
18933
- "broker"
18934
- ]),
18935
- candidateStableId: string().optional()
18936
- });
18937
18879
  /** No part holds the id a call named. */
18938
18880
  var UnknownInstanceError = class extends Error {
18939
18881
  instanceId;
@@ -18994,8 +18936,8 @@ function composeInstanceKinds(parts, base) {
18994
18936
  instanceFormSchema: async ({ id, kind }) => {
18995
18937
  return (id === null ? byKind(kind) : await holderOf(id)).provider.instanceFormSchema({ id });
18996
18938
  },
18997
- listInstances: async () => {
18998
- return (await Promise.all(parts.map(async (part) => (await part.provider.listInstances()).map((instance) => tagged(part, instance))))).flat();
18939
+ listInstances: async (input) => {
18940
+ return (await Promise.all(parts.map(async (part) => (await part.provider.listInstances(input)).map((instance) => tagged(part, instance))))).flat();
18999
18941
  },
19000
18942
  getInstance: async ({ id }) => {
19001
18943
  for (const part of parts) {
@@ -45121,10 +45063,6 @@ method(object({
45121
45063
  scope: ScopedSettingsScopeSchema,
45122
45064
  nodeId: string().optional()
45123
45065
  }), record(string(), unknown()).nullable()), method(object({
45124
- addonId: string(),
45125
- nodeId: string().optional(),
45126
- instance: IntegrationInstanceRefSchema
45127
- }), SettingsSchemaWithValuesSchema.nullable()), method(object({
45128
45066
  addonId: string(),
45129
45067
  nodeId: string().optional()
45130
45068
  }), object({ keys: array(string()) }).nullable(), { auth: "admin" }), method(object({
@@ -47160,7 +47098,14 @@ var CalendarInfoSchema = object({
47160
47098
  id: string().min(1),
47161
47099
  name: string().min(1),
47162
47100
  source: CalendarSourceKindSchema,
47163
- enabled: boolean()
47101
+ enabled: boolean(),
47102
+ /**
47103
+ * The `integration-instances` record that owns this calendar (the record the switch writes).
47104
+ * Every source stamps it from the record it read the calendar from, so a consumer joins on
47105
+ * it instead of rebuilding an id from form values. Optional on the wire so a source addon
47106
+ * that predates the field still lists its calendars: such a row simply has no switch.
47107
+ */
47108
+ instanceId: string().min(1).optional()
47164
47109
  });
47165
47110
  /**
47166
47111
  * Time contract of {@link CalendarEvent}.
@@ -49156,8 +49101,12 @@ var RemoteSourceSchema = discriminatedUnion("kind", [
49156
49101
  object({
49157
49102
  ...sourceBase,
49158
49103
  kind: literal("ir"),
49159
- /** The `ir-transmitter` device the code is sent through. */
49160
- transmitterId: number$1().int().nonnegative(),
49104
+ /**
49105
+ * The `ir-transmitter` device the code is sent through. Absent = the remote's
49106
+ * `defaultTransmitterId` at run time (a source stored before this field was
49107
+ * optional keeps the emitter it names).
49108
+ */
49109
+ transmitterId: number$1().int().nonnegative().optional(),
49161
49110
  /** The code itself; whether a transmitter could send it is `irSourceProblem`. */
49162
49111
  payload: IrPayloadSchema
49163
49112
  })
@@ -55508,6 +55457,12 @@ var IntegrationWithStateSchema = object({
55508
55457
  name: string(),
55509
55458
  /** A projection of the instance body's switch (`setInstanceEnabled` is the only writer). */
55510
55459
  enabled: boolean(),
55460
+ /**
55461
+ * True when the addon that holds the switch did not answer (down, failed, or keeps no record for
55462
+ * this row): `enabled` is then the stored registry flag, a stale value, not the state. A reader
55463
+ * must not draw it as on or off (D315).
55464
+ */
55465
+ switchUnknown: literal(true).optional(),
55511
55466
  info: record(string(), unknown()).readonly(),
55512
55467
  /** The discovery candidate this integration was set up from (D984). */
55513
55468
  originStableId: string().optional(),
@@ -55521,6 +55476,12 @@ var IntegrationLiteSchema = object({
55521
55476
  name: string(),
55522
55477
  /** A projection of the instance body's switch (`setInstanceEnabled` is the only writer). */
55523
55478
  enabled: boolean(),
55479
+ /**
55480
+ * True when the addon that holds the switch did not answer (down, failed, or keeps no record for
55481
+ * this row): `enabled` is then the stored registry flag, a stale value, not the state. A reader
55482
+ * must not draw it as on or off (D315).
55483
+ */
55484
+ switchUnknown: literal(true).optional(),
55524
55485
  info: record(string(), unknown()).readonly(),
55525
55486
  /** The discovery candidate this integration was set up from (D984). */
55526
55487
  originStableId: string().optional(),
@@ -55619,9 +55580,9 @@ var UpdateIntegrationInputSchema = object({
55619
55580
  id: string(),
55620
55581
  name: string().optional(),
55621
55582
  /**
55622
- * Accepted for a FIXED builtin only (`info.fixed`: alarm panel, camera grid, core blocks,
55623
- * terminal), which keeps no instance record: the registry flag is its one store. Any other
55624
- * integration is switched through `integration-instances.setInstanceEnabled`.
55583
+ * Honoured ONLY for a fixed builtin (`info.fixed`), whose switch is the hub's own registry flag
55584
+ * and works while its addon is down. Any other row is refused (a typed `BAD_REQUEST`): its
55585
+ * switch is `integration-instances.setInstanceEnabled`.
55625
55586
  */
55626
55587
  enabled: boolean().optional(),
55627
55588
  info: record(string(), unknown()).optional()
@@ -55655,6 +55616,12 @@ method(_void(), array(IntegrationWithStateSchema)), method(object({ id: string()
55655
55616
  * the form as a `SecretFieldView`, never text (D789). A patch value omitted, `''`
55656
55617
  * or the redaction token KEEPS the stored secret; `{ $secretClear: true }`
55657
55618
  * clears it.
55619
+ *
55620
+ * Who may call (epic #440): every method but `describe` and `instanceFormSchema` is open to any
55621
+ * session (`caller: 'scoped'`) and default-denies. An admin passes everywhere. A non-admin passes
55622
+ * only on a call pinned to one addon whose `describe().userScoped` is true, and that provider
55623
+ * filters every row on the `caller` the router injected (a notification target is somebody's
55624
+ * phone: a user sees and changes only their own). An addon that says nothing keeps the admin door.
55658
55625
  */
55659
55626
  var ConfigSchemaPassthrough$2 = custom();
55660
55627
  var IntegrationInstanceIdSchema = string().min(1);
@@ -55768,7 +55735,15 @@ var IntegrationInstanceDescriptionSchema = object({
55768
55735
  */
55769
55736
  mintsId: boolean().optional(),
55770
55737
  /** The links to other instances the provider's kinds declare; absent means none. */
55771
- links: array(IntegrationInstanceLinkSchema).optional()
55738
+ links: array(IntegrationInstanceLinkSchema).optional(),
55739
+ /**
55740
+ * The rows belong to individual users (a notification target is somebody's phone). The router
55741
+ * then opens `listInstances`, `getInstance`, `createInstance`, `updateInstance`,
55742
+ * `setInstanceEnabled`, `deleteInstance` and `testInstance` to a NON-admin session on a call
55743
+ * pinned to this addon, and hands the provider the `caller` so it keeps a user to their own rows.
55744
+ * Absent means admin only, as it always was.
55745
+ */
55746
+ userScoped: boolean().optional()
55772
55747
  });
55773
55748
  var IntegrationInstanceStatusSchema = object({
55774
55749
  state: _enum([
@@ -55826,8 +55801,14 @@ var integrationInstancesCapability = {
55826
55801
  /** The discovery candidate the wizard was seeded from (`stableId`), if any. */
55827
55802
  candidateStableId: string().min(1).optional()
55828
55803
  }), ConfigSchemaPassthrough$2, { auth: "admin" }),
55829
- listInstances: method(_void(), array(IntegrationInstanceSchema).readonly(), { auth: "admin" }),
55830
- getInstance: method(object({ id: IntegrationInstanceIdSchema }), IntegrationInstanceSchema.nullable(), { auth: "admin" }),
55804
+ listInstances: method(looseObject({}), array(IntegrationInstanceSchema).readonly(), {
55805
+ auth: "protected",
55806
+ caller: "scoped"
55807
+ }),
55808
+ getInstance: method(object({ id: IntegrationInstanceIdSchema }), IntegrationInstanceSchema.nullable(), {
55809
+ auth: "protected",
55810
+ caller: "scoped"
55811
+ }),
55831
55812
  /**
55832
55813
  * Insert the typed record. With `id` it is stored under that id (a duplicate id is refused);
55833
55814
  * without one the PROVIDER mints it and answers it. `kind` picks one of `describe().kinds`.
@@ -55860,11 +55841,13 @@ var integrationInstancesCapability = {
55860
55841
  seed: object({ info: record(string(), unknown()) }).optional()
55861
55842
  }), object({ id: string() }), {
55862
55843
  kind: "mutation",
55863
- auth: "admin"
55844
+ auth: "protected",
55845
+ caller: "scoped"
55864
55846
  }),
55865
55847
  updateInstance: method(IntegrationInstancePatchSchema, object({ ok: literal(true) }), {
55866
55848
  kind: "mutation",
55867
- auth: "admin"
55849
+ auth: "protected",
55850
+ caller: "scoped"
55868
55851
  }),
55869
55852
  /**
55870
55853
  * Switch ONE instance on or off, for every role; a missing record is created from the addon's
@@ -55876,7 +55859,8 @@ var integrationInstancesCapability = {
55876
55859
  enabled: boolean()
55877
55860
  }), object({ ok: literal(true) }), {
55878
55861
  kind: "mutation",
55879
- auth: "admin"
55862
+ auth: "protected",
55863
+ caller: "scoped"
55880
55864
  }),
55881
55865
  /**
55882
55866
  * Delete the record and its keychain refs together. For an instance that brings devices the hub
@@ -55885,7 +55869,8 @@ var integrationInstancesCapability = {
55885
55869
  */
55886
55870
  deleteInstance: method(object({ id: IntegrationInstanceIdSchema }), object({ ok: literal(true) }), {
55887
55871
  kind: "mutation",
55888
- auth: "admin"
55872
+ auth: "protected",
55873
+ caller: "scoped"
55889
55874
  }),
55890
55875
  testInstance: optionalMethod(object({
55891
55876
  id: IntegrationInstanceIdSchema.nullable(),
@@ -55894,7 +55879,8 @@ var integrationInstancesCapability = {
55894
55879
  kind: string().min(1).optional()
55895
55880
  }), TestConnectionResultSchema, {
55896
55881
  kind: "mutation",
55897
- auth: "admin"
55882
+ auth: "protected",
55883
+ caller: "scoped"
55898
55884
  })
55899
55885
  }
55900
55886
  };
@@ -72375,7 +72361,6 @@ var RemoteCustomButtonSchema = object({
72375
72361
  /** What the operator calls it, and what a voice command may name. */
72376
72362
  name: string().min(1).max(60)
72377
72363
  });
72378
- var RemotePowerModeSchema = _enum(["toggle", "discrete"]);
72379
72364
  /**
72380
72365
  * The source rules: every step role is bound, ids and names are unique, a
72381
72366
  * channel number belongs to one `digits` source, and no name or id is another
@@ -72456,7 +72441,6 @@ var RemoteConfigSchema = object({
72456
72441
  sources: array(RemoteSourceSchema).max(200).default([]),
72457
72442
  /** The pause between two steps of a source: the television's receiver, not a repeat. */
72458
72443
  stepDelayMs: number$1().int().min(100).max(REMOTE_STEP_DELAY_MAX_MS).default(500),
72459
- power: object({ mode: RemotePowerModeSchema }),
72460
72444
  /**
72461
72445
  * READ-ONLY: sources a stored configuration carries that no longer parse,
72462
72446
  * left out of `sources` with the reason (`readStoredRemoteConfig`). Never
@@ -72560,6 +72544,11 @@ var RemoteLayoutButtonSchema = object({
72560
72544
  /** Absent = the plain rendering every layout had before shapes existed. */
72561
72545
  shape: RemoteButtonShapeSchema.optional(),
72562
72546
  tone: RemoteButtonToneSchema.optional(),
72547
+ /**
72548
+ * Draw the label on a colour-toned key. A colour key shows only its colour
72549
+ * by default; a remote whose plastic prints letters on them (A B C D) sets it.
72550
+ */
72551
+ showLegend: boolean().optional(),
72563
72552
  /** The group this button belongs to; it must lie inside that group's rectangle. */
72564
72553
  groupId: string().min(1).max(40).optional()
72565
72554
  });
@@ -72697,7 +72686,6 @@ var RemoteBoundCommandSchema = object({
72697
72686
  });
72698
72687
  var RemoteCommandListSchema = object({
72699
72688
  layoutTemplateId: string().nullable(),
72700
- power: object({ mode: RemotePowerModeSchema }),
72701
72689
  /** Only the roles that are BOUND — the ones a press can reach. */
72702
72690
  commands: array(RemoteBoundCommandSchema),
72703
72691
  /** The sources the operator declared; empty when none (planning#460). */
@@ -72710,7 +72698,8 @@ var RemoteRefusalReasonSchema = _enum([
72710
72698
  "unknown-source",
72711
72699
  "unbound-step",
72712
72700
  "undeclared-channel",
72713
- "press-timeout"
72701
+ "press-timeout",
72702
+ "no-transmitter"
72714
72703
  ]);
72715
72704
  var RemoteSendResultSchema = discriminatedUnion("status", [
72716
72705
  object({
@@ -72803,7 +72792,8 @@ var RemoteComponentButtonSchema = object({
72803
72792
  icon: string().min(1).max(60).optional(),
72804
72793
  label: string().min(1).max(40).optional(),
72805
72794
  shape: RemoteButtonShapeSchema.optional(),
72806
- tone: RemoteButtonToneSchema.optional()
72795
+ tone: RemoteButtonToneSchema.optional(),
72796
+ showLegend: boolean().optional()
72807
72797
  });
72808
72798
  var RemoteLayoutComponentSchema = object({
72809
72799
  id: string().max(80).regex(COMPONENT_ID_RE, { message: "<namespace>:<name>, lowercase" }),
@@ -73758,6 +73748,11 @@ var SendEmailResultSchema = object({
73758
73748
  var SmtpStatusSchema = object({
73759
73749
  /** True iff the addon has successfully verified the relay. */
73760
73750
  ready: boolean(),
73751
+ /**
73752
+ * The tri-state behind `ready` (D315): true when the last send worked, false when it failed,
73753
+ * ABSENT when the relay has not sent yet (unknown, never "not verified").
73754
+ */
73755
+ verified: boolean().optional(),
73761
73756
  /** Operator-visible host string (no credentials). */
73762
73757
  host: string(),
73763
73758
  /** Last error message reported by the relay, when not ready. */
@@ -73769,10 +73764,6 @@ method(SendEmailInputSchema, SendEmailResultSchema, {
73769
73764
  kind: "mutation",
73770
73765
  auth: "admin",
73771
73766
  access: "create"
73772
- }), method(RelayPinSchema, SmtpStatusSchema, {
73773
- kind: "mutation",
73774
- auth: "admin",
73775
- access: "view"
73776
73767
  }), method(RelayPinSchema, SmtpStatusSchema, { auth: "admin" });
73777
73768
  /**
73778
73769
  * A single device snapshot returned as base64 JPEG/PNG.
@@ -80441,13 +80432,6 @@ Object.freeze({
80441
80432
  access: "view",
80442
80433
  role: "admin"
80443
80434
  },
80444
- "addonSettings.getIntegrationFormSchema": {
80445
- capName: "addon-settings",
80446
- capScope: "system",
80447
- addonId: null,
80448
- access: "view",
80449
- role: "admin"
80450
- },
80451
80435
  "addonSettings.getScopedSettings": {
80452
80436
  capName: "addon-settings",
80453
80437
  capScope: "system",
@@ -88470,13 +88454,6 @@ Object.freeze({
88470
88454
  access: "create",
88471
88455
  role: "admin"
88472
88456
  },
88473
- "smtpProvider.verify": {
88474
- capName: "smtp-provider",
88475
- capScope: "system",
88476
- addonId: null,
88477
- access: "view",
88478
- role: "admin"
88479
- },
88480
88457
  "snapshot.applyDeviceSettingsPatch": {
88481
88458
  capName: "snapshot",
88482
88459
  capScope: "device",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-mqtt-broker",
3
- "version": "1.2.157",
3
+ "version": "1.2.158",
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",
@@ -60,7 +60,7 @@
60
60
  "aedes"
61
61
  ],
62
62
  "requires": {
63
- "server": ">=1.2.817"
63
+ "server": ">=1.2.820"
64
64
  }
65
65
  },
66
66
  "files": [