@camstack/system 1.2.267 → 1.2.269

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 (65) hide show
  1. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  2. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  3. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  4. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  5. package/dist/builtins/alerts/alerts.addon.js +1 -1
  6. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  7. package/dist/builtins/autotrack/index.js +1 -1
  8. package/dist/builtins/autotrack/index.mjs +1 -1
  9. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  10. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  11. package/dist/builtins/camera-grid/addon.d.ts +13 -2
  12. package/dist/builtins/camera-grid/grid-canvas-derivation.d.ts +19 -0
  13. package/dist/builtins/camera-grid/grid-compositor.d.ts +8 -0
  14. package/dist/builtins/camera-grid/grid-instances.d.ts +5 -2
  15. package/dist/builtins/camera-grid/grid-plan.d.ts +8 -6
  16. package/dist/builtins/camera-grid/grid-profiles.d.ts +42 -39
  17. package/dist/builtins/camera-grid/grid-stream-descriptor.d.ts +7 -4
  18. package/dist/builtins/camera-grid/grid-stream-relay.d.ts +10 -7
  19. package/dist/builtins/camera-grid/grid-tile-feed.d.ts +12 -0
  20. package/dist/builtins/camera-grid/index.d.ts +3 -2
  21. package/dist/builtins/camera-grid/index.js +438 -265
  22. package/dist/builtins/camera-grid/index.mjs +435 -263
  23. package/dist/builtins/console-logging/index.js +1 -1
  24. package/dist/builtins/console-logging/index.mjs +1 -1
  25. package/dist/builtins/core-blocks/core-blocks.addon.js +1 -1
  26. package/dist/builtins/core-blocks/core-blocks.addon.mjs +1 -1
  27. package/dist/builtins/device-manager/device-manager.addon.js +2 -2
  28. package/dist/builtins/device-manager/device-manager.addon.mjs +2 -2
  29. package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
  30. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
  31. package/dist/builtins/hub-forwarder/index.js +1 -1
  32. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  33. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  34. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  35. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  36. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  37. package/dist/builtins/local-network/local-network.addon.js +1 -1
  38. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  39. package/dist/builtins/loki-logging/index.js +1 -1
  40. package/dist/builtins/loki-logging/index.mjs +1 -1
  41. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  42. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  43. package/dist/builtins/platform-probe/index.js +1 -1
  44. package/dist/builtins/platform-probe/index.mjs +1 -1
  45. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  46. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  47. package/dist/builtins/snapshot/index.js +1 -1
  48. package/dist/builtins/snapshot/index.mjs +1 -1
  49. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  50. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  51. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
  52. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
  53. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  54. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  55. package/dist/builtins/system-config/system-config.addon.js +1 -1
  56. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  57. package/dist/builtins/winston-logging/index.js +1 -1
  58. package/dist/builtins/winston-logging/index.mjs +1 -1
  59. package/dist/{dist-BbPssgI6.js → dist-BTpfLiUX.js} +31 -6
  60. package/dist/{dist-Ck0rjYOQ.mjs → dist-CqmImT7i.mjs} +31 -6
  61. package/dist/index.js +1 -1
  62. package/dist/index.mjs +1 -1
  63. package/dist/{retired-settings-keys-BZpDuJVh.mjs → retired-settings-keys-C8nV-AUi.mjs} +1 -1
  64. package/dist/{retired-settings-keys-Dg_69cOY.js → retired-settings-keys-D_DIuT_N.js} +1 -1
  65. package/package.json +1 -1
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-BbPssgI6.js");
6
+ const require_dist = require("../../dist-BTpfLiUX.js");
7
7
  const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
8
8
  let node_crypto = require("node:crypto");
9
9
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { P as addonPagesCapability, Pn as EventCategory, an as errMsg, sn as BaseAddon } from "../../dist-Ck0rjYOQ.mjs";
1
+ import { P as addonPagesCapability, Pn as EventCategory, an as errMsg, sn as BaseAddon } from "../../dist-CqmImT7i.mjs";
2
2
  import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
