@camstack/addon-post-analysis 1.2.336 → 1.2.338

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 (15) hide show
  1. package/dist/{clip-model-registry-D7e1kEqc.mjs → clip-model-registry-BLUVLdlY.mjs} +492 -195
  2. package/dist/{clip-model-registry-BxUHFGUg.js → clip-model-registry-BcSLJ8aL.js} +502 -193
  3. package/dist/embedding-encoder/index.js +2 -2
  4. package/dist/embedding-encoder/index.mjs +2 -2
  5. package/dist/pipeline-analytics/_stub.js +2 -2
  6. package/dist/pipeline-analytics/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-y9isEkU9.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-DDfv_NZB.mjs} +2 -2
  7. package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-D3jDbheU.mjs +26 -0
  8. package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BRmdbHeK.mjs +26 -0
  9. package/dist/pipeline-analytics/{hostInit-DH7hZ_gJ.mjs → hostInit-BTA95n_5.mjs} +2 -2
  10. package/dist/pipeline-analytics/index.js +149 -62
  11. package/dist/pipeline-analytics/index.mjs +149 -62
  12. package/dist/pipeline-analytics/remoteEntry.js +1 -1
  13. package/package.json +2 -2
  14. package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BZ-aada5.mjs +0 -26
  15. package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DxUsRAkr.mjs +0 -26
