@camstack/addon-post-analysis 1.2.297 → 1.2.299

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.
@@ -5401,7 +5401,7 @@ var ZodIssueCode = {
5401
5401
  var ZodFirstPartyTypeKind;
5402
5402
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5403
5403
  //#endregion
5404
- //#region ../types/dist/sleep-DlrgY4Qb.mjs
5404
+ //#region ../types/dist/sleep-C-v96WpE.mjs
5405
5405
  /**
5406
5406
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5407
5407
  * window to float samples (D455).
@@ -8626,7 +8626,6 @@ var CompositionSchema = object({
8626
8626
  });
8627
8627
  var OWNER_TYPES = new Set([
8628
8628
  "track",
8629
- "summary",
8630
8629
  "face",
8631
8630
  "identity",
8632
8631
  "plate",
@@ -8782,6 +8781,90 @@ var BASE_LIVE_EGRESS_PROFILE = {
8782
8781
  ({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
8783
8782
  ({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
8784
8783
  /**
8784
+ * The notification GIF's filter chain and argv — ONE definition for every
8785
+ * process that derives a gif from a notification video.
8786
+ *
8787
+ * ## Why this lives in `@camstack/types`
8788
+ *
8789
+ * Two addons derive a notification gif from an mp4, and they may never import
8790
+ * each other:
8791
+ *
8792
+ * - the stream broker (`addon-pipeline`), from the clip it just cut out of its
8793
+ * own ring (`gif-from-mp4.ts`);
8794
+ * - the notification centre (`addon-post-analysis`), from a clip cut out of
8795
+ * the RECORDINGS when the moment is older than any ring holds
8796
+ * ([D682](../../../../docs/decisions/adr-0682-a-pick-ups-footage-is-cut-around-the-pick-up.md)).
8797
+ *
8798
+ * Two copies of this chain would be two gifs of the same kind of moment that
8799
+ * look different depending on how old the moment was — the class of defect
8800
+ * D85/D91 already paid for once. So the chain is here, pure and dependency
8801
+ * free, and each caller owns only its own process lifecycle.
8802
+ *
8803
+ * ## The palette was never the problem
8804
+ *
8805
+ * The `split` + `palettegen(stats_mode=diff)` + `paletteuse(bayer)` pair is
8806
+ * right and stays. The measured cause of "the gif looks de-pixellated" was a
8807
+ * 640×360 substream scaled DOWN to 480 px, upstream of the palette. The `split`
8808
+ * form is a single READ of the input, not a lesser two-pass.
8809
+ */
8810
+ /**
8811
+ * Format a frame rate for an ffmpeg filter argument.
8812
+ *
8813
+ * `12 / 4` must reach the filter as `3` and `15 / 4` as `3.75`, not as a float
8814
+ * tail that `av_parse_video_rate` then has to guess at.
8815
+ */
8816
+ function ffmpegRate(rate) {
8817
+ return String(Math.round(rate * 1e3) / 1e3);
8818
+ }
8819
+ /**
8820
+ * The factor the derive must apply ON TOP of the speed the mp4 already carries.
8821
+ *
8822
+ * The gif is derived from a muxed mp4, so if that mux already ran `setpts` at
8823
+ * the caller's `speed`, applying the absolute gif rate again would compound
8824
+ * them — a 4× gif beside a 2× video would come out at 8×. Discounting here is
8825
+ * what keeps the gif rate ABSOLUTE against real time whatever the video does.
8826
+ */
8827
+ function gifDeriveSpeed(gifSpeed, videoSpeed) {
8828
+ if (!Number.isFinite(videoSpeed) || videoSpeed <= 0) return gifSpeed;
8829
+ return gifSpeed / videoSpeed;
8830
+ }
8831
+ /**
8832
+ * The filter chain. Extracted so a test can assert the palette pair without
8833
+ * spawning ffmpeg — an argv test cannot see quality, but it can see a filter
8834
+ * that somebody deleted.
8835
+ *
8836
+ * `fps` BEFORE `setpts`: decimating an already sped-up timeline yields `speed`
8837
+ * times the frames asked for, and a gif pays for every one. So the decimation
8838
+ * runs at `fps / speed` in SOURCE time and `setpts` multiplies what survived.
8839
+ * The trailing `fps` re-declares the rate, which is NOT redundant: `setpts`
8840
+ * leaves the filter link advertising the sampled rate and the gif muxer
8841
+ * believes the link — measured on 615 as a 3.01 s gif of ten frames.
8842
+ */
8843
+ function gifFilterComplex(input) {
8844
+ const speed = input.speed > 0 ? input.speed : 1;
8845
+ if (speed === 1) return `[0:v]fps=${ffmpegRate(input.fps)},scale=${input.maxWidth}:-2:flags=lanczos,split[a][b];[a]palettegen=stats_mode=diff[p];[b][p]paletteuse=dither=bayer:bayer_scale=5:diff_mode=rectangle`;
8846
+ return `[0:v]fps=${ffmpegRate(input.fps / speed)},setpts=PTS/${speed},fps=${ffmpegRate(input.fps)},scale=${input.maxWidth}:-2:flags=lanczos,split[a][b];[a]palettegen=stats_mode=diff[p];[b][p]paletteuse=dither=bayer:bayer_scale=5:diff_mode=rectangle`;
8847
+ }
8848
+ /** The full argv: mp4 in, gif on stdout. */
8849
+ function gifFromMp4Args(input) {
8850
+ return [
8851
+ "-y",
8852
+ "-v",
8853
+ "error",
8854
+ "-f",
8855
+ "mp4",
8856
+ "-i",
8857
+ input.input ?? "pipe:0",
8858
+ "-filter_complex",
8859
+ gifFilterComplex(input),
8860
+ "-loop",
8861
+ "0",
8862
+ "-f",
8863
+ "gif",
8864
+ "pipe:1"
8865
+ ];
8866
+ }
8867
+ /**
8785
8868
  * Deep wiring healthcheck — snapshot of active reachability probes across
8786
8869
  * every declared capability + widget of every installed plugin, on every
8787
8870
  * node. Produced by the backend `WiringHealthService` and surfaced via
@@ -23013,6 +23096,21 @@ var ObjectEventSchema = object({
23013
23096
  keyFrameMediaId: number().int().optional(),
23014
23097
  /** Populated by B5 (recording playback URL for this event). */
23015
23098
  mediaUrl: string().optional(),
23099
+ /**
23100
+ * When the change this row records HAPPENED, epoch ms, when that is earlier
23101
+ * than {@link timestamp} and the producer could date it (D684).
23102
+ *
23103
+ * Set on a package PICK-UP row only: its `timestamp` is when the departure
23104
+ * was CONCLUDED — five minutes of unseen observed time after the parcel went
23105
+ * — and a notification's footage has to be cut around the pick-up, not the
23106
+ * empty doormat after it (D682). Stored so every path that rebuilds a
23107
+ * notification subject from the row (the boot reconcile, a dry-run) anchors
23108
+ * on the same instant the live hook did.
23109
+ *
23110
+ * `timestamp` keeps its meaning. Absent on every other row and on every
23111
+ * pick-up written before D684 — UNKNOWN, never 0 and never `timestamp`.
23112
+ */
23113
+ observedAt: number().optional(),
23016
23114
  /** The parent track's key-event importance [0,1], propagated to every object
23017
23115
  * event of the track (so an event row can be sorted by importance without a
23018
23116
  * track join). Absent on legacy rows / before the track was scored. */
@@ -23348,131 +23446,6 @@ var RecentTracksQueryInput = object({
23348
23446
  /** See {@link ExcludeSourcesDoc}. */
23349
23447
  excludeSources: array(TrackSourceSchema).optional()
23350
23448
  });
23351
- /**
23352
- * A Summary (D359): the per-camera session envelope that references tracks.
23353
- * `groupShotMediaId` is the media ROW id of its group shot (`ownerKind:
23354
- * 'summary'`, served by the event-media plane at `/m/<id>`), null until the
23355
- * first frame with a member visible has been materialised (D482 — it was the
23356
- * row's composite key, which embedded the owner and could name another table's
23357
- * row once event ids became per-table rowids).
23358
- */
23359
- var SummarySchema = object({
23360
- id: string(),
23361
- deviceId: number(),
23362
- openedAt: number(),
23363
- lastActiveAt: number(),
23364
- sealedAt: number().nullable(),
23365
- memberCount: number().int().nonnegative(),
23366
- groupShotMediaId: number().int().nullable()
23367
- });
23368
- var SummariesQueryInput = object({
23369
- deviceIds: array(number()).min(1),
23370
- since: number().optional(),
23371
- until: number().optional(),
23372
- limit: number().int().min(1).max(200).default(50),
23373
- /** The same member-wise filter {@link listRecentSummaries} takes — one
23374
- * meaning of "dog" on every summary surface. */
23375
- classes: array(string().min(1).max(60)).max(40).optional()
23376
- });
23377
- var SummaryDetailSchema = object({
23378
- summary: SummarySchema,
23379
- /** Members in absorption order, oldest join first. */
23380
- members: array(object({
23381
- trackId: string(),
23382
- /**
23383
- * The track's class at the time it JOINED, or `null` when it was unresolved
23384
- * and the track no longer exists to fill it.
23385
- *
23386
- * The join, not the latest opinion: class voting can re-decide a track's
23387
- * class afterwards, and a group's composition is the history of who came
23388
- * together. A consumer counts these to badge a thumbnail — "two people and a
23389
- * dog" — rather than being handed a second, denormalised tally that would
23390
- * drift from the members it claims to describe.
23391
- */
23392
- className: string().nullable(),
23393
- /** `primary` is the one member that carries the group's identity. */
23394
- role: _enum([
23395
- "primary",
23396
- "sibling",
23397
- "child"
23398
- ]).nullable(),
23399
- joinedAt: number(),
23400
- /** Tier 1 — the sub-class (`dog`, `van`), resolved from the member's track
23401
- * at read time. Absent when nothing resolved, never an empty string. */
23402
- label: string().optional(),
23403
- /** Tier 2 — the instance: a person's name, a plate. Absent when the pipeline
23404
- * recognised nobody, and absent for a member whose track has been pruned —
23405
- * a thumbnail that names the wrong person is worse than one naming nobody. */
23406
- subLabel: string().optional()
23407
- })).readonly()
23408
- });
23409
- /**
23410
- * What a LIST of groups carries: the envelope plus what it is MADE OF.
23411
- *
23412
- * Coarse on purpose — the operator's rule is "only the rough data on the list,
23413
- * we extend when we notice we need more". Enough to draw the card ("two people
23414
- * and a dog") and no more. The MEMBERS, their names and the per-member links
23415
- * are on {@link getSummary}: shipping every member of every group so a client
23416
- * can count them turns a page of two hundred groups into a thousand records to
23417
- * draw two hundred badges.
23418
- */
23419
- var SummaryListItemSchema = object({
23420
- summary: SummarySchema,
23421
- /** Class counts, most numerous first; `className: null` is a member whose
23422
- * class never resolved, counted so the counts add up to `memberCount`. */
23423
- classes: array(object({
23424
- className: string().nullable(),
23425
- count: number().int().positive()
23426
- })).readonly()
23427
- });
23428
- var SummariesPageSchema = object({ summaries: array(SummaryListItemSchema).readonly() });
23429
- /**
23430
- * The paged feed, deliberately the SAME shape as {@link RecentTracksQueryInput}.
23431
- *
23432
- * The reel on the cameras page and the Events gallery both ride a cursor, so a
23433
- * summaries feed that could only answer "the last N for these cameras"
23434
- * (`listSummaries`) would make groups available in the timeline and nowhere
23435
- * else. Two feeds with different ordering contracts would be two ideas of what
23436
- * "newest" means, on one screen.
23437
- */
23438
- var RecentSummariesQueryInput = object({
23439
- /** Devices to merge. An empty array yields an empty page. */
23440
- deviceIds: array(number()),
23441
- /** Window lower bound on `lastActiveAt` (inclusive). */
23442
- since: number().optional(),
23443
- /** Window upper bound on `lastActiveAt` (inclusive). */
23444
- until: number().optional(),
23445
- limit: number().int().min(1).max(500).default(100),
23446
- /** Opaque continuation cursor from a previous page's `nextCursor`. */
23447
- cursor: string().optional(),
23448
- /**
23449
- * Restrict to these classes — THE SAME FIELD `listRecentTracks` takes, and
23450
- * deliberately the same name: the events filter tree emits one list of ticked
23451
- * taxonomy nodes, and a summaries feed that called it something else would
23452
- * make the operator's one filter component produce two shapes.
23453
- *
23454
- * A question about the MEMBERS: a group matches when ANY of them does. "Show
23455
- * me the arrivals with a dog" has to return the group of four people who had
23456
- * one with them; a filter on the group's own fields could only ever answer
23457
- * about its primary.
23458
- *
23459
- * Matched against all THREE tiers of a member — the class (`animal`), the
23460
- * sub-class (`dog`) and the instance (a name, a plate) — because which tier a
23461
- * ticked node lives on is the taxonomy's business, not the caller's. `dog` is
23462
- * an event kind in the tree and a tier-1 label on an `animal` track; a filter
23463
- * that read only the class would answer "animal" and never "dog".
23464
- *
23465
- * ABSENT or EMPTY means no filter — absent is not a selection of none.
23466
- */
23467
- classes: array(string().min(1).max(60)).max(40).optional()
23468
- });
23469
- var RecentSummariesPageSchema = object({
23470
- /** Ordered by (`lastActiveAt` DESC, id DESC). Same light item as
23471
- * {@link listSummaries} — one list shape, so a card renders the same
23472
- * whichever feed drew it. */
23473
- summaries: array(SummaryListItemSchema).readonly(),
23474
- nextCursor: string().nullable()
23475
- });
23476
23449
  var RecentTracksPageSchema = object({
23477
23450
  /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
23478
23451
  tracks: array(TrackSchema).readonly(),
@@ -24025,15 +23998,6 @@ var pipelineAnalyticsCapability = {
24025
23998
  * are not included (same contract as `listTracks`).
24026
23999
  */
24027
24000
  listRecentTracks: method(RecentTracksQueryInput, RecentTracksPageSchema),
24028
- /** Newest first by `openedAt`, for a camera set, inside an optional window. */
24029
- listSummaries: method(SummariesQueryInput, SummariesPageSchema),
24030
- /**
24031
- * The PAGED feed — the reel and the Events gallery. Same cursor contract as
24032
- * {@link listRecentTracks}, so one screen cannot hold two ideas of newest.
24033
- */
24034
- listRecentSummaries: method(RecentSummariesQueryInput, RecentSummariesPageSchema),
24035
- /** One summary with its member track ids; `null` for an id nobody wrote. */
24036
- getSummary: method(object({ id: string() }), SummaryDetailSchema.nullable()),
24037
24001
  clearTracks: method(object({ deviceId: number() }), _void(), {
24038
24002
  kind: "mutation",
24039
24003
  auth: "admin"
@@ -47405,12 +47369,6 @@ Object.freeze({
47405
47369
  addonId: null,
47406
47370
  access: "view"
47407
47371
  },
47408
- "pipelineAnalytics.getSummary": {
47409
- capName: "pipeline-analytics",
47410
- capScope: "device",
47411
- addonId: null,
47412
- access: "view"
47413
- },
47414
47372
  "pipelineAnalytics.getTrack": {
47415
47373
  capName: "pipeline-analytics",
47416
47374
  capScope: "device",
@@ -47471,12 +47429,6 @@ Object.freeze({
47471
47429
  addonId: null,
47472
47430
  access: "view"
47473
47431
  },
47474
- "pipelineAnalytics.listRecentSummaries": {
47475
- capName: "pipeline-analytics",
47476
- capScope: "device",
47477
- addonId: null,
47478
- access: "view"
47479
- },
47480
47432
  "pipelineAnalytics.listRecentTracks": {
47481
47433
  capName: "pipeline-analytics",
47482
47434
  capScope: "device",
@@ -47507,12 +47459,6 @@ Object.freeze({
47507
47459
  addonId: null,
47508
47460
  access: "view"
47509
47461
  },
47510
- "pipelineAnalytics.listSummaries": {
47511
- capName: "pipeline-analytics",
47512
- capScope: "device",
47513
- addonId: null,
47514
- access: "view"
47515
- },
47516
47462
  "pipelineAnalytics.listTrackMedia": {
47517
47463
  capName: "pipeline-analytics",
47518
47464
  capScope: "device",
@@ -51682,11 +51628,6 @@ Object.freeze({
51682
51628
  form: "single",
51683
51629
  optional: true
51684
51630
  }],
51685
- "pipelineAnalytics.listRecentSummaries": [{
51686
- name: "deviceIds",
51687
- form: "array",
51688
- optional: false
51689
- }],
51690
51631
  "pipelineAnalytics.listRecentTracks": [{
51691
51632
  name: "deviceIds",
51692
51633
  form: "array",
@@ -51697,11 +51638,6 @@ Object.freeze({
51697
51638
  form: "array",
51698
51639
  optional: true
51699
51640
  }],
51700
- "pipelineAnalytics.listSummaries": [{
51701
- name: "deviceIds",
51702
- form: "array",
51703
- optional: false
51704
- }],
51705
51641
  "pipelineAnalytics.listTrackMedia": [{
51706
51642
  name: "deviceId",
51707
51643
  form: "single",
@@ -56136,6 +56072,18 @@ Object.defineProperty(exports, "failureContributionCapability", {
56136
56072
  return failureContributionCapability;
56137
56073
  }
56138
56074
  });
56075
+ Object.defineProperty(exports, "gifDeriveSpeed", {
56076
+ enumerable: true,
56077
+ get: function() {
56078
+ return gifDeriveSpeed;
56079
+ }
56080
+ });
56081
+ Object.defineProperty(exports, "gifFromMp4Args", {
56082
+ enumerable: true,
56083
+ get: function() {
56084
+ return gifFromMp4Args;
56085
+ }
56086
+ });
56139
56087
  Object.defineProperty(exports, "hydrateSchema", {
56140
56088
  enumerable: true,
56141
56089
  get: function() {
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_clip_model_registry = require("../clip-model-registry-BTpYUJzK.js");
5
+ const require_clip_model_registry = require("../clip-model-registry-hTbsQ-z7.js");
6
6
  let node_fs = require("node:fs");
7
7
  node_fs = require_clip_model_registry.__toESM(node_fs);
8
8
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { Hn as normalizeNodeId, Ht as embeddingRequirementsUnavailableError, Pn as BaseAddon, Rt as embeddingEncoderCapability, Vt as embeddingRequirementsFailedError, a as CLIP_EMBEDDING_STEP_ID, an as parseProcStatus, c as resolveClusterModelPin, ft as PoolMemoryWatchdog, i as CLIP_TEXT_MODELS, n as DEFAULT_CLIP_MODEL, pn as resolvePoolMemoryPolicy, r as CLIP_IMAGE_MODELS, t as BUILTIN_CLIP_MODELS, zt as embeddingModelFailedError } from "../clip-model-registry-BP_o2Oi4.mjs";
1
+ import { Ht as embeddingRequirementsUnavailableError, In as BaseAddon, Rt as embeddingEncoderCapability, Vt as embeddingRequirementsFailedError, Wn as normalizeNodeId, a as CLIP_EMBEDDING_STEP_ID, c as resolveClusterModelPin, ft as PoolMemoryWatchdog, hn as resolvePoolMemoryPolicy, i as CLIP_TEXT_MODELS, n as DEFAULT_CLIP_MODEL, r as CLIP_IMAGE_MODELS, sn as parseProcStatus, t as BUILTIN_CLIP_MODELS, zt as embeddingModelFailedError } from "../clip-model-registry-DCztUu1G.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import * as fs from "node:fs";
4
4
  import * as path$1 from "node:path";
@@ -1,8 +1,8 @@
1
1
  import { a as e, i as t, n, o as r, r as i, t as a } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare__react__loadShare__.js-C0AuF9av.mjs";
2
2
  import { t as o } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-B3Wx5J80.mjs";
3
- import { a as s, i as c, n as l, o as u, r as d, s as f, t as p } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-KXwf-qxG.mjs";
3
+ import { a as s, i as c, n as l, o as u, r as d, s as f, t as p } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-Ckt8VrEv.mjs";
4
4
  import { n as m, r as h, t as g } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-Bm-iyjmq.mjs";
5
- import { t as _ } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BVgWHpfo.mjs";
5
+ import { t as _ } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-C3QGV7zb.mjs";
6
6
  //#region ../../node_modules/lucide-react/dist/esm/shared/src/utils/mergeClasses.js
7
7
  var v = (...e) => e.filter((e, t, n) => !!e && e.trim() !== "" && n.indexOf(e) === t).join(" ").trim(), y = (e) => e.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(), b = (e) => e.replace(/^([A-Z])|[\s-_]+(\w)/g, (e, t, n) => n ? n.toUpperCase() : t.toLowerCase()), x = (e) => {
8
8
  let t = b(e);
@@ -18,7 +18,7 @@ var e = {
18
18
  },
19
19
  "@camstack/types": {
20
20
  name: "@camstack/types",
21
- version: "1.2.272",
21
+ version: "1.2.274",
22
22
  scope: ["default"],
23
23
  loaded: !1,
24
24
  from: "addon_pipeline_analytics_widgets",
@@ -33,7 +33,7 @@ var e = {
33
33
  },
34
34
  "@camstack/ui-library": {
35
35
  name: "@camstack/ui-library",
36
- version: "1.2.213",
36
+ version: "1.2.214",
37
37
  scope: ["default"],
38
38
  loaded: !1,
39
39
  from: "addon_pipeline_analytics_widgets",