@camstack/addon-osd-manager 0.1.167 → 0.1.169

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.
Files changed (19) hide show
  1. package/dist/{MotionZonesSettings-BS0B2G3Q.mjs → MotionZonesSettings-CTFqdJfp.mjs} +2 -2
  2. package/dist/{PrivacyMaskSettings-DLJ0DHZT.mjs → PrivacyMaskSettings-M3LLrSyZ.mjs} +4 -4
  3. package/dist/{SceneMonitorEditor-CDDYaoCX.mjs → SceneMonitorEditor-BWTOg6t0.mjs} +3 -3
  4. package/dist/_stub.js +3124 -3039
  5. package/dist/{_virtual_mf-localSharedImportMap___mfe_internal__addon_osd_manager_page-B4Z53O4w.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_osd_manager_page-CW_hXAxF.mjs} +4 -4
  6. package/dist/_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-B4GSezZ1.mjs +26 -0
  7. package/dist/addon-osd-manager.css +1 -1
  8. package/dist/{hostInit-K1eoWfNR.mjs → hostInit-AjcCWOye.mjs} +3 -3
  9. package/dist/index.js +153 -13
  10. package/dist/index.mjs +153 -13
  11. package/dist/{player-overlays-BX9_cgYi.mjs → player-overlays-DBi0aH1E.mjs} +1 -1
  12. package/dist/remoteEntry.js +1 -1
  13. package/dist/{responsive-DQHzOXvm.mjs → responsive-BoQdxzOM.mjs} +1 -1
  14. package/dist/{scene-monitor-copy-CVQQynEG.mjs → scene-monitor-copy-CwfDunLo.mjs} +1 -1
  15. package/dist/{square-BjnEKMWp.mjs → square-C-adTToZ.mjs} +1 -1
  16. package/dist/{trash-2-CUYOgymv.mjs → trash-2-DJjBuL5Q.mjs} +1 -1
  17. package/dist/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_osd_manager_page__remoteEntry_js-C2WG2Ab3.mjs → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_osd_manager_page__remoteEntry_js-T0PnCKpV.mjs} +1 -1
  18. package/package.json +1 -1
  19. package/dist/_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BZTcxI6n.mjs +0 -26