@@ -5482,7 +5482,7 @@ var ZodIssueCode = {
5482
5482
  var ZodFirstPartyTypeKind;
5483
5483
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5484
5484
  //#endregion
5485
- //#region ../types/dist/sleep-DXKLNFvA.mjs
5485
+ //#region ../types/dist/sleep-C16NCZR2.mjs
5486
5486
  /**
5487
5487
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5488
5488
  * window to float samples (D455).
@@ -11560,89 +11560,51 @@ function resolveClipSearchMinScore(meta, request) {
11560
11560
  const factor = CLIP_STRICTNESS_FACTOR[request.strictness ?? "loose"];
11561
11561
  return Math.min(1, Math.round(meta.searchMinScore * factor * 1e3) / 1e3);
11562
11562
  }
11563
- /**
11564
- * The class names a per-class COUNT can ever be keyed on — the macro ids, and
11565
- * only those.
11566
- *
11567
- * `preserveOriginal: false` below is the whole reason this set exists: the
11568
- * executor maps each raw COCO label onto its macro and DROPS everything else,
11569
- * so a tracked detection's `className` is always one of {@link MACRO_LABELS}.
11570
- * Any surface that indexes counts by class name — the ZoneAnalytics occupancy
11571
- * snapshot's `byClass`, and therefore every occupancy rule — can match nothing
11572
- * else. Derived from the catalog, never hand-listed, so a new macro joins it by
11573
- * being declared once.
11574
- *
11575
- * Cost of not having it, 2026-08-12: the notification rule editor offered the
11576
- * full taxonomy for an occupancy class (occupancy is the one condition that
11577
- * does not go through the engine's macro-expanding `expandClassSelector`), two
11578
- * live rules were authored on `car`, and both counters read 0 forever.
11579
- */
11580
- var DETECTION_MACRO_CLASSES = new Set([
11581
- {
11582
- id: "person",
11583
- name: "Person"
11584
- },
11585
- {
11586
- id: "vehicle",
11587
- name: "Vehicle"
11588
- },
11589
- {
11590
- id: "animal",
11591
- name: "Animal"
11592
- },
11593
- {
11594
- id: "package",
11595
- name: "Package"
11596
- }
11597
- ].map((l) => l.id));
11598
- /** True when `className` is a macro the detector can actually emit (and hence a
11599
- * class a count can be keyed on) — see {@link DETECTION_MACRO_CLASSES}. */
11600
- function isDetectionMacroClass(className) {
11601
- return DETECTION_MACRO_CLASSES.has(className.trim().toLowerCase());
11602
- }
11603
- var COCO_TO_MACRO = {
11604
- mapping: {
11605
- person: "person",
11606
- bicycle: "vehicle",
11607
- car: "vehicle",
11608
- motorcycle: "vehicle",
11609
- airplane: "vehicle",
11610
- bus: "vehicle",
11611
- train: "vehicle",
11612
- truck: "vehicle",
11613
- boat: "vehicle",
11614
- bird: "animal",
11615
- cat: "animal",
11616
- dog: "animal",
11617
- horse: "animal",
11618
- sheep: "animal",
11619
- cow: "animal",
11620
- elephant: "animal",
11621
- bear: "animal",
11622
- zebra: "animal",
11623
- giraffe: "animal",
11624
- suitcase: "package",
11625
- backpack: "package",
11626
- handbag: "package"
11627
- },
11628
- preserveOriginal: false
11629
- };
11630
- /** Steps a root detector may declare it fills. */
11631
- var FILLABLE_STEP_IDS = [
11563
+ /** Steps whose effect a root label can BE. */
11564
+ var LABEL_SUPPLY_STEP_IDS = [
11632
11565
  "animal-classifier",
11633
11566
  "vehicle-classifier",
11634
11567
  "package-detection"
11635
11568
  ];
11636
- /** Narrow a step id to a fillable one — type guard, not a cast. */
11637
- function isFillableStepId(value) {
11638
- return FILLABLE_STEP_IDS.some((id) => id === value);
11569
+ /** Steps whose box a root detection can BE. */
11570
+ var CROP_SUPPLY_STEP_IDS = ["plate-detection", "face-detection"];
11571
+ /** Every step a root model can supply. */
11572
+ var ROOT_SUPPLIABLE_STEP_IDS = [...LABEL_SUPPLY_STEP_IDS, ...CROP_SUPPLY_STEP_IDS];
11573
+ /** Narrow a step id to a suppliable one — type guard, not a cast. */
11574
+ function isRootSuppliableStepId(value) {
11575
+ return ROOT_SUPPLIABLE_STEP_IDS.some((id) => id === value);
11576
+ }
11577
+ /** Narrow a step id to a label-kind one. */
11578
+ function isLabelSupplyStepId(value) {
11579
+ return LABEL_SUPPLY_STEP_IDS.some((id) => id === value);
11639
11580
  }
11581
+ var CROP_SUPPLY_SOURCES = {
11582
+ "plate-detection": {
11583
+ rootLabels: ["license_plate"],
11584
+ parentMacro: "vehicle",
11585
+ childClass: "plate",
11586
+ servedChildSteps: ["plate-ocr"],
11587
+ use: "as-output"
11588
+ },
11589
+ "face-detection": {
11590
+ rootLabels: ["face"],
11591
+ parentMacro: "person",
11592
+ childClass: "face",
11593
+ servedChildSteps: ["face-embedding"],
11594
+ use: "refine",
11595
+ minRootInputPx: 640
11596
+ }
11597
+ };
11640
11598
  /** The step a linked label stands in for, or `undefined` for any other attribution. */
11641
11599
  function linkedStepOf(attributionStepId) {
11642
11600
  if (attributionStepId === void 0) return void 0;
11643
11601
  if (!attributionStepId.startsWith("detector-link:")) return void 0;
11644
11602
  const stepId = attributionStepId.slice(14);
11645
- return isFillableStepId(stepId) ? stepId : void 0;
11603
+ return isLabelSupplyStepId(stepId) ? stepId : void 0;
11604
+ }
11605
+ /** The child steps of a crop-kind step that still run on the root's box. */
11606
+ function rootSupplyServes(stepId) {
11607
+ return CROP_SUPPLY_SOURCES[stepId].servedChildSteps;
11646
11608
  }
11647
11609
  var MODEL_FORMATS = [
11648
11610
  "onnx",
@@ -11776,12 +11738,35 @@ var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { wei
11776
11738
  /** True when the weights or their data forbid commercial use. */
11777
11739
  nonCommercial: boolean().optional()
11778
11740
  }));
11779
- /** One `fillsClassifierEffects` entry — see `ModelCatalogEntry.fillsClassifierEffects`. */
11780
- var FillsClassifierEffectSchema = object({
11781
- stepId: _enum(FILLABLE_STEP_IDS),
11741
+ /**
11742
+ * One step a ROOT detector can supply from its own output (D730) — see
11743
+ * `ModelCatalogEntry.suppliesSteps`.
11744
+ *
11745
+ * - `label`: the root's raw class IS the step's answer. `labelToEffect` maps
11746
+ * the root's label to the step's vocabulary; `uncovered` is the vocabulary
11747
+ * the root cannot produce (shown as unavailable, never a blocker).
11748
+ * - `crop`: the root draws the box the step would have found (`license_plate`
11749
+ * for plate-detection, `face` for face-detection). The box becomes a detail
11750
+ * child of the `parentMacro` detection that contains it — never a track.
11751
+ */
11752
+ var RootStepSupplySchema = discriminatedUnion("kind", [object({
11753
+ kind: literal("label"),
11754
+ stepId: _enum(LABEL_SUPPLY_STEP_IDS),
11782
11755
  labelToEffect: record(string(), string()),
11783
11756
  uncovered: array(string()).readonly()
11784
- });
11757
+ }), object({
11758
+ kind: literal("crop"),
11759
+ stepId: _enum(CROP_SUPPLY_STEP_IDS),
11760
+ rootLabels: array(string()).readonly(),
11761
+ parentMacro: _enum(["vehicle", "person"]),
11762
+ childClass: _enum(["plate", "face"]),
11763
+ /**
11764
+ * The root's smaller input side, stamped on read by `rootSuppliesOf` from
11765
+ * the model entry — what a step's `minRootInputPx` gate judges. Never
11766
+ * stored by an import.
11767
+ */
11768
+ rootInputPx: number().int().positive().optional()
11769
+ })]);
11785
11770
  var ModelCatalogEntrySchema = object({
11786
11771
  id: string(),
11787
11772
  name: string(),
@@ -11908,15 +11893,15 @@ var ModelCatalogEntrySchema = object({
11908
11893
  */
11909
11894
  classMap: DetectionCatalogClassMapSchema.optional(),
11910
11895
  /**
11911
- * The pipeline steps this ROOT detector already does the work of (D715):
11912
- * its labels name the effect the step exists to produce (`deer` for
11913
- * `animal-classifier`, `package` for `package-detection`). Derived from the
11914
- * labelmap by `deriveClassifierFills`, never hand-written; a COCO model
11915
- * declares none. Whether a declaration is honoured is the step's own
11916
- * `labelLink` policy (`resolveLabelLink`). `labelToEffect` values are in
11917
- * `FILLABLE_STEP_VOCABULARIES` (guard `check-label-link-vocabulary`).
11896
+ * The pipeline steps this ROOT detector can supply from its own output
11897
+ * (D730): its labels name a step's effect (`deer` for `animal-classifier`)
11898
+ * or draw a step's box (`license_plate` for `plate-detection`). Computed at
11899
+ * import from THIS model's labelmap by `deriveRootSupplies`, never written
11900
+ * by hand and never assumed per family; a row without it is derived on read
11901
+ * (`rootSuppliesOf`). Whether a camera uses it is the step's own
11902
+ * `useRootModel` flag (`resolveRootSupply`).
11918
11903
  */
11919
- fillsClassifierEffects: array(FillsClassifierEffectSchema).readonly().optional(),
11904
+ suppliesSteps: array(RootStepSupplySchema).readonly().optional(),
11920
11905
  /**
11921
11906
  * The model's CLIP feature-space contract (text encoder, dimension, vector
11922
11907
  * index, token window, search floor) — see `clip-model.ts`. Present ONLY on a
@@ -19500,6 +19485,96 @@ var filesystemBrowseCapability = {
19500
19485
  })
19501
19486
  }
19502
19487
  };
19488
+ /** The central link domain the viewer app claims (Universal Links / App Links). */
19489
+ var CAMSTACK_APP_LINK_ORIGIN = "https://camstack.zentik.app";
19490
+ /** Where the hub serves the viewer SPA. */
19491
+ var HUB_VIEWER_MOUNT = "/viewer/camstack";
19492
+ /** True when `baseUrl` names the CamStack app link rather than a hub address. */
19493
+ function isAppLinkBase(baseUrl) {
19494
+ if (baseUrl === null || baseUrl === void 0 || baseUrl === "") return false;
19495
+ try {
19496
+ return new URL(baseUrl).origin === CAMSTACK_APP_LINK_ORIGIN;
19497
+ } catch {
19498
+ return false;
19499
+ }
19500
+ }
19501
+ /**
19502
+ * The base a viewer link is built on, from the flagged notification address:
19503
+ * the effective address is the explicit choice, else AUTO's `resolved`. The
19504
+ * one reading of that answer — the NC's tap and the Network page's preview
19505
+ * both go through it.
19506
+ */
19507
+ function viewerLinkBaseOf(endpoint) {
19508
+ const flagged = endpoint.baseUrl ?? endpoint.resolved;
19509
+ return isAppLinkBase(flagged) ? {
19510
+ form: "app",
19511
+ hubBaseUrl: endpoint.appLinkHub ?? null
19512
+ } : {
19513
+ form: "hub",
19514
+ hubBaseUrl: flagged
19515
+ };
19516
+ }
19517
+ /**
19518
+ * Reduce a base URL to the bare origin the central page accepts as `hub=`,
19519
+ * or `null` when it cannot be one: not http(s), carries credentials, or does
19520
+ * not parse. A path/query/fragment is dropped — the central page mounts the
19521
+ * viewer under the origin itself.
19522
+ */
19523
+ function toAppLinkHubOrigin(baseUrl) {
19524
+ let parsed;
19525
+ try {
19526
+ parsed = new URL(baseUrl);
19527
+ } catch {
19528
+ return null;
19529
+ }
19530
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") return null;
19531
+ if (parsed.username !== "" || parsed.password !== "") return null;
19532
+ if (parsed.hostname === "") return null;
19533
+ return parsed.origin;
19534
+ }
19535
+ /** The viewer route for a destination, or null when it names nothing. */
19536
+ function viewerRoute(destination) {
19537
+ switch (destination.kind) {
19538
+ case "camera": {
19539
+ if (!Number.isInteger(destination.deviceId) || destination.deviceId <= 0) return null;
19540
+ const at = destination.atMs;
19541
+ return {
19542
+ path: `/camera/${String(destination.deviceId)}`,
19543
+ query: at !== void 0 && Number.isFinite(at) ? [["at", String(Math.trunc(at))]] : []
19544
+ };
19545
+ }
19546
+ case "events": return {
19547
+ path: "/events",
19548
+ query: []
19549
+ };
19550
+ case "notifications": return {
19551
+ path: "/notifications",
19552
+ query: []
19553
+ };
19554
+ }
19555
+ }
19556
+ function encodeQuery(query) {
19557
+ if (query.length === 0) return "";
19558
+ return `?${query.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join("&")}`;
19559
+ }
19560
+ /**
19561
+ * The link for a viewer destination, or `null` when none can be minted: an
19562
+ * unknown destination, or the `hub` form with no reachable base (a dead link
19563
+ * is worse than none).
19564
+ */
19565
+ function buildViewerLink(input) {
19566
+ const route = viewerRoute(input.destination);
19567
+ if (route === null) return null;
19568
+ const raw = input.base.hubBaseUrl;
19569
+ const base = raw === null ? "" : raw.replace(/\/+$/, "");
19570
+ if (input.base.form === "app") {
19571
+ const origin = base === "" ? null : toAppLinkHubOrigin(base);
19572
+ const query = origin === null ? route.query : [...route.query, ["hub", origin]];
19573
+ return `${CAMSTACK_APP_LINK_ORIGIN}${route.path}${encodeQuery(query)}`;
19574
+ }
19575
+ if (base === "" || isAppLinkBase(base)) return null;
19576
+ return `${base}${HUB_VIEWER_MOUNT}${route.path}${encodeQuery(route.query)}`;
19577
+ }
19503
19578
  /**
19504
19579
  * Transport bounds for AI capability methods.
19505
19580
  *
@@ -21560,6 +21635,73 @@ var notificationOutputCapability = {
21560
21635
  })
21561
21636
  }
21562
21637
  };
21638
+ /**
21639
+ * The class names a per-class COUNT can ever be keyed on — the macro ids, and
21640
+ * only those.
21641
+ *
21642
+ * `preserveOriginal: false` below is the whole reason this set exists: the
21643
+ * executor maps each raw COCO label onto its macro and DROPS everything else,
21644
+ * so a tracked detection's `className` is always one of {@link MACRO_LABELS}.
21645
+ * Any surface that indexes counts by class name — the ZoneAnalytics occupancy
21646
+ * snapshot's `byClass`, and therefore every occupancy rule — can match nothing
21647
+ * else. Derived from the catalog, never hand-listed, so a new macro joins it by
21648
+ * being declared once.
21649
+ *
21650
+ * Cost of not having it, 2026-08-12: the notification rule editor offered the
21651
+ * full taxonomy for an occupancy class (occupancy is the one condition that
21652
+ * does not go through the engine's macro-expanding `expandClassSelector`), two
21653
+ * live rules were authored on `car`, and both counters read 0 forever.
21654
+ */
21655
+ var DETECTION_MACRO_CLASSES = new Set([
21656
+ {
21657
+ id: "person",
21658
+ name: "Person"
21659
+ },
21660
+ {
21661
+ id: "vehicle",
21662
+ name: "Vehicle"
21663
+ },
21664
+ {
21665
+ id: "animal",
21666
+ name: "Animal"
21667
+ },
21668
+ {
21669
+ id: "package",
21670
+ name: "Package"
21671
+ }
21672
+ ].map((l) => l.id));
21673
+ /** True when `className` is a macro the detector can actually emit (and hence a
21674
+ * class a count can be keyed on) — see {@link DETECTION_MACRO_CLASSES}. */
21675
+ function isDetectionMacroClass(className) {
21676
+ return DETECTION_MACRO_CLASSES.has(className.trim().toLowerCase());
21677
+ }
21678
+ var COCO_TO_MACRO = {
21679
+ mapping: {
21680
+ person: "person",
21681
+ bicycle: "vehicle",
21682
+ car: "vehicle",
21683
+ motorcycle: "vehicle",
21684
+ airplane: "vehicle",
21685
+ bus: "vehicle",
21686
+ train: "vehicle",
21687
+ truck: "vehicle",
21688
+ boat: "vehicle",
21689
+ bird: "animal",
21690
+ cat: "animal",
21691
+ dog: "animal",
21692
+ horse: "animal",
21693
+ sheep: "animal",
21694
+ cow: "animal",
21695
+ elephant: "animal",
21696
+ bear: "animal",
21697
+ zebra: "animal",
21698
+ giraffe: "animal",
21699
+ suitcase: "package",
21700
+ backpack: "package",
21701
+ handbag: "package"
21702
+ },
21703
+ preserveOriginal: false
21704
+ };
21563
21705
  var AUDIO_MACRO_LABELS = [
21564
21706
  {
21565
21707
  id: "speech",
@@ -24109,7 +24251,7 @@ var NC_CONDITION_CATALOG = [
24109
24251
  operator: "in",
24110
24252
  appliesTo: ["immediate", "track-end"],
24111
24253
  phase: "P1",
24112
- description: "Only recognised people. Selecting NOBODY means every identity in the face gallery; selecting some narrows to those. Matched on the gallery id, so renaming a person does not break the rule. On Immediate delivery the name must already be known when an event is written — choose Immediate, grouped to wait for it (D692)."
24254
+ description: "Only recognised people. Selecting NOBODY means every identity in the face gallery; selecting some narrows to those. Matched on the gallery id, so renaming a person does not break the rule. On Immediate delivery the name must already be known when an event is written — choose Immediate, grouped to wait for it."
24113
24255
  },
24114
24256
  {
24115
24257
  id: "plates",
@@ -28530,6 +28672,34 @@ var pipelineAnalyticsCapability = {
28530
28672
  }
28531
28673
  };
28532
28674
  /**
28675
+ * A root model's boxes standing in for one crop-kind step's own inference
28676
+ * (D730) — see `runPipeline.suppliedRoot`.
28677
+ */
28678
+ var SuppliedRootOutputSchema = object({
28679
+ stepId: string(),
28680
+ /** The root model that drew the boxes — stamped on the result. */
28681
+ modelId: string(),
28682
+ detections: array(object({
28683
+ /** `[x1, y1, x2, y2]` in the pixels of the call's image. */
28684
+ bbox: tuple([
28685
+ number(),
28686
+ number(),
28687
+ number(),
28688
+ number()
28689
+ ]),
28690
+ score: number(),
28691
+ /**
28692
+ * Five facial landmarks in the same pixels — a face the step's own
28693
+ * detector already re-found inside a root face box (D730), so its
28694
+ * embedder child aligns it exactly as it aligns any detected face.
28695
+ */
28696
+ landmarks: array(object({
28697
+ x: number(),
28698
+ y: number()
28699
+ })).optional()
28700
+ })).min(1)
28701
+ });
28702
+ /**
28533
28703
  * Reference to the frame's retained NATIVE surface + the parent crop's placement
28534
28704
  * within the frame, so the executor can re-cut a leaf child ROI at native
28535
28705
  * resolution on the detail plane. See the `runPipeline` `nativeCropRef` field.
@@ -28660,7 +28830,7 @@ var PipelineModelOptionSchema = object({
28660
28830
  legacy: boolean().optional(),
28661
28831
  provider: ModelProviderIdSchema.optional(),
28662
28832
  defaultConfidence: number().optional(),
28663
- fillsClassifierEffects: array(FillsClassifierEffectSchema).readonly().optional()
28833
+ suppliesSteps: array(RootStepSupplySchema).readonly().optional()
28664
28834
  });
28665
28835
  var ConfigFieldBridge = custom();
28666
28836
  var PipelineAddonSchemaSchema = object({
@@ -29064,7 +29234,16 @@ var pipelineExecutorCapability = {
29064
29234
  * `device-not-servable`), and nothing reaches the camera's live
29065
29235
  * trace stream. Absent ⇒ unchanged behaviour.
29066
29236
  */
29067
- replay: literal(true).optional()
29237
+ replay: literal(true).optional(),
29238
+ /**
29239
+ * Root-supplied detections for the tree's ROOT step (D730). Set by
29240
+ * `runDetailSubtree` when the camera's root model supplies a crop-kind
29241
+ * step (a Frigate+ `license_plate` for `plate-detection`): the step is
29242
+ * NOT inferred, these boxes are its output, and its children (the plate
29243
+ * reader) run on them through their own crop policy. Boxes are in the
29244
+ * PIXELS of the image this call carries. Absent ⇒ the root step runs.
29245
+ */
29246
+ suppliedRoot: SuppliedRootOutputSchema.optional()
29068
29247
  }), PipelineRunResultBridge, { kind: "mutation" }),
29069
29248
  /**
29070
29249
  * Batched run — N raw frames packed into one cap call. The provider
@@ -30377,7 +30556,22 @@ var pipelineRunnerCapability = {
30377
30556
  */
30378
30557
  cropJpeg: string().optional(),
30379
30558
  parent: DetailParentSchema,
30380
- steps: array(string()).optional()
30559
+ steps: array(string()).optional(),
30560
+ /**
30561
+ * The camera's root model already drew this step's boxes (D730): a
30562
+ * `license_plate` inside the parent vehicle. The named step is NOT
30563
+ * inferred — these FRAME-space boxes are its output — and its
30564
+ * requested children (the plate reader) run on them. Absent ⇒ every
30565
+ * requested step infers as before.
30566
+ */
30567
+ supplied: object({
30568
+ stepId: string(),
30569
+ modelId: string(),
30570
+ boxes: array(object({
30571
+ bbox: NativeCropBboxSchema,
30572
+ score: number()
30573
+ })).min(1)
30574
+ }).optional()
30381
30575
  }), object({ details: array(DetailResultSchema) }).nullable(), { kind: "mutation" }),
30382
30576
  /**
30383
30577
  * Run ONE enrichment step against caller-supplied pixels, with NO camera
@@ -34458,96 +34652,6 @@ var videoclipsCapability = {
34458
34652
  })
34459
34653
  }
34460
34654
  };
34461
- /** The central link domain the viewer app claims (Universal Links / App Links). */
34462
- var CAMSTACK_APP_LINK_ORIGIN = "https://camstack.zentik.app";
34463
- /** Where the hub serves the viewer SPA. */
34464
- var HUB_VIEWER_MOUNT = "/viewer/camstack";
34465
- /** True when `baseUrl` names the CamStack app link rather than a hub address. */
34466
- function isAppLinkBase(baseUrl) {
34467
- if (baseUrl === null || baseUrl === void 0 || baseUrl === "") return false;
34468
- try {
34469
- return new URL(baseUrl).origin === CAMSTACK_APP_LINK_ORIGIN;
34470
- } catch {
34471
- return false;
34472
- }
34473
- }
34474
- /**
34475
- * The base a viewer link is built on, from the flagged notification address:
34476
- * the effective address is the explicit choice, else AUTO's `resolved`. The
34477
- * one reading of that answer — the NC's tap and the Network page's preview
34478
- * both go through it.
34479
- */
34480
- function viewerLinkBaseOf(endpoint) {
34481
- const flagged = endpoint.baseUrl ?? endpoint.resolved;
34482
- return isAppLinkBase(flagged) ? {
34483
- form: "app",
34484
- hubBaseUrl: endpoint.appLinkHub ?? null
34485
- } : {
34486
- form: "hub",
34487
- hubBaseUrl: flagged
34488
- };
34489
- }
34490
- /**
34491
- * Reduce a base URL to the bare origin the central page accepts as `hub=`,
34492
- * or `null` when it cannot be one: not http(s), carries credentials, or does
34493
- * not parse. A path/query/fragment is dropped — the central page mounts the
34494
- * viewer under the origin itself.
34495
- */
34496
- function toAppLinkHubOrigin(baseUrl) {
34497
- let parsed;
34498
- try {
34499
- parsed = new URL(baseUrl);
34500
- } catch {
34501
- return null;
34502
- }
34503
- if (parsed.protocol !== "https:" && parsed.protocol !== "http:") return null;
34504
- if (parsed.username !== "" || parsed.password !== "") return null;
34505
- if (parsed.hostname === "") return null;
34506
- return parsed.origin;
34507
- }
34508
- /** The viewer route for a destination, or null when it names nothing. */
34509
- function viewerRoute(destination) {
34510
- switch (destination.kind) {
34511
- case "camera": {
34512
- if (!Number.isInteger(destination.deviceId) || destination.deviceId <= 0) return null;
34513
- const at = destination.atMs;
34514
- return {
34515
- path: `/camera/${String(destination.deviceId)}`,
34516
- query: at !== void 0 && Number.isFinite(at) ? [["at", String(Math.trunc(at))]] : []
34517
- };
34518
- }
34519
- case "events": return {
34520
- path: "/events",
34521
- query: []
34522
- };
34523
- case "notifications": return {
34524
- path: "/notifications",
34525
- query: []
34526
- };
34527
- }
34528
- }
34529
- function encodeQuery(query) {
34530
- if (query.length === 0) return "";
34531
- return `?${query.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join("&")}`;
34532
- }
34533
- /**
34534
- * The link for a viewer destination, or `null` when none can be minted: an
34535
- * unknown destination, or the `hub` form with no reachable base (a dead link
34536
- * is worse than none).
34537
- */
34538
- function buildViewerLink(input) {
34539
- const route = viewerRoute(input.destination);
34540
- if (route === null) return null;
34541
- const raw = input.base.hubBaseUrl;
34542
- const base = raw === null ? "" : raw.replace(/\/+$/, "");
34543
- if (input.base.form === "app") {
34544
- const origin = base === "" ? null : toAppLinkHubOrigin(base);
34545
- const query = origin === null ? route.query : [...route.query, ["hub", origin]];
34546
- return `${CAMSTACK_APP_LINK_ORIGIN}${route.path}${encodeQuery(query)}`;
34547
- }
34548
- if (base === "" || isAppLinkBase(base)) return null;
34549
- return `${base}${HUB_VIEWER_MOUNT}${route.path}${encodeQuery(route.query)}`;
34550
- }
34551
34655
  /**
34552
34656
  * Optional client-side hints sent at session creation to help the provider
34553
34657
  * pick the best native source. All fields optional — a viewer that knows
@@ -35023,6 +35127,35 @@ var webrtcSessionCapability = {
35023
35127
  alive: boolean()
35024
35128
  })),
35025
35129
  /**
35130
+ * The viewer's downlink probe, for ONE live session (D733).
35131
+ *
35132
+ * The player measures `/adaptive-probe` after the session's first decoded
35133
+ * frame (D635). It used to act on the reading itself, by opening a SECOND
35134
+ * session with `hints.downlinkMbps` — every adaptive live open became two
35135
+ * sessions, two ICE + DTLS handshakes and two server pipelines. It now
35136
+ * hands the measurement to the session it already has; the provider picks
35137
+ * the rung exactly as it would from an offer's hints (same viewport
35138
+ * ceiling) and moves the session there — in place when the negotiated
35139
+ * codec carries the new rendition, by the existing re-offer
35140
+ * (`getSessionState.pendingRenegotiation`) when it cannot.
35141
+ *
35142
+ * A MEASUREMENT, never a tier: the client does not choose. A probe only
35143
+ * raises the rung; lowering it stays the ladder's call on delivery.
35144
+ * `held` answers why nothing moved (`not-adaptive`, `pinned`,
35145
+ * `already-there`, `recorded`, …) — a client that gets ANY answer must not
35146
+ * fall back to a reconnect; only a provider that does not know the method
35147
+ * (an older hub) leaves the client its legacy second session.
35148
+ */
35149
+ applyDownlinkProbe: method(object({
35150
+ deviceId: number().int().nonnegative(),
35151
+ sessionId: string(),
35152
+ downlinkMbps: number().nonnegative()
35153
+ }), object({
35154
+ outcome: _enum(["switching", "held"]),
35155
+ tier: CamProfileSchema.nullable(),
35156
+ reason: string()
35157
+ }), { kind: "mutation" }),
35158
+ /**
35026
35159
  * The SERVER's half of the stream-debug overlay, for one live session.
35027
35160
  *
35028
35161
  * The client can measure its own transport (`getStats()`); it cannot see
@@ -39273,7 +39406,8 @@ var ConnectionEndpointSchema = object({
39273
39406
  "lan-ipv6",
39274
39407
  "public",
39275
39408
  "loopback",
39276
- "app-link"
39409
+ "app-link",
39410
+ "custom"
39277
39411
  ]),
39278
39412
  /**
39279
39413
  * Originating-interface kind — `lan`/`wifi`/`docker`/`vpn`/`other`/
@@ -39375,6 +39509,76 @@ var ViewerEndpointsSchema = object({
39375
39509
  /** What the ranking currently resolves to (may be empty if nothing is up). */
39376
39510
  resolved: array(string()).readonly()
39377
39511
  });