3
3
  import { createHash, randomUUID } from "node:crypto";
4
4
  import * as path$1 from "node:path";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-BbPssgI6.js");
6
+ const require_dist = require("../../dist-BTpfLiUX.js");
7
7
  const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
8
8
  let node_crypto = require("node:crypto");
9
9
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { I as addonWidgetsCapability, Pn as EventCategory, an as errMsg, sn as BaseAddon } from "../../dist-Ck0rjYOQ.mjs";
1
+ import { I as addonWidgetsCapability, Pn as EventCategory, an as errMsg, sn as BaseAddon } from "../../dist-CqmImT7i.mjs";
2
2
  import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
3
3
  import { createHash, randomUUID } from "node:crypto";
4
4
  import * as path$1 from "node:path";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-BbPssgI6.js");
6
+ const require_dist = require("../../dist-BTpfLiUX.js");
7
7
  //#region src/builtins/alerts/prune-policy.ts
8
8
  /**
9
9
  * Ids older than `cutoffMs`, oldest first.
@@ -1,4 +1,4 @@
1
- import { L as alertsCapability, Pn as EventCategory, an as errMsg, bn as createEvent, n as AlertSchema, sn as BaseAddon } from "../../dist-Ck0rjYOQ.mjs";
1
+ import { L as alertsCapability, Pn as EventCategory, an as errMsg, bn as createEvent, n as AlertSchema, sn as BaseAddon } from "../../dist-CqmImT7i.mjs";
2
2
  //#region src/builtins/alerts/prune-policy.ts
3
3
  /**
4
4
  * Ids older than `cutoffMs`, oldest first.
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-BbPssgI6.js");
6
+ const require_dist = require("../../dist-BTpfLiUX.js");
7
7
  //#region src/builtins/autotrack/autotrack-config.ts
8
8
  var DEFAULT_AUTOTRACK_LOOP_CONFIG = {
9
9
  deadZoneFraction: .5,
@@ -1,4 +1,4 @@
1
- import { B as bareAddonId, En as isEvent, It as ptzAutotrackCapability, Pn as EventCategory, an as errMsg, h as FIRST_LEVEL_MACRO_CLASSES, sn as BaseAddon } from "../../dist-Ck0rjYOQ.mjs";
1
+ import { B as bareAddonId, En as isEvent, It as ptzAutotrackCapability, Pn as EventCategory, an as errMsg, h as FIRST_LEVEL_MACRO_CLASSES, sn as BaseAddon } from "../../dist-CqmImT7i.mjs";
2
2
  //#region src/builtins/autotrack/autotrack-config.ts
3
3
  var DEFAULT_AUTOTRACK_LOOP_CONFIG = {
4
4
  deadZoneFraction: .5,
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-BbPssgI6.js");
6
+ const require_dist = require("../../dist-BTpfLiUX.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  let buffer = require("buffer");
9
9
  let node_fs_promises = require("node:fs/promises");
@@ -1,4 +1,4 @@
1
- import { Dt as mayWriteToLocation, Pn as EventCategory, Zt as storageOccupancyCapability, sn as BaseAddon, z as backupCapability } from "../../dist-Ck0rjYOQ.mjs";
1
+ import { Dt as mayWriteToLocation, Pn as EventCategory, Zt as storageOccupancyCapability, sn as BaseAddon, z as backupCapability } from "../../dist-CqmImT7i.mjs";
2
2
  import { randomBytes, randomUUID } from "node:crypto";
3
3
  import { Buffer as Buffer$1 } from "buffer";
4
4
  import * as fsp from "node:fs/promises";
@@ -22,7 +22,7 @@ export declare class CameraGridAddon extends BaseAddon<CameraGridAddonConfig> {
22
22
  * (D224), and 60 s is the window for a fact — "does 615 have a low assigned"
23
23
  * — that only changes when an operator changes it.
24
24
  */
