@camstack/addon-import-alexa 0.2.118 → 0.2.119

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 (3) hide show
  1. package/dist/addon.js +122 -96
  2. package/dist/addon.mjs +122 -96
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -10690,11 +10690,11 @@ var ModelVariantGroupSchema = object({
10690
10690
  /** Quantization axis. Omit ⇒ the fp32 base build. */
10691
10691
  precision: _enum(["fp32", "int8"]).optional(),
10692
10692
  /**
10693
- * Speed-optimization axis. Omit ⇒ the standard build. `fast` marks a
10694
- * latency-optimized export (e.g. ReLU-activation variant) — the slot the
10695
- * future performance variants plug into.
10693
+ * Training / latency-variant axis. Omit ⇒ the standard build. `test` marks
10694
+ * an alternate training of the same family (Scrypted `relu_test`); chip
10695
+ * label is "Test".
10696
10696
  */
10697
- optimization: _enum(["standard", "fast"]).optional(),
10697
+ optimization: _enum(["standard", "test"]).optional(),
10698
10698
  /**
10699
10699
  * Input-resolution axis (square input side, px). Omit ⇒ the family's native
10700
10700
  * resolution (640 for yolo26). Reduced-input builds (320 / 256) are a big,
@@ -10717,9 +10717,10 @@ var ModelProviderIdSchema = _enum([
10717
10717
  * are per upstream. A persisted custom-model row written when this field was a
10718
10718
  * string still parses — the string is lifted into `{ weights }`.
10719
10719
  *
10720
- * Every licence surface (the admin "Models and licenses" page,
10721
- * `THIRD_PARTY_MODELS.md`, the Hugging Face model table) is GENERATED from
10722
- * these records by `scripts/gen-model-licenses.ts` (D661).
10720
+ * Every machine licence surface (`THIRD_PARTY_MODELS.md`, the Hugging Face
10721
+ * model table) is GENERATED from these records by
10722
+ * `scripts/gen-model-licenses.ts` (D661). Operator-facing docs live in
10723
+ * `camstack/docs` → `/docs/detection/models`.
10723
10724
  */
10724
10725
  var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { weights: value } : value, object({
10725
10726
  /** SPDX id of the WEIGHTS' terms, a `LicenseRef-*` for non-SPDX terms, or `UNKNOWN`. */
@@ -14418,7 +14419,7 @@ DeviceType.Camera;
14418
14419
  * This matters here more than anywhere else in the repo, because every provider
14419
14420
  * that knows a device's host knows its PASSWORD too: `{ host, port, username,
14420
14421
  * password }` sit in one object on Hikvision, Amcrest, Reolink and ONVIF alike,
14421
- * and `http://admin:hunter2@192.168.x.x/` is a URL a browser accepts. The
14422
+ * and `http://admin:hunter2@192.168.60.139/` is a URL a browser accepts. The
14422
14423
  * camera's own page will ask for its own login. That is correct, and pre-
14423
14424
  * filling it is the operator's business, not ours.
14424
14425
  *
@@ -17607,7 +17608,7 @@ method(object({
17607
17608
  timeoutMs: 6e5
17608
17609
  });
17609
17610
  method(object({
17610
- nodeId: string(),
17611
+ targetNodeId: string(),
17611
17612
  modelId: string(),
17612
17613
  format: _enum(MODEL_FORMATS),
17613
17614
  entry: ModelCatalogEntrySchema
@@ -20111,8 +20112,9 @@ var NcRuleSchema = NcRuleInputSchema.extend({
20111
20112
  disabledTargetIds: array(string()).default([])
20112
20113
  });
20113
20114
  /**
20114
- * The state-summary SECTIONS (D647 / D698): the D637 kind groups that report a
20115
- * still-true state. `backups-exports` and `alarm` are not sections — a completed
20115
+ * The state-summary SECTIONS (D647 / D698 / D708): the D637 kind groups that
20116
+ * report a still-true state. `addons` is the crash-looped addons only and
20117
+ * `addon-updates` the addons that are behind (D708 split them). `backups-exports` and `alarm` are not sections — a completed
20116
20118
  * job is not an open state, and the alarm stays instant.
20117
20119
  */
20118
20120
  var NcStateSummarySectionIdSchema = _enum([
@@ -20124,6 +20126,7 @@ var NcStateSummarySectionIdSchema = _enum([
20124
20126
  "detection-blind",
20125
20127
  "nodes",
20126
20128
  "addons",
20129
+ "addon-updates",
20127
20130
  "updates"
20128
20131
  ]);
20129
20132
  /** One section of a previewed state summary. `unavailable` = its state could not be read. */
@@ -20604,7 +20607,19 @@ var NcAlarmModeDelaysListSchema = array(object({
20604
20607
  * When this mode may be armed. Absent / null = always allowed (same as a
20605
20608
  * rule with no `schedule`). Evaluated with {@link isScheduleActive}.
20606
20609
  */
20607
- schedule: NcScheduleSchema.optional()
20610
+ schedule: NcScheduleSchema.optional(),
20611
+ /**
20612
+ * D706: while this mode's ENTRY DELAY runs, do the alarm rules' own pushes go out (as an
20613
+ * intrusion naming the locations)? Absent = false — the entry-delay notification is the
20614
+ * only one, and the matches ride the triggered notification's mosaic (D705).
20615
+ */
20616
+ notifyDuringEntryDelay: boolean().optional(),
20617
+ /**
20618
+ * D706: notify "watched again" when a sensor this arm bypassed closes and opens again.
20619
+ * Absent = false (logged, not sent). Even when true it is not sent when that same sensor
20620
+ * is the one that starts the entry delay — the entry-delay notification already names it.
20621
+ */
20622
+ notifySensorRewatched: boolean().optional()
20608
20623
  })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
20609
20624
  var NcAlarmModeDelaysEditListSchema = array(object({
20610
20625
  mode: AlarmArmModeSchema,
@@ -20613,7 +20628,11 @@ var NcAlarmModeDelaysEditListSchema = array(object({
20613
20628
  triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional(),
20614
20629
  postTriggeredAction: NcAlarmPostTriggeredActionSchema.nullable().optional(),
20615
20630
  /** Set a schedule, or `null` to clear (mode always allowed again). */
20616
- schedule: NcScheduleSchema.nullable().optional()
20631
+ schedule: NcScheduleSchema.nullable().optional(),
20632
+ /** D706: set the switch, or `null` to clear it (back to the default, false). */
20633
+ notifyDuringEntryDelay: boolean().nullable().optional(),
20634
+ /** D706: set the switch, or `null` to clear it (back to the default, false). */
20635
+ notifySensorRewatched: boolean().nullable().optional()
20617
20636
  })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
20618
20637
  /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
20619
20638
  var NcAlarmNonBlockingEditSchema = object({
@@ -21574,39 +21593,19 @@ Object.freeze(Object.fromEntries([{
21574
21593
  label: "Face recognition model",
21575
21594
  defaultModelId: "auraface-r100",
21576
21595
  indexName: "the enrolled face gallery",
21577
- options: [
21578
- {
21579
- id: "auraface-r100",
21580
- label: "AuraFace R100"
21581
- },
21582
- {
21583
- id: "arcface-r100",
21584
- label: "ArcFace (ResNet34)"
21585
- },
21586
- {
21587
- id: "inception-resnet-v1",
21588
- label: "Inception ResNet V1"
21589
- }
21590
- ]
21596
+ options: [{
21597
+ id: "auraface-r100",
21598
+ label: "AuraFace R100"
21599
+ }]
21591
21600
  }, {
21592
21601
  stepId: "clip-embedding",
21593
21602
  label: "Semantic search model",
21594
- defaultModelId: "mobileclip-s1",
21603
+ defaultModelId: "siglip2-b16-224",
21595
21604
  indexName: "the object semantic-search index",
21596
- options: [
21597
- {
21598
- id: "mobileclip-s1",
21599
- label: "MobileCLIP S1"
21600
- },
21601
- {
21602
- id: "mobileclip-s2",
21603
- label: "MobileCLIP S2"
21604
- },
21605
- {
21606
- id: "siglip2-b16-224",
21607
- label: "SigLIP2 B/16 (Apache-2.0)"
21608
- }
21609
- ]
21605
+ options: [{
21606
+ id: "siglip2-b16-224",
21607
+ label: "SigLIP2 B/16 (Apache-2.0)"
21608
+ }]
21610
21609
  }].map((s) => [s.stepId, s.defaultModelId])));
21611
21610
  var CLUSTER_STEP_SETTING_FIELDS = [{
21612
21611
  stepId: "face-embedding",
@@ -24494,6 +24493,22 @@ var MotionSourceEnum = _enum([
24494
24493
  "device-activity"
24495
24494
  ]);
24496
24495
  /**
24496
+ * What opened an on-motion detection SESSION: the motion source that passed the
24497
+ * camera's `motionSources` gate, and what raised it (the camera itself, or a
24498
+ * sensor the operator attached — D672). `sensorName` is the attached sensor's
24499
+ * device name as the orchestrator's camera-sensors resolution last read it;
24500
+ * absent when unknown or when the camera itself triggered.
24501
+ *
24502
+ * Carried on the session attach ONLY so the runner's `DetectionPhaseTransition`
24503
+ * can say what started the session (D672 rule 11, amended 2026-10-06). The
24504
+ * runner never decides anything on it.
24505
+ */
24506
+ var SessionTriggerSchema = object({
24507
+ source: MotionSourceEnum,
24508
+ triggeredBy: MotionTriggeredBySchema,
24509
+ sensorName: string().optional()
24510
+ });
24511
+ /**
24497
24512
  * List of motion sources active on a camera. Empty array is valid:
24498
24513
  * "no source" — happens for battery cams without firmware motion when
24499
24514
  * the operator hasn't opted into the SW analyzer (would hold the
@@ -24745,6 +24760,14 @@ var RunnerCameraConfigSchema = object({
24745
24760
  */
24746
24761
  motionSources: MotionSourcesSchema.default(["analyzer"]),
24747
24762
  /**
24763
+ * What opened this attach, on a SESSION attach only (see
24764
+ * {@link SessionTriggerSchema}). OPTIONAL with no default: absent on a
24765
+ * standing attach, an occupancy burst, a re-dispatch with no motion event
24766
+ * behind it, and every attach from an orchestrator older than the field — the
24767
+ * runner then names no source on the phase event.
24768
+ */
24769
+ sessionTrigger: SessionTriggerSchema.optional(),
24770
+ /**
24748
24771
  * WHICH root detector runs for this camera. The detection counterpart of
24749
24772
  * {@link motionSources}, same shape and same discipline: a per-camera list
24750
24773
  * of sources the system understands, vendor-agnostic, owned here.
@@ -32150,7 +32173,7 @@ var LocalInterfaceSchema = object({
32150
32173
  name: string(),
32151
32174
  family: _enum(["IPv4", "IPv6"]),
32152
32175
  address: string(),
32153
- /** CIDR shorthand (e.g. `192.168.x.x/24`). Empty when OS doesn't expose. */
32176
+ /** CIDR shorthand (e.g. `192.168.10.10/24`). Empty when OS doesn't expose. */
32154
32177
  cidr: string(),
32155
32178
  /** OS netmask. Stable across calls so the SDK can hash on it. */
32156
32179
  netmask: string(),
@@ -32204,7 +32227,8 @@ var ConnectionEndpointSchema = object({
32204
32227
  "lan-ipv4",
32205
32228
  "lan-ipv6",
32206
32229
  "public",
32207
- "loopback"
32230
+ "loopback",
32231
+ "app-link"
32208
32232
  ]),
32209
32233
  /**
32210
32234
  * Originating-interface kind — `lan`/`wifi`/`docker`/`vpn`/`other`/
@@ -32273,15 +32297,27 @@ var GetConnectionEndpointsResultSchema = object({
32273
32297
  localPort: AdvertisedLocalPortSchema
32274
32298
  });
32275
32299
  /**
32276
- * The chosen outbound endpoint for notification artifacts. `baseUrl: null` =
32277
- * AUTO (resolved from the candidate ranking at send time); `resolved` reports
32278
- * what AUTO currently picks, so the UI can show the effective value either way.
32300
+ * The address flagged for notification links. `baseUrl: null` = AUTO, which
32301
+ * since D709 is the CamStack app link; `resolved` reports the effective value,
32302
+ * so the UI can show it either way.
32279
32303
  */
32280
32304
  var NotificationEndpointSchema = object({
32281
32305
  /** The operator's explicit choice, or null for AUTO. */
32282
32306
  baseUrl: string().nullable(),
32283
- /** What the ranking currently resolves to (null when nothing is reachable). */
32284
- resolved: string().nullable()
32307
+ /**
32308
+ * The effective flagged address: the explicit choice, else (AUTO) the
32309
+ * CamStack app link `https://camstack.zentik.app` (D709). A pre-D709 hub
32310
+ * answered the public tunnel / mesh here, or null.
32311
+ */
32312
+ resolved: string().nullable(),
32313
+ /**
32314
+ * The hub origin an app link carries as `hub=` (D709): the hub's best
32315
+ * public HTTPS address — the tunnel, then the mesh (Tailscale MagicDNS) —
32316
+ * picked from this cap's own palette by `pickAppLinkHub`. `null` when the
32317
+ * hub advertises neither; the app link is then minted without `hub=`.
32318
+ * Absent on a pre-D709 hub.
32319
+ */
32320
+ appLinkHub: string().nullable()
32285
32321
  });
32286
32322
  /**
32287
32323
  * The URLs the SDK / viewer should race for API access. `baseUrls` empty =
@@ -32335,7 +32371,11 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
32335
32371
  * Pass `'https'` when the caller is itself loaded over HTTPS
32336
32372
  * to avoid mixed-content blocks in the browser. The public
32337
32373
  * tunnel always emits `https://` regardless. */
32338
- scheme: _enum(["http", "https"]).optional()
32374
+ scheme: _enum(["http", "https"]).optional(),
32375
+ /** Append the CamStack app link entry (`kind: 'app-link'`, D709) —
32376
+ * an address notification links can be flagged with, not a hub
32377
+ * route. Default `false`: racers and rankers never see it. */
32378
+ includeAppLink: boolean().optional()
32339
32379
  }), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), ViewerEndpointsSchema), method(object({ baseUrls: array(string()).readonly() }), ViewerEndpointsSchema, { kind: "mutation" }), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" }), method(_void(), TlsStatusSchema), method(object({ reason: string().optional() }), TlsStatusSchema, {
32340
32380
  kind: "mutation",
32341
32381
  auth: "admin"
@@ -32664,7 +32704,7 @@ var MeshPeerSchema = object({
32664
32704
  tags: array(string()).readonly(),
32665
32705
  /** True when the peer advertises itself as an exit-node candidate. */
32666
32706
  exitNodeOption: boolean(),
32667
- /** Subnet routes the peer advertises (e.g. `["192.168.x.x/24"]`). */
32707
+ /** Subnet routes the peer advertises (e.g. `["192.168.10.0/24"]`). */
32668
32708
  advertisedRoutes: array(string()).readonly(),
32669
32709
  /** Owner account login (e.g. `foo@example.com`). Null for tagged peers. */
32670
32710
  userLogin: string().nullable(),
@@ -33992,7 +34032,13 @@ var OsdStatusSchema = object({ overlays: array(object({
33992
34032
  */
33993
34033
  availablePositions: array(OsdPositionEnum).readonly(),
33994
34034
  /** Firmware does not allow editing the `text` field (e.g. timestamp). */
33995
- readOnly: boolean().optional()
34035
+ readOnly: boolean().optional(),
34036
+ /**
34037
+ * Firmware text ceiling for this overlay. Absent = no known limit.
34038
+ * The OSD manager truncates here on every write — never stores its own
34039
+ * copy on the binding.
34040
+ */
34041
+ maxCharacters: number().int().positive().optional()
33996
34042
  })).readonly() });
33997
34043
  var OsdOverlayPatchSchema = object({
33998
34044
  enabled: boolean().optional(),
@@ -34043,7 +34089,9 @@ var OsdTemplateBindingSchema = object({
34043
34089
  valuePath: string().min(1).max(64),
34044
34090
  /** Convert TO this unit at render (`tryConvertUnit`). Absent = source unit. */
34045
34091
  displayUnit: string().max(16).optional(),
34046
- maxDecimals: number().int().min(0).max(4).default(1)
34092
+ maxDecimals: number().int().min(0).max(4).default(1),
34093
+ /** Raw value → display text (same shape as slot binding). Empty string hides. */
34094
+ valueMap: record(string(), string()).optional()
34047
34095
  });
34048
34096
  /**
34049
34097
  * A named template: bindings (alias → leaf field) + a parser that
@@ -34093,18 +34141,11 @@ var OsdSlotBindingSchema = object({
34093
34141
  source: OsdSourceSchema,
34094
34142
  /** `${value}` and `${unit}` are substituted; every occurrence. */
34095
34143
  template: string().max(96).default("${value}"),
34096
- /** Truncate with an ellipsis past this length. Absent = no limit. */
34097
- maxCharacters: number().int().min(4).max(64).optional(),
34098
34144
  /**
34099
34145
  * Decimal places for a numeric value. `0` yields an integer — the
34100
34146
  * documented workaround for firmwares that reject `.` in overlay text.
34101
34147
  */
34102
34148
  maxDecimals: number().int().min(0).max(4).default(1),
34103
- /**
34104
- * Appended via `${unit}` when no unit conversion produces a label.
34105
- * Prefer `source.displayUnit` for converted device-state values.
34106
- */
34107
- unitLabel: string().max(8).optional(),
34108
34149
  /** Raw value → display text, e.g. `{"true":"MOTION","false":""}`. */
34109
34150
  valueMap: record(string(), string()).optional(),
34110
34151
  /** Time windows in which the slot is shown. Absent = always. */
@@ -34113,9 +34154,7 @@ var OsdSlotBindingSchema = object({
34113
34154
  * Display gate, in the notification centre's condition vocabulary.
34114
34155
  * Only the keys reported by `getConditionSupport` are accepted.
34115
34156
  */
34116
- conditions: NcConditionsSchema.optional(),
34117
- /** Rendered when the gate is closed or the value unreadable. Empty = hide. */
34118
- fallbackText: string().max(64).default("")
34157
+ conditions: NcConditionsSchema.optional()
34119
34158
  });
34120
34159
  /** One camera slot, as the operator sees it: firmware truth + our binding. */
34121
34160
  var OsdSlotViewSchema = object({
@@ -52348,12 +52387,14 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
52348
52387
  {
52349
52388
  id: "addons",
52350
52389
  family: "system",
52351
- label: "Addons",
52352
- kinds: [
52353
- "addon-crash-loop",
52354
- "addon-update-available",
52355
- "addon-updated"
52356
- ]
52390
+ label: "Addons stopped",
52391
+ kinds: ["addon-crash-loop"]
52392
+ },
52393
+ {
52394
+ id: "addon-updates",
52395
+ family: "system",
52396
+ label: "Addon updates",
52397
+ kinds: ["addon-update-available", "addon-updated"]
52357
52398
  },
52358
52399
  {
52359
52400
  id: "updates",
@@ -52513,13 +52554,15 @@ var STATE_SUMMARY_SECTION_VARS = [
52513
52554
  },
52514
52555
  {
52515
52556
  name: "summaryAddons",
52516
- label: "Summary: addons",
52517
- example: "@camstack/addon-recorder 1.2.3 → 1.2.4",
52518
- kinds: [
52519
- "addon-crash-loop",
52520
- "addon-update-available",
52521
- "addon-updated"
52522
- ]
52557
+ label: "Summary: addons stopped",
52558
+ example: "hub — recorder stopped after repeated crashes",
52559
+ kinds: ["addon-crash-loop"]
52560
+ },
52561
+ {
52562
+ name: "summaryAddonUpdates",
52563
+ label: "Summary: addon updates",
52564
+ example: "hub:\n• @camstack/addon-recorder 1.2.3 → 1.2.4",
52565
+ kinds: ["addon-update-available", "addon-updated"]
52523
52566
  },
52524
52567
  {
52525
52568
  name: "summaryUpdates",
@@ -52603,6 +52646,7 @@ var STATE_SUMMARY_VARS = [
52603
52646
  [...RULE_BODY_ONLY],
52604
52647
  [...RULE_TEXT],
52605
52648
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
52649
+ ([...RULE_TEXT], [...COMBINED_ALARM]),
52606
52650
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
52607
52651
  ([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
52608
52652
  ([...RULE_TEXT], [...CONSUMABLE]),
@@ -52643,6 +52687,8 @@ var STATE_SUMMARY_VARS = [
52643
52687
  [...RULE_TEXT],
52644
52688
  [...RULE_TEXT],
52645
52689
  [...RULE_TEXT],
52690
+ [...RULE_TEXT],
52691
+ [...RULE_TEXT],
52646
52692
  ...STATE_SUMMARY_VARS
52647
52693
  ];
52648
52694
  new Set([
@@ -96247,26 +96293,6 @@ function setBrokerDevicesOnline(devices, brokerId, online) {
96247
96293
  }
96248
96294
  //#endregion
96249
96295
  //#region src/alexa-state-to-cap.ts
96250
- /**
96251
- * Pure decoders translating a single polled Alexa property value (as stored on
96252
- * the {@link AlexaAccountResolver} by interface + property) into the CamStack cap
96253
- * status field it drives. The inverse of the exporter's report-state mapping.
96254
- *
96255
- * Each function takes the raw `unknown` value (provider-specific) and returns a
96256
- * narrowed primitive or `null` when the value is absent / unrecognised, so the
96257
- * device class can fall back to its cold-start/runtime default. No I/O, no
96258
- * alexa-remote2 import — unit-testable with fixtures.
96259
- *
96260
- * Alexa property reference (smart-home Phoenix state):
96261
- * - Alexa.PowerController.powerState → 'ON' | 'OFF'
96262
- * - Alexa.BrightnessController.brightness → 0..100
96263
- * - Alexa.LockController.lockState → 'LOCKED' | 'UNLOCKED' | 'JAMMED'
96264
- * - Alexa.ContactSensor.detectionState → 'DETECTED' | 'NOT_DETECTED'
96265
- * - Alexa.MotionSensor.detectionState → 'DETECTED' | 'NOT_DETECTED'
96266
- * - Alexa.TemperatureSensor.temperature → { value:number, scale:'CELSIUS'|'FAHRENHEIT' } | number
96267
- * - Alexa.PercentageController.percentage → 0..100
96268
- * - humidity → number (percent)
96269
- */
96270
96296
  /** Decode an Alexa `powerState` to a boolean on-state, or null. */
96271
96297
  function decodePowerState(value) {
96272
96298
  if (value === "ON") return true;
package/dist/addon.mjs CHANGED
@@ -10690,11 +10690,11 @@ var ModelVariantGroupSchema = object({
10690
10690
  /** Quantization axis. Omit ⇒ the fp32 base build. */
10691
10691
  precision: _enum(["fp32", "int8"]).optional(),
10692
10692
  /**
10693
- * Speed-optimization axis. Omit ⇒ the standard build. `fast` marks a
10694
- * latency-optimized export (e.g. ReLU-activation variant) — the slot the
10695
- * future performance variants plug into.
10693
+ * Training / latency-variant axis. Omit ⇒ the standard build. `test` marks
10694
+ * an alternate training of the same family (Scrypted `relu_test`); chip
10695
+ * label is "Test".
10696
10696
  */
10697
- optimization: _enum(["standard", "fast"]).optional(),
10697
+ optimization: _enum(["standard", "test"]).optional(),
10698
10698
  /**
10699
10699
  * Input-resolution axis (square input side, px). Omit ⇒ the family's native
10700
10700
  * resolution (640 for yolo26). Reduced-input builds (320 / 256) are a big,
@@ -10717,9 +10717,10 @@ var ModelProviderIdSchema = _enum([
10717
10717
  * are per upstream. A persisted custom-model row written when this field was a
10718
10718
  * string still parses — the string is lifted into `{ weights }`.
10719
10719
  *
10720
- * Every licence surface (the admin "Models and licenses" page,
10721
- * `THIRD_PARTY_MODELS.md`, the Hugging Face model table) is GENERATED from
10722
- * these records by `scripts/gen-model-licenses.ts` (D661).
10720
+ * Every machine licence surface (`THIRD_PARTY_MODELS.md`, the Hugging Face
10721
+ * model table) is GENERATED from these records by
10722
+ * `scripts/gen-model-licenses.ts` (D661). Operator-facing docs live in
10723
+ * `camstack/docs` → `/docs/detection/models`.
10723
10724
  */
10724
10725
  var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { weights: value } : value, object({
10725
10726
  /** SPDX id of the WEIGHTS' terms, a `LicenseRef-*` for non-SPDX terms, or `UNKNOWN`. */
@@ -14418,7 +14419,7 @@ DeviceType.Camera;
14418
14419
  * This matters here more than anywhere else in the repo, because every provider
14419
14420
  * that knows a device's host knows its PASSWORD too: `{ host, port, username,
14420
14421
  * password }` sit in one object on Hikvision, Amcrest, Reolink and ONVIF alike,
14421
- * and `http://admin:hunter2@192.168.x.x/` is a URL a browser accepts. The
14422
+ * and `http://admin:hunter2@192.168.60.139/` is a URL a browser accepts. The
14422
14423
  * camera's own page will ask for its own login. That is correct, and pre-
14423
14424
  * filling it is the operator's business, not ours.
14424
14425
  *
@@ -17607,7 +17608,7 @@ method(object({
17607
17608
  timeoutMs: 6e5
17608
17609
  });
17609
17610
  method(object({
17610
- nodeId: string(),
17611
+ targetNodeId: string(),
17611
17612
  modelId: string(),
17612
17613
  format: _enum(MODEL_FORMATS),
17613
17614
  entry: ModelCatalogEntrySchema
@@ -20111,8 +20112,9 @@ var NcRuleSchema = NcRuleInputSchema.extend({
20111
20112
  disabledTargetIds: array(string()).default([])
20112
20113
  });
20113
20114
  /**
20114
- * The state-summary SECTIONS (D647 / D698): the D637 kind groups that report a
20115
- * still-true state. `backups-exports` and `alarm` are not sections — a completed
20115
+ * The state-summary SECTIONS (D647 / D698 / D708): the D637 kind groups that
20116
+ * report a still-true state. `addons` is the crash-looped addons only and
20117
+ * `addon-updates` the addons that are behind (D708 split them). `backups-exports` and `alarm` are not sections — a completed
20116
20118
  * job is not an open state, and the alarm stays instant.
20117
20119
  */
20118
20120
  var NcStateSummarySectionIdSchema = _enum([
@@ -20124,6 +20126,7 @@ var NcStateSummarySectionIdSchema = _enum([
20124
20126
  "detection-blind",
20125
20127
  "nodes",
20126
20128
  "addons",
20129
+ "addon-updates",
20127
20130
  "updates"
20128
20131
  ]);
20129
20132
  /** One section of a previewed state summary. `unavailable` = its state could not be read. */
@@ -20604,7 +20607,19 @@ var NcAlarmModeDelaysListSchema = array(object({
20604
20607
  * When this mode may be armed. Absent / null = always allowed (same as a
20605
20608
  * rule with no `schedule`). Evaluated with {@link isScheduleActive}.
20606
20609
  */
20607
- schedule: NcScheduleSchema.optional()
20610
+ schedule: NcScheduleSchema.optional(),
20611
+ /**
20612
+ * D706: while this mode's ENTRY DELAY runs, do the alarm rules' own pushes go out (as an
20613
+ * intrusion naming the locations)? Absent = false — the entry-delay notification is the
20614
+ * only one, and the matches ride the triggered notification's mosaic (D705).
20615
+ */
20616
+ notifyDuringEntryDelay: boolean().optional(),
20617
+ /**
20618
+ * D706: notify "watched again" when a sensor this arm bypassed closes and opens again.
20619
+ * Absent = false (logged, not sent). Even when true it is not sent when that same sensor
20620
+ * is the one that starts the entry delay — the entry-delay notification already names it.
20621
+ */
20622
+ notifySensorRewatched: boolean().optional()
20608
20623
  })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
20609
20624
  var NcAlarmModeDelaysEditListSchema = array(object({
20610
20625
  mode: AlarmArmModeSchema,
@@ -20613,7 +20628,11 @@ var NcAlarmModeDelaysEditListSchema = array(object({
20613
20628
  triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional(),
20614
20629
  postTriggeredAction: NcAlarmPostTriggeredActionSchema.nullable().optional(),
20615
20630
  /** Set a schedule, or `null` to clear (mode always allowed again). */
20616
- schedule: NcScheduleSchema.nullable().optional()
20631
+ schedule: NcScheduleSchema.nullable().optional(),
20632
+ /** D706: set the switch, or `null` to clear it (back to the default, false). */
20633
+ notifyDuringEntryDelay: boolean().nullable().optional(),
20634
+ /** D706: set the switch, or `null` to clear it (back to the default, false). */
20635
+ notifySensorRewatched: boolean().nullable().optional()
20617
20636
  })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
20618
20637
  /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
20619
20638
  var NcAlarmNonBlockingEditSchema = object({
@@ -21574,39 +21593,19 @@ Object.freeze(Object.fromEntries([{
21574
21593
  label: "Face recognition model",
21575
21594
  defaultModelId: "auraface-r100",
21576
21595
  indexName: "the enrolled face gallery",
21577
- options: [
21578
- {
21579
- id: "auraface-r100",
21580
- label: "AuraFace R100"
21581
- },
21582
- {
21583
- id: "arcface-r100",
21584
- label: "ArcFace (ResNet34)"
21585
- },
21586
- {
21587
- id: "inception-resnet-v1",
21588
- label: "Inception ResNet V1"
21589
- }
21590
- ]
21596
+ options: [{
21597
+ id: "auraface-r100",
21598
+ label: "AuraFace R100"
21599
+ }]
21591
21600
  }, {
21592
21601
  stepId: "clip-embedding",
21593
21602
  label: "Semantic search model",
21594
- defaultModelId: "mobileclip-s1",
21603
+ defaultModelId: "siglip2-b16-224",
21595
21604
  indexName: "the object semantic-search index",
21596
- options: [
21597
- {
21598
- id: "mobileclip-s1",
21599
- label: "MobileCLIP S1"
21600
- },
21601
- {
21602
- id: "mobileclip-s2",
21603
- label: "MobileCLIP S2"
21604
- },
21605
- {
21606
- id: "siglip2-b16-224",
21607
- label: "SigLIP2 B/16 (Apache-2.0)"
21608
- }
21609
- ]
21605
+ options: [{
21606
+ id: "siglip2-b16-224",
21607
+ label: "SigLIP2 B/16 (Apache-2.0)"
21608
+ }]
21610
21609
  }].map((s) => [s.stepId, s.defaultModelId])));
21611
21610
  var CLUSTER_STEP_SETTING_FIELDS = [{
21612
21611
  stepId: "face-embedding",
@@ -24494,6 +24493,22 @@ var MotionSourceEnum = _enum([
24494
24493
  "device-activity"
24495
24494
  ]);
24496
24495
  /**
24496
+ * What opened an on-motion detection SESSION: the motion source that passed the
24497
+ * camera's `motionSources` gate, and what raised it (the camera itself, or a
24498
+ * sensor the operator attached — D672). `sensorName` is the attached sensor's
24499
+ * device name as the orchestrator's camera-sensors resolution last read it;
24500
+ * absent when unknown or when the camera itself triggered.
24501
+ *
24502
+ * Carried on the session attach ONLY so the runner's `DetectionPhaseTransition`
24503
+ * can say what started the session (D672 rule 11, amended 2026-10-06). The
24504
+ * runner never decides anything on it.
24505
+ */
24506
+ var SessionTriggerSchema = object({
24507
+ source: MotionSourceEnum,
24508
+ triggeredBy: MotionTriggeredBySchema,
24509
+ sensorName: string().optional()
24510
+ });
24511
+ /**
24497
24512
  * List of motion sources active on a camera. Empty array is valid:
24498
24513
  * "no source" — happens for battery cams without firmware motion when
24499
24514
  * the operator hasn't opted into the SW analyzer (would hold the
@@ -24745,6 +24760,14 @@ var RunnerCameraConfigSchema = object({
24745
24760
  */
24746
24761
  motionSources: MotionSourcesSchema.default(["analyzer"]),
24747
24762
  /**
24763
+ * What opened this attach, on a SESSION attach only (see
24764
+ * {@link SessionTriggerSchema}). OPTIONAL with no default: absent on a
24765
+ * standing attach, an occupancy burst, a re-dispatch with no motion event
24766
+ * behind it, and every attach from an orchestrator older than the field — the
24767
+ * runner then names no source on the phase event.
24768
+ */
24769
+ sessionTrigger: SessionTriggerSchema.optional(),
24770
+ /**
24748
24771
  * WHICH root detector runs for this camera. The detection counterpart of
24749
24772
  * {@link motionSources}, same shape and same discipline: a per-camera list
24750
24773
  * of sources the system understands, vendor-agnostic, owned here.
@@ -32150,7 +32173,7 @@ var LocalInterfaceSchema = object({
32150
32173
  name: string(),
32151
32174
  family: _enum(["IPv4", "IPv6"]),
32152
32175
  address: string(),
32153
- /** CIDR shorthand (e.g. `192.168.x.x/24`). Empty when OS doesn't expose. */
32176
+ /** CIDR shorthand (e.g. `192.168.10.10/24`). Empty when OS doesn't expose. */
32154
32177
  cidr: string(),
32155
32178
  /** OS netmask. Stable across calls so the SDK can hash on it. */
32156
32179
  netmask: string(),
@@ -32204,7 +32227,8 @@ var ConnectionEndpointSchema = object({
32204
32227
  "lan-ipv4",
32205
32228
  "lan-ipv6",
32206
32229
  "public",
32207
- "loopback"
32230
+ "loopback",
32231
+ "app-link"
32208
32232
  ]),
32209
32233
  /**
32210
32234
  * Originating-interface kind — `lan`/`wifi`/`docker`/`vpn`/`other`/
@@ -32273,15 +32297,27 @@ var GetConnectionEndpointsResultSchema = object({
32273
32297
  localPort: AdvertisedLocalPortSchema
32274
32298
  });
32275
32299
  /**
32276
- * The chosen outbound endpoint for notification artifacts. `baseUrl: null` =
32277
- * AUTO (resolved from the candidate ranking at send time); `resolved` reports
32278
- * what AUTO currently picks, so the UI can show the effective value either way.
32300
+ * The address flagged for notification links. `baseUrl: null` = AUTO, which
32301
+ * since D709 is the CamStack app link; `resolved` reports the effective value,
32302
+ * so the UI can show it either way.
32279
32303
  */
32280
32304
  var NotificationEndpointSchema = object({
32281
32305
  /** The operator's explicit choice, or null for AUTO. */
32282
32306
  baseUrl: string().nullable(),
32283
- /** What the ranking currently resolves to (null when nothing is reachable). */
32284
- resolved: string().nullable()
32307
+ /**
32308
+ * The effective flagged address: the explicit choice, else (AUTO) the
32309
+ * CamStack app link `https://camstack.zentik.app` (D709). A pre-D709 hub
32310
+ * answered the public tunnel / mesh here, or null.
32311
+ */
32312
+ resolved: string().nullable(),
32313
+ /**
32314
+ * The hub origin an app link carries as `hub=` (D709): the hub's best
32315
+ * public HTTPS address — the tunnel, then the mesh (Tailscale MagicDNS) —
32316
+ * picked from this cap's own palette by `pickAppLinkHub`. `null` when the
32317
+ * hub advertises neither; the app link is then minted without `hub=`.
32318
+ * Absent on a pre-D709 hub.
32319
+ */
32320
+ appLinkHub: string().nullable()
32285
32321
  });
32286
32322
  /**
32287
32323
  * The URLs the SDK / viewer should race for API access. `baseUrls` empty =
@@ -32335,7 +32371,11 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
32335
32371
  * Pass `'https'` when the caller is itself loaded over HTTPS
32336
32372
  * to avoid mixed-content blocks in the browser. The public
32337
32373
  * tunnel always emits `https://` regardless. */
32338
- scheme: _enum(["http", "https"]).optional()
32374
+ scheme: _enum(["http", "https"]).optional(),
32375
+ /** Append the CamStack app link entry (`kind: 'app-link'`, D709) —
32376
+ * an address notification links can be flagged with, not a hub
32377
+ * route. Default `false`: racers and rankers never see it. */
32378
+ includeAppLink: boolean().optional()
32339
32379
  }), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), ViewerEndpointsSchema), method(object({ baseUrls: array(string()).readonly() }), ViewerEndpointsSchema, { kind: "mutation" }), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" }), method(_void(), TlsStatusSchema), method(object({ reason: string().optional() }), TlsStatusSchema, {
32340
32380
  kind: "mutation",
32341
32381
  auth: "admin"
@@ -32664,7 +32704,7 @@ var MeshPeerSchema = object({
32664
32704
  tags: array(string()).readonly(),
32665
32705
  /** True when the peer advertises itself as an exit-node candidate. */
32666
32706
  exitNodeOption: boolean(),
32667
- /** Subnet routes the peer advertises (e.g. `["192.168.x.x/24"]`). */
32707
+ /** Subnet routes the peer advertises (e.g. `["192.168.10.0/24"]`). */
32668
32708
  advertisedRoutes: array(string()).readonly(),
32669
32709
  /** Owner account login (e.g. `foo@example.com`). Null for tagged peers. */
32670
32710
  userLogin: string().nullable(),
@@ -33992,7 +34032,13 @@ var OsdStatusSchema = object({ overlays: array(object({
33992
34032
  */
33993
34033
  availablePositions: array(OsdPositionEnum).readonly(),
33994
34034
  /** Firmware does not allow editing the `text` field (e.g. timestamp). */
33995
- readOnly: boolean().optional()
34035
+ readOnly: boolean().optional(),
34036
+ /**
34037
+ * Firmware text ceiling for this overlay. Absent = no known limit.
34038
+ * The OSD manager truncates here on every write — never stores its own
34039
+ * copy on the binding.
34040
+ */
34041
+ maxCharacters: number().int().positive().optional()
33996
34042
  })).readonly() });
33997
34043
  var OsdOverlayPatchSchema = object({
33998
34044
  enabled: boolean().optional(),
@@ -34043,7 +34089,9 @@ var OsdTemplateBindingSchema = object({
34043
34089
  valuePath: string().min(1).max(64),
34044
34090
  /** Convert TO this unit at render (`tryConvertUnit`). Absent = source unit. */
34045
34091
  displayUnit: string().max(16).optional(),
34046
- maxDecimals: number().int().min(0).max(4).default(1)
34092
+ maxDecimals: number().int().min(0).max(4).default(1),
34093
+ /** Raw value → display text (same shape as slot binding). Empty string hides. */
34094
+ valueMap: record(string(), string()).optional()
34047
34095
  });
34048
34096
  /**
34049
34097
  * A named template: bindings (alias → leaf field) + a parser that
@@ -34093,18 +34141,11 @@ var OsdSlotBindingSchema = object({
34093
34141
  source: OsdSourceSchema,
34094
34142
  /** `${value}` and `${unit}` are substituted; every occurrence. */
34095
34143
  template: string().max(96).default("${value}"),
34096
- /** Truncate with an ellipsis past this length. Absent = no limit. */
34097
- maxCharacters: number().int().min(4).max(64).optional(),
34098
34144
  /**
34099
34145
  * Decimal places for a numeric value. `0` yields an integer — the
34100
34146
  * documented workaround for firmwares that reject `.` in overlay text.
34101
34147
  */
34102
34148
  maxDecimals: number().int().min(0).max(4).default(1),
34103
- /**
34104
- * Appended via `${unit}` when no unit conversion produces a label.
34105
- * Prefer `source.displayUnit` for converted device-state values.
34106
- */
34107
- unitLabel: string().max(8).optional(),
34108
34149
  /** Raw value → display text, e.g. `{"true":"MOTION","false":""}`. */
34109
34150
  valueMap: record(string(), string()).optional(),
34110
34151
  /** Time windows in which the slot is shown. Absent = always. */
@@ -34113,9 +34154,7 @@ var OsdSlotBindingSchema = object({
34113
34154
  * Display gate, in the notification centre's condition vocabulary.
34114
34155
  * Only the keys reported by `getConditionSupport` are accepted.
34115
34156
  */
34116
- conditions: NcConditionsSchema.optional(),
34117
- /** Rendered when the gate is closed or the value unreadable. Empty = hide. */
34118
- fallbackText: string().max(64).default("")
34157
+ conditions: NcConditionsSchema.optional()
34119
34158
  });
34120
34159
  /** One camera slot, as the operator sees it: firmware truth + our binding. */
34121
34160
  var OsdSlotViewSchema = object({
@@ -52348,12 +52387,14 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
52348
52387
  {
52349
52388
  id: "addons",
52350
52389
  family: "system",
52351
- label: "Addons",
52352
- kinds: [
52353
- "addon-crash-loop",
52354
- "addon-update-available",
52355
- "addon-updated"
52356
- ]
52390
+ label: "Addons stopped",
52391
+ kinds: ["addon-crash-loop"]
52392
+ },
52393
+ {
52394
+ id: "addon-updates",
52395
+ family: "system",
52396
+ label: "Addon updates",
52397
+ kinds: ["addon-update-available", "addon-updated"]
52357
52398
  },
52358
52399
  {
52359
52400
  id: "updates",
@@ -52513,13 +52554,15 @@ var STATE_SUMMARY_SECTION_VARS = [
52513
52554
  },
52514
52555
  {
52515
52556
  name: "summaryAddons",
52516
- label: "Summary: addons",
52517
- example: "@camstack/addon-recorder 1.2.3 → 1.2.4",
52518
- kinds: [
52519
- "addon-crash-loop",
52520
- "addon-update-available",
52521
- "addon-updated"
52522
- ]
52557
+ label: "Summary: addons stopped",
52558
+ example: "hub — recorder stopped after repeated crashes",
52559
+ kinds: ["addon-crash-loop"]
52560
+ },
52561
+ {
52562
+ name: "summaryAddonUpdates",
52563
+ label: "Summary: addon updates",
52564
+ example: "hub:\n• @camstack/addon-recorder 1.2.3 → 1.2.4",
52565
+ kinds: ["addon-update-available", "addon-updated"]
52523
52566
  },
52524
52567
  {
52525
52568
  name: "summaryUpdates",
@@ -52603,6 +52646,7 @@ var STATE_SUMMARY_VARS = [
52603
52646
  [...RULE_BODY_ONLY],
52604
52647
  [...RULE_TEXT],
52605
52648
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
52649
+ ([...RULE_TEXT], [...COMBINED_ALARM]),
52606
52650
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
52607
52651
  ([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
52608
52652
  ([...RULE_TEXT], [...CONSUMABLE]),
@@ -52643,6 +52687,8 @@ var STATE_SUMMARY_VARS = [
52643
52687
  [...RULE_TEXT],
52644
52688
  [...RULE_TEXT],
52645
52689
  [...RULE_TEXT],
52690
+ [...RULE_TEXT],
52691
+ [...RULE_TEXT],
52646
52692
  ...STATE_SUMMARY_VARS
52647
52693
  ];
52648
52694
  new Set([
@@ -96247,26 +96293,6 @@ function setBrokerDevicesOnline(devices, brokerId, online) {
96247
96293
  }
96248
96294
  //#endregion
96249
96295
  //#region src/alexa-state-to-cap.ts
96250
- /**
96251
- * Pure decoders translating a single polled Alexa property value (as stored on
96252
- * the {@link AlexaAccountResolver} by interface + property) into the CamStack cap
96253
- * status field it drives. The inverse of the exporter's report-state mapping.
96254
- *
96255
- * Each function takes the raw `unknown` value (provider-specific) and returns a
96256
- * narrowed primitive or `null` when the value is absent / unrecognised, so the
96257
- * device class can fall back to its cold-start/runtime default. No I/O, no
96258
- * alexa-remote2 import — unit-testable with fixtures.
96259
- *
96260
- * Alexa property reference (smart-home Phoenix state):
96261
- * - Alexa.PowerController.powerState → 'ON' | 'OFF'
96262
- * - Alexa.BrightnessController.brightness → 0..100
96263
- * - Alexa.LockController.lockState → 'LOCKED' | 'UNLOCKED' | 'JAMMED'
96264
- * - Alexa.ContactSensor.detectionState → 'DETECTED' | 'NOT_DETECTED'
96265
- * - Alexa.MotionSensor.detectionState → 'DETECTED' | 'NOT_DETECTED'
96266
- * - Alexa.TemperatureSensor.temperature → { value:number, scale:'CELSIUS'|'FAHRENHEIT' } | number
96267
- * - Alexa.PercentageController.percentage → 0..100
96268
- * - humidity → number (percent)
96269
- */
96270
96296
  /** Decode an Alexa `powerState` to a boolean on-state, or null. */
96271
96297
  function decodePowerState(value) {
96272
96298
  if (value === "ON") return true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-import-alexa",
3
- "version": "0.2.118",
3
+ "version": "0.2.119",
4
4
  "description": "Alexa device-import provider for CamStack — imports the smart-home devices in a user's Alexa account via the unofficial alexa-remote2 cookie/token client (the inverse of the Alexa exporter)",
5
5
  "keywords": [
6
6
  "camstack",