39512
+ /**
39513
+ * DEPRECATED compatibility shape of `getHubAddresses` (D729 amendment, kept
39514
+ * one release for addons built against it): `cluster` is the `agents` role,
39515
+ * `browser` the `signIn` role; `override` is the flagged address.
39516
+ */
39517
+ var HubAddressSnapshotSchema = object({
39518
+ override: string().nullable(),
39519
+ resolved: string().nullable(),
39520
+ source: _enum([
39521
+ "override",
39522
+ "auto",
39523
+ "none"
39524
+ ])
39525
+ });
39526
+ var HubAddressesSchema = object({
39527
+ cluster: HubAddressSnapshotSchema,
39528
+ browser: HubAddressSnapshotSchema
39529
+ });
39530
+ /**
39531
+ * What an address is used for (`hub-address.ts`). `viewer` is many-valued;
39532
+ * `notifications`, `agents` and `signIn` are carried by at most one address.
39533
+ */
39534
+ var HubAddressRoleSchema = _enum([
39535
+ "viewer",
39536
+ "notifications",
39537
+ "agents",
39538
+ "signIn"
39539
+ ]);
39540
+ var RoleSourceSchema = _enum([
39541
+ "flagged",
39542
+ "auto",
39543
+ "none"
39544
+ ]);
39545
+ /** One single-valued role: the flagged address, the one in use, and why. */
39546
+ var HubAddressRoleResolutionSchema = object({
39547
+ /** The address carrying the flag, or null = automatic. */
39548
+ flagged: string().nullable(),
39549
+ /** The address in use, or null when nothing qualifies (never loopback). */
39550
+ resolved: string().nullable(),
39551
+ source: RoleSourceSchema
39552
+ });
39553
+ var HubViewerResolutionSchema = object({
39554
+ /** The addresses flagged `viewer`, or empty = automatic. */
39555
+ flagged: array(string()).readonly(),
39556
+ /** What the apps race right now. */
39557
+ resolved: array(string()).readonly(),
39558
+ source: RoleSourceSchema
39559
+ });
39560
+ var HubAddressBookSchema = object({
39561
+ rows: array(ConnectionEndpointSchema.extend({
39562
+ /** In the hub's detected palette right now. */
39563
+ detected: boolean(),
39564
+ /** Entered by the operator (removable). */
39565
+ custom: boolean(),
39566
+ /** The roles explicitly flagged on this address. */
39567
+ flags: array(HubAddressRoleSchema).readonly(),
39568
+ /** The roles this address serves right now — flagged or automatic. */
39569
+ inUse: array(HubAddressRoleSchema).readonly(),
39570
+ /** The roles this address may be flagged with. */
39571
+ eligible: array(HubAddressRoleSchema).readonly()
39572
+ })).readonly(),
39573
+ roles: object({
39574
+ viewer: HubViewerResolutionSchema,
39575
+ notifications: HubAddressRoleResolutionSchema,
39576
+ agents: HubAddressRoleResolutionSchema,
39577
+ signIn: HubAddressRoleResolutionSchema
39578
+ }),
39579
+ /** The `hub=` an app link carries (D709), or null. */
39580
+ appLinkHub: string().nullable()
39581
+ });
39378
39582
  var AllowedAddressesSchema = object({
39379
39583
  /**
39380
39584
  * Allowlist of interface addresses operators have explicitly opted
@@ -39487,26 +39691,78 @@ var localNetworkCapability = {
39487
39691
  */
39488
39692
  getNotificationEndpoint: method(_void(), NotificationEndpointSchema),
39489
39693
  /**
39490
- * Mark which endpoint notification artifacts use. `baseUrl: null` restores
39491
- * AUTO. The value is stored verbatim (not an index into the candidate
39492
- * list): interfaces come and go, and an index would silently re-point at a
39493
- * different address after a reboot.
39694
+ * @deprecated Use `setAddressRole({ role: 'notifications', … })`. Kept so
39695
+ * an older admin UI keeps working: it writes the same `notifications`
39696
+ * flag, with the same validation. `baseUrl: null` restores automatic; an
39697
+ * address that is not detected becomes a custom address.
39494
39698
  */
39495
39699
  setNotificationEndpoint: method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }),