25
- private readonly planByInstanceId;
25
+ private readonly plansByInstanceId;
26
26
  private activity;
27
27
  private snapshots;
28
28
  private frameSampler;
@@ -87,12 +87,23 @@ export declare class CameraGridAddon extends BaseAddon<CameraGridAddonConfig> {
87
87
  * line a minute for ever.
88
88
  */
89
89
  private logSourcePlan;
90
+ private plansFor;
90
91
  private planFor;
92
+ /**
93
+ * The canvas of the BEST profile this grid offers.
94
+ *
95
+ * Used where a single geometry is needed for something that is not a
96
+ * composition — the detection boxes a grid forwards (`grid-activity`), which
97
+ * are normalized against whatever picture the viewer is looking at. The best
98
+ * offered one is the honest default; a grid offering nothing has no geometry
99
+ * and says so.
100
+ */
101
+ private canvasFor;
91
102
  private ensureSessions;
92
103
  private makeSession;
93
104
  /** The session a dial is asking for, or `null` - which the relay answers 404 to. */
94
105
  private sessionFor;
95
- /** This grid's composition, as the list the snapshot source expects. */
106
+ /** This grid's sessions, in DESCENDING quality — the snapshot takes the first running one. */
96
107
  private sessionsForDevice;
97
108
  /** A grid that is gone stops immediately - it must not keep N sources dialled. */
98
109
  private retireWithdrawnSessions;
@@ -0,0 +1,19 @@
1
+ import { PixelSize } from './grid-canvas.js';
2
+ import { NormalizedRect } from './grid-filter-graph.js';
3
+ export interface GridCanvasCell {
4
+ /** The part of the source this cell shows, normalized against the SOURCE. */
5
+ readonly source: NormalizedRect;
6
+ /** Where it lands, normalized against the CANVAS. */
7
+ readonly cell: NormalizedRect;
8
+ /** The source's size AT THE PROFILE being derived for. */
9
+ readonly sourceSize: PixelSize;
10
+ }
11
+ /**
12
+ * The canvas these cells imply, or `null` when they imply none.
13
+ *
14
+ * `null` for a grid with no cells — the normal freshly-created state — and for
15
+ * a layout whose every rectangle is degenerate. Both are "there is no picture
16
+ * to size", which the caller turns into "this profile is not on offer" rather
17
+ * than into a guess.
18
+ */
19
+ export declare function deriveGridCanvas(cells: readonly GridCanvasCell[]): PixelSize | null;
@@ -31,6 +31,14 @@ export declare class GridCompositor {
31
31
  * flicker. The canvas is never cleared between ticks for the same reason.
32
32
  */
33
33
  tick(): boolean;
34
+ /**
35
+ * A tile's decoder was replaced: drop its half frame, keep its picture.
36
+ *
37
+ * Without this the new decoder's bytes would be appended to the old one's
38
+ * partial frame and every frame after would be sheared — raw video has no
39
+ * framing to re-sync on.
40
+ */
41
+ resetTile(tileId: string): void;
34
42
  /** After this, a tick emits nothing — a dead child must not keep writing. */
35
43
  close(): void;
36
44
  }
@@ -25,9 +25,12 @@ declare const GridInstanceSchema: z.ZodObject<{
25
25
  cameraStableId: z.ZodString;
26
26
  name: z.ZodString;
27
27
  enabled: z.ZodBoolean;
28
- width: z.ZodNumber;
29
- height: z.ZodNumber;
30
28
  fps: z.ZodNumber;
29
+ publishedProfiles: z.ZodDefault<z.ZodArray<z.ZodEnum<{
30
+ high: "high";
31
+ mid: "mid";
32
+ low: "low";
33
+ }>>>;
31
34
  cells: z.ZodDefault<z.ZodArray<z.ZodObject<{
32
35
  deviceId: z.ZodNumber;
33
36
  source: z.ZodObject<{
@@ -5,15 +5,17 @@ export interface GridPlanEncodeContext {
5
5
  readonly encoder: FfmpegVideoEncoderId;
6
6
  readonly decodeHwAccel: string | null;
7
7
  /**
8
- * The canvas to compose onto, when it is not the one the operator laid out.
8
+ * The canvas to compose onto. REQUIRED, and never authored: each profile
9
+ * derives its own from the cells and its sources' size
10
+ * (`grid-canvas-derivation.ts`). It used to fall back to two numbers the
11
+ * operator typed into the editor, and that field is gone — it silently
12
+ * decided both what the composite cost and how sharp it was.
9
13
  *
10
- * A grid publishes one composition per profile, and `mid`/`low` compose onto
11
- * a SCALED copy of the operator's canvas (`grid-profiles.ts` owns the
12
- * scale). The geometry needs no second version of itself: every rectangle is
14
+ * The geometry needs no second version of itself: every rectangle is
13
15
  * normalized on both sides (D519), so the same fractions land correctly on a
14
- * smaller picture. Absent ⇒ the operator's own canvas, which is `high`.
16
+ * canvas of any size.
15
17
  */
16
- readonly canvas?: {
18
+ readonly canvas: {
17
19
  readonly width: number;
18
20
  readonly height: number;
19
21
  };
@@ -1,61 +1,64 @@
1
1
  import { CamProfile } from '@camstack/types';
2
+ import { PixelSize } from './grid-canvas.js';
2
3
  import { NormalizedRect } from './grid-filter-graph.js';
3
4
  /**
4
- * One id, for every grid, forever.
5
+ * One id per profile, for every grid, forever.
5
6
  *
6
- * D519's reason is what keeps this id bare: a per-instance or newly-spelled id
7
- * mints a second cam-stream and orphans whatever profile assignment the
8
- * operator had made. It was `high` on the live hub before the per-profile
9
- * detour and it is `high` again, so nothing an operator assigned is disturbed.
7
+ * D519's reason is what keeps `high`'s id bare: a newly-spelled id mints a
8
+ * second cam-stream and orphans whatever profile assignment the operator had
9
+ * made. `grid` was `high` on the live hub before any of this and still is.
10
10
  */
11
11
  export declare const GRID_CAM_STREAM_ID = "grid";
12
- /**
13
- * The slot the single composition claims.
14
- *
15
- * NOT decoration. A device publishing one stream with no hint is ranked by
16
- * pixel count and lands in `mid` — the slot `recordings` does not select on its
17
- * own, that `recordingsLow` ignores, and that scrub never reads. The Dreame
18
- * robot's single 720p relay landed exactly there and its footage was written
19
- * where nothing looked.
20
- */
21
- export declare const GRID_OUTPUT_PROFILE: CamProfile;
22
- /** The cheapest stream this source serves, or `null` when it serves none. */
23
- export declare function lowestServedProfile(served: readonly CamProfile[]): CamProfile | null;
24
- /** One stream a camera serves, with the size that decides whether it fits. */
12
+ /** Every profile a grid can compose, in descending quality. */
13
+ export declare const GRID_PROFILES: readonly CamProfile[];
14
+ /** The cam-stream id a grid publishes for one profile. */
15
+ export declare function gridCamStreamId(profile: CamProfile): string;
16
+ /** One stream a camera serves, with the size the canvas is derived from. */
25
17
  export interface ServedProfile {
26
18
  readonly profile: CamProfile;
27
- /** `0` means the broker stated no size — see `gridSourceProfiles`. */
28
19
  readonly width: number;
29
20
  readonly height: number;
30
21
  }
31
- /** One cell, as the two rectangles that decide what its source must carry. */
22
+ /** One cell: which part of which source, and where it lands. */
32
23
  export interface GridSourceCell {
33
24
  readonly deviceId: number;
34
- /** The part of the source it shows, normalized against the SOURCE. */
35
25
  readonly source: NormalizedRect;
36
- /** Where it lands, normalized against the CANVAS. */
37
26
  readonly cell: NormalizedRect;
38
27
  }
39
- export interface GridSourceProfilesInput {
40
- readonly canvas: {
41
- readonly width: number;
42
- readonly height: number;
43
- };
28
+ export interface GridProfilePlansInput {
44
29
  readonly cells: readonly GridSourceCell[];
45
30
  /**
46
- * Which streams this source can serve, or `null` when nobody could say.
47
- * `null` is not an empty list: an unanswerable question is a refusal, and
48
- * saying so separately keeps "we did not ask" out of the catalog.
31
+ * Which profiles the operator wants published. A profile that is not in here
32
+ * is still SIZED and reported — the editor shows what it would come out as,
33
+ * so turning it on is a decision made with the number in view — but it is not
34
+ * offered to the broker.
35
+ */
36
+ readonly publishedProfiles: readonly CamProfile[];
37
+ /**
38
+ * Which streams this source serves, or `null` when nobody could say. `null`
39
+ * is not an empty list: an unanswerable question is a refusal, and saying so
40
+ * separately keeps "we did not ask" out of the catalog.
49
41
  */
50
42
  readonly profilesServedBy: (deviceId: number) => readonly ServedProfile[] | null;
51
43
  }
52
- export interface GridSourcePlan {
53
- /** True when every source can be read — the only case a grid is on offer. */
54
- readonly offered: boolean;
55
- /** Which stream each source is read at. Only contains readable sources. */
56
- readonly profileBySource: ReadonlyMap<number, CamProfile>;
57
- /** The sources that serve nothing, or that nobody could answer for. */
44
+ export type GridProfilePlan = {
45
+ readonly profile: CamProfile;
46
+ readonly offered: true;
47
+ readonly canvas: PixelSize;
48
+ /** False ⇒ serviceable, sized, and deliberately not published. */
49
+ readonly published: boolean;
50
+ } | {
51
+ readonly profile: CamProfile;
52
+ readonly offered: false;
53
+ /** The sources that cannot serve it. Empty only when there are none at all. */
58
54
  readonly missingSources: readonly number[];
59
- }
60
- /** Which stream to read each source at, and who cannot be read at all. */
61
- export declare function gridSourceProfiles(input: GridSourceProfilesInput): GridSourcePlan;
55
+ };
56
+ /**
57
+ * What this grid can honestly publish, per profile, with the canvas or the
58
+ * refusal.
59
+ *
60
+ * Every profile gets a row whether it is offered or not: an absent row says
61
+ * nothing, and the caller logging a refusal needs the reason more than the
62
+ * caller publishing an offer needs the offer.
63
+ */
64
+ export declare function gridProfilePlans(input: GridProfilePlansInput): readonly GridProfilePlan[];
@@ -1,5 +1,8 @@
1
- import { CamStreamDescriptor } from '@camstack/types';
1
+ import { CamProfile, CamStreamDescriptor } from '@camstack/types';
2
2
  export interface GridStreamDescriptorInput {
3
+ /** Which composition this is. Also the `profileHint` — see below. */
4
+ readonly profile: CamProfile;
5
+ /** The DERIVED canvas of that profile, never an authored number. */
3
6
  readonly width: number;
4
7
  readonly height: number;
5
8
  readonly fps: number;
@@ -15,8 +18,8 @@ export interface GridStreamDescriptorInput {
15
18
  * scrub never reads. The Dreame robot's one 720p relay landed exactly there and
16
19
  * its footage was written nowhere anything looked.
17
20
  *
18
- * So the single composition claims `high` EXPLICITLY (`GRID_OUTPUT_PROFILE`).
19
- * It is also the slot this stream held before the per-profile detour, which is
20
- * what keeps an operator's existing assignment intact.
21
+ * With several compositions published the hint does a second job: it says which
22
+ * slot each one is FOR. Ranked by pixels a grid's `mid` would take the `high`
23
+ * slot on any grid whose `high` was not offered.
21
24
  */
22
25
  export declare function gridStreamDescriptor(input: GridStreamDescriptorInput): CamStreamDescriptor;
@@ -1,17 +1,20 @@
1
+ import { CamProfile } from '@camstack/types';
1
2
  import { GridStreamLogger, GridStreamSession } from './grid-stream-session.js';
2
3
  /**
3
- * Which grid. There is one composition of it, so that is the whole address.
4
+ * Which grid, and WHICH COMPOSITION of it.
4
5
  *
5
- * The path used to carry a profile segment, because a grid published one
6
- * composition per profile and a dial naming none would have been the broker
7
- * asking for "whichever". With a single output "whichever" is well defined,
8
- * and the segment would be a choice with one option — which is not a choice,
9
- * it is a way to spell one stream two ways.
6
+ * The profile is a path segment and not a query string for the reason the
7
+ * restream suffixes are (`restream-intent.ts`): the choice belongs to the URL
8
+ * the consumer was handed, so a broker configured once keeps asking for the
9
+ * same thing. It is REQUIRED — a dial naming none would be the broker asking
10
+ * for "whichever", which is how a `low` slot ends up holding a `high`
11
+ * composition.
10
12
  */
11
13
  export interface GridStreamRequest {
12
14
  readonly instanceId: string;
15
+ readonly profile: CamProfile;
13
16
  }
14
- /** `/grid/<instanceId>.flv`, or `null` when it is anything else. */
17
+ /** `/grid/<instanceId>/<profile>.flv`, or `null` when it is anything else. */
15
18
  export declare function parseGridStreamPath(url: string | undefined): GridStreamRequest | null;
16
19
  export interface GridStreamRelayDeps {
17
20
  readonly logger: GridStreamLogger;
@@ -33,6 +33,18 @@ export declare class GridTileFeed {
33
33
  latest(): Buffer | null;
34
34
  /** Has a new frame arrived since the last {@link latest}? */
35
35
  hasFresh(): boolean;
36
+ /**
37
+ * Forget the half frame, keep the picture.
38
+ *
39
+ * Raw video has no framing: the feed cuts on a fixed length, so bytes from a
40
+ * NEW decoder concatenated onto a partial frame from the old one would be
41
+ * misaligned for ever — every frame after it sheared, with nothing to
42
+ * re-sync on. Called whenever a tile's decoder is replaced.
43
+ *
44
+ * The newest frame is kept deliberately: the cell holds its last picture
45
+ * while its decoder comes back, instead of blinking to black.
46
+ */
47
+ resetPartial(): void;
36
48
  /** For the bound in the spec: one frame plus at most a partial one. */
37
49
  bufferedBytes(): number;
38
50
  }
@@ -22,8 +22,9 @@ export type { GridPlanEncodeContext } from './grid-plan.js';
22
22
  export { normalizeGridRows } from './grid-row-normalization.js';
23
23
  export type { NormalizedGridRows } from './grid-row-normalization.js';
24
24
  export { gridStreamDescriptor } from './grid-stream-descriptor.js';
25
- export { GRID_CAM_STREAM_ID, GRID_OUTPUT_PROFILE, gridSourceProfiles, lowestServedProfile, } from './grid-profiles.js';
26
- export type { GridSourcePlan } from './grid-profiles.js';
25
+ export { GRID_CAM_STREAM_ID, GRID_PROFILES, gridCamStreamId, gridProfilePlans, } from './grid-profiles.js';
26
+ export type { GridProfilePlan, ServedProfile } from './grid-profiles.js';
27
+ export { deriveGridCanvas } from './grid-canvas-derivation.js';
27
28
  export { gridSourceDial } from './grid-sentry-sources.js';
28
29
  export type { GridSourceAcquisition, GridSourceDial } from './grid-sentry-sources.js';
29
30
  export { GridSnapshotSource, gridSnapshotAnswerFor } from './grid-snapshot.js';