package/dist/index.js CHANGED
@@ -5382,7 +5382,7 @@ var ZodIssueCode = {
5382
5382
  var ZodFirstPartyTypeKind;
5383
5383
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5384
5384
  //#endregion
5385
- //#region ../types/dist/sleep-CDCONfkt.mjs
5385
+ //#region ../types/dist/sleep-DXKLNFvA.mjs
5386
5386
  /**
5387
5387
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5388
5388
  * window to float samples (D455).
@@ -5690,6 +5690,43 @@ function hydrateField(field, values) {
5690
5690
  }
5691
5691
  const rawValue = storedValue !== void 0 ? storedValue : defaultValue !== void 0 ? defaultValue : null;
5692
5692
  const value = field.type === "textarea" && field.isJson && rawValue !== null && typeof rawValue === "object" ? JSON.stringify(rawValue, null, 2) : rawValue;
5693
+ if (field.type === "tags" && typeof field.suggestionsFrom === "string") {
5694
+ const from = values[field.suggestionsFrom];
5695
+ const extra = Array.isArray(from) ? from.filter((s) => typeof s === "string" && s.length > 0) : [];
5696
+ const merged = [...new Set([...field.suggestions ?? [], ...extra])];
5697
+ return {
5698
+ ...field,
5699
+ suggestions: merged,
5700
+ value
5701
+ };
5702
+ }
5703
+ if ((field.type === "select" || field.type === "multiselect") && typeof field.optionsFrom === "string") {
5704
+ const from = values[field.optionsFrom];
5705
+ const byValue = /* @__PURE__ */ new Map();
5706
+ for (const opt of field.options) byValue.set(opt.value, opt);
5707
+ if (Array.isArray(from)) for (const entry of from) {
5708
+ if (typeof entry === "string" && entry.length > 0) {
5709
+ if (!byValue.has(entry)) byValue.set(entry, {
5710
+ value: entry,
5711
+ label: entry
5712
+ });
5713
+ continue;
5714
+ }
5715
+ if (entry === null || typeof entry !== "object") continue;
5716
+ const v = Reflect.get(entry, "value");
5717
+ const lbl = Reflect.get(entry, "label");
5718
+ if (typeof v !== "string" || v.length === 0) continue;
5719
+ if (!byValue.has(v)) byValue.set(v, {
5720
+ value: v,
5721
+ label: typeof lbl === "string" && lbl.length > 0 ? lbl : v
5722
+ });
5723
+ }
5724
+ return {
5725
+ ...field,
5726
+ options: [...byValue.values()],
5727
+ value
5728
+ };
5729
+ }
5693
5730
  return {
5694
5731
  ...field,
5695
5732
  value
@@ -10994,7 +11031,16 @@ var AutomationActionSchema = discriminatedUnion("kind", [
10994
11031
  }),
10995
11032
  object({
10996
11033
  kind: literal("cap"),
10997
- deviceId: union([number().int(), object({ $var: string().min(1) })]),
11034
+ /**
11035
+ * One device, several same-family devices (locks / climate family / …),
11036
+ * or `{ $var }` for the device that triggered the run. An array is
11037
+ * fan-out at codegen — each id gets the same cap.method call.
11038
+ */
11039
+ deviceId: union([
11040
+ number().int(),
11041
+ array(number().int()).min(1),
11042
+ object({ $var: string().min(1) })
11043
+ ]),
10998
11044
  cap: string().min(1),
10999
11045
  method: string().min(1),
11000
11046
  /** Values may carry `{{vars.x}}` slots, which SUBSTITUTE and do not
@@ -15435,7 +15481,7 @@ var detectionPipelineCapability = {
15435
15481
  * This matters here more than anywhere else in the repo, because every provider
15436
15482
  * that knows a device's host knows its PASSWORD too: `{ host, port, username,
15437
15483
  * password }` sit in one object on Hikvision, Amcrest, Reolink and ONVIF alike,
15438
- * and `http://admin:hunter2@192.168.50.139/` is a URL a browser accepts. The
15484
+ * and `http://admin:hunter2@192.168.x.x/` is a URL a browser accepts. The
15439
15485
  * camera's own page will ask for its own login. That is correct, and pre-
15440
15486
  * filling it is the operator's business, not ours.
15441
15487
  *
@@ -20279,6 +20325,17 @@ var SendResultSchema = object({
20279
20325
  });
20280
20326
  /** Same shape as SendResult — kept as a distinct name for the test panel. */
20281
20327
  var TestResultSchema = SendResultSchema;
20328
+ /**
20329
+ * Pre-save credential probe against a partial (unsaved) target config.
20330
+ * `resolvedUrl` never includes secrets (token stripped from path).
20331
+ */
20332
+ var ProbeTargetConfigResultSchema = object({
20333
+ ok: boolean(),
20334
+ resolvedUrl: string(),
20335
+ httpStatus: number().int().optional(),
20336
+ stateInstance: string().optional(),
20337
+ error: string().optional()
20338
+ });
20282
20339
  var notificationOutputCapability = {
20283
20340
  name: "notification-output",
20284
20341
  scope: "system",
@@ -20286,10 +20343,32 @@ var notificationOutputCapability = {
20286
20343
  methods: {
20287
20344
  listTargetKinds: method(object({}), array(TargetKindSchema)),
20288
20345
  listTargets: method(object({}), array(TargetSchema), { auth: "admin" }),
20346
+ /**
20347
+ * One target WITH secrets — admin edit / duplicate hydration only.
20348
+ * `listTargets` stays redacted; the editor loads this so password fields
20349
+ * are filled (masked in the input) and a save can round-trip the token
20350
+ * when a destination changes (Duplicate with a new chatId, etc.).
20351
+ */
20352
+ getTarget: method(object({ targetId: string() }), TargetSchema, { auth: "admin" }),
20289
20353
  discoverTargets: method(object({
20290
20354
  kind: string(),
20291
- config: record(string(), unknown()).optional()
20355
+ config: record(string(), unknown()).optional(),
20356
+ /**
20357
+ * When editing / duplicating, the blank password field never round-trips
20358
+ * the stored token. Pass the source target id so the provider can restore
20359
+ * secrets server-side before dialling (same merge as upsert).
20360
+ */
20361
+ targetId: string().optional()
20292
20362
  }), array(DiscoveredTargetSchema), { auth: "admin" }),
20363
+ probeTargetConfig: method(object({
20364
+ kind: string(),
20365
+ config: record(string(), unknown()),
20366
+ /** See `discoverTargets.targetId` — restore stored secrets for a blank password. */
20367
+ targetId: string().optional()
20368
+ }), ProbeTargetConfigResultSchema, {
20369
+ kind: "mutation",
20370
+ auth: "admin"
20371
+ }),
20293
20372
  send: method(object({
20294
20373
  targetId: string(),
20295
20374
  notification: NotificationSchema
@@ -20304,7 +20383,16 @@ var notificationOutputCapability = {
20304
20383
  kind: "mutation",
20305
20384
  auth: "admin"
20306
20385
  }),
20307
- upsertTarget: method(object({ target: TargetSchema }), TargetSchema, {
20386
+ upsertTarget: method(object({
20387
+ target: TargetSchema,
20388
+ /**
20389
+ * Duplicate flow: create a NEW target id while copying secrets from an
20390
+ * existing row. The UI never holds the stored token; blank / redacted
20391
+ * password fields are restored from this source (D634 still applies if
20392
+ * destinations diverge without a re-typed secret).
20393
+ */
20394
+ cloneSecretsFrom: string().optional()
20395
+ }), TargetSchema, {
20308
20396
  kind: "mutation",
20309
20397
  auth: "admin"
20310
20398
  }),
@@ -20945,6 +21033,15 @@ var AlarmArmModeSchema = _enum([
20945
21033
  var AlarmPanelStatusSchema = object({
20946
21034
  /** Current lifecycle state. */
20947
21035
  state: AlarmStateSchema,
21036
+ /**
21037
+ * The arm mode the machine belongs to under transitional words
21038
+ * (`arming` / `pending` / `triggered` / `disarming`). `null` when
21039
+ * disarmed or when a provider cannot name one. Exporters MUST prefer
21040
+ * this over an in-process memo — a HomeKit accessory that missed the
21041
+ * settled `armed_*` slice used to map `pending` to DISARMED and hide
21042
+ * an entry delay.
21043
+ */
21044
+ targetMode: AlarmArmModeSchema.nullable().optional(),
20948
21045
  /** Subset of arm modes the panel accepts. UI renders one button per
20949
21046
  * mode in this list. */
20950
21047
  availableModes: array(AlarmArmModeSchema),
@@ -23254,17 +23351,41 @@ var NC_ALARM_TRIGGERED_MAX_SEC = 3600;
23254
23351
  var NcAlarmDelaySecSchema = number().int().min(0).max(600);
23255
23352
  var NcAlarmTriggeredSecSchema = number().int().min(0).max(NC_ALARM_TRIGGERED_MAX_SEC);
23256
23353
  var uniqueModes = (entries) => new Set(entries.map((e) => e.mode)).size === entries.length;
23354
+ /**
23355
+ * What the panel does when a bounded triggered window ends.
23356
+ * - `rearmAfter` — return to the armed mode
23357
+ * - `disableAfter` — auto-disarm
23358
+ * - `doNothing` — stay triggered until a human disarms
23359
+ */
23360
+ var NcAlarmPostTriggeredActionSchema = _enum([
23361
+ "rearmAfter",
23362
+ "disableAfter",
23363
+ "doNothing"
23364
+ ]);
23257
23365
  var NcAlarmModeDelaysListSchema = array(object({
23258
23366
  mode: AlarmArmModeSchema,
23259
23367
  exitDelaySec: NcAlarmDelaySecSchema.optional(),
23260
23368
  entryDelaySec: NcAlarmDelaySecSchema.optional(),
23261
- triggeredDurationSec: NcAlarmTriggeredSecSchema.optional()
23369
+ /**
23370
+ * Duration of `triggered` before {@link postTriggeredAction}. Kept as the
23371
+ * historical field name so older clients still read/write a number.
23372
+ */
23373
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.optional(),
23374
+ postTriggeredAction: NcAlarmPostTriggeredActionSchema.optional(),
23375
+ /**
23376
+ * When this mode may be armed. Absent / null = always allowed (same as a
23377
+ * rule with no `schedule`). Evaluated with {@link isScheduleActive}.
23378
+ */
23379
+ schedule: NcScheduleSchema.optional()
23262
23380
  })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
23263
23381
  var NcAlarmModeDelaysEditListSchema = array(object({
23264
23382
  mode: AlarmArmModeSchema,
23265
23383
  exitDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
23266
23384
  entryDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
23267
- triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional()
23385
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional(),
23386
+ postTriggeredAction: NcAlarmPostTriggeredActionSchema.nullable().optional(),
23387
+ /** Set a schedule, or `null` to clear (mode always allowed again). */
23388
+ schedule: NcScheduleSchema.nullable().optional()
23268
23389
  })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
23269
23390
  /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
23270
23391
  var NcAlarmNonBlockingEditSchema = object({
@@ -23336,12 +23457,18 @@ var NcAlarmSettingsSchema = object({
23336
23457
  /** Grace period between a trigger and the alarm firing. 0 = immediate. */
23337
23458
  entryDelaySec: NcAlarmDelaySecSchema,
23338
23459
  /**
23339
- * How long `triggered` lasts before the panel re-arms itself.
23340
- * **0 = until an operator disarms it** — the behaviour before this field
23341
- * existed, and therefore what an untouched install keeps doing.
23460
+ * How long `triggered` lasts before {@link postTriggeredAction} runs.
23461
+ * Ignored when the action is `doNothing`. Historical name kept so older
23462
+ * clients still round-trip a number.
23342
23463
  */
23343
23464
  triggeredDurationSec: NcAlarmTriggeredSecSchema,
23344
23465
  /**
23466
+ * What happens when the triggered window ends. Absent on a blob older than
23467
+ * this field → derived from {@link triggeredDurationSec} (`>0` ⇒ rearmAfter,
23468
+ * else doNothing).
23469
+ */
23470
+ postTriggeredAction: NcAlarmPostTriggeredActionSchema.optional(),
23471
+ /**
23345
23472
  * Deprecated by D630 — every transition is announced. Parsed, never read;
23346
23473
  * remove after one release. Optional so an older admin's patch (which still
23347
23474
  * sends it) parses rather than failing the whole save.
@@ -37562,7 +37689,7 @@ var LocalInterfaceSchema = object({
37562
37689
  name: string(),
37563
37690
  family: _enum(["IPv4", "IPv6"]),
37564
37691
  address: string(),
37565
- /** CIDR shorthand (e.g. `192.168.1.10/24`). Empty when OS doesn't expose. */
37692
+ /** CIDR shorthand (e.g. `192.168.x.x/24`). Empty when OS doesn't expose. */
37566
37693
  cidr: string(),
37567
37694
  /** OS netmask. Stable across calls so the SDK can hash on it. */
37568
37695
  netmask: string(),
@@ -37761,7 +37888,7 @@ var localNetworkCapability = {
37761
37888
  * every client a second authority on a socket only the hub binds. A viewer
37762
37889
  * configured with a port-less public URL (`https://camstack.example.top`)
37763
37890
  * infers 443 from the scheme, asks with 443, and was handed
37764
- * `https://192.168.1.9:443` for a hub listening on 4443. That candidate
37891
+ * `https://192.168.x.x:443` for a hub listening on 4443. That candidate
37765
37892
  * cannot ever answer, and losing its race reads in the log exactly like
37766
37893
  * "the LAN was tried and it was slower" — so an operator sitting on his own
37767
37894
  * WiFi stayed on the public tunnel for weeks, with the LAN candidate born
@@ -38193,7 +38320,7 @@ var MeshPeerSchema = object({
38193
38320
  tags: array(string()).readonly(),
38194
38321
  /** True when the peer advertises itself as an exit-node candidate. */
38195
38322
  exitNodeOption: boolean(),
38196
- /** Subnet routes the peer advertises (e.g. `["192.168.1.0/24"]`). */
38323
+ /** Subnet routes the peer advertises (e.g. `["192.168.x.x/24"]`). */
38197
38324
  advertisedRoutes: array(string()).readonly(),
38198
38325
  /** Owner account login (e.g. `foo@example.com`). Null for tagged peers. */
38199
38326
  userLogin: string().nullable(),
@@ -49670,6 +49797,12 @@ Object.freeze({
49670
49797
  addonId: null,
49671
49798
  access: "view"
49672
49799
  },
49800
+ "notificationOutput.getTarget": {
49801
+ capName: "notification-output",
49802
+ capScope: "system",
49803
+ addonId: null,
49804
+ access: "view"
49805
+ },
49673
49806
  "notificationOutput.listTargetKinds": {
49674
49807
  capName: "notification-output",
49675
49808
  capScope: "system",
@@ -49682,6 +49815,12 @@ Object.freeze({
49682
49815
  addonId: null,
49683
49816
  access: "view"
49684
49817
  },
49818
+ "notificationOutput.probeTargetConfig": {
49819
+ capName: "notification-output",
49820
+ capScope: "system",
49821
+ addonId: null,
49822
+ access: "create"
49823
+ },
49685
49824
  "notificationOutput.send": {
49686
49825
  capName: "notification-output",
49687
49826
  capScope: "system",
@@ -53391,6 +53530,7 @@ Object.freeze({
53391
53530
  access: "create"
53392
53531
  }
53393
53532
  });
53533
+ DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder;
53394
53534
  DeviceFeature.BatteryOperated;
53395
53535
  /**
53396
53536
  * The vocabulary, in the order a picker offers it.
package/dist/index.mjs CHANGED
@@ -5378,7 +5378,7 @@ var ZodIssueCode = {
5378
5378
  var ZodFirstPartyTypeKind;
5379
5379
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5380
5380
  //#endregion
5381
- //#region ../types/dist/sleep-CDCONfkt.mjs
5381
+ //#region ../types/dist/sleep-DXKLNFvA.mjs
5382
5382
  /**
5383
5383
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5384
5384
  * window to float samples (D455).
@@ -5686,6 +5686,43 @@ function hydrateField(field, values) {
5686
5686
  }
5687
5687
  const rawValue = storedValue !== void 0 ? storedValue : defaultValue !== void 0 ? defaultValue : null;
5688
5688
  const value = field.type === "textarea" && field.isJson && rawValue !== null && typeof rawValue === "object" ? JSON.stringify(rawValue, null, 2) : rawValue;
5689
+ if (field.type === "tags" && typeof field.suggestionsFrom === "string") {
5690
+ const from = values[field.suggestionsFrom];
5691
+ const extra = Array.isArray(from) ? from.filter((s) => typeof s === "string" && s.length > 0) : [];
5692
+ const merged = [...new Set([...field.suggestions ?? [], ...extra])];
5693
+ return {
5694
+ ...field,
5695
+ suggestions: merged,
5696
+ value
5697
+ };
5698
+ }
5699
+ if ((field.type === "select" || field.type === "multiselect") && typeof field.optionsFrom === "string") {
5700
+ const from = values[field.optionsFrom];
5701
+ const byValue = /* @__PURE__ */ new Map();
5702
+ for (const opt of field.options) byValue.set(opt.value, opt);
5703
+ if (Array.isArray(from)) for (const entry of from) {
5704
+ if (typeof entry === "string" && entry.length > 0) {
5705
+ if (!byValue.has(entry)) byValue.set(entry, {
5706
+ value: entry,
5707
+ label: entry
5708
+ });
5709
+ continue;
5710
+ }
5711
+ if (entry === null || typeof entry !== "object") continue;
5712
+ const v = Reflect.get(entry, "value");
5713
+ const lbl = Reflect.get(entry, "label");
5714
+ if (typeof v !== "string" || v.length === 0) continue;
5715
+ if (!byValue.has(v)) byValue.set(v, {
5716
+ value: v,
5717
+ label: typeof lbl === "string" && lbl.length > 0 ? lbl : v
5718
+ });
5719
+ }
5720
+ return {
5721
+ ...field,
5722
+ options: [...byValue.values()],
5723
+ value
5724
+ };
5725
+ }
5689
5726
  return {
5690
5727
  ...field,
5691
5728
  value
@@ -10990,7 +11027,16 @@ var AutomationActionSchema = discriminatedUnion("kind", [
10990
11027
  }),
10991
11028
  object({
10992
11029
  kind: literal("cap"),
10993
- deviceId: union([number().int(), object({ $var: string().min(1) })]),
11030
+ /**
11031
+ * One device, several same-family devices (locks / climate family / …),
11032
+ * or `{ $var }` for the device that triggered the run. An array is
11033
+ * fan-out at codegen — each id gets the same cap.method call.
11034
+ */
11035
+ deviceId: union([
11036
+ number().int(),
11037
+ array(number().int()).min(1),
11038
+ object({ $var: string().min(1) })
11039
+ ]),
10994
11040
  cap: string().min(1),
10995
11041
  method: string().min(1),
10996
11042
  /** Values may carry `{{vars.x}}` slots, which SUBSTITUTE and do not
@@ -15431,7 +15477,7 @@ var detectionPipelineCapability = {
15431
15477
  * This matters here more than anywhere else in the repo, because every provider
15432
15478
  * that knows a device's host knows its PASSWORD too: `{ host, port, username,
15433
15479
  * password }` sit in one object on Hikvision, Amcrest, Reolink and ONVIF alike,
15434
- * and `http://admin:hunter2@192.168.50.139/` is a URL a browser accepts. The
15480
+ * and `http://admin:hunter2@192.168.x.x/` is a URL a browser accepts. The
15435
15481
  * camera's own page will ask for its own login. That is correct, and pre-
15436
15482
  * filling it is the operator's business, not ours.
15437
15483
  *
@@ -20275,6 +20321,17 @@ var SendResultSchema = object({
20275
20321
  });
20276
20322
  /** Same shape as SendResult — kept as a distinct name for the test panel. */
20277
20323
  var TestResultSchema = SendResultSchema;
20324
+ /**
20325
+ * Pre-save credential probe against a partial (unsaved) target config.
20326
+ * `resolvedUrl` never includes secrets (token stripped from path).
20327
+ */
20328
+ var ProbeTargetConfigResultSchema = object({
20329
+ ok: boolean(),
20330
+ resolvedUrl: string(),
20331
+ httpStatus: number().int().optional(),
20332
+ stateInstance: string().optional(),
20333
+ error: string().optional()
20334
+ });
20278
20335
  var notificationOutputCapability = {
20279
20336
  name: "notification-output",
20280
20337
  scope: "system",
@@ -20282,10 +20339,32 @@ var notificationOutputCapability = {
20282
20339
  methods: {
20283
20340
  listTargetKinds: method(object({}), array(TargetKindSchema)),
20284
20341
  listTargets: method(object({}), array(TargetSchema), { auth: "admin" }),
20342
+ /**
20343
+ * One target WITH secrets — admin edit / duplicate hydration only.
20344
+ * `listTargets` stays redacted; the editor loads this so password fields
20345
+ * are filled (masked in the input) and a save can round-trip the token
20346
+ * when a destination changes (Duplicate with a new chatId, etc.).
20347
+ */
20348
+ getTarget: method(object({ targetId: string() }), TargetSchema, { auth: "admin" }),
20285
20349
  discoverTargets: method(object({
20286
20350
  kind: string(),
20287
- config: record(string(), unknown()).optional()
20351
+ config: record(string(), unknown()).optional(),
20352
+ /**
20353
+ * When editing / duplicating, the blank password field never round-trips
20354
+ * the stored token. Pass the source target id so the provider can restore
20355
+ * secrets server-side before dialling (same merge as upsert).
20356
+ */
20357
+ targetId: string().optional()
20288
20358
  }), array(DiscoveredTargetSchema), { auth: "admin" }),
20359
+ probeTargetConfig: method(object({
20360
+ kind: string(),
20361
+ config: record(string(), unknown()),
20362
+ /** See `discoverTargets.targetId` — restore stored secrets for a blank password. */
20363
+ targetId: string().optional()
20364
+ }), ProbeTargetConfigResultSchema, {
20365
+ kind: "mutation",
20366
+ auth: "admin"
20367
+ }),
20289
20368
  send: method(object({
20290
20369
  targetId: string(),
20291
20370
  notification: NotificationSchema
@@ -20300,7 +20379,16 @@ var notificationOutputCapability = {
20300
20379
  kind: "mutation",
20301
20380
  auth: "admin"
20302
20381
  }),
20303
- upsertTarget: method(object({ target: TargetSchema }), TargetSchema, {
20382
+ upsertTarget: method(object({
20383
+ target: TargetSchema,
20384
+ /**
20385
+ * Duplicate flow: create a NEW target id while copying secrets from an
20386
+ * existing row. The UI never holds the stored token; blank / redacted
20387
+ * password fields are restored from this source (D634 still applies if
20388
+ * destinations diverge without a re-typed secret).
20389
+ */
20390
+ cloneSecretsFrom: string().optional()
20391
+ }), TargetSchema, {
20304
20392
  kind: "mutation",
20305
20393
  auth: "admin"
20306
20394
  }),
@@ -20941,6 +21029,15 @@ var AlarmArmModeSchema = _enum([
20941
21029
  var AlarmPanelStatusSchema = object({
20942
21030
  /** Current lifecycle state. */
20943
21031
  state: AlarmStateSchema,
21032
+ /**
21033
+ * The arm mode the machine belongs to under transitional words
21034
+ * (`arming` / `pending` / `triggered` / `disarming`). `null` when
21035
+ * disarmed or when a provider cannot name one. Exporters MUST prefer
21036
+ * this over an in-process memo — a HomeKit accessory that missed the
21037
+ * settled `armed_*` slice used to map `pending` to DISARMED and hide
21038
+ * an entry delay.
21039
+ */
21040
+ targetMode: AlarmArmModeSchema.nullable().optional(),
20944
21041
  /** Subset of arm modes the panel accepts. UI renders one button per
20945
21042
  * mode in this list. */
20946
21043
  availableModes: array(AlarmArmModeSchema),
@@ -23250,17 +23347,41 @@ var NC_ALARM_TRIGGERED_MAX_SEC = 3600;
23250
23347
  var NcAlarmDelaySecSchema = number().int().min(0).max(600);
23251
23348
  var NcAlarmTriggeredSecSchema = number().int().min(0).max(NC_ALARM_TRIGGERED_MAX_SEC);
23252
23349
  var uniqueModes = (entries) => new Set(entries.map((e) => e.mode)).size === entries.length;
23350
+ /**
23351
+ * What the panel does when a bounded triggered window ends.
23352
+ * - `rearmAfter` — return to the armed mode
23353
+ * - `disableAfter` — auto-disarm
23354
+ * - `doNothing` — stay triggered until a human disarms
23355
+ */
23356
+ var NcAlarmPostTriggeredActionSchema = _enum([
23357
+ "rearmAfter",
23358
+ "disableAfter",
23359
+ "doNothing"
23360
+ ]);
23253
23361
  var NcAlarmModeDelaysListSchema = array(object({
23254
23362
  mode: AlarmArmModeSchema,
23255
23363
  exitDelaySec: NcAlarmDelaySecSchema.optional(),
23256
23364
  entryDelaySec: NcAlarmDelaySecSchema.optional(),
23257
- triggeredDurationSec: NcAlarmTriggeredSecSchema.optional()
23365
+ /**
23366
+ * Duration of `triggered` before {@link postTriggeredAction}. Kept as the
23367
+ * historical field name so older clients still read/write a number.
23368
+ */
23369
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.optional(),
23370
+ postTriggeredAction: NcAlarmPostTriggeredActionSchema.optional(),
23371
+ /**
23372
+ * When this mode may be armed. Absent / null = always allowed (same as a
23373
+ * rule with no `schedule`). Evaluated with {@link isScheduleActive}.
23374
+ */
23375
+ schedule: NcScheduleSchema.optional()
23258
23376
  })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
23259
23377
  var NcAlarmModeDelaysEditListSchema = array(object({
23260
23378
  mode: AlarmArmModeSchema,
23261
23379
  exitDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
23262
23380
  entryDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
23263
- triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional()
23381
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional(),
23382
+ postTriggeredAction: NcAlarmPostTriggeredActionSchema.nullable().optional(),
23383
+ /** Set a schedule, or `null` to clear (mode always allowed again). */
23384
+ schedule: NcScheduleSchema.nullable().optional()
23264
23385
  })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
23265
23386
  /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
23266
23387
  var NcAlarmNonBlockingEditSchema = object({
@@ -23332,12 +23453,18 @@ var NcAlarmSettingsSchema = object({
23332
23453
  /** Grace period between a trigger and the alarm firing. 0 = immediate. */
23333
23454
  entryDelaySec: NcAlarmDelaySecSchema,
23334
23455
  /**
23335
- * How long `triggered` lasts before the panel re-arms itself.
23336
- * **0 = until an operator disarms it** — the behaviour before this field
23337
- * existed, and therefore what an untouched install keeps doing.
23456
+ * How long `triggered` lasts before {@link postTriggeredAction} runs.
23457
+ * Ignored when the action is `doNothing`. Historical name kept so older
23458
+ * clients still round-trip a number.
23338
23459
  */
23339
23460
  triggeredDurationSec: NcAlarmTriggeredSecSchema,
23340
23461
  /**
23462
+ * What happens when the triggered window ends. Absent on a blob older than
23463
+ * this field → derived from {@link triggeredDurationSec} (`>0` ⇒ rearmAfter,
23464
+ * else doNothing).
23465
+ */
23466
+ postTriggeredAction: NcAlarmPostTriggeredActionSchema.optional(),
23467
+ /**
23341
23468
  * Deprecated by D630 — every transition is announced. Parsed, never read;
23342
23469
  * remove after one release. Optional so an older admin's patch (which still
23343
23470
  * sends it) parses rather than failing the whole save.
@@ -37558,7 +37685,7 @@ var LocalInterfaceSchema = object({
37558
37685
  name: string(),
37559
37686
  family: _enum(["IPv4", "IPv6"]),
37560
37687
  address: string(),
37561
- /** CIDR shorthand (e.g. `192.168.1.10/24`). Empty when OS doesn't expose. */
37688
+ /** CIDR shorthand (e.g. `192.168.x.x/24`). Empty when OS doesn't expose. */
37562
37689
  cidr: string(),
37563
37690
  /** OS netmask. Stable across calls so the SDK can hash on it. */
37564
37691
  netmask: string(),
@@ -37757,7 +37884,7 @@ var localNetworkCapability = {
37757
37884
  * every client a second authority on a socket only the hub binds. A viewer
37758
37885
  * configured with a port-less public URL (`https://camstack.example.top`)
37759
37886
  * infers 443 from the scheme, asks with 443, and was handed
37760
- * `https://192.168.1.9:443` for a hub listening on 4443. That candidate
37887
+ * `https://192.168.x.x:443` for a hub listening on 4443. That candidate
37761
37888
  * cannot ever answer, and losing its race reads in the log exactly like
37762
37889
  * "the LAN was tried and it was slower" — so an operator sitting on his own
37763
37890
  * WiFi stayed on the public tunnel for weeks, with the LAN candidate born
@@ -38189,7 +38316,7 @@ var MeshPeerSchema = object({
38189
38316
  tags: array(string()).readonly(),
38190
38317
  /** True when the peer advertises itself as an exit-node candidate. */
38191
38318
  exitNodeOption: boolean(),
38192
- /** Subnet routes the peer advertises (e.g. `["192.168.1.0/24"]`). */
38319
+ /** Subnet routes the peer advertises (e.g. `["192.168.x.x/24"]`). */
38193
38320
  advertisedRoutes: array(string()).readonly(),
38194
38321
  /** Owner account login (e.g. `foo@example.com`). Null for tagged peers. */
38195
38322
  userLogin: string().nullable(),
@@ -49666,6 +49793,12 @@ Object.freeze({
49666
49793
  addonId: null,
49667
49794
  access: "view"
49668
49795
  },
49796
+ "notificationOutput.getTarget": {
49797
+ capName: "notification-output",
49798
+ capScope: "system",
49799
+ addonId: null,
49800
+ access: "view"
49801
+ },
49669
49802
  "notificationOutput.listTargetKinds": {
49670
49803
  capName: "notification-output",
49671
49804
  capScope: "system",
@@ -49678,6 +49811,12 @@ Object.freeze({
49678
49811
  addonId: null,
49679
49812
  access: "view"
49680
49813
  },
49814
+ "notificationOutput.probeTargetConfig": {
49815
+ capName: "notification-output",
49816
+ capScope: "system",
49817
+ addonId: null,
49818
+ access: "create"
49819
+ },
49681
49820
  "notificationOutput.send": {
49682
49821
  capName: "notification-output",
49683
49822
  capScope: "system",
@@ -53387,6 +53526,7 @@ Object.freeze({
53387
53526
  access: "create"
53388
53527
  }
53389
53528
  });
53529
+ DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder;
53390
53530
  DeviceFeature.BatteryOperated;
53391
53531
  /**
53392
53532
  * The vocabulary, in the order a picker offers it.
@@ -1,5 +1,5 @@
1
1
  import { b as e, g as t, l as n, u as r } from "./_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare__react__loadShare__.js-C5jUMd7X.mjs";
2
- import { c as i, s as a } from "./responsive-DQHzOXvm.mjs";
2
+ import { c as i, s as a } from "./responsive-BoQdxzOM.mjs";
3
3
  import { n as o, r as s, t as c } from "./_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-DalfdIDw.mjs";
4
4
  var l = i("chevron-down", [["path", {
5
5
  d: "m6 9 6 6 6-6",
@@ -1,2 +1,2 @@
1
- import { n as e, t } from "./virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_osd_manager_page__remoteEntry_js-C2WG2Ab3.mjs";
1
+ import { n as e, t } from "./virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_osd_manager_page__remoteEntry_js-T0PnCKpV.mjs";
2
2
  export { t as get, e as init };
@@ -1,6 +1,6 @@
1
1
  import { _ as e, b as t, c as n, g as r, l as i, m as a, n as o, r as s, t as c, u as l } from "./_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare__react__loadShare__.js-C5jUMd7X.mjs";
2
2
  import "./_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-DalfdIDw.mjs";
3
- import { i as u } from "./_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BZTcxI6n.mjs";
3
+ import { i as u } from "./_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-B4GSezZ1.mjs";
4
4
  //#region ../../node_modules/lucide-react/dist/esm/shared/src/utils/mergeClasses.js
5
5
  t();
6
6
  var d = (...e) => e.filter((e, t, n) => !!e && e.trim() !== "" && n.indexOf(e) === t).join(" ").trim(), f = (e) => e.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(), p = (e) => e.replace(/^([A-Z])|[\s-_]+(\w)/g, (e, t, n) => n ? n.toUpperCase() : t.toLowerCase()), m = (e) => {
@@ -1,5 +1,5 @@
1
1
  import { b as e, c as t, g as n, m as r } from "./_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare__react__loadShare__.js-C5jUMd7X.mjs";
2
- import { c as i } from "./responsive-DQHzOXvm.mjs";
2
+ import { c as i } from "./responsive-BoQdxzOM.mjs";
3
3
  var a = i("camera", [["path", {
4
4
  d: "M13.997 4a2 2 0 0 1 1.76 1.05l.486.9A2 2 0 0 0 18.003 7H20a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2h1.997a2 2 0 0 0 1.759-1.048l.489-.904A2 2 0 0 1 10.004 4z",
5
5
  key: "18u6gg"
@@ -1,4 +1,4 @@
1
- import { c as e } from "./responsive-DQHzOXvm.mjs";
1
+ import { c as e } from "./responsive-BoQdxzOM.mjs";
2
2
  var t = e("eye-off", [
3
3
  ["path", {
4
4
  d: "M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49",
@@ -1,4 +1,4 @@
1
- import { c as e } from "./responsive-DQHzOXvm.mjs";
1
+ import { c as e } from "./responsive-BoQdxzOM.mjs";
2
2
  var t = e("trash-2", [
3
3
  ["path", {
4
4
  d: "M10 11v6",
@@ -2753,7 +2753,7 @@ async function rr(e) {
2753
2753
  }
2754
2754
  }
2755
2755
  async function ir() {
2756
- return tr ||= rr(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_osd_manager_page-B4Z53O4w.mjs")).catch((e) => {
2756
+ return tr ||= rr(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_osd_manager_page-CW_hXAxF.mjs")).catch((e) => {
2757
2757
  throw tr = void 0, e;
2758
2758
  }), tr;
2759
2759
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-osd-manager",
3
- "version": "0.1.167",
3
+ "version": "0.1.169",
4
4
  "description": "Binds camera on-screen-display slots to live state and recognitions",
5
5
  "keywords": [
6
6
  "camstack",