39496
39700
  /**
39497
- * The endpoints the SDK / viewer races for API access. Empty `baseUrls`
39498
- * means AUTO: every LAN IPv4 address plus the public tunnel, never IPv6,
39499
- * never mesh, never loopback. `resolved` is that set (or the operator's
39500
- * explicit subset) as it stands right now.
39701
+ * The `viewer` role as shipped apps read it: the flagged addresses
39702
+ * (detected or custom), or empty for AUTO — every LAN IPv4 address plus
39703
+ * the public tunnel, never IPv6, mesh, loopback or a custom address.
39704
+ * `resolved` is the set as it stands right now; the custom ones in it are
39705
+ * also in `getConnectionEndpoints`, which the apps filter by it.
39501
39706
  */
39502
39707
  getViewerEndpoints: method(_void(), ViewerEndpointsSchema),
39503
39708
  /**
39504
- * Replace the viewer race set. Empty `baseUrls` restores AUTO. Stored
39505
- * verbatim (not indices) so a temporarily-down tunnel is not silently
39506
- * dropped from the operator's choice.
39709
+ * @deprecated Use `setAddressRole({ role: 'viewer', … })`. Kept so an
39710
+ * older admin UI keeps working: it replaces the same `viewer` flags.
39711
+ * Empty `baseUrls` restores automatic.
39507
39712
  */
39508
39713
  setViewerEndpoints: method(object({ baseUrls: array(string()).readonly() }), ViewerEndpointsSchema, { kind: "mutation" }),
39509
39714
  /**
39715
+ * The Network page's Addresses table and every role's answer — the ONE
39716
+ * reading of "which address is this hub reached at, for what": detected
39717
+ * endpoints and custom addresses with their role flags, and per role the
39718
+ * flagged address, the one in use and whether it is automatic. Agent
39719
+ * deliveries, sign-in and LAN devices read `roles.agents` / `roles.signIn`
39720
+ * here; nothing ranks the palette itself. `scheme` is the one the caller
39721
+ * shows LAN rows in (as `getConnectionEndpoints`); agents and sign-in are
39722
+ * always resolved over the HTTPS palette.
39723
+ */
39724
+ getAddresses: method(object({ scheme: _enum(["http", "https"]).optional() }).optional(), HubAddressBookSchema),
39725
+ /**
39726
+ * Add a custom address. Validated: an http(s) origin with a host, no
39727
+ * credentials, no path, never loopback — an invalid one is refused with
39728
+ * the reason and nothing is stored. Adding an address that already exists
39729
+ * only updates its label.
39730
+ */
39731
+ addCustomAddress: method(object({
39732
+ baseUrl: string(),
39733
+ label: string().max(80)
39734
+ }), HubAddressBookSchema, {
39735
+ kind: "mutation",
39736
+ auth: "admin"
39737
+ }),
39738
+ /** Remove a custom address. Its role flags go with it (those roles turn automatic). */
39739
+ removeCustomAddress: method(object({ baseUrl: string() }), HubAddressBookSchema, {
39740
+ kind: "mutation",
39741
+ auth: "admin"
39742
+ }),
39743
+ /**
39744
+ * Flag (`enabled: true`) or unflag an address for a role. For a
39745
+ * single-valued role, flagging moves the flag off every other address.
39746
+ * `baseUrl: null` returns the role to automatic. The address must be a row
39747
+ * of the table (detected, custom, or the app link for notifications);
39748
+ * `signIn` on a plain-http address is refused unless `acceptInsecureHttp`.
39749
+ */
39750
+ setAddressRole: method(object({
39751
+ role: HubAddressRoleSchema,
39752
+ baseUrl: string().nullable(),
39753
+ enabled: boolean(),
39754
+ acceptInsecureHttp: boolean().optional()
39755
+ }), HubAddressBookSchema, {
39756
+ kind: "mutation",
39757
+ auth: "admin"
39758
+ }),
39759
+ /**
39760
+ * @deprecated Read `getAddresses().roles.agents` / `.signIn`. Kept one
39761
+ * release so an addon built against the D729 amendment keeps resolving:
39762
+ * `cluster` = the `agents` role, `browser` = the `signIn` role.
39763
+ */
39764
+ getHubAddresses: method(_void(), HubAddressesSchema),
39765
+ /**
39510
39766
  * Read the operator's allowlist. Empty = "auto" (no filter). Used
39511
39767
  * by the admin UI's address selector to seed its checkbox state.
39512
39768
  */
@@ -51519,12 +51775,24 @@ Object.freeze({
51519
51775
  addonId: null,
51520
51776
  access: "view"
51521
51777
  },
51778
+ "localNetwork.addCustomAddress": {
51779
+ capName: "local-network",
51780
+ capScope: "system",
51781
+ addonId: null,
51782
+ access: "create"
51783
+ },
51522
51784
  "localNetwork.downloadCa": {
51523
51785
  capName: "local-network",
51524
51786
  capScope: "system",
51525
51787
  addonId: null,
51526
51788
  access: "view"
51527
51789
  },
51790
+ "localNetwork.getAddresses": {
51791
+ capName: "local-network",
51792
+ capScope: "system",
51793
+ addonId: null,
51794
+ access: "view"
51795
+ },
51528
51796
  "localNetwork.getAllowedAddresses": {
51529
51797
  capName: "local-network",
51530
51798
  capScope: "system",
@@ -51537,6 +51805,12 @@ Object.freeze({
51537
51805
  addonId: null,
51538
51806
  access: "view"
51539
51807
  },
51808
+ "localNetwork.getHubAddresses": {
51809
+ capName: "local-network",
51810
+ capScope: "system",
51811
+ addonId: null,
51812
+ access: "view"
51813
+ },
51540
51814
  "localNetwork.getNotificationEndpoint": {
51541
51815
  capName: "local-network",
51542
51816
  capScope: "system",
@@ -51573,6 +51847,12 @@ Object.freeze({
51573
51847
  addonId: null,
51574
51848
  access: "create"
51575
51849
  },
51850
+ "localNetwork.removeCustomAddress": {
51851
+ capName: "local-network",
51852
+ capScope: "system",
51853
+ addonId: null,
51854
+ access: "delete"
51855
+ },
51576
51856
  "localNetwork.resetAllowlistToBestMatch": {
51577
51857
  capName: "local-network",
51578
51858
  capScope: "system",
@@ -51585,6 +51865,12 @@ Object.freeze({
51585
51865
  addonId: null,
51586
51866
  access: "create"
51587
51867
  },
51868
+ "localNetwork.setAddressRole": {
51869
+ capName: "local-network",
51870
+ capScope: "system",
51871
+ addonId: null,
51872
+ access: "create"
51873
+ },
51588
51874
  "localNetwork.setAllowedAddresses": {
51589
51875
  capName: "local-network",
51590
51876
  capScope: "system",
@@ -55839,6 +56125,12 @@ Object.freeze({
55839
56125
  addonId: null,
55840
56126
  access: "create"
55841
56127
  },
56128
+ "webrtcSession.applyDownlinkProbe": {
56129
+ capName: "webrtc-session",
56130
+ capScope: "device",
56131
+ addonId: null,
56132
+ access: "create"
56133
+ },
55842
56134
  "webrtcSession.closeSession": {
55843
56135
  capName: "webrtc-session",
55844
56136
  capScope: "device",
@@ -59937,6 +60229,11 @@ Object.freeze({
59937
60229
  form: "single",
59938
60230
  optional: false
59939
60231
  }],
60232
+ "webrtcSession.applyDownlinkProbe": [{
60233
+ name: "deviceId",
60234
+ form: "single",
60235
+ optional: false
60236
+ }],
59940
60237
  "webrtcSession.closeSession": [{
59941
60238
  name: "deviceId",
59942
60239
  form: "single",
@@ -61321,7 +61618,7 @@ var STATE_SUMMARY_VARS = [
61321
61618
  {
61322
61619
  name: "summarySection",
61323
61620
  label: "Summary: this section",
61324
- description: "The section a per-section summary row is about (D698); on a summary sent as one message, every section it reports, comma-separated.",
61621
+ description: "The section a per-section summary row is about; on a summary sent as one message, every section it reports, comma-separated.",
61325
61622
  example: "Batterie scariche",
61326
61623
  group: "system",
61327
61624
  families: ["rule"],
@@ -65019,6 +65316,12 @@ Object.defineProperty(exports, "isRetiredClearKey", {
65019
65316
  return isRetiredClearKey;
65020
65317
  }
65021
65318
  });
65319
+ Object.defineProperty(exports, "isRootSuppliableStepId", {
65320
+ enumerable: true,
65321
+ get: function() {
65322
+ return isRootSuppliableStepId;
65323
+ }
65324
+ });
65022
65325
  Object.defineProperty(exports, "isScheduleActive", {
65023
65326
  enumerable: true,
65024
65327
  get: function() {
@@ -65217,6 +65520,12 @@ Object.defineProperty(exports, "resolvePoolMemoryPolicy", {
65217
65520
  return resolvePoolMemoryPolicy;
65218
65521
  }
65219
65522
  });
65523
+ Object.defineProperty(exports, "rootSupplyServes", {
65524
+ enumerable: true,
65525
+ get: function() {
65526
+ return rootSupplyServes;
65527
+ }
65528
+ });
65220
65529
  Object.defineProperty(exports, "ruleAutoTriggersAlarm", {
65221
65530
  enumerable: true,
65222
65531
  get: